diff --git a/README.md b/.github/README.md similarity index 100% rename from README.md rename to .github/README.md diff --git a/_locales/am/messages.json b/_locales/am/messages.json index 2132f13..731646d 100644 --- a/_locales/am/messages.json +++ b/_locales/am/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/ar/messages.json b/_locales/ar/messages.json index 2132f13..731646d 100644 --- a/_locales/ar/messages.json +++ b/_locales/ar/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/bg/messages.json b/_locales/bg/messages.json index 2132f13..731646d 100644 --- a/_locales/bg/messages.json +++ b/_locales/bg/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/bn/messages.json b/_locales/bn/messages.json new file mode 100644 index 0000000..731646d --- /dev/null +++ b/_locales/bn/messages.json @@ -0,0 +1,95 @@ +{ + "areYouSureYouWantToExportTheData": { + "message": "Are you sure you want to export the data?" + }, + "areYouSureYouWantToImportTheData": { + "message": "Are you sure you want to import the data?" + }, + "black": { + "message": "Black" + }, + "cancel": { + "message": "Cancel" + }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, + "create": { + "message": "Create" + }, + "dark": { + "message": "Dark" + }, + "dataExportedSuccessfully": { + "message": "Data exported successfully" + }, + "dataImportedSuccessfully": { + "message": "Data imported successfully" + }, + "decryption": { + "message": "Decryption" + }, + "description": { + "message": "With the To-Do extension you get a simple popup to capture your ideas, goals and daily tasks." + }, + "encryption": { + "message": "Encryption" + }, + "export": { + "message": "Export" + }, + "icons": { + "message": "Icons" + }, + "import": { + "message": "Import" + }, + "language": { + "message": "Language" + }, + "light": { + "message": "Light" + }, + "lists": { + "message": "Lists" + }, + "myTasks": { + "message": "My tasks" + }, + "newList": { + "message": "New list" + }, + "newTask": { + "message": "New task" + }, + "noLists": { + "message": "No lists" + }, + "noTasks": { + "message": "No tasks" + }, + "ok": { + "message": "OK" + }, + "password": { + "message": "Password" + }, + "remove": { + "message": "Remove" + }, + "rename": { + "message": "Rename" + }, + "selectFile": { + "message": "Select file" + }, + "theme": { + "message": "Theme" + } +} \ No newline at end of file diff --git a/_locales/ca/messages.json b/_locales/ca/messages.json index 2132f13..731646d 100644 --- a/_locales/ca/messages.json +++ b/_locales/ca/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/cs/messages.json b/_locales/cs/messages.json index 2132f13..731646d 100644 --- a/_locales/cs/messages.json +++ b/_locales/cs/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/da/messages.json b/_locales/da/messages.json index 2132f13..731646d 100644 --- a/_locales/da/messages.json +++ b/_locales/da/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 6e565e9..7063f31 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Erstellen" }, @@ -35,6 +44,9 @@ "export": { "message": "Exportieren" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Importieren" }, diff --git a/_locales/el/messages.json b/_locales/el/messages.json index 2132f13..731646d 100644 --- a/_locales/el/messages.json +++ b/_locales/el/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 2132f13..731646d 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/es/messages.json b/_locales/es/messages.json index 2132f13..731646d 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/et/messages.json b/_locales/et/messages.json index 2132f13..731646d 100644 --- a/_locales/et/messages.json +++ b/_locales/et/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/fa/messages.json b/_locales/fa/messages.json index 2132f13..731646d 100644 --- a/_locales/fa/messages.json +++ b/_locales/fa/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/fi/messages.json b/_locales/fi/messages.json index 2132f13..731646d 100644 --- a/_locales/fi/messages.json +++ b/_locales/fi/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/fil/messages.json b/_locales/fil/messages.json index 2132f13..731646d 100644 --- a/_locales/fil/messages.json +++ b/_locales/fil/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index 2132f13..731646d 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/gu/messages.json b/_locales/gu/messages.json index 2132f13..731646d 100644 --- a/_locales/gu/messages.json +++ b/_locales/gu/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/he/messages.json b/_locales/he/messages.json index 2132f13..731646d 100644 --- a/_locales/he/messages.json +++ b/_locales/he/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/hi/messages.json b/_locales/hi/messages.json index 2132f13..731646d 100644 --- a/_locales/hi/messages.json +++ b/_locales/hi/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/hin/messages.json b/_locales/hin/messages.json new file mode 100644 index 0000000..731646d --- /dev/null +++ b/_locales/hin/messages.json @@ -0,0 +1,95 @@ +{ + "areYouSureYouWantToExportTheData": { + "message": "Are you sure you want to export the data?" + }, + "areYouSureYouWantToImportTheData": { + "message": "Are you sure you want to import the data?" + }, + "black": { + "message": "Black" + }, + "cancel": { + "message": "Cancel" + }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, + "create": { + "message": "Create" + }, + "dark": { + "message": "Dark" + }, + "dataExportedSuccessfully": { + "message": "Data exported successfully" + }, + "dataImportedSuccessfully": { + "message": "Data imported successfully" + }, + "decryption": { + "message": "Decryption" + }, + "description": { + "message": "With the To-Do extension you get a simple popup to capture your ideas, goals and daily tasks." + }, + "encryption": { + "message": "Encryption" + }, + "export": { + "message": "Export" + }, + "icons": { + "message": "Icons" + }, + "import": { + "message": "Import" + }, + "language": { + "message": "Language" + }, + "light": { + "message": "Light" + }, + "lists": { + "message": "Lists" + }, + "myTasks": { + "message": "My tasks" + }, + "newList": { + "message": "New list" + }, + "newTask": { + "message": "New task" + }, + "noLists": { + "message": "No lists" + }, + "noTasks": { + "message": "No tasks" + }, + "ok": { + "message": "OK" + }, + "password": { + "message": "Password" + }, + "remove": { + "message": "Remove" + }, + "rename": { + "message": "Rename" + }, + "selectFile": { + "message": "Select file" + }, + "theme": { + "message": "Theme" + } +} \ No newline at end of file diff --git a/_locales/hr/messages.json b/_locales/hr/messages.json index 2132f13..731646d 100644 --- a/_locales/hr/messages.json +++ b/_locales/hr/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/hu/messages.json b/_locales/hu/messages.json index 2132f13..731646d 100644 --- a/_locales/hu/messages.json +++ b/_locales/hu/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/id/messages.json b/_locales/id/messages.json index 2132f13..731646d 100644 --- a/_locales/id/messages.json +++ b/_locales/id/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/it/messages.json b/_locales/it/messages.json index 2132f13..731646d 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index 2132f13..731646d 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/kn/messages.json b/_locales/kn/messages.json index 2132f13..731646d 100644 --- a/_locales/kn/messages.json +++ b/_locales/kn/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/ko/messages.json b/_locales/ko/messages.json index 2132f13..731646d 100644 --- a/_locales/ko/messages.json +++ b/_locales/ko/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/lt/messages.json b/_locales/lt/messages.json index 2132f13..731646d 100644 --- a/_locales/lt/messages.json +++ b/_locales/lt/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/lv/messages.json b/_locales/lv/messages.json index 2132f13..731646d 100644 --- a/_locales/lv/messages.json +++ b/_locales/lv/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/ml/messages.json b/_locales/ml/messages.json index 2132f13..731646d 100644 --- a/_locales/ml/messages.json +++ b/_locales/ml/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/mr/messages.json b/_locales/mr/messages.json index 2132f13..731646d 100644 --- a/_locales/mr/messages.json +++ b/_locales/mr/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/ms/messages.json b/_locales/ms/messages.json index 2132f13..731646d 100644 --- a/_locales/ms/messages.json +++ b/_locales/ms/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/nb_NO/messages.json b/_locales/nb_NO/messages.json new file mode 100644 index 0000000..731646d --- /dev/null +++ b/_locales/nb_NO/messages.json @@ -0,0 +1,95 @@ +{ + "areYouSureYouWantToExportTheData": { + "message": "Are you sure you want to export the data?" + }, + "areYouSureYouWantToImportTheData": { + "message": "Are you sure you want to import the data?" + }, + "black": { + "message": "Black" + }, + "cancel": { + "message": "Cancel" + }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, + "create": { + "message": "Create" + }, + "dark": { + "message": "Dark" + }, + "dataExportedSuccessfully": { + "message": "Data exported successfully" + }, + "dataImportedSuccessfully": { + "message": "Data imported successfully" + }, + "decryption": { + "message": "Decryption" + }, + "description": { + "message": "With the To-Do extension you get a simple popup to capture your ideas, goals and daily tasks." + }, + "encryption": { + "message": "Encryption" + }, + "export": { + "message": "Export" + }, + "icons": { + "message": "Icons" + }, + "import": { + "message": "Import" + }, + "language": { + "message": "Language" + }, + "light": { + "message": "Light" + }, + "lists": { + "message": "Lists" + }, + "myTasks": { + "message": "My tasks" + }, + "newList": { + "message": "New list" + }, + "newTask": { + "message": "New task" + }, + "noLists": { + "message": "No lists" + }, + "noTasks": { + "message": "No tasks" + }, + "ok": { + "message": "OK" + }, + "password": { + "message": "Password" + }, + "remove": { + "message": "Remove" + }, + "rename": { + "message": "Rename" + }, + "selectFile": { + "message": "Select file" + }, + "theme": { + "message": "Theme" + } +} \ No newline at end of file diff --git a/_locales/nl/messages.json b/_locales/nl/messages.json index 2132f13..731646d 100644 --- a/_locales/nl/messages.json +++ b/_locales/nl/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/no/messages.json b/_locales/no/messages.json index 2132f13..731646d 100644 --- a/_locales/no/messages.json +++ b/_locales/no/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/pl/messages.json b/_locales/pl/messages.json index 2132f13..731646d 100644 --- a/_locales/pl/messages.json +++ b/_locales/pl/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/pt_BR/messages.json b/_locales/pt_BR/messages.json index 2132f13..731646d 100644 --- a/_locales/pt_BR/messages.json +++ b/_locales/pt_BR/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/pt_PT/messages.json b/_locales/pt_PT/messages.json index 2132f13..731646d 100644 --- a/_locales/pt_PT/messages.json +++ b/_locales/pt_PT/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/ro/messages.json b/_locales/ro/messages.json index 2132f13..731646d 100644 --- a/_locales/ro/messages.json +++ b/_locales/ro/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 3669be0..6fc8d0a 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Отмена" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Создать" }, @@ -35,6 +44,9 @@ "export": { "message": "Экспорт" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Импорт" }, diff --git a/_locales/sk/messages.json b/_locales/sk/messages.json index 2132f13..731646d 100644 --- a/_locales/sk/messages.json +++ b/_locales/sk/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/sl/messages.json b/_locales/sl/messages.json index 2132f13..731646d 100644 --- a/_locales/sl/messages.json +++ b/_locales/sl/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/sr/messages.json b/_locales/sr/messages.json index 2132f13..731646d 100644 --- a/_locales/sr/messages.json +++ b/_locales/sr/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 2132f13..731646d 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/sw/messages.json b/_locales/sw/messages.json index 2132f13..731646d 100644 --- a/_locales/sw/messages.json +++ b/_locales/sw/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/ta/messages.json b/_locales/ta/messages.json index 2132f13..731646d 100644 --- a/_locales/ta/messages.json +++ b/_locales/ta/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/te/messages.json b/_locales/te/messages.json index 2132f13..731646d 100644 --- a/_locales/te/messages.json +++ b/_locales/te/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/th/messages.json b/_locales/th/messages.json index 2132f13..731646d 100644 --- a/_locales/th/messages.json +++ b/_locales/th/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/tr/messages.json b/_locales/tr/messages.json new file mode 100644 index 0000000..731646d --- /dev/null +++ b/_locales/tr/messages.json @@ -0,0 +1,95 @@ +{ + "areYouSureYouWantToExportTheData": { + "message": "Are you sure you want to export the data?" + }, + "areYouSureYouWantToImportTheData": { + "message": "Are you sure you want to import the data?" + }, + "black": { + "message": "Black" + }, + "cancel": { + "message": "Cancel" + }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, + "create": { + "message": "Create" + }, + "dark": { + "message": "Dark" + }, + "dataExportedSuccessfully": { + "message": "Data exported successfully" + }, + "dataImportedSuccessfully": { + "message": "Data imported successfully" + }, + "decryption": { + "message": "Decryption" + }, + "description": { + "message": "With the To-Do extension you get a simple popup to capture your ideas, goals and daily tasks." + }, + "encryption": { + "message": "Encryption" + }, + "export": { + "message": "Export" + }, + "icons": { + "message": "Icons" + }, + "import": { + "message": "Import" + }, + "language": { + "message": "Language" + }, + "light": { + "message": "Light" + }, + "lists": { + "message": "Lists" + }, + "myTasks": { + "message": "My tasks" + }, + "newList": { + "message": "New list" + }, + "newTask": { + "message": "New task" + }, + "noLists": { + "message": "No lists" + }, + "noTasks": { + "message": "No tasks" + }, + "ok": { + "message": "OK" + }, + "password": { + "message": "Password" + }, + "remove": { + "message": "Remove" + }, + "rename": { + "message": "Rename" + }, + "selectFile": { + "message": "Select file" + }, + "theme": { + "message": "Theme" + } +} \ No newline at end of file diff --git a/_locales/uk/messages.json b/_locales/uk/messages.json index 2132f13..731646d 100644 --- a/_locales/uk/messages.json +++ b/_locales/uk/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/vi/messages.json b/_locales/vi/messages.json index 2132f13..731646d 100644 --- a/_locales/vi/messages.json +++ b/_locales/vi/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json index 2132f13..731646d 100644 --- a/_locales/zh_CN/messages.json +++ b/_locales/zh_CN/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/_locales/zh_TW/messages.json b/_locales/zh_TW/messages.json index 2132f13..731646d 100644 --- a/_locales/zh_TW/messages.json +++ b/_locales/zh_TW/messages.json @@ -11,6 +11,15 @@ "cancel": { "message": "Cancel" }, + "changeColor": { + "message": "Change color" + }, + "changeIcon": { + "message": "Change icon" + }, + "color": { + "message": "Color" + }, "create": { "message": "Create" }, @@ -35,6 +44,9 @@ "export": { "message": "Export" }, + "icons": { + "message": "Icons" + }, "import": { "message": "Import" }, diff --git a/assets/data/color.js b/assets/data/color.js new file mode 100644 index 0000000..76c518e --- /dev/null +++ b/assets/data/color.js @@ -0,0 +1,12 @@ +/*-------------------------------------------------------------- +>>> COLOR +--------------------------------------------------------------*/ + +extension.color = [ + '#f6b465', + '#f56666', + '#7c66f5', + '#66c0f5', + '#66f5b3', + '#b1f566' +]; \ No newline at end of file diff --git a/assets/data/icons.js b/assets/data/icons.js new file mode 100644 index 0000000..f9d333e --- /dev/null +++ b/assets/data/icons.js @@ -0,0 +1,27 @@ +/*-------------------------------------------------------------- +>>> ICONS +--------------------------------------------------------------*/ + +extension.icons = { + folder: 'M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z', + home: 'M6 21q-.825 0-1.412-.587Q4 19.825 4 19v-9q0-.475.213-.9.212-.425.587-.7l6-4.5q.275-.2.575-.3.3-.1.625-.1t.625.1q.3.1.575.3l6 4.5q.375.275.588.7.212.425.212.9v9q0 .825-.587 1.413Q18.825 21 18 21h-4v-7h-4v7Z', + star: 'M8.3 20.125q-.575.45-1.175.025-.6-.425-.4-1.125L8.15 14.4l-3.625-2.575q-.6-.425-.362-1.125.237-.7.962-.7H9.6l1.45-4.8q.125-.35.388-.538.262-.187.562-.187.3 0 .562.187.263.188.388.538L14.4 10h4.475q.725 0 .963.7.237.7-.363 1.125L15.85 14.4l1.425 4.625q.2.7-.4 1.125-.6.425-1.175-.025L12 17.3Z', + smile: 'M15.5 11q.65 0 1.075-.425Q17 10.15 17 9.5q0-.65-.425-1.075Q16.15 8 15.5 8q-.65 0-1.075.425Q14 8.85 14 9.5q0 .65.425 1.075Q14.85 11 15.5 11Zm-7 0q.65 0 1.075-.425Q10 10.15 10 9.5q0-.65-.425-1.075Q9.15 8 8.5 8q-.65 0-1.075.425Q7 8.85 7 9.5q0 .65.425 1.075Q7.85 11 8.5 11Zm3.5 6.5q1.425 0 2.6-.637 1.175-.638 1.825-1.613.3-.45.088-.85-.213-.4-.663-.4-.175 0-.35.1t-.275.25q-.55.75-1.375 1.2-.825.45-1.85.45-1.025 0-1.85-.45-.825-.45-1.375-1.2-.1-.15-.287-.25-.188-.1-.363-.1-.425 0-.637.387-.213.388.062.813.675 1.025 1.85 1.663 1.175.637 2.6.637Zm0 4.5q-2.075 0-3.9-.788-1.825-.787-3.175-2.137-1.35-1.35-2.137-3.175Q2 14.075 2 12t.788-3.9q.787-1.825 2.137-3.175 1.35-1.35 3.175-2.138Q9.925 2 12 2t3.9.787q1.825.788 3.175 2.138 1.35 1.35 2.137 3.175Q22 9.925 22 12t-.788 3.9q-.787 1.825-2.137 3.175-1.35 1.35-3.175 2.137Q14.075 22 12 22Z', + pet: 'M4.5 12.125q-1.05 0-1.775-.725Q2 10.675 2 9.625q0-1.05.725-1.775.725-.725 1.775-.725 1.05 0 1.775.725Q7 8.575 7 9.625q0 1.05-.725 1.775-.725.725-1.775.725Zm4.5-4q-1.05 0-1.775-.725Q6.5 6.675 6.5 5.625q0-1.05.725-1.775Q7.95 3.125 9 3.125q1.05 0 1.775.725.725.725.725 1.775 0 1.05-.725 1.775-.725.725-1.775.725Zm6 0q-1.05 0-1.775-.725-.725-.725-.725-1.775 0-1.05.725-1.775.725-.725 1.775-.725 1.05 0 1.775.725.725.725.725 1.775 0 1.05-.725 1.775-.725.725-1.775.725Zm4.5 4q-1.05 0-1.775-.725Q17 10.675 17 9.625q0-1.05.725-1.775.725-.725 1.775-.725 1.05 0 1.775.725.725.725.725 1.775 0 1.05-.725 1.775-.725.725-1.775.725Zm-12.85 10q-1.125 0-1.887-.863Q4 20.4 4 19.225q0-1.3.888-2.275.887-.975 1.762-1.925.725-.775 1.25-1.688.525-.912 1.25-1.712.55-.65 1.275-1.075.725-.425 1.575-.425t1.575.4q.725.4 1.275 1.05.7.8 1.237 1.725.538.925 1.263 1.725.875.95 1.763 1.925.887.975.887 2.275 0 1.175-.762 2.037-.763.863-1.888.863-1.35 0-2.675-.225-1.325-.225-2.675-.225-1.35 0-2.675.225-1.325.225-2.675.225Z', + idea: 'M12 22q-.65 0-1.175-.312-.525-.313-.825-.838-.825 0-1.412-.587Q8 19.675 8 18.85V15.3q-1.475-.975-2.362-2.575-.888-1.6-.888-3.475 0-3.025 2.112-5.138Q8.975 2 12 2t5.137 2.112Q19.25 6.225 19.25 9.25q0 1.925-.887 3.5-.888 1.575-2.363 2.55v3.55q0 .825-.587 1.413-.588.587-1.413.587-.3.525-.825.838Q12.65 22 12 22Zm-2-3.15h4v-.9h-4Zm0-1.9h4V16h-4ZM11.25 14h1.5v-2.7l1.675-1.675q.225-.225.225-.525 0-.3-.225-.525-.225-.225-.525-.225-.3 0-.5.2L12 9.95l-1.375-1.375Q10.4 8.35 10.1 8.35q-.3 0-.525.225-.225.225-.225.525 0 .3.2.5l1.7 1.7Z', + forest: 'M15 22q-.825 0-1.412-.587Q13 20.825 13 20v-1h4v1q0 .825-.587 1.413Q15.825 22 15 22Zm-6 0q-.825 0-1.412-.587Q7 20.825 7 20v-2H1.825q-.6 0-.875-.525T1 16.45L3.85 12q-.6 0-.85-.538-.25-.537.1-1.037l5.075-7.25q.3-.425.825-.425.525 0 .825.425l5.075 7.25q.35.5.1 1.037-.25.538-.85.538L17 16.45q.275.425.013.988-.263.562-.838.562H11v2q0 .825-.587 1.413Q9.825 22 9 22Zm8.875-4q.25-.25.337-.837.088-.588-.212-1.063l-2.375-3.725q.375-.35.475-1.088.1-.737-.3-1.312l-3.175-4.55 1.55-2.25q.3-.425.825-.425.525 0 .825.425l5.075 7.25q.35.5.1 1.037-.25.538-.85.538L23 16.45q.325.5.05 1.025-.275.525-.875.525Z', + mail: 'M4 20q-.825 0-1.412-.587Q2 18.825 2 18V6q0-.825.588-1.412Q3.175 4 4 4h16q.825 0 1.413.588Q22 5.175 22 6v12q0 .825-.587 1.413Q20.825 20 20 20Zm8-7.175q.125 0 .262-.038.138-.037.263-.112L19.6 8.25q.2-.125.3-.312.1-.188.1-.413 0-.5-.425-.75T18.7 6.8L12 11 5.3 6.8q-.45-.275-.875-.013Q4 7.05 4 7.525q0 .25.1.437.1.188.3.288l7.075 4.425q.125.075.263.112.137.038.262.038Z', + call: 'M19.95 21q-3.225 0-6.287-1.438-3.063-1.437-5.425-3.8-2.363-2.362-3.8-5.425Q3 7.275 3 4.05q0-.45.3-.75t.75-.3H8.1q.35 0 .625.225t.325.575l.65 3.5q.05.35-.012.637-.063.288-.288.513L7 10.9q1.05 1.8 2.625 3.375T13.1 17l2.35-2.35q.225-.225.588-.338.362-.112.712-.062l3.45.7q.35.075.575.337.225.263.225.613v4.05q0 .45-.3.75t-.75.3Z', + hearth: 'm12 21-1.45-1.3q-3.925-3.5-6.238-6.088Q2 11.025 2 8.15 2 5.8 3.575 4.225 5.15 2.65 7.5 2.65q1.325 0 2.5.562 1.175.563 2 1.538.825-.975 2-1.538 1.175-.562 2.5-.562 2.35 0 3.925 1.575Q22 5.8 22 8.15q0 2.875-2.312 5.462Q17.375 16.2 13.45 19.7Z', + shopping: 'M7 22q-.825 0-1.412-.587Q5 20.825 5 20q0-.825.588-1.413Q6.175 18 7 18t1.412.587Q9 19.175 9 20q0 .825-.588 1.413Q7.825 22 7 22Zm10 0q-.825 0-1.412-.587Q15 20.825 15 20q0-.825.588-1.413Q16.175 18 17 18t1.413.587Q19 19.175 19 20q0 .825-.587 1.413Q17.825 22 17 22ZM6.15 6l2.4 5h7l2.75-5ZM5.2 4h14.75q.675 0 .925.5t-.025 1.05l-3.55 6.4q-.275.5-.725.775-.45.275-1.025.275H8.1L7 15h12v2H7q-1.125 0-1.7-.988-.575-.987-.05-1.962L6.6 11.6 3 4H1V2h3.25Zm3.35 7-2.4-5H18.3l-2.75 5Z', + money: 'M11.025 21v-2.15q-1.325-.3-2.287-1.15-.963-.85-1.413-2.4l1.85-.75q.375 1.2 1.113 1.825.737.625 1.937.625 1.025 0 1.738-.462.712-.463.712-1.438 0-.875-.55-1.388-.55-.512-2.55-1.162-2.15-.675-2.95-1.612-.8-.938-.8-2.288 0-1.625 1.05-2.525 1.05-.9 2.15-1.025V3h2v2.1q1.25.2 2.063.912.812.713 1.187 1.738l-1.85.8q-.3-.8-.85-1.2-.55-.4-1.5-.4-1.1 0-1.675.488-.575.487-.575 1.212 0 .825.75 1.3.75.475 2.6 1 1.725.5 2.613 1.587.887 1.088.887 2.513 0 1.775-1.05 2.7-1.05.925-2.6 1.15V21Z', + notify: 'M3 10q-.425 0-.712-.3Q2 9.4 2.05 9q.175-1.65.863-3.163.687-1.512 1.812-2.712.275-.275.7-.275.425 0 .725.3.275.275.275.675t-.275.725q-.875.95-1.412 2.062Q4.2 7.725 4.05 9q-.05.425-.337.712Q3.425 10 3 10Zm18 0q-.4 0-.7-.288-.3-.287-.35-.712-.15-1.275-.687-2.388Q18.725 5.5 17.85 4.55q-.275-.325-.275-.725 0-.4.3-.675.3-.3.712-.3.413 0 .688.275 1.125 1.2 1.813 2.712.687 1.513.862 3.163.05.4-.238.7-.287.3-.712.3ZM5 19q-.425 0-.713-.288Q4 18.425 4 18t.287-.712Q4.575 17 5 17h1v-7q0-2.075 1.25-3.688Q8.5 4.7 10.5 4.2v-.7q0-.625.438-1.062Q11.375 2 12 2t1.062.438q.438.437.438 1.062v.7q2 .5 3.25 2.112Q18 7.925 18 10v7h1q.425 0 .712.288.288.287.288.712t-.288.712Q19.425 19 19 19Zm7 3q-.825 0-1.412-.587Q10 20.825 10 20h4q0 .825-.587 1.413Q12.825 22 12 22Z', + food: 'M18 22q-.425 0-.712-.288Q17 21.425 17 21v-7h-1q-.825 0-1.412-.588Q14 12.825 14 12V7q0-2.075 1.463-3.537Q16.925 2 19 2v19q0 .425-.288.712Q18.425 22 18 22ZM8 22q-.425 0-.713-.288Q7 21.425 7 21v-8.15q-1.275-.35-2.137-1.4Q4 10.4 4 9V3q0-.425.287-.713Q4.575 2 5 2t.713.287Q6 2.575 6 3v6h1V3q0-.425.287-.713Q7.575 2 8 2t.713.287Q9 2.575 9 3v6h1V3q0-.425.288-.713Q10.575 2 11 2t.713.287Q12 2.575 12 3v6q0 1.4-.863 2.45-.862 1.05-2.137 1.4V21q0 .425-.287.712Q8.425 22 8 22Z', + handyman: 'M18.85 21.975q-.2 0-.375-.062-.175-.063-.325-.213l-5.3-5.3v-1l2.525-2.525h1l5.3 5.3q.15.15.213.325.062.175.062.375t-.062.375q-.063.175-.213.325L19.55 21.7q-.15.15-.325.213-.175.062-.375.062Zm0-2.375.725-.725-4.25-4.25-.725.725ZM5.125 22q-.2 0-.387-.075-.188-.075-.338-.225l-2.1-2.1q-.15-.15-.225-.338Q2 19.075 2 18.875t.075-.375q.075-.175.225-.325l5.3-5.3h2.125l.85-.85L6.45 7.9H5.025L2 4.875 4.825 2.05 7.85 5.075V6.5l4.125 4.125 2.9-2.9L13.8 6.65l1.4-1.4h-2.825l-.7-.7L15.225 1l.7.7v2.825l1.4-1.4 3.55 3.55q.45.425.663.975.212.55.212 1.125T21.538 9.9q-.213.55-.663 1L18.75 8.775l-1.4 1.4-1.05-1.05-5.175 5.175v2.1l-5.3 5.3q-.15.15-.325.225-.175.075-.375.075Zm0-2.4 4.25-4.25-.725-.725-4.25 4.25Z', + note: 'M10 21q-1.65 0-2.825-1.175Q6 18.65 6 17q0-1.65 1.175-2.825Q8.35 13 10 13q.575 0 1.062.137.488.138.938.413V5q0-.825.588-1.413Q13.175 3 14 3h2q.825 0 1.413.587Q18 4.175 18 5q0 .825-.587 1.412Q16.825 7 16 7h-2v10q0 1.65-1.175 2.825Q11.65 21 10 21Z', + movie: 'M5 21q-.425 0-.713-.288Q4 20.425 4 20V4q0-.425.287-.713Q4.575 3 5 3t.713.287Q6 3.575 6 4v1h2V4q0-.425.288-.713Q8.575 3 9 3h6q.425 0 .713.287Q16 3.575 16 4v1h2V4q0-.425.288-.713Q18.575 3 19 3t.712.287Q20 3.575 20 4v16q0 .425-.288.712Q19.425 21 19 21t-.712-.288Q18 20.425 18 20v-1h-2v1q0 .425-.287.712Q15.425 21 15 21H9q-.425 0-.712-.288Q8 20.425 8 20v-1H6v1q0 .425-.287.712Q5.425 21 5 21Zm1-4h2v-2H6Zm0-4h2v-2H6Zm0-4h2V7H6Zm10 8h2v-2h-2Zm0-4h2v-2h-2Zm0-4h2V7h-2Z', + car: 'M6 19v.525q0 .625-.425 1.05Q5.15 21 4.5 21q-.625 0-1.062-.438Q3 20.125 3 19.5V12l2.1-6q.15-.45.538-.725Q6.025 5 6.5 5h11q.475 0 .863.275.387.275.537.725l2.1 6v7.525q0 .625-.425 1.05Q20.15 21 19.5 21q-.625 0-1.062-.438Q18 20.125 18 19.5V19Zm-.2-9h12.4l-1.05-3H6.85Zm1.7 6q.625 0 1.062-.438Q9 15.125 9 14.5t-.438-1.062Q8.125 13 7.5 13t-1.062.438Q6 13.875 6 14.5t.438 1.062Q6.875 16 7.5 16Zm9 0q.625 0 1.062-.438Q18 15.125 18 14.5t-.438-1.062Q17.125 13 16.5 13t-1.062.438Q15 13.875 15 14.5t.438 1.062Q15.875 16 16.5 16Z', + school: 'M22 17q-.425 0-.712-.288Q21 16.425 21 16v-5.9l-8.025 4.375q-.225.125-.463.187-.237.063-.512.063t-.512-.063q-.238-.062-.463-.187L2.6 9.875q-.25-.125-.387-.363-.138-.237-.138-.512t.138-.512q.137-.238.387-.363l8.45-4.6q.225-.125.462-.188.238-.062.488-.062t.488.062q.237.063.462.188l9.525 5.2q.25.125.388.362.137.238.137.513V16q0 .425-.288.712Q22.425 17 22 17Zm-10 3.725q-.25 0-.488-.062-.237-.063-.462-.188l-5-2.7q-.5-.275-.775-.737Q5 16.575 5 16v-3.8l5.675 3.075q.325.175.65.312.325.138.675.138.35 0 .688-.15.337-.15.662-.325L19 12.2V16q0 .575-.275 1.038-.275.462-.775.737l-5 2.7q-.225.125-.462.188-.238.062-.488.062Z', + science: 'M5 21q-1.275 0-1.812-1.137-.538-1.138.262-2.113L9 11V5H8q-.425 0-.713-.288Q7 4.425 7 4t.287-.713Q7.575 3 8 3h8q.425 0 .712.287Q17 3.575 17 4t-.288.712Q16.425 5 16 5h-1v6l5.55 6.75q.8.975.262 2.113Q20.275 21 19 21Z', + sport: 'M12.7 21.2q-.275-.275-.275-.7 0-.425.275-.7l2.85-2.85-8.5-8.5L4.2 11.3q-.3.3-.7.287-.4-.012-.7-.312-.3-.3-.3-.713 0-.412.3-.712l.7-.7-.7-.7q-.3-.3-.3-.7 0-.4.3-.7l1.425-1.425L3.5 4.9q-.3-.3-.287-.713.012-.412.312-.712t.713-.3q.412 0 .712.3l.7.725 1.4-1.4q.3-.3.7-.3.4 0 .7.3l.725.725L9.9 2.8q.275-.275.7-.275.425 0 .7.275.275.275.275.7 0 .425-.275.7L8.45 7.05l8.5 8.5 2.85-2.85q.3-.3.713-.3.412 0 .712.3t.3.712q0 .413-.3.713l-.725.725.7.7q.3.3.3.7 0 .4-.3.7l-1.425 1.425.725.725q.3.3.3.7 0 .4-.3.7-.3.3-.712.3-.413 0-.713-.3l-.725-.7-1.4 1.4q-.3.3-.7.3-.4 0-.7-.3l-.725-.725-.725.725q-.275.275-.7.275-.425 0-.7-.275Z' +}; \ No newline at end of file diff --git a/ui/fonts/Roboto-Bold.ttf b/assets/fonts/Roboto-Bold.ttf similarity index 100% rename from ui/fonts/Roboto-Bold.ttf rename to assets/fonts/Roboto-Bold.ttf diff --git a/ui/fonts/Roboto-Medium.ttf b/assets/fonts/Roboto-Medium.ttf similarity index 100% rename from ui/fonts/Roboto-Medium.ttf rename to assets/fonts/Roboto-Medium.ttf diff --git a/ui/fonts/Roboto-Regular.ttf b/assets/fonts/Roboto-Regular.ttf similarity index 100% rename from ui/fonts/Roboto-Regular.ttf rename to assets/fonts/Roboto-Regular.ttf diff --git a/icons/128.png b/assets/icons/128.png similarity index 100% rename from icons/128.png rename to assets/icons/128.png diff --git a/icons/16.png b/assets/icons/16.png similarity index 100% rename from icons/16.png rename to assets/icons/16.png diff --git a/icons/32.png b/assets/icons/32.png similarity index 100% rename from icons/32.png rename to assets/icons/32.png diff --git a/icons/48.png b/assets/icons/48.png similarity index 100% rename from icons/48.png rename to assets/icons/48.png diff --git a/assets/satus/satus.css b/assets/satus/satus.css new file mode 100644 index 0000000..bad90b9 --- /dev/null +++ b/assets/satus/satus.css @@ -0,0 +1,1996 @@ +/*-------------------------------------------------------------- +# SCROLLBAR +--------------------------------------------------------------*/ + +:where([class^='satus'])::-webkit-scrollbar { + width: 4px; +} + +:where([class^='satus'])::-webkit-scrollbar:hover { + width: 8px; +} + +:where([class^='satus'])::-webkit-scrollbar-thumb { + background: rgba(var(--satus-light), .2); +} + +:where([class^='satus'])::-webkit-scrollbar-thumb:hover { + background: rgba(var(--satus-light), .3); +} +/*-------------------------------------------------------------- +# ANIMATIONS +--------------------------------------------------------------*/ + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeInLeft { + from { + opacity: 0; + transform: translateX(-100%); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes fadeInRight { + from { + opacity: 0; + transform: translateX(100%); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +@keyframes fadeOutLeft { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(-50%); + } +} + +@keyframes fadeOutRight { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(50%); + } +} + +@keyframes zoomIn { + from { + transform: scale(.8); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } +} + +@keyframes zoomOut { + from { + transform: scale(1); + opacity: 1; + } + to { + transform: scale(.8); + opacity: 0; + } +} +/*-------------------------------------------------------------- +>>> THEMES +--------------------------------------------------------------*/ + +body { + --satus-light: 0, 20, 82; + --satus-primary: #ff4158; + + --satus-alert-hue-error: 0; + --satus-alert-hue-success: 200; + + --satus-base-background: #f3f4f6; + --satus-base-foreground: #565e76; + + --satus-checkbox-background: #f3f4f6; + --satus-checkbox-border: #dcdfe5; + --satus-checkbox-foreground: rgb(255, 255, 255, .96); + + --satus-divider: rgba(var(--satus-light),.1); + + --satus-header-background: #fff; + --satus-header-foreground: inherit; + --satus-header-shadow: 0 1px 0 #dcdee5; + + --satus-layers-background: var(--satus-base-background); + --satus-layers-foreground: inherit; + + --satus-section-background: #fff; + --satus-section-border: #dcdee5; + + --satus-sidebar-background: #fff; + --satus-sidebar-foreground: inherit; + --satus-sidebar-shadow: #dcdee5; + + --satus-modal-foreground: inherit; + --satus-modal-background: #fff; + --satus-modal-shadow: 0 1px 4px #7d86a1; + + --satus-tabs-background: rgba(var(--satus-light), .04); + --satus-tabs-foreground: #fff; + + --satus-text-field-background: #edf0f2; + --satus-text-field-border: #dcdee5; + --satus-text-field-color: #7d8ba1; + --satus-text-field-selection: rgb(149, 166, 178, .35); + --satus-text-field-cursor: #fa0; + + --satus-switch-track: #e1e4ea; + --satus-switch-track--checked: var(--satus-primary); + --satus-switch-thumb: #fff; + + --satus-input-text-background: #e8e8e3; + --satus-input-text-border: #d6d6cd; + --satus-input-text-text: #848471; +} +/*-------------------------------------------------------------- +>>> NORMALIZE +--------------------------------------------------------------*/ + +:where([class^='satus']) { + box-sizing: border-box; +} + +:where([class^='satus'])[hidden]:not([hidden='false']) { + display: none; +} + +:where([class^='satus'])[transparent] { + opacity: 0; +} +/*-------------------------------------------------------------- +>>> MODAL +---------------------------------------------------------------- +# Container +# Scrim +# Surface +# Variants + # Vertical menu +--------------------------------------------------------------*/ + + +/*-------------------------------------------------------------- +# CONTAINER +--------------------------------------------------------------*/ + +.satus-modal { + position: fixed; + z-index: 9; + top: 0; + left: 0; + display: flex; + width: 100vw; + height: 100vh; + justify-content: center; + align-items: center; +} + + +/*-------------------------------------------------------------- +# SCRIM +--------------------------------------------------------------*/ + +.satus-modal__scrim { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + animation: fadeIn 150ms linear forwards; + opacity: 0; + background: rgba(0, 0, 0, .16); + backdrop-filter: blur(8px); +} + +.satus-modal--closing .satus-modal__scrim { + animation: fadeOut 70ms linear forwards; +} + + +/*-------------------------------------------------------------- +# SURFACE +--------------------------------------------------------------*/ + +.satus-modal__surface { + display: flex; + overflow-y: auto; + flex-direction: column; + box-sizing: border-box; + width: 95%; + min-width: 240px; + max-width: 560px; + max-height: 80%; + margin: 8px; + padding: 12px 16px; + transform: scale(.8); + animation: zoomIn 150ms linear forwards; + animation-delay: 20ms; + opacity: 0; + color: var(--satus-modal-foreground); + border-radius: 3px; + background-color: var(--satus-modal-background); + box-shadow: var(--satus-modal-shadow); +} + +.satus-modal--closing .satus-modal__surface { + animation: zoomOut 70ms linear forwards; +} + +.satus-section--actions { + justify-content: flex-end; +} +.satus-section--actions > *:not(:first-child) { + margin-left: 8px; +} + + +/*-------------------------------------------------------------- +# VARIANTS +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# VERTICAL MENU +--------------------------------------------------------------*/ + +.satus-modal--vertical-menu .satus-modal__surface { + position: absolute; + top: 8px; + right: 8px; + left: auto; + min-width: 180px; + max-width: 180px; + margin: 0; + padding: 8px 0; + transform-origin: right top; +} + +.satus-modal--vertical-menu .satus-modal__surface>[class^='satus']:where(:not(.satus-divider)) { + height: 36px; + padding: 0 16px; + border-radius: 0; +} + +.satus-modal--vertical-menu .satus-modal__surface>.satus-span { + font-size: 13px; + font-weight: 500; + margin: 6px 0; + padding: 0 12px; + height: auto; +} + +.satus-modal--vertical-menu .satus-modal__surface>.satus-tabs { + margin: 0 12px; + border-radius: 3px; + height: 26px; + padding: 0; +} + +.satus-modal--vertical-menu .satus-select svg, +.satus-modal--vertical-menu .satus-button svg { + margin: 0 14px 0 0; + opacity: .64; + flex: 0 0 18px; +} + +.satus-modal--vertical-menu .satus-button .satus-span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.satus-modal--vertical-menu .satus-switch:hover { + cursor: pointer; + + background-color: rgba(var(--satus-light), .06); +} + +.satus-modal--vertical-menu .satus-switch:focus { + background-color: rgba(var(--satus-light), .08); +} +/*-------------------------------------------------------------- +>>> GRID +--------------------------------------------------------------*/ + +.satus-grid { + display: flex; + align-items: stretch; + height: 100%; + padding: 8px; +} +/*-------------------------------------------------------------- +>>> TEXT FIELD +---------------------------------------------------------------- +# Parts + # Container + # Input + # +# Syntax highlighting + # Regular expression +--------------------------------------------------------------*/ + +.satus-text-field { + display: flex; + + min-width: 240px; + height: 36px; + + color: var(--satus-text-field-foreground, inherit); + border-radius: 4px; + background: var(--satus-text-field-background); + + align-items: center; + justify-content: space-between; +} + +.satus-text-field__container { + position: relative; + + overflow: hidden; + + height: 100%; + + flex: 1; +} + +.satus-text-field__textarea { + font: inherit; + + position: absolute; + z-index: 9; + top: 0; + left: 0; + + overflow: auto; + + width: 100%; + min-width: 0; + max-width: none; + height: 100%; + min-height: 0; + max-height: none; + margin: 0; + padding: 0 12px; + + white-space: pre; + + opacity: 0; + color: inherit; + border: none; + border-radius: 4px; + outline: none; + + appearance: none; + overflow-wrap: normal; +} + +.satus-text-field__display { + position: absolute; + top: 0; + left: 0; + + display: flex; + + width: 100%; + height: 100%; +} + +.satus-text-field__line-numbers { + padding: 0 12px 0 0; + + opacity: .5; +} + +.satus-text-field__line-numbers>span { + font-size: inherit; + + display: block; + + width: 100%; + + text-align: right; +} + +.satus-text-field__pre { + font: inherit; + + display: flex; + + margin: 0; +} + +.satus-text-field__hidden-value { + font: inherit; + + position: absolute; + + overflow: auto; + + white-space: pre; + pointer-events: none; + + opacity: 0; + + overflow-wrap: normal; +} + +.satus-text-field__selection { + position: absolute; + top: 0; + left: 0; + + display: none; + + width: 0; + height: 22px; + margin: 6px 12px; + + border: 1px solid var(--satus-text-field-selection); + border-radius: 3px; + background: var(--satus-text-field-selection); +} + +.satus-text-field__cursor { + position: absolute; + top: 0; + left: 0; + + display: none; + + width: 2px; + height: 22px; + margin: -3px 0 0; + + animation: blink 1s step-end 8; + + background: var(--satus-text-field-cursor); +} + +.satus-text-field__textarea:focus+.satus-text-field__display>.satus-text-field__cursor, +.satus-text-field__textarea:focus+.satus-text-field__display>.satus-text-field__selection:not([disabled]) { + display: block; +} + +@keyframes blink { + + from, + to { + opacity: 1; + } + + 50% { + opacity: 0; + } +} + + +/*-------------------------------------------------------------- +# SYNTAX HIGHLIGHTING +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# REGULAR EXPRESSION +--------------------------------------------------------------*/ + +.satus-text-field__pre>.group { + color: #47ff47; + background-color: rgb(71, 255, 71, .16); +} + +.satus-text-field__pre>.character-class { + color: #ffc247; + background-color: rgb(255, 170, 0, .16); +} + +.satus-text-field__pre>.quantifier { + color: #47c2ff; + background-color: rgb(71, 194, 255, .16); +} + +.satus-text-field__pre>.anchor { + color: #47c2ff; + background-color: rgb(71, 194, 255, .16); +} + +.satus-text-field__pre>.metasequence { + color: #47ff47; + background-color: rgb(71, 255, 71, .16); +} + +.satus-text-field__pre>.text { + color: #c4c4d4; + background-color: rgb(196, 196, 212, .16); +} +/*-------------------------------------------------------------- +>>> CHART +--------------------------------------------------------------*/ + +.satus-chart { + font-size: 90%; + + position: relative; + + height: 128px; + margin: 4px 12px; + + color: rgba(var(--satus-light), .32); + border: 1px dashed rgba(var(--satus-light), .2); + border-top: unset; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} + +.satus-chart__labels { + position: absolute; + top: 0; + left: 0; + + display: flex; + + width: 100%; + height: 100%; + + justify-content: space-between; + align-items: stretch; +} + +.satus-chart__section { + padding: 4px; + + flex: 1; +} + +.satus-chart__section:not(:last-child) { + border-right: 1px dashed rgba(var(--satus-light), .2); +} + + +.satus-chart__bars { + position: absolute; + top: 0; + left: 0; + + display: flex; + + width: 100%; + height: 100%; + + justify-content: space-between; + align-items: stretch; +} + +.satus-chart__bar { + display: flex; + flex-direction: column; + + margin: 0 1px; + + flex: 1; + align-items: center; + justify-content: flex-end; +} + +.satus-chart__piece { + width: 100%; +} + +.satus-chart__piece:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +/*-------------------------------------------------------------- +>>> SELECT +--------------------------------------------------------------*/ + +.satus-select { + position: relative; + + display: flex; + + cursor: pointer; + + align-items: center; + justify-content: space-between; +} + +.satus-select:hover { + background-color: var(--satus-hover); +} + +.satus-select__content { + display: flex; + + flex: 2; + overflow: hidden; + + align-items: center; +} + +.satus-select svg { + width: 20px; + height: 18px; + margin: 0 14px 0 0; + + opacity: .64; +} + +.satus-select__content .satus-span { + overflow: hidden; + + text-overflow: ellipsis; +} + +.satus-select__value { + display: block; + overflow: hidden; + + flex: 1; + margin-left: 8px; + + text-align: right; + text-overflow: ellipsis; + + opacity: .64; +} + +.satus-select select { + font: inherit; + + position: absolute; + z-index: 1; + top: 0; + left: 0; + + width: 100%; + height: 100%; + margin: 0; + padding: inherit; + + cursor: inherit; + + opacity: 0; + border: none; + outline: none; + + appearance: none; +} + +.satus-select:hover { + cursor: pointer; + + background-color: rgba(var(--satus-light), .06); +} + +.satus-select:focus { + background-color: rgba(var(--satus-light), .08); +} + +.satus-select select::-webkit-scrollbar { + width: 4px; +} + +.satus-select select::-webkit-scrollbar:hover { + width: 8px; +} + +.satus-select select::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, .2); +} + +.satus-select select::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, .3); +} + +.satus-select option { + color: var(--satus-select-text); + background: var(--satus-select-background); +} +/*-------------------------------------------------------------- +>>> DIVIDER +--------------------------------------------------------------*/ + +.satus-divider { + height: 1px; + margin: 16px 0 12px; + background: var(--satus-divider); +} +/*-------------------------------------------------------------- +>>> SECTION +---------------------------------------------------------------- +# Variants + # Align start + # Align end + # Card +# Media +--------------------------------------------------------------*/ + +.satus-section { + display: flex; + + flex-wrap: wrap; +} + + +/*-------------------------------------------------------------- +# ALIGN START +--------------------------------------------------------------*/ + +.satus-section--align-start { + align-items: center; +} + +.satus-section--align-start>*:not(:last-child) { + margin-right: 8px; +} + + +/*-------------------------------------------------------------- +# ALIGN END +--------------------------------------------------------------*/ + +.satus-section--align-end { + align-items: center; + justify-content: flex-end; +} + +.satus-section--align-end>*:not(:first-child) { + margin-left: 8px; +} + + +/*-------------------------------------------------------------- +# CARD +--------------------------------------------------------------*/ + +.satus-section--card { + flex-direction: column; + + max-width: 900px; + margin: 12px; + padding: 8px 0; + + border: 1px solid var(--satus-section-border); + border-radius: 3px; + background: var(--satus-section-background); +} + +.satus-section--transparent-card { + max-width: 900px; + margin: 8px 12px; +} + +.satus-section--card[data-title], +.satus-section--transparent-card[data-title] +{ + position: relative; + + margin-top: 32px; +} + +.satus-section--card[data-title]::before, +.satus-section--transparent-card::before +{ + position: absolute; + top: -8px; + left: 0; + + content: attr(data-title); + transform: translateY(-100%); +} + + +.satus-section--transparent-card > [class^='satus'] { + width: 100%; +} + +.satus-section--card>[class^='satus']:not(.satus-list):not(.satus-section) { + display: flex; + + width: 100%; + min-height: 48px; + padding: 8px 12px; + + transition: background-color .18s cubic-bezier(.25, .8, .5, 1); + text-align: left; + + border-radius: 0; + + align-items: center; +} + +.satus-section--card>[class^='satus']:not(.satus-list):not(.satus-span):hover { + background-color: rgba(var(--satus-light), .06); +} + +.satus-section--card>.satus-button { + justify-content: flex-start; +} + +.satus-section--card>.satus-button>svg, +.satus-section--card>.satus-select>svg +{ + width: 20px; + margin: 0 14px 0 0; + + color: var(--satus-primary); +} + +.satus-section--card>.satus-span { + display: flex; + + align-items: center; +} + +.satus-section--transparent { + background: unset; + border: unset; + padding: 0; + border-radius: unset; +} + + +/*-------------------------------------------------------------- +# MEDIA +--------------------------------------------------------------*/ + +@media (min-width: 901px) { + .satus-section--card, + .satus-section--transparent-card { + margin-left: auto; + margin-right: auto; + } +} +/*-------------------------------------------------------------- +>>> BASE +--------------------------------------------------------------*/ + +.satus-base { + display: flex; + flex-direction: column; + + width: 100%; + height: 100%; + + color: var(--satus-base-foreground); + background: var(--satus-base-background); +} +/*-------------------------------------------------------------- +>>> ALERT +---------------------------------------------------------------- +# Media +--------------------------------------------------------------*/ + +.satus-alert { + display: flex; + min-height: 48px; + margin: 12px; + padding: 8px 12px; + border-radius: 3px; + align-items: center; + max-width: 900px; +} + +.satus-alert--error { + color: hsl(var(--satus-alert-hue-error), 56%, 64%); + border: 1px solid hsl(var(--satus-alert-hue-error), 56%, 28%); + background: hsl(var(--satus-alert-hue-error), 56%, 20%); +} + +.satus-alert--success { + color: hsl(var(--satus-alert-hue-success), 56%, 56%); + border: 1px solid hsl(var(--satus-alert-hue-success), 56%, 26%); + background: hsl(var(--satus-alert-hue-success), 56%, 18%); +} + + +/*-------------------------------------------------------------- +# MEDIA +--------------------------------------------------------------*/ + +@media (min-width: 901px) { + .satus-alert { + margin-left: auto; + margin-right: auto; + } +} +/*-------------------------------------------------------------- +>>> INPUT +--------------------------------------------------------------*/ + +.satus-input[type=text], +.satus-input[type=password] { + font: inherit; + box-sizing: border-box; + width: 100%; + margin: 0; + padding: 0 8px; + color: var(--satus-input-text-foreground, inherit); + border: none; + outline: none; + background: none; + appearance: none; + font-size: 16px; + margin: 8px 0; + border: 1px solid var(--satus-input-text-border); + border-radius: 4px; + background-color: var(--satus-input-text-background); +} +/*-------------------------------------------------------------- +>>> MAIN +--------------------------------------------------------------*/ + +.satus-main { + display: flex; + background: var(--satus-base-background); + flex: 1 +} +/*-------------------------------------------------------------- +>>> SIDEBAR +--------------------------------------------------------------*/ + +.satus-sidebar { + z-index: 1; + display: flex; + flex-direction: column; + width: 56px; + padding: 12px 0; + color: var(--satus-sidebar-foreground); + background: var(--satus-sidebar-background); + box-shadow: 1px 0 0 var(--satus-sidebar-shadow) +} +/*-------------------------------------------------------------- +>>> LAYERS +--------------------------------------------------------------*/ + +.satus-layers { + position: relative; + + overflow: hidden; + + flex: 1; +} + +.satus-layers__layer { + position: absolute; + top: 0; + left: 0; + + overflow: auto; + + width: 100%; + height: 100%; + + color: var(--satus-layers-foreground); + background: var(--satus-layers-background); +} +/*-------------------------------------------------------------- +>>> LIST +--------------------------------------------------------------*/ + +.satus-list { + margin: 0; + + list-style: none; +} + +.satus-list__item { + display: flex; + + min-height: 48px; + padding: 0 16px; + + align-items: center; + justify-content: space-between; +} + +.satus-list__item>*:not(:first-child) { + margin-left: 8px; +} + +.satus-list__item>*:last-child { + font-size: 92%; + + text-align: right; + + opacity: .64; +} +/*-------------------------------------------------------------- +>>> COLOR PICKER: +---------------------------------------------------------------- +# Button +# Modal +--------------------------------------------------------------*/ + + +/*-------------------------------------------------------------- +# BUTTON +--------------------------------------------------------------*/ + +.satus-color-picker { + font-size: inherit; + + position: relative; + + display: flex; + + box-sizing: border-box; + margin: 0; + + cursor: pointer; + + color: inherit; + border: none; + outline: none; + background-color: var(--satus-theme-button); + + justify-content: space-between; + -webkit-tap-highlight-color: transparent; + align-items: center; + -webkit-appearance: none; +} + +.satus-color-picker__value { + width: 22px; + height: 22px; + + border: 2px solid rgba(0, 0, 0, .16); + border-radius: 50%; +} + + +/*-------------------------------------------------------------- +# MODAL +--------------------------------------------------------------*/ + +.satus-modal--color-picker .satus-modal__surface { + padding: 8px; +} + +.satus-color-picker__palette { + position: relative; + + overflow: hidden; + + width: 100%; + height: 256px; + margin: 0 0 4px; + + border-radius: 5px; + background-color: #f00; +} + +.satus-color-picker__palette:before { + position: absolute; + top: 0; + left: 0; + + width: 100%; + height: 100%; + + content: ''; + + background-image: linear-gradient(0deg, black, transparent), linear-gradient(90deg, white, transparent); +} + +.satus-color-picker__cursor { + position: absolute; + + width: 5px; + height: 5px; + + transform: translate(-50%, -50%); + pointer-events: none; + + border: 1px solid #fff; + border-radius: 50%; + box-shadow: 0 0 0 1px #000; +} + +.satus-modal--color-picker .satus-modal__surface .satus-section--color { + margin: 8px 4px; + + align-items: center; +} + +.satus-color-picker__color { + width: 32px; + height: 32px; + margin: 0 16px 0 0; + + border: 2px solid rgba(0, 0, 0, .16); + border-radius: 50%; + background: #f00; +} + +.satus-slider.satus-color-picker__hue { + padding: 0; + + flex: 1; +} + +.satus-color-picker__hue .satus-slider__track-container { + height: 16px; + margin: 0; + + border-radius: 4px; + background-image: linear-gradient(90deg, #f00, #ff2a00, #f50, #ff7f00, #fa0, #ffd400, #ff0, #d4ff00, #af0, #80ff00, #5f0, #2bff00, #0f0, #00ff2b, #0f5, #00ff80, #0fa, #00ffd5, #0ff, #00d4ff, #0af, #007fff, #05f, #002bff, #00f, #2a00ff, #50f, #7f00ff, #a0f, #d400ff, #f0f, #ff00d4, #f0a, #ff0080, #f05, #ff002b, #f00); +} + +.satus-color-picker__hue .satus-slider__track-container::before { + display: none; +} + +.satus-color-picker__hue .satus-slider__track { + background: transparent; +} + +.satus-color-picker__hue .satus-slider__track::after { + width: 16px; + height: 16px; + + background: #fff; + box-shadow: 0 0 4px rgb(0, 0, 0, .64); +} +/*-------------------------------------------------------------- +>>> SPAN +--------------------------------------------------------------*/ + +.satus-span--title { + font-weight: 500; + overflow: hidden; + + white-space: nowrap; + text-overflow: ellipsis; + + flex: 1; +} +/*-------------------------------------------------------------- +>>> BUTTON +---------------------------------------------------------------- +# Base +# Basic +# Icon +--------------------------------------------------------------*/ + + +/*-------------------------------------------------------------- +# BASE +--------------------------------------------------------------*/ + +.satus-button { + font: inherit; + + position: relative; + + display: inline-flex; + overflow: hidden; + + height: 36px; + padding: 8px; + + transition: background-color .3s cubic-bezier(.25, .8, .5, 1); + + color: inherit; + border: none; + border-radius: 6px; + outline: none; + background: transparent; + + appearance: none; + align-items: center; +} + +.satus-button:hover { + cursor: pointer; + + background-color: rgba(var(--satus-light), .06); +} + +.satus-button:focus { + background-color: rgba(var(--satus-light), .08); +} + +.satus-button svg { + width: 100%; + max-width: 24px; + height: 100%; + max-height: 24px; +} + + +/*-------------------------------------------------------------- +# BASIC +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# ICON +--------------------------------------------------------------*/ + +.satus-button--icon { + width: 40px; + height: 40px; + + border-radius: 50%; +} + +.satus-button--icon svg { + width: 24px; + height: 24px; +} +/*-------------------------------------------------------------- +>>> HEADER +--------------------------------------------------------------*/ + +.satus-header { + z-index: 1; + + display: flex; + + height: 56px; + padding: 0 12px; + + color: var(--satus-header-foreground); + background: var(--satus-header-background); + box-shadow: var(--satus-header-shadow); + + justify-content: space-between; + align-items: center; +} +/*-------------------------------------------------------------- +>>> RADIO +--------------------------------------------------------------*/ + +.satus-radio { + position: relative; + display: flex; +} + +.satus-radio__input { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + opacity: 0; + margin: 0; + z-index: 9; +} + +.satus-radio__content { + flex: 1; + padding: 0 12px; +} + +.satus-radio__i { + width: 16px; + height: 16px; + border: 1px solid rgba(var(--satus-light),.64); + border-radius: 50%; + transition: 200ms; +} + +.satus-radio__input + .satus-radio__i::before { + width: 8px; + height: 8px; + margin: 3px; + border-radius: 50%; + background: var(--satus-primary); + content: ''; + display: block; + transform: scale(0); + transition: 200ms; +} + +.satus-radio__input:checked + .satus-radio__i { + border-color: var(--satus-primary); +} + +.satus-radio__input:checked + .satus-radio__i::before { + background: var(--satus-primary); + transform: scale(1); +} +/*-------------------------------------------------------------- +>>> SLIDER +--------------------------------------------------------------*/ + +.satus-slider { + display: flex; + + flex-wrap: wrap; +} + +.satus-slider__track-container { + position: relative; + + width: 100%; + height: 20px; + margin: 10px 0 -2px; +} + +.satus-slider__track-container::before { + position: absolute; + top: calc(50% - 1px); + left: 0; + + width: 100%; + height: 2px; + + content: ''; + + opacity: .24; + background: var(--satus-primary); +} + +.satus-slider__input { + position: absolute; + top: 0; + left: 0; + + width: 100%; + height: 100%; + margin: 0; + + opacity: 0; +} + +.satus-slider__track { + position: absolute; + top: calc(50% - 1px); + left: 0; + + width: 0; + height: 2px; + + background: var(--satus-primary); + pointer-events: none; +} + +.satus-slider__track::before { + position: absolute; + top: 50%; + right: 0; + transform: translate(50%, -50%); + display: block; + width: 16px; + height: 16px; + content: ''; + transition: width 200ms, height 200ms, opacity 200ms; + opacity: 0; + border-radius: 50%; + background: var(--satus-primary); +} + +.satus-slider__input:focus + .satus-slider__track::before { + width: 24px; + height: 24px; + opacity: .16; +} + +.satus-slider__input:active + .satus-slider__track::before { + width: 26px; + height: 26px; + opacity: .16; +} + +.satus-slider__track::after { + position: absolute; + top: 50%; + right: 0; + transform: translate(50%, -50%); + + width: 10px; + height: 10px; + + content: ''; + + border-radius: 50%; + background: var(--satus-primary); + pointer-events: none; + transition: width 200ms, height 200ms, opacity 200ms; +} + +.satus-slider__input:active + .satus-slider__track::after +{ + width: 12px; + height: 12px; +} + + + + + +.satus-slider--row { + flex-wrap: nowrap; + justify-content: space-between; +} + +.satus-slider--row .satus-slider__track-container { + margin: 0 0 -2px 12px; + max-width: 50%; +} +/*-------------------------------------------------------------- +>>> TABS +--------------------------------------------------------------*/ + +.satus-tabs { + position: relative; + + display: flex; + + border: 2px solid var(--satus-tabs-background); + border-radius: 4px; + background: var(--satus-tabs-background); +} + +.satus-tabs::before { + position: absolute; + top: 0; + left: calc(calc(100% / var(--satus-tabs-count)) * var(--satus-tabs-current)); + + width: calc(100% / var(--satus-tabs-count)); + height: 100%; + + content: ''; + transition: left .25s; + + border-radius: 3px; + background: var(--satus-tabs-foreground); +} + +.satus-tabs__button { + font: inherit; + + position: relative; + z-index: 1; + + overflow: hidden; + + margin: 0; + padding: 0 8px; + + text-overflow: ellipsis; + + color: inherit; + border: none; + border-radius: 3px; + outline: none; + background: transparent; + + flex: 1; + appearance: none; +} +/*-------------------------------------------------------------- +>>> SHORTCUT: +---------------------------------------------------------------- +# +--------------------------------------------------------------*/ + +.satus-shortcut__value { + font-size: 11px; + + display: flex; + + margin-left: 16px; + + text-transform: uppercase; + + align-items: center; + flex: 1; + justify-content: flex-end; +} + +.satus-shortcut__actions { + display: flex; + + justify-content: flex-end; +} + +.satus-shortcut__actions .satus-button { + height: 32px; + margin: 8px 4px 0; + + border-radius: 8px; + background: rgba(0, 0, 0, .15); +} + +.satus-shortcut__actions .satus-button:hover { + background: rgba(0, 0, 0, .25); +} + +.satus-shortcut__primary { + display: flex; + + height: 64px; + margin: 0 0 12px; + padding: 16px; + + border-radius: 3px; + background: rgba(0, 0, 0, .16); + + align-items: center; +} + +.satus-shortcut__key { + display: flex; + + min-width: 32px; + height: 32px; + padding: 4px 8px; + + color: #242424; + border-radius: 4px; + background: #fff; + box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1); + + align-items: center; + justify-content: center; +} + +.satus-shortcut__value>.satus-shortcut__key { + font-size: 14px; + + min-width: 24px; + height: 24px; +} + +.satus-shortcut__plus { + position: relative; + + width: 12px; + height: 12px; + margin: 8px; +} + +.satus-shortcut__plus::before { + position: absolute; + top: 0; + left: 5px; + + width: 2px; + height: 12px; + + content: ''; + + background-color: #aaa; +} + +.satus-shortcut__plus::after { + position: absolute; + top: 5px; + left: 0; + + width: 12px; + height: 2px; + + content: ''; + + background-color: #aaa; +} + +.satus-shortcut__mouse { + position: relative; + + display: flex; + + width: 28px; + height: 36px; + + border-radius: 50%; + border-top-left-radius: 12px; + border-top-right-radius: 12px; + background: #fff; + box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1); +} + +.satus-shortcut__value>.satus-shortcut__mouse { + width: 22px; + height: 28px; +} + +.satus-shortcut__mouse>div { + position: absolute; + top: 0; + left: calc(50% - 1px); + + width: 2px; + height: 11px; + + border-radius: 2px; + background: #ccc; +} + +.satus-shortcut__mouse::before { + position: absolute; + top: -16%; + right: 14%; + + width: 2px; + height: 60%; + + content: ''; + + background: #f96754; +} + +.satus-shortcut__mouse.false::before { + top: -6%; +} + +.satus-shortcut__mouse.false::after { + position: absolute; + top: -20%; + right: calc(14% - 4px); + + width: 0; + height: 0; + + content: ''; + + border-right: 5px solid transparent; + border-bottom: 8px solid #f96754; + border-left: 5px solid transparent; +} + +.satus-shortcut__mouse.true::after { + position: absolute; + top: 40%; + right: calc(14% - 4px); + + width: 0; + height: 0; + + content: ''; + + border-top: 8px solid #f96754; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.satus-shortcut__mouse.click::before { + position: absolute; + top: 0; + left: -1px; + + width: 10px; + height: 10px; + + content: ''; + + border-radius: 50%; + background: #f96754; +} + +.satus-shortcut__mouse.middle::before { + position: absolute; + z-index: 1; + top: 0; + left: 50%; + + width: 10px; + height: 10px; + + content: ''; + transform: translateX(-50%); + + border-radius: 50%; + background: #f96754; +} + +.satus-shortcut__mouse.context::before { + position: absolute; + top: 0; + left: 15px; + + width: 10px; + height: 10px; + + content: ''; + + border-radius: 50%; + background: #f96754; +} + +.satus-section_shortcut { + width: 100%; + margin: 8px 0 0; + + justify-content: flex-end; +} + +.satus-button_shortcut { + font-weight: 500; + + overflow: hidden; + + height: 28px; + min-height: 28px; + margin-right: 2px; + padding: 4px 8px; + + text-transform: uppercase; + + color: #f96754; + border-radius: 4px; +} +/*-------------------------------------------------------------- +>>> CHECKBOX +--------------------------------------------------------------*/ + +.satus-checkbox { + position: relative; + + display: flex; + + cursor: pointer; + + align-items: center; +} + +.satus-checkbox__input { + position: absolute; + top: 0; + left: 0; + + width: 100%; + height: 100%; + margin: 0; + padding: 0; + + opacity: 0; + border: none; + + appearance: none; +} + +.satus-checkbox__checkmark { + position: relative; + + display: flex; + + width: 16px; + min-width: 16px; + height: 16px; + min-height: 16px; + margin: 0 12px 0 0; + + content: ''; + + border: 1px solid var(--satus-checkbox-border); + border-radius: 3px; + background: var(--satus-checkbox-background); +} + +.satus-checkbox[data-value=true] .satus-checkbox__checkmark { + border-color: var(--satus-primary); + background: var(--satus-primary); +} + +.satus-checkbox[data-value=true] .satus-checkbox__checkmark::before { + position: absolute; + top: 3px; + left: 2px; + + width: 8px; + height: 4px; + + content: ''; + transform: rotate(-45deg); + + border: 2px solid var(--satus-checkbox-foreground); + border-top: none; + border-right: none; +} +/*-------------------------------------------------------------- +>>> SWITCH +---------------------------------------------------------------- +# Container +# Track +# Thumb +--------------------------------------------------------------*/ + + +/*-------------------------------------------------------------- +# CONTAINER +--------------------------------------------------------------*/ + +.satus-switch { + font: inherit; + + display: flex; + + transition: background-color 75ms; + + color: inherit; + border: none; + outline: none; + background-color: transparent; + + justify-content: space-between; + align-items: center; +} + +.satus-switch:hover { + cursor: pointer; +} + +.satus-switch__content { + display: flex; + + align-items: center; +} + +.satus-switch__content>svg { + width: 20px; + height: 18px; + margin: 0 14px 0 0; + + opacity: .64; +} + + +/*-------------------------------------------------------------- +# TRACK +--------------------------------------------------------------*/ + +.satus-switch>i { + width: 32px; + height: 18px; + + transition: background-color 150ms; + + border-radius: 18px; + background-color: var(--satus-switch-track); + + flex: 0 0 32px; +} + +.satus-section--card .satus-switch>i { + margin-left: 16px; +} + +.satus-switch[data-value='true']>i { + background-color: var(--satus-switch-track--checked); +} + + +/*-------------------------------------------------------------- +# THUMB +--------------------------------------------------------------*/ + +.satus-switch>i::before { + display: block; + + width: 14px; + height: 14px; + margin: 2px; + + content: ''; + transition: transform 150ms cubic-bezier(.4, 0, .2, 1); + + border-radius: 50%; + background-color: var(--satus-switch-thumb); + + will-change: transform; +} + +.satus-switch[data-value='true']>i::before { + transform: translateX(14px); +} +/*-------------------------------------------------------------- +>>> CONTEXT MENU +--------------------------------------------------------------*/ + +.satus-modal--contextmenu .satus-modal__scrim { + visibility: visible; + + transform: none; + animation: none; + + opacity: 1; + background: none; + + backdrop-filter: none; +} + +.satus-modal--contextmenu .satus-modal__surface { + position: absolute; + + visibility: visible; + + min-width: 200px; + max-width: 200px; + margin: 0; + padding: 4px 0; + + transform: none; + animation: none; + + opacity: 1; + border-radius: 4px; + box-shadow: 0 0 0 1px rgba(var(--satus-light), .1); +} + +.satus-modal--contextmenu .satus-modal__surface>* { + display: flex; + + height: 32px; + padding: 0 16px; + + align-items: center; +} + +.satus-modal--contextmenu .satus-modal__surface .satus-button svg { + width: 20px; + height: 18px; + margin: 0 14px 0 0; + + opacity: .75; + + fill: none; + stroke: var(--satus-primary); + flex: 0 0 20px; +} + +.satus-modal--contextmenu .satus-modal__surface .satus-button .satus-span { + overflow: hidden; + + white-space: nowrap; + text-overflow: ellipsis; +} +/*-------------------------------------------------------------- +>>> SORTABLE +--------------------------------------------------------------*/ + +.satus-sortable__chosen { + color: var(--satus-sortable-text) !important; + background-color: var(--satus-sortable-background) !important; +} + +.satus-sortable__ghost { + position: fixed !important; + z-index: 999 !important; + top: 0 !important; + left: 0 !important; + + pointer-events: none !important; + + opacity: .8 !important; + box-shadow: 0 1px 3px rgb(0, 0, 0, .2), 0 4px 8px rgb(0, 0, 0, .1), inset 0 0 0 1px rgb(0, 0, 0, .16) !important; + + will-change: transform !important; +} diff --git a/assets/satus/satus.js b/assets/satus/satus.js new file mode 100644 index 0000000..4794646 --- /dev/null +++ b/assets/satus/satus.js @@ -0,0 +1,3266 @@ +/*-------------------------------------------------------------- +>>> CORE +---------------------------------------------------------------- +# Global variable +# Animations duration +# Append +# Attr +# Camelize +# Snakelize +# Class +# Create element +# CSS +# Empty +# Element index +# Events +# Get property +# Is +# On +# Render +# Sort +# Storage + # Clear + # Get + # Import + # Set + # Remove + # On changed +# Localization +# Log +# Text +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# GLOBAL VARIABLE +--------------------------------------------------------------*/ + +var satus = { + components: {}, + events: { + data: {} + }, + locale: { + data: {} + }, + storage: { + data: {}, + type: 'extension' + } +}; + + +/*-------------------------------------------------------------- +# ANIMATION DURATION +--------------------------------------------------------------*/ + +satus.getAnimationDuration = function (element) { + return Number(window.getComputedStyle(element).getPropertyValue('animation-duration').replace(/[^0-9.]/g, '')) * 1000; +}; + + +/*-------------------------------------------------------------- +# APPEND +--------------------------------------------------------------*/ + +satus.append = function (child, parent) { + (parent || document.body).appendChild(child); +}; + + +/*-------------------------------------------------------------- +# ATTR +--------------------------------------------------------------*/ + +satus.attr = function (element, attributes) { + if (attributes) { + for (var name in attributes) { + var value = attributes[name]; + + if (satus.isFunction(value)) { + value = value(); + } + + if (element.namespaceURI) { + if (value === false) { + element.removeAttributeNS(null, name); + } else { + element.setAttributeNS(null, name, value); + } + } else { + if (value === false) { + element.removeAttribute(name); + } else { + element.setAttribute(name, value); + } + } + } + } +}; + + +/*-------------------------------------------------------------- +# CAMELIZE +--------------------------------------------------------------*/ + +satus.camelize = function (string) { + var result = ''; + + for (var i = 0, l = string.length; i < l; i++) { + var character = string[i]; + + if (character === '_' || character === '-') { + i++; + + result += string[i].toUpperCase(); + } else { + result += character; + } + } + + return result; +}; + + +/*-------------------------------------------------------------- +# SNAKELIZE +--------------------------------------------------------------*/ + +satus.snakelize = function (string) { + return string.replace(/([A-Z])/g, '-$1').toLowerCase(); +}; + + +/*-------------------------------------------------------------- +# CLASS +--------------------------------------------------------------*/ + +satus.class = function (element, className) { + if (className) { + element.classList.add(className); + } +}; + + +/*-------------------------------------------------------------- +# CLONE +--------------------------------------------------------------*/ + +satus.clone = function (item) { + var clone = item.cloneNode(true), + parent_css = window.getComputedStyle(item.parentNode), + css = window.getComputedStyle(item), + style = ''; + + for (var i = 0, l = css.length; i < l; i++) { + var property = css[i], + value = css.getPropertyValue(property); + + if (property === 'background-color') { + value = parent_css.getPropertyValue('background-color'); + } + + if (['box-shadow', 'left', 'top', 'bottom', 'right', 'opacity'].indexOf(property) === -1) { + style += property + ':' + value + ';'; + } + } + + + clone.setAttribute('style', style); + + return clone; +}; + + +/*-------------------------------------------------------------- +# CREATE ELEMENT +--------------------------------------------------------------*/ + +satus.createElement = function (tagName, componentName, namespaceURI) { + var camelizedTagName = this.camelize(tagName), + className = 'satus-' + (componentName || tagName), + element, + match = className.match(/__[^__]+/g); + + if (!namespaceURI) { + if (tagName === 'svg') { + namespaceURI = 'http://www.w3.org/2000/svg'; + } + } + + if (namespaceURI) { + element = document.createElementNS(namespaceURI, tagName); + } else if (this.components[camelizedTagName]) { + element = document.createElement('div'); + } else { + element = document.createElement(tagName); + } + + if (match && match.length > 1) { + className = className.slice(0, className.indexOf('__')) + match[match.length - 1]; + } + + element.componentName = componentName; + element.className = className; + + element.createChildElement = function (tagName, componentName, namespaceURI) { + var element = satus.createElement(tagName, this.componentName + '__' + (componentName || tagName), namespaceURI); + + this.appendChild(element); + + return element; + }; + + return element; +}; + + +/*-------------------------------------------------------------- +# CSS +--------------------------------------------------------------*/ + +satus.css = function (element, property) { + return window.getComputedStyle(element).getPropertyValue(property); +}; + + +/*-------------------------------------------------------------- +# CRYPT +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# DECRYPTION +--------------------------------------------------------------*/ + +satus.decrypt = async function (text, password) { + var iv = text.slice(0, 24).match(/.{2}/g).map(byte => parseInt(byte, 16)), + algorithm = { + name: 'AES-GCM', + iv: new Uint8Array(iv) + }; + + try { + var data = new TextDecoder().decode(await crypto.subtle.decrypt( + algorithm, + await crypto.subtle.importKey( + 'raw', + await crypto.subtle.digest('SHA-256', new TextEncoder().encode(password)), + algorithm, + false, ['decrypt'] + ), + new Uint8Array(atob(text.slice(24)).match(/[\s\S]/g).map(ch => ch.charCodeAt(0))) + )); + } catch (err) { + return false; + } + + return data; +}; + + +/*-------------------------------------------------------------- +# ENCRYPTION +--------------------------------------------------------------*/ + +satus.encrypt = async function (text, password) { + var iv = crypto.getRandomValues(new Uint8Array(12)), + algorithm = { + name: 'AES-GCM', + iv: iv + }; + + return Array.from(iv).map(b => ('00' + b.toString(16)).slice(-2)).join('') + btoa(Array.from(new Uint8Array(await crypto.subtle.encrypt( + algorithm, + await crypto.subtle.importKey('raw', await crypto.subtle.digest('SHA-256', new TextEncoder().encode(password)), algorithm, false, ['encrypt']), + new TextEncoder().encode(text) + ))).map(byte => String.fromCharCode(byte)).join('')); +}; + + +/*-------------------------------------------------------------- +# DATA +--------------------------------------------------------------*/ + +satus.data = function (element, data) { + if (data) { + for (var key in data) { + var value = data[key]; + + if (satus.isFunction(value)) { + value = value(); + } + + element.dataset[key] = value; + } + } +}; + + +/*-------------------------------------------------------------- +# EMPTY +--------------------------------------------------------------*/ + +satus.empty = function (element, exclude = []) { + for (var i = element.childNodes.length - 1; i > -1; i--) { + var child = element.childNodes[i]; + + if (exclude.indexOf(child) === -1) { + child.remove(); + } + } +}; + + +/*-------------------------------------------------------------- +# ELEMENT INDEX +--------------------------------------------------------------*/ + +satus.elementIndex = function (element) { + return Array.prototype.slice.call(element.parentNode.children).indexOf(element); +}; + + +/*-------------------------------------------------------------- +# EVENTS +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# ON +--------------------------------------------------------------*/ + +satus.events.on = function (type, handler) { + if (!this.data[type]) { + this.data[type] = []; + } + + this.data[type].push(handler); +}; + + +/*-------------------------------------------------------------- +# TRIGGER +--------------------------------------------------------------*/ + +satus.events.trigger = function (type, data) { + var handlers = this.data[type]; + + if (handlers) { + for (var i = 0, l = handlers.length; i < l; i++) { + handlers[i](data); + } + } +}; + + +/*-------------------------------------------------------------- +# FETCH +--------------------------------------------------------------*/ + +satus.fetch = function (url, success, error, type) { + fetch(url).then(function (response) { + if (response.ok) { + response[type || 'json']().then(success); + } else { + error(); + } + }).catch(function () { + error(success); + }); +}; + + +/*-------------------------------------------------------------- +# GET PROPERTY +--------------------------------------------------------------*/ + +satus.getProperty = function (object, string) { + var properties = string.split('.'); + + for (var i = 0, l = properties.length; i < l; i++) { + var property = properties[i]; + + console.log(object); + + if (object = object[property]) { + if (i === l - 1) { + return object; + } + } else { + return false; + } + } +}; + + +/*-------------------------------------------------------------- +# INDEX OF +--------------------------------------------------------------*/ + +satus.indexOf = function (child, parent) { + var index = 0; + + if (satus.isArray(parent)) { + index = parent.indexOf(child); + } else { + while ((child = child.previousElementSibling)) { + index++; + } + } + + return index; +}; + + +/*-------------------------------------------------------------- +# TO INDEX +--------------------------------------------------------------*/ + +satus.toIndex = function (index, child, parent) { + if (satus.isArray(parent)) { + parent.splice(index, 0, parent.splice(satus.indexOf(child, parent), 1)[0]) + } +}; + + +/*-------------------------------------------------------------- +# ISSET +--------------------------------------------------------------*/ + +satus.isset = function (target, is_object) { + if (is_object === true) { + var keys = target.split('.').filter(function (value) { + return value != ''; + }); + + for (var i = 0, l = keys.length; i < l; i++) { + if (satus.isset(target[keys[i]])) { + target = target[keys[i]]; + } else { + return undefined; + } + } + + return target; + } else { + if (target === null || target === undefined) { + return false; + } + } + + return true; +}; + + +/*-------------------------------------------------------------- +# IS +--------------------------------------------------------------*/ + +satus.isArray = function (target) { + if (Array.isArray(target)) { + return true; + } else { + return false; + } +}; + +satus.isBoolean = function (target) { + return target === false || target === true; +}; + +satus.isElement = function (target) { + return target instanceof Element || target instanceof HTMLDocument; +}; + +satus.isFunction = function (target) { + return typeof target === 'function'; +}; + +satus.isNodeList = function (target) { + return target instanceof NodeList; +}; + +satus.isNumber = function (target) { + if (typeof target === 'number' && isNaN(target) === false) { + return true; + } else { + return false; + } +}; + +satus.isObject = function (target) { + return target instanceof Object && target !== null; +}; + +satus.isString = function (target) { + if (typeof target === 'string') { + return true; + } else { + return false; + } +}; + + +/*-------------------------------------------------------------- +# ON +--------------------------------------------------------------*/ + +satus.on = function (element, listeners) { + if (listeners) { + for (var type in listeners) { + var listener = listeners[type]; + + if (type === 'selectionchange') { + element = document; + } + + if (satus.isFunction(listener)) { + element.addEventListener(type, listener); + } else if (satus.isArray(listener) || satus.isObject(listener)) { + element.addEventListener(type, function (event) { + var target = this.skeleton.on[event.type], + parent = this.parentNode; + + target.parentSkeleton = this.skeleton; + target.parentElement = this; + + while (parent.componentName !== 'layers' && parent.componentName !== 'base' && parent !== document.body && parent.parentNode) { + parent = parent.parentNode; + } + + if (parent.componentName === 'layers' && target.component !== 'modal') { + parent.open(target); + } else if (this.baseProvider && this.baseProvider.layers.length === 1 && target.component !== 'modal') { + satus.render(target, this.baseProvider.layers[0]); + } else { + satus.render(target, this.baseProvider); + } + }); + } else if (satus.isString(listener)) { + element.addEventListener(type, function () { + var match = this.skeleton.on[event.type].match(/(["'`].+["'`]|[^.()]+)/g), + target = this.baseProvider; + + for (var i = 0, l = match.length; i < l; i++) { + var key = match[i]; + + if (target.skeleton[key]) { + target = target.skeleton[key]; + } else { + if (typeof target[key] === 'function') { + target[key](); + } else { + target = target[key]; + } + } + + if (target.rendered) { + target = target.rendered; + } + } + }); + } + } + } +}; + + +/*-------------------------------------------------------------- +# PARENTIFY +--------------------------------------------------------------*/ + +satus.parentify = function (parentObject, exclude) { + for (var key in parentObject) { + if (exclude.indexOf(key) === -1) { + var child = parentObject[key]; + + child.parentObject = parentObject; + + if (typeof child === 'object' && child.component !== 'shortcut') { + this.parentify(child, exclude); + } + } + } +}; + + +/*-------------------------------------------------------------- +# PREPEND +--------------------------------------------------------------*/ + +satus.prepend = function (child, parent) { + if (this.isElement(child)) { + parent.prepend(child); + } else if (this.isObject(child)) { + this.render(child, parent, undefined, undefined, true); + } +}; + + +/*-------------------------------------------------------------- +# PROPERTIES +--------------------------------------------------------------*/ + +satus.properties = function (element, properties) { + if (properties) { + for (var key in properties) { + var property = properties[key]; + + if (['placeholder', 'title'].indexOf(key) !== -1) { + property = satus.locale.get(property); + } + + element[key] = property; + } + } +}; + + +/*-------------------------------------------------------------- +# REMOVE +--------------------------------------------------------------*/ + +satus.remove = function (child, parent) { + if (satus.isArray(parent)) { + parent.splice(satus.indexOf(child, parent), 1); + } +}; + + +/*-------------------------------------------------------------- +# RENDER +--------------------------------------------------------------*/ + +satus.render = function (skeleton, container, property, childrenOnly, prepend) { + var element; + + if (skeleton.component && childrenOnly !== true) { + var tagName = skeleton.component, + camelizedTagName = this.camelize(tagName), + namespaceURI = skeleton.namespaceURI; + + if (!namespaceURI) { + if (tagName === 'svg') { + namespaceURI = 'http://www.w3.org/2000/svg'; + } else if (skeleton.parentSkeleton && skeleton.parentSkeleton.namespaceURI) { + namespaceURI = skeleton.parentSkeleton.namespaceURI; + } + + skeleton.namespaceURI = namespaceURI; + } + + element = this.createElement(tagName, tagName, namespaceURI); + + skeleton.rendered = element; + element.skeleton = skeleton; + element.childrenContainer = element; + element.componentName = tagName; + + if (skeleton.variant) { + var variant = skeleton.variant; + + if (this.isFunction(variant)) { + variant = variant(); + } + + if (satus.isArray(variant)) { + for (var i = 0, l = variant.length; i < l; i++) { + element.className += ' satus-' + tagName + '--' + variant[i]; + } + } else { + element.className += ' satus-' + tagName + '--' + variant; + } + } + + if (skeleton.id) { + element.id = skeleton.id; + } + + if (container) { + element.baseProvider = container.baseProvider; + } + + this.attr(element, skeleton.attr); + this.style(element, skeleton.style); + this.data(element, skeleton.data); + this.class(element, skeleton.class); + this.properties(element, skeleton.properties); + this.on(element, skeleton.on); + + element.storage = (function () { + var parent = element, + key = skeleton.storage || property || false, + value; + + if (satus.isFunction(key)) { + key = key(); + } + + if (skeleton.storage !== false) { + if (key) { + value = satus.storage.get(key); + } + + if (skeleton.hasOwnProperty('value') && value === undefined) { + value = skeleton.value; + } + } + + return Object.defineProperties({}, { + key: { + get: function () { + return key; + }, + set: function (string) { + key = string; + } + }, + value: { + get: function () { + return value; + }, + set: function (val) { + value = val; + + if (skeleton.storage !== false) { + satus.storage.set(key, val); + } + + parent.dispatchEvent(new CustomEvent('change')); + } + } + }); + }()); + + if (this.components[camelizedTagName]) { + this.components[camelizedTagName](element, skeleton); + } + + this.text(element.childrenContainer, skeleton.text); + this.prepend(skeleton.before, element.childrenContainer); + + if (prepend) { + this.prepend(element, container); + } else { + this.append(element, container); + } + + if (skeleton.hasOwnProperty('parentSkeleton') === false && container) { + skeleton.parentSkeleton = container.skeleton; + } + + satus.events.trigger('render', element); + + element.dispatchEvent(new CustomEvent('render')); + + container = element.childrenContainer || element; + } + + if (!element || element.renderChildren !== false) { + for (var key in skeleton) { + var item = skeleton[key]; + + if (key !== 'parentSkeleton' && key !== 'parentElement' && key !== 'parentObject' && key !== 'before') { + if (item && item.component) { + item.parentSkeleton = skeleton; + + if (element) { + item.parentElement = element; + } + + this.render(item, container, key, undefined, prepend); + } + } + } + } + + return element; +}; + + +/*-------------------------------------------------------------- +# SORT +--------------------------------------------------------------*/ + +satus.sort = function (array, order, property) { + var type; + + if (property) { + type = typeof array[0][property]; + } else { + type = typeof array[0]; + } + + if (order !== 'desc') { + if (type === 'number') { + if (property) { + return array.sort(function (a, b) { + return a[property] - b[property]; + }); + } else { + return array.sort(function (a, b) { + return a - b; + }); + } + } else if (type === 'string') { + if (property) { + return array.sort(function (a, b) { + return a[property].localeCompare(b[property]); + }); + } else { + return array.sort(function (a, b) { + return a.localeCompare(b); + }); + } + } + } else { + if (type === 'number') { + if (property) { + return array.sort(function (a, b) { + return b[property] - a[property]; + }); + } else { + return array.sort(function (a, b) { + return b - a; + }); + } + } else if (type === 'string') { + if (property) { + return array.sort(function (a, b) { + return b[property].localeCompare(a[property]); + }); + } else { + return array.sort(function (a, b) { + return b.localeCompare(a); + }); + } + } + } +}; + + +/*-------------------------------------------------------------- +# STORAGE +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# CLEAR +--------------------------------------------------------------*/ + +satus.storage.clear = function (callback) { + this.data = {}; + + chrome.storage.local.clear(function () { + satus.events.trigger('storage-clear'); + + if (callback) { + callback(); + } + }); +}; + + +/*-------------------------------------------------------------- +# GET +--------------------------------------------------------------*/ + +satus.storage.get = function (key, callback) { + var target = this.data; + + if (typeof key !== 'string') { + return; + } + + key = key.split('/').filter(function (value) { + return value != ''; + }); + + for (var i = 0, l = key.length; i < l; i++) { + if (satus.isset(target[key[i]])) { + target = target[key[i]]; + } else { + return undefined; + } + } + + if (typeof target === 'function') { + return target(); + } else { + return target; + } +}; + + +/*-------------------------------------------------------------- +# IMPORT +--------------------------------------------------------------*/ + +satus.storage.import = function (keys, callback) { + var self = this; + + if (typeof keys === 'function') { + callback = keys; + + keys = undefined; + } + + chrome.storage.local.get(keys, function (items) { + for (var key in items) { + self.data[key] = items[key]; + } + + satus.log('STORAGE: data was successfully imported'); + + satus.events.trigger('storage-import'); + + if (callback) { + callback(items); + } + }); +}; + + +/*-------------------------------------------------------------- +# REMOVE +--------------------------------------------------------------*/ + +satus.storage.remove = function (key) { + delete this.data[key]; + + chrome.storage.local.remove(key, function () { + satus.events.trigger('storage-remove'); + }); +}; + + +/*-------------------------------------------------------------- +# SET +--------------------------------------------------------------*/ + +satus.storage.set = function (key, value, callback) { + var items = {}, + target = this.data; + + if (typeof key !== 'string') { + return; + } + + key = key.split('/').filter(function (value) { + return value != ''; + }); + + for (var i = 0, l = key.length; i < l; i++) { + var item = key[i]; + + if (i < l - 1) { + + if (target[item]) { + target = target[item]; + } else { + target[item] = {}; + + target = target[item]; + } + } else { + target[item] = value; + } + } + + for (var key in this.data) { + if (typeof this.data[key] !== 'function') { + items[key] = this.data[key]; + } + } + + chrome.storage.local.set(items, function () { + satus.events.trigger('storage-set'); + + if (callback) { + callback(); + } + }); +}; + + +/*-------------------------------------------------------------- +# ON CHANGED +--------------------------------------------------------------*/ + +satus.storage.onchanged = function (callback) { + chrome.storage.onChanged.addListener(function (changes) { + for (var key in changes) { + callback(key, changes[key].newValue); + } + }); +}; + + +/*-------------------------------------------------------------- +# LAST +--------------------------------------------------------------*/ + +satus.last = function (variable) { + if (this.isArray(variable) || this.isNodeList(variable) || variable instanceof HTMLCollection) { + return variable[variable.length - 1]; + } +}; + + +/*-------------------------------------------------------------- +# LOCALIZATION +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# GET +--------------------------------------------------------------*/ + +satus.locale.get = function (string) { + return this.data[string] || string; +}; + + +/*-------------------------------------------------------------- +# IMPORT +---------------------------------------------------------------- +satus.locale.import(url, onload, onsuccess); +--------------------------------------------------------------*/ + +satus.locale.import = function (code, callback, path) { + var language = code || window.navigator.language; + + if (language.indexOf('en') === 0) { + language = 'en'; + } + + if (!path) { + path = '_locales/'; + } + + satus.fetch(chrome.runtime.getURL(path + language + '/messages.json'), function (response) { + for (var key in response) { + satus.locale.data[key] = response[key].message; + } + + satus.log('LOCALE: data was successfully imported'); + + if (callback) { + callback(); + } + }, function (success) { + satus.fetch(chrome.runtime.getURL(path + 'en/messages.json'), success, function () { + success(); + }); + }); +}; + + +/*-------------------------------------------------------------- +# LOG +--------------------------------------------------------------*/ + +satus.log = function () { + console.log.apply(null, arguments); +}; + + +/*-------------------------------------------------------------- +# STYLE +--------------------------------------------------------------*/ + +satus.style = function (element, object) { + if (object) { + for (var key in object) { + element.style[key] = object[key]; + } + } +}; + + +/*-------------------------------------------------------------- +# TEXT +--------------------------------------------------------------*/ + +satus.text = function (element, value) { + if (value) { + if (satus.isFunction(value)) { + value = value(); + } + + element.appendChild(document.createTextNode(this.locale.get(value))); + } +}; +/*-------------------------------------------------------------- +>>> MODAL +---------------------------------------------------------------- +# Confirm +--------------------------------------------------------------*/ + +satus.components.modal = function (component, skeleton) { + component.scrim = component.createChildElement('div', 'scrim'); + component.surface = component.createChildElement('div', 'surface'); + + component.close = function () { + var component = this; + + this.classList.add('satus-modal--closing'); + + setTimeout(function () { + component.remove(); + + component.dispatchEvent(new CustomEvent('close')); + }, Number(satus.css(this.surface, 'animation-duration').replace(/[^0-9.]/g, '')) * 1000); + }; + + component.scrim.addEventListener('click', function () { + this.parentNode.close(); + }); + + if (satus.isset(skeleton.content)) { + component.surface.content = component.surface.createChildElement('p', 'content'); + + if (satus.isObject(skeleton.content)) { + satus.render(skeleton.content, component.surface.content); + } else { + component.surface.content.textContent = satus.locale.get(skeleton.content); + } + } else { + component.childrenContainer = component.surface; + } + + if (satus.components.modal[skeleton.variant]) { + satus.components.modal[skeleton.variant](component, skeleton); + } +}; + + +/*-------------------------------------------------------------- +# CONFIRM +--------------------------------------------------------------*/ + +satus.components.modal.confirm = function (component, skeleton) { + component.surface.actions = satus.render({ + component: 'section', + variant: 'align-end' + }, component.surface); + + if (skeleton.buttons) { + for (var key in skeleton.buttons) { + var button = satus.render(skeleton.buttons[key], component.surface.actions); + + button.modalProvider = component; + } + } else { + satus.render({ + cancel: { + component: 'button', + text: 'cancel', + properties: { + modalProvider: component, + }, + on: { + click: function () { + this.modalProvider.dispatchEvent(new CustomEvent('cancel')); + this.modalProvider.close(); + } + } + }, + ok: { + component: 'button', + text: 'ok', + properties: { + modalProvider: component, + }, + on: { + click: function () { + this.modalProvider.dispatchEvent(new CustomEvent('confirm')); + this.modalProvider.close(); + } + } + } + }, component.surface.actions); + } +}; +/*-------------------------------------------------------------- +>>> GRID +--------------------------------------------------------------*/ + +satus.components.grid = function (component, skeleton) { + console.log(component, skeleton); +}; +/*-------------------------------------------------------------- +>>> TEXT FIELD +--------------------------------------------------------------*/ + +satus.components.textField = function (component, skeleton) { + var container = component.createChildElement('div', 'container'), + input = container.createChildElement('textarea'), + display = container.createChildElement('div', 'display'), + line_numbers = display.createChildElement('div', 'line-numbers'), + pre = display.createChildElement('pre'), + selection = display.createChildElement('div', 'selection'), + cursor = display.createChildElement('div', 'cursor'), + hiddenValue = container.createChildElement('pre', 'hidden-value'); + + component.placeholder = skeleton.placeholder; + component.input = input; + component.display = display; + component.line_numbers = line_numbers; + component.pre = pre; + component.hiddenValue = hiddenValue; + component.selection = selection; + component.cursor = cursor; + component.syntax = { + current: 'text', + handlers: { + regex: function (value, target) { + var regex_token = /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g, + char_class_token = /[^\\-]+|-|\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)/g, + char_class_parts = /^(\[\^?)(]?(?:[^\\\]]+|\\[\S\s]?)*)(]?)$/, + quantifier = /^(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??$/, + matches = value.match(regex_token); + + function create(type, string) { + var span = document.createElement('span'); + + span.className = type; + span.textContent = string; + + target.appendChild(span); + } + + for (var i = 0, l = matches.length; i < l; i++) { + var match = matches[i]; + + if (match[0] === '[') { + create('character-class', match); + } else if (match[0] === '(') { + create('group', match); + } else if (match[0] === ')') { + create('group', match); + } else if (match[0] === '\\' || match === '^') { + create('anchor', match); + } else if (quantifier.test(match)) { + create('quantifier', match); + } else if (match === '|' || match === '.') { + create('metasequence', match); + } else { + create('text', match); + } + } + } + }, + set: function (syntax) { + if (this.handlers[syntax]) { + this.current = syntax; + } else { + this.current = 'text'; + } + + pre.update(); + } + }; + component.focus = function () { + this.input.focus(); + }; + + if (satus.isset(skeleton.cols)) { + input.cols = skeleton.cols; + } + + if (satus.isset(skeleton.rows)) { + input.rows = skeleton.rows; + } + + Object.defineProperty(component, 'value', { + get: function () { + return this.input.value; + }, + set: function (value) { + this.input.value = value; + } + }); + + if (skeleton.syntax) { + component.syntax.set(skeleton.syntax); + } + + selection.setAttribute('disabled', ''); + + line_numbers.update = function () { + var component = this.parentNode.parentNode.parentNode, + count = component.input.value.split('\n').length; + + if (count !== this.children.length) { + satus.empty(this); + + for (var i = 1; i <= count; i++) { + var span = document.createElement('span'); + + span.textContent = i; + + this.appendChild(span); + } + } + + component.input.style.paddingLeft = this.offsetWidth + 'px'; + }; + + pre.update = function () { + var component = this.parentNode.parentNode.parentNode, + handler = component.syntax.handlers[component.syntax.current], + value = component.value || ''; + + for (var i = this.childNodes.length - 1; i > -1; i--) { + this.childNodes[i].remove(); + } + + if (handler) { + handler(value, this); + } else { + this.textContent = value; + } + + if (value.length === 0) { + var placeholder = component.placeholder; + + if (typeof placeholder === 'function') { + placeholder = component.placeholder(); + } else { + placeholder = satus.locale.get(placeholder); + } + + this.textContent = placeholder; + } + }; + + cursor.update = function () { + var component = this.parentNode.parentNode.parentNode, + input = component.input, + value = input.value, + rows_count = value.split('\n').length, + start = input.selectionStart, + end = input.selectionEnd, + rows = value.slice(0, start).split('\n'), + top = 0; + + this.style.animation = 'none'; + + if (input.selectionDirection === 'forward') { + component.hiddenValue.textContent = value.substring(0, end); + } else { + component.hiddenValue.textContent = value.substring(0, start); + } + + top = component.hiddenValue.offsetHeight; + + component.hiddenValue.textContent = satus.last(rows); + + top -= component.hiddenValue.offsetHeight; + + this.style.top = top + 'px'; + this.style.left = component.hiddenValue.offsetWidth + component.line_numbers.offsetWidth + 'px'; + + if (start === end) { + component.selection.setAttribute('disabled', ''); + } else { + component.selection.removeAttribute('disabled'); + + /*component.hiddenValue.textContent = value.substring(0, start); + + component.selection.style.left = component.hiddenValue.offsetWidth - input.scrollLeft + 'px'; + + component.hiddenValue.textContent = value.substring(start, end); + + component.selection.style.width = component.hiddenValue.offsetWidth + 'px';*/ + } + + this.style.animation = ''; + + component.hiddenValue.textContent = ''; + }; + + document.addEventListener('selectionchange', function (event) { + component.line_numbers.update(); + component.pre.update(); + component.cursor.update(); + }); + + input.addEventListener('input', function () { + var component = this.parentNode.parentNode; + + component.storage.value = this.value; + + component.line_numbers.update(); + component.pre.update(); + component.cursor.update(); + }); + + input.addEventListener('scroll', function (event) { + var component = this.parentNode.parentNode; + + component.display.style.top = -this.scrollTop + 'px'; + component.display.style.left = -this.scrollLeft + 'px'; + + component.line_numbers.update(); + component.pre.update(); + component.cursor.update(); + }); + + component.addEventListener('change', function () { + this.line_numbers.update(); + this.pre.update(); + this.cursor.update(); + }); + + component.value = component.storage.value || ''; + + component.addEventListener('render', function () { + component.line_numbers.update(); + component.pre.update(); + component.cursor.update(); + }); + + if (skeleton.on) { + for (var type in skeleton.on) { + input.addEventListener(type, function (event) { + this.parentNode.parentNode.dispatchEvent(new Event(event.type)); + }); + } + } +}; +/*-------------------------------------------------------------- +>>> CHART +---------------------------------------------------------------- +# Core + # Bar +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# CORE +--------------------------------------------------------------*/ + +satus.components.chart = function (component, skeleton) { + var type = skeleton.type; + + if (this.chart[type]) { + component.classList.add('satus-chart--' + type); + + this.chart[type](component, skeleton); + } +}; + + +/*-------------------------------------------------------------- +# BAR +--------------------------------------------------------------*/ + +satus.components.chart.bar = function (component, skeleton) { + var labels = skeleton.labels, + datasets = skeleton.datasets, + bars = []; + + if (satus.isFunction(labels)) { + labels = labels(); + } + + if (satus.isFunction(datasets)) { + datasets = datasets(); + } + + if (satus.isArray(labels)) { + var container = component.createChildElement('div', 'labels'); + + for (var i = 0, l = labels.length; i < l; i++) { + var label = labels[i], + section = container.createChildElement('div', 'section'); + + section.textContent = label; + } + } + + if (satus.isArray(datasets)) { + var container = component.createChildElement('div', 'bars'); + + for (var i = 0, l = datasets.length; i < l; i++) { + var dataset = datasets[i]; + + for (var j = 0, k = dataset.data.length; j < k; j++) { + if (!satus.isElement(bars[j])) { + bars.push(container.createChildElement('div', 'bar')); + } + + var piece = bars[j].createChildElement('div', 'piece'); + + piece.title = dataset.label; + piece.style.height = dataset.data[j] + '%'; + piece.style.backgroundColor = 'rgb(' + dataset.color.join(',') + ')'; + } + } + } +}; +/*-------------------------------------------------------------- +>>> SELECT +--------------------------------------------------------------*/ + +satus.components.select = function (component, skeleton) { + var content = component.createChildElement('div', 'content'); + + component.childrenContainer = content; + component.valueElement = document.createElement('span'); + component.selectElement = document.createElement('select'); + + component.valueElement.className = 'satus-select__value'; + + component.appendChild(component.valueElement); + component.appendChild(component.selectElement); + + component.options = skeleton.options || []; + + if (satus.isFunction(component.options)) { + component.options = component.options(); + } + + for (var i = 0, l = component.options.length; i < l; i++) { + var option = document.createElement('option'); + + option.value = component.options[i].value; + + satus.text(option, component.options[i].text); + + component.selectElement.appendChild(option); + } + + Object.defineProperty(component, 'value', { + get() { + return this.selectElement.value; + }, + set(value) { + this.selectElement.value = value; + } + }); + + component.render = function () { + satus.empty(this.valueElement); + + if (this.selectElement.options[this.selectElement.selectedIndex]) { + satus.text(this.valueElement, this.selectElement.options[this.selectElement.selectedIndex].text); + } + + this.dataset.value = this.value; + }; + + component.selectElement.addEventListener('change', function () { + var component = this.parentNode; + + component.storage.value = this.value; + + component.render(); + }); + + component.value = component.storage.value || component.options[0].value; + + component.render(); +}; +/*-------------------------------------------------------------- +>>> DIVIDER +--------------------------------------------------------------*/ + +satus.components.divider = function () {}; +/*-------------------------------------------------------------- +>>> SECTION +--------------------------------------------------------------*/ + +satus.components.section = function (component, skeleton) { + if (satus.isString(skeleton.title)) { + component.dataset.title = satus.locale.get(skeleton.title); + } +}; +/*-------------------------------------------------------------- +>>> BASE +--------------------------------------------------------------*/ + +satus.components.base = function (component) { + component.baseProvider = component; + component.layers = []; +}; +/*-------------------------------------------------------------- +>>> ALERT +--------------------------------------------------------------*/ + +satus.components.alert = function (component, skeleton) {}; +/*-------------------------------------------------------------- +>>> TIME +--------------------------------------------------------------*/ + +satus.components.time = function (component, skeleton) { + var select_skeleton = Object.assign({}, skeleton); + + select_skeleton.component = 'select'; + select_skeleton.options = []; + + if (satus.isFunction(select_skeleton.hour12)) { + select_skeleton.hour12 = select_skeleton.hour12(); + } + + for (var i = 0, l = 24; i < l; i++) { + var hour = i, + value = i; + + if (select_skeleton.hour12 === true && i > 12) { + hour -= 12; + } + + if (hour < 10) { + hour = '0' + hour; + value = '0' + value; + } + + if (select_skeleton.hour12 === true) { + if (i > 12) { + hour += ':00 pm'; + } else { + hour += ':00 am'; + } + } else { + hour += ':00' + } + + select_skeleton.options.push({ + text: hour, + value: value + ':00' + }); + } + + satus.components.select(component, select_skeleton); + + component.classList.add('satus-select'); +}; +/*-------------------------------------------------------------- +>>> SIDEBAR +--------------------------------------------------------------*/ + +satus.components.sidebar = function (component, skeleton) {}; +/*-------------------------------------------------------------- +>>> LAYERS +--------------------------------------------------------------*/ + +satus.components.layers = function (component, skeleton) { + component.path = []; + component.renderChildren = false; + component.baseProvider.layers.push(component); + + component.back = function () { + if (this.path.length > 1) { + this.path.pop(); + + this.open(this.path[this.path.length - 1], false); + } + }; + + component.open = function (skeleton, history) { + var previous_layer = satus.last(this.querySelectorAll('.satus-layers__layer')), + layer = this.createChildElement('div', 'layer'); + + if (history !== false) { + if (previous_layer) { + previous_layer.style.animation = 'fadeOutLeft 100ms linear forwards'; + layer.style.animation = 'fadeInRight 100ms linear forwards'; + } + + this.path.push(skeleton); + } else { + previous_layer.style.animation = 'fadeOutRight 100ms linear forwards'; + layer.style.animation = 'fadeInLeft 100ms linear forwards'; + } + + if (previous_layer) { + setTimeout(function () { + previous_layer.remove(); + }, satus.getAnimationDuration(previous_layer)); + } + + layer.skeleton = skeleton; + layer.baseProvider = this.baseProvider; + + satus.render(skeleton, layer, undefined, skeleton.component === 'layers'); + + this.dispatchEvent(new Event('open')); + }; + + component.update = function () { + var layer = this.querySelector('.satus-layers__layer'); + + satus.empty(layer); + satus.render(layer.skeleton, layer); + }; + + component.open(skeleton); +}; +/*-------------------------------------------------------------- +>>> LIST +--------------------------------------------------------------*/ + +satus.components.list = function (component, skeleton) { + for (var i = 0, l = skeleton.items.length; i < l; i++) { + var li = component.createChildElement('div', 'item'), + item = skeleton.items[i]; + + for (var j = 0, k = item.length; j < k; j++) { + var child = item[j]; + + if (satus.isObject(child)) { + satus.render(child, li); + } else { + var span = li.createChildElement('span'); + + span.textContent = satus.locale.get(child); + } + } + } +}; +/*-------------------------------------------------------------- +>>> COLOR PICKER +--------------------------------------------------------------*/ + +satus.components.colorPicker = function (component, skeleton) { + var component_content = component.createChildElement('div', 'content'), + component_value = component.createChildElement('span', 'value'); + + component.childrenContainer = component_content; + component.valueElement = component_value; + + component.className = 'satus-button'; + + component.addEventListener('click', function () { + var rgb = this.rgb, + hsl = satus.color.rgbToHsl(rgb), + s = hsl[1] / 100, + l = hsl[2] / 100; + + s *= l < .5 ? l : 1 - l; + + var v = l + s; + + s = 2 * s / (l + s); + + satus.render({ + component: 'modal', + variant: 'color-picker', + value: hsl, + parentElement: this, + + palette: { + component: 'div', + class: 'satus-color-picker__palette', + style: { + 'backgroundColor': 'hsl(' + hsl[0] + 'deg, 100%, 50%)' + }, + on: { + mousedown: function () { + var palette = this, + rect = this.getBoundingClientRect(), + cursor = this.children[0]; + + function mousemove(event) { + var hsl = palette.skeleton.parentSkeleton.storage.value, + x = event.clientX - rect.left, + y = event.clientY - rect.top, + s; + + x = Math.min(Math.max(x, 0), rect.width) / (rect.width / 100); + y = Math.min(Math.max(y, 0), rect.height) / (rect.height / 100); + + var v = 100 - y, + l = (2 - x / 100) * v / 2; + + hsl[1] = x * v / (l < 50 ? l * 2 : 200 - l * 2); + hsl[2] = l; + + cursor.style.left = x + '%'; + cursor.style.top = y + '%'; + + palette.nextSibling.children[0].style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; + + event.preventDefault(); + } + + function mouseup() { + window.removeEventListener('mousemove', mousemove); + window.removeEventListener('mouseup', mouseup); + } + + window.addEventListener('mousemove', mousemove); + window.addEventListener('mouseup', mouseup); + } + }, + + cursor: { + component: 'div', + class: 'satus-color-picker__cursor', + style: { + 'left': s * 100 + '%', + 'top': 100 - v * 100 + '%' + } + } + }, + section: { + component: 'section', + variant: 'color', + + color: { + component: 'div', + class: 'satus-color-picker__color', + style: { + 'backgroundColor': 'rgb(' + this.rgb.join(',') + ')' + } + }, + hue: { + component: 'slider', + class: 'satus-color-picker__hue', + storage: false, + value: hsl[0], + max: 360, + on: { + change: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + hsl = modal.storage.value; + + hsl[0] = this.values[0]; + + this.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; + this.parentSkeletonNode.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg, 100%, 50%)'; + } + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + reset: { + component: 'button', + text: 'reset', + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + component = modal.parentSkeleton; + + component.rgb = component.skeleton.value; + + component.storage.value = component.rgb; + + component.valueElement.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; + + modal.rendered.close(); + } + } + }, + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.skeleton.parentSkeleton.parentSkeleton.rendered.close(); + } + } + }, + ok: { + component: 'button', + text: 'OK', + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + component = modal.parentSkeleton; + + component.rgb = satus.color.hslToRgb(modal.storage.value); + + component.storage.value = component.rgb; + + component.valueElement.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; + + modal.rendered.close(); + } + } + } + } + }, this.baseProvider.layers[0]); + }); + + component.addEventListener('render', function () { + component.rgb = this.storage.value || [0, 100, 50]; + + component_value.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; + }); +}; + +satus.components.colorPicker = function (component, skeleton) { + component.childrenContainer = component.createChildElement('div', 'content'); + + component.color = (function (element) { + var array; + + Object.defineProperty(element, 'value', { + get: function () { + return array; + }, + set: function (value) { + array = value; + + this.parentNode.storage.value = array; + + element.style.backgroundColor = 'rgb(' + value.join(',') + ')'; + } + }); + + element.value = component.storage.value || component.skeleton.value || [0, 0, 0]; + + return element; + })(component.createChildElement('span', 'value')); + + component.addEventListener('click', function () { + var hsl = satus.color.rgbToHsl(this.color.value), + s = hsl[1] / 100, + l = hsl[2] / 100; + + s *= l < .5 ? l : 1 - l; + + var v = l + s; + + s = 2 * s / (l + s); + + satus.render({ + component: 'modal', + variant: 'color-picker', + value: hsl, + parentElement: this, + + palette: { + component: 'div', + class: 'satus-color-picker__palette', + style: { + 'backgroundColor': 'hsl(' + hsl[0] + 'deg, 100%, 50%)' + }, + on: { + mousedown: function (event) { + if (event.button !== 0) { + return false; + } + + var palette = this, + rect = this.getBoundingClientRect(), + cursor = this.children[0]; + + function mousemove(event) { + var hsl = palette.skeleton.parentSkeleton.value, + x = event.clientX - rect.left, + y = event.clientY - rect.top, + s; + + x = Math.min(Math.max(x, 0), rect.width) / (rect.width / 100); + y = Math.min(Math.max(y, 0), rect.height) / (rect.height / 100); + + var v = 100 - y, + l = (2 - x / 100) * v / 2; + + hsl[1] = x * v / (l < 50 ? l * 2 : 200 - l * 2); + hsl[2] = l; + + cursor.style.left = x + '%'; + cursor.style.top = y + '%'; + + palette.nextSibling.children[0].style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; + + event.preventDefault(); + } + + function mouseup() { + window.removeEventListener('mousemove', mousemove); + window.removeEventListener('mouseup', mouseup); + } + + window.addEventListener('mousemove', mousemove); + window.addEventListener('mouseup', mouseup); + } + }, + + cursor: { + component: 'div', + class: 'satus-color-picker__cursor', + style: { + 'left': s * 100 + '%', + 'top': 100 - v * 100 + '%' + } + } + }, + section: { + component: 'section', + variant: 'color', + + color: { + component: 'div', + class: 'satus-color-picker__color', + style: { + 'backgroundColor': 'rgb(' + this.color.value.join(',') + ')' + } + }, + hue: { + component: 'slider', + class: 'satus-color-picker__hue', + storage: false, + value: hsl[0], + max: 360, + on: { + input: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + hsl = modal.value; + + hsl[0] = this.storage.value; + + this.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; + this.parentNode.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg, 100%, 50%)'; + } + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + reset: { + component: 'button', + text: 'reset', + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + component = modal.parentElement; + + component.color.value = component.skeleton.value || [0, 0, 0]; + + modal.rendered.close(); + } + } + }, + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.skeleton.parentSkeleton.parentSkeleton.rendered.close(); + } + } + }, + ok: { + component: 'button', + text: 'OK', + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + component = modal.parentElement; + + component.color.value = satus.color.hslToRgb(modal.value); + + modal.rendered.close(); + } + } + } + } + }, this.baseProvider.layers[0]); + }); +}; +/*-------------------------------------------------------------- +>>> RADIO +--------------------------------------------------------------*/ + +satus.components.radio = function (component, skeleton) { + component.nativeControl = component.createChildElement('input', 'input'); + + component.createChildElement('i'); + + component.childrenContainer = component.createChildElement('div', 'content'); + + component.nativeControl.type = 'radio'; + + if (skeleton.group) { + component.storage.key = skeleton.group; + component.nativeControl.name = skeleton.group; + } + + if (skeleton.value) { + component.nativeControl.value = skeleton.value; + } + + component.storage.value = satus.storage.get(component.storage.key); + + if (satus.isset(component.storage.value)) { + component.nativeControl.checked = component.storage.value === skeleton.value; + } else if (skeleton.checked) { + component.nativeControl.checked = true; + } + + component.nativeControl.addEventListener('change', function () { + var component = this.parentNode; + + component.storage.value = this.value; + }); +}; +/*-------------------------------------------------------------- +>>> SLIDER +--------------------------------------------------------------*/ + +satus.components.slider = function (component, skeleton) { + var content = component.createChildElement('div', 'content'), + track_container = component.createChildElement('div', 'track-container'), + input = track_container.createChildElement('input', 'input'); + + component.childrenContainer = content; + component.input = input; + component.track = track_container.createChildElement('div', 'track'); + + input.type = 'range'; + input.min = skeleton.min || 0; + input.max = skeleton.max || 1; + input.step = skeleton.step || 1; + input.value = component.storage.value || skeleton.value || 0; + + input.addEventListener('input', function () { + var component = this.parentNode.parentNode; + + component.storage.value = Number(this.value); + + component.update(); + }); + + component.update = function () { + var input = this.input; + + this.track.style.width = 100 / (input.max - input.min) * (input.value - input.min) + '%'; + }; + + component.update(); + + if (skeleton.on) { + for (var type in skeleton.on) { + input.addEventListener(type, function (event) { + this.parentNode.parentNode.dispatchEvent(new Event(event.type)); + }); + } + } +}; +/*-------------------------------------------------------------- +>>> TABS +--------------------------------------------------------------*/ + +satus.components.tabs = function (component, skeleton) { + var tabs = skeleton.items, + value = skeleton.value; + + if (satus.isFunction(tabs)) { + tabs = tabs(); + } + + if (satus.isFunction(value)) { + value = value(); + } + + for (var i = 0, l = tabs.length; i < l; i++) { + var tab = tabs[i], + button = component.createChildElement('button'); + + button.addEventListener('click', function () { + var component = this.parentNode, + index = satus.elementIndex(this); + + component.value = index; + + component.style.setProperty('--satus-tabs-current', index); + }); + + satus.text(button, tab); + } + + component.style.setProperty('--satus-tabs-count', tabs.length); + component.style.setProperty('--satus-tabs-current', value || 0); +}; +/*-------------------------------------------------------------- +>>> SHORTCUT +--------------------------------------------------------------*/ + +satus.components.shortcut = function (component, skeleton) { + component.childrenContainer = component.createChildElement('div', 'content'); + component.valueElement = component.createChildElement('div', 'value'); + + component.className = 'satus-button'; + + component.render = function (parent) { + var self = this, + parent = parent || self.primary, + children = parent.children; + + satus.empty(parent); + + function createElement(name) { + var element = document.createElement('div'); + + element.className = 'satus-shortcut__' + name; + + parent.appendChild(element); + + return element; + } + + if (this.data.alt) { + createElement('key').textContent = 'Alt'; + } + + if (this.data.ctrl) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + createElement('key').textContent = 'Ctrl'; + } + + if (this.data.shift) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + createElement('key').textContent = 'Shift'; + } + + for (var code in this.data.keys) { + var key = this.data.keys[code].key, + arrows = ['ArrowUp', 'ArrowRight', 'ArrowDown', 'ArrowLeft'], + index = arrows.indexOf(key); + + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + if (index !== -1) { + createElement('key').textContent = ['↑', '→', '↓', '←'][index]; + } else if (key === ' ') { + createElement('key').textContent = '␣'; + } else if (key) { + createElement('key').textContent = key.toUpperCase(); + } + } + + if (this.data.wheel) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + var mouse = createElement('mouse'), + div = document.createElement('div'); + + mouse.appendChild(div); + + mouse.className += ' ' + (this.data.wheel > 0); + } + + if (this.data.click) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + var mouse = createElement('mouse'), + div = document.createElement('div'); + + mouse.appendChild(div); + + mouse.className += ' click'; + } + + if (this.data.middle) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + var mouse = createElement('mouse'), + div = document.createElement('div'); + + mouse.appendChild(div); + + mouse.className += ' middle'; + } + + if (this.data.context) { + if (children.length && children[children.length - 1].className.indexOf('plus') === -1) { + createElement('plus'); + } + + var mouse = createElement('mouse'), + div = document.createElement('div'); + + mouse.appendChild(div); + + mouse.className += ' context'; + } + }; + + component.keydown = function (event) { + event.preventDefault(); + event.stopPropagation(); + + component.data = { + alt: event.altKey, + ctrl: event.ctrlKey, + shift: event.shiftKey, + keys: {} + }; + + if (['control', 'alt', 'altgraph', 'shift'].indexOf(event.key.toLowerCase()) === -1) { + component.data.keys[event.keyCode] = { + code: event.code, + key: event.key + }; + } + + component.data.wheel = 0; + + component.render(); + + return false; + }; + + if (skeleton.wheel !== false) { + component.mousewheel = function (event) { + event.stopPropagation(); + + if ( + ( + component.data.wheel === 0 && + ( + Object.keys(component.data.keys).length === 0 && + component.data.alt === false && + component.data.ctrl === false && + component.data.shift === false + ) + ) || + component.data.wheel < 0 && event.deltaY > 0 || + component.data.wheel > 0 && event.deltaY < 0) { + component.data = { + alt: false, + ctrl: false, + shift: false, + keys: {} + }; + } + + component.data.wheel = event.deltaY < 0 ? -1 : 1; + + component.render(); + + return false; + }; + } + + component.addEventListener('click', function () { + satus.render({ + component: 'modal', + properties: { + parent: this + }, + on: { + close: function () { + window.removeEventListener('keydown', component.keydown); + window.removeEventListener('wheel', component.mousewheel); + } + }, + + primary: { + component: 'div', + class: 'satus-shortcut__primary', + on: { + render: function () { + component.primary = this; + + if (component.skeleton.mouseButtons === true) { + this.addEventListener('mousedown', function (event) { + if ( + component.data.click && event.button === 0 || + component.data.middle && event.button === 1 + ) { + component.data = { + alt: false, + ctrl: false, + shift: false, + keys: {} + }; + } + + component.data.click = false; + component.data.middle = false; + component.data.context = false; + + if (event.button === 0) { + component.data.click = true; + + component.render(); + } else if (event.button === 1) { + component.data.middle = true; + + component.render(); + } + }); + + this.addEventListener('contextmenu', function (event) { + event.preventDefault(); + event.stopPropagation(); + + if (component.data.context) { + component.data = { + alt: false, + ctrl: false, + shift: false, + keys: {} + }; + } + + component.data.context = true; + component.data.middle = false; + component.data.click = false; + + component.render(); + + return false; + }); + } + + component.render(); + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + reset: { + component: 'button', + text: 'reset', + on: { + click: function () { + var component = this.parentNode.parentNode.parentNode.parent; + + component.data = component.skeleton.value || {}; + + component.render(component.valueElement); + + satus.storage.remove(component.storage); + + this.parentNode.parentNode.parentNode.close(); + + window.removeEventListener('keydown', component.keydown); + window.removeEventListener('wheel', component.mousewheel); + } + } + }, + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + component.data = satus.storage.get(component.storage) || component.skeleton.value || {}; + + component.render(component.valueElement); + + this.parentNode.parentNode.parentNode.close(); + + window.removeEventListener('keydown', component.keydown); + window.removeEventListener('wheel', component.mousewheel); + } + } + }, + save: { + component: 'button', + text: 'save', + on: { + click: function () { + component.storage.value = component.data; + + component.render(component.valueElement); + + this.parentNode.parentNode.parentNode.close(); + + window.removeEventListener('keydown', component.keydown); + window.removeEventListener('wheel', component.mousewheel); + } + } + } + } + }, this.baseProvider); + + window.addEventListener('keydown', this.keydown); + window.addEventListener('wheel', this.mousewheel); + }); + + component.data = component.storage.value || { + alt: false, + ctrl: false, + shift: false, + keys: {}, + wheel: 0 + }; + + component.render(component.valueElement); +}; +/*-------------------------------------------------------------- +>>> CHECKBOX +--------------------------------------------------------------*/ + +satus.components.checkbox = function (component, skeleton) { + component.input = component.createChildElement('input'); + component.input.type = 'checkbox'; + + component.checkmark = component.createChildElement('div', 'checkmark'); + + component.childrenContainer = component.createChildElement('div', 'content'); + + component.dataset.value = component.storage.value || skeleton.value; + component.input.checked = component.storage.value || skeleton.value; + + component.input.addEventListener('change', function () { + var component = this.parentNode; + + if (this.checked === true) { + component.storage.value = true; + component.dataset.value = 'true'; + } else { + component.storage.value = false; + component.dataset.value = 'false'; + } + }); +}; +/*-------------------------------------------------------------- +>>> SWITCH +--------------------------------------------------------------*/ + +satus.components.switch = function (component, skeleton) { + var value = component.storage.value || skeleton.value; + + if (satus.isFunction(value)) { + value = value(); + } + + component.childrenContainer = component.createChildElement('div', 'content'); + + component.createChildElement('i'); + + component.dataset.value = value; + + component.addEventListener('click', function () { + if (this.dataset.value === 'true') { + this.dataset.value = 'false'; + this.storage.value = false; + } else { + this.dataset.value = 'true'; + this.storage.value = true; + } + }, true); +}; +/*-------------------------------------------------------------- +>>> CONTEXT MENU +--------------------------------------------------------------*/ + +satus.events.on('render', function (component) { + if (component.skeleton.contextMenu) { + component.addEventListener('contextmenu', function (event) { + var base = this.baseProvider, + base_rect = base.getBoundingClientRect(), + x = event.clientX - base_rect.left, + y = event.clientY - base_rect.top, + modal = satus.render({ + component: 'modal', + variant: 'contextmenu', + parentSkeleton: this.skeleton, + baseProvider: base + }, base); + + if (base_rect.width - x < 200) { + x = base_rect.width - x; + + if (x + 200 > base_rect.width) { + x = 0; + } + + modal.childrenContainer.style.right = x + 'px'; + } else { + modal.childrenContainer.style.left = x + 'px'; + } + + modal.childrenContainer.style.top = y + 'px'; + + this.skeleton.contextMenu.parentSkeleton = this.skeleton; + + satus.render(this.skeleton.contextMenu, modal.childrenContainer); + + event.preventDefault(); + event.stopPropagation(); + + return false; + }); + } +}); +/*-------------------------------------------------------------- +>>> SORTABLE +--------------------------------------------------------------*/ + +satus.events.on('render', function (component) { + if (component.skeleton.sortable === true) { + component.addEventListener('mousedown', function (event) { + if (event.button !== 0) { + return false; + } + + var component = this, + rect = this.getBoundingClientRect(), + x = event.clientX, + y = event.clientY, + offset_x = event.clientX - rect.left, + offset_y = event.clientY - rect.top, + ghost = satus.clone(this), + children = this.parentNode.children, + appended = false; + + ghost.classList.add('satus-sortable__ghost'); + + function mousemove(event) { + if (appended === false && (Math.abs(event.clientX - x) > 4 || Math.abs(event.clientY - y) > 4)) { + appended = true; + + component.classList.add('satus-sortable__chosen'); + + component.baseProvider.appendChild(ghost); + } + + ghost.style.transform = 'translate(' + (event.clientX - offset_x) + 'px, ' + (event.clientY - offset_y) + 'px)'; + } + + function mouseup(event) { + component.classList.remove('satus-sortable__chosen'); + ghost.remove(); + + window.removeEventListener('mousemove', mousemove, true); + window.removeEventListener('mouseup', mouseup, true); + + for (var i = 0, l = children.length; i < l; i++) { + var child = children[i]; + + if (child !== component) { + child.removeEventListener('mouseover', siblingMouseOver); + } + } + + component.dispatchEvent(new CustomEvent('sort')); + + event.stopPropagation(); + + return false; + } + + window.addEventListener('mousemove', mousemove, { + passive: true, + capture: true + }); + + window.addEventListener('mouseup', mouseup, { + passive: true, + capture: true + }); + + function siblingMouseOver(event) { + var parent = this.parentNode, + y = event.layerY / (this.offsetHeight / 100); + + if (y < 50 && this.previousSibling !== component || y >= 50 && this.nextSibling === component) { + parent.insertBefore(component, this); + } else { + parent.insertBefore(component, this.nextSibling); + } + } + + for (var i = 0, l = children.length; i < l; i++) { + var child = children[i]; + + if (child !== component) { + child.addEventListener('mouseover', siblingMouseOver); + } + } + + event.stopPropagation(); + event.preventDefault(); + + return false; + }); + } +}); +/*-------------------------------------------------------------- +>>> MANIFEST +--------------------------------------------------------------*/ + +satus.manifest = function () { + var object = {}; + + if (this.isset('chrome.runtime.getManifest')) { + object = chrome.runtime.getManifest(); + } + + return object; +}; +/*-------------------------------------------------------------- +>>> COLOR: +---------------------------------------------------------------- +# String to array +# RGB to HSL +# HUE to RGB +# HSL to RGB +--------------------------------------------------------------*/ + +satus.color = {}; + + +/*-------------------------------------------------------------- +# STRING TO ARRAY +--------------------------------------------------------------*/ + +satus.color.stringToArray = function (string) { + var match = string.match(/[0-9.]+/g); + + if (match) { + for (var i = 0, l = match.length; i < l; i++) { + match[i] = parseFloat(match[i]); + } + } + + return match; +}; + + +/*-------------------------------------------------------------- +# RGB TO HSL +--------------------------------------------------------------*/ + +satus.color.rgbToHsl = function (array) { + var r = array[0] / 255, + g = array[1] / 255, + b = array[2] / 255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + h = 0, + s = 0, + l = (min + max) / 2; + + if (min === max) { + h = 0; + s = 0; + } else { + var delta = max - min; + + s = l <= 0.5 ? delta / (max + min) : delta / (2 - max - min); + + if (max === r) { + h = (g - b) / delta + (g < b ? 6 : 0); + } else if (max === g) { + h = (b - r) / delta + 2; + } else if (max === b) { + h = (r - g) / delta + 4; + } + + h /= 6; + } + + h *= 360; + s *= 100; + l *= 100; + + if (array.length === 3) { + return [h, s, l]; + } else { + return [h, s, l, array[3]]; + } +}; + + +/*-------------------------------------------------------------- +# HUE TO RGB +--------------------------------------------------------------*/ + +satus.color.hueToRgb = function (array) { + var t1 = array[0], + t2 = array[1], + hue = array[2]; + + if (hue < 0) { + hue += 6; + } + + if (hue >= 6) { + hue -= 6; + } + + if (hue < 1) { + return (t2 - t1) * hue + t1; + } else if (hue < 3) { + return t2; + } else if (hue < 4) { + return (t2 - t1) * (4 - hue) + t1; + } else { + return t1; + } +}; + + +/*-------------------------------------------------------------- +# HSL TO RGB +--------------------------------------------------------------*/ + +satus.color.hslToRgb = function (array) { + var h = array[0] / 360, + s = array[1] / 100, + l = array[2] / 100, + r, g, b; + + if (s == 0) { + r = g = b = l; + } else { + var hue2rgb = function (p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + }; + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; +}; +/*-------------------------------------------------------------- +>>> USER +---------------------------------------------------------------- +# OS + # Name + # Bitness +# Browser + # Name + # Version + # Platform + # Manifest + # Languages + # Cookies + # Flash + # Java + # Audio + # Video + # WebGL +# Device + # Screen + # RAM + # GPU + # Cores + # Touch + # Connection +--------------------------------------------------------------*/ + +satus.user = { + browser: {}, + device: {}, + os: {} +}; + +/*-------------------------------------------------------------- +# OS +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# NAME +--------------------------------------------------------------*/ + +satus.user.os.name = function () { + var app_version = navigator.appVersion; + + if (app_version.indexOf('Win') !== -1) { + if (app_version.match(/(Windows 10.0|Windows NT 10.0)/)) { + return 'Windows 10'; + } else if (app_version.match(/(Windows 8.1|Windows NT 6.3)/)) { + return 'Windows 8.1'; + } else if (app_version.match(/(Windows 8|Windows NT 6.2)/)) { + return 'Windows 8'; + } else if (app_version.match(/(Windows 7|Windows NT 6.1)/)) { + return 'Windows 7'; + } else if (app_version.match(/(Windows NT 6.0)/)) { + return 'Windows Vista'; + } else if (app_version.match(/(Windows NT 5.1|Windows XP)/)) { + return 'Windows XP'; + } else { + return 'Windows'; + } + } else if (app_version.indexOf('(iPhone|iPad|iPod)') !== -1) { + return 'iOS'; + } else if (app_version.indexOf('Mac') !== -1) { + return 'macOS'; + } else if (app_version.indexOf('Android') !== -1) { + return 'Android'; + } else if (app_version.indexOf('OpenBSD') !== -1) { + return 'OpenBSD'; + } else if (app_version.indexOf('SunOS') !== -1) { + return 'SunOS'; + } else if (app_version.indexOf('Linux') !== -1) { + return 'Linux'; + } else if (app_version.indexOf('X11') !== -1) { + return 'UNIX'; + } +}; + + +/*-------------------------------------------------------------- +# BITNESS +--------------------------------------------------------------*/ + +satus.user.os.bitness = function () { + if (navigator.appVersion.match(/(Win64|x64|x86_64|WOW64)/)) { + return '64-bit'; + } else { + return '32-bit'; + } +}; + + +/*-------------------------------------------------------------- +# BROWSER +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# NAME +--------------------------------------------------------------*/ + +satus.user.browser.name = function () { + var user_agent = navigator.userAgent; + + if (user_agent.indexOf('Opera') !== -1) { + return 'Opera'; + } else if (user_agent.indexOf('Vivaldi') !== -1) { + return 'Vivaldi'; + } else if (user_agent.indexOf('Edge') !== -1) { + return 'Edge'; + } else if (user_agent.indexOf('Chrome') !== -1) { + return 'Chrome'; + } else if (user_agent.indexOf('Safari') !== -1) { + return 'Safari'; + } else if (user_agent.indexOf('Firefox') !== -1) { + return 'Firefox'; + } else if (user_agent.indexOf('MSIE') !== -1) { + return 'IE'; + } +}; + + +/*-------------------------------------------------------------- +# VERSION +--------------------------------------------------------------*/ + +satus.user.browser.version = function () { + var browser_name = satus.user.browser.name(), + browser_version = navigator.userAgent.match(new RegExp(browser_name + '/([0-9.]+)')); + + return browser_version[1]; +}; + + +/*-------------------------------------------------------------- +# PLATFORM +--------------------------------------------------------------*/ + +satus.user.browser.platform = function () { + return navigator.platform; +}; + + +/*-------------------------------------------------------------- +# MANIFEST +--------------------------------------------------------------*/ + +satus.user.browser.manifest = function () { + return chrome.runtime.getManifest() || {}; +}; + + +/*-------------------------------------------------------------- +# LANGUAGES +--------------------------------------------------------------*/ + +satus.user.browser.languages = function () { + return navigator.languages; +}; + + +/*-------------------------------------------------------------- +# COOKIES +--------------------------------------------------------------*/ + +satus.user.browser.cookies = function () { + if (document.cookie) { + var random_cookie = 'ta{t`nX6cMXK,Wsc'; + + document.cookie = random_cookie; + + if (document.cookie.indexOf(random_cookie) !== -1) { + return true; + } + } + + return false; +}; + + +/*-------------------------------------------------------------- +# FLASH +--------------------------------------------------------------*/ + +satus.user.browser.flash = function () { + try { + if (new ActiveXObject('ShockwaveFlash.ShockwaveFlash')) { + return true; + } + } catch (error) { + if (navigator.mimeTypes['application/x-shockwave-flash']) { + return true; + } + } + + return false; +}; + + +/*-------------------------------------------------------------- +# JAVA +--------------------------------------------------------------*/ + +satus.user.browser.java = function () { + if (satus.isFunction(navigator.javaEnabled) && navigator.javaEnabled()) { + return true; + } else { + return false; + } +}; + + +/*-------------------------------------------------------------- +# AUDIO +--------------------------------------------------------------*/ + +satus.user.browser.audio = function () { + var audio = document.createElement('audio'), + types = { + mp3: 'audio/mpeg', + mp4: 'audio/mp4', + aif: 'audio/x-aiff' + }, + result = []; + + if (satus.isFunction(audio.canPlayType)) { + for (var key in types) { + var can_play_type = audio.canPlayType(types[key]); + + if (can_play_type !== '') { + result.push(key); + } + } + } + + return result; +}; + + +/*-------------------------------------------------------------- +# VIDEO +--------------------------------------------------------------*/ + +satus.user.browser.video = function () { + var video = document.createElement('video'), + types = { + ogg: 'video/ogg; codecs="theora"', + h264: 'video/mp4; codecs="avc1.42E01E"', + webm: 'video/webm; codecs="vp8, vorbis"', + vp9: 'video/webm; codecs="vp9"', + hls: 'application/x-mpegURL; codecs="avc1.42E01E"' + }, + result = []; + + if (satus.isFunction(video.canPlayType)) { + for (var key in types) { + var can_play_type = video.canPlayType(types[key]); + + if (can_play_type !== '') { + result.push(key); + } + } + } + + return result; +}; + + +/*-------------------------------------------------------------- +# WEBGL +--------------------------------------------------------------*/ + +satus.user.browser.webgl = function () { + var cvs = document.createElement('canvas'), + ctx = cvs.getContext('webgl'); + + return ctx && ctx instanceof WebGLRenderingContext; +}; + + +/*-------------------------------------------------------------- +# HARDWARE +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# SCREEN +--------------------------------------------------------------*/ + +satus.user.device.screen = function () { + if (screen) { + return screen.width + 'x' + screen.height; + } +}; + + +/*-------------------------------------------------------------- +# RAM +--------------------------------------------------------------*/ + +satus.user.device.ram = function () { + if ('deviceMemory' in navigator) { + return navigator.deviceMemory + ' GB'; + } +}; + + +/*-------------------------------------------------------------- +# GPU +--------------------------------------------------------------*/ + +satus.user.device.gpu = function () { + var cvs = document.createElement('canvas'), + ctx = cvs.getContext('webgl'); + + if ( + ctx && + ctx instanceof WebGLRenderingContext && + 'getParameter' in ctx && + 'getExtension' in ctx + ) { + var info = ctx.getExtension('WEBGL_debug_renderer_info'); + + if (info) { + return ctx.getParameter(info.UNMASKED_RENDERER_WEBGL); + } + } +}; + + +/*-------------------------------------------------------------- +# CORES +--------------------------------------------------------------*/ + +satus.user.device.cores = function () { + return navigator.deviceConcurrency; +}; + + +/*-------------------------------------------------------------- +# TOUCH +--------------------------------------------------------------*/ + +satus.user.device.touch = function () { + var result = {}; + + if ( + window.hasOwnProperty('ontouchstart') || + window.DocumentTouch && document instanceof window.DocumentTouch || + navigator.maxTouchPoints > 0 || + window.navigator.msMaxTouchPoints > 0 + ) { + result.touch = true; + result.maxTouchPoints = navigator.maxTouchPoints; + } + + return result; +}; + + +/*-------------------------------------------------------------- +# CONNECTION +--------------------------------------------------------------*/ + +satus.user.device.connection = function () { + var result = {}; + + if (typeof navigator.connection === 'object') { + result.type = navigator.connection.effectiveType || null; + + if (navigator.connection.downlink) { + result.speed = navigator.connection.downlink + ' Mbps'; + } + } + + return result; +}; +/*-------------------------------------------------------------- +# SEARCH +--------------------------------------------------------------*/ + +satus.search = function (query, object, callback) { + var elements = ['switch', 'select', 'slider', 'shortcut', 'radio', 'color-picker'], + threads = 0, + results = {}, + excluded = [ + 'baseProvider', + 'childrenContainer', + 'parentElement', + 'parentObject', + 'parentSkeleton', + 'rendered', + 'namespaceURI' + ]; + + query = query.toLowerCase(); + + function parse(items, parent) { + threads++; + + for (var key in items) { + if (excluded.indexOf(key) === -1) { + var item = items[key]; + + if (item.component) { + //console.log(key, item.component); + + if (elements.indexOf(item.component) !== -1 && key.indexOf(query) !== -1) { + results[key] = Object.assign({}, item); + } + } + + if (typeof item === 'object') { + parse(item, items); + } + } + } + + threads--; + + if (threads === 0) { + callback(results); + } + } + + parse(object); +}; diff --git a/background.js b/background.js new file mode 100644 index 0000000..7fe8c64 --- /dev/null +++ b/background.js @@ -0,0 +1,13 @@ +/*-------------------------------------------------------------- +>>> BACKGROUND +--------------------------------------------------------------*/ + +chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { + var action = message.action; + + if (action === 'options-page-connected') { + sendResponse({ + isPopup: sender.hasOwnProperty('tab') === false + }); + } +}); \ No newline at end of file diff --git a/manifest.json b/manifest.json index ed6adee..98e6c6e 100644 --- a/manifest.json +++ b/manifest.json @@ -1,24 +1,27 @@ { - "manifest_version": 2, - "name": "ToDo", - "description": "__MSG_description__", - "version": "3.1", - "default_locale": "en", - "icons": { - "16": "icons/16.png", - "32": "icons/32.png", - "48": "icons/48.png", - "128": "icons/128.png" - }, - "browser_action": { - "default_popup": "ui/popup.html" - }, - "options_page": "ui/options.html", - "optional_permissions": [ - "downloads" - ], - "offline_enabled": true, - "permissions": [ - "storage" - ] -} + "manifest_version": 3, + "name": "ToDo", + "description": "__MSG_description__", + "version": "3.4", + "default_locale": "en", + "icons": { + "16": "assets/icons/16.png", + "32": "assets/icons/32.png", + "48": "assets/icons/48.png", + "128": "assets/icons/128.png" + }, + "background": { + "service_worker": "background.js" + }, + "action": { + "default_popup": "options-page/index.html" + }, + "options_page": "options-page/index.html", + "optional_permissions": [ + "downloads" + ], + "permissions": [ + "storage" + ], + "offline_enabled": true +} \ No newline at end of file diff --git a/options-page/functions.js b/options-page/functions.js new file mode 100644 index 0000000..0866a60 --- /dev/null +++ b/options-page/functions.js @@ -0,0 +1,712 @@ +/*-------------------------------------------------------------- +>>> FUNCTIONS +---------------------------------------------------------------- +# Export settings +# Import settings +# Update lists +# Update tasks +# Update data +# Encryption +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# EXPORT SETTINGS +--------------------------------------------------------------*/ + +extension.exportSettings = function () { + if (location.href.indexOf('action=export-settings') !== -1) { + satus.render({ + component: 'modal', + variant: 'confirm', + content: 'areYouSureYouWantToExportTheData', + buttons: { + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.modalProvider.close(); + } + } + }, + ok: { + component: 'button', + text: 'ok', + on: { + click: function () { + try { + var blob = new Blob([JSON.stringify(satus.storage.data)], { + type: 'application/json;charset=utf-8' + }); + + chrome.permissions.request({ + permissions: ['downloads'] + }, function (granted) { + if (granted) { + chrome.downloads.download({ + url: URL.createObjectURL(blob), + filename: 'user-agent.json', + saveAs: true + }, function () { + setTimeout(function () { + close(); + }, 1000); + }); + } + }); + } catch (error) { + console.error(error); + } + } + } + } + } + }, extension.skeleton.rendered); + } +}; + + +/*-------------------------------------------------------------- +# IMPORT SETTINGS +--------------------------------------------------------------*/ + +extension.importSettings = function () { + if (location.href.indexOf('action=import-settings') !== -1) { + satus.render({ + component: 'modal', + variant: 'confirm', + content: 'areYouSureYouWantToImportTheData', + buttons: { + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + this.modalProvider.close(); + } + } + }, + ok: { + component: 'button', + text: 'ok', + on: { + click: function () { + var input = document.createElement('input'); + + input.type = 'file'; + + input.addEventListener('change', function () { + var file_reader = new FileReader(); + + file_reader.onload = function () { + var data = JSON.parse(this.result); + + for (var key in data) { + satus.storage.set(key, data[key]); + } + + setTimeout(function () { + chrome.runtime.sendMessage({ + action: 'import-settings' + }); + + setTimeout(function () { + close(); + }, 128); + }, 256); + }; + + file_reader.readAsText(this.files[0]); + }); + + input.click(); + } + } + } + } + }, extension.skeleton.rendered); + } +}; + + +/*-------------------------------------------------------------- +# UPDATE LISTS +--------------------------------------------------------------*/ + +extension.updateLists = function () { + var layer = satus.last(extension.skeleton.main.layers.rendered.children), + section = { + component: 'section', + variant: 'card' + }; + + if (extension.lists.length === 0) { + section.span = { + component: 'span', + text: 'noLists', + style: { + 'display': 'flex', + 'alignItems': 'center' + } + }; + } + + for (var i = 0, l = extension.lists.length; i < l; i++) { + var list = extension.lists[i]; + + section['list_' + i] = { + component: 'button', + variant: 'folder', + attr: { + title: list.name + }, + text: list.name, + before: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': list.color || extension.color[0] + }, + + path: { + component: 'path', + attr: { + 'd': extension.icons[list.icon] || extension.icons['folder'] + } + } + }, + list: list, + sortable: true, + contextMenu: { + rename: { + component: 'button', + text: 'rename', + on: { + click: function () { + var modal = this.parentNode.parentNode; + + satus.render({ + component: 'modal', + parentSkeleton: modal.skeleton.parentSkeleton, + + title: { + component: 'span', + text: 'rename' + }, + input: { + component: 'input', + type: 'text', + attr: { + 'autofocus': true, + 'value': modal.skeleton.parentSkeleton.list.name + }, + on: { + render: function () { + this.focus(); + this.select(); + }, + keydown: function (event) { + if (event.key === 'Enter') { + this.parentNode.parentNode.skeleton.actions.ok.rendered.click(); + } + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + var modal = this.parentNode.parentNode.parentNode; + + modal.close(); + } + } + }, + ok: { + component: 'button', + text: 'ok', + on: { + click: function () { + var modal = this.parentNode.parentNode.parentNode, + item = modal.skeleton.parentSkeleton; + + item.list.name = modal.skeleton.input.rendered.value; + + extension.updateData(); + + extension.updateLists(); + + modal.close(); + } + } + } + } + }, modal.baseProvider); + + modal.close(); + } + } + }, + changeIcon: { + component: 'button', + text: 'changeIcon', + on: { + click: function () { + var modal = this.parentNode.parentNode; + + satus.render({ + component: 'modal', + parentSkeleton: modal.skeleton, + + label: { + component: 'span', + text: 'icons' + }, + grid: { + component: 'section', + variant: 'grid', + style: { + margin: '12px 0 6px', + justifyContent: 'center' + }, + on: { + render: function () { + var list = this.skeleton.parentSkeleton.parentSkeleton.parentSkeleton.list; + + for (var key in extension.icons) { + var skeleton = { + component: 'button', + data: { + key: key + }, + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + list = modal.parentSkeleton.parentSkeleton.list; + + list.icon = this.dataset.key; + + extension.updateData(); + + extension.updateLists(); + + modal.rendered.close(); + } + }, + + svg: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'currentColor' + }, + + path: { + component: 'path', + attr: { + 'd': extension.icons[key] + } + } + } + }; + + if ( + satus.isset(list.icon) === false && key === 'folder' || + list.icon === key + ) { + skeleton.svg.attr.fill = 'var(--satus-primary)'; + } + + satus.render(skeleton, this); + } + } + } + } + }, modal.baseProvider); + + modal.close(); + } + } + }, + changeColor: { + component: 'button', + text: 'changeColor', + on: { + click: function () { + var modal = this.parentNode.parentNode; + + satus.render({ + component: 'modal', + parentSkeleton: modal.skeleton, + + label: { + component: 'span', + text: 'color' + }, + grid: { + component: 'section', + variant: 'grid', + style: { + margin: '12px 0 6px', + justifyContent: 'center' + }, + on: { + render: function () { + var list = this.skeleton.parentSkeleton.parentSkeleton.parentSkeleton.list; + + for (var color of extension.color) { + var skeleton = { + component: 'button', + data: { + color + }, + on: { + click: function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + list = modal.parentSkeleton.parentSkeleton.list; + + list.color = this.dataset.color; + + extension.updateData(); + + extension.updateLists(); + + modal.rendered.close(); + } + }, + + circle: { + component: 'span', + style: { + width: '20px', + height: '20px', + backgroundColor: color, + borderRadius: '50%' + } + } + }; + + /*if ( + satus.isset(list.color) === false && color === list.color[0] || + list.color === color + ) { + skeleton.svg.attr.fill = 'var(--satus-primary)'; + }*/ + + satus.render(skeleton, this); + } + } + } + } + }, modal.baseProvider); + + modal.close(); + } + } + }, + remove: { + component: 'button', + text: 'remove', + on: { + click: function () { + var modal = this.parentNode.parentNode, + parent = modal.skeleton.parentSkeleton; + + satus.remove(parent.list, extension.lists); + + extension.updateData(); + + extension.updateLists(); + + modal.close(); + } + } + } + }, + on: { + click: { + component: 'section', + variant: 'card', + tasks: list.tasks, + on: { + render: function () { + extension.updateTasks(this.skeleton.tasks); + } + } + }, + sort: function () { + var index = satus.indexOf(this); + + satus.toIndex(index, this.skeleton.list, extension.lists); + + extension.updateData(); + } + } + }; + } + + satus.empty(layer); + + satus.render(section, layer); +}; + + +/*-------------------------------------------------------------- +# UPDATE TASKS +--------------------------------------------------------------*/ + +extension.updateTasks = function (tasks) { + var path = extension.skeleton.main.layers.rendered.path, + section = path[path.length - 1].rendered; + + satus.empty(section); + + if (tasks.length === 0) { + satus.render({ + component: 'span', + text: 'noTasks', + style: { + 'display': 'flex', + 'alignItems': 'center' + } + }, section); + } + + for (var i = 0, l = tasks.length; i < l; i++) { + var task = tasks[i]; + + satus.render({ + component: 'checkbox', + attr: { + title: task.name + }, + text: [task.name], + value: task.value, + storage: false, + tasks: tasks, + task: task, + contextMenu: { + rename: { + component: 'button', + text: 'rename', + on: { + click: function () { + var modal = this.parentNode.parentNode; + + satus.render({ + component: 'modal', + parentSkeleton: modal.skeleton.parentSkeleton, + + title: { + component: 'span', + text: 'rename' + }, + input: { + component: 'input', + type: 'text', + attr: { + 'autofocus': true, + 'value': modal.skeleton.parentSkeleton.task.name + }, + on: { + render: function () { + this.focus(); + this.select(); + }, + keydown: function (event) { + if (event.key === 'Enter') { + this.parentNode.parentNode.skeleton.actions.ok.rendered.click(); + } + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + cancel: { + component: 'button', + text: 'cancel', + on: { + click: function () { + var modal = this.parentNode.parentNode.parentNode; + + modal.close(); + } + } + }, + ok: { + component: 'button', + text: 'ok', + on: { + click: function () { + var modal = this.parentNode.parentNode.parentNode, + item = modal.skeleton.parentSkeleton; + + item.task.name = modal.skeleton.input.rendered.value; + + extension.updateData(); + + extension.updateTasks(item.tasks); + + modal.close(); + } + } + } + } + }, modal.baseProvider); + + modal.close(); + } + } + }, + remove: { + component: 'button', + text: 'remove', + on: { + click: function () { + var path = extension.skeleton.main.layers.rendered.path, + layer = path[path.length - 1], + modal = this.parentNode.parentNode, + parent = modal.skeleton.parent; + + satus.remove(parent.task, parent.tasks); + + extension.updateData(); + + extension.updateTasks(parent.tasks); + + modal.close(); + } + } + } + }, + sortable: true, + on: { + change: function () { + console.log(this.skeleton.task); + this.skeleton.task.value = this.storage.value; + + extension.updateData(); + }, + sort: function () { + var index = satus.indexOf(this); + + satus.toIndex(index, this.skeleton.task, this.skeleton.tasks); + + extension.updateData(); + } + } + }, section); + } +}; + + +/*-------------------------------------------------------------- +# UPDATE DATA +--------------------------------------------------------------*/ + +extension.updateData = function () { + if (satus.storage.get('encrypted') === true && extension.password) { + extension.encr(); + } else { + satus.storage.set('lists', extension.lists); + } +}; + + +/*-------------------------------------------------------------- +# ENCRYPTION +--------------------------------------------------------------*/ + +extension.crypt = function (mode, data, callback, component) { + satus.render({ + component: 'modal', + parentSkeleton: component ? component.skeleton : undefined, + on: { + close: function () { + if (this.skeleton.parentSkeleton) { + var component = this.skeleton.parentSkeleton.parentSkeleton.encrypted.rendered; + + if (satus.storage.get('encrypted') === true) { + component.dataset.value = 'true'; + } else { + component.dataset.value = 'false'; + } + } + } + }, + + title: { + component: 'span', + text: mode ? 'encryption' : 'decryption' + }, + input: { + component: 'input', + attr: { + type: 'password' + }, + on: { + render: function () { + this.focus(); + }, + keydown: async function (event) { + if (event.key === 'Enter') { + this.parentNode.parentNode.skeleton.actions.ok.rendered.click(); + } + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + ok: { + component: 'button', + text: 'ok', + on: { + click: async function () { + var modal = this.skeleton.parentSkeleton.parentSkeleton, + input = modal.input.rendered, + result = false; + + if (input.value.length > 1) { + if (mode) { + result = await satus.encrypt(data, input.value); + extension.password = input.value; + } else { + result = JSON.parse(await satus.decrypt(data, input.value)); + extension.password = input.value; + } + + if (result) { + callback(mode, result); + + modal.rendered.close(); + } else { + input.classList.add('error'); + } + } else { + input.classList.add('error'); + } + } + } + } + } + }, document.querySelector('.satus-base')); +}; + +extension.encr = async function (callback) { + satus.storage.set('lists', await satus.encrypt(JSON.stringify(extension.lists), extension.password)); + satus.storage.set('encrypted', true); + satus.storage.remove('data'); + + if (callback) { + callback(); + } +}; \ No newline at end of file diff --git a/options-page/index.css b/options-page/index.css new file mode 100644 index 0000000..a00dccc --- /dev/null +++ b/options-page/index.css @@ -0,0 +1,205 @@ +/*-------------------------------------------------------------- +>>> USER INTERFACE +---------------------------------------------------------------- +# Fonts +# Themes +# Header +# Layers + Folder +# Create +# Tab +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# FONTS +--------------------------------------------------------------*/ + +@font-face { + font-family: Roboto; + + src: url(../assets/fonts/Roboto-Regular.ttf); +} + +@font-face { + font-family: Roboto; + font-weight: 500; + + src: url(../assets/fonts/Roboto-Medium.ttf); +} + +@font-face { + font-family: Roboto; + font-weight: 700; + + src: url(../assets/fonts/Roboto-Bold.ttf); +} + + +/*-------------------------------------------------------------- +# THEMES +--------------------------------------------------------------*/ + +body { + --satus-light: 0, 0, 0; + --satus-primary: #f6b465; + --satus-header-background: #fff; + --satus-header-shadow: 0 0 3px rgba(var(--satus-light), .1), inset 0 -1px 0 rgba(var(--satus-light), .1); + --satus-header-foreground: #848471; + --satus-base-background: #f6f6f4; + --satus-base-foreground: #848471; + --satus-section-card-background: #fff; + --satus-section-card-border: rgba(var(--satus-light), .1); + --satus-modal-background: #f6f6f4; + --satus-modal-border: rgba(var(--satus-light), .1); + --satus-modal-text: #848471; + --satus-tabs-background: #e8e8e3; + --satus-tabs-foreground: #fff; +} + +body[theme='dark'] { + --satus-light: 255, 255, 255; + --satus-primary: #8f8f8f; + --satus-base-background: #000; + --satus-base-foreground: #ccc; + --satus-switch-background: rgba(var(--satus-light), .08); + --satus-header-background: #1f1f1f; + --satus-header-border: rgba(var(--satus-light), .08); + --satus-header-foreground: #ccc; + --satus-layers-background: #000; + --satus-layers-foreground: #ccc; + --satus-section-background: #1e1e1e; + --satus-section-border: rgba(var(--satus-light), .08); + --satus-modal-background: #212121; + --satus-modal-border: rgba(var(--satus-light), .08); + --satus-modal-shadow: 0 1px 4px rgba(var(--satus-light), .08); + --satus-modal-foreground: #ccc; + --satus-hover: rgba(var(--satus-light), .05); + --satus-input-text-background: #333; + --satus-input-text-border: #525252; + --satus-input-text-foreground: #ccc; + --satus-switch-track: #111; + --satus-switch-track--active: var(--satus-primary); + --satus-switch-thumb: #ddd; + --satus-tooltip: rgba(var(--satus-light), .4); + --satus-sortable-ghost: rgba(var(--satus-light), .8); + --satus-sortable-background: rgba(var(--satus-light), .1); + --satus-sortable-foreground: #fff; + --satus-divider: rgba(var(--satus-light), .08); + --satus-tabs-background: #111; + --satus-tabs-foreground: #2e2e2e; + --satus-tabs-border: #2f2f2f; + --satus-checkbox--background: rgb(var(--satus-light), .08); + --satus-checkbox--border: #2f2f2f; + --satus-checkbox--mark: #fff; + --satus-alert-error-background: #501616; + --satus-alert-error-border: #6f1f1f; + --satus-alert-error-color: #cf7777; +} + + +/*-------------------------------------------------------------- +# HEADER +--------------------------------------------------------------*/ + +.satus-header .satus-section--align-start { + max-width: calc(100% - 40px); +} + + +/*-------------------------------------------------------------- +# LAYERS +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# FOLDER +--------------------------------------------------------------*/ + +.satus-button--folder { + display: flex; + + align-items: center; +} + +.satus-button.satus-button--folder>svg { + width: 20px; + min-width: 20px; + margin: -2px 16px 0 0; +} + +.satus-button--folder>.satus-span { + display: block; + overflow: hidden; + + white-space: nowrap; + text-overflow: ellipsis; +} + + +/*-------------------------------------------------------------- +# CREATE +--------------------------------------------------------------*/ + +.satus-button--create { + position: fixed; + right: 16px; + bottom: 16px; + + width: 56px; + height: 56px; + + color: #fff; + border-radius: 50%; + background: linear-gradient(135deg, #f8d266, #f17953); + box-shadow: 0 2px 1px 1px rgb(230, 109, 70, .7), 0 3px 5px rgb(0, 0, 0, .35); +} + +.satus-button--create::before { + position: absolute; + top: calc(50% - 1px); + left: calc(50% - 7px); + + width: 14px; + height: 2px; + + content: ''; + + background: currentColor; +} + +.satus-button--create::after { + position: absolute; + top: calc(50% - 7px); + left: calc(50% - 1px); + + width: 2px; + height: 14px; + + content: ''; + + background: currentColor; +} + + +/*-------------------------------------------------------------- +# TAB +--------------------------------------------------------------*/ + +body[tab] { + overflow: hidden; + + width: 100vw; + height: 100vh; +} + +body[tab] .satus-base { + width: 100%; + height: 100%; +} + +body[tab] .satus-alert { + display: none; +} + +.satus-modal__surface { + max-width: 290px; +} \ No newline at end of file diff --git a/options-page/index.html b/options-page/index.html new file mode 100644 index 0000000..9f6980a --- /dev/null +++ b/options-page/index.html @@ -0,0 +1,27 @@ + + + + + + ToDo + + + + + + + + + + + + + \ No newline at end of file diff --git a/options-page/index.js b/options-page/index.js new file mode 100644 index 0000000..5183d1f --- /dev/null +++ b/options-page/index.js @@ -0,0 +1,64 @@ +/*-------------------------------------------------------------- +>>> USER INTERFACE +---------------------------------------------------------------- +# Global variable +# Initialization +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# GLOBAL VARIABLE +--------------------------------------------------------------*/ + +var extension = { + lists: [] +}; + + +/*-------------------------------------------------------------- +# INITIALIZATION +--------------------------------------------------------------*/ + +satus.storage.attributes = { + theme: true +}; + +satus.storage.import(function (items) { + var language = items.language; + + if (!language) { + language = window.navigator.language; + } + + if (items.theme === 'dark') { + document.body.setAttribute('theme', 'dark'); + } + + satus.locale.import(language, function () { + if (extension.lists.length > 0) { + satus.render(extension.skeleton); + } else if (Array.isArray(satus.storage.get('lists'))) { + extension.lists = satus.storage.get('lists'); + + satus.render(extension.skeleton); + } else if (satus.storage.get('encrypted') === true && typeof satus.storage.get('lists') === 'string') { + extension.crypt(false, satus.storage.get('lists'), function (mode, data) { + extension.lists = data; + + satus.render(extension.skeleton); + }); + } else { + satus.render(extension.skeleton); + } + + extension.exportSettings(); + extension.importSettings(); + }, '_locales/'); +}); + +chrome.runtime.sendMessage({ + action: 'options-page-connected' +}, function (response) { + if (response.isPopup === false) { + document.body.setAttribute('tab', ''); + } +}); \ No newline at end of file diff --git a/options-page/skeleton.js b/options-page/skeleton.js new file mode 100644 index 0000000..28244d1 --- /dev/null +++ b/options-page/skeleton.js @@ -0,0 +1,431 @@ +/*-------------------------------------------------------------- +>>> SKELETON +---------------------------------------------------------------- +# Base +# Header +# Main +# Create +--------------------------------------------------------------*/ + +/*-------------------------------------------------------------- +# BASE +--------------------------------------------------------------*/ + +extension.skeleton = { + component: 'base' +}; + + +/*-------------------------------------------------------------- +# HEADER +--------------------------------------------------------------*/ + +extension.skeleton.header = { + component: 'header', + + sectionStart: { + component: 'section', + variant: 'align-start', + + back: { + component: 'button', + variant: 'icon', + attr: { + 'hidden': 'true' + }, + on: { + click: 'main.layers.back' + }, + + svg: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'none', + 'stroke-width': '1.5', + 'stroke': 'currentColor' + }, + + path: { + component: 'path', + attr: { + 'd': 'M14 18l-6-6 6-6' + } + } + } + }, + title: { + component: 'span', + variant: 'title' + } + }, + sectionEnd: { + component: 'section', + variant: 'align-end', + + menu: { + component: 'button', + variant: 'icon', + on: { + click: { + component: 'modal', + variant: 'vertical-menu', + + label: { + component: 'span', + text: 'theme' + }, + theme: { + component: 'tabs', + items: [ + 'light', + 'dark' + ], + value: function () { + return satus.storage.get('theme') === 'dark' ? 1 : 0; + }, + on: { + click: function () { + if (this.value === 1) { + satus.storage.set('theme', 'dark'); + + document.body.setAttribute('theme', 'dark'); + } else { + satus.storage.remove('theme'); + + document.body.removeAttribute('theme'); + } + } + } + }, + divider: { + component: 'divider' + }, + language: { + component: 'select', + before: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'currentColor' + }, + + path: { + component: 'path', + attr: { + 'd': 'M12.9 15l-2.6-2.4c1.8-2 3-4.2 3.8-6.6H17V4h-7V2H8v2H1v2h11.2c-.7 2-1.8 3.8-3.2 5.3-1-1-1.7-2.1-2.3-3.3h-2c.7 1.6 1.7 3.2 3 4.6l-5.1 5L4 19l5-5 3.1 3.1.8-2zm5.6-5h-2L12 22h2l1.1-3H20l1.1 3h2l-4.5-12zm-2.6 7l1.6-4.3 1.6 4.3H16z' + } + } + }, + text: 'language', + on: { + change: function (name, value) { + var language = satus.storage.get('language'); + + if (!language || language === 'default') { + language = window.navigator.language; + } + + satus.locale.import(language, function () { + var layers = document.querySelector('.satus-layers'); + + extension.skeleton.main.layers.rendered.dispatchEvent(new CustomEvent('open')); + + satus.empty(layers.firstChild); + + satus.render(satus.last(layers.path), layers.firstChild, undefined, true); + }, '_locales/'); + } + }, + options: [{ + value: 'en', + text: 'English' + }, { + value: 'ru', + text: 'Русский' + }, { + value: 'de', + text: 'Deutsch' + }] + }, + encrypted: { + component: 'switch', + text: 'encryption', + before: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'none', + 'stroke': 'currentColor', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + 'stroke-width': '2' + }, + + path: { + component: 'path', + attr: { + 'd': 'M21 2l-2 2m-7.61 7.61a5.5 5.5 0 11-7.778 7.778 5.5 5.5 0 017.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4' + } + } + }, + storage: false, + value: function () { + return satus.storage.get('encrypted'); + }, + on: { + change: function () { + var component = this; + + if (this.storage.value === true) { + extension.crypt(this.dataset.value === 'true', JSON.stringify(extension.lists), function (mode, data) { + satus.storage.set('encrypted', true); + + component.dataset.value = 'true'; + + satus.storage.set('lists', data); + }, component); + } else { + satus.storage.remove('encrypted'); + + component.dataset.value = 'false'; + + satus.storage.set('lists', extension.lists); + } + } + } + }, + export: { + component: 'button', + before: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'none', + 'stroke': 'currentColor', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + 'stroke-width': '2' + }, + + path: { + component: 'path', + attr: { + 'd': 'M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12' + } + } + }, + text: 'export', + on: { + click: function () { + if (location.href.indexOf('options-page/index.html?action=export-settings') !== -1) { + extension.exportSettings(); + } else { + chrome.tabs.create({ + url: 'options-page/index.html?action=export-settings' + }); + } + } + } + }, + import: { + component: 'button', + before: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'none', + 'stroke': 'currentColor', + 'stroke-linecap': 'round', + 'stroke-linejoin': 'round', + 'stroke-width': '2' + }, + + path: { + component: 'path', + attr: { + 'd': 'M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3' + } + } + }, + text: 'import', + on: { + click: function () { + if (location.href.indexOf('options-page/index.html?action=import-settings') !== -1) { + extension.importSettings(); + } else { + chrome.tabs.create({ + url: 'options-page/index.html?action=import-settings' + }); + } + } + } + } + } + }, + + svg: { + component: 'svg', + attr: { + 'viewBox': '0 0 24 24', + 'fill': 'currentColor' + }, + + circle_1: { + component: 'circle', + attr: { + 'cx': '12', + 'cy': '5.25', + 'r': '1' + } + }, + circle_2: { + component: 'circle', + attr: { + 'cx': '12', + 'cy': '12', + 'r': '1' + } + }, + circle_3: { + component: 'circle', + attr: { + 'cx': '12', + 'cy': '18.75', + 'r': '1' + } + } + } + } + } +}; + + +/*-------------------------------------------------------------- +# MAIN +--------------------------------------------------------------*/ + +extension.skeleton.main = { + component: 'main', + + layers: { + component: 'layers', + on: { + open: function () { + var skeleton = satus.last(this.path), + section = this.baseProvider.skeleton.header.sectionStart, + title = satus.manifest().name; + + if (skeleton.parentSkeleton) { + if (skeleton.parentSkeleton.label) { + title = skeleton.parentSkeleton.label.text; + } else if (skeleton.parentSkeleton.text) { + title = skeleton.parentSkeleton.text; + } + } + + section.back.rendered.hidden = this.path.length <= 1; + section.title.rendered.innerText = satus.locale.get(title); + + if (this.path.length <= 1) { + extension.updateLists(); + } + + var vertical_menu = document.querySelector('.satus-modal--vertical-menu'); + + if (vertical_menu) { + vertical_menu.close(); + } + } + } + } +}; + + +/*-------------------------------------------------------------- +# CREATE +--------------------------------------------------------------*/ + +extension.skeleton.create = { + component: 'button', + variant: 'create', + attr: { + 'title': 'create' + }, + on: { + click: { + component: 'modal', + + title: { + component: 'span', + text: function () { + if (extension.skeleton.main.layers.rendered.path.length > 1) { + return 'newTask'; + } else { + return 'newList'; + } + } + }, + input: { + component: 'input', + attr: { + type: 'text', + autofocus: 'true' + }, + storage: false, + on: { + render: function () { + this.focus(); + }, + keydown: function (event) { + if (event.key === 'Enter') { + this.parentNode.parentNode.skeleton.actions.create.rendered.click(); + } + } + } + }, + actions: { + component: 'section', + variant: 'actions', + + create: { + component: 'button', + text: 'create', + on: { + click: function () { + var path = extension.skeleton.main.layers.rendered.path, + modal = this.skeleton.parentSkeleton.parentSkeleton, + name = modal.input.rendered.value; + + if (path.length > 1) { + var layer = satus.last(path), + task = { + name: name, + value: false, + time: new Date().getTime() + }; + + layer.tasks.push(task); + + satus.empty(layer.rendered); + + extension.updateTasks(layer.tasks); + } else { + extension.lists.push({ + name: name, + tasks: [] + }); + + extension.updateLists(); + } + + extension.updateData(); + + modal.rendered.close(); + } + } + } + } + } + } +}; \ No newline at end of file diff --git a/py/locale.py b/py/locale.py index 10b38b0..f484f75 100644 --- a/py/locale.py +++ b/py/locale.py @@ -1,22 +1,23 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # >>> TABLE OF CONTENTS: -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 1.0 Import modules # 2.0 Lower camel case # 3.0 Get list of files # 4.0 Add item # 5.0 Remove item -# 6.0 Decode -# 7.0 Add locales -# 8.0 Initialization -# -------------------------------------------------------------- +# 6.0 Change key +# 7.0 Decode +# 8.0 Upgrade +# 9.0 Initialization +# ------------------------------------------------------------------------------ -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 1.0 IMPORT MODULES -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ import io import json @@ -26,9 +27,9 @@ import sys -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 2.0 LOWER CAMEL CASE -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ def lowerCamelCase(string): string = re.sub(r"(-|_)+", ' ', string).title() @@ -37,21 +38,21 @@ def lowerCamelCase(string): return string[0].lower() + string[1:] -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 3.0 GET LIST OF FILES -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ -def getListOfFiles(dirName): +def getListOfFiles(path): allFiles = list() - for entry in os.listdir(dirName): - fullPath = os.path.join(dirName, entry) + for entry in os.listdir(path): + fullPath = os.path.join(path, entry) if not os.path.isdir(fullPath): allFiles.append(fullPath) - for entry in os.listdir(dirName): - fullPath = os.path.join(dirName, entry) + for entry in os.listdir(path): + fullPath = os.path.join(path, entry) if os.path.isdir(fullPath): allFiles = allFiles + getListOfFiles(fullPath) @@ -59,9 +60,9 @@ def getListOfFiles(dirName): return allFiles -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 4.0 ADD ITEM -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ def addItem(allFiles): message = input('Enter your message: ') @@ -75,14 +76,13 @@ def addItem(allFiles): data[camelized_message] = {'message': message} json_file.seek(0) - json.dump(data, json_file, ensure_ascii=False, indent=4, - sort_keys=True) + json.dump(data, json_file, ensure_ascii=False, indent=4, sort_keys=True) json_file.truncate() -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ # 5.0 REMOVE ITEM -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ def removeItem(allFiles): key = input('Enter your key (lowerCamelCase): ') @@ -100,9 +100,31 @@ def removeItem(allFiles): json_file.truncate() -# -------------------------------------------------------------- -# 6.0 DECODE -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ +# 6.0 CHANGE KEY +# ------------------------------------------------------------------------------ + +def changeKey(allFiles): + old_key = input('Enter key: ') + new_key = input('Enter new key: ') + + for keyFile in allFiles: + with open(keyFile, 'r+') as file: + data = json.load(file) + + if old_key in data: + data[new_key] = data[old_key] + + del data[old_key] + + file.seek(0) + json.dump(data, file, ensure_ascii=False, indent=4, sort_keys=True) + file.truncate() + + +# ------------------------------------------------------------------------------ +# 7.0 DECODE +# ------------------------------------------------------------------------------ def decodeCharacters(allFiles): for keyFile in allFiles: @@ -115,11 +137,11 @@ def decodeCharacters(allFiles): json_file.truncate() -# -------------------------------------------------------------- -# 7.0 ADD LOCALES -# -------------------------------------------------------------- +# ------------------------------------------------------------------------------ +# 8.0 UPGRADE +# ------------------------------------------------------------------------------ -def addLocales(): +def upgrade(): locales = [ 'am', 'ar', @@ -176,24 +198,49 @@ def addLocales(): 'zh_TW' ] + if os.path.exists('../_locales/en/messages.json'): + file = open('../_locales/en/messages.json', 'r+') + + default_locale = json.load(file) + + file.close() + else: + default_locale = {} + for locale in locales: - if not os.path.exists('../_locales/' + locale): - pathlib.Path('../_locales/' + locale).mkdir(parents=True, - exist_ok=True) + path = '../_locales/' + locale - file = io.open('../_locales/' + locale + '/messages.json', - mode='w', encoding='utf-8') + if not os.path.exists(path): + pathlib.Path(path).mkdir(parents=True, exist_ok=True) - file.write('{}') + file = io.open(path + '/messages.json', mode='w', encoding='utf-8') + json.dump(default_locale, file, ensure_ascii=False, indent=4, sort_keys=True) + file.close() + else: + with open(path + '/messages.json', 'r+') as file: + data = json.load(file) + + file.seek(0) + + for key in default_locale: + if (key in data) == False: + data[key] = default_locale[key] + + json.dump(data, file, ensure_ascii=False, indent=4, sort_keys=True) + + file.truncate() + + file.close() - print(locale) +# ------------------------------------------------------------------------------ +# 9.0 INITIALIZATION +# ------------------------------------------------------------------------------ -# -------------------------------------------------------------- -# 8.0 INITIALIZATION -# -------------------------------------------------------------- +if not os.path.exists('../_locales/'): + pathlib.Path('../_locales/').mkdir(parents=True, exist_ok=True) allFiles = getListOfFiles('../_locales/') @@ -204,5 +251,7 @@ def addLocales(): removeItem(allFiles) elif arg == '-decode': decodeCharacters(allFiles) - elif arg == '-generate': - addLocales() \ No newline at end of file + elif arg == '-change-key': + changeKey(allFiles) + elif arg == '-upgrade': + upgrade() \ No newline at end of file diff --git a/ui/fonts/LICENSE.txt b/ui/fonts/LICENSE.txt deleted file mode 100644 index 75b5248..0000000 --- a/ui/fonts/LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/ui/fonts/Roboto-Black.ttf b/ui/fonts/Roboto-Black.ttf deleted file mode 100644 index 43a00e0..0000000 Binary files a/ui/fonts/Roboto-Black.ttf and /dev/null differ diff --git a/ui/fonts/Roboto-BlackItalic.ttf b/ui/fonts/Roboto-BlackItalic.ttf deleted file mode 100644 index 5082cdc..0000000 Binary files a/ui/fonts/Roboto-BlackItalic.ttf and /dev/null differ diff --git a/ui/fonts/Roboto-BoldItalic.ttf b/ui/fonts/Roboto-BoldItalic.ttf deleted file mode 100644 index e85e7fb..0000000 Binary files a/ui/fonts/Roboto-BoldItalic.ttf and /dev/null differ diff --git a/ui/fonts/Roboto-Italic.ttf b/ui/fonts/Roboto-Italic.ttf deleted file mode 100644 index c9df607..0000000 Binary files a/ui/fonts/Roboto-Italic.ttf and /dev/null differ diff --git a/ui/fonts/Roboto-Light.ttf b/ui/fonts/Roboto-Light.ttf deleted file mode 100644 index 0e97751..0000000 Binary files a/ui/fonts/Roboto-Light.ttf and /dev/null differ diff --git a/ui/fonts/Roboto-LightItalic.ttf b/ui/fonts/Roboto-LightItalic.ttf deleted file mode 100644 index 3ad14fa..0000000 Binary files a/ui/fonts/Roboto-LightItalic.ttf and /dev/null differ diff --git a/ui/fonts/Roboto-MediumItalic.ttf b/ui/fonts/Roboto-MediumItalic.ttf deleted file mode 100644 index a5a41d3..0000000 Binary files a/ui/fonts/Roboto-MediumItalic.ttf and /dev/null differ diff --git a/ui/fonts/Roboto-Thin.ttf b/ui/fonts/Roboto-Thin.ttf deleted file mode 100644 index 7d084ae..0000000 Binary files a/ui/fonts/Roboto-Thin.ttf and /dev/null differ diff --git a/ui/fonts/Roboto-ThinItalic.ttf b/ui/fonts/Roboto-ThinItalic.ttf deleted file mode 100644 index c173389..0000000 Binary files a/ui/fonts/Roboto-ThinItalic.ttf and /dev/null differ diff --git a/ui/options.html b/ui/options.html deleted file mode 100644 index d64dd9b..0000000 --- a/ui/options.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - ToDo - - - - - - - - - - \ No newline at end of file diff --git a/ui/popup.html b/ui/popup.html deleted file mode 100644 index eed4a03..0000000 --- a/ui/popup.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - ToDo - - - - - - - - - - \ No newline at end of file diff --git a/ui/satus/satus.css b/ui/satus/satus.css deleted file mode 100644 index 0a182d5..0000000 --- a/ui/satus/satus.css +++ /dev/null @@ -1,1591 +0,0 @@ - -/*-------------------------------------------------------------- ->>> ELEMENTS: ----------------------------------------------------------------- -# Reset -# Attributes - # Hidden ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# RESET ---------------------------------------------------------------*/ - -:where([class^=satus]:not(iframe, canvas, img, svg, video, svg *, symbol *)) { - display: revert; - all: unset; -} - -:where([class^=satus]:not(iframe, canvas, img, svg, video, svg *, symbol *)) { - box-sizing: border-box; -} - - -/*-------------------------------------------------------------- -# ATTRIBUTES ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# HIDDEN ---------------------------------------------------------------*/ - -[class^=satus][hidden] { - display: none; -} -/*-------------------------------------------------------------- ->>> THEMES: ----------------------------------------------------------------- -# Default ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# DEFAULT ---------------------------------------------------------------*/ - -:root { - -} - -body { - --satus-contrast: 0, 0, 0; - --satus-primary: #f6b465; - --satus-switch-background: rgba(var(--satus-contrast),.08); - --satus-header-background: #fff; - --satus-header-border: rgba(var(--satus-contrast),.1); - --satus-header-text: #848471; - --satus-layers-background: #f6f6f4; - --satus-layers-text: #848471; - --satus-section-card-background: #fff; - --satus-section-card-border: rgba(var(--satus-contrast),.1); - --satus-modal-background: #f6f6f4; - --satus-modal-border: rgba(var(--satus-contrast), .1); - --satus-modal-text: #848471; - --satus-hover: rgba(var(--satus-contrast), .04); - --satus-text-field--background: #e8e8e3; - --satus-text-field--border: #d6d6cd; - --satus-text-field--text: #848471; - --satus-switch-track: #e0e0e0; - --satus-switch-track--active: var(--satus-primary); - --satus-switch-thumb: #fff; - --satus-tabs: #fff; - --satus-tooltip: rgba(var(--satus-contrast),.4); - --satus-sortable-ghost: rgba(var(--satus-contrast), .80); - --satus-sortable-background: rgba(var(--satus-contrast), .08); - --satus-sortable-text: currentColor; - --satus-divider: rgba(var(--satus-contrast),.1); - --satus-tabs-background: #e8e8e3; - --satus-tabs-foreground: #fff; - --satus-tabs-border: rgba(var(--satus-contrast), .1); - --satus-checkbox--background: rgb(90, 90, 73, .08); - --satus-checkbox--border: rgb(90, 90, 73, .16); - --satus-checkbox--mark: #fff; - --satus-alert-error-background: #fde6e6; - --satus-alert-error-border: #ecd7d7; - --satus-alert-error-color: #ad5f5f; -} - -body[theme=dark] { - --satus-contrast: 255, 255, 255; - --satus-primary: #8f8f8f; - --satus-switch-background: rgba(var(--satus-contrast),.08); - --satus-header-background: #1f1f1f; - --satus-header-border: rgba(var(--satus-contrast),.08); - --satus-header-text: #ccc; - --satus-layers-background: #000; - --satus-layers-text: #ccc; - --satus-section-card-background: #1e1e1e; - --satus-section-card-border: rgba(var(--satus-contrast),.08); - --satus-modal-background: #212121; - --satus-modal-border: rgba(var(--satus-contrast),.08); - --satus-modal-text: #ccc; - --satus-hover: rgba(var(--satus-contrast), .05); - --satus-text-field--background: #333333; - --satus-text-field--border: #525252; - --satus-text-field--text: #ccc; - --satus-switch-track: #111; - --satus-switch-track--active: var(--satus-primary); - --satus-switch-thumb: #ddd; - --satus-tooltip: rgba(var(--satus-contrast),.4); - --satus-sortable-ghost: rgba(var(--satus-contrast), .8); - --satus-sortable-background: rgba(var(--satus-contrast), .1); - --satus-sortable-text: #fff; - --satus-divider: rgba(var(--satus-contrast),.08); - --satus-tabs-background: #111; - --satus-tabs-foreground: #2e2e2e; - --satus-tabs-border: #2f2f2f; - --satus-checkbox--background: rgb(var(--satus-contrast), .08); - --satus-checkbox--border: #2f2f2f; - --satus-checkbox--mark: #fff; - --satus-alert-error-background: #501616; - --satus-alert-error-border: #6f1f1f; - --satus-alert-error-color: #cf7777; -} -/*-------------------------------------------------------------- ->>> COLOR PICKER: ----------------------------------------------------------------- -# Button -# Modal ---------------------------------------------------------------*/ - - -/*-------------------------------------------------------------- -# BUTTON ---------------------------------------------------------------*/ - -.satus-color-picker { - font-size: inherit; - position: relative; - display: flex; - box-sizing: border-box; - margin: 0; - cursor: pointer; - color: inherit; - border: none; - outline: none; - background-color: var(--satus-theme-button); - justify-content: space-between; - -webkit-tap-highlight-color: transparent; - align-items: center; - -webkit-appearance: none; -} - -.satus-color-picker__value { - width: 22px; - height: 22px; - border: 2px solid rgba(0, 0, 0, .16); - border-radius: 50%; - background: #fff; -} - - -/*-------------------------------------------------------------- -# MODAL ---------------------------------------------------------------*/ - -.satus-modal--color-picker { - position: relative; -} - -.satus-modal--color-picker .satus-modal__surface { - padding-top: 0; -} - -.satus-color-picker__palette { - position: relative; - overflow: hidden; - width: 100%; - height: 256px; - background-color: #f00; -} - -.satus-color-picker__palette:before { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - content: ''; - background-image: linear-gradient(0deg, black, transparent), linear-gradient(90deg, white, transparent); -} - -.satus-color-picker__cursor { - position: absolute; - width: 5px; - height: 5px; - transform: translate(-50%, -50%); - pointer-events: none; - border: 1px solid #fff; - border-radius: 50%; - box-shadow: 0 0 0 1px #000; -} - -.satus-modal--color-picker .satus-modal__surface .satus-section--color { - margin: 8px 16px 0; - align-items: center; -} - -.satus-color-picker__color { - width: 32px; - height: 32px; - margin: 0 16px 0 0; - border: 2px solid rgba(0, 0, 0, .16); - border-radius: 50%; - background: #f00; -} - -.satus-slider.satus-color-picker__hue { - padding: 0; - flex: 1; -} - -.satus-color-picker__hue .satus-slider__track { - height: 16px; - border-radius: 4px; - background-image: linear-gradient(90deg, #f00, #ff2a00, #f50, #ff7f00, #fa0, #ffd400, #ff0, #d4ff00, #af0, #80ff00, #5f0, #2bff00, #0f0, #00ff2b, #0f5, #00ff80, #0fa, #00ffd5, #0ff, #00d4ff, #0af, #007fff, #05f, #002bff, #00f, #2a00ff, #50f, #7f00ff, #a0f, #d400ff, #f0f, #ff00d4, #f0a, #ff0080, #f05, #ff002b, #f00); -} - -.satus-color-picker__hue .satus-slider__handle { - width: 16px; - height: 16px; - background: #fff; - box-shadow: 0 0 4px rgb(0, 0, 0, .64); -} - -.satus-color-picker__hue::before, -.satus-color-picker__hue .satus-slider__track-fill, -.satus-color-picker__hue .satus-slider__handle:focus::after { - display: none; -} -/*-------------------------------------------------------------- -# MAIN ---------------------------------------------------------------*/ - -.satus-main { - color: var(--satus-main-text); - background: var(--satus-main-background); - overflow-y: auto; - box-sizing: border-box; -} -/*-------------------------------------------------------------- ->>> TABS ---------------------------------------------------------------*/ - -.satus-tabs { - display: flex; - height: 26px !important; -} - -.satus-tabs__content { - position: relative; - overflow: hidden; - width: 100%; - height: 100%; - border: 2px solid var(--satus-tabs-background); - border-radius: 4px; - background: var(--satus-tabs-background); - display: flex; -} - -.satus-tabs__selection { - position: absolute; - z-index: 0; - top: 0; - left: 0; - height: 100%; - transition: left .25s; - border-radius: 4px; - background: var(--satus-tabs-foreground); - box-sizing: border-box; - border: 1px solid var(--satus-tabs-border); -} - -.satus-tabs__button { - font: inherit; - position: relative; - z-index: 1; - overflow: hidden; - height: 100%; - padding: 0 4px; - white-space: nowrap; - text-overflow: ellipsis; - color: inherit; - border: none; - background: transparent; - flex: 1; - text-align: center; -} - -.satus-tabs__button:hover { - cursor: pointer; -} -/*-------------------------------------------------------------- ->>> MENUBAR ---------------------------------------------------------------*/ - -.satus-menubar { - display: flex; -} - -.satus-menubar, -.satus-menubar ul { - margin: 0; - padding: 0; - list-style: none; - color: var(--satus-menubar-text); - background: var(--satus-menubar-background); -} - -.satus-menubar li { - position: relative; -} - -.satus-menubar li:focus, -.satus-menubar li:hover { - background: var(--satus-menubar-hover); -} - -.satus-menubar>li ul { - position: absolute; - min-width: 126px; -} - -.satus-menubar>li>ul ul { - top: 0; - left: 100%; -} - -.satus-menubar li>ul { - position: absolute; - display: none; -} - -.satus-menubar li>*:not(ul):focus+ul, -.satus-menubar li>*:not(ul):hover+ul, -.satus-menubar li>ul:hover { - display: block; -} - -.satus-menubar li> :not(ul) { - font-size: 14px; - display: flex; - width: 100%; - height: 32px; - align-items: center; -} -/*-------------------------------------------------------------- ->>> RADIO ---------------------------------------------------------------*/ -/*-------------------------------------------------------------- -# BUTTON ---------------------------------------------------------------*/ - -.satus-button { - font: inherit; - position: relative; - display: flex; - overflow: hidden; - height: 48px; - margin: 0; - padding: 8px; - text-align: left; - color: var(--satus-button-text, inherit); - border: none; - background: var(--satus-button-background, transparent); - appearance: none; - align-items: center; -} - -.satus-button:hover { - cursor: pointer; - background-color: var(--satus-hover); -} - -.satus-button[hidden] { - display: none; -} - -.satus-button>svg { - min-width: 20px; -} - -.satus-button>.satus-span--label { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -/*-------------------------------------------------------------- ->>> LIST: ---------------------------------------------------------------*/ - -.satus-list { - list-style: none; - margin: 0; -} - -.satus-list__item { - display: flex; - align-items: center; - justify-content: space-between; - min-height: 48px; -} - -.satus-list__item>*:last-child { - text-align: right; -} -/*-------------------------------------------------------------- ->>> TEXTAREA ---------------------------------------------------------------*/ - -.satus-textarea { - position: relative; - display: flex; - overflow: hidden; - color: var(--satus-textarea-color, inherit); - background: var(--satus-textarea-background); -} - -.satus-textarea textarea { - font-size: inherit; - line-height: 1.2; - overflow: auto; - width: 100%; - height: 100%; - padding: 0; - resize: none; - white-space: pre; - word-break: break-all; - color: inherit; - border: none; - outline: none; - background: transparent; - overflow-wrap: normal; -} - -.satus-textarea__line-number { - width: 32px; - padding: 0 16px 0 0; - word-break: break-all; - opacity: .5; -} - -.satus-textarea__line-number>span { - font-size: inherit; - line-height: 1.2; - display: block; - width: 100%; - text-align: right; -} -/*-------------------------------------------------------------- ->>> SECTION: ----------------------------------------------------------------- -# Align -# Card ---------------------------------------------------------------*/ - -.satus-section { - display: flex; - box-sizing: border-box; - flex-wrap: wrap; -} - - -/*-------------------------------------------------------------- -# ALIGN ---------------------------------------------------------------*/ - -.satus-section--align-start { - align-items: center; - justify-content: flex-start; -} - -.satus-section--align-end { - align-items: center; - justify-content: flex-end; -} - -.satus-section--space-between { - align-items: center; - justify-content: space-between; -} - -.satus-section--column { - flex-direction: column; -} - - -/*-------------------------------------------------------------- -# CARD ---------------------------------------------------------------*/ - -.satus-section--card { - flex-direction: column; - box-sizing: border-box; - width: 100%; - max-width: 900px; - margin: 8px auto; - padding: 8px 0; - color: var(--satus-section-card-text); - border: 1px solid var(--satus-section-card-border); - border-radius: 8px; - background: var(--satus-section-card-background); - justify-content: stretch; -} - -.satus-section--label { - width: 100%; - max-width: 900px; - margin: 8px auto; -} - -.satus-section--card>*:not(.satus-button) { - box-sizing: border-box; - min-height: 48px; - padding: 0 16px; - text-align: left; -} - -.satus-section--card>.satus-switch, -.satus-section--card>.satus-select, -.satus-section--card>.satus-radio { - display: flex; - justify-content: space-between; - align-items: center; -} - -.satus-section--card>.satus-button:hover, -.satus-section--card>.satus-switch:hover, -.satus-section--card>.satus-select:hover, -.satus-section--card>.satus-slider:hover, -.satus-section--card>.satus-radio:hover { - background-color: var(--satus-hover); -} - -.satus-section--card>.satus-button { - width: 100%; - padding: 0 16px; -} - -.satus-section--card>.satus-button>svg { - width: 20px; - margin: 2px 16px 0 0; - color: var(--satus-primary); -} - -.satus-section--card>.satus-span { - display: flex; - align-items: center; -} -/*-------------------------------------------------------------- -# SCROLLBAR ---------------------------------------------------------------*/ - -::-webkit-scrollbar { - width: 4px; -} - -::-webkit-scrollbar:hover { - width: 8px; -} - -::-webkit-scrollbar-thumb { - background: rgba(0, 0, 0, .3); -} -/*-------------------------------------------------------------- ->>> MODAL ---------------------------------------------------------------*/ - -.satus-modal { - position: absolute; - z-index: 100; - top: 0; - left: 0; - display: flex; - width: 100%; - height: 100vh; - justify-content: center; - align-items: center; -} - -.satus-modal__scrim { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - animation: modalFadeIn 150ms linear forwards; - opacity: 0; - background: rgba(0, 0, 0, .16); - backdrop-filter: blur(8px); -} - -.satus-modal__surface { - display: flex; - overflow-y: auto; - flex-direction: column; - width: 95%; - min-width: 240px; - max-width: 560px; - max-height: 80%; - margin: 0 16px; - padding: 12px 16px; - transform: scale(.8); - animation: modalZoomIn 150ms linear forwards; - animation-delay: 20ms; - opacity: 0; - color: var(--satus-modal-text); - border-radius: 6px; - background-color: var(--satus-modal-background); - border: 1px solid var(--satus-modal-border); - box-shadow: 0 2px 6px rgb(0, 0, 0, .15); - box-sizing: border-box; -} - -.satus-modal__surface .satus-section--actions { - display: flex; - width: 100%; - margin: 8px 0 0; - padding: 0; - justify-content: flex-end; - align-items: center; -} - -.satus-modal__surface .satus-section--actions .satus-button { - font-weight: 500; - height: 32px; - margin-left: 8px; - padding: 0 8px; - letter-spacing: .5px; - color: var(--satus-primary); - border-radius: 4px; -} - -.satus-modal--closing .satus-modal__scrim { - animation: modalFadeOut 70ms linear forwards; -} - -.satus-modal--closing .satus-modal__surface { - animation: modalZoomOut 70ms linear forwards; -} - -.satus-modal--vertical .satus-modal__surface { - position: absolute; - top: 8px; - right: 8px; - left: auto; - min-width: 200px; - max-width: 200px; - margin: 0; - padding: 8px 0; - transform-origin: right top; -} - -.satus-modal--vertical .satus-modal__surface>.satus-button, -.satus-modal--vertical .satus-modal__surface>.satus-switch, -.satus-modal--vertical .satus-modal__surface>.satus-select { - display: flex; - height: 36px; - padding: 0 16px; - align-items: center; -} - -.satus-modal--vertical .satus-modal__surface>.satus-tabs { - padding: 0 12px; -} - -.satus-modal--vertical .satus-modal__surface>.satus-span { - font-size: 13px; - font-weight: 500; - margin: 6px 0; - padding: 0 12px; -} - -.satus-modal--vertical .satus-modal__surface>.satus-button:hover, -.satus-modal--vertical .satus-modal__surface>.satus-switch:hover, -.satus-modal--vertical .satus-modal__surface>.satus-select:hover { - background-color: var(--satus-hover); -} - -.satus-modal--vertical .satus-button svg { - width: 20px; - height: 18px; - margin: 0 14px 0 0; - opacity: .75; - flex: 0 0 20px; -} - -.satus-modal--vertical .satus-button .satus-span { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - - -/*-------------------------------------------------------------- -# ANIMATIONS ---------------------------------------------------------------*/ - -@keyframes modalFadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes modalFadeOut { - from { - opacity: 1; - } - to { - opacity: 0; - } -} - -@keyframes modalZoomIn { - from { - transform: scale(.8); - opacity: 0; - } - to { - transform: scale(1); - opacity: 1; - } -} - -@keyframes modalZoomOut { - from { - transform: scale(1); - opacity: 1; - } - to { - transform: scale(.8); - opacity: 0; - } -} -/*-------------------------------------------------------------- ->>> CHECKBOX ---------------------------------------------------------------*/ - -.satus-checkbox { - position: relative; - font: inherit; - display: flex; - color: inherit; - border: none; - background: transparent; - appearance: none; - align-items: center; - justify-content: flex-start; -} - -.satus-checkbox:hover { - cursor: pointer; - background-color: var(--satus-hover); -} - -.satus-checkbox:focus { - outline: none; -} - -.satus-checkbox__content { - display: block; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} - -.satus-checkbox::before { - display: flex; - min-width: 16px; - width: 16px; - height: 16px; - margin: 0 12px 0 0; - content: ''; - border: 1px solid var(--satus-checkbox--border); - border-radius: 6px; - background: var(--satus-checkbox--background); - align-items: center; - justify-content: center; -} - -.satus-checkbox[data-value=true]::before { - background: var(--satus-primary); -} - -.satus-checkbox[data-value=true]::after { - position: absolute; - top: 20px; - left: 20px; - width: 8px; - height: 4px; - content: ''; - transform: rotate(-45deg); - border: 2px solid var(--satus-checkbox--mark); - border-top: none; - border-right: none; -} -/*-------------------------------------------------------------- ->>> SWITCH ----------------------------------------------------------------- -# Container -# Track -# Thumb ---------------------------------------------------------------*/ - - -/*-------------------------------------------------------------- -# CONTAINER ---------------------------------------------------------------*/ - -.satus-switch { - font: inherit; - display: flex; - transition: background-color 75ms; - color: inherit; - border: none; - outline: none; - background-color: transparent; - justify-content: space-between; - align-items: center; -} - -.satus-switch:hover { - cursor: pointer; -} - -.satus-switch__content { - display: flex; - align-items: center; -} - -.satus-switch__content>svg { - width: 20px; - height: 18px; - margin: 0 14px 0 0; - opacity: .75; -} - - -/*-------------------------------------------------------------- -# TRACK ---------------------------------------------------------------*/ - -.satus-switch>i { - width: 32px; - height: 18px; - transition: background-color 150ms; - border-radius: 18px; - background-color: var(--satus-switch-track); - flex: 0 0 32px; -} - -.satus-section--card .satus-switch>i { - margin-left: 16px; -} - -.satus-switch[data-value='true']>i { - background-color: var(--satus-switch-track--active); -} - - -/*-------------------------------------------------------------- -# THUMB ---------------------------------------------------------------*/ - -.satus-switch>i::before { - display: block; - width: 14px; - height: 14px; - margin: 2px; - content: ''; - transition: transform 150ms cubic-bezier(.4, 0, .2, 1); - border-radius: 50%; - background-color: var(--satus-switch-thumb); - will-change: transform; -} - -.satus-switch[data-value='true']>i::before { - transform: translateX(14px); -} -/*-------------------------------------------------------------- ->>> SLIDER ---------------------------------------------------------------*/ - -.satus-slider { - box-sizing: border-box; - width: 100%; - padding: 8px 16px 0; - outline: none; -} - -.satus-slider__container { - position: relative; - display: block; - width: 100%; - height: 32px; -} - -.satus-slider__track { - position: absolute; - top: 50%; - left: 0; - width: 100%; - height: 2px; - transform: translateY(-50%); -} - -.satus-slider__track::before { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - content: ''; - opacity: .24; - background: var(--satus-primary); -} - -.satus-slider__handle:focus::after { - position: absolute; - top: -2px; - left: 50%; - display: block; - padding: 1px 4px; - content: attr(data-value); - transform: translate(-50%, -100%); - color: #fff; - border-radius: 4px; - background: var(--satus-primary); -} - -.satus-slider__track-fill { - position: absolute; - top: 0; - left: 0; - height: 100%; - background: var(--satus-primary); -} - -.satus-slider__handle { - position: absolute; - top: 50%; - left: 0; - width: 10px; - height: 10px; - transform: translate(-50%, -50%); - border-radius: 50%; - background: var(--satus-primary); -} - -.satus-slider__handle::before { - position: absolute; - top: 50%; - left: 50%; - width: 1px; - height: 1px; - content: ''; - transition: .2s; - transform: translate(-50%, -50%) scale(1); - opacity: 0; - border-radius: 50%; - background: var(--satus-primary); -} - -.satus-slider:focus .satus-slider__handle::before { - transform: translate(-50%, -50%) scale(26); - opacity: .24; -} -/*-------------------------------------------------------------- ->>> SHORTCUT: ----------------------------------------------------------------- -# ---------------------------------------------------------------*/ - -.satus-shortcut { - justify-content: space-between; -} - -.satus-shortcut__value { - font-size: 11px; - display: flex; - text-transform: uppercase; - align-items: center; -} - -.satus-shortcut__actions { - display: flex; - justify-content: flex-end; -} - -.satus-shortcut__actions .satus-button { - height: 32px; - margin: 8px 4px 0; - border-radius: 8px; - background: rgba(0, 0, 0, .15); -} - -.satus-shortcut__actions .satus-button:hover { - background: rgba(0, 0, 0, .25); -} - -.satus-shortcut__primary { - display: flex; - box-sizing: border-box; - width: 100%; - height: 68px; - padding: 16px; - background: rgba(0, 0, 0, .16); - align-items: center; -} - -.satus-shortcut__key { - display: flex; - box-sizing: border-box; - min-width: 32px; - height: 32px; - padding: 4px 8px; - border-radius: 4px; - background: #fff; - box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1); - align-items: center; - justify-content: center; -} - -.satus-shortcut__value>.satus-shortcut__key { - font-size: 14px; - min-width: 24px; - height: 24px; -} - -.satus-shortcut__plus { - position: relative; - width: 12px; - height: 12px; - margin: 8px; -} - -.satus-shortcut__plus::before { - position: absolute; - top: 0; - left: 5px; - width: 2px; - height: 12px; - content: ''; - background-color: #aaa; -} - -.satus-shortcut__plus::after { - position: absolute; - top: 5px; - left: 0; - width: 12px; - height: 2px; - content: ''; - background-color: #aaa; -} - -.satus-shortcut__mouse { - position: relative; - display: flex; - width: 28px; - height: 36px; - border-radius: 50%; - border-top-left-radius: 12px; - border-top-right-radius: 12px; - background: #fff; - box-shadow: 0 1px 3px rgba(0, 0, 0, .15), inset 0 -3px 0 rgba(0, 0, 0, .1); -} - -.satus-shortcut__value>.satus-shortcut__mouse { - width: 22px; - height: 28px; -} - -.satus-shortcut__mouse>div { - position: absolute; - top: 0; - left: calc(50% - 1px); - width: 2px; - height: 11px; - border-radius: 2px; - background: #ccc; -} - -.satus-shortcut__mouse::before { - position: absolute; - top: -16%; - right: 14%; - width: 2px; - height: 60%; - content: ''; - background: #f96754; -} - -.satus-shortcut__mouse.false::before { - top: -6%; -} - -.satus-shortcut__mouse.false::after { - position: absolute; - top: -20%; - right: calc(14% - 4px); - width: 0; - height: 0; - content: ''; - border-right: 5px solid transparent; - border-bottom: 8px solid #f96754; - border-left: 5px solid transparent; -} - -.satus-shortcut__mouse.true::after { - position: absolute; - top: 40%; - right: calc(14% - 4px); - width: 0; - height: 0; - content: ''; - border-top: 8px solid #f96754; - border-right: 5px solid transparent; - border-left: 5px solid transparent; -} - -.satus-shortcut__mouse.click::before { - position: absolute; - top: 0; - left: -1px; - width: 10px; - height: 10px; - content: ''; - border-radius: 50%; - background: #f96754; -} - -.satus-shortcut__mouse.context::before { - position: absolute; - top: 0; - left: 15px; - width: 10px; - height: 10px; - content: ''; - border-radius: 50%; - background: #f96754; -} - -.satus-section_shortcut { - width: 100%; - margin: 8px 0 0; - justify-content: flex-end; -} - -.satus-button_shortcut { - font-weight: 500; - overflow: hidden; - height: 28px; - min-height: 28px; - margin-right: 2px; - padding: 4px 8px; - text-transform: uppercase; - color: #f96754; - border-radius: 4px; -} -/*-------------------------------------------------------------- ->>> BASE ---------------------------------------------------------------*/ - -.satus-base { - display: flex; - flex-direction: column; - width: 100%; - height: 100% -} -/*-------------------------------------------------------------- ->>> TEXT FIELD ---------------------------------------------------------------*/ - -.satus-text-field { - position: relative; - padding: 0 16px; - background-color: var(--satus-text-field--background); - border-radius: 8px; - color: var(--satus-text-field--text); - overflow: hidden; - display: flex; -} - -.satus-text-field__pre { - display: flex; - position: relative; - height: 100%; - margin: 0; - padding: 0; - overflow: hidden; - align-items: center; - flex: 1; -} - -.satus-text-field__input { - font: inherit; - position: absolute; - top: 0; - left: 0; - width: 100%; - min-width: 0; - max-width: none; - height: 100%; - min-height: 0; - max-height: none; - margin: 0; - padding: 0; - opacity: 0; - border: none; - appearance: none; - z-index: 9; -} - -.satus-text-field__hidden-text { - position: absolute; - pointer-events: none; - opacity: 0; -} - -.satus-text-field__text { - position: absolute; - top: 0; - left: 0; - display: flex; - height: 100%; - margin: 0; - align-items: center; -} - -.satus-text-field__cursor { - position: absolute; - top: 6px; - left: 0; - display: none; - width: 2px; - height: 25px; - animation: blink 1s step-end 8; - background: #fa0; -} - -.satus-text-field__selection { - position: absolute; - top: 5px; - left: 0; - display: none; - width: 0; - height: 25px; - border: 1px solid rgba(255, 255, 255, .2); - border-radius: 3px; - background: rgba(255, 255, 255, .1); -} - -.satus-text-field__input:focus + * + * + * + .satus-text-field__cursor, -.satus-text-field__selection:not([disabled]) { - display: block; -} - -@keyframes blink { - from, - to { - opacity: 1; - } - 50% { - opacity: 0; - } -} - - -/*-------------------------------------------------------------- -# SYNTAX HIGHLIGHTING ---------------------------------------------------------------*/ - -.satus-text-field__text>.group { - color: #47ff47; - background-color: rgb(71, 255, 71, .16); -} - -.satus-text-field__text>.character-class { - color: #ffc247; - background-color: rgb(255, 170, 0, .16); -} - -.satus-text-field__text>.quantifier { - color: #47c2ff; - background-color: rgb(71, 194, 255, .16); -} - -.satus-text-field__text>.anchor { - color: #47c2ff; - background-color: rgb(71, 194, 255, .16); -} - -.satus-text-field__text>.metasequence { - color: #47ff47; - background-color: rgb(71, 255, 71, .16); -} - -.satus-text-field__text>.text { - color: #c4c4d4; - background-color: rgb(196, 196, 212, .16); -} -/*-------------------------------------------------------------- ->>> HEADER ---------------------------------------------------------------*/ - -.satus-header { - z-index: 1; - display: flex; - box-sizing: border-box; - height: 56px; - padding: 0 12px; - color: var(--satus-header-text); - background: var(--satus-header-background); - border-bottom: 1px solid var(--satus-header-border); - box-shadow: 0 0 3px rgb(0, 0, 0, .1); - align-items: center; - justify-content: space-between; -} - -.satus-header .satus-button { - width: 40px; - min-width: 40px; - height: 40px; - padding: 8px; - color: inherit; - border-radius: 50%; -} - -.satus-header .satus-section--align-start>* { - margin-right: 8px; -} - -.satus-header .satus-span--title { - font-size: 15px; - font-weight: 500; - overflow: hidden; - white-space: nowrap; - letter-spacing: .0125em; - text-overflow: ellipsis; - flex: 1; -} -/*-------------------------------------------------------------- ->>> ALERT ---------------------------------------------------------------*/ - -.satus-alert { - display: flex; - box-sizing: border-box; - min-height: 48px; - margin: 8px 0 0; - padding: 8px 16px; - border-radius: 8px; - align-items: center; -} - -.satus-alert--error { - color: var(--satus-alert-error-color); - border: 1px solid var(--satus-alert-error-border); - background: var(--satus-alert-error-background); -} -/*-------------------------------------------------------------- ->>> LAYERS ---------------------------------------------------------------*/ - -.satus-layers { - position: relative; - overflow: hidden; - color: var(--satus-layers-text); - background: var(--satus-layers-background); - flex: 1; -} - -.satus-layer { - position: absolute; - top: 0; - left: 0; - display: flex; - overflow-y: auto; - flex-direction: column; - box-sizing: border-box; - width: 100%; - height: 100%; - padding: 0 12px; - align-content: center; -} -/*-------------------------------------------------------------- ->>> DIVIDER ---------------------------------------------------------------*/ - -.satus-divider { - height: 1px; - margin: 16px 0 12px; - background: var(--satus-divider); -} -/*-------------------------------------------------------------- -# INPUT ---------------------------------------------------------------*/ - -.satus-input[type=text], -.satus-input[type=password] { - font: inherit; - box-sizing: border-box; - width: 100%; - margin: 0; - padding: 0 8px; - color: var(--satus-text-field--text, inherit); - border: none; - outline: none; - background: none; - appearance: none; - font-size: 16px; - margin: 8px 0; - border: 1px solid var(--satus-text-field--border); - border-radius: 4px; - background-color: var(--satus-text-field--background); -} -/**/ - -.satus-aside { - color: var(--satus-aside-text); - background: var(--satus-aside-background); - box-sizing: border-box; -} -/*-------------------------------------------------------------- ->>> SELECT ---------------------------------------------------------------*/ - -.satus-select { - position: relative; - display: flex; - box-sizing: border-box; - align-items: center; - justify-content: space-between; -} - -.satus-select__content { - display: flex; - align-items: center; -} - -.satus-select__content > svg { - width: 20px; - - height: 18px; - margin: 0 14px 0 0; - opacity: .75; -} - -.satus-select__value { - margin-left: 16px; - text-align: right; - opacity: .75; -} - -.satus-select select { - font: inherit; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - margin: 0; - padding: 0; - padding: inherit; - cursor: pointer; - opacity: 0; - border: none; - outline: none; - background: none; - appearance: none; -} - -.satus-select:hover { - cursor: pointer; - background-color: var(--satus-hover); -} -/*-------------------------------------------------------------- ->>> CONTEXT MENU ---------------------------------------------------------------*/ - -.satus-modal--contextmenu .satus-modal__scrim { - background: none; - backdrop-filter: none; - animation: none; - visibility: visible; - opacity: 1; - transform: none; -} - -.satus-modal--contextmenu .satus-modal__surface { - position: absolute; - margin: 0; - box-sizing: border-box; - min-width: 200px; - max-width: 200px; - padding: 4px 0; - border-radius: 4px; - box-shadow: none; - animation: none; - visibility: visible; - opacity: 1; - transform: none; -} - -.satus-modal--contextmenu .satus-modal__surface > * { - -} - -.satus-modal--contextmenu .satus-modal__surface>* { - display: flex; - height: 32px; - padding: 0 16px; - align-items: center; -} - -.satus-modal--contextmenu .satus-modal__surface .satus-button svg { - width: 20px; - height: 18px; - margin: 0 14px 0 0; - opacity: .75; - fill: none; - stroke: var(--satus-primary); - flex: 0 0 20px; -} - -.satus-modal--contextmenu .satus-modal__surface .satus-button .satus-span { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -/*-------------------------------------------------------------- ->>> PLUVIAM ---------------------------------------------------------------*/ - -.satus-pluviam { - position: absolute; - transform: scale(0); - animation-name: pluviam; - animation-duration: 1000ms; - opacity: var(--satus-pluviam-opacity, .08); - border-radius: 50%; - background: var(--satus-pluviam-background, #000); - animation-fill-mode: forwards; -} - -@keyframes pluviam { - 0% { - transform: scale(0); - opacity: var(--satus-pluviam-opacity, .08); - } - 70% { - transform: scale(.8); - opacity: var(--satus-pluviam-opacity, .08); - } - 100% { - transform: scale(1); - opacity: 0; - } -} -/*-------------------------------------------------------------- ->>> SORTABLE ---------------------------------------------------------------*/ - -.satus-sortable__chosen { - color: var(--satus-sortable-text) !important; - background-color: var(--satus-sortable-background) !important; -} - -.satus-sortable__ghost { - position: fixed !important; - z-index: 999 !important; - top: 0 !important; - left: 0 !important; - pointer-events: none !important; - box-shadow: 0 1px 3px rgb(0, 0, 0, .2), 0 4px 8px rgb(0, 0, 0, .1), inset 0 0 0 1px rgb(0, 0, 0, .16); - will-change: transform !important; - opacity: .8 !important; -} \ No newline at end of file diff --git a/ui/satus/satus.js b/ui/satus/satus.js deleted file mode 100644 index 91cbef6..0000000 --- a/ui/satus/satus.js +++ /dev/null @@ -1,2722 +0,0 @@ - -/*-------------------------------------------------------------- ->>> CORE: ----------------------------------------------------------------- -# Global variable -# Functions -# Render ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# GLOBAL VARIABLE ---------------------------------------------------------------*/ - -var satus = { - components: {}, - events: {}, - locale: { - strings: {} - }, - storage: { - attributes: {}, - data: {} - } -}; - - -/*-------------------------------------------------------------- -# FUNCTIONS ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# APPEND ---------------------------------------------------------------*/ - -satus.append = function (element, container) { - (container || document.body).appendChild(element); -}; - - -/*-------------------------------------------------------------- -# ANIMATION DURATION ---------------------------------------------------------------*/ - -satus.getAnimationDuration = function (element) { - return Number(window.getComputedStyle(element).getPropertyValue('animation-duration').replace(/[^0-9.]/g, '')) * 1000; -}; - - -/*-------------------------------------------------------------- -# APPEND ---------------------------------------------------------------*/ - -satus.attr = function (element, attributes) { - if (attributes) { - for (var key in attributes) { - if (element.is_svg) { - element.setAttributeNS(null, key, attributes[key]); - } else { - var value = attributes[key]; - - if (['placeholder', 'title'].indexOf(key) !== -1) { - value = satus.locale.get(value); - } - - element.setAttribute(key, value); - } - } - } -}; - -satus.elementIndex = function (element) { - return Array.prototype.slice.call(element.parentNode.children).indexOf(element); -}; - - -/*-------------------------------------------------------------- -# DATA ---------------------------------------------------------------*/ - -satus.data = function (element, data) { - if (data) { - for (var key in data) { - element.dataset[key] = data[key]; - } - } -}; - - -/*-------------------------------------------------------------- -# PROPERTIES ---------------------------------------------------------------*/ - -satus.properties = function (element, properties) { - if (properties) { - for (var key in properties) { - element[key] = properties[key]; - } - } -}; - - -/*-------------------------------------------------------------- -# CAMELIZE ---------------------------------------------------------------*/ - -satus.camelize = function (string) { - var result = ''; - - for (var i = 0, l = string.length; i < l; i++) { - var character = string[i]; - - if (character === '-') { - i++; - - result += string[i].toUpperCase(); - } else { - result += character; - } - } - - return result; -}; - - -/*-------------------------------------------------------------- -# SNAKELIZE ---------------------------------------------------------------*/ - -satus.snakelize = function (string) { - return string.replace(/([A-Z])/g, '-$1').toLowerCase(); -}; - - -/*-------------------------------------------------------------- -# CLASS ---------------------------------------------------------------*/ - -satus.class = function (element, string) { - if (string) { - element.className += ' ' + string; - } -}; - - -/*-------------------------------------------------------------- -# EMPTY ---------------------------------------------------------------*/ - -satus.empty = function (element, exclude = []) { - for (var i = element.childNodes.length - 1; i > -1; i--) { - var child = element.childNodes[i]; - - if (exclude.indexOf(child) === -1) { - child.remove(); - } - } -}; - - -/*-------------------------------------------------------------- -# EVENTS ---------------------------------------------------------------*/ - -Object.defineProperty(satus.events, 'add', { - value: function (type, listener) { - if (this.hasOwnProperty(type) === false) { - this[type] = []; - } - - this[type].push(listener); - } -}); - - -/*-------------------------------------------------------------- -# ISSET ---------------------------------------------------------------*/ - -satus.isset = function (variable) { - if (variable === null || variable === undefined) { - return false; - } - - return true; -}; - - -/*-------------------------------------------------------------- -# FETCH ---------------------------------------------------------------*/ - -satus.fetch = function (url, success, error) { - fetch(url).then(function (response) { - if (response.ok) { - response.json().then(success); - } else { - error(); - } - }); -}; - - -/*-------------------------------------------------------------- -# AJAX ---------------------------------------------------------------*/ - -satus.ajax = function (url, success, error) { - var xhr = new XMLHttpRequest(); - - xhr.onload = function () { - success(this.response); - }; - xhr.onerror = function () { - error(success); - }; - - xhr.open('GET', url, true); - xhr.send(); -}; - - -/*-------------------------------------------------------------- -# STORAGE ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# GET ---------------------------------------------------------------*/ - -satus.storage.get = function (name) { - var target = satus.storage.data; - - if (typeof name !== 'string') { - return; - } - - name = name.split('/').filter(function (value) { - return value != ''; - }); - - for (var i = 0, l = name.length; i < l; i++) { - if (satus.isset(target[name[i]])) { - target = target[name[i]]; - } else { - return undefined; - } - } - - return target; -}; - - -/*-------------------------------------------------------------- -# SET ---------------------------------------------------------------*/ - -satus.storage.set = function (name, value, callback) { - var items = {}, - target = satus.storage.data; - - if (typeof name !== 'string') { - return; - } - - name = name.split('/').filter(function (value) { - return value != ''; - }); - - for (var i = 0, l = name.length; i < l; i++) { - var item = name[i]; - - if (i < l - 1) { - - if (target[item]) { - target = target[item]; - } else { - target[item] = {}; - - target = target[item]; - } - } else { - target[item] = value; - } - } - - for (var key in this.data) { - if (typeof this.data[key] !== 'function') { - items[key] = this.data[key]; - } - } - - if (satus.storage.attributes[name]) { - document.body.setAttribute(name, value); - } - - chrome.storage.local.set(items, callback); -}; - - -/*-------------------------------------------------------------- -# REMOVE ---------------------------------------------------------------*/ - -satus.storage.remove = function (name) { - delete this.data[name]; - - chrome.storage.local.remove(name); -}; - - -/*-------------------------------------------------------------- -# IMPORT ---------------------------------------------------------------*/ - -satus.storage.import = function (keys, callback) { - if (typeof keys === 'function') { - callback = keys; - - keys = undefined; - } - - chrome.storage.local.get(keys, function (items) { - for (var key in items) { - if (satus.storage.attributes[key]) { - document.body.setAttribute(key, items[key]); - } - - satus.storage.data[key] = items[key]; - } - - if (callback) { - callback(items); - } - }); -}; - - -/*-------------------------------------------------------------- -# CLEAR ---------------------------------------------------------------*/ - -satus.storage.clear = function (callback) { - this.data = {}; - - chrome.storage.local.clear(callback); -}; - - -/*-------------------------------------------------------------- -# LOCALIZATION ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# GET ---------------------------------------------------------------*/ - -satus.locale.get = function (string) { - return this.strings[string] || string; -}; - - -/*-------------------------------------------------------------- -# IMPORT ---------------------------------------------------------------*/ - -satus.locale.import = function (code, path, callback) { - var language = code || window.navigator.language; - - if (language.indexOf('en') === 0) { - language = 'en'; - } - - if (!path) { - path = '_locales/'; - } - - satus.fetch(path + language + '/messages.json', function (response) { - for (var key in response) { - satus.locale.strings[key] = response[key].message; - } - - callback(); - }, function (success) { - satus.fetch(path + 'en/messages.json', success); - }); -}; - - -/*-------------------------------------------------------------- -# ON ---------------------------------------------------------------*/ - -satus.on = function (element, events) { - if (this.isset(events) && typeof events === 'object') { - for (var selector in events) { - var type = typeof events[selector]; - - if (selector === 'selectionchange') { - element = document; - } - - if (type === 'function') { - element.addEventListener(selector, events[selector]); - } else if (type === 'object') { - element.addEventListener(selector, function (event) { - this.skeleton.on[event.type].parent = this.skeleton; - - if (this.skeleton.on[event.type].component !== 'modal' && this.base && this.base.layers) { - this.base.layers.open(this.skeleton.on[event.type]); - } else { - satus.render(this.skeleton.on[event.type], this.base); - } - }); - } else if (type === 'string') { - element.addEventListener(selector, function () { - var match = this.skeleton.on[event.type].match(/(["'`].+["'`]|[^.()]+)/g), - target = this.base; - - for (var i = 0, l = match.length; i < l; i++) { - var key = match[i]; - - if (target.skeleton[key]) { - target = target.skeleton[key]; - } else { - if (typeof target[key] === 'function') { - target[key](); - } else { - target = target[key]; - } - } - - if (target.rendered) { - target = target.rendered; - } - } - }); - } - } - } -}; - - -/*-------------------------------------------------------------- -# STYLE ---------------------------------------------------------------*/ - -satus.style = function (component, object) { - for (var key in object) { - component.style[key] = object[key]; - } -}; - - -/*-------------------------------------------------------------- -# SEARCH ---------------------------------------------------------------*/ - -satus.search = function (query, object, callback) { - var elements = ['switch', 'select', 'slider', 'shortcut', 'radio', 'color-picker'], - threads = 0, - results = {}; - - query = query.toLowerCase(); - - function parse(items, parent) { - threads++; - - for (var key in items) { - if (key !== 'rendered' && key !== 'base' && key !== 'parent') { - var item = items[key]; - - if (elements.indexOf(item.component) !== -1 && key.indexOf(query) !== -1) { - results[key] = Object.assign({}, item); - } - - if (typeof item === 'object') { - parse(item, items); - } - } - } - - threads--; - - if (threads === 0) { - callback(results); - } - } - - parse(object); -}; - - -/*-------------------------------------------------------------- -# PARENTS ---------------------------------------------------------------*/ - -satus.parents = function (object, components_only) { - function parse(items, parent) { - for (var key in items) { - if (key !== 'rendered' && key !== 'base' && key !== 'parent') { - var item = items[key]; - - if (components_only !== true || item.component) { - item.parent = items; - } - - if (typeof item === 'object' && item.component !== 'shortcut') { - parse(item, items); - } - } - } - } - - parse(object); -}; - - -/*-------------------------------------------------------------- -# TEXT ---------------------------------------------------------------*/ - -satus.text = function (component, value) { - if (typeof value === 'function') { - value = value(); - } - - if (value) { - component.appendChild(document.createTextNode(this.locale.get(value))); - } -}; - - -/*-------------------------------------------------------------- -# DECRYPTION ---------------------------------------------------------------*/ - -satus.decrypt = async function (text, password) { - var iv = text.slice(0, 24).match(/.{2}/g).map(byte => parseInt(byte, 16)), - algorithm = { - name: 'AES-GCM', - iv: new Uint8Array(iv) - }; - - try { - var data = new TextDecoder().decode(await crypto.subtle.decrypt( - algorithm, - await crypto.subtle.importKey( - 'raw', - await crypto.subtle.digest('SHA-256', new TextEncoder().encode(password)), - algorithm, - false, ['decrypt'] - ), - new Uint8Array(atob(text.slice(24)).match(/[\s\S]/g).map(ch => ch.charCodeAt(0))) - )); - } catch (err) { - return false; - } - - return data; -}; - - -/*-------------------------------------------------------------- -# ENCRYPTION ---------------------------------------------------------------*/ - -satus.encrypt = async function (text, password) { - var iv = crypto.getRandomValues(new Uint8Array(12)), - algorithm = { - name: 'AES-GCM', - iv: iv - }; - - return Array.from(iv).map(b => ('00' + b.toString(16)).slice(-2)).join('') + btoa(Array.from(new Uint8Array(await crypto.subtle.encrypt( - algorithm, - await crypto.subtle.importKey('raw', await crypto.subtle.digest('SHA-256', new TextEncoder().encode(password)), algorithm, false, ['encrypt']), - new TextEncoder().encode(text) - ))).map(byte => String.fromCharCode(byte)).join('')); -}; - - -/*-------------------------------------------------------------- -# IS ---------------------------------------------------------------*/ - -satus.isArray = function (array) { - if (Array.isArray(array)) { - return true; - } else { - return false; - } -}; - -satus.isNumber = function (number) { - if (typeof number === 'number' && isNaN(number) === false) { - return true; - } else { - return false; - } -}; - - -/*-------------------------------------------------------------- -# INDEX OF ---------------------------------------------------------------*/ - -satus.indexOf = function (child, parent) { - var index = 0; - - if (satus.isArray(parent)) { - index = parent.indexOf(child); - } else { - while ((child = child.previousElementSibling)) { - index++; - } - } - - return index; -}; - - -/*-------------------------------------------------------------- -# TO INDEX ---------------------------------------------------------------*/ - -satus.toIndex = function (index, child, parent) { - if (satus.isArray(parent)) { - parent.splice(index, 0, parent.splice(satus.indexOf(child, parent), 1)[0]) - } -}; - - -/*-------------------------------------------------------------- -# CLONE ---------------------------------------------------------------*/ - -satus.clone = function (item) { - var clone = item.cloneNode(true), - parent_css = window.getComputedStyle(item.parentNode), - css = window.getComputedStyle(item), - style = ''; - - for (var i = 0, l = css.length; i < l; i++) { - var property = css[i], - value = css.getPropertyValue(property); - - if (property === 'background-color') { - value = parent_css.getPropertyValue('background-color'); - } - - if (['box-shadow', 'left', 'top', 'bottom', 'right', 'opacity'].indexOf(property) === -1) { - style += property + ':' + value + ';'; - } - } - - - clone.setAttribute('style', style); - - return clone; -}; - - -/*-------------------------------------------------------------- -# REMOVE ---------------------------------------------------------------*/ - -satus.remove = function (child, parent) { - if (satus.isArray(parent)) { - parent.splice(satus.indexOf(child, parent), 1); - } -}; - - -/*-------------------------------------------------------------- -# RENDER ---------------------------------------------------------------*/ - -satus.render = function (skeleton, container, skip, property) { - var component; - - if (skeleton.hasOwnProperty('component') && skip !== true) { - var name = skeleton.component, - camelized_name = this.camelize(name); - - if (skeleton.on && skeleton.on.beforerender) { - skeleton.on.beforerender(skeleton); - } - - if (this.components[camelized_name]) { - component = this.components[camelized_name](skeleton); - - if (this.isset(component.inner) === false) { - component.inner = component; - } - } else if (name === 'svg' || container && container.is_svg) { - component = document.createElementNS('http://www.w3.org/2000/svg', name); - - component.is_svg = true; - - component.inner = component; - } else { - component = document.createElement(skeleton.component); - - component.inner = component; - } - - if (component.inner.hasOwnProperty('base') === false && container) { - component.inner.base = container.base; - } - - if (component.inner.base && name === 'layers') { - component.inner.base.layers = component; - } - - skeleton.rendered = component; - component.skeleton = skeleton; - - component.className = (component.className + ' satus-' + skeleton.component).trim(); - - if (skeleton.variant) { - component.className += ' satus-' + skeleton.component + '--' + skeleton.variant; - } - - this.append(component, container); - - container = component.inner || component; - - this.class(component, skeleton.class); - this.style(component, skeleton.style); - this.attr(component, skeleton.attr); - this.data(component, skeleton.data); - this.properties(component, skeleton.properties); - this.on(component, skeleton.on); - this.text(container, skeleton.text); - - if (component.hasOwnProperty('storage') === false && skeleton.storage !== false) { - component.storage = skeleton.storage || property || false; - } - - if (component.hasOwnProperty('storageValue') === false) { - if (component.storage !== false) { - component.storageValue = satus.storage.get(component.storage); - } - - if (skeleton.hasOwnProperty('value') && component.storageValue === undefined) { - component.storageValue = skeleton.value; - } - } - - component.storageChange = function () { - if (this.storage) { - var key = this.storage; - - if (typeof key === 'function') { - key = key(); - } - - satus.storage.set(key, this.storageValue); - } - - this.dispatchEvent(new CustomEvent('change')); - }; - - component.dispatchEvent(new CustomEvent('render')); - - if (skeleton.autofocus === true) { - component.focus(); - } - - if (this.events.hasOwnProperty('render')) { - for (var i = 0, l = this.events['render'].length; i < l; i++) { - this.events['render'][i](component, skeleton); - } - } - } - - if (!component || component.render_children !== false) { - for (var key in skeleton) { - if (key !== 'parent' && skeleton[key] && skeleton[key].hasOwnProperty('component')) { - skeleton[key].parent = skeleton; - - this.render(skeleton[key], container, false, key); - } - } - } - - return component; -}; -/*-------------------------------------------------------------- ->>> COLOR PICKER ---------------------------------------------------------------*/ - -satus.components.colorPicker = function (skeleton) { - var component = document.createElement('button'), - component_label = document.createElement('span'), - component_value = document.createElement('span'); - - component.inner = component_label; - component.valueElement = component_value; - - component.className = 'satus-button'; - component_value.className = 'satus-color-picker__value'; - - component.appendChild(component_label); - component.appendChild(component_value); - - component.addEventListener('click', function () { - var rgb = this.rgb, - hsl = satus.color.rgbToHsl(rgb), - s = hsl[1] / 100, - l = hsl[2] / 100; - - s *= l < .5 ? l : 1 - l; - - var v = l + s; - - s = 2 * s / (l + s); - - satus.render({ - component: 'modal', - variant: 'color-picker', - value: hsl, - parent: this, - - palette: { - component: 'div', - class: 'satus-color-picker__palette', - style: { - 'backgroundColor': 'hsl(' + hsl[0] + 'deg, 100%, 50%)' - }, - on: { - mousedown: function () { - var palette = this, - rect = this.getBoundingClientRect(), - cursor = this.children[0]; - - function mousemove(event) { - var hsl = palette.skeleton.parent.value, - x = event.clientX - rect.left, - y = event.clientY - rect.top, - s; - - x = Math.min(Math.max(x, 0), rect.width) / (rect.width / 100); - y = Math.min(Math.max(y, 0), rect.height) / (rect.height / 100); - - var v = 100 - y, - l = (2 - x / 100) * v / 2; - - hsl[1] = x * v / (l < 50 ? l * 2 : 200 - l * 2); - hsl[2] = l; - - cursor.style.left = x + '%'; - cursor.style.top = y + '%'; - - palette.nextSibling.children[0].style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; - - event.preventDefault(); - } - - function mouseup() { - window.removeEventListener('mousemove', mousemove); - window.removeEventListener('mouseup', mouseup); - } - - window.addEventListener('mousemove', mousemove); - window.addEventListener('mouseup', mouseup); - } - }, - - cursor: { - component: 'div', - class: 'satus-color-picker__cursor', - style: { - 'left': s * 100 + '%', - 'top': 100 - v * 100 + '%' - } - } - }, - section: { - component: 'section', - variant: 'color', - - color: { - component: 'div', - class: 'satus-color-picker__color', - style: { - 'backgroundColor': 'rgb(' + this.rgb.join(',') + ')' - } - }, - hue: { - component: 'slider', - class: 'satus-color-picker__hue', - storage: false, - value: hsl[0], - max: 360, - on: { - change: function () { - var modal = this.skeleton.parent.parent, - hsl = modal.value; - - hsl[0] = this.values[0]; - - this.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg,' + hsl[1] + '%, ' + hsl[2] + '%)'; - this.parentNode.previousSibling.style.backgroundColor = 'hsl(' + hsl[0] + 'deg, 100%, 50%)'; - } - } - } - }, - actions: { - component: 'section', - variant: 'actions', - - reset: { - component: 'button', - text: 'reset', - on: { - click: function () { - var modal = this.skeleton.parent.parent, - component = modal.parent; - - component.rgb = component.skeleton.value; - - component.storageValue = component.rgb; - component.storageChange(); - - component.valueElement.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; - - modal.rendered.close(); - } - } - }, - cancel: { - component: 'button', - text: 'cancel', - on: { - click: function () { - this.skeleton.parent.parent.rendered.close(); - } - } - }, - ok: { - component: 'button', - text: 'OK', - on: { - click: function () { - var modal = this.skeleton.parent.parent, - component = modal.parent; - - component.rgb = satus.color.hslToRgb(modal.value); - - component.storageValue = component.rgb; - component.storageChange(); - - component.valueElement.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; - - modal.rendered.close(); - } - } - } - } - }); - }); - - component.addEventListener('render', function () { - component.rgb = this.storageValue || [0, 100, 50]; - - component_value.style.backgroundColor = 'rgb(' + component.rgb.join(',') + ')'; - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> TABS ---------------------------------------------------------------*/ - -satus.components.tabs = function (skeleton) { - var component = document.createElement('div'), - content = document.createElement('div'), - selection = document.createElement('div'); - - content.className = 'satus-tabs__content'; - selection.className = 'satus-tabs__selection'; - selection.style.width = 100 / skeleton.items.length + '%'; - - content.appendChild(selection); - - component.selection = selection; - - for (var i = 0, l = skeleton.items.length; i < l; i++) { - var item = skeleton.items[i], - button = document.createElement('button'); - - button.className = 'satus-tabs__button'; - button.value = item; - button.style.width = 100 / l + '%'; - - satus.text(button, item); - - button.addEventListener('click', function () { - var component = this.parentNode.parentNode; - - component.selection.style.left = 100 / (this.parentNode.children.length - 1) * (satus.indexOf(this) - 1) + '%'; - - component.storageValue = this.value; - component.storageChange(); - }); - - if (skeleton.value === item) { - selection.style.left = i * 50 + '%'; - } - - content.appendChild(button); - } - - component.appendChild(content); - - component.addEventListener('render', function () { - var index = satus.indexOf(this.storageValue, this.skeleton.items); - - if (index === -1) { - index = 0; - } - - this.selection.style.left = 100 / this.skeleton.items.length * index + '%'; - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> MENUBAR ---------------------------------------------------------------*/ - -satus.components.menubar = function (skeleton) { - function createList(items) { - var ul = document.createElement('ul'); - - for (var key in items) { - var item = items[key], - li = document.createElement('li'); - - satus.render(item, li); - - if (item.items) { - li.appendChild(createList(item.items)); - } - - ul.appendChild(li); - } - - return ul; - } - - return createList(skeleton.items); -}; -/*-------------------------------------------------------------- ->>> RADIO ---------------------------------------------------------------*/ - -satus.components.radio = function (skeleton) { - var component = document.createElement('label'), - content = document.createElement('span'), - radio = document.createElement('input'); - - component.inner = content; - - radio.type = 'radio'; - - if (skeleton.group) { - component.storage = skeleton.group; - radio.name = skeleton.group; - } - - if (skeleton.value) { - radio.value = skeleton.value; - } - - component.addEventListener('render', function () { - this.storageValue = satus.storage.get(this.storage); - - if (satus.isset(this.storageValue)) { - radio.checked = this.storageValue === skeleton.value; - } else if (skeleton.checked) { - radio.checked = true; - } - }); - - radio.addEventListener('change', function () { - component.storageValue = this.value; - component.storageChange(); - }); - - component.appendChild(content); - component.appendChild(radio); - - return component; -}; -/*-------------------------------------------------------------- ->>> LIST ---------------------------------------------------------------*/ - -satus.components.list = function (skeleton) { - var ul = document.createElement('ul'); - - for (var i = 0, l = skeleton.items.length; i < l; i++) { - var li = document.createElement('li'), - item = skeleton.items[i]; - - li.className = 'satus-list__item'; - - for (var j = 0, k = item.length; j < k; j++) { - var child = item[j]; - - if (typeof child === 'string') { - var span = document.createElement('span'); - - span.textContent = satus.locale.get(child); - - li.appendChild(span); - } else { - satus.render(child, li); - } - } - - ul.appendChild(li); - } - - return ul; -}; -/*-------------------------------------------------------------- ->>> TEXTAREA ---------------------------------------------------------------*/ - -satus.components.textarea = function (skeleton) { - var component = document.createElement('div'), - line_number = document.createElement('div'), - textarea = document.createElement('textarea'); - - line_number.className = 'satus-textarea__line-number'; - - component.line_number = line_number; - component.textarea = textarea; - - line_number.update = function (count) { - if (count !== this.children.length) { - satus.empty(this); - - for (var i = 1; i <= count; i++) { - var span = document.createElement('span'); - - span.textContent = i; - - this.appendChild(span); - } - } - }; - - textarea.addEventListener('input', function () { - this.parentNode.line_number.update(this.value.split('\n').length); - }); - - textarea.addEventListener('selectionchange', function () { - this.parentNode.line_number.update(this.value.split('\n').length); - }); - - textarea.addEventListener('scroll', function () { - this.parentNode.line_number.style.transform = 'translateY(-' + this.scrollTop + 'px)'; - - this.parentNode.line_number.update(this.value.split('\n').length); - }); - - component.appendChild(line_number); - component.appendChild(textarea); - - line_number.update(1); - - return component; -}; -/*-------------------------------------------------------------- ->>> MODAL ---------------------------------------------------------------*/ - -satus.components.modal = function (skeleton) { - var component = document.createElement('div'), - scrim = document.createElement('div'), - surface = document.createElement('div'); - - component.inner = surface; - - scrim.className = 'satus-modal__scrim'; - surface.className = 'satus-modal__surface'; - - component.close = function () { - var component = this, - component_surface = this.children[1]; - - this.classList.add('satus-modal--closing'); - - setTimeout(function () { - component.remove(); - - component.dispatchEvent(new CustomEvent('close')); - }, satus.getAnimationDuration(component_surface)); - }; - - scrim.addEventListener('click', function () { - this.parentNode.close(); - }); - - component.appendChild(scrim); - component.appendChild(surface); - - return component; -}; -/*-------------------------------------------------------------- ->>> CHECKBOX ---------------------------------------------------------------*/ - -satus.components.checkbox = function (skeleton) { - var component = document.createElement('button'), - content = document.createElement('span'); - - component.inner = content; - - content.className = 'satus-checkbox__content'; - - component.appendChild(content); - - component.addEventListener('click', function () { - if (this.dataset.value === 'true') { - this.storageValue = false; - this.dataset.value = 'false'; - } else { - this.storageValue = true; - this.dataset.value = 'true'; - } - - this.storageChange(); - }); - - component.addEventListener('render', function () { - this.dataset.value = this.storageValue; - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> SWITCH ---------------------------------------------------------------*/ - -satus.components.switch = function (skeleton) { - var component = document.createElement('button'), - component_content = document.createElement('span'), - component_thumb = document.createElement('i'); - - component.inner = component_content; - - component_content.className = 'satus-switch__content'; - - component.addEventListener('click', function () { - if (this.dataset.value === 'true') { - this.storageValue = false; - this.dataset.value = 'false'; - } else { - this.storageValue = true; - this.dataset.value = 'true'; - } - - this.storageChange(); - }); - - component.addEventListener('render', function () { - this.dataset.value = this.storageValue; - }); - - component.appendChild(component_content); - component.appendChild(component_thumb); - - return component; -}; -/*-------------------------------------------------------------- ->>> SLIDER ---------------------------------------------------------------*/ - -satus.components.slider = function (skeleton) { - var component = document.createElement('div'), - content = document.createElement('div'), - container = document.createElement('div'), - track = document.createElement('div'), - track_fill = document.createElement('div'); - - container.className = 'satus-slider__container'; - track.className = 'satus-slider__track'; - track_fill.className = 'satus-slider__track-fill'; - - component.min = skeleton.min || 0; - component.max = skeleton.max || 1; - component.step = (skeleton.step || 1); - component.percent = 100 / ((component.max - component.min) / component.step); - component.precision = String(component.step).replace(/[0-9]./, '').length; - - component.container = container; - component.track = track_fill; - component.handles = []; - component.inner = content; - - component.toPercent = function (number) { - return number / this.step * this.percent + '%'; - }; - - component.createHandle = function (index) { - var handle = document.createElement('div'); - - handle.className = 'satus-slider__handle'; - handle.handleIndex = index; - handle.tabIndex = 0; - - this.handles.push(handle); - - this.container.appendChild(handle); - }; - - component.update = function () { - if (this.values.length > 1) { - var min = Math.min.apply(null, this.values) - this.min, - max = Math.max.apply(null, this.values) - this.min; - - this.track.style.left = this.toPercent(min); - this.track.style.width = this.toPercent(max - min); - - for (var i = 0, l = this.handles.length; i < l; i++) { - var handle = this.handles[i], - value = this.values[i]; - - handle.style.left = this.toPercent(value - this.min); - handle.dataset.value = value; - } - } else { - var value = this.values[0]; - - this.track.style.width = this.toPercent(value - this.min); - this.handles[0].style.left = this.toPercent(value - this.min); - this.handles[0].dataset.value = value; - } - }; - - component.appendChild(content); - track.appendChild(track_fill); - container.appendChild(track); - component.appendChild(container); - - component.addEventListener('keydown', function (event) { - var code = event.keyCode; - - console.log(code); - }); - - component.addEventListener('render', function () { - var value = this.storageValue; - - if (satus.isArray(value)) { - this.values = value; - } else if (satus.isNumber(value)) { - this.values = [value]; - } else { - this.values = this.skeleton.values || [satus.isset(this.skeleton.value) ? this.skeleton.value : 1]; - } - - for (var i = 0, l = this.values.length; i < l; i++) { - this.createHandle(i); - } - - this.update(); - }); - - container.addEventListener('mousedown', function (event) { - if (event.button === 0) { - var component = this.parentNode, - rect = this.getBoundingClientRect(), - cursor_x = event.clientX - rect.left, - percent = cursor_x / rect.width * 100, - steps = percent / component.percent * component.step + component.min, - closest_value = component.values.indexOf(component.values.reduce(function(previous, current, index) { - return Math.abs(current - steps) < Math.abs(previous - steps) ? current : previous; - })), - handle_index = component.handles[closest_value].handleIndex; - - setTimeout(function () { - component.handles[closest_value].focus(); - }); - - function update(event) { - var cursor_x = Math.min(Math.max(event.clientX - rect.left, 0), rect.width), - percent = cursor_x / rect.width * 100, - value = percent / component.percent * component.step + component.min; - - value = (Math.round(value / component.step) * component.step); - - value = Number(value.toFixed(component.precision)); - - if (component.values[handle_index] !== value) { - component.values[handle_index] = value; - - component.storageValue = component.values.length === 1 ? component.values[0] : component.values; - component.value = component.storageValue; - - component.storageChange(); - } - - component.update(); - } - - function mousemove(event) { - update(event); - } - - function mouseup(event) { - window.removeEventListener('mousemove', mousemove); - window.removeEventListener('mouseup', mouseup); - }; - - window.addEventListener('mousemove', mousemove); - window.addEventListener('mouseup', mouseup); - - update(event); - - return true; - } - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> SHORTCUT ---------------------------------------------------------------*/ - -satus.components.shortcut = function (skeleton) { - var component = document.createElement('button'), - content = document.createElement('span'), - value = document.createElement('div'); - - component.inner = content; - - component.className = 'satus-button'; - value.className = 'satus-shortcut__value'; - - component.render = function (parent) { - var self = this, - parent = parent || self.primary, - children = parent.children; - - satus.empty(parent); - - function createElement(name) { - var element = document.createElement('div'); - - element.className = 'satus-shortcut__' + name; - - parent.appendChild(element); - - return element; - } - - if (this.data.alt) { - createElement('key').textContent = 'Alt'; - } - - if (this.data.ctrl) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - createElement('key').textContent = 'Ctrl'; - } - - if (this.data.shift) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - createElement('key').textContent = 'Shift'; - } - - for (var code in this.data.keys) { - var key = this.data.keys[code].key, - arrows = ['ArrowUp', 'ArrowRight', 'ArrowDown', 'ArrowLeft'], - index = arrows.indexOf(key); - - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - if (index !== -1) { - createElement('key').textContent = ['↑', '→', '↓', '←'][index]; - } else if (key === ' ') { - createElement('key').textContent = '␣'; - } else if (key) { - createElement('key').textContent = key.toUpperCase(); - } - } - - if (this.data.wheel) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - var mouse = createElement('mouse'), - div = document.createElement('div'); - - mouse.appendChild(div); - - mouse.className += ' ' + (this.data.wheel > 0); - } - - if (this.data.click) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - var mouse = createElement('mouse'), - div = document.createElement('div'); - - mouse.appendChild(div); - - mouse.className += ' click'; - } - - if (this.data.context) { - if (children.length && children[children.length - 1].className.indexOf('key') !== -1) { - createElement('plus'); - } - - var mouse = createElement('mouse'), - div = document.createElement('div'); - - mouse.appendChild(div); - - mouse.className += ' context'; - } - }; - - component.valueElement = value; - - component.appendChild(content); - component.appendChild(value); - - component.keydown = function (event) { - event.preventDefault(); - event.stopPropagation(); - - component.data = { - alt: event.altKey, - ctrl: event.ctrlKey, - shift: event.shiftKey, - keys: {} - }; - - if (['control', 'alt', 'altgraph', 'shift'].indexOf(event.key.toLowerCase()) === -1) { - component.data.keys[event.keyCode] = { - code: event.code, - key: event.key - }; - } - - component.data.wheel = 0; - - component.render(); - - return false; - }; - - component.mousewheel = function (event) { - event.stopPropagation(); - - if ( - ( - component.data.wheel === 0 && - ( - Object.keys(component.data.keys).length === 0 && - component.data.alt === false && - component.data.ctrl === false && - component.data.shift === false - ) - ) || - component.data.wheel < 0 && event.deltaY > 0 || - component.data.wheel > 0 && event.deltaY < 0) { - component.data = { - alt: false, - ctrl: false, - shift: false, - keys: {} - }; - } - - component.data.wheel = event.deltaY < 0 ? -1 : 1; - - component.render(); - - return false; - }; - - component.addEventListener('render', function () { - this.data = this.storageValue || { - alt: false, - ctrl: false, - shift: false, - keys: {}, - wheel: 0 - }; - - this.render(this.valueElement); - }); - - component.addEventListener('click', function () { - satus.render({ - component: 'modal', - on: { - close: function () { - window.removeEventListener('keydown', component.keydown); - window.removeEventListener('mousewheel', component.mousewheel); - } - }, - - primary: { - component: 'div', - class: 'satus-shortcut__primary', - on: { - render: function () { - component.primary = this; - - if (component.skeleton.mouseButtons === true) { - this.addEventListener('click', function () { - component.data.context = false; - component.data.click = true; - - component.render(); - }); - - this.addEventListener('contextmenu', function (event) { - event.preventDefault(); - event.stopPropagation(); - - component.data.context = true; - component.data.click = false; - - component.render(); - - return false; - }); - } - - component.render(); - } - } - }, - actions: { - component: 'section', - variant: 'actions', - - reset: { - component: 'button', - text: 'reset', - on: { - click: function () { - component.data = component.skeleton.value || {}; - - component.render(component.valueElement); - - satus.storage.set(skeleton.storage, false); - - this.parentNode.parentNode.parentNode.close(); - - window.removeEventListener('keydown', component.keydown); - window.removeEventListener('mousewheel', component.mousewheel); - } - } - }, - cancel: { - component: 'button', - text: 'cancel', - on: { - click: function () { - component.data = satus.storage.get(component.storage) || component.skeleton.value || {}; - - component.render(component.valueElement); - - this.parentNode.parentNode.parentNode.close(); - - window.removeEventListener('keydown', component.keydown); - window.removeEventListener('mousewheel', component.mousewheel); - } - } - }, - save: { - component: 'button', - text: 'save', - on: { - click: function () { - component.storageValue = component.data; - - component.storageChange(); - - component.render(component.valueElement); - - this.parentNode.parentNode.parentNode.close(); - - window.removeEventListener('keydown', component.keydown); - window.removeEventListener('mousewheel', component.mousewheel); - } - } - } - } - }); - - window.addEventListener('keydown', this.keydown); - window.addEventListener('mousewheel', this.mousewheel); - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> BASE ---------------------------------------------------------------*/ - -satus.components.base = function (skeleton) { - var component = document.createElement('div'); - - component.base = component; - - return component; -}; -/*-------------------------------------------------------------- ->>> TEXT FIELD ---------------------------------------------------------------*/ - -satus.components.textField = function (skeleton) { - var component = document.createElement('div'), - pre = document.createElement('pre'), - input = document.createElement('textarea'), - hidden_text = document.createElement('span'), - text = document.createElement('span'), - selection = document.createElement('div'), - cursor = document.createElement('div'); - - input.className = 'satus-text-field__input'; - pre.className = 'satus-text-field__pre'; - hidden_text.className = 'satus-text-field__hidden-text'; - text.className = 'satus-text-field__text'; - selection.className = 'satus-text-field__selection'; - cursor.className = 'satus-text-field__cursor'; - - component.inputElement = input; - component.textElement = text; - component.languages = { - regex: function (component) { - var regex_token = /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g, - char_class_token = /[^\\-]+|-|\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)/g, - char_class_parts = /^(\[\^?)(]?(?:[^\\\]]+|\\[\S\s]?)*)(]?)$/, - quantifier = /^(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??$/, - matches = component.inputElement.value.match(regex_token); - - function create(type, string) { - var span = document.createElement('span'); - - span.className = type; - span.textContent = string; - - component.textElement.appendChild(span); - } - - for (var i = 0, l = matches.length; i < l; i++) { - var match = matches[i]; - - if (match[0] === '[') { - create('character-class', match); - } else if (match[0] === '(') { - create('group', match); - } else if (match[0] === ')') { - create('group', match); - } else if (match[0] === '\\' || match === '^') { - create('anchor', match); - } else if (quantifier.test(match)) { - create('quantifier', match); - } else if (match === '|' || match === '.') { - create('metasequence', match); - } else { - create('text', match); - } - } - } - }; - component._syntax = skeleton.syntax; - - Object.defineProperty(component, 'value', { - get: function () { - return this.inputElement.value; - }, - set: function (value) { - var input = this.inputElement; - - input.value = value; - - input.updateValue(); - input.updateCursor(); - } - }); - - Object.defineProperty(component, 'syntax', { - get: function () { - return this._syntax; - }, - set: function (value) { - var input = this.inputElement; - - this._syntax = value; - - input.updateValue(); - input.updateCursor(); - } - }); - - input.rows = skeleton.rows || 1; - input.autocapitalize = 'none'; - input.autocomplete = 'off'; - input.autocorrect = 'off'; - input.spellcheck = false; - input.autofocus = true; - input.textElement = text; - input.hiddenTextElement = hidden_text; - input.selectionElement = selection; - input.cursorElement = cursor; - - input.updateValue = function () { - var component = this.parentNode.parentNode; - - for (var i = this.textElement.childNodes.length - 1; i > -1; i--) { - this.textElement.childNodes[i].remove(); - } - - if (this.value.length > 0) { - if (component.languages[component._syntax]) { - component.languages[component._syntax](component); - } else { - this.textElement.textContent = this.value; - } - } - }; - - input.updateCursor = function () { - var cursor = this.cursorElement, - selection = this.selectionElement, - hidden_text = this.hiddenTextElement, - start = this.selectionStart, - end = this.selectionEnd; - - cursor.style.animation = 'none'; - - if (start === end) { - selection.setAttribute('disabled', ''); - } else { - selection.removeAttribute('disabled'); - - hidden_text.textContent = this.value.substring(0, start); - - selection.style.left = hidden_text.offsetWidth - this.scrollLeft + 'px'; - - hidden_text.textContent = this.value.substring(start, end); - - selection.style.width = hidden_text.offsetWidth + 'px'; - } - - if (this.selectionDirection === 'forward') { - hidden_text.textContent = this.value.substring(0, end); - } else { - hidden_text.textContent = this.value.substring(0, start); - } - - cursor.style.left = hidden_text.offsetWidth - this.scrollLeft + 'px'; - - cursor.style.animation = ''; - - hidden_text.textContent = ''; - }; - - input.addEventListener('keydown', function () { - var self = this; - - setTimeout(function () { - var component = self.parentNode.parentNode; - - component.storageValue = self.value; - component.storageChange(); - - self.updateValue(); - self.updateCursor(); - }); - }); - - input.addEventListener('scroll', function (event) { - this.textElement.style.left = -this.scrollLeft + 'px'; - }); - - document.addEventListener('selectionchange', function () { - input.updateCursor(); - }); - - selection.setAttribute('disabled', ''); - - pre.appendChild(input); - pre.appendChild(hidden_text); - pre.appendChild(text); - pre.appendChild(selection); - pre.appendChild(cursor); - component.appendChild(pre); - - component.addEventListener('render', function () { - input.value = this.storageValue; - - this.inputElement.updateValue(); - this.inputElement.updateCursor(); - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> ALERT ---------------------------------------------------------------*/ - -satus.components.alert = function (skeleton) { - var component = document.createElement('div'); - - return component; -}; -/*-------------------------------------------------------------- ->>> LAYERS ---------------------------------------------------------------*/ - -satus.components.layers = function (skeleton) { - var component = document.createElement('div'); - - component.path = [skeleton]; - - component.back = function () { - if (this.path.length > 1) { - this.path.pop(); - - this.open(); - } - }; - - component.open = function (skeleton) { - var layer = document.createElement('div'); - - if (skeleton) { - this.path.push(skeleton); - } else { - skeleton = this.path[this.path.length - 1]; - } - - layer.className = 'satus-layer'; - - layer.skeleton = skeleton; - layer.base = this.base; - - satus.render(skeleton, layer, skeleton.component === 'layers'); - - satus.empty(this); - - this.appendChild(layer); - - this.dispatchEvent(new Event('open')); - }; - - component.update = function () { - var layer = this.querySelector('.satus-layer'); - - satus.empty(layer); - - satus.render(layer.skeleton, layer); - }; - - component.render_children = false; - - component.addEventListener('render', function () { - this.open(); - }); - - return component; -}; -/*-------------------------------------------------------------- ->>> DIVIDER ---------------------------------------------------------------*/ - -satus.components.divider = function () { - var component = document.createElement('div'); - - return component; -}; -/*-------------------------------------------------------------- ->>> INPUT ---------------------------------------------------------------*/ - -satus.components.input = function (skeleton) { - var component = document.createElement('input'); - - if (skeleton.attr) { - var key = skeleton.attr.name || skeleton.storage, - value; - - if (satus.isset(satus.storage.get(key))) { - value = satus.storage.get(key); - } else { - value = skeleton.value; - } - - if (skeleton.attr.type === 'radio') { - component.checked = value === skeleton.attr.value || skeleton.value; - } else if (satus.isset(value)) { - component.value = value; - } - - component.addEventListener('change', function () { - var key = this.skeleton.attr.name || this.skeleton.storage; - - satus.storage.set(key, this.value); - }); - } else { - var key = skeleton.name || skeleton.storage, - value; - - component.type = skeleton.type; - - if (satus.isset(satus.storage.get(key))) { - value = satus.storage.get(key); - } else { - value = skeleton.value; - } - - if (skeleton.type === 'radio') { - component.checked = value === skeleton.value || skeleton.value; - } else if (satus.isset(value)) { - component.value = value; - } - - component.addEventListener('change', function () { - var key = this.skeleton.name || this.skeleton.storage; - - satus.storage.set(key, this.value); - }); - } - - return component; -}; -/*-------------------------------------------------------------- ->>> SELECT ---------------------------------------------------------------*/ - -satus.components.select = function (skeleton) { - var component = document.createElement('div'), - component_content = document.createElement('span'), - component_value = document.createElement('span'), - select = document.createElement('select'); - - component_content.className = 'satus-select__content'; - component_value.className = 'satus-select__value'; - - for (var i = 0, l = skeleton.options.length; i < l; i++) { - var option = document.createElement('option'); - - option.value = skeleton.options[i].value; - - satus.text(option, skeleton.options[i].text); - - select.appendChild(option); - } - - component.selectElement = select; - select.valueElement = component_value; - - select.addEventListener('change', function () { - satus.empty(this.valueElement); - - satus.text(this.valueElement, this.options[this.selectedIndex].text); - - this.parentNode.storageValue = this.value; - - this.parentNode.storageChange(); - }); - - component.appendChild(component_content); - component.appendChild(component_value); - component.appendChild(select); - - component.addEventListener('render', function () { - select.value = this.storageValue || this.skeleton.options[0].value; - - satus.text(select.valueElement, select.options[select.selectedIndex].text); - }); - - component.inner = component_content; - - return component; -}; -/*-------------------------------------------------------------- ->>> COLOR: ----------------------------------------------------------------- -# RGB to HSL -# HUE to RGB -# HSL to RGB ---------------------------------------------------------------*/ - -satus.color = {}; - - -/*-------------------------------------------------------------- -# RGB TO HSL ---------------------------------------------------------------*/ - -satus.color.rgbToHsl = function (array) { - var r = array[0] / 255, - g = array[1] / 255, - b = array[2] / 255, - min = Math.min(r, g, b), - max = Math.max(r, g, b), - h = 0, - s = 0, - l = (min + max) / 2; - - if (min === max) { - h = 0; - s = 0; - } else { - var delta = max - min; - - s = l <= 0.5 ? delta / (max + min) : delta / (2 - max - min); - - if (max === r) { - h = (g - b) / delta + (g < b ? 6 : 0); - } else if (max === g) { - h = (b - r) / delta + 2; - } else if (max === b) { - h = (r - g) / delta + 4; - } - - h /= 6; - } - - h *= 360; - s *= 100; - l *= 100; - - if (array.length === 3) { - return [h, s, l]; - } else { - return [h, s, l, array[3]]; - } -}; - - -/*-------------------------------------------------------------- -# HUE TO RGB ---------------------------------------------------------------*/ - -satus.color.hueToRgb = function (array) { - var t1 = array[0], - t2 = array[1], - hue = array[2]; - - if (hue < 0) { - hue += 6; - } - - if (hue >= 6) { - hue -= 6; - } - - if (hue < 1) { - return (t2 - t1) * hue + t1; - } else if (hue < 3) { - return t2; - } else if (hue < 4) { - return (t2 - t1) * (4 - hue) + t1; - } else { - return t1; - } -}; - - -/*-------------------------------------------------------------- -# HSL TO RGB ---------------------------------------------------------------*/ - -satus.color.hslToRgb = function (array) { - var h = array[0] / 360, - s = array[1] / 100, - l = array[2] / 100, - r, g, b; - - if (s == 0) { - r = g = b = l; - } else { - var hue2rgb = function hue2rgb(p, q, t) { - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6) return p + (q - p) * 6 * t; - if (t < 1 / 2) return q; - if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; - return p; - } - - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1 / 3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1 / 3); - } - - return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; -}; -/*-------------------------------------------------------------- ->>> USER ---------------------------------------------------------------*/ - -satus.user = function () { - /*-------------------------------------------------------------- - 1.0 VARIABLES - --------------------------------------------------------------*/ - - var user_agent = navigator.userAgent, - random_cookie = 'ta{t`nX6cMXK,Wsc', - video = document.createElement('video'), - video_formats = { - ogg: 'video/ogg; codecs="theora"', - h264: 'video/mp4; codecs="avc1.42E01E"', - webm: 'video/webm; codecs="vp8, vorbis"', - vp9: 'video/webm; codecs="vp9"', - hls: 'application/x-mpegURL; codecs="avc1.42E01E"' - }, - audio = document.createElement('audio'), - audio_formats = { - mp3: 'audio/mpeg', - mp4: 'audio/mp4', - aif: 'audio/x-aiff' - }, - cvs = document.createElement('canvas'), - ctx = cvs.getContext('webgl'), - data = { - browser: { - audio: null, - cookies: null, - flash: null, - java: null, - languages: null, - name: null, - platform: null, - version: null, - video: null, - webgl: null - }, - os: { - name: null, - type: null - }, - device: { - connection: { - type: null, - speed: null - }, - cores: null, - gpu: null, - max_touch_points: null, - ram: null, - screen: null, - touch: null - } - }; - - - /*-------------------------------------------------------------- - 2.0 SOFTWARE - --------------------------------------------------------------*/ - - /*-------------------------------------------------------------- - 2.1.0 OS - --------------------------------------------------------------*/ - - /*-------------------------------------------------------------- - 2.1.1 NAME - --------------------------------------------------------------*/ - - if (navigator.appVersion.indexOf('Win') !== -1) { - if (navigator.appVersion.match(/(Windows 10.0|Windows NT 10.0)/)) { - data.os.name = 'Windows 10'; - } else if (navigator.appVersion.match(/(Windows 8.1|Windows NT 6.3)/)) { - data.os.name = 'Windows 8.1'; - } else if (navigator.appVersion.match(/(Windows 8|Windows NT 6.2)/)) { - data.os.name = 'Windows 8'; - } else if (navigator.appVersion.match(/(Windows 7|Windows NT 6.1)/)) { - data.os.name = 'Windows 7'; - } else if (navigator.appVersion.match(/(Windows NT 6.0)/)) { - data.os.name = 'Windows Vista'; - } else if (navigator.appVersion.match(/(Windows NT 5.1|Windows XP)/)) { - data.os.name = 'Windows XP'; - } else { - data.os.name = 'Windows'; - } - } else if (navigator.appVersion.indexOf('(iPhone|iPad|iPod)') !== -1) { - data.os.name = 'iOS'; - } else if (navigator.appVersion.indexOf('Mac') !== -1) { - data.os.name = 'macOS'; - } else if (navigator.appVersion.indexOf('Android') !== -1) { - data.os.name = 'Android'; - } else if (navigator.appVersion.indexOf('OpenBSD') !== -1) { - data.os.name = 'OpenBSD'; - } else if (navigator.appVersion.indexOf('SunOS') !== -1) { - data.os.name = 'SunOS'; - } else if (navigator.appVersion.indexOf('Linux') !== -1) { - data.os.name = 'Linux'; - } else if (navigator.appVersion.indexOf('X11') !== -1) { - data.os.name = 'UNIX'; - } - - /*-------------------------------------------------------------- - 2.1.2 TYPE - --------------------------------------------------------------*/ - - if (navigator.appVersion.match(/(Win64|x64|x86_64|WOW64)/)) { - data.os.type = '64-bit'; - } else { - data.os.type = '32-bit'; - } - - - /*-------------------------------------------------------------- - 2.2.0 BROWSER - --------------------------------------------------------------*/ - - /*-------------------------------------------------------------- - 2.2.1 NAME - --------------------------------------------------------------*/ - - if (user_agent.indexOf('Opera') !== -1) { - data.browser.name = 'Opera'; - } else if (user_agent.indexOf('Vivaldi') !== -1) { - data.browser.name = 'Vivaldi'; - } else if (user_agent.indexOf('Edge') !== -1) { - data.browser.name = 'Edge'; - } else if (user_agent.indexOf('Chrome') !== -1) { - data.browser.name = 'Chrome'; - } else if (user_agent.indexOf('Safari') !== -1) { - data.browser.name = 'Safari'; - } else if (user_agent.indexOf('Firefox') !== -1) { - data.browser.name = 'Firefox'; - } else if (user_agent.indexOf('MSIE') !== -1) { - data.browser.name = 'IE'; - } - - - /*-------------------------------------------------------------- - 2.2.2 VERSION - --------------------------------------------------------------*/ - - var browser_version = user_agent.match(new RegExp(data.browser.name + '/([0-9.]+)')); - - if (browser_version[1]) { - data.browser.version = browser_version[1]; - } - - - /*-------------------------------------------------------------- - 2.2.3 PLATFORM - --------------------------------------------------------------*/ - - data.browser.platform = navigator.platform || null; - - - /*-------------------------------------------------------------- - 2.2.4 LANGUAGES - --------------------------------------------------------------*/ - - data.browser.languages = navigator.languages || null; - - - /*-------------------------------------------------------------- - 2.2.5 COOKIES - --------------------------------------------------------------*/ - - if (document.cookie) { - document.cookie = random_cookie; - - if (document.cookie.indexOf(random_cookie) !== -1) { - data.browser.cookies = true; - } - } - - - /*-------------------------------------------------------------- - 2.2.6 FLASH - --------------------------------------------------------------*/ - - try { - if (new ActiveXObject('ShockwaveFlash.ShockwaveFlash')) { - data.browser.flash = true; - } - } catch (e) { - if (navigator.mimeTypes['application/x-shockwave-flash']) { - data.browser.flash = true; - } - } - - - /*-------------------------------------------------------------- - 2.2.7 JAVA - --------------------------------------------------------------*/ - - if (typeof navigator.javaEnabled === 'function' && navigator.javaEnabled()) { - data.browser.java = true; - } - - - /*-------------------------------------------------------------- - 2.2.8 VIDEO FORMATS - --------------------------------------------------------------*/ - - if (typeof video.canPlayType === 'function') { - data.browser.video = {}; - - for (var i in video_formats) { - var can_play_type = video.canPlayType(video_formats[i]); - - if (can_play_type === '') { - data.browser.video[i] = false; - } else { - data.browser.video[i] = can_play_type; - } - } - } - - - /*-------------------------------------------------------------- - 2.2.9 AUDIO FORMATS - --------------------------------------------------------------*/ - - if (typeof audio.canPlayType === 'function') { - data.browser.audio = {}; - - for (var i in audio_formats) { - var can_play_type = audio.canPlayType(audio_formats[i]); - - if (can_play_type == '') { - data.browser.audio[i] = false; - } else { - data.browser.audio[i] = can_play_type; - } - } - } - - - /*-------------------------------------------------------------- - 2.2.10 WEBGL - --------------------------------------------------------------*/ - - if (ctx && ctx instanceof WebGLRenderingContext) { - data.browser.webgl = true; - } - - - /*-------------------------------------------------------------- - 3.0 HARDWARE - --------------------------------------------------------------*/ - - /*-------------------------------------------------------------- - 3.1 SCREEN - --------------------------------------------------------------*/ - - if (screen) { - data.device.screen = screen.width + 'x' + screen.height; - } - - - /*-------------------------------------------------------------- - 3.2 RAM - --------------------------------------------------------------*/ - - if ('deviceMemory' in navigator) { - data.device.ram = navigator.deviceMemory + ' GB'; - } - - - /*-------------------------------------------------------------- - 3.3 GPU - --------------------------------------------------------------*/ - - if ( - ctx && - ctx instanceof WebGLRenderingContext && - 'getParameter' in ctx && - 'getExtension' in ctx - ) { - var info = ctx.getExtension('WEBGL_debug_renderer_info'); - - if (info) { - data.device.gpu = ctx.getParameter(info.UNMASKED_RENDERER_WEBGL); - } - } - - - /*-------------------------------------------------------------- - 3.4 CORES - --------------------------------------------------------------*/ - - if (navigator.hardwareConcurrency) { - data.device.cores = navigator.hardwareConcurrency; - } - - - /*-------------------------------------------------------------- - 3.5 TOUCH - --------------------------------------------------------------*/ - - if ( - window.hasOwnProperty('ontouchstart') || - window.DocumentTouch && document instanceof window.DocumentTouch || - navigator.maxTouchPoints > 0 || - window.navigator.msMaxTouchPoints > 0 - ) { - data.device.touch = true; - data.device.max_touch_points = navigator.maxTouchPoints; - } - - - /*-------------------------------------------------------------- - 3.6 CONNECTION - --------------------------------------------------------------*/ - - if (typeof navigator.connection === 'object') { - data.device.connection.type = navigator.connection.effectiveType || null; - - if (navigator.connection.downlink) { - data.device.connection.speed = navigator.connection.downlink + ' Mbps'; - } - } - - - /*-------------------------------------------------------------- - 4.0 CLEARING - --------------------------------------------------------------*/ - - video.remove(); - audio.remove(); - cvs.remove(); - - - return data; -}; -/*-------------------------------------------------------------- ->>> CONTEXT MENU ---------------------------------------------------------------*/ - -satus.events.add('render', function (component, skeleton) { - if (skeleton.contextMenu) { - component.addEventListener('contextmenu', function (event) { - var x = event.clientX, - y = event.clientY, - modal = satus.render({ - component: 'modal', - variant: 'contextmenu', - parent: skeleton - }); - - if (window.innerWidth - x < 200) { - x = window.innerWidth - 200; - } - - modal.inner.style.left = x + 'px'; - modal.inner.style.top = y + 'px'; - - satus.render(skeleton.contextMenu, modal.inner); - - event.preventDefault(); - event.stopPropagation(); - - return false; - }); - } -}); -/*-------------------------------------------------------------- ->>> EXTENSION STORAGE ---------------------------------------------------------------*/ -/*-------------------------------------------------------------- ->>> UUID ---------------------------------------------------------------*/ - -satus.uuid = function () { - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (match) { - return (match ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> match / 4).toString(16) - }); -}; -/*-------------------------------------------------------------- ->>> PLUVIAM ---------------------------------------------------------------*/ - -satus.events.add('render', function (component, skeleton) { - if (skeleton.pluviam === true) { - function createPluviam(event) { - var pluviam = document.createElement('span'), - rect = this.getBoundingClientRect(), - x = event.clientX - rect.left, - y = event.clientY - rect.top, - diameter = Math.sqrt(Math.pow(rect.width * 2, 2) + Math.pow(rect.height * 2, 2)); - - pluviam.className = 'satus-pluviam'; - - pluviam.style.left = x - diameter / 2 + 'px'; - pluviam.style.top = y - diameter / 2 + 'px'; - pluviam.style.width = diameter + 'px'; - pluviam.style.height = diameter + 'px'; - - this.appendChild(pluviam); - - setTimeout(function () { - pluviam.remove(); - }, 1000); - } - - component.addEventListener('mousedown', createPluviam); - component.addEventListener('mouseover', createPluviam); - } -}); -/*-------------------------------------------------------------- ->>> SORTABLE ---------------------------------------------------------------*/ - -satus.events.add('render', function (component, skeleton) { - if (skeleton.sortable === true) { - component.addEventListener('mousedown', function (event) { - if (event.button !== 0) { - return false; - } - - var component = this, - rect = this.getBoundingClientRect(), - x = event.clientX, - y = event.clientY, - offset_x = event.clientX - rect.left, - offset_y = event.clientY - rect.top, - ghost = satus.clone(this), - children = this.parentNode.children, - appended = false; - - ghost.classList.add('satus-sortable__ghost'); - - function mousemove(event) { - if (appended === false && (Math.abs(event.clientX - x) > 4 || Math.abs(event.clientY - y) > 4)) { - appended = true; - - component.classList.add('satus-sortable__chosen'); - - component.parentNode.appendChild(ghost); - } - - ghost.style.transform = 'translate(' + (event.clientX - offset_x) + 'px, ' + (event.clientY - offset_y) + 'px)'; - } - - function mouseup(event) { - component.classList.remove('satus-sortable__chosen'); - ghost.remove(); - - window.removeEventListener('mousemove', mousemove, true); - window.removeEventListener('mouseup', mouseup, true); - - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i]; - - if (child !== component) { - child.removeEventListener('mouseover', siblingMouseOver); - } - } - - component.dispatchEvent(new CustomEvent('sort')); - - event.stopPropagation(); - - return false; - } - - window.addEventListener('mousemove', mousemove, { - passive: true, - capture: true - }); - - window.addEventListener('mouseup', mouseup, { - passive: true, - capture: true - }); - - function siblingMouseOver(event) { - var target = event.target, - parent = target.parentNode, - y = event.layerY / (target.offsetHeight / 100); - - if (y < 50 && target.previousSibling !== component || y >= 50 && target.nextSibling === component) { - parent.insertBefore(component, target); - } else { - parent.insertBefore(component, target.nextSibling); - } - } - - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i]; - - if (child !== component) { - child.addEventListener('mouseover', siblingMouseOver); - } - } - - event.stopPropagation(); - event.preventDefault(); - - return false; - }); - } -}); \ No newline at end of file diff --git a/ui/script.js b/ui/script.js deleted file mode 100644 index bc873a3..0000000 --- a/ui/script.js +++ /dev/null @@ -1,1016 +0,0 @@ -/*-------------------------------------------------------------- ->>> USER INTERFACE ----------------------------------------------------------------- -# Skeleton -# Initialization ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# SKELETON ---------------------------------------------------------------*/ - -var password, - lists = [], - skeleton = { - component: 'base', - - header: { - component: 'header', - - section_1: { - component: 'section', - variant: 'align-start', - - back: { - component: 'button', - attr: { - 'hidden': 'true' - }, - on: { - click: 'layers.back' - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'none', - 'stroke-width': '1.5', - 'stroke': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M14 18l-6-6 6-6' - } - } - } - }, - title: { - component: 'span', - variant: 'title' - } - }, - section_2: { - component: 'section', - variant: 'align-end', - - menu: { - component: 'button', - on: { - click: { - component: 'modal', - variant: 'vertical', - - label: { - component: 'span', - text: 'theme' - }, - theme: { - component: 'tabs', - items: [ - 'light', - 'dark' - ] - }, - divider: { - component: 'divider' - }, - language: { - component: 'select', - on: { - change: function (name, value) { - var self = this; - - satus.fetch(chrome.runtime.getURL('_locales/' + this.querySelector('select').value + '/messages.json'), function (response) { - response = JSON.parse(response); - - for (var key in response) { - satus.locale.strings[key] = response[key].message; - } - - self.base.skeleton.header.section_1.title.rendered.textContent = satus.locale.get('languages'); - - self.base.skeleton.layers.rendered.update(); - }); - } - }, - options: [{ - value: 'en', - text: 'English' - }, { - value: 'ru', - text: 'Русский' - }, { - value: 'de', - text: 'Deutsch' - }], - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - path: { - component: 'path', - attr: { - 'd': 'M12.9 15l-2.6-2.4c1.8-2 3-4.2 3.8-6.6H17V4h-7V2H8v2H1v2h11.2c-.7 2-1.8 3.8-3.2 5.3-1-1-1.7-2.1-2.3-3.3h-2c.7 1.6 1.7 3.2 3 4.6l-5.1 5L4 19l5-5 3.1 3.1.8-2zm5.6-5h-2L12 22h2l1.1-3H20l1.1 3h2l-4.5-12zm-2.6 7l1.6-4.3 1.6 4.3H16z' - } - } - }, - label: { - component: 'span', - text: 'language' - } - }, - encrypted: { - component: 'switch', - storage: false, - on: { - render: function () { - if (satus.storage.get('encrypted') === true) { - this.dataset.value = 'true'; - } else { - this.dataset.value = 'false'; - } - }, - change: function () { - var component = this; - - crypt(this.dataset.value === 'true', JSON.stringify(lists), function (mode, data) { - if (mode) { - satus.storage.set('encrypted', true); - - component.dataset.value = 'true'; - } else { - satus.storage.remove('encrypted'); - - component.dataset.value = 'false'; - } - - satus.storage.set('lists', data); - }, component); - } - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'none', - 'stroke': 'currentColor', - 'stroke-linecap': 'round', - 'stroke-linejoin': 'round', - 'stroke-width': '2' - }, - - path: { - component: 'path', - attr: { - 'd': 'M21 2l-2 2m-7.61 7.61a5.5 5.5 0 11-7.778 7.778 5.5 5.5 0 017.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4' - } - } - }, - label: { - component: 'span', - text: 'encryption' - } - }, - export: { - component: 'button', - on: { - click: function () { - if (location.href.indexOf('/options.html?action=export') !== -1) { - exportData(); - } else { - chrome.tabs.create({ - url: chrome.runtime.getURL('ui/options.html?action=export') - }); - } - } - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'none', - 'stroke': 'currentColor', - 'stroke-linecap': 'round', - 'stroke-linejoin': 'round', - 'stroke-width': '2' - }, - - path: { - component: 'path', - attr: { - 'd': 'M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12' - } - } - }, - label: { - component: 'span', - text: 'export' - } - }, - import: { - component: 'button', - on: { - click: function () { - if (location.href.indexOf('/options.html?action=import') !== -1) { - importData(); - } else { - chrome.tabs.create({ - url: chrome.runtime.getURL('ui/options.html?action=import') - }); - } - } - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'none', - 'stroke': 'currentColor', - 'stroke-linecap': 'round', - 'stroke-linejoin': 'round', - 'stroke-width': '2' - }, - - path: { - component: 'path', - attr: { - 'd': 'M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3' - } - } - }, - label: { - component: 'span', - text: 'import' - } - } - } - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'currentColor' - }, - - circle_1: { - component: 'circle', - attr: { - 'cx': '12', - 'cy': '5.25', - 'r': '1' - } - }, - circle_2: { - component: 'circle', - attr: { - 'cx': '12', - 'cy': '12', - 'r': '1' - } - }, - circle_3: { - component: 'circle', - attr: { - 'cx': '12', - 'cy': '18.75', - 'r': '1' - } - } - } - } - } - }, - layers: { - component: 'layers', - on: { - open: function () { - var skeleton = this.path[this.path.length - 1], - parent = skeleton.parent, - section = this.base.skeleton.header.section_1, - is_home = this.path.length <= 1, - title = 'ToDo'; - - if (parent) { - if (parent.label) { - title = parent.label.text; - } else if (parent.text) { - title = parent.text; - } - } - - section.back.rendered.hidden = is_home; - section.title.rendered.innerText = satus.locale.get(title); - - if (this.path.length === 1) { - updateLists(); - } - } - } - }, - create: { - component: 'button', - variant: 'create', - attr: { - 'title': 'create' - }, - on: { - click: { - component: 'modal', - - title: { - component: 'span', - text: function () { - if (skeleton.layers.rendered.path.length > 1) { - return 'newTask'; - } else { - return 'newList'; - } - } - }, - input: { - component: 'input', - type: 'text', - autofocus: true, - storage: false, - on: { - render: function () { - this.focus(); - }, - keydown: function (event) { - if (event.key === 'Enter') { - this.parentNode.parentNode.skeleton.actions.create.rendered.click(); - } - } - } - }, - actions: { - component: 'section', - variant: 'actions', - - create: { - component: 'button', - text: 'create', - on: { - click: function () { - var path = skeleton.layers.rendered.path, - modal = this.skeleton.parent.parent, - name = modal.input.rendered.value; - - if (path.length > 1) { - var layer = path[path.length - 1], - task = { - name: name, - value: false, - time: new Date().getTime() - }; - - layer.tasks.push(task); - - satus.empty(layer.rendered); - - updateTasks(layer.tasks); - } else { - lists.push({ - name: name, - tasks: [] - }); - - updateLists(); - } - - updateData(); - - modal.rendered.close(); - } - } - } - } - } - } - } - }; - -function updateLists() { - var layer = skeleton.layers.rendered.children[0], - section = { - component: 'section', - variant: 'card' - }; - - satus.empty(layer); - - if (lists.length === 0) { - section.span = { - component: 'span', - text: 'noLists', - style: { - 'display': 'flex', - 'alignItems': 'center' - } - }; - } - - for (var i = 0, l = lists.length; i < l; i++) { - var list = lists[i]; - - section['list_' + i] = { - component: 'button', - variant: 'folder', - attr: { - title: list.name - }, - list: list, - sortable: true, - contextMenu: { - rename: { - component: 'button', - text: 'rename', - on: { - click: function () { - var modal = this.parentNode.parentNode; - - satus.render({ - component: 'modal', - parent: modal.skeleton.parent, - - title: { - component: 'span', - text: 'rename' - }, - input: { - component: 'input', - type: 'text', - autofocus: true, - storage: false, - value: modal.skeleton.parent.list.name, - on: { - render: function () { - this.focus(); - this.select(); - }, - keydown: function (event) { - if (event.key === 'Enter') { - this.parentNode.parentNode.skeleton.actions.ok.rendered.click(); - } - } - } - }, - actions: { - component: 'section', - variant: 'actions', - - cancel: { - component: 'button', - text: 'cancel', - on: { - click: function () { - var modal = this.parentNode.parentNode.parentNode; - - modal.close(); - } - } - }, - ok: { - component: 'button', - text: 'ok', - on: { - click: function () { - var modal = this.parentNode.parentNode.parentNode, - item = modal.skeleton.parent; - - item.list.name = modal.skeleton.input.rendered.value; - - updateData(); - - updateLists(); - - modal.close(); - } - } - } - } - }); - - modal.close(); - } - } - }, - remove: { - component: 'button', - text: 'remove', - on: { - click: function () { - var modal = this.parentNode.parentNode, - parent = modal.skeleton.parent; - - satus.remove(parent.list, lists); - - updateData(); - - updateLists(); - - modal.close(); - } - } - } - }, - on: { - click: { - component: 'section', - variant: 'card', - tasks: list.tasks, - on: { - render: function () { - updateTasks(this.skeleton.tasks); - } - } - }, - sort: function () { - var index = satus.indexOf(this); - - satus.toIndex(index, this.skeleton.list, lists); - - updateData(); - } - }, - - svg: { - component: 'svg', - attr: { - 'viewBox': '0 0 24 24', - 'fill': 'var(--satus-primary)' - }, - - path: { - component: 'path', - attr: { - 'd': 'M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z' - } - } - }, - label: { - component: 'span', - text: list.name - } - }; - } - - satus.empty(layer); - satus.render(section, layer); -} - -function updateTasks(tasks) { - var path = skeleton.layers.rendered.path, - section = path[path.length - 1].rendered; - - satus.empty(section); - - if (tasks.length === 0) { - satus.render({ - component: 'span', - text: 'noTasks', - style: { - 'display': 'flex', - 'alignItems': 'center' - } - }, section); - } - - for (var i = 0, l = tasks.length; i < l; i++) { - var task = tasks[i]; - - satus.render({ - component: 'checkbox', - attr: { - title: task.name - }, - text: [task.name], - value: task.value, - storage: false, - tasks: tasks, - task: task, - contextMenu: { - rename: { - component: 'button', - text: 'rename', - on: { - click: function () { - var modal = this.parentNode.parentNode; - - satus.render({ - component: 'modal', - parent: modal.skeleton.parent, - - title: { - component: 'span', - text: 'rename' - }, - input: { - component: 'input', - type: 'text', - autofocus: true, - storage: false, - value: modal.skeleton.parent.task.name, - on: { - render: function () { - this.focus(); - this.select(); - }, - keydown: function (event) { - if (event.key === 'Enter') { - this.parentNode.parentNode.skeleton.actions.ok.rendered.click(); - } - } - } - }, - actions: { - component: 'section', - variant: 'actions', - - cancel: { - component: 'button', - text: 'cancel', - on: { - click: function () { - var modal = this.parentNode.parentNode.parentNode; - - modal.close(); - } - } - }, - ok: { - component: 'button', - text: 'ok', - on: { - click: function () { - var modal = this.parentNode.parentNode.parentNode, - item = modal.skeleton.parent; - - item.task.name = modal.skeleton.input.rendered.value; - - updateData(); - - updateTasks(item.tasks); - - modal.close(); - } - } - } - } - }); - - modal.close(); - } - } - }, - remove: { - component: 'button', - text: 'remove', - on: { - click: function () { - var path = skeleton.layers.rendered.path, - layer = path[path.length - 1], - modal = this.parentNode.parentNode, - parent = modal.skeleton.parent; - - satus.remove(parent.task, parent.tasks); - - updateData(); - - updateTasks(parent.tasks); - - modal.close(); - } - } - } - }, - sortable: true, - on: { - change: function () { - this.skeleton.task.value = this.storageValue; - - updateData(); - }, - sort: function () { - var index = satus.indexOf(this); - - satus.toIndex(index, this.skeleton.task, this.skeleton.tasks); - - updateData(); - } - } - }, section); - } -} - -function updateData() { - if (satus.storage.get('encrypted') === true && password) { - encr(); - } else { - satus.storage.set('lists', lists); - } -} - -function crypt(mode, data, callback, component) { - satus.render({ - component: 'modal', - parent: component ? component.skeleton : undefined, - on: { - close: function () { - if (this.skeleton.parent) { - var component = this.skeleton.parent.parent.encrypted.rendered; - - if (satus.storage.get('encrypted') === true) { - component.dataset.value = 'true'; - } else { - component.dataset.value = 'false'; - } - } - } - }, - - title: { - component: 'span', - text: mode ? 'encryption' : 'decryption' - }, - input: { - component: 'input', - type: 'password', - on: { - render: function () { - this.focus(); - }, - keydown: async function (event) { - if (event.key === 'Enter') { - this.parentNode.parentNode.skeleton.actions.ok.rendered.click(); - } - } - } - }, - actions: { - component: 'section', - variant: 'actions', - - ok: { - component: 'button', - text: 'ok', - on: { - click: async function () { - var modal = this.skeleton.parent.parent, - input = modal.input.rendered; - - if (input.value.length > 1) { - if (mode) { - data = await satus.encrypt(data, input.value); - password = input.value; - } else { - data = JSON.parse(await satus.decrypt(data, input.value)); - password = input.value; - } - - if (callback) { - callback(mode, data); - } - - modal.rendered.close(); - } else { - input.classList.add('error'); - } - } - } - } - } - }); -} - -function exportData() { - if (location.href.indexOf('action=export') !== -1) { - var blob; - - try { - blob = new Blob([JSON.stringify(satus.storage.data)], { - type: 'application/json;charset=utf-8' - }); - } catch (error) { - return modalError(error); - } - - satus.render({ - component: 'modal', - - label: { - component: 'span', - text: 'areYouSureYouWantToExportTheData' - }, - actions: { - component: 'section', - variant: 'actions', - - ok: { - component: 'button', - text: 'ok', - on: { - click: function () { - try { - chrome.permissions.request({ - permissions: ['downloads'] - }, function (granted) { - if (granted) { - chrome.downloads.download({ - url: URL.createObjectURL(blob), - filename: 'todo.json', - saveAs: true - }, function () { - setTimeout(function () { - close(); - }, 1000); - }); - } - }); - } catch (error) { - return modalError(error); - } - - this.parentNode.parentNode.parentNode.close(); - } - } - }, - cancel: { - component: 'button', - text: 'cancel', - on: { - click: function () { - this.parentNode.parentNode.parentNode.close(); - } - } - } - } - }); - } -} - -function importData() { - if (location.href.indexOf('action=import') !== -1) { - satus.render({ - component: 'modal', - - label: { - component: 'span', - text: 'areYouSureYouWantToImportTheData' - }, - actions: { - component: 'section', - variant: 'actions', - - ok: { - component: 'button', - text: 'ok', - on: { - click: function () { - var input = document.createElement('input'); - - input.type = 'file'; - - input.addEventListener('change', function () { - var file_reader = new FileReader(); - - file_reader.onload = function () { - var data = JSON.parse(this.result); - - for (var key in data) { - satus.storage.set(key, data[key]); - } - - close(); - }; - - file_reader.readAsText(this.files[0]); - }); - - input.click(); - - this.parentNode.parentNode.parentNode.close(); - } - } - }, - cancel: { - component: 'button', - text: 'cancel', - on: { - click: function () { - this.parentNode.parentNode.parentNode.close(); - } - } - } - } - }); - } -} - -async function encr(callback) { - satus.storage.set('lists', await satus.encrypt(JSON.stringify(lists), password)); - satus.storage.set('encrypted', true); - satus.storage.remove('data'); - - if (callback) { - callback(); - } -} - -function migrateData(callback) { - function change(data) { - lists = []; - - try { - if (typeof data === 'string') { - data = JSON.parse(data); - } - - for (var i = 0, l = data.lists.length; i < l; i++) { - var list = data.lists[i]; - - lists.push({ - name: list.name, - tasks: [] - }); - - for (var j = 0, k = list.items.length; j < k; j++) { - var task = list.items[j]; - - lists[i].tasks.push({ - name: task.name, - value: task.value, - date: new Date().getTime() - }); - } - } - } catch (error) { - console.log(error); - } - } - - if (satus.storage.get('data')) { - if (satus.storage.get('encrypted')) { - crypt(false, satus.storage.get('data'), function (mode, data) { - change(data); - - encr(callback); - }); - } else { - change(satus.storage.get('data')); - - satus.storage.set('lists', lists); - satus.storage.remove('encrypted'); - satus.storage.remove('data'); - - callback(); - } - } else { - callback(); - } -} - - -/*-------------------------------------------------------------- -# INITIALIZATION ---------------------------------------------------------------*/ - -satus.storage.attributes = { - theme: true -}; - -satus.storage.import(function (items) { - satus.locale.import(items.language, '../_locales/', function () { - migrateData(function () { - if (lists.length > 0) { - satus.render(skeleton); - } else if (Array.isArray(satus.storage.get('lists'))) { - lists = satus.storage.get('lists'); - - satus.render(skeleton); - } else if (satus.storage.get('encrypted') === true && typeof satus.storage.get('lists') === 'string') { - crypt(false, satus.storage.get('lists'), function (mode, data) { - lists = data; - - satus.render(skeleton); - }); - } else { - satus.render(skeleton); - } - - exportData(); - importData(); - }); - }); -}); \ No newline at end of file diff --git a/ui/styles.css b/ui/styles.css deleted file mode 100644 index d559c4b..0000000 --- a/ui/styles.css +++ /dev/null @@ -1,80 +0,0 @@ -/*-------------------------------------------------------------- ->>> USER INTERFACE ----------------------------------------------------------------- -# Header -# Layers - Folder -# Create ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# HEADER ---------------------------------------------------------------*/ - -.satus-header .satus-section--align-start { - max-width: calc(100% - 40px); -} - - -/*-------------------------------------------------------------- -# LAYERS ---------------------------------------------------------------*/ - -/*-------------------------------------------------------------- -# FOLDER ---------------------------------------------------------------*/ - -.satus-button--folder { - display: flex; - align-items: center; -} - -.satus-button.satus-button--folder>svg { - width: 20px; - min-width: 20px; - margin: -2px 16px 0 0; -} - -.satus-button--folder>.satus-span { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - - -/*-------------------------------------------------------------- -# CREATE ---------------------------------------------------------------*/ - -.satus-button--create { - position: fixed; - right: 16px; - bottom: 16px; - width: 56px; - height: 56px; - color: #fff; - border-radius: 50%; - background: linear-gradient(135deg, #f8d266, #f17953); - box-shadow: 0 2px 1px 1px rgb(230, 109, 70, .7), 0 3px 5px rgb(0, 0, 0, .35); -} - -.satus-button--create::before { - position: absolute; - top: calc(50% - 1px); - left: calc(50% - 7px); - width: 14px; - height: 2px; - content: ''; - background: currentColor; -} - -.satus-button--create::after { - position: absolute; - top: calc(50% - 7px); - left: calc(50% - 1px); - width: 2px; - height: 14px; - content: ''; - background: currentColor; -} \ No newline at end of file