mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-14 20:21:39 +03:00
refactor(theme): rename surface tokens to raised (#49655)
This commit is contained in:
committed by
GitHub
Unverified
parent
b278ef6b82
commit
0ac458b3b3
@@ -136,9 +136,10 @@ export const DEFAULT_THEME = {
|
||||
},
|
||||
background: {
|
||||
default: "$hue.neutral.200",
|
||||
surface: {
|
||||
offset: "$hue.neutral.300",
|
||||
overlay: "$hue.neutral.400",
|
||||
raised: {
|
||||
base: "$hue.neutral.300",
|
||||
high: "$hue.neutral.400",
|
||||
max: "$hue.neutral.500",
|
||||
},
|
||||
action: {
|
||||
primary: {
|
||||
@@ -161,7 +162,7 @@ export const DEFAULT_THEME = {
|
||||
},
|
||||
formfield: {
|
||||
default: "$background.default",
|
||||
$hovered: "$background.surface.offset",
|
||||
$hovered: "$background.raised.base",
|
||||
$focused: "$background.action.primary.default",
|
||||
$pressed: "$hue.interactive.800",
|
||||
$disabled: "$background.default",
|
||||
@@ -220,14 +221,14 @@ export const DEFAULT_THEME = {
|
||||
"@context:elevated": {
|
||||
text: { action: { primary: { default: "$hue.neutral.100" } } },
|
||||
background: {
|
||||
default: "$background.surface.offset",
|
||||
action: { primary: { default: "$hue.interactive.500", $hovered: "$background.surface.overlay" } },
|
||||
default: "$background.raised.base",
|
||||
action: { primary: { default: "$hue.interactive.500", $hovered: "$background.raised.high" } },
|
||||
},
|
||||
},
|
||||
"@context:overlay": {
|
||||
text: { action: { primary: { default: "$hue.neutral.100" } } },
|
||||
background: {
|
||||
default: "$background.surface.overlay",
|
||||
default: "$background.raised.high",
|
||||
action: { primary: { default: "$hue.interactive.500" } },
|
||||
},
|
||||
},
|
||||
@@ -357,9 +358,10 @@ export const DEFAULT_THEME = {
|
||||
},
|
||||
background: {
|
||||
default: "$hue.neutral.800",
|
||||
surface: {
|
||||
offset: "$hue.neutral.700",
|
||||
overlay: "$hue.neutral.600",
|
||||
raised: {
|
||||
base: "$hue.neutral.700",
|
||||
high: "$hue.neutral.600",
|
||||
max: "$hue.neutral.500",
|
||||
},
|
||||
action: {
|
||||
primary: {
|
||||
@@ -382,7 +384,7 @@ export const DEFAULT_THEME = {
|
||||
},
|
||||
formfield: {
|
||||
default: "$background.default",
|
||||
$hovered: "$background.surface.offset",
|
||||
$hovered: "$background.raised.base",
|
||||
$focused: "$background.action.primary.default",
|
||||
$pressed: "$hue.interactive.800",
|
||||
$disabled: "$background.default",
|
||||
@@ -441,14 +443,14 @@ export const DEFAULT_THEME = {
|
||||
"@context:elevated": {
|
||||
text: { action: { primary: { default: "$hue.neutral.200" } } },
|
||||
background: {
|
||||
default: "$background.surface.offset",
|
||||
action: { primary: { default: "$hue.interactive.400", $hovered: "$background.surface.overlay" } },
|
||||
default: "$background.raised.base",
|
||||
action: { primary: { default: "$hue.interactive.400", $hovered: "$background.raised.high" } },
|
||||
},
|
||||
},
|
||||
"@context:overlay": {
|
||||
text: { action: { primary: { default: "$hue.neutral.200" } } },
|
||||
background: {
|
||||
default: "$background.surface.overlay",
|
||||
default: "$background.raised.high",
|
||||
action: { primary: { default: "$hue.interactive.400" } },
|
||||
},
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ export function fallback(mode: Mode): ThemeTokensDefinition {
|
||||
},
|
||||
background: {
|
||||
default: red,
|
||||
surface: { offset: red, overlay: red },
|
||||
raised: { base: red, high: red, max: red },
|
||||
action: Object.fromEntries(ActionVariant.literals.map((variant) => [variant, { default: red }])),
|
||||
formfield: { default: red },
|
||||
feedback: Object.fromEntries(FeedbackKind.literals.map((kind) => [kind, { default: red }])),
|
||||
|
||||
@@ -129,10 +129,11 @@ export type TextDefinition = Schema.Schema.Type<typeof TextDefinition>
|
||||
|
||||
const BackgroundDefinition = Schema.Struct({
|
||||
default: Schema.optional(ColorValue),
|
||||
surface: Schema.optional(
|
||||
raised: Schema.optional(
|
||||
Schema.Struct({
|
||||
offset: Schema.optional(ColorValue),
|
||||
overlay: Schema.optional(ColorValue),
|
||||
base: Schema.optional(ColorValue),
|
||||
high: Schema.optional(ColorValue),
|
||||
max: Schema.optional(ColorValue),
|
||||
}),
|
||||
),
|
||||
action: Schema.optional(ActionColorDefinition),
|
||||
|
||||
@@ -40,9 +40,10 @@ export type ResolvedThemeTokens = {
|
||||
}
|
||||
readonly background: {
|
||||
readonly default: RGBA
|
||||
readonly surface: {
|
||||
readonly offset: RGBA
|
||||
readonly overlay: RGBA
|
||||
readonly raised: {
|
||||
readonly base: RGBA
|
||||
readonly high: RGBA
|
||||
readonly max: RGBA
|
||||
}
|
||||
readonly action: Readonly<Record<ActionVariant, StatefulColor>>
|
||||
readonly formfield: FormfieldColor
|
||||
|
||||
@@ -57,6 +57,7 @@ function migrateMode(theme: Theme, mode: Mode): FileThemeDefinition {
|
||||
const background = mode === "light" ? "$hue.neutral.200" : "$hue.neutral.800"
|
||||
const backgroundPanel = mode === "light" ? "$hue.neutral.300" : "$hue.neutral.700"
|
||||
const backgroundMenu = mode === "light" ? "$hue.neutral.400" : "$hue.neutral.600"
|
||||
const backgroundRaisedMax = "$hue.neutral.500"
|
||||
|
||||
return referenceHues({
|
||||
hue: {
|
||||
@@ -102,9 +103,10 @@ function migrateMode(theme: Theme, mode: Mode): FileThemeDefinition {
|
||||
},
|
||||
background: {
|
||||
default: background,
|
||||
surface: {
|
||||
offset: backgroundPanel,
|
||||
overlay: backgroundMenu,
|
||||
raised: {
|
||||
base: backgroundPanel,
|
||||
high: backgroundMenu,
|
||||
max: backgroundRaisedMax,
|
||||
},
|
||||
action: {
|
||||
primary: { default: "transparent", $hovered: backgroundPanel, $focused: primary, $selected: "transparent" },
|
||||
@@ -173,11 +175,11 @@ function migrateMode(theme: Theme, mode: Mode): FileThemeDefinition {
|
||||
},
|
||||
"@context:elevated": {
|
||||
background: {
|
||||
default: "$background.surface.offset",
|
||||
action: { primary: { $hovered: "$background.surface.overlay" } },
|
||||
default: "$background.raised.base",
|
||||
action: { primary: { $hovered: "$background.raised.high" } },
|
||||
},
|
||||
},
|
||||
"@context:overlay": { background: { default: "$background.surface.overlay" } },
|
||||
"@context:overlay": { background: { default: "$background.raised.high" } },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +350,7 @@ export function Prompt(props: PromptProps) {
|
||||
|
||||
createEffect(() => {
|
||||
if (!input || input.isDestroyed) return
|
||||
input.cursorColor = disabled() ? theme.background.surface.offset : theme.text.default
|
||||
input.cursorColor = disabled() ? theme.background.raised.base : theme.text.default
|
||||
if (config.cursor) input.cursorStyle = config.cursor
|
||||
})
|
||||
|
||||
@@ -1642,7 +1642,7 @@ export function Prompt(props: PromptProps) {
|
||||
})
|
||||
const maxHeight = createMemo(() => Math.max(6, Math.floor(dimensions().height / 3)))
|
||||
|
||||
const promptBg = createMemo(() => theme.raise(theme.background.surface.offset))
|
||||
const promptBg = createMemo(() => theme.raise(theme.background.raised.base))
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -1799,7 +1799,7 @@ export function Prompt(props: PromptProps) {
|
||||
setTimeout(() => {
|
||||
// setTimeout is a workaround and needs to be addressed properly
|
||||
if (!input || input.isDestroyed) return
|
||||
input.cursorColor = disabled() ? theme.background.surface.offset : theme.text.default
|
||||
input.cursorColor = disabled() ? theme.background.raised.base : theme.text.default
|
||||
if (config.cursor) input.cursorStyle = config.cursor
|
||||
}, 0)
|
||||
}}
|
||||
@@ -1818,7 +1818,7 @@ export function Prompt(props: PromptProps) {
|
||||
r.stopPropagation()
|
||||
}}
|
||||
focusedBackgroundColor="transparent"
|
||||
cursorColor={disabled() ? theme.background.surface.offset : theme.text.default}
|
||||
cursorColor={disabled() ? theme.background.raised.base : theme.text.default}
|
||||
syntaxStyle={syntax()}
|
||||
/>
|
||||
<box flexDirection="row" flexShrink={0} paddingTop={1} gap={1} justifyContent="space-between">
|
||||
|
||||
@@ -1530,7 +1530,7 @@ function HorizontalSessionTabs(props: {
|
||||
const lifted = (hovered() === tab.sessionID || dragged()) && !selected()
|
||||
const base = lifted ? theme.background.action.primary.hovered : theme.background.default
|
||||
// A dragged tab lifts to full selected elevation while it is held.
|
||||
return tint(base, theme.raise(theme.background.surface.offset), dragged() ? 1 : selection())
|
||||
return tint(base, theme.raise(theme.background.raised.base), dragged() ? 1 : selection())
|
||||
})
|
||||
const pulseColor = () => tint(background(), theme.text.default, 0.45)
|
||||
// The edge flash washes toward a brighter stop on the same background-to-text ramp,
|
||||
|
||||
@@ -887,7 +887,7 @@ export function DiffViewerContent(props: {
|
||||
)
|
||||
edge.backgroundColor =
|
||||
entry && reviewedFileNames().has(entry.file.file)
|
||||
? theme.background.surface.overlay
|
||||
? theme.background.raised.high
|
||||
: theme.diff.background.context
|
||||
}
|
||||
renderer.registerLifecyclePass(edge)
|
||||
@@ -911,7 +911,7 @@ export function DiffViewerContent(props: {
|
||||
{(entry, index) => {
|
||||
const reviewed = () => reviewedFileNames().has(entry.file.file)
|
||||
const background = () =>
|
||||
reviewed() ? theme.background.surface.overlay : theme.diff.background.context
|
||||
reviewed() ? theme.background.raised.high : theme.diff.background.context
|
||||
const image = () => isDiffImageFile(entry.file.file)
|
||||
const countsWidth = () =>
|
||||
(image() ? 6 : String(entry.file.additions).length + String(entry.file.deletions).length + 5) +
|
||||
|
||||
@@ -161,7 +161,7 @@ function map(
|
||||
surface: exact(elevated.background.default),
|
||||
pane: exact(theme.contextual.overlay.background.default),
|
||||
border: exact(theme.border.default),
|
||||
line: exact(theme.background.surface.overlay),
|
||||
line: exact(theme.background.raised.high),
|
||||
},
|
||||
entry: {
|
||||
system: { body: scrollback(theme.text.subdued) },
|
||||
@@ -174,7 +174,7 @@ function map(
|
||||
splash: {
|
||||
left: nearestIndexed(indexed, theme.text.subdued),
|
||||
right: nearestIndexed(indexed, theme.text.default),
|
||||
leftShadow: nearestIndexed(indexed, theme.background.surface.offset),
|
||||
leftShadow: nearestIndexed(indexed, theme.background.raised.base),
|
||||
},
|
||||
block: {
|
||||
text: scrollback(theme.text.default),
|
||||
|
||||
@@ -1292,7 +1292,7 @@ export function Session(props: {
|
||||
paddingLeft: 1,
|
||||
visible: showScrollbar(),
|
||||
trackOptions: {
|
||||
backgroundColor: theme.raise(theme.background.surface.offset),
|
||||
backgroundColor: theme.raise(theme.background.raised.base),
|
||||
foregroundColor: theme.border.default,
|
||||
},
|
||||
}}
|
||||
@@ -1836,7 +1836,7 @@ function SessionReasoningGroupView(props: {
|
||||
<box
|
||||
border={["left"]}
|
||||
customBorderChars={SplitBorder.customBorderChars}
|
||||
borderColor={theme.raise(theme.background.surface.offset)}
|
||||
borderColor={theme.raise(theme.background.raised.base)}
|
||||
paddingLeft={1}
|
||||
>
|
||||
<code
|
||||
|
||||
@@ -762,7 +762,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
||||
backgroundColor={
|
||||
active()
|
||||
? actionFocused()
|
||||
? theme.background.surface.overlay
|
||||
? theme.background.raised.high
|
||||
: (option.bg ?? theme.background.action.primary.focused)
|
||||
: RGBA.fromInts(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ function expectFooter(actual: RunTheme, theme: ResolvedTheme) {
|
||||
surface: theme.contextual.elevated.background.default,
|
||||
pane: theme.contextual.overlay.background.default,
|
||||
border: theme.border.default,
|
||||
line: theme.background.surface.overlay,
|
||||
line: theme.background.raised.high,
|
||||
}
|
||||
Object.entries(expected).forEach(([key, color]) => {
|
||||
expect(rgba(actual.footer[key as keyof typeof expected]).toInts()).toEqual(color.toInts())
|
||||
|
||||
@@ -19,12 +19,12 @@ test("provides reactive properties, states, contexts, and color operations", ()
|
||||
expect(theme.hue.interactive[500]).toBe(resolved().hue.interactive[500])
|
||||
expect(theme.hue.gray[200]).toBe(resolved().hue.gray[200])
|
||||
expect(theme.categorical.map((scale) => scale[500])).toEqual(resolved().categorical.map((scale) => scale[500]))
|
||||
expect(theme.increase(theme.background.surface.offset, 1)).toBe(resolved().hue.neutral[400])
|
||||
expect(theme.raise(theme.background.surface.offset)).toBe(resolved().hue.neutral[400])
|
||||
expect(theme.increase(theme.background.raised.base, 1)).toBe(resolved().hue.neutral[400])
|
||||
expect(theme.raise(theme.background.raised.base)).toBe(resolved().hue.neutral[400])
|
||||
expect(theme.decrease(theme.hue.red[300], 2)).toBe(resolved().hue.red[100])
|
||||
expect(theme.increase(theme.hue.red[900], 3)).toBe(resolved().hue.red[900])
|
||||
expect(theme.decrease(theme.hue.red[100], 3)).toBe(resolved().hue.red[100])
|
||||
expect(theme.source(theme.background.surface.offset)).toEqual({ hue: "neutral", step: 300 })
|
||||
expect(theme.source(theme.background.raised.base)).toEqual({ hue: "neutral", step: 300 })
|
||||
const equivalent = RGBA.fromInts(...resolved().hue.green[500].toInts())
|
||||
expect(theme.source(equivalent)).toBeUndefined()
|
||||
expect(theme.increase(equivalent, 1)).toBe(equivalent)
|
||||
@@ -46,8 +46,8 @@ test("provides reactive properties, states, contexts, and color operations", ()
|
||||
expect(theme.background.formfield.selected).toBe(resolved().background.formfield.selected)
|
||||
expect(theme.background.formfield.focused).toBe(resolved().background.formfield.focused)
|
||||
expect(theme.background.formfield.disabled).toBe(resolved().background.formfield.disabled)
|
||||
expect(theme.background.surface.offset).toBe(resolved().background.surface.offset)
|
||||
expect(theme.background.surface.overlay).toBe(resolved().background.surface.overlay)
|
||||
expect(theme.background.raised.base).toBe(resolved().background.raised.base)
|
||||
expect(theme.background.raised.high).toBe(resolved().background.raised.high)
|
||||
expect(theme.scrollbar.default).toBe(resolved().scrollbar.default)
|
||||
expect(theme.diff.text.added).toBe(resolved().diff.text.added)
|
||||
|
||||
@@ -58,14 +58,14 @@ test("provides reactive properties, states, contexts, and color operations", ()
|
||||
expect(current().background.action.primary.focused).toBe(
|
||||
resolved().contextual.elevated.background.action.primary.focused,
|
||||
)
|
||||
expect(current().background.action.primary.hovered).toBe(resolved().background.surface.overlay)
|
||||
expect(current().background.action.primary.hovered).toBe(resolved().background.raised.high)
|
||||
expect(current().background.formfield.selected).toBe(resolved().contextual.elevated.background.formfield.selected)
|
||||
|
||||
setResolved(resolveTheme(selectTheme(DEFAULT_THEME, "dark")))
|
||||
setMode("dark")
|
||||
expect(current().text.default).toBe(resolved().contextual.elevated.text.default)
|
||||
expect(current().decrease(current().background.surface.offset, 1)).toBe(resolved().hue.neutral[600])
|
||||
expect(current().raise(current().background.surface.offset)).toBe(resolved().hue.neutral[600])
|
||||
expect(current().decrease(current().background.raised.base, 1)).toBe(resolved().hue.neutral[600])
|
||||
expect(current().raise(current().background.raised.base)).toBe(resolved().hue.neutral[600])
|
||||
})
|
||||
|
||||
test("a stable component theme view follows presentation context changes", () => {
|
||||
|
||||
@@ -71,21 +71,21 @@ test("resolves independent definitions and hue aliases", () => {
|
||||
expect(lightTheme.categorical[0]).toBe(lightTheme.hue.blue)
|
||||
expect(lightTheme.source(lightTheme.hue.blue[500])).toEqual({ hue: "blue", step: 500 })
|
||||
expect(lightTheme.source(lightTheme.hue.neutral[200])).toEqual({ hue: "neutral", step: 200 })
|
||||
expect(lightTheme.source(lightTheme.background.surface.offset)).toEqual({ hue: "neutral", step: 300 })
|
||||
expect(lightTheme.source(lightTheme.background.raised.base)).toEqual({ hue: "neutral", step: 300 })
|
||||
expect(lightTheme.increase(lightTheme.hue.red[100])).toBe(lightTheme.hue.red[200])
|
||||
expect(lightTheme.decrease(lightTheme.hue.red[200])).toBe(lightTheme.hue.red[100])
|
||||
expect(lightTheme.contextual.elevated.increase(lightTheme.hue.red[100])).toBe(lightTheme.hue.red[200])
|
||||
expect(lightTheme.text.default).toBeInstanceOf(RGBA)
|
||||
expect(darkTheme.background.default).toBeInstanceOf(RGBA)
|
||||
expect(lightTheme.background.surface.offset).toBe(lightTheme.hue.neutral[300])
|
||||
expect(lightTheme.background.surface.overlay).toBe(lightTheme.hue.neutral[400])
|
||||
expect(lightTheme.background.raised.base).toBe(lightTheme.hue.neutral[300])
|
||||
expect(lightTheme.background.raised.high).toBe(lightTheme.hue.neutral[400])
|
||||
expect(lightTheme.syntax.keyword).toBeInstanceOf(RGBA)
|
||||
expect(lightTheme.text.action.primary.default).toBe(lightTheme.hue.neutral[200])
|
||||
expect(lightTheme.contextual.elevated.background.action.primary.default).toBe(lightTheme.hue.interactive[500])
|
||||
expect(lightTheme.contextual.elevated.background.default).toBe(lightTheme.background.surface.offset)
|
||||
expect(lightTheme.contextual.elevated.background.default).toBe(lightTheme.background.raised.base)
|
||||
expect(lightTheme.contextual.elevated.text.action.primary.default).toBe(lightTheme.hue.neutral[100])
|
||||
expect(lightTheme.contextual.overlay.background.action.primary.default).toBe(lightTheme.hue.interactive[500])
|
||||
expect(lightTheme.contextual.overlay.background.default).toBe(lightTheme.background.surface.overlay)
|
||||
expect(lightTheme.contextual.overlay.background.default).toBe(lightTheme.background.raised.high)
|
||||
expect(lightTheme.contextual.overlay.text.action.primary.default).toBe(lightTheme.hue.neutral[100])
|
||||
expect(darkTheme.contextual.elevated.background.action.primary.default).toBe(darkTheme.hue.interactive[400])
|
||||
expect(darkTheme.contextual.elevated.text.action.primary.default).toBe(darkTheme.hue.neutral[200])
|
||||
@@ -244,7 +244,7 @@ test("resolves elevated hover surfaces from direct colors", () => {
|
||||
const theme = resolveSource(
|
||||
{
|
||||
version: 2,
|
||||
light: { background: { surface: { offset: "#123456", overlay: "#234567" } } },
|
||||
light: { background: { raised: { base: "#123456", high: "#234567" } } },
|
||||
dark: {},
|
||||
},
|
||||
"light",
|
||||
|
||||
@@ -19,7 +19,7 @@ const text = {
|
||||
|
||||
const background = {
|
||||
default: "$hue.neutral.100",
|
||||
surface: { offset: "$hue.neutral.200", overlay: "$hue.neutral.300" },
|
||||
raised: { base: "$hue.neutral.200", high: "$hue.neutral.300", max: "$hue.neutral.400" },
|
||||
action: {
|
||||
primary: {
|
||||
default: "$hue.interactive.600",
|
||||
|
||||
@@ -24,17 +24,17 @@ test("migrates resolved V1 modes into V2 tokens", () => {
|
||||
expect(migrated.light.text?.subdued).toBe("$hue.neutral.600")
|
||||
expect(migrated.light.background?.action?.primary?.default).toBe("transparent")
|
||||
expect(migrated.light.background?.default).toBe("$hue.neutral.200")
|
||||
expect(migrated.light.background?.surface?.offset).toBe("$hue.neutral.300")
|
||||
expect(migrated.light.background?.surface?.overlay).toBe("$hue.neutral.400")
|
||||
expect(migrated.light.background?.raised?.base).toBe("$hue.neutral.300")
|
||||
expect(migrated.light.background?.raised?.high).toBe("$hue.neutral.400")
|
||||
expect(migrated.dark.background?.default).toBe("$hue.neutral.800")
|
||||
expect(migrated.dark.background?.surface?.offset).toBe("$hue.neutral.700")
|
||||
expect(migrated.dark.background?.surface?.overlay).toBe("$hue.neutral.600")
|
||||
expect(migrated.dark.background?.raised?.base).toBe("$hue.neutral.700")
|
||||
expect(migrated.dark.background?.raised?.high).toBe("$hue.neutral.600")
|
||||
expect(migrated.light.text?.action?.primary?.default).toBe("$text.default")
|
||||
expect(migrated.light.text?.action?.secondary?.default).toBe("$text.subdued")
|
||||
expect(migrated.light.text?.action?.secondary?.$hovered).toBe("$text.default")
|
||||
expect(migrated.light.background?.action?.primary?.$selected).toBe("transparent")
|
||||
expect(resolved.background.surface.offset.toInts()).toEqual(legacy.backgroundPanel.toInts())
|
||||
expect(resolved.background.surface.overlay.toInts()).toEqual(legacy.backgroundElement.toInts())
|
||||
expect(resolved.background.raised.base.toInts()).toEqual(legacy.backgroundPanel.toInts())
|
||||
expect(resolved.background.raised.high.toInts()).toEqual(legacy.backgroundElement.toInts())
|
||||
expect(resolved.background.formfield.selected.toInts()).toEqual(legacy.background.toInts())
|
||||
expect(resolved.background.formfield.focused.toInts()).toEqual(legacy.background.toInts())
|
||||
expect(resolved.text.formfield.default.toInts()).toEqual(legacy.text.toInts())
|
||||
|
||||
Reference in New Issue
Block a user