Windmill
diff --git a/frontend/src/lib/components/apps/editor/PublicApp.svelte b/frontend/src/lib/components/apps/editor/PublicApp.svelte
index 8995684e28..c0cf693e0f 100644
--- a/frontend/src/lib/components/apps/editor/PublicApp.svelte
+++ b/frontend/src/lib/components/apps/editor/PublicApp.svelte
@@ -1,5 +1,6 @@
-
+
{
+ darkVariant = getAppliedDarkModeVariant()
+ }}
+/>
diff --git a/frontend/src/lib/components/sidebar/sidebarChrome.ts b/frontend/src/lib/components/sidebar/sidebarChrome.ts
index 110435c058..71ff703d27 100644
--- a/frontend/src/lib/components/sidebar/sidebarChrome.ts
+++ b/frontend/src/lib/components/sidebar/sidebarChrome.ts
@@ -1,5 +1,6 @@
-// Sidebar rail background. Deliberately raw hex — no theme token exists for
-// the rail chrome — kept here as the single source for every host that renders
-// or mimics the sidebar (app layout, kitchen-sink harness).
+// Sidebar rail background. Kept here as the single source for every host that
+// renders or mimics the sidebar (app layout, kitchen-sink harness).
+// The dark value is a theme-driven CSS variable so it adapts across dark
+// variants (default vs GitHub dark) — see tailwind.config.cjs `--sidebar-bg-dark`.
export const SIDEBAR_BG = '#F3F3F7'
-export const SIDEBAR_BG_DARK = '#1e232e'
+export const SIDEBAR_BG_DARK = 'var(--sidebar-bg-dark)'
diff --git a/frontend/src/lib/components/vscode.ts b/frontend/src/lib/components/vscode.ts
index 1277ac1b4a..f30ffcd780 100644
--- a/frontend/src/lib/components/vscode.ts
+++ b/frontend/src/lib/components/vscode.ts
@@ -1,6 +1,7 @@
import '@codingame/monaco-vscode-standalone-typescript-language-features'
import { editor as meditor, Uri as mUri } from 'monaco-editor'
+import { getAppliedDarkModeVariant } from '$lib/darkModeVariant'
export let isInitialized = false
export let isInitializing = false
@@ -12,6 +13,15 @@ import {
import getLanguagesServiceOverride from '@codingame/monaco-vscode-languages-service-override'
import { getCssColor } from '$lib/utils'
+// Monaco theme name matching the current document theme (light / dark / GitHub dark variant).
+export function getEditorTheme(): string {
+ const classes = document.documentElement.classList
+ if (!classes.contains('dark')) {
+ return 'myTheme'
+ }
+ return getAppliedDarkModeVariant() === 'github' ? 'github-dark' : 'nord'
+}
+
export function buildWorkerDefinition() {
const envEnhanced = getEnhancedMonacoEnvironment()
const getWorker = (moduleId: string, label: string) => {
@@ -248,6 +258,47 @@ export async function initializeVscode(caller?: string, htmlContainer?: HTMLElem
}
})
+ meditor.defineTheme('github-dark', {
+ base: 'vs-dark',
+ inherit: true,
+ rules: [
+ { background: '0D1117', token: '' },
+ { foreground: '8b949e', token: 'comment' },
+ { foreground: 'a5d6ff', token: 'string' },
+ { foreground: '79c0ff', token: 'constant.numeric' },
+ { foreground: '79c0ff', token: 'constant.language' },
+ { foreground: 'ff7b72', token: 'keyword' },
+ { foreground: 'ff7b72', token: 'storage' },
+ { foreground: 'ff7b72', token: 'storage.type' },
+ { foreground: 'ffa657', token: 'entity.name.class' },
+ { foreground: 'ffa657', fontStyle: 'bold', token: 'entity.other.inherited-class' },
+ { foreground: 'd2a8ff', token: 'entity.name.function' },
+ { foreground: '7ee787', token: 'entity.name.tag' },
+ { foreground: '79c0ff', token: 'entity.other.attribute-name' },
+ { foreground: 'd2a8ff', token: 'support.function' },
+ { foreground: 'f0f6fc', background: 'f85149', token: 'invalid' },
+ { foreground: 'f0f6fc', background: 'bd561d', token: 'invalid.deprecated' },
+ { foreground: '79c0ff', token: 'constant.color.other.rgb-value' },
+ { foreground: '79c0ff', token: 'constant.character.escape' },
+ { foreground: 'ffa657', token: 'variable.other.constant' },
+ { token: 'string.value.json', foreground: 'a5d6ff' }, // string values in JSON
+ { token: 'keyword.json', foreground: '79c0ff' } // true, false, null in JSON
+ ],
+ colors: {
+ 'editor.foreground': '#e6edf3',
+ 'editor.background': getCssColor('surface-input', { format: 'hex-github-dark' }),
+ 'editor.selectionBackground': '#3392FF44',
+ 'editor.inactiveSelectionBackground': '#3392FF22',
+ 'editor.lineHighlightBackground': '#161b22',
+ 'editorCursor.foreground': '#e6edf3',
+ 'editorWhitespace.foreground': '#484f58',
+ 'editorIndentGuide.background1': '#21262d',
+ 'editorIndentGuide.activeBackground1': '#30363d',
+ 'editorLineNumber.foreground': '#6e7681',
+ 'editorLineNumber.activeForeground': '#e6edf3'
+ }
+ })
+
meditor.defineTheme('myTheme', {
base: 'vs',
inherit: true,
@@ -262,11 +313,7 @@ export async function initializeVscode(caller?: string, htmlContainer?: HTMLElem
}
})
- if (document.documentElement.classList.contains('dark')) {
- meditor.setTheme('nord')
- } else {
- meditor.setTheme('myTheme')
- }
+ meditor.setTheme(getEditorTheme())
} catch (e) {
console.error('Failed to initialize monaco services', e)
} finally {
diff --git a/frontend/src/lib/darkModeVariant.ts b/frontend/src/lib/darkModeVariant.ts
new file mode 100644
index 0000000000..1e1bbff28b
--- /dev/null
+++ b/frontend/src/lib/darkModeVariant.ts
@@ -0,0 +1,27 @@
+export type DarkModeVariant = 'default' | 'github'
+
+const DARK_MODE_VARIANT_KEY = 'dark-mode-variant'
+
+export function getDarkModeVariant(): DarkModeVariant {
+ return window.localStorage.getItem(DARK_MODE_VARIANT_KEY) === 'github' ? 'github' : 'default'
+}
+
+// The variant currently applied to the DOM (the `github-dark` class) — the
+// runtime source of truth, as opposed to the persisted preference above.
+export function getAppliedDarkModeVariant(): DarkModeVariant {
+ return typeof document !== 'undefined' &&
+ document.documentElement.classList.contains('github-dark')
+ ? 'github'
+ : 'default'
+}
+
+// The `github-dark` class only takes effect when `dark` is also present (see tailwind.config.cjs).
+// It lives on permanently so it survives the many independent `dark` toggle sites.
+export function applyDarkModeVariant(variant: DarkModeVariant = getDarkModeVariant()): void {
+ document.documentElement.classList.toggle('github-dark', variant === 'github')
+}
+
+export function setDarkModeVariant(variant: DarkModeVariant): void {
+ window.localStorage.setItem(DARK_MODE_VARIANT_KEY, variant)
+ applyDarkModeVariant(variant)
+}
diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts
index 28d33335ae..e9acfdacab 100644
--- a/frontend/src/lib/utils.ts
+++ b/frontend/src/lib/utils.ts
@@ -2029,6 +2029,8 @@ export function validateRetryConfig(retry: Retry | undefined): string | null {
}
export type CssColor = keyof (typeof tokensFile)['tokens']['light']
import tokensFile from './assets/tokens/tokens.json'
+// Hand-authored variant kept out of the Figma-generated tokens.json.
+import githubDarkTokens from './assets/tokens/githubDark.json'
import { darkModeName, lightModeName } from './assets/tokens/colorTokensConfig'
import BarsStaggered from './components/icons/BarsStaggered.svelte'
import { GitIcon } from './components/icons'
@@ -2041,7 +2043,7 @@ export function getCssColor(
format = 'css-var'
}: {
alpha?: number
- format?: 'css-var' | 'hex-dark' | 'hex-light'
+ format?: 'css-var' | 'hex-dark' | 'hex-light' | 'hex-github-dark'
}
): string {
if (format === 'hex-light') {
@@ -2050,6 +2052,9 @@ export function getCssColor(
if (format === 'hex-dark') {
return tokensFile.tokens[darkModeName][color]
}
+ if (format === 'hex-github-dark') {
+ return githubDarkTokens[color]
+ }
return `rgb(var(--color-${color}) / ${alpha})`
}
diff --git a/frontend/src/routes/(root)/(logged)/+layout.svelte b/frontend/src/routes/(root)/(logged)/+layout.svelte
index 7dbe5ca376..9de1123ff9 100644
--- a/frontend/src/routes/(root)/(logged)/+layout.svelte
+++ b/frontend/src/routes/(root)/(logged)/+layout.svelte
@@ -1052,7 +1052,7 @@
style:width="{railWidth}rem"
>
{#if !isCollapsed}
diff --git a/frontend/src/routes/(root)/+layout.svelte b/frontend/src/routes/(root)/+layout.svelte
index 8b7736965d..3db5efcf60 100644
--- a/frontend/src/routes/(root)/+layout.svelte
+++ b/frontend/src/routes/(root)/+layout.svelte
@@ -19,6 +19,7 @@
// import EditorTheme from '$lib/components/EditorTheme.svelte'
import { computeDrift } from '$lib/forLater'
import { setLicense } from '$lib/enterpriseUtils'
+ import { applyDarkModeVariant } from '$lib/darkModeVariant'
import { deepEqual } from 'fast-equals'
interface Props {
children?: import('svelte').Snippet
@@ -255,6 +256,8 @@
} else {
document.documentElement.classList.remove('dark')
}
+
+ applyDarkModeVariant()
{@render children?.()}
diff --git a/frontend/src/routes/user/login_callback/[client_name]/+page.svelte b/frontend/src/routes/user/login_callback/[client_name]/+page.svelte
index 737da14321..1aeb57f223 100644
--- a/frontend/src/routes/user/login_callback/[client_name]/+page.svelte
+++ b/frontend/src/routes/user/login_callback/[client_name]/+page.svelte
@@ -1,5 +1,6 @@