diff --git a/package.json b/package.json index 2d68ed7..77ab71e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,8 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", - "preview": "vite preview" + "preview": "vite preview", + "colortheme":"esbuild static/colortheme/colortheme.ts --bundle --minify --sourcemap --outdir=static/colortheme/" }, "dependencies": { "@codemirror/autocomplete": "^6.1.0", diff --git a/static/colortheme/README.md b/static/colortheme/README.md new file mode 100644 index 0000000..88b09c6 --- /dev/null +++ b/static/colortheme/README.md @@ -0,0 +1,5 @@ +It would be nice if colortheme.ts could be a part of the regular bundle. +But it needs to load as early as possible and blocking to avoid having white flashes in the dark theme. +Even using it in a seperate module that is loaded in the header doesn't work as modules are always deferred. + +That's why it is built to a separate JS file by esbuild and hardcoded into the header. diff --git a/static/colortheme/colortheme.js b/static/colortheme/colortheme.js new file mode 100644 index 0000000..93ed036 --- /dev/null +++ b/static/colortheme/colortheme.js @@ -0,0 +1,7 @@ +"use strict";(()=>{var o="(prefers-color-scheme: dark)",s=()=>localStorage.getItem("theme"),m=e=>localStorage.setItem("theme",e),i=()=>{let e=s();return e||(window.matchMedia(o).matches?"dark":"light")},n=e=>{e==="auto"&&window.matchMedia(o).matches?document.documentElement.setAttribute("data-bs-theme","dark"):document.documentElement.setAttribute("data-bs-theme",e)};n(i());var c=(e,a=!1)=>{let t=document.getElementById("navbar-main-dropdown");if(!t)return;let r=document.querySelector(`[data-bs-theme-value="${e}"]`);r&&(console.log(r),document.querySelectorAll("[data-bs-theme-value]").forEach(d=>{d.classList.remove("active"),d.setAttribute("aria-pressed","false")}),r.classList.add("active"),r.setAttribute("aria-pressed","true"),a&&t.focus())};window.matchMedia(o).addEventListener("change",()=>{let e=s();e!=="light"&&e!=="dark"&&n(i())});window.addEventListener("DOMContentLoaded",()=>{let e=s();e||(e="auto"),c(e),document.querySelectorAll("[data-bs-theme-value]").forEach(a=>{a.addEventListener("click",()=>{let t=a.getAttribute("data-bs-theme-value");m(t),n(t),c(t,!0)})})});})(); +/*! + * Color mode toggler based on Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + */ +//# sourceMappingURL=colortheme.js.map diff --git a/static/colortheme/colortheme.js.map b/static/colortheme/colortheme.js.map new file mode 100644 index 0000000..98b37bf --- /dev/null +++ b/static/colortheme/colortheme.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["colortheme.ts"], + "sourcesContent": ["/*!\n * Color mode toggler based on Bootstrap's docs (https://getbootstrap.com/)\n * Copyright 2011-2023 The Bootstrap Authors\n * Licensed under the Creative Commons Attribution 3.0 Unported License.\n */\n\nconst darkQuery='(prefers-color-scheme: dark)'\n\nconst getStoredTheme = () => localStorage.getItem('theme')\nconst setStoredTheme = (theme: string) => localStorage.setItem('theme', theme)\n\nconst getPreferredTheme = () => {\n const storedTheme = getStoredTheme()\n if (storedTheme) {\n return storedTheme\n }\n\n return window.matchMedia(darkQuery).matches ? 'dark' : 'light'\n}\n\nconst setTheme = (theme: string) => {\n if (theme === 'auto' && window.matchMedia(darkQuery).matches) {\n document.documentElement.setAttribute('data-bs-theme', 'dark')\n } else {\n document.documentElement.setAttribute('data-bs-theme', theme)\n }\n}\n\nsetTheme(getPreferredTheme())\n\nconst showActiveTheme = (theme: string, focus: boolean = false) => {\n const themeSwitcher = document.getElementById(\"navbar-main-dropdown\")\n if (!themeSwitcher) {\n return\n }\n\n const btnToActive = document.querySelector(`[data-bs-theme-value=\"${theme}\"]`)\n if (!btnToActive) {\n return\n }\n console.log(btnToActive)\n\n document.querySelectorAll('[data-bs-theme-value]').forEach(element => {\n element.classList.remove('active')\n element.setAttribute('aria-pressed', 'false')\n })\n\n btnToActive.classList.add('active')\n btnToActive.setAttribute('aria-pressed', 'true')\n\n if (focus) {\n themeSwitcher.focus()\n }\n}\n\nwindow.matchMedia(darkQuery).addEventListener('change', () => {\n const storedTheme = getStoredTheme()\n if (storedTheme !== 'light' && storedTheme !== 'dark') {\n setTheme(getPreferredTheme())\n }\n})\n\nwindow.addEventListener('DOMContentLoaded', () => {\n let showTheme = getStoredTheme()\n if (!showTheme) {\n showTheme = \"auto\"\n }\n showActiveTheme(showTheme)\n\n document.querySelectorAll('[data-bs-theme-value]')\n .forEach(toggle => {\n toggle.addEventListener('click', () => {\n const theme = toggle.getAttribute('data-bs-theme-value')!\n setStoredTheme(theme)\n setTheme(theme)\n showActiveTheme(theme, true)\n })\n })\n})\n"], + "mappings": "mBAMA,IAAMA,EAAU,+BAEVC,EAAiB,IAAM,aAAa,QAAQ,OAAO,EACnDC,EAAkBC,GAAkB,aAAa,QAAQ,QAASA,CAAK,EAEvEC,EAAoB,IAAM,CAC5B,IAAMC,EAAcJ,EAAe,EACnC,OAAII,IAIG,OAAO,WAAWL,CAAS,EAAE,QAAU,OAAS,QAC3D,EAEMM,EAAYH,GAAkB,CAC5BA,IAAU,QAAU,OAAO,WAAWH,CAAS,EAAE,QACjD,SAAS,gBAAgB,aAAa,gBAAiB,MAAM,EAE7D,SAAS,gBAAgB,aAAa,gBAAiBG,CAAK,CAEpE,EAEAG,EAASF,EAAkB,CAAC,EAE5B,IAAMG,EAAkB,CAACJ,EAAeK,EAAiB,KAAU,CAC/D,IAAMC,EAAgB,SAAS,eAAe,sBAAsB,EACpE,GAAI,CAACA,EACD,OAGJ,IAAMC,EAAc,SAAS,cAAc,yBAAyBP,CAAK,IAAI,EACxEO,IAGL,QAAQ,IAAIA,CAAW,EAEvB,SAAS,iBAAiB,uBAAuB,EAAE,QAAQC,GAAW,CAClEA,EAAQ,UAAU,OAAO,QAAQ,EACjCA,EAAQ,aAAa,eAAgB,OAAO,CAChD,CAAC,EAEDD,EAAY,UAAU,IAAI,QAAQ,EAClCA,EAAY,aAAa,eAAgB,MAAM,EAE3CF,GACAC,EAAc,MAAM,EAE5B,EAEA,OAAO,WAAWT,CAAS,EAAE,iBAAiB,SAAU,IAAM,CAC1D,IAAMK,EAAcJ,EAAe,EAC/BI,IAAgB,SAAWA,IAAgB,QAC3CC,EAASF,EAAkB,CAAC,CAEpC,CAAC,EAED,OAAO,iBAAiB,mBAAoB,IAAM,CAC9C,IAAIQ,EAAYX,EAAe,EAC1BW,IACDA,EAAY,QAEhBL,EAAgBK,CAAS,EAEzB,SAAS,iBAAiB,uBAAuB,EAC5C,QAAQC,GAAU,CACfA,EAAO,iBAAiB,QAAS,IAAM,CACnC,IAAMV,EAAQU,EAAO,aAAa,qBAAqB,EACvDX,EAAeC,CAAK,EACpBG,EAASH,CAAK,EACdI,EAAgBJ,EAAO,EAAI,CAC/B,CAAC,CACL,CAAC,CACT,CAAC", + "names": ["darkQuery", "getStoredTheme", "setStoredTheme", "theme", "getPreferredTheme", "storedTheme", "setTheme", "showActiveTheme", "focus", "themeSwitcher", "btnToActive", "element", "showTheme", "toggle"] +} diff --git a/static/js/colortheme.ts b/static/colortheme/colortheme.ts similarity index 100% rename from static/js/colortheme.ts rename to static/colortheme/colortheme.ts diff --git a/templates/base.jinja b/templates/base.jinja index 7646919..3227387 100644 --- a/templates/base.jinja +++ b/templates/base.jinja @@ -15,7 +15,7 @@ {% endfor %} {% endif %} - + @@ -50,7 +50,7 @@ {% else %} - + {% endif %} {% if sentry_event_id %} diff --git a/vite.config.js b/vite.config.js index 530dd88..140ffea 100644 --- a/vite.config.js +++ b/vite.config.js @@ -14,7 +14,7 @@ export default defineConfig({ // overwrite default .html entry input: { "main": 'static/main.ts', - "colortheme": 'static/js/colortheme.ts', + // "colortheme": 'static/js/colortheme.ts', // "tenantbase": 'static/tenantbase.js', // "editor": 'static/editor.js' },