diff --git a/app/angular/components/dropdownIcon.html b/app/angular/components/dropdownIcon.html index c9f1c844..c537ca2e 100644 --- a/app/angular/components/dropdownIcon.html +++ b/app/angular/components/dropdownIcon.html @@ -3,6 +3,26 @@ - \ No newline at end of file + diff --git a/app/angular/components/dropdownIcon.js b/app/angular/components/dropdownIcon.js index 71039d4f..afed8749 100644 --- a/app/angular/components/dropdownIcon.js +++ b/app/angular/components/dropdownIcon.js @@ -1,14 +1,20 @@ import angular from "angular"; import template from "./dropdownIcon.html"; +import themeService from "../service/themeService"; -const dropDownIconController = function ($element, $timeout) { +const dropDownIconController = function ($element, $timeout, ThemeService) { const ctrl = this; ctrl.open = false; + ctrl.theme = ThemeService.getTheme(); ctrl.toggle = (command) => { ctrl.open = command; }; + ctrl.setTheme = (theme) => { + ctrl.theme = ThemeService.applyTheme(theme); + }; + ctrl.select = (option) => { ctrl.selected = option; ctrl.toggle(false); @@ -26,7 +32,7 @@ const dropDownIconController = function ($element, $timeout) { }; }; -export default angular.module("app.dropdownIcon", []).component("dropdownIcon", { +export default angular.module("app.dropdownIcon", [themeService]).component("dropdownIcon", { template, controller: dropDownIconController, bindings: { diff --git a/app/angular/index.js b/app/angular/index.js index 76c57165..11477e8e 100644 --- a/app/angular/index.js +++ b/app/angular/index.js @@ -17,6 +17,7 @@ import "oclazyload"; import sidebarControlConceptual from "./conceptual/sidebarControl"; import sidebarControlLogic from "./logic/sidebarControl"; import authService from "./service/authService"; +import themeService from "./service/themeService"; import modelService from "./service/modelAPI"; import dropdownComponent from "./components/dropdown"; import dropdownIconComponent from "./components/dropdownIcon"; @@ -41,6 +42,7 @@ const app = angular.module("app", [ "ngCookies" /** textangular */, "oc.lazyLoad", authService, + themeService, modelService, logicService, dropdownComponent, @@ -249,7 +251,9 @@ app.config([ }, ]); -app.run(function ($transitions, $rootScope, AuthService, $state, $window, $location) { +app.run(function ($transitions, $rootScope, AuthService, ThemeService, $state, $window, $location) { + ThemeService.applyTheme(ThemeService.getTheme()); + $transitions.onStart({}, function (trans) { const { requireLogin } = trans.to().data; if (requireLogin) { diff --git a/app/angular/service/themeService.js b/app/angular/service/themeService.js new file mode 100644 index 00000000..cbe5e2f5 --- /dev/null +++ b/app/angular/service/themeService.js @@ -0,0 +1,34 @@ +import angular from "angular"; + +const themeService = function ($window, $document) { + const service = this; + const storageKey = "brmw-theme"; + const themes = { + light: "light", + dark: "dark", + }; + + const getBody = () => $document[0].body; + + service.getTheme = () => { + return $window.localStorage.getItem(storageKey) || themes.light; + }; + + service.applyTheme = (theme) => { + const selectedTheme = theme === themes.dark ? themes.dark : themes.light; + const body = getBody(); + + body.classList.toggle("theme-dark", selectedTheme === themes.dark); + body.classList.toggle("theme-light", selectedTheme === themes.light); + $window.localStorage.setItem(storageKey, selectedTheme); + + return selectedTheme; + }; + + service.toggleTheme = () => { + const nextTheme = service.getTheme() === themes.dark ? themes.light : themes.dark; + return service.applyTheme(nextTheme); + }; +}; + +export default angular.module("app.themeService", []).service("ThemeService", themeService).name; diff --git a/app/i18n/languages/en.js b/app/i18n/languages/en.js index 4399a215..ffc4a755 100644 --- a/app/i18n/languages/en.js +++ b/app/i18n/languages/en.js @@ -180,5 +180,8 @@ export default { 'Star on Github': 'Star on Github', 'Donate': 'Donate', 'Note': 'Note', - 'Color': 'Cor' -}; \ No newline at end of file + 'Color': 'Color', + 'Theme': 'Theme', + 'Light': 'Light', + 'Dark': 'Dark' +}; diff --git a/app/i18n/languages/pt_BR.js b/app/i18n/languages/pt_BR.js index 43688298..38327b8f 100644 --- a/app/i18n/languages/pt_BR.js +++ b/app/i18n/languages/pt_BR.js @@ -182,5 +182,8 @@ export default { 'Star on Github': 'Dê uma estrela', 'Donate': 'Doar', 'Note': 'Anotação', - 'Color': 'Cor' -}; \ No newline at end of file + 'Color': 'Cor', + 'Theme': 'Tema', + 'Light': 'Claro', + 'Dark': 'Escuro' +}; diff --git a/app/sass/colors.scss b/app/sass/colors.scss index 78bca912..b55fc077 100644 --- a/app/sass/colors.scss +++ b/app/sass/colors.scss @@ -67,4 +67,24 @@ // Theme: Purple /////////////////////////////////////////////////////////////////////////////// --theme-purple: hsl(24, 80% 60%); -} \ No newline at end of file +} + +body.theme-dark { + --brand-default: var(--brand-primary-40); + --border-light: hsl(220, 16%, 24%); + --border-default: hsl(220, 14%, 32%); + --border-dark: hsl(220, 12%, 46%); + --gray-95: hsl(220, 18%, 12%); + --gray-90: hsl(220, 16%, 16%); + --gray-80: hsl(220, 14%, 24%); + --gray-70: hsl(220, 12%, 36%); + --gray-50: hsl(220, 10%, 62%); + --gray-30: hsl(220, 14%, 82%); + --gray-20: hsl(220, 18%, 90%); + --gray-10: hsl(220, 22%, 96%); + --white: hsl(220, 18%, 12%); + --black: hsl(220, 22%, 96%); + --accent-light: hsl(52, 60%, 20%); + --accent-base: hsl(52, 80%, 58%); + --accent-dark: hsl(52, 90%, 72%); +} diff --git a/app/sass/joint-custom.scss b/app/sass/joint-custom.scss index 702592c0..035d61ca 100644 --- a/app/sass/joint-custom.scss +++ b/app/sass/joint-custom.scss @@ -16,3 +16,47 @@ .joint-link.joint-theme-default .connection-wrap:hover { display: none; } + +.theme-dark .joint-paper .joint-cell .outer, +.theme-dark .joint-paper .joint-cell .poly { + fill: hsl(220, 16%, 18%); + stroke: hsl(170, 70%, 58%); +} + +.theme-dark .joint-paper .joint-cell .inner { + stroke: hsl(170, 70%, 58%); +} + +.theme-dark .joint-paper .joint-cell text { + fill: hsl(220, 22%, 96%); +} + +.theme-dark .joint-paper .joint-link .connection, +.theme-dark .joint-paper .joint-link .marker-source, +.theme-dark .joint-paper .joint-link .marker-target { + stroke: hsl(220, 22%, 86%); +} + +.theme-dark .joint-paper .joint-link .connection[stroke-dasharray] { + stroke: hsl(45, 86%, 68%); +} + +.theme-dark .joint-paper .uml-class-name-rect { + fill: hsl(170, 58%, 32%); + stroke: hsl(170, 70%, 58%); +} + +.theme-dark .joint-paper .uml-class-attrs-rect, +.theme-dark .joint-paper .uml-class-methods-rect { + fill: hsl(220, 16%, 18%); + stroke: hsl(170, 34%, 48%); +} + +.theme-dark .joint-paper .uml-class-name-text { + fill: hsl(0, 0%, 100%); +} + +.theme-dark .joint-paper .uml-class-attrs-text, +.theme-dark .joint-paper .uml-class-methods-text { + fill: hsl(220, 22%, 94%); +} diff --git a/app/sass/mainHeader.scss b/app/sass/mainHeader.scss index 5e0c19dd..750fba96 100644 --- a/app/sass/mainHeader.scss +++ b/app/sass/mainHeader.scss @@ -139,4 +139,41 @@ .nav-icons .dropdown-menu > li > a { color: var(--gray-20); -} \ No newline at end of file +} + +.theme-menu-item { + min-width: 190px; + padding: 8px 12px 10px; +} + +.theme-menu-label { + display: block; + margin-bottom: 6px; + font-size: 0.85em; + font-weight: 600; + color: var(--gray-30); +} + +.theme-toggle { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 2px; + border: 1px solid var(--border-default); + border-radius: 4px; + background-color: var(--gray-90); +} + +.theme-toggle button { + border: 0; + border-radius: 2px; + padding: 5px 8px; + font-size: 0.9em; + line-height: 1.2; + color: var(--gray-20); + background-color: transparent; +} + +.theme-toggle button.active { + color: hsl(0, 0%, 100%); + background-color: var(--brand-default); +} diff --git a/app/sass/structure.scss b/app/sass/structure.scss index 7e1a969d..22492fdd 100644 --- a/app/sass/structure.scss +++ b/app/sass/structure.scss @@ -26,6 +26,7 @@ body { font-family: BlinkMacSystemFont,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif; font-weight: 400; color: var(--gray-20); + background-color: var(--white); } a, @@ -288,4 +289,44 @@ a:hover, //////////////////////////////////////////////////////////////////////////////// .page-header { border-color: var(--border-default); -} \ No newline at end of file +} + +.theme-dark .dropdown-menu, +.theme-dark .modal-content { + background-color: var(--gray-95); + border-color: var(--border-default); + color: var(--gray-20); +} + +.theme-dark .dropdown-menu .divider { + background-color: var(--border-default); +} + +.theme-dark .dropdown-menu > li > a:hover, +.theme-dark .dropdown-menu > li > a:focus { + background-color: var(--gray-90); + color: var(--gray-10); +} + +.theme-dark .table > thead > tr > th, +.theme-dark .table > tbody > tr > td { + border-color: var(--border-default); +} + +.theme-dark .table-hover > tbody > tr:hover { + background-color: var(--gray-90); +} + +.theme-dark .form-control { + background-color: var(--gray-90); + border-color: var(--border-default); + color: var(--gray-20); +} + +.theme-dark .editor-scroller { + background-color: hsl(220, 18%, 10%); +} + +.theme-dark .editor-scroller .joint-paper { + background-color: hsl(220, 18%, 13%); +}