Skip to content

Commit bea9d1b

Browse files
committed
Dark mode theme switcher
1 parent 36a9a93 commit bea9d1b

File tree

21 files changed

+155
-73
lines changed

21 files changed

+155
-73
lines changed

mathesar_ui/src/App.svelte

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -91,26 +91,6 @@
9191
--cell-border-horizontal: 1px solid var(--gray-300);
9292
--cell-border-vertical: 1px solid var(--gray-300);
9393
94-
@media (prefers-color-scheme: dark) {
95-
--cell-bg-mix-blend-mode: screen;
96-
--cell-bg-color-base: var(--background-color);
97-
--cell-bg-color-error: rgba(255, 107, 107, 0.15);
98-
--cell-bg-color-header: rgba(39, 43, 48, 0.5);
99-
--cell-bg-color-processing: rgba(251, 191, 36, 0.15);
100-
--cell-bg-color-disabled: rgba(39, 43, 48, 0.3);
101-
--cell-bg-color-row-hover: rgba(39, 43, 48, 0.2);
102-
--cell-bg-color-row-selected: rgba(122, 92, 166, 0.3);
103-
104-
--cell-border-horizontal: 1px solid var(--gray-700);
105-
--cell-border-vertical: 1px solid var(--gray-700);
106-
107-
--color-fk: rgba(235, 157, 32, 0.15);
108-
--color-fk-border: var(--pumpkin-600);
109-
--color-error: #ff6b6b;
110-
--cell-text-color-processing: var(--gray-300);
111-
--color-array-element: var(--sky-400);
112-
}
113-
11494
--page-padding-x: 2em;
11595
--page-padding-y: 2em;
11696
--page-padding: var(--page-padding-x) var(--page-padding-y);
@@ -154,6 +134,26 @@
154134
text-rendering: optimizeLegibility;
155135
}
156136
137+
body.theme-dark {
138+
--cell-bg-mix-blend-mode: screen;
139+
--cell-bg-color-base: var(--background-color);
140+
--cell-bg-color-error: rgba(255, 107, 107, 0.15);
141+
--cell-bg-color-header: rgba(39, 43, 48, 0.5);
142+
--cell-bg-color-processing: rgba(251, 191, 36, 0.15);
143+
--cell-bg-color-disabled: rgba(39, 43, 48, 0.3);
144+
--cell-bg-color-row-hover: rgba(39, 43, 48, 0.2);
145+
--cell-bg-color-row-selected: rgba(122, 92, 166, 0.3);
146+
147+
--cell-border-horizontal: 1px solid var(--gray-700);
148+
--cell-border-vertical: 1px solid var(--gray-700);
149+
150+
--color-fk: rgba(235, 157, 32, 0.15);
151+
--color-fk-border: var(--pumpkin-600);
152+
--color-error: #ff6b6b;
153+
--cell-text-color-processing: var(--gray-300);
154+
--color-array-element: var(--sky-400);
155+
}
156+
157157
h1 {
158158
margin: 0 0 1.5rem 0;
159159
font-size: var(--size-ultra-large);
@@ -209,7 +209,7 @@
209209
border-radius: 0.2em;
210210
color: var(--text-color);
211211
212-
@media (prefers-color-scheme: dark) {
212+
body.theme-dark & {
213213
background: var(--gray-900);
214214
border: 1px solid var(--gray-700);
215215
}
@@ -246,7 +246,7 @@
246246
color: var(--text-color-muted);
247247
font-weight: bold;
248248
249-
@media (prefers-color-scheme: dark) {
249+
body.theme-dark & {
250250
background: var(--gray-900);
251251
border: 1px solid var(--gray-700);
252252
}

mathesar_ui/src/AppContext.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@
1616
} from '@mathesar/systems/record-selector/RecordSelectorController';
1717
import type { CommonData } from '@mathesar/utils/preloadData';
1818
import { Confirmation, ToastPresenter } from '@mathesar-component-library';
19+
import { initUiTheme } from './utils/uiThemePreference';
1920
2021
export let commonData: CommonData;
2122
23+
if (typeof window !== 'undefined') {
24+
initUiTheme();
25+
}
26+
2227
setBreadcrumbItemsInContext([]);
2328
2429
function setUserProfileAndReleaseStores() {

mathesar_ui/src/component-library/button/Button.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@
124124
}
125125
}
126126

127-
@media (prefers-color-scheme: dark) {
127+
:global(body.theme-dark) & {
128128
&.btn-secondary {
129129
&:not(:disabled) {
130130
&:hover,

mathesar_ui/src/component-library/common/styles/variables.scss

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* File to place common css & scss variables for the component library
33
*/
4-
:root {
4+
body {
55
--background-color: #ffffff;
66
--border-color: var(--sand-300);
77
--header-background: var(--white);
@@ -295,8 +295,7 @@
295295
--collapsible-button-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
296296
}
297297

298-
@media (prefers-color-scheme: dark) {
299-
:root {
298+
body.theme-dark {
300299
--background-color: var(--gray-900);
301300
--border-color: var(--gray-600);
302301
--header-background: var(--gray-800);
@@ -389,4 +388,3 @@
389388
--collapsible-button-text: var(--text-color-primary);
390389
--collapsible-button-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
391390
}
392-
}

mathesar_ui/src/component-library/menu/Menu.scss

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
}
1717

1818
.menu-item {
19-
cursor: pointer;
2019
color: var(--text-color);
2120
display: flex;
2221
flex-grow: 1;
@@ -26,8 +25,14 @@
2625
var(--Menu__padding-x, $padding-x-default);
2726
line-height: 1;
2827

29-
&.menu-item-link {
28+
&.menu-item-link,
29+
&.menu-item-button {
3030
text-decoration: none;
31+
cursor: pointer;
32+
}
33+
&.menu-item-link:not(.disabled):hover,
34+
&.menu-item-button:not(.disabled):hover {
35+
background-color: var(--hover-background);
3136
}
3237
&.menu-item-button {
3338
border-radius: inherit;
@@ -38,13 +43,10 @@
3843
text-align: inherit;
3944
margin: 0;
4045
}
41-
4246
&.danger {
4347
color: var(--danger-color);
4448
}
45-
&:not(.disabled):hover {
46-
background-color: var(--hover-background);
47-
}
49+
4850
&.disabled {
4951
color: var(--text-color-muted);
5052
cursor: not-allowed;

mathesar_ui/src/component-library/menu/MenuItemWrapper.svelte

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
{...$$restProps}
1313
class="menu-item {classes}"
1414
role="menuitem"
15-
on:click
1615
class:disabled
1716
class:danger
1817
>

mathesar_ui/src/components/AppHeader.svelte

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
3434
import Breadcrumb from './breadcrumb/Breadcrumb.svelte';
3535
import { getBreadcrumbItemsFromContext } from './breadcrumb/breadcrumbUtils';
36+
import UiThemeSelect from './UiThemeSelect.svelte';
3637
3738
const commonData = preloadCommonData();
3839
const userProfile = getUserProfileStoreFromContext();
@@ -76,7 +77,7 @@
7677
<DropdownMenu
7778
triggerAppearance="ghost"
7879
size="small"
79-
closeOnInnerClick={true}
80+
closeOnInnerClick={false}
8081
menuStyle="--Menu__padding-x: 0.3em;"
8182
>
8283
<div class="user-switcher" slot="trigger">
@@ -110,6 +111,13 @@
110111
<MenuDivider />
111112
{/if}
112113

114+
<MenuDivider />
115+
<MenuHeading>{$_('theme')}</MenuHeading>
116+
<div class="theme-switcher">
117+
<UiThemeSelect />
118+
</div>
119+
<MenuDivider />
120+
113121
<MenuHeading>{$_('resources')}</MenuHeading>
114122
<LinkMenuItem
115123
icon={iconDocumentation}
@@ -171,6 +179,11 @@
171179
gap: var(--size-x-small);
172180
}
173181
182+
.theme-switcher {
183+
padding: 0.5rem;
184+
margin-top: -0.5rem;
185+
}
186+
174187
.user-switcher {
175188
color: var(--text-color);
176189
border-radius: var(--border-radius-m);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<script lang="ts">
2+
import { Select } from '@mathesar/component-library';
3+
import { uiThemePreference } from '@mathesar/stores/localStorage';
4+
import type { UiTheme } from '@mathesar/utils/uiThemePreference';
5+
import { _ } from 'svelte-i18n';
6+
7+
let options: { id: number; value: UiTheme; label: string }[] = [
8+
{ id: 1, value: 'light', label: $_('theme_light') },
9+
{ id: 2, value: 'dark', label: $_('theme_dark') },
10+
{ id: 3, value: 'system', label: $_('theme_system') },
11+
];
12+
let value = options.find((i) => i.value === $uiThemePreference);
13+
14+
function setUiTheme(event: CustomEvent<(typeof options)[0] | undefined>) {
15+
if (!event.detail) return;
16+
uiThemePreference.set(event.detail.value);
17+
}
18+
</script>
19+
20+
<Select {value} {options} on:change={setUiTheme} triggerAppearance="action" />

mathesar_ui/src/components/abstract-type-control/DbTypeIndicator.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
font-size: var(--text-size-x-small);
2424
font-weight: var(--font-weight-bold);
2525
26-
@media (prefers-color-scheme: dark) {
26+
:global(body.theme-dark) & {
2727
background-color: var(--stormy-800);
2828
border: 1px solid var(--stormy-600);
2929
color: var(--text-color-secondary);

mathesar_ui/src/components/sheet/SheetHeader.svelte

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@
7676
}
7777
}
7878
79-
@media (prefers-color-scheme: dark) {
80-
[data-sheet-element='header-row'] {
81-
border-bottom: 1px solid var(--gray-500);
82-
}
79+
:global(body.theme-dark) [data-sheet-element='header-row'] {
80+
border-bottom: 1px solid var(--gray-500);
8381
}
8482
</style>

mathesar_ui/src/i18n/languages/en/dict.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,10 @@
662662
"thanks_for_feedback": "Thank you for your feedback!",
663663
"the_errors_are_shown_below_for_each_database": "The errors are shown below for each database.",
664664
"the_following_databases_will_be_upgraded": "The following databases will be upgraded:",
665+
"theme": "Theme",
666+
"theme_dark": "Dark",
667+
"theme_light": "Light",
668+
"theme_system": "System",
665669
"this_behavior_is_not_configurable": "This behavior is not configurable.",
666670
"this_will_remove_following_columns": "This will remove the following column(s):",
667671
"this_will_remove_following_transformations": "This will remove the following transformation(s):",

mathesar_ui/src/stores/localStorage.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
import type { UiTheme } from '@mathesar/utils/uiThemePreference';
2+
13
import LocalStorageStore from './LocalStorageStore';
24

35
// prettier-ignore
46
export const LOCAL_STORAGE_KEYS = {
57
releaseData: 'mathesar-release-data',
68

9+
// UI theme
10+
uiThemePreference: 'ui-theme-preference',
11+
712
// Table inspector
813
tableInspectorVisible: 'table-inspector-visible',
914
tableInspectorWidth: 'table-inspector-width',
@@ -89,6 +94,11 @@ export const tableInspectorColumnActionsVisible = new LocalStorageStore({
8994
defaultValue: true,
9095
});
9196

97+
export const uiThemePreference = new LocalStorageStore<UiTheme>({
98+
key: LOCAL_STORAGE_KEYS.uiThemePreference,
99+
defaultValue: 'system',
100+
});
101+
92102
export const dataExplorerLeftSidebarWidth = new LocalStorageStore({
93103
key: LOCAL_STORAGE_KEYS.dataExplorerLeftSidebarWidth,
94104
defaultValue: 400,

mathesar_ui/src/systems/permissions/overview/RoleWithChildren.svelte

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,10 @@
7171
}
7272
}
7373
74-
@media (prefers-color-scheme: dark) {
75-
.role-with-children {
76-
.name {
77-
background: var(--stormy-900);
78-
border-color: var(--stormy-400);
79-
}
74+
:global(body.theme-dark) .role-with-children {
75+
.name {
76+
background: var(--stormy-900);
77+
border-color: var(--stormy-400);
8078
}
8179
}
8280
</style>

mathesar_ui/src/systems/record-selector/RecordSelectorCellWrapper.svelte

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,7 @@
113113
clip-path: inset(0 var(--clip-path-size) var(--clip-path-size) 0);
114114
}
115115
116-
@media (prefers-color-scheme: dark) {
117-
.td {
118-
border-color: var(--gray-700);
119-
}
116+
:global(body.theme-dark) .td {
117+
border-color: var(--gray-700);
120118
}
121119
</style>

mathesar_ui/src/systems/record-selector/RecordSelectorColumnHeaderCell.svelte

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,13 @@
188188
z-index: 1;
189189
}
190190
191-
@media (prefers-color-scheme: dark) {
192-
.column-header-cell :global(.record-selector-input) {
193-
box-shadow: 0 0 0 0.1rem var(--gray-700);
194-
}
191+
:global(body.theme-dark) .column-header-cell :global(.record-selector-input) {
192+
box-shadow: 0 0 0 0.1rem var(--gray-700);
193+
}
194+
195+
:global(body.theme-dark)
195196
.column-header-cell.has-nested-selector-open
196-
:global(.record-selector-input) {
197-
box-shadow: 0 0 0 0.2rem var(--gray-600);
198-
}
197+
:global(.record-selector-input) {
198+
box-shadow: 0 0 0 0.2rem var(--gray-600);
199199
}
200200
</style>

mathesar_ui/src/systems/table-view/constraints/ConstraintCollapseHeader.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
margin-bottom: var(--size-super-ultra-small);
5050
font-weight: var(--font-weight-bold);
5151
52-
@media (prefers-color-scheme: dark) {
52+
:global(body.theme-dark) & {
5353
background-color: var(--stormy-800);
5454
border: 1px solid var(--stormy-600);
5555
color: var(--text-color-secondary);

mathesar_ui/src/systems/table-view/constraints/ForeignKeyConstraintDetails.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
padding: 0.285rem 0.428rem;
8080
font-weight: var(--font-weight-bold);
8181
82-
@media (prefers-color-scheme: dark) {
82+
:global(body.theme-dark) & {
8383
background-color: var(--stormy-800);
8484
border: 1px solid var(--stormy-600);
8585
color: var(--text-color-secondary);

mathesar_ui/src/systems/table-view/link-table/LinkTableForm.svelte

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -414,15 +414,13 @@
414414
line-height: 1.6;
415415
}
416416
417-
@media (prefers-color-scheme: dark) {
418-
.form {
419-
--base-fill: var(--stormy-800);
420-
--base-stroke: var(--stormy-600);
421-
--target-fill: var(--pumpkin-800);
422-
--target-stroke: var(--pumpkin-600);
423-
--mapping-fill: var(--salmon-800);
424-
--mapping-stroke: var(--salmon-600);
425-
}
417+
:global(body.theme-dark) .form {
418+
--base-fill: var(--stormy-800);
419+
--base-stroke: var(--stormy-600);
420+
--target-fill: var(--pumpkin-800);
421+
--target-stroke: var(--pumpkin-600);
422+
--mapping-fill: var(--salmon-800);
423+
--mapping-stroke: var(--salmon-600);
426424
}
427425
428426
.form.self-referential {

mathesar_ui/src/systems/table-view/link-table/LinkTablePill.svelte

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@
4343
border: 1px solid var(--mapping-stroke);
4444
}
4545
46-
@media (prefers-color-scheme: dark) {
47-
.table-pill {
48-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
49-
}
46+
:global(body.theme-dark) .table-pill {
47+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
5048
}
5149
</style>

0 commit comments

Comments
 (0)