mirror of
https://github.com/gramps-project/gramps-web.git
synced 2026-10-16 21:01:38 +08:00
Centralize color management (#1135)
This commit is contained in:
@@ -42,8 +42,10 @@ src/
|
|||||||
gramps-js.js # Entry point (registers the custom element)
|
gramps-js.js # Entry point (registers the custom element)
|
||||||
api.js # All API calls, auth helpers, localStorage utilities
|
api.js # All API calls, auth helpers, localStorage utilities
|
||||||
appState.js # App-wide state initialisation
|
appState.js # App-wide state initialisation
|
||||||
|
color.js # Gramps internal hex format converters (tag colours etc.)
|
||||||
config.js # Runtime config (window.grampsjsConfig); see below
|
config.js # Runtime config (window.grampsjsConfig); see below
|
||||||
strings.js # i18n string keys and language list
|
strings.js # i18n string keys and language list
|
||||||
|
theme.js # Colour theme: applyScheme(), applyColors(), DEFAULT_PRIMARY/SECONDARY
|
||||||
util.js # Shared helpers
|
util.js # Shared helpers
|
||||||
components/ # Reusable components
|
components/ # Reusable components
|
||||||
views/ # Page-level components
|
views/ # Page-level components
|
||||||
@@ -80,7 +82,7 @@ html`<grampsjs-icon path="${mdiInformation}"></grampsjs-icon>`
|
|||||||
|
|
||||||
Optional attributes: `color`, `height`, `width`, `rotate`.
|
Optional attributes: `color`, `height`, `width`, `rotate`.
|
||||||
|
|
||||||
For action icon color (add/edit/delete buttons), use `color="var(--mdc-theme-secondary)"` — this is `#0277bd` and is consistent across light and dark mode.
|
For action icon color (add/edit/delete buttons), use `color="var(--mdc-theme-secondary)"` — this is derived from the active secondary seed colour and adapts to light/dark mode.
|
||||||
|
|
||||||
### Mixins
|
### Mixins
|
||||||
|
|
||||||
|
|||||||
+77
-121
@@ -11,8 +11,7 @@ body {
|
|||||||
/* Web Awesome color token overrides.
|
/* Web Awesome color token overrides.
|
||||||
default.css (loaded in index.html) defines --wa-* tokens inside @layer wa-theme,
|
default.css (loaded in index.html) defines --wa-* tokens inside @layer wa-theme,
|
||||||
so these unlayered declarations win without !important. The --md-sys-color-*
|
so these unlayered declarations win without !important. The --md-sys-color-*
|
||||||
values on the right are defined in the light/dark blocks below, so the
|
values on the right are set dynamically by applyColors() in theme.js. */
|
||||||
color picker automatically adapts to the active theme. */
|
|
||||||
--wa-color-surface-raised: var(--md-sys-color-surface-container-high);
|
--wa-color-surface-raised: var(--md-sys-color-surface-container-high);
|
||||||
--wa-color-surface-default: var(--md-sys-color-surface);
|
--wa-color-surface-default: var(--md-sys-color-surface);
|
||||||
--wa-color-surface-border: var(--md-sys-color-outline-variant);
|
--wa-color-surface-border: var(--md-sys-color-outline-variant);
|
||||||
@@ -29,7 +28,7 @@ body {
|
|||||||
--color-other: #ce93d8;
|
--color-other: #ce93d8;
|
||||||
--mdc-theme-primary: var(--md-sys-color-primary);
|
--mdc-theme-primary: var(--md-sys-color-primary);
|
||||||
--mdc-theme-on-primary: var(--md-sys-color-on-primary);
|
--mdc-theme-on-primary: var(--md-sys-color-on-primary);
|
||||||
--mdc-theme-secondary: #0277bd;
|
--mdc-theme-secondary: var(--md-sys-color-secondary);
|
||||||
--mdc-theme-on-secondary: rgba(255, 255, 255, 0.95);
|
--mdc-theme-on-secondary: rgba(255, 255, 255, 0.95);
|
||||||
--mdc-theme-background: var(--md-sys-color-background);
|
--mdc-theme-background: var(--md-sys-color-background);
|
||||||
--mdc-theme-surface: var(--md-sys-color-surface);
|
--mdc-theme-surface: var(--md-sys-color-surface);
|
||||||
@@ -49,11 +48,27 @@ body {
|
|||||||
--grampsjs-lightbox-font-color: #fff;
|
--grampsjs-lightbox-font-color: #fff;
|
||||||
--grampsjs-lightbox-nav-color: #aaa;
|
--grampsjs-lightbox-nav-color: #aaa;
|
||||||
--grampsjs-lightbox-nav-hover-color: #fff;
|
--grampsjs-lightbox-nav-hover-color: #fff;
|
||||||
--grampsjs-alert-background-color: rgba(109, 76, 65, 0.15);
|
--grampsjs-alert-background-color: color-mix(
|
||||||
--grampsjs-alert-border-color: rgba(109, 76, 65, 0.7);
|
in srgb,
|
||||||
--grampsjs-alert-error-background-color: rgba(191, 54, 12, 0.2);
|
var(--md-sys-color-primary) 15%,
|
||||||
--grampsjs-alert-error-border-color: rgba(191, 54, 12, 0.7);
|
transparent
|
||||||
--grampsjs-alert-error-font-color: #bf360c;
|
);
|
||||||
|
--grampsjs-alert-border-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--md-sys-color-primary) 70%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-alert-error-background-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--md-sys-color-error) 20%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-alert-error-border-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--md-sys-color-error) 70%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-alert-error-font-color: var(--md-sys-color-error);
|
||||||
--grampsjs-map-marker-color: #ea4335;
|
--grampsjs-map-marker-color: #ea4335;
|
||||||
--grampsjs-map-filter-badge-color: #ba1b1b;
|
--grampsjs-map-filter-badge-color: #ba1b1b;
|
||||||
--grampsjs-logout-font-color: #c62828;
|
--grampsjs-logout-font-color: #c62828;
|
||||||
@@ -64,16 +79,59 @@ body {
|
|||||||
--grampsjs-task-open: #007bff;
|
--grampsjs-task-open: #007bff;
|
||||||
--grampsjs-task-progress: #ff9800;
|
--grampsjs-task-progress: #ff9800;
|
||||||
--grampsjs-task-done: rgba(65, 173, 73, 0.4);
|
--grampsjs-task-done: rgba(65, 173, 73, 0.4);
|
||||||
--grampsjs-editable-title-hover-background-color: rgba(2, 119, 189, 0.2);
|
--grampsjs-editable-title-hover-background-color: color-mix(
|
||||||
--grampsjs-delete-all-filter-chip-color: rgba(109, 76, 65, 0.32);
|
in srgb,
|
||||||
--grampsjs-connection-chart-border-color: rgba(137, 107, 94, 0.4);
|
var(--mdc-theme-secondary) 20%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-delete-all-filter-chip-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--md-sys-color-primary) 32%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-connection-chart-border-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--md-sys-color-primary) 40%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
--grampsjs-connection-chart-person-box: #e6e6e6;
|
--grampsjs-connection-chart-person-box: #e6e6e6;
|
||||||
--grampsjs-editable-list-hover-background-color: rgba(2, 119, 189, 0.1);
|
--grampsjs-editable-list-hover-background-color: color-mix(
|
||||||
--grampsjs-editable-list-active-background-color: rgba(2, 119, 189, 0.2);
|
in srgb,
|
||||||
--grampsjs-editable-list-selected-active-background-color: rgba(2, 119, 189, 0.3);
|
var(--mdc-theme-secondary) 10%,
|
||||||
--grampsjs-editable-list-selected-hover-background-color: rgba(2, 119, 189, 0.4);
|
transparent
|
||||||
--grampsjs-editable-list-selected-background-color: rgba(2, 119, 189, 0.5);
|
);
|
||||||
--grampsjs-mobile-table-sort-menu-color: rgba(109, 76, 65, 0.3);
|
--grampsjs-editable-list-active-background-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--mdc-theme-secondary) 20%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-editable-list-selected-active-background-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--mdc-theme-secondary) 30%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-editable-list-selected-hover-background-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--mdc-theme-secondary) 40%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-editable-list-selected-background-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--mdc-theme-secondary) 50%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-mobile-table-sort-menu-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--md-sys-color-primary) 30%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
--grampsjs-color-link-font: var(--mdc-theme-secondary);
|
||||||
|
--grampsjs-color-link-hover: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--mdc-theme-secondary) 80%,
|
||||||
|
black
|
||||||
|
);
|
||||||
|
--grampsjs-color-page-loading-progress: var(--mdc-theme-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-theme='light'] {
|
:root[data-theme='light'] {
|
||||||
@@ -116,9 +174,6 @@ body {
|
|||||||
--grampsjs-color-skeleton-background: #eee;
|
--grampsjs-color-skeleton-background: #eee;
|
||||||
--grampsjs-color-skeleton-base: #ececec;
|
--grampsjs-color-skeleton-base: #ececec;
|
||||||
--grampsjs-color-skeleton-shine: #f5f5f5;
|
--grampsjs-color-skeleton-shine: #f5f5f5;
|
||||||
--grampsjs-color-link-font: #0d47a1;
|
|
||||||
--grampsjs-color-link-hover: #1976d2;
|
|
||||||
--grampsjs-color-page-loading-progress: #4fc3f7;
|
|
||||||
--grampsjs-color-revision-deleted-background-red: #ffebe9;
|
--grampsjs-color-revision-deleted-background-red: #ffebe9;
|
||||||
--grampsjs-color-revision-added-background-green: #dafbe1;
|
--grampsjs-color-revision-added-background-green: #dafbe1;
|
||||||
--grampsjs-color-revision-moved-background-blue: #ddf4ff;
|
--grampsjs-color-revision-moved-background-blue: #ddf4ff;
|
||||||
@@ -131,55 +186,7 @@ body {
|
|||||||
--grampsjs-color-ytree-expand-font: #555;
|
--grampsjs-color-ytree-expand-font: #555;
|
||||||
--grampsjs-color-ytree-default-person-icon-background: #bbb;
|
--grampsjs-color-ytree-default-person-icon-background: #bbb;
|
||||||
--grampsjs-note-color: #333;
|
--grampsjs-note-color: #333;
|
||||||
--md-sys-color-primary: rgb(109, 76, 65);
|
/* --md-sys-color-* tokens are set dynamically by applyColors() in theme.js */
|
||||||
--md-sys-color-surface-tint: rgb(109, 76, 65);
|
|
||||||
--md-sys-color-on-primary: rgb(255, 255, 255);
|
|
||||||
--md-sys-color-primary-container: rgb(255, 219, 207);
|
|
||||||
--md-sys-color-on-primary-container: rgb(57, 12, 0);
|
|
||||||
--md-sys-color-secondary: rgb(49, 98, 141);
|
|
||||||
--md-sys-color-on-secondary: rgb(255, 255, 255);
|
|
||||||
--md-sys-color-secondary-container: rgb(207, 229, 255);
|
|
||||||
--md-sys-color-on-secondary-container: rgb(0, 29, 52);
|
|
||||||
--md-sys-color-tertiary: rgb(106, 94, 47);
|
|
||||||
--md-sys-color-on-tertiary: rgb(255, 255, 255);
|
|
||||||
--md-sys-color-tertiary-container: rgb(243, 226, 167);
|
|
||||||
--md-sys-color-on-tertiary-container: rgb(34, 27, 0);
|
|
||||||
--md-sys-color-error: rgb(186, 26, 26);
|
|
||||||
--md-sys-color-on-error: rgb(255, 255, 255);
|
|
||||||
--md-sys-color-error-container: rgb(255, 218, 214);
|
|
||||||
--md-sys-color-on-error-container: rgb(65, 0, 2);
|
|
||||||
--md-sys-color-background: #fff;;
|
|
||||||
--md-sys-color-on-background: var(--grampsjs-body-font-color);
|
|
||||||
--md-sys-color-surface: #fff;
|
|
||||||
--md-sys-color-on-surface: var(--grampsjs-body-font-color);
|
|
||||||
--md-sys-color-surface-variant: rgb(232, 224, 222);
|
|
||||||
--md-sys-color-on-surface-variant: rgb(83, 67, 63);
|
|
||||||
--md-sys-color-outline: rgb(133, 115, 110);
|
|
||||||
--md-sys-color-outline-variant: rgb(200, 200, 200);
|
|
||||||
--md-sys-color-shadow: rgb(0, 0, 0);
|
|
||||||
--md-sys-color-scrim: rgb(0, 0, 0);
|
|
||||||
--md-sys-color-inverse-surface: rgb(57, 46, 43);
|
|
||||||
--md-sys-color-inverse-on-surface: rgb(255, 237, 232);
|
|
||||||
--md-sys-color-inverse-primary: rgb(255, 181, 156);
|
|
||||||
--md-sys-color-primary-fixed: rgb(255, 219, 207);
|
|
||||||
--md-sys-color-on-primary-fixed: rgb(57, 12, 0);
|
|
||||||
--md-sys-color-primary-fixed-dim: rgb(255, 181, 156);
|
|
||||||
--md-sys-color-on-primary-fixed-variant: rgb(114, 53, 32);
|
|
||||||
--md-sys-color-secondary-fixed: rgb(207, 229, 255);
|
|
||||||
--md-sys-color-on-secondary-fixed: rgb(0, 29, 52);
|
|
||||||
--md-sys-color-secondary-fixed-dim: rgb(157, 203, 251);
|
|
||||||
--md-sys-color-on-secondary-fixed-variant: rgb(18, 74, 115);
|
|
||||||
--md-sys-color-tertiary-fixed: rgb(243, 226, 167);
|
|
||||||
--md-sys-color-on-tertiary-fixed: rgb(34, 27, 0);
|
|
||||||
--md-sys-color-tertiary-fixed-dim: rgb(214, 198, 141);
|
|
||||||
--md-sys-color-on-tertiary-fixed-variant: rgb(81, 70, 26);
|
|
||||||
--md-sys-color-surface-dim: rgb(232, 214, 209);
|
|
||||||
--md-sys-color-surface-bright: rgb(255, 248, 246);
|
|
||||||
--md-sys-color-surface-container-lowest: rgb(245, 245, 245);
|
|
||||||
--md-sys-color-surface-container-low: rgb(240, 240, 240);
|
|
||||||
--md-sys-color-surface-container: #fff;
|
|
||||||
--md-sys-color-surface-container-high: #fff;
|
|
||||||
--md-sys-color-surface-container-highest: whitesmoke;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[data-theme='dark'] {
|
:root[data-theme='dark'] {
|
||||||
@@ -222,9 +229,6 @@ body {
|
|||||||
--grampsjs-color-skeleton-background: #222;
|
--grampsjs-color-skeleton-background: #222;
|
||||||
--grampsjs-color-skeleton-base: #232323;
|
--grampsjs-color-skeleton-base: #232323;
|
||||||
--grampsjs-color-skeleton-shine: #1a1a1a;
|
--grampsjs-color-skeleton-shine: #1a1a1a;
|
||||||
--grampsjs-color-link-font: #5193f6;
|
|
||||||
--grampsjs-color-link-hover: #62adf8;
|
|
||||||
--grampsjs-color-page-loading-progress: #42a6d2;
|
|
||||||
--grampsjs-color-revision-deleted-background-red: rgba(248, 81, 73, 0.3);
|
--grampsjs-color-revision-deleted-background-red: rgba(248, 81, 73, 0.3);
|
||||||
--grampsjs-color-revision-added-background-green: rgba(46, 160, 67, 0.15);
|
--grampsjs-color-revision-added-background-green: rgba(46, 160, 67, 0.15);
|
||||||
--grampsjs-color-revision-moved-background-blue: rgba(56, 139, 253, 0.1);
|
--grampsjs-color-revision-moved-background-blue: rgba(56, 139, 253, 0.1);
|
||||||
@@ -238,55 +242,7 @@ body {
|
|||||||
--grampsjs-color-ytree-default-person-icon-background: var(--md-sys-color-surface-container);
|
--grampsjs-color-ytree-default-person-icon-background: var(--md-sys-color-surface-container);
|
||||||
--grampsjs-note-color: #ccc;
|
--grampsjs-note-color: #ccc;
|
||||||
--grampsjs-map-marker-color: #bb1f11;
|
--grampsjs-map-marker-color: #bb1f11;
|
||||||
--md-sys-color-primary: #8d7168;
|
/* --md-sys-color-* tokens are set dynamically by applyColors() in theme.js */
|
||||||
--md-sys-color-surface-tint: rgb(233, 189, 174);
|
|
||||||
--md-sys-color-on-primary: rgba(0, 0, 0, 0.8);
|
|
||||||
--md-sys-color-primary-container: rgb(109, 76, 65);
|
|
||||||
--md-sys-color-on-primary-container: rgb(235, 190, 176);
|
|
||||||
--md-sys-color-secondary: rgb(156, 203, 251);
|
|
||||||
--md-sys-color-on-secondary: rgb(0, 51, 84);
|
|
||||||
--md-sys-color-secondary-container: rgb(49, 98, 141);
|
|
||||||
--md-sys-color-on-secondary-container: rgb(189, 220, 255);
|
|
||||||
--md-sys-color-tertiary: rgb(214, 198, 141);
|
|
||||||
--md-sys-color-on-tertiary: rgb(57, 48, 5);
|
|
||||||
--md-sys-color-tertiary-container: rgb(106, 94, 47);
|
|
||||||
--md-sys-color-on-tertiary-container: rgb(233, 216, 158);
|
|
||||||
--md-sys-color-error: rgb(255, 180, 171);
|
|
||||||
--md-sys-color-on-error: rgb(105, 0, 4);
|
|
||||||
--md-sys-color-error-container: rgb(186, 26, 26);
|
|
||||||
--md-sys-color-on-error-container: rgb(255, 205, 199);
|
|
||||||
--md-sys-color-background: rgb(22, 19, 18);
|
|
||||||
--md-sys-color-on-background: rgb(233, 225, 222);
|
|
||||||
--md-sys-color-surface: rgb(20, 19, 19);
|
|
||||||
--md-sys-color-on-surface: rgb(229, 226, 225);
|
|
||||||
--md-sys-color-surface-variant: rgb(68, 71, 72);
|
|
||||||
--md-sys-color-on-surface-variant: rgb(196, 199, 200);
|
|
||||||
--md-sys-color-outline: rgb(142, 145, 146);
|
|
||||||
--md-sys-color-outline-variant: rgb(68, 71, 72);
|
|
||||||
--md-sys-color-shadow: rgb(0, 0, 0);
|
|
||||||
--md-sys-color-scrim: rgb(0, 0, 0);
|
|
||||||
--md-sys-color-inverse-surface: rgb(229, 226, 225);
|
|
||||||
--md-sys-color-inverse-on-surface: rgb(49, 48, 48);
|
|
||||||
--md-sys-color-inverse-primary: rgb(121, 86, 75);
|
|
||||||
--md-sys-color-primary-fixed: rgb(255, 219, 207);
|
|
||||||
--md-sys-color-on-primary-fixed: rgb(45, 21, 13);
|
|
||||||
--md-sys-color-primary-fixed-dim: rgb(233, 189, 174);
|
|
||||||
--md-sys-color-on-primary-fixed-variant: rgb(94, 63, 53);
|
|
||||||
--md-sys-color-secondary-fixed: rgb(207, 229, 255);
|
|
||||||
--md-sys-color-on-secondary-fixed: rgb(0, 29, 51);
|
|
||||||
--md-sys-color-secondary-fixed-dim: rgb(156, 203, 251);
|
|
||||||
--md-sys-color-on-secondary-fixed-variant: rgb(17, 74, 115);
|
|
||||||
--md-sys-color-tertiary-fixed: rgb(243, 226, 167);
|
|
||||||
--md-sys-color-on-tertiary-fixed: rgb(34, 27, 0);
|
|
||||||
--md-sys-color-tertiary-fixed-dim: rgb(214, 198, 141);
|
|
||||||
--md-sys-color-on-tertiary-fixed-variant: rgb(81, 70, 26);
|
|
||||||
--md-sys-color-surface-dim: rgb(20, 19, 19);
|
|
||||||
--md-sys-color-surface-bright: rgb(58, 57, 57);
|
|
||||||
--md-sys-color-surface-container-lowest: rgb(14, 14, 14);
|
|
||||||
--md-sys-color-surface-container-low: rgb(28, 27, 27);
|
|
||||||
--md-sys-color-surface-container: rgb(32, 31, 31);
|
|
||||||
--md-sys-color-surface-container-high: rgb(42, 42, 42);
|
|
||||||
--md-sys-color-surface-container-highest: rgb(53, 52, 52);
|
|
||||||
--mdc-select-fill-color: var(--md-sys-color-surface-container-highest);
|
--mdc-select-fill-color: var(--md-sys-color-surface-container-highest);
|
||||||
--mdc-select-ink-color: var(--md-sys-color-on-surface);
|
--mdc-select-ink-color: var(--md-sys-color-on-surface);
|
||||||
--mdc-select-label-ink-color: rgba(255, 255, 255, 0.5);
|
--mdc-select-label-ink-color: rgba(255, 255, 255, 0.5);
|
||||||
|
|||||||
Generated
+11
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@awesome.me/webawesome": "^3.4.0",
|
"@awesome.me/webawesome": "^3.4.0",
|
||||||
"@hpcc-js/wasm": "^2.22.4",
|
"@hpcc-js/wasm": "^2.22.4",
|
||||||
|
"@material/material-color-utilities": "^0.4.0",
|
||||||
"@material/mwc-button": "^0.27.0",
|
"@material/mwc-button": "^0.27.0",
|
||||||
"@material/mwc-circular-progress": "^0.27.0",
|
"@material/mwc-circular-progress": "^0.27.0",
|
||||||
"@material/mwc-drawer": "^0.27.0",
|
"@material/mwc-drawer": "^0.27.0",
|
||||||
@@ -2859,6 +2860,11 @@
|
|||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@material/material-color-utilities": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-dlq6VExJReb8dhjj3a/yTigr3ncNwoFmL5Iy2ENtbDX03EmNeOEdZ+vsaGrj7RTuO+mB7L58II4LCsl4NpM8uw=="
|
||||||
|
},
|
||||||
"node_modules/@material/menu": {
|
"node_modules/@material/menu": {
|
||||||
"version": "14.0.0-canary.53b3cad2f.0",
|
"version": "14.0.0-canary.53b3cad2f.0",
|
||||||
"resolved": "https://registry.npmjs.org/@material/menu/-/menu-14.0.0-canary.53b3cad2f.0.tgz",
|
"resolved": "https://registry.npmjs.org/@material/menu/-/menu-14.0.0-canary.53b3cad2f.0.tgz",
|
||||||
@@ -16642,6 +16648,11 @@
|
|||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@material/material-color-utilities": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-dlq6VExJReb8dhjj3a/yTigr3ncNwoFmL5Iy2ENtbDX03EmNeOEdZ+vsaGrj7RTuO+mB7L58II4LCsl4NpM8uw=="
|
||||||
|
},
|
||||||
"@material/menu": {
|
"@material/menu": {
|
||||||
"version": "14.0.0-canary.53b3cad2f.0",
|
"version": "14.0.0-canary.53b3cad2f.0",
|
||||||
"resolved": "https://registry.npmjs.org/@material/menu/-/menu-14.0.0-canary.53b3cad2f.0.tgz",
|
"resolved": "https://registry.npmjs.org/@material/menu/-/menu-14.0.0-canary.53b3cad2f.0.tgz",
|
||||||
|
|||||||
+2
-1
@@ -127,6 +127,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@awesome.me/webawesome": "^3.4.0",
|
"@awesome.me/webawesome": "^3.4.0",
|
||||||
"@hpcc-js/wasm": "^2.22.4",
|
"@hpcc-js/wasm": "^2.22.4",
|
||||||
|
"@material/material-color-utilities": "^0.4.0",
|
||||||
"@material/mwc-button": "^0.27.0",
|
"@material/mwc-button": "^0.27.0",
|
||||||
"@material/mwc-circular-progress": "^0.27.0",
|
"@material/mwc-circular-progress": "^0.27.0",
|
||||||
"@material/mwc-drawer": "^0.27.0",
|
"@material/mwc-drawer": "^0.27.0",
|
||||||
@@ -163,4 +164,4 @@
|
|||||||
"pwa-helpers": "^0.9.1",
|
"pwa-helpers": "^0.9.1",
|
||||||
"tippy.js": "^6.3.7"
|
"tippy.js": "^6.3.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-3
@@ -39,7 +39,7 @@ import './components/GrampsjsUndoTransaction.js'
|
|||||||
import './components/GrampsjsUpdateAvailable.js'
|
import './components/GrampsjsUpdateAvailable.js'
|
||||||
import './components/GrampsjsUpgradeDb.js'
|
import './components/GrampsjsUpgradeDb.js'
|
||||||
import {sharedStyles} from './SharedStyles.js'
|
import {sharedStyles} from './SharedStyles.js'
|
||||||
import {applyTheme} from './theme.js'
|
import {applyScheme, DEFAULT_PRIMARY, DEFAULT_SECONDARY} from './theme.js'
|
||||||
import {handleOIDCCallback, handleOIDCComplete} from './oidc.js'
|
import {handleOIDCCallback, handleOIDCComplete} from './oidc.js'
|
||||||
|
|
||||||
const LOADING_STATE_INITIAL = 0
|
const LOADING_STATE_INITIAL = 0
|
||||||
@@ -661,10 +661,18 @@ export class GrampsJs extends LitElement {
|
|||||||
this._loadFrontendStrings(this.appState.settings.lang)
|
this._loadFrontendStrings(this.appState.settings.lang)
|
||||||
}
|
}
|
||||||
|
|
||||||
applyTheme(this.appState.settings.theme)
|
applyScheme(
|
||||||
|
DEFAULT_PRIMARY,
|
||||||
|
DEFAULT_SECONDARY,
|
||||||
|
this.appState.settings.theme
|
||||||
|
)
|
||||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||||
mediaQuery.addEventListener('change', () =>
|
mediaQuery.addEventListener('change', () =>
|
||||||
applyTheme(this.appState.settings.theme)
|
applyScheme(
|
||||||
|
DEFAULT_PRIMARY,
|
||||||
|
DEFAULT_SECONDARY,
|
||||||
|
this.appState.settings.theme
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+109
-2
@@ -1,3 +1,16 @@
|
|||||||
|
import {
|
||||||
|
DynamicScheme,
|
||||||
|
Hct,
|
||||||
|
MaterialDynamicColors,
|
||||||
|
TonalPalette,
|
||||||
|
Variant,
|
||||||
|
argbFromHex,
|
||||||
|
hexFromArgb,
|
||||||
|
} from '@material/material-color-utilities'
|
||||||
|
|
||||||
|
export const DEFAULT_PRIMARY = '#6d4c41'
|
||||||
|
export const DEFAULT_SECONDARY = '#0277bd'
|
||||||
|
|
||||||
export function getSystemTheme() {
|
export function getSystemTheme() {
|
||||||
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
? 'dark'
|
? 'dark'
|
||||||
@@ -8,6 +21,100 @@ export function getCurrentTheme(theme) {
|
|||||||
return theme === undefined || theme === 'system' ? getSystemTheme() : theme
|
return theme === undefined || theme === 'system' ? getSystemTheme() : theme
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyTheme(theme) {
|
function toKebabCase(str) {
|
||||||
document.documentElement.setAttribute('data-theme', getCurrentTheme(theme))
|
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyColors(
|
||||||
|
primaryHex = DEFAULT_PRIMARY,
|
||||||
|
secondaryHex = DEFAULT_SECONDARY,
|
||||||
|
isDark = false
|
||||||
|
) {
|
||||||
|
const primaryHct = Hct.fromInt(argbFromHex(primaryHex))
|
||||||
|
const secondaryHct = Hct.fromInt(argbFromHex(secondaryHex))
|
||||||
|
const secondaryPalette = TonalPalette.fromHueAndChroma(
|
||||||
|
secondaryHct.hue,
|
||||||
|
secondaryHct.chroma
|
||||||
|
)
|
||||||
|
|
||||||
|
const primaryPalette = TonalPalette.fromHueAndChroma(
|
||||||
|
primaryHct.hue,
|
||||||
|
primaryHct.chroma
|
||||||
|
)
|
||||||
|
|
||||||
|
const scheme = new DynamicScheme({
|
||||||
|
sourceColorHct: primaryHct,
|
||||||
|
variant: Variant.TONAL_SPOT,
|
||||||
|
isDark,
|
||||||
|
contrastLevel: 0,
|
||||||
|
// Preserve the seed's own hue+chroma rather than TONAL_SPOT's fixed values.
|
||||||
|
primaryPalette,
|
||||||
|
secondaryPalette,
|
||||||
|
// Chroma 0 → pure neutral grays; no hue tint bleeds into surfaces.
|
||||||
|
neutralPalette: TonalPalette.fromHueAndChroma(primaryHct.hue, 0),
|
||||||
|
neutralVariantPalette: TonalPalette.fromHueAndChroma(primaryHct.hue, 0),
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = document.documentElement
|
||||||
|
for (const [name, color] of Object.entries(MaterialDynamicColors)) {
|
||||||
|
if (typeof color?.getArgb !== 'function') continue
|
||||||
|
root.style.setProperty(
|
||||||
|
`--md-sys-color-${toKebabCase(name)}`,
|
||||||
|
hexFromArgb(color.getArgb(scheme))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primary: use seed's own tone clamped to [30, 50] so users see their chosen
|
||||||
|
// colour on the app bar. Tone 30-50 always reads white on-primary text.
|
||||||
|
const primaryTone = isDark
|
||||||
|
? Math.min(80, Math.max(60, Math.round(primaryHct.tone)))
|
||||||
|
: Math.min(50, Math.max(30, Math.round(primaryHct.tone)))
|
||||||
|
root.style.setProperty(
|
||||||
|
'--md-sys-color-primary',
|
||||||
|
hexFromArgb(primaryPalette.tone(primaryTone))
|
||||||
|
)
|
||||||
|
|
||||||
|
// M3 achromatic tones 90-98 are darker than expected for a web app.
|
||||||
|
// Override light-mode surfaces to lighter neutrals.
|
||||||
|
if (!isDark) {
|
||||||
|
root.style.setProperty('--md-sys-color-background', '#ffffff')
|
||||||
|
root.style.setProperty('--md-sys-color-surface', '#ffffff')
|
||||||
|
// lowest/low/container → menus, cards, sheets: white
|
||||||
|
root.style.setProperty('--md-sys-color-surface-container-lowest', '#ffffff')
|
||||||
|
root.style.setProperty('--md-sys-color-surface-container-low', '#ffffff')
|
||||||
|
root.style.setProperty('--md-sys-color-surface-container', '#ffffff')
|
||||||
|
// high/highest → filled input and select backgrounds: light gray
|
||||||
|
root.style.setProperty(
|
||||||
|
'--md-sys-color-surface-container-high',
|
||||||
|
'rgb(240, 240, 240)'
|
||||||
|
)
|
||||||
|
root.style.setProperty(
|
||||||
|
'--md-sys-color-surface-container-highest',
|
||||||
|
'rgb(235, 235, 235)'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action color for edit/add/delete buttons: clamp tone to a readable range
|
||||||
|
// so very light or very dark seeds still contrast against their background.
|
||||||
|
const actionTone = isDark
|
||||||
|
? Math.min(80, Math.max(60, Math.round(secondaryHct.tone)))
|
||||||
|
: Math.min(55, Math.max(30, Math.round(secondaryHct.tone)))
|
||||||
|
root.style.setProperty(
|
||||||
|
'--mdc-theme-secondary',
|
||||||
|
hexFromArgb(secondaryPalette.tone(actionTone))
|
||||||
|
)
|
||||||
|
root.style.setProperty(
|
||||||
|
'--mdc-theme-on-secondary',
|
||||||
|
actionTone < 60 ? 'rgba(255, 255, 255, 0.95)' : 'rgba(0, 0, 0, 0.87)'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyScheme(
|
||||||
|
primaryHex = DEFAULT_PRIMARY,
|
||||||
|
secondaryHex = DEFAULT_SECONDARY,
|
||||||
|
theme
|
||||||
|
) {
|
||||||
|
const isDark = getCurrentTheme(theme) === 'dark'
|
||||||
|
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light')
|
||||||
|
applyColors(primaryHex, secondaryHex, isDark)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {GrampsjsView} from './GrampsjsView.js'
|
|||||||
import {mdiCheck, mdiContentCopy} from '@mdi/js'
|
import {mdiCheck, mdiContentCopy} from '@mdi/js'
|
||||||
import {__APIHOST__} from '../api.js'
|
import {__APIHOST__} from '../api.js'
|
||||||
import {fireEvent} from '../util.js'
|
import {fireEvent} from '../util.js'
|
||||||
import {applyTheme} from '../theme.js'
|
import {applyScheme, DEFAULT_PRIMARY, DEFAULT_SECONDARY} from '../theme.js'
|
||||||
import {DEFAULT_TREE_VIEW, TREE_VIEWS} from '../treeDefaults.js'
|
import {DEFAULT_TREE_VIEW, TREE_VIEWS} from '../treeDefaults.js'
|
||||||
|
|
||||||
export class GrampsjsViewSettingsUser extends GrampsjsView {
|
export class GrampsjsViewSettingsUser extends GrampsjsView {
|
||||||
@@ -186,7 +186,7 @@ export class GrampsjsViewSettingsUser extends GrampsjsView {
|
|||||||
_handleThemeSelected(event) {
|
_handleThemeSelected(event) {
|
||||||
const theme = event.target.value
|
const theme = event.target.value
|
||||||
this.appState.updateSettings({theme})
|
this.appState.updateSettings({theme})
|
||||||
applyTheme(theme)
|
applyScheme(DEFAULT_PRIMARY, DEFAULT_SECONDARY, theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTreePreferences() {
|
renderTreePreferences() {
|
||||||
|
|||||||
@@ -8,5 +8,12 @@ export default defineConfig({
|
|||||||
reporter: ['text', 'lcov'],
|
reporter: ['text', 'lcov'],
|
||||||
include: ['src/**/*.js'],
|
include: ['src/**/*.js'],
|
||||||
},
|
},
|
||||||
|
server: {
|
||||||
|
deps: {
|
||||||
|
// ESM imports in this package lack .js extensions, which Node.js
|
||||||
|
// strict ESM requires. Inline through Vite's bundler instead.
|
||||||
|
inline: ['@material/material-color-utilities'],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user