mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-01 22:48:16 +00:00
chore: cleanup
This commit is contained in:
@@ -13,9 +13,36 @@
|
||||
<meta name="theme-color" content="#131010" media="(prefers-color-scheme: dark)" />
|
||||
<meta property="og:image" content="/social-share.png" />
|
||||
<meta property="twitter:image" content="/social-share.png" />
|
||||
<!-- Theme preload script - injected by Vite plugin to avoid FOUC -->
|
||||
<!-- Theme preload script - applies cached theme to avoid FOUC -->
|
||||
<script id="oc-theme-preload-script">
|
||||
/* THEME_PRELOAD_SCRIPT */
|
||||
;(function () {
|
||||
var themeId = localStorage.getItem("opencode-theme-id")
|
||||
if (!themeId) return
|
||||
|
||||
var scheme = localStorage.getItem("opencode-color-scheme") || "system"
|
||||
var isDark = scheme === "dark" || (scheme === "system" && matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
var mode = isDark ? "dark" : "light"
|
||||
|
||||
document.documentElement.dataset.theme = themeId
|
||||
document.documentElement.dataset.colorScheme = mode
|
||||
|
||||
if (themeId === "oc-1") return
|
||||
|
||||
var css = localStorage.getItem("opencode-theme-css-" + themeId + "-" + mode)
|
||||
if (css) {
|
||||
var style = document.createElement("style")
|
||||
style.id = "oc-theme-preload"
|
||||
style.textContent =
|
||||
":root{color-scheme:" +
|
||||
mode +
|
||||
";--text-mix-blend-mode:" +
|
||||
(isDark ? "plus-lighter" : "multiply") +
|
||||
";" +
|
||||
css +
|
||||
"}"
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
</head>
|
||||
<body class="antialiased overscroll-none text-12-regular overflow-hidden">
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* Injects the theme preload script into index.html.
|
||||
* Run this as part of the build process.
|
||||
*/
|
||||
|
||||
import { generatePreloadScript } from "@opencode-ai/ui/theme"
|
||||
|
||||
const htmlPath = new URL("../index.html", import.meta.url).pathname
|
||||
const html = await Bun.file(htmlPath).text()
|
||||
|
||||
const script = generatePreloadScript()
|
||||
const injectedHtml = html.replace(
|
||||
/<script id="oc-theme-preload-script">\s*\/\* THEME_PRELOAD_SCRIPT \*\/\s*<\/script>/,
|
||||
`<script id="oc-theme-preload-script">${script}</script>`,
|
||||
)
|
||||
|
||||
await Bun.write(htmlPath, injectedHtml)
|
||||
console.log("Injected theme preload script into index.html")
|
||||
@@ -1,23 +1,6 @@
|
||||
import solidPlugin from "vite-plugin-solid"
|
||||
import tailwindcss from "@tailwindcss/vite"
|
||||
import { fileURLToPath } from "url"
|
||||
import { generatePreloadScript } from "@opencode-ai/ui/theme"
|
||||
|
||||
/**
|
||||
* Vite plugin that injects the theme preload script into index.html.
|
||||
* This ensures the theme is applied before the page renders, avoiding FOUC.
|
||||
* @type {import("vite").Plugin}
|
||||
*/
|
||||
const themePreloadPlugin = {
|
||||
name: "opencode-desktop:theme-preload",
|
||||
transformIndexHtml(html) {
|
||||
const script = generatePreloadScript()
|
||||
return html.replace(
|
||||
/<script id="oc-theme-preload-script">\s*\/\* THEME_PRELOAD_SCRIPT \*\/\s*<\/script>/,
|
||||
`<script id="oc-theme-preload-script">${script}</script>`,
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {import("vite").PluginOption}
|
||||
@@ -38,7 +21,6 @@ export default [
|
||||
}
|
||||
},
|
||||
},
|
||||
themePreloadPlugin,
|
||||
tailwindcss(),
|
||||
solidPlugin(),
|
||||
]
|
||||
|
||||
@@ -13,9 +13,36 @@
|
||||
<meta name="theme-color" content="#131010" media="(prefers-color-scheme: dark)" />
|
||||
<meta property="og:image" content="/social-share.png" />
|
||||
<meta property="twitter:image" content="/social-share.png" />
|
||||
<!-- Theme preload script - injected by Vite plugin to avoid FOUC -->
|
||||
<!-- Theme preload script - applies cached theme to avoid FOUC -->
|
||||
<script id="oc-theme-preload-script">
|
||||
/* THEME_PRELOAD_SCRIPT */
|
||||
;(function () {
|
||||
var themeId = localStorage.getItem("opencode-theme-id")
|
||||
if (!themeId) return
|
||||
|
||||
var scheme = localStorage.getItem("opencode-color-scheme") || "system"
|
||||
var isDark = scheme === "dark" || (scheme === "system" && matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
var mode = isDark ? "dark" : "light"
|
||||
|
||||
document.documentElement.dataset.theme = themeId
|
||||
document.documentElement.dataset.colorScheme = mode
|
||||
|
||||
if (themeId === "oc-1") return
|
||||
|
||||
var css = localStorage.getItem("opencode-theme-css-" + themeId + "-" + mode)
|
||||
if (css) {
|
||||
var style = document.createElement("style")
|
||||
style.id = "oc-theme-preload"
|
||||
style.textContent =
|
||||
":root{color-scheme:" +
|
||||
mode +
|
||||
";--text-mix-blend-mode:" +
|
||||
(isDark ? "plus-lighter" : "multiply") +
|
||||
";" +
|
||||
css +
|
||||
"}"
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
</head>
|
||||
<body class="antialiased overscroll-none text-12-regular overflow-hidden">
|
||||
|
||||
@@ -126,11 +126,13 @@ function applyThemeCss(theme: DesktopTheme, themeId: string, mode: "light" | "da
|
||||
const css = themeToCss(tokens)
|
||||
|
||||
// Cache to localStorage for preload script
|
||||
const cacheKey = getThemeCacheKey(themeId, mode)
|
||||
try {
|
||||
localStorage.setItem(cacheKey, css)
|
||||
} catch {
|
||||
// localStorage might be full or disabled
|
||||
if (themeId !== "oc-1") {
|
||||
const cacheKey = getThemeCacheKey(themeId, mode)
|
||||
try {
|
||||
localStorage.setItem(cacheKey, css)
|
||||
} catch {
|
||||
// localStorage might be full or disabled
|
||||
}
|
||||
}
|
||||
|
||||
// Build full CSS
|
||||
@@ -159,6 +161,8 @@ function applyThemeCss(theme: DesktopTheme, themeId: string, mode: "light" | "da
|
||||
* Cache both light and dark variants of a theme
|
||||
*/
|
||||
function cacheThemeVariants(theme: DesktopTheme, themeId: string): void {
|
||||
if (themeId === "oc-1") return
|
||||
|
||||
for (const mode of ["light", "dark"] as const) {
|
||||
const isDark = mode === "dark"
|
||||
const variant = isDark ? theme.dark : theme.light
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
* Generates a minimal inline script that:
|
||||
* 1. Reads theme preferences from localStorage
|
||||
* 2. Applies cached theme CSS immediately (avoiding FOUC)
|
||||
* 3. Falls back to embedded default theme CSS on first visit
|
||||
*
|
||||
* The default (oc-1) theme is provided by `@opencode-ai/ui/styles` via `theme.css`,
|
||||
* so the preload script only runs when a non-default theme is selected.
|
||||
*
|
||||
* The script should be placed in the document <head> before any stylesheets.
|
||||
*/
|
||||
|
||||
import { resolveThemeVariant, themeToCss } from "./resolve"
|
||||
import type { DesktopTheme } from "./types"
|
||||
import oc1Theme from "./themes/oc-1.json"
|
||||
|
||||
// Storage keys used by both the preload script and the ThemeProvider
|
||||
export const STORAGE_KEYS = {
|
||||
THEME_ID: "opencode-theme-id",
|
||||
@@ -27,34 +25,17 @@ export function getThemeCacheKey(themeId: string, mode: "light" | "dark"): strin
|
||||
return `${STORAGE_KEYS.THEME_CSS_PREFIX}-${themeId}-${mode}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the embedded default theme CSS for the preload script.
|
||||
* This is used as a fallback when no cached theme exists.
|
||||
*/
|
||||
function generateEmbeddedDefaults(): { light: string; dark: string } {
|
||||
const theme = oc1Theme as DesktopTheme
|
||||
const lightTokens = resolveThemeVariant(theme.light, false)
|
||||
const darkTokens = resolveThemeVariant(theme.dark, true)
|
||||
|
||||
return {
|
||||
light: themeToCss(lightTokens),
|
||||
dark: themeToCss(darkTokens),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the inline preload script.
|
||||
*
|
||||
* This script should be placed in the document <head> to avoid FOUC.
|
||||
* It reads theme preferences from localStorage and applies the theme CSS
|
||||
* immediately, falling back to an embedded default theme.
|
||||
* It reads theme preferences from localStorage and applies cached theme CSS
|
||||
* immediately.
|
||||
*/
|
||||
export function generatePreloadScript(): string {
|
||||
const defaults = generateEmbeddedDefaults()
|
||||
|
||||
// Minified version of the preload logic
|
||||
// Variables: T=themeId, S=scheme, D=isDark, M=mode, C=css, K=cacheKey
|
||||
return `(function(){var T=localStorage.getItem("${STORAGE_KEYS.THEME_ID}")||"oc-1";var S=localStorage.getItem("${STORAGE_KEYS.COLOR_SCHEME}")||"system";var D=S==="dark"||(S==="system"&&matchMedia("(prefers-color-scheme:dark)").matches);var M=D?"dark":"light";var K="${STORAGE_KEYS.THEME_CSS_PREFIX}-"+T+"-"+M;var C=localStorage.getItem(K);if(!C&&T==="oc-1"){C=D?${JSON.stringify(defaults.dark)}:${JSON.stringify(defaults.light)}}if(C){var s=document.createElement("style");s.id="oc-theme-preload";s.textContent=":root{color-scheme:"+M+";--text-mix-blend-mode:"+(D?"plus-lighter":"multiply")+";"+C+"}";document.head.appendChild(s)}document.documentElement.dataset.theme=T;document.documentElement.dataset.colorScheme=M})();`
|
||||
return `(function(){var T=localStorage.getItem("${STORAGE_KEYS.THEME_ID}");if(!T)return;var S=localStorage.getItem("${STORAGE_KEYS.COLOR_SCHEME}")||"system";var D=S==="dark"||(S==="system"&&matchMedia("(prefers-color-scheme:dark)").matches);var M=D?"dark":"light";document.documentElement.dataset.theme=T;document.documentElement.dataset.colorScheme=M;if(T==="oc-1")return;var K="${STORAGE_KEYS.THEME_CSS_PREFIX}-"+T+"-"+M;var C=localStorage.getItem(K);if(C){var s=document.createElement("style");s.id="oc-theme-preload";s.textContent=":root{color-scheme:"+M+";--text-mix-blend-mode:"+(D?"plus-lighter":"multiply")+";"+C+"}";document.head.appendChild(s)}})();`
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,15 +43,16 @@ export function generatePreloadScript(): string {
|
||||
* Useful for debugging.
|
||||
*/
|
||||
export function generatePreloadScriptFormatted(): string {
|
||||
const defaults = generateEmbeddedDefaults()
|
||||
|
||||
return `(function() {
|
||||
var THEME_KEY = "${STORAGE_KEYS.THEME_ID}";
|
||||
var SCHEME_KEY = "${STORAGE_KEYS.COLOR_SCHEME}";
|
||||
var CSS_PREFIX = "${STORAGE_KEYS.THEME_CSS_PREFIX}";
|
||||
|
||||
// Read preferences from localStorage
|
||||
var themeId = localStorage.getItem(THEME_KEY) || "oc-1";
|
||||
// Only preload when a theme is selected
|
||||
var themeId = localStorage.getItem(THEME_KEY);
|
||||
if (!themeId) return;
|
||||
|
||||
// Read color scheme preference
|
||||
var scheme = localStorage.getItem(SCHEME_KEY) || "system";
|
||||
|
||||
// Determine if dark mode
|
||||
@@ -78,17 +60,17 @@ export function generatePreloadScriptFormatted(): string {
|
||||
(scheme === "system" && matchMedia("(prefers-color-scheme: dark)").matches);
|
||||
var mode = isDark ? "dark" : "light";
|
||||
|
||||
// Set data attributes for CSS/JS reference
|
||||
document.documentElement.dataset.theme = themeId;
|
||||
document.documentElement.dataset.colorScheme = mode;
|
||||
|
||||
// Default theme is handled by theme.css
|
||||
if (themeId === "oc-1") return;
|
||||
|
||||
// Try to get cached CSS for this theme + mode
|
||||
var cacheKey = CSS_PREFIX + "-" + themeId + "-" + mode;
|
||||
var css = localStorage.getItem(cacheKey);
|
||||
|
||||
// Fallback to embedded default for oc-1 theme
|
||||
if (!css && themeId === "oc-1") {
|
||||
css = isDark
|
||||
? ${JSON.stringify(defaults.dark)}
|
||||
: ${JSON.stringify(defaults.light)};
|
||||
}
|
||||
|
||||
// Apply CSS if we have it
|
||||
if (css) {
|
||||
var style = document.createElement("style");
|
||||
@@ -100,9 +82,5 @@ export function generatePreloadScriptFormatted(): string {
|
||||
"}";
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
// Set data attributes for CSS/JS reference
|
||||
document.documentElement.dataset.theme = themeId;
|
||||
document.documentElement.dataset.colorScheme = mode;
|
||||
})();`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user