diff --git a/assets/icons/brightness.svg b/assets/icons/brightness.svg new file mode 100644 index 0000000..752d895 --- /dev/null +++ b/assets/icons/brightness.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/toggle-left.svg b/assets/icons/toggle-left.svg deleted file mode 100644 index c3048d4..0000000 --- a/assets/icons/toggle-left.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/icons/toggle-right.svg b/assets/icons/toggle-right.svg deleted file mode 100644 index d3edd63..0000000 --- a/assets/icons/toggle-right.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/scss/partials/highlight/dark.scss b/assets/scss/partials/highlight/dark.scss new file mode 100644 index 0000000..00e8942 --- /dev/null +++ b/assets/scss/partials/highlight/dark.scss @@ -0,0 +1,385 @@ +/* +* Style: monokai +* https://xyproto.github.io/splash/docs/monokai.html +*/ + +/* Background */ +.chroma { + color: #f8f8f2; + background-color: #272822 +} + +/* Other */ +.chroma .x {} + +/* Error */ +.chroma .err { + color: #960050; + background-color: #1e0010 +} + +/* LineTableTD */ +.chroma .lntd { + vertical-align: top; + padding: 0; + margin: 0; + border: 0; +} + +/* LineTable */ +.chroma .lntable { + border-spacing: 0; + padding: 0; + margin: 0; + border: 0; + width: auto; + overflow: auto; + display: block; +} + +/* LineHighlight */ +.chroma .hl { + display: block; + width: 100%; + background-color: #ffffcc +} + +/* LineNumbersTable */ +.chroma .lnt { + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #7f7f7f +} + +/* LineNumbers */ +.chroma .ln { + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #7f7f7f +} + +/* Keyword */ +.chroma .k { + color: #66d9ef +} + +/* KeywordConstant */ +.chroma .kc { + color: #66d9ef +} + +/* KeywordDeclaration */ +.chroma .kd { + color: #66d9ef +} + +/* KeywordNamespace */ +.chroma .kn { + color: #f92672 +} + +/* KeywordPseudo */ +.chroma .kp { + color: #66d9ef +} + +/* KeywordReserved */ +.chroma .kr { + color: #66d9ef +} + +/* KeywordType */ +.chroma .kt { + color: #66d9ef +} + +/* Name */ +.chroma .n {} + +/* NameAttribute */ +.chroma .na { + color: #a6e22e +} + +/* NameBuiltin */ +.chroma .nb {} + +/* NameBuiltinPseudo */ +.chroma .bp {} + +/* NameClass */ +.chroma .nc { + color: #a6e22e +} + +/* NameConstant */ +.chroma .no { + color: #66d9ef +} + +/* NameDecorator */ +.chroma .nd { + color: #a6e22e +} + +/* NameEntity */ +.chroma .ni {} + +/* NameException */ +.chroma .ne { + color: #a6e22e +} + +/* NameFunction */ +.chroma .nf { + color: #a6e22e +} + +/* NameFunctionMagic */ +.chroma .fm {} + +/* NameLabel */ +.chroma .nl {} + +/* NameNamespace */ +.chroma .nn {} + +/* NameOther */ +.chroma .nx { + color: #a6e22e +} + +/* NameProperty */ +.chroma .py {} + +/* NameTag */ +.chroma .nt { + color: #f92672 +} + +/* NameVariable */ +.chroma .nv {} + +/* NameVariableClass */ +.chroma .vc {} + +/* NameVariableGlobal */ +.chroma .vg {} + +/* NameVariableInstance */ +.chroma .vi {} + +/* NameVariableMagic */ +.chroma .vm {} + +/* Literal */ +.chroma .l { + color: #ae81ff +} + +/* LiteralDate */ +.chroma .ld { + color: #e6db74 +} + +/* LiteralString */ +.chroma .s { + color: #e6db74 +} + +/* LiteralStringAffix */ +.chroma .sa { + color: #e6db74 +} + +/* LiteralStringBacktick */ +.chroma .sb { + color: #e6db74 +} + +/* LiteralStringChar */ +.chroma .sc { + color: #e6db74 +} + +/* LiteralStringDelimiter */ +.chroma .dl { + color: #e6db74 +} + +/* LiteralStringDoc */ +.chroma .sd { + color: #e6db74 +} + +/* LiteralStringDouble */ +.chroma .s2 { + color: #e6db74 +} + +/* LiteralStringEscape */ +.chroma .se { + color: #ae81ff +} + +/* LiteralStringHeredoc */ +.chroma .sh { + color: #e6db74 +} + +/* LiteralStringInterpol */ +.chroma .si { + color: #e6db74 +} + +/* LiteralStringOther */ +.chroma .sx { + color: #e6db74 +} + +/* LiteralStringRegex */ +.chroma .sr { + color: #e6db74 +} + +/* LiteralStringSingle */ +.chroma .s1 { + color: #e6db74 +} + +/* LiteralStringSymbol */ +.chroma .ss { + color: #e6db74 +} + +/* LiteralNumber */ +.chroma .m { + color: #ae81ff +} + +/* LiteralNumberBin */ +.chroma .mb { + color: #ae81ff +} + +/* LiteralNumberFloat */ +.chroma .mf { + color: #ae81ff +} + +/* LiteralNumberHex */ +.chroma .mh { + color: #ae81ff +} + +/* LiteralNumberInteger */ +.chroma .mi { + color: #ae81ff +} + +/* LiteralNumberIntegerLong */ +.chroma .il { + color: #ae81ff +} + +/* LiteralNumberOct */ +.chroma .mo { + color: #ae81ff +} + +/* Operator */ +.chroma .o { + color: #f92672 +} + +/* OperatorWord */ +.chroma .ow { + color: #f92672 +} + +/* Punctuation */ +.chroma .p {} + +/* Comment */ +.chroma .c { + color: #75715e +} + +/* CommentHashbang */ +.chroma .ch { + color: #75715e +} + +/* CommentMultiline */ +.chroma .cm { + color: #75715e +} + +/* CommentSingle */ +.chroma .c1 { + color: #75715e +} + +/* CommentSpecial */ +.chroma .cs { + color: #75715e +} + +/* CommentPreproc */ +.chroma .cp { + color: #75715e +} + +/* CommentPreprocFile */ +.chroma .cpf { + color: #75715e +} + +/* Generic */ +.chroma .g {} + +/* GenericDeleted */ +.chroma .gd { + color: #f92672 +} + +/* GenericEmph */ +.chroma .ge { + font-style: italic +} + +/* GenericError */ +.chroma .gr {} + +/* GenericHeading */ +.chroma .gh {} + +/* GenericInserted */ +.chroma .gi { + color: #a6e22e +} + +/* GenericOutput */ +.chroma .go {} + +/* GenericPrompt */ +.chroma .gp {} + +/* GenericStrong */ +.chroma .gs { + font-weight: bold +} + +/* GenericSubheading */ +.chroma .gu { + color: #75715e +} + +/* GenericTraceback */ +.chroma .gt {} + +/* GenericUnderline */ +.chroma .gl {} + +/* TextWhitespace */ +.chroma .w {} \ No newline at end of file diff --git a/assets/scss/partials/highlight/light.scss b/assets/scss/partials/highlight/light.scss new file mode 100644 index 0000000..7ac7d71 --- /dev/null +++ b/assets/scss/partials/highlight/light.scss @@ -0,0 +1,407 @@ +/* +* Style: monokailight +* https://xyproto.github.io/splash/docs/monokailight.html +*/ + +/* Background */ +.chroma { + color: #272822; + background-color: #fafafa; +} + +/* Other */ +.chroma .x {} + +/* Error */ +.chroma .err { + color: #960050; + background-color: #1e0010 +} + +/* LineTableTD */ +.chroma .lntd { + vertical-align: top; + padding: 0; + margin: 0; + border: 0; +} + +/* LineTable */ +.chroma .lntable { + border-spacing: 0; + padding: 0; + margin: 0; + border: 0; + width: auto; + overflow: auto; + display: block; +} + +/* LineHighlight */ +.chroma .hl { + display: block; + width: 100%; + background-color: #ffffcc +} + +/* LineNumbersTable */ +.chroma .lnt { + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #7f7f7f +} + +/* LineNumbers */ +.chroma .ln { + margin-right: 0.4em; + padding: 0 0.4em 0 0.4em; + color: #7f7f7f +} + +/* Keyword */ +.chroma .k { + color: #00a8c8 +} + +/* KeywordConstant */ +.chroma .kc { + color: #00a8c8 +} + +/* KeywordDeclaration */ +.chroma .kd { + color: #00a8c8 +} + +/* KeywordNamespace */ +.chroma .kn { + color: #f92672 +} + +/* KeywordPseudo */ +.chroma .kp { + color: #00a8c8 +} + +/* KeywordReserved */ +.chroma .kr { + color: #00a8c8 +} + +/* KeywordType */ +.chroma .kt { + color: #00a8c8 +} + +/* Name */ +.chroma .n { + color: #111111 +} + +/* NameAttribute */ +.chroma .na { + color: #75af00 +} + +/* NameBuiltin */ +.chroma .nb { + color: #111111 +} + +/* NameBuiltinPseudo */ +.chroma .bp { + color: #111111 +} + +/* NameClass */ +.chroma .nc { + color: #75af00 +} + +/* NameConstant */ +.chroma .no { + color: #00a8c8 +} + +/* NameDecorator */ +.chroma .nd { + color: #75af00 +} + +/* NameEntity */ +.chroma .ni { + color: #111111 +} + +/* NameException */ +.chroma .ne { + color: #75af00 +} + +/* NameFunction */ +.chroma .nf { + color: #75af00 +} + +/* NameFunctionMagic */ +.chroma .fm { + color: #111111 +} + +/* NameLabel */ +.chroma .nl { + color: #111111 +} + +/* NameNamespace */ +.chroma .nn { + color: #111111 +} + +/* NameOther */ +.chroma .nx { + color: #75af00 +} + +/* NameProperty */ +.chroma .py { + color: #111111 +} + +/* NameTag */ +.chroma .nt { + color: #f92672 +} + +/* NameVariable */ +.chroma .nv { + color: #111111 +} + +/* NameVariableClass */ +.chroma .vc { + color: #111111 +} + +/* NameVariableGlobal */ +.chroma .vg { + color: #111111 +} + +/* NameVariableInstance */ +.chroma .vi { + color: #111111 +} + +/* NameVariableMagic */ +.chroma .vm { + color: #111111 +} + +/* Literal */ +.chroma .l { + color: #ae81ff +} + +/* LiteralDate */ +.chroma .ld { + color: #d88200 +} + +/* LiteralString */ +.chroma .s { + color: #d88200 +} + +/* LiteralStringAffix */ +.chroma .sa { + color: #d88200 +} + +/* LiteralStringBacktick */ +.chroma .sb { + color: #d88200 +} + +/* LiteralStringChar */ +.chroma .sc { + color: #d88200 +} + +/* LiteralStringDelimiter */ +.chroma .dl { + color: #d88200 +} + +/* LiteralStringDoc */ +.chroma .sd { + color: #d88200 +} + +/* LiteralStringDouble */ +.chroma .s2 { + color: #d88200 +} + +/* LiteralStringEscape */ +.chroma .se { + color: #8045ff +} + +/* LiteralStringHeredoc */ +.chroma .sh { + color: #d88200 +} + +/* LiteralStringInterpol */ +.chroma .si { + color: #d88200 +} + +/* LiteralStringOther */ +.chroma .sx { + color: #d88200 +} + +/* LiteralStringRegex */ +.chroma .sr { + color: #d88200 +} + +/* LiteralStringSingle */ +.chroma .s1 { + color: #d88200 +} + +/* LiteralStringSymbol */ +.chroma .ss { + color: #d88200 +} + +/* LiteralNumber */ +.chroma .m { + color: #ae81ff +} + +/* LiteralNumberBin */ +.chroma .mb { + color: #ae81ff +} + +/* LiteralNumberFloat */ +.chroma .mf { + color: #ae81ff +} + +/* LiteralNumberHex */ +.chroma .mh { + color: #ae81ff +} + +/* LiteralNumberInteger */ +.chroma .mi { + color: #ae81ff +} + +/* LiteralNumberIntegerLong */ +.chroma .il { + color: #ae81ff +} + +/* LiteralNumberOct */ +.chroma .mo { + color: #ae81ff +} + +/* Operator */ +.chroma .o { + color: #f92672 +} + +/* OperatorWord */ +.chroma .ow { + color: #f92672 +} + +/* Punctuation */ +.chroma .p { + color: #111111 +} + +/* Comment */ +.chroma .c { + color: #75715e +} + +/* CommentHashbang */ +.chroma .ch { + color: #75715e +} + +/* CommentMultiline */ +.chroma .cm { + color: #75715e +} + +/* CommentSingle */ +.chroma .c1 { + color: #75715e +} + +/* CommentSpecial */ +.chroma .cs { + color: #75715e +} + +/* CommentPreproc */ +.chroma .cp { + color: #75715e +} + +/* CommentPreprocFile */ +.chroma .cpf { + color: #75715e +} + +/* Generic */ +.chroma .g {} + +/* GenericDeleted */ +.chroma .gd {} + +/* GenericEmph */ +.chroma .ge { + font-style: italic +} + +/* GenericError */ +.chroma .gr {} + +/* GenericHeading */ +.chroma .gh {} + +/* GenericInserted */ +.chroma .gi {} + +/* GenericOutput */ +.chroma .go {} + +/* GenericPrompt */ +.chroma .gp {} + +/* GenericStrong */ +.chroma .gs { + font-weight: bold +} + +/* GenericSubheading */ +.chroma .gu {} + +/* GenericTraceback */ +.chroma .gt {} + +/* GenericUnderline */ +.chroma .gl {} + +/* TextWhitespace */ +.chroma .w {} \ No newline at end of file diff --git a/assets/scss/partials/menu.scss b/assets/scss/partials/menu.scss index 7cb7e83..a5a8e73 100644 --- a/assets/scss/partials/menu.scss +++ b/assets/scss/partials/menu.scss @@ -207,29 +207,29 @@ } } -.theme-dark { - #dark-mode-toggle { +[data-scheme="dark"] { + #schemeSelectItem { color: var(--accent-color); font-weight: 700; - - .icon-tabler-toggle-left { - display: none; - } - - .icon-tabler-toggle-right { - display: unset; - } } } -#dark-mode-toggle { +#schemeSelectItem { margin-top: auto; color: var(--body-text-color); display: flex; align-items: center; - cursor: pointer; +} - .icon-tabler-toggle-right { - display: none; +#schemeSelect { + background: transparent; + border: 0; + color: var(--body-text-color); + padding: 0; + appearance: none; + + option { + color: var(--card-text-color-main); + background-color: var(--card-background); } } diff --git a/assets/scss/variables.scss b/assets/scss/variables.scss index 3e886fb..862cf8f 100644 --- a/assets/scss/variables.scss +++ b/assets/scss/variables.scss @@ -1,6 +1,18 @@ $defaultTagBackgrounds: #8ea885, #df7988, #0177b8, #ffb900, #6b69d6; $defaultTagColors: #fff, #fff, #fff, #fff, #fff; +[data-scheme="light"]{ + --pre-text-color: #272822; + --pre-background-color: #fafafa; + @import "partials/highlight/light.scss"; +} + +[data-scheme="dark"]{ + --pre-text-color: #f8f8f2; + --pre-background-color: #272822; + @import "partials/highlight/dark.scss"; +} + /* * Global style */ @@ -20,7 +32,7 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff; --section-separation: 40px; - .theme-dark { + [data-scheme="dark"] { --body-background: #303030; --accent-color: #ecf0f1; --accent-color-darker: #bdc3c7; @@ -64,7 +76,7 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff; --small-card-padding: 25px; - .theme-dark { + [data-scheme="dark"] { --card-background: #424242; --card-background-selected: rgba(255, 255, 255, 0.16); --card-text-color-main: rgba(255, 255, 255, 0.9); @@ -108,7 +120,7 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff; --table-border-color: #dadada; --tr-even-background-color: #efefee; - .theme-dark { + [data-scheme="dark"] { --code-background-color: #272822; --code-text-color: rgba(255, 255, 255, 0.9); diff --git a/assets/ts/darkmode.ts b/assets/ts/darkmode.ts index 00ccfe5..2b0db49 100644 --- a/assets/ts/darkmode.ts +++ b/assets/ts/darkmode.ts @@ -1,58 +1,68 @@ -export default () => { - const toggleDarkMode = document.getElementById('dark-mode-toggle'); - const darkModeKey = 'StackDarkMode'; - const darkModeItem = localStorage.getItem(darkModeKey); - const darkModeEnabled = localStorage.getItem(darkModeKey) === 'true'; - const supportDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches === true; - const mql = window.matchMedia('(prefers-color-scheme: dark)'); +type colorScheme = 'light' | 'dark' | 'auto'; - let darkMode = false; +const colorSchemeKey = 'StackColorScheme'; +const mql = window.matchMedia('(prefers-color-scheme: dark)'); +const schemeSelect = document.getElementById('schemeSelect') as HTMLSelectElement; - if (darkModeItem && darkModeEnabled || !darkModeItem && supportDarkMode) { - /** - * Enable dark mode if: - * 1. If dark mode is set already (in local storage) - * 2. No color scheme preference is set in localstorage, and user's browser indicates preference for dark mode - */ - darkMode = true; - } +const supportDarkMode = () => { + return window.matchMedia('(prefers-color-scheme: dark)').matches === true; +} - const setBodyClass = () => { - if (darkMode) { - document.body.classList.add('theme-dark'); +const saveScheme = (scheme: colorScheme) => { + localStorage.setItem(colorSchemeKey, scheme); +} + +const getScheme = () => { + return localStorage.getItem(colorSchemeKey) as colorScheme; +}; + +const setScheme = (scheme: colorScheme) => { + if (scheme === 'auto') { + if (supportDarkMode()) { + document.body.dataset.scheme = 'dark'; } else { - document.body.classList.remove('theme-dark'); + document.body.dataset.scheme = 'light'; } } - - const mediaQueryListener = (e) => { - darkMode = e.matches; - setBodyClass(); - } - - let listening = false; - if (!darkModeItem) { - /** - * If no dark mode preference is set in local storage, listen to browser color preference change - */ - mql.addEventListener('change', mediaQueryListener); - listening = true; + else { + document.body.dataset.scheme = scheme; } +} +const mediaQueryListener = (e) => { + setScheme('auto'); +} + +export default () => { document.body.style.setProperty('transition', 'background-color .3s ease'); - toggleDarkMode.addEventListener('click', (e) => { - darkMode = !darkMode; - setBodyClass(); - localStorage.setItem(darkModeKey, darkMode.toString()); + if (!getScheme()) { + /// First time visiting + setScheme('auto'); + saveScheme('auto') + mql.addEventListener('change', mediaQueryListener); + } + else { + setScheme(getScheme()); + } - if (listening) { + schemeSelect.value = getScheme(); + + schemeSelect.addEventListener('change', (e) => { + const value = schemeSelect.value as colorScheme; + + setScheme(value); + saveScheme(value); + + if (value === 'auto') { + mql.addEventListener('change', mediaQueryListener); + } + else { /** * Remove listener once user set color preference in website */ mql.removeEventListener('change', mediaQueryListener); - listening = false; } }) } \ No newline at end of file diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index 21cdb4e..f1a5900 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -4,13 +4,19 @@ diff --git a/layouts/partials/footer/components/highlight.html b/layouts/partials/footer/components/highlight.html deleted file mode 100644 index d428695..0000000 --- a/layouts/partials/footer/components/highlight.html +++ /dev/null @@ -1,4 +0,0 @@ -{{- $light := resources.Get "css/highlight/light.css" | minify -}} -{{- $dark := resources.Get "css/highlight/dark.css" | minify -}} - - \ No newline at end of file diff --git a/layouts/partials/footer/include.html b/layouts/partials/footer/include.html index ffa7573..4b50a88 100644 --- a/layouts/partials/footer/include.html +++ b/layouts/partials/footer/include.html @@ -1,4 +1,3 @@ {{ partialCached "footer/components/script.html" . }} {{ partialCached "footer/components/custom-font.html" . }} -{{ partialCached "footer/components/highlight.html" . }} {{ partial "footer/custom.html" . }} \ No newline at end of file diff --git a/layouts/partials/sidebar/left.html b/layouts/partials/sidebar/left.html index c525031..c1b135c 100644 --- a/layouts/partials/sidebar/left.html +++ b/layouts/partials/sidebar/left.html @@ -40,10 +40,14 @@ {{ end }} -
  • - {{ (resources.Get "icons/toggle-left.svg").Content | safeHTML }} - {{ (resources.Get "icons/toggle-right.svg").Content | safeHTML }} - {{ T "darkModeToggle" }} +
  • + {{ (resources.Get "icons/brightness.svg").Content | safeHTML }} + +
  • \ No newline at end of file