Skip to content

Commit 59ec5cc

Browse files
committed
refactor theme and mode in progress
1 parent 9733bed commit 59ec5cc

File tree

11 files changed

+141
-71
lines changed

11 files changed

+141
-71
lines changed

docs/working-notes/todo3.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,5 +505,8 @@ a href open in new tab
505505
fix links page links color for history back view transition
506506

507507
refactor theme script, osDefaultMode, appDefaultMode, storedMode
508+
change meta theme bg color with js, astro-paper
509+
510+
replace import config with import.meta.env.VAR
508511
------------
509512
```

src/components/Giscus.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ const { class: className } = Astro.props;
3434
import 'giscus';
3535

3636
import { SELECTORS } from '@/constants/dom';
37-
import { THEME_CONFIG } from '@/constants/themes';
38-
import { getCurrentMode, sendModeToGiscus } from '@/utils/dom';
37+
import { THEME_CONFIG } from '@/constants/theme';
38+
import { getCurrentMode, sendModeToGiscus } from '@/utils/theme';
3939

4040
import type { ChangeThemeCustomEvent } from '@/types/constants';
4141

src/components/ThemeScript.astro

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,56 @@
11
---
2-
import * as themeConstants from '@/constants/themes';
2+
import * as themeConstants from '@/constants/theme';
3+
import { getDefaultThemes } from '@/utils/theme';
4+
5+
const defaultThemes = getDefaultThemes();
36
---
47

58
{/* Inlined to avoid flash of white content. */}
6-
<script is:inline define:vars={{ themeConstants }}>
9+
<script is:inline define:vars={{ themeConstants, defaultThemes }}>
10+
// this is JavaScript, not TypeScript
711
const { MODES, THEMES, THEME_CONFIG } = themeConstants;
812
const { DATA_ATTRIBUTE, CHANGE_EVENT, LOCAL_STORAGE_KEY } = THEME_CONFIG;
913

10-
// this is JavaScript, not TypeScript
11-
const defaultThemes = { light: THEMES[0], dark: THEMES[1] };
14+
const darkModePreference = window.matchMedia('(prefers-color-scheme: dark)');
1215

13-
const lightModePreference = window.matchMedia('(prefers-color-scheme: light)');
16+
// 1. stored mode
17+
// 2. default app mode, config
18+
// 3. OS mode
1419

1520
// light is default
1621
const getMode = (themeMode) => (themeMode === MODES.dark ? MODES.dark : MODES.light);
1722

1823
const getDefaultTheme = (themeMode) => defaultThemes[getMode(themeMode)];
1924

20-
const changeThemeMode = (themeMode) => {
21-
const storedTheme = getTheme();
25+
const setMode = (themeMode) => {
26+
const storedTheme = getStoredTheme();
2227

2328
if (!storedTheme) return getDefaultTheme(themeMode);
2429

2530
const newTheme = { ...storedTheme, mode: getMode(themeMode) };
2631
return newTheme;
2732
};
2833

29-
const getUserPreference = () => {
34+
const getOSMode = () => (darkModePreference.matches ? MODES.dark : MODES.light);
35+
36+
const getOSTheme = () => {
37+
const themeMode = getOSMode();
38+
const defaultOSTheme = getDefaultTheme(themeMode);
39+
40+
return defaultOSTheme;
41+
};
42+
43+
const getTheme = () => {
3044
// either from storage
31-
const storedTheme = getTheme();
45+
const storedTheme = getStoredTheme();
3246
if (storedTheme) return storedTheme;
3347

34-
// or fallback to browser default
35-
const preferedMode = lightModePreference.matches ? MODES.light : MODES.dark;
36-
const defaultTheme = getDefaultTheme(preferedMode);
37-
return defaultTheme;
48+
// or fallback to default theme for OS mode
49+
const defaultOSTheme = getOSTheme();
50+
return defaultOSTheme;
3851
};
3952

40-
const getTheme = () => {
53+
const getStoredTheme = () => {
4154
const storedThemeString =
4255
typeof localStorage !== 'undefined' && localStorage.getItem(LOCAL_STORAGE_KEY);
4356

@@ -46,7 +59,7 @@ import * as themeConstants from '@/constants/themes';
4659
let storedTheme;
4760
try {
4861
storedTheme = JSON.parse(storedThemeString);
49-
} catch (error) {
62+
} catch (_error) {
5063
localStorage.removeItem(LOCAL_STORAGE_KEY);
5164
return null;
5265
}
@@ -100,21 +113,20 @@ import * as themeConstants from '@/constants/themes';
100113
};
101114

102115
// initial setup
103-
setTheme(getUserPreference());
116+
setTheme(getTheme());
104117

105-
// fails in firefox
106118
// View Transitions hook to restore theme
107-
document.addEventListener('astro:after-swap', () => setTheme(getUserPreference()));
119+
document.addEventListener('astro:after-swap', () => setTheme(getTheme()));
108120

109121
// listen for theme-change custom event, fired in src/components/ThemeToggle.astro
110122
document.addEventListener(CHANGE_EVENT, (event) => {
111123
setTheme(event.detail.theme);
112124
});
113125

114-
// listen for prefers-color-scheme change.
115-
lightModePreference.addEventListener('change', (event) => {
116-
const newMode = event.matches ? MODES.light : MODES.dark;
117-
const newTheme = changeThemeMode(newMode);
126+
// listen for prefers-color-scheme change
127+
darkModePreference.addEventListener('change', (event) => {
128+
const newMode = event.matches ? MODES.dark : MODES.light;
129+
const newTheme = setMode(newMode);
118130
setTheme(newTheme);
119131
});
120132
</script>

src/components/ThemeToggle.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { Icon } from 'astro-icon/components';
1010
</theme-toggle>
1111

1212
<script>
13-
import { THEME_CONFIG } from '@/constants/themes';
14-
import { getNextTheme } from '@/utils/dom';
13+
import { THEME_CONFIG } from '@/constants/theme';
14+
import { getNextTheme } from '@/utils/theme';
1515

1616
import type { ChangeThemeCustomEvent } from '@/types/constants';
1717

src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ const configData: ConfigType = {
3535
PAGE_SIZE_POST_CARD: 3,
3636
PAGE_SIZE_POST_CARD_SMALL: 6,
3737
MORE_POSTS_COUNT: 3,
38+
DEFAULT_MODE: 'light',
39+
DEFAULT_THEME: 'default-light',
3840
AUTHOR_NAME: 'Nemanja Mitic',
3941
AUTHOR_EMAIL: '[email protected]',
4042
AUTHOR_GITHUB: 'https://github.com/nemanjam',

src/constants/themes.ts renamed to src/constants/theme.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
export const MODES = {
22
dark: 'dark',
33
light: 'light',
4+
// add auto
45
} as const;
56

6-
export const DEFAULT_THEMES = {
7-
light: {
7+
export const THEMES = [
8+
{
89
mode: MODES.light,
910
name: 'default-light',
1011
},
11-
dark: {
12+
{
1213
mode: MODES.dark,
1314
name: 'default-dark',
1415
},
15-
} as const;
16-
17-
export const THEMES = [
18-
DEFAULT_THEMES.light,
19-
DEFAULT_THEMES.dark,
2016
{
2117
mode: MODES.light,
2218
name: 'green-light',

src/pages/links.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ const { GITHUB_MARKDOWN_BODY_ID } = SELECTORS;
4747

4848
<script>
4949
import { SELECTORS } from '@/constants/dom';
50-
import { MODES, THEME_CONFIG } from '@/constants/themes';
51-
import { getCurrentMode } from '@/utils/dom';
50+
import { MODES, THEME_CONFIG } from '@/constants/theme';
51+
import { getCurrentMode } from '@/utils/theme';
5252

5353
import type { ChangeThemeCustomEvent, Mode } from '@/types/constants';
5454

src/schemas/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { z } from 'zod';
33
export const nodeEnvValues = ['development', 'test', 'production'] as const;
44
export const booleanValues = ['true', 'false', ''] as const;
55

6+
export const modeValues = ['light', 'dark'] as const;
7+
export const themeValues = ['default-light', 'default-dark', 'green-light', 'green-dark'] as const;
8+
69
export const configSchema = z.object({
710
NODE_ENV: z.enum(nodeEnvValues),
811
PREVIEW_MODE: z
@@ -16,6 +19,8 @@ export const configSchema = z.object({
1619
PAGE_SIZE_POST_CARD: z.number(),
1720
PAGE_SIZE_POST_CARD_SMALL: z.number(),
1821
MORE_POSTS_COUNT: z.number(),
22+
DEFAULT_MODE: z.enum(modeValues), // check that theme and mode match
23+
DEFAULT_THEME: z.enum(themeValues),
1924
AUTHOR_NAME: z.string().min(1),
2025
AUTHOR_EMAIL: z.string().email(),
2126
AUTHOR_GITHUB: z.string().url(),

src/types/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { CATEGORIES } from '@/constants/collections';
22
import type { PAGE_METADATA } from '@/constants/metadata';
33
import type { NAVIGATION_ITEMS } from '@/constants/navigation';
4-
import type { MODES, THEMES } from '@/constants/themes';
4+
import type { MODES, THEMES } from '@/constants/theme';
55
import type { ValueUnion } from '@/types/utils';
66
import type { LocalImageProps } from 'astro:assets';
77

src/utils/dom.ts

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,6 @@
11
import { SELECTORS } from '@/constants/dom';
2-
import { DEFAULT_THEMES, MODES, THEME_CONFIG, THEMES } from '@/constants/themes';
32

4-
import type { Mode, Theme } from '@/types/constants';
5-
6-
const { MODE_CLASS, DATA_ATTRIBUTE } = THEME_CONFIG;
7-
8-
export const getCurrentMode = () =>
9-
document.documentElement.classList.contains(MODE_CLASS) ? MODES.dark : MODES.light;
10-
11-
export const getCurrentTheme = () => {
12-
const themeName = document.documentElement.getAttribute(DATA_ATTRIBUTE);
13-
const isValidThemeName =
14-
Boolean(themeName) && THEMES.map((theme) => theme.name).includes(themeName as Theme['name']);
15-
16-
if (!isValidThemeName) return null;
17-
18-
const currentTheme = THEMES.find((theme) => theme.name === themeName) as Theme;
19-
return currentTheme;
20-
};
21-
22-
export const getNextTheme = () => {
23-
const currentTheme = getCurrentTheme();
24-
25-
const currentIndex = THEMES.findIndex(
26-
(theme) => currentTheme && currentTheme.name === theme.name
27-
);
28-
29-
if (currentIndex === -1) {
30-
const currentMode = getCurrentMode();
31-
return DEFAULT_THEMES[currentMode];
32-
}
33-
34-
const nextIndex = (currentIndex + 1) % THEMES.length;
35-
return THEMES[nextIndex];
36-
};
3+
import type { Mode } from '@/types/constants';
374

385
/*-------------------------------- giscus dark/light mode ------------------------------*/
396

0 commit comments

Comments
 (0)