moved theme-detector to public folder

This commit is contained in:
Sergey Yarkov 2022-07-28 00:05:02 +03:00
parent 75fa8117f6
commit b0d7490ecb
12 changed files with 35 additions and 38 deletions

View File

@ -9,9 +9,9 @@ Personal website created with Astro.
- [x] HTML layout - [x] HTML layout
- [x] Adaptive & Responsive layout - [x] Adaptive & Responsive layout
- [ ] Dark/Light Theme - [x] Search articles by title or description
- [x] Dark/Light Theme
- [ ] Multilang web-site - [ ] Multilang web-site
- [ ] Search articles by title or description
- [ ] Form handling via Netlify Forms - [ ] Form handling via Netlify Forms
- [ ] SEO optimized - [ ] SEO optimized

View File

@ -12,7 +12,7 @@
"scripts": { "scripts": {
"dev": "astro dev --host", "dev": "astro dev --host",
"start": "astro dev", "start": "astro dev",
"build": "astro check && tsc --noEmit && astro build", "build": "astro build",
"preview": "astro preview --host", "preview": "astro preview --host",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json}\"", "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json}\"",
"lint": "eslint '**/*.{js,mjs,ts,tsx}'" "lint": "eslint '**/*.{js,mjs,ts,tsx}'"

View File

@ -0,0 +1,23 @@
/**
* This script is used to determine the theme of the site.
* The theme value is taken from localstorage, otherwise from the operating system.
* It is very important to include this script before loading the CSS
* and body markup to prevent FOUC (Flash of unstyled content).
*/
const getTheme = () => {
const local = localStorage.getItem('theme');
if (local && (local === 'dark' || local === 'light')) return local;
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
return isDark ? 'dark' : 'light';
};
window.theme = getTheme();
document.documentElement.setAttribute('data-theme', window.theme);
/* Sync with OS theme */
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({ matches: isDark }) => {
window.theme = isDark ? 'dark' : 'light';
localStorage.setItem('theme', window.theme);
document.documentElement.setAttribute('data-theme', window.theme);
});

View File

@ -1,6 +1,5 @@
--- ---
import { SITE_METADATA } from '@root/config'; import { SITE_METADATA } from '@root/config';
import { DetectThemeScript } from '@root/scripts';
export interface Props { export interface Props {
title?: string | undefined; title?: string | undefined;
@ -13,8 +12,6 @@ const { title = SITE_METADATA.title, description } = Astro.props as Props;
<link rel='preconnect' href='https://fonts.googleapis.com' /> <link rel='preconnect' href='https://fonts.googleapis.com' />
<link rel='preconnect' href='https://fonts.gstatic.com' crossorigin /> <link rel='preconnect' href='https://fonts.gstatic.com' crossorigin />
<link href='https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap' rel='stylesheet' /> <link href='https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap' rel='stylesheet' />
<!-- <link rel='stylesheet' href='assets/dark.css' media='(prefers-color-scheme: dark)' /> -->
<!-- <link rel='stylesheet' href='assets/light.css' media='(prefers-color-scheme: light)' /> -->
<meta charset='utf-8' /> <meta charset='utf-8' />
<meta name='viewport' content='width=device-width, initial-scale=1' /> <meta name='viewport' content='width=device-width, initial-scale=1' />
@ -23,7 +20,7 @@ const { title = SITE_METADATA.title, description } = Astro.props as Props;
</title> </title>
<meta name='title' content={title} /> <meta name='title' content={title} />
<meta name='description' content={description || SITE_METADATA.description} /> <meta name='description' content={description || SITE_METADATA.description} />
<script is:inline src='assets/js/detect-theme.js'>
<!-- This script will prevent FOUC --> </script>
<DetectThemeScript />
<slot></slot> <slot></slot>

View File

@ -38,7 +38,7 @@ const { pathname } = Astro.canonicalURL;
<Icon name='telegram' width='18' height='18' /> <Icon name='telegram' width='18' height='18' />
</a> </a>
</div> </div>
<ThemeSwitcher client:load /> <ThemeSwitcher client:visible />
</nav> </nav>
<NavToggle client:visible /> <NavToggle client:visible />
</div> </div>

View File

@ -26,7 +26,9 @@ const ThemeSwitcher: Component = () => {
const [theme, setTheme] = createSignal<ThemeModeType>(SITE_SETTINGS.defaultTheme); const [theme, setTheme] = createSignal<ThemeModeType>(SITE_SETTINGS.defaultTheme);
const [isReady, setIsReady] = createSignal<boolean>(false); const [isReady, setIsReady] = createSignal<boolean>(false);
const toggleTheme: JSX.EventHandler<HTMLButtonElement, MouseEvent> = (e) => { const toggleTheme: JSX.EventHandler<HTMLButtonElement, MouseEvent> = () => {
if (!window.theme) return;
const newTheme = theme() === 'light' ? 'dark' : 'light'; const newTheme = theme() === 'light' ? 'dark' : 'light';
setTheme(newTheme); setTheme(newTheme);
localStorage.setItem('theme', newTheme); localStorage.setItem('theme', newTheme);
@ -46,7 +48,7 @@ const ThemeSwitcher: Component = () => {
}); });
return ( return (
<button onClick={toggleTheme} class={isReady() ? 'theme-switcher ready' : 'theme-switcher'}> <button onClick={toggleTheme} class={isReady() ? 'theme-switcher ready' : 'theme-switcher'} aria-label={theme()}>
<Switch <Switch
children={ children={
<> <>

View File

@ -18,8 +18,8 @@ const { lang = 'ru', content } = Astro.props as Props;
<html lang={lang}> <html lang={lang}>
<head> <head>
<BaseHead title={content.title}> <BaseHead title={content.title}>
<link rel='stylesheet' href='assets/prism-one-dark.min.css' media='(prefers-color-scheme: dark)' /> <link rel='stylesheet' href='assets/css/prism-one-dark.min.css' media='(prefers-color-scheme: dark)' />
<link rel='stylesheet' href='assets/prism-one-light.min.css' media='(prefers-color-scheme: light)' /> <link rel='stylesheet' href='assets/css/prism-one-light.min.css' media='(prefers-color-scheme: light)' />
</BaseHead> </BaseHead>
</head> </head>

View File

@ -1,20 +0,0 @@
<script is:inline>
const THEME_STORAGE_KEY = 'theme';
const getTheme = () => {
const local = localStorage.getItem(THEME_STORAGE_KEY);
if (local && (local === 'dark' || local === 'light')) return local;
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
return isDark ? 'dark' : 'light';
};
window.theme = getTheme();
document.documentElement.setAttribute('data-theme', theme);
/* Sync with OS theme */
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ({ matches: isDark }) => {
window.theme = isDark ? 'dark' : 'light';
localStorage.setItem(THEME_STORAGE_KEY, theme);
document.documentElement.setAttribute('data-theme', theme);
});
</script>

View File

@ -1 +0,0 @@
export { default as DetectThemeScript } from './detect-theme.astro';

4
src/types/main.d.ts vendored
View File

@ -32,8 +32,4 @@ declare global {
}; };
type ThemeModeType = 'light' | 'dark'; type ThemeModeType = 'light' | 'dark';
type SiteConfigType = {
defaultTheme: ThemeModeType;
};
} }