mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fmt(js): npm run fix on merge (#68976)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
e0e15436ee
commit
96ba7ec529
14 changed files with 162 additions and 143 deletions
|
|
@ -9,7 +9,11 @@ describe('ShimmerRows leniency (agent-authored calls)', () => {
|
|||
const { createElement } = await import('react')
|
||||
|
||||
const { screen, height } = renderToScreen(
|
||||
createElement(ShimmerRows, { rows: 3, width: 20, t: { color: { completionBg: '#1a1a2e', label: '#DAA520', muted: '#B8860B' } } }),
|
||||
createElement(ShimmerRows, {
|
||||
rows: 3,
|
||||
width: 20,
|
||||
t: { color: { completionBg: '#1a1a2e', label: '#DAA520', muted: '#B8860B' } }
|
||||
}),
|
||||
30
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -303,7 +303,10 @@ describe('fromSkin', () => {
|
|||
})
|
||||
|
||||
it('keeps truecolor light Apple Terminal in truecolor (adapting, not ansi256-bucketing)', async () => {
|
||||
const { contrastRatio, fromSkin } = await importThemeWithEnv({ COLORTERM: 'truecolor', TERM_PROGRAM: 'Apple_Terminal' })
|
||||
const { contrastRatio, fromSkin } = await importThemeWithEnv({
|
||||
COLORTERM: 'truecolor',
|
||||
TERM_PROGRAM: 'Apple_Terminal'
|
||||
})
|
||||
const theme = fromSkin({ banner_text: '#FFF8DC' }, {})
|
||||
|
||||
// No ansi256 bucketing on truecolor terminals — a truly invisible cream
|
||||
|
|
@ -418,10 +421,7 @@ describe('derived tone ladder', () => {
|
|||
const { fromSkin } = await importThemeWithCleanEnv()
|
||||
|
||||
// A seeds-only skin (no dim/label/menu keys authored at all).
|
||||
const { color } = fromSkin(
|
||||
{ banner_accent: '#DD4A3A', banner_text: '#F1E6CF', banner_title: '#C7A96B' },
|
||||
{}
|
||||
)
|
||||
const { color } = fromSkin({ banner_accent: '#DD4A3A', banner_text: '#F1E6CF', banner_title: '#C7A96B' }, {})
|
||||
|
||||
// Muted recedes from THIS skin's text toward the background with an
|
||||
// accent tint — a red-family derivative, never another skin's gold.
|
||||
|
|
|
|||
|
|
@ -193,11 +193,7 @@ describe('layoutGridAreas', () => {
|
|||
columns: 2,
|
||||
gap: 0,
|
||||
height: 12,
|
||||
items: [
|
||||
{ col: 1, id: 'pinned', row: 2 },
|
||||
{ id: 'auto-a' },
|
||||
{ id: 'auto-b' }
|
||||
],
|
||||
items: [{ col: 1, id: 'pinned', row: 2 }, { id: 'auto-a' }, { id: 'auto-b' }],
|
||||
rowGap: 0,
|
||||
rows: 2,
|
||||
width: 10
|
||||
|
|
|
|||
|
|
@ -47,10 +47,16 @@ const themeForSkin = (s: GatewaySkin) => {
|
|||
// still works — it just overrides every key it lists.
|
||||
const paired = detectLightMode() ? s.light_colors : s.dark_colors
|
||||
|
||||
const colors =
|
||||
paired && Object.keys(paired).length ? { ...(s.colors ?? {}), ...paired } : (s.colors ?? {})
|
||||
const colors = paired && Object.keys(paired).length ? { ...(s.colors ?? {}), ...paired } : (s.colors ?? {})
|
||||
|
||||
return fromSkin(colors, s.branding ?? {}, s.banner_logo ?? '', s.banner_hero ?? '', s.tool_prefix ?? '', s.help_header ?? '')
|
||||
return fromSkin(
|
||||
colors,
|
||||
s.branding ?? {},
|
||||
s.banner_logo ?? '',
|
||||
s.banner_hero ?? '',
|
||||
s.tool_prefix ?? '',
|
||||
s.help_header ?? ''
|
||||
)
|
||||
}
|
||||
|
||||
// Patch the live theme AND persist it for the next launch's first frame
|
||||
|
|
@ -95,7 +101,12 @@ const themesEqual = (a: Theme, b: Theme) => {
|
|||
}
|
||||
}
|
||||
|
||||
return a.brand.name === b.brand.name && a.brand.prompt === b.brand.prompt && a.bannerLogo === b.bannerLogo && a.bannerHero === b.bannerHero
|
||||
return (
|
||||
a.brand.name === b.brand.name &&
|
||||
a.brand.prompt === b.brand.prompt &&
|
||||
a.bannerLogo === b.bannerLogo &&
|
||||
a.bannerHero === b.bannerHero
|
||||
)
|
||||
}
|
||||
|
||||
const applySkin = (s: GatewaySkin) => {
|
||||
|
|
|
|||
|
|
@ -799,7 +799,9 @@ export function TranscriptScrollbar({ scrollRef, t }: TranscriptScrollbarProps)
|
|||
<Text color={thumbColor}>{`${'┃\n'.repeat(Math.max(0, thumb - 1))}${thumb > 0 ? '┃' : ''}`}</Text>
|
||||
) : null}
|
||||
{vp - thumbTop - thumb > 0 ? (
|
||||
<Text color={trackColor}>{`${'│\n'.repeat(Math.max(0, vp - thumbTop - thumb - 1))}${vp - thumbTop - thumb > 0 ? '│' : ''}`}</Text>
|
||||
<Text
|
||||
color={trackColor}
|
||||
>{`${'│\n'.repeat(Math.max(0, vp - thumbTop - thumb - 1))}${vp - thumbTop - thumb > 0 ? '│' : ''}`}</Text>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -401,117 +401,115 @@ export function SessionPanel({ info, maxWidth, sid, t }: SessionPanelProps) {
|
|||
|
||||
const infoColumn = (
|
||||
<Box flexDirection="column" width="100%">
|
||||
{wide ? (
|
||||
<Box justifyContent="center" marginBottom={1}>
|
||||
<Text bold color={t.color.primary}>
|
||||
{t.brand.name}
|
||||
{info.version ? ` v${info.version}` : ''}
|
||||
{info.release_date ? ` (${info.release_date})` : ''}
|
||||
</Text>
|
||||
</Box>
|
||||
) : (
|
||||
// Narrow layout hides the hero column; surface model/cwd/session
|
||||
// here so they aren't lost.
|
||||
<Box flexDirection="column" marginBottom={1}>
|
||||
<Text color={t.color.accent} wrap="truncate-end">
|
||||
{info.model.split('/').pop()}
|
||||
<Text color={t.color.muted}> · Nous Research</Text>
|
||||
</Text>
|
||||
<Text color={t.color.muted} wrap="truncate-end">
|
||||
{info.cwd || process.cwd()}
|
||||
</Text>
|
||||
{sid && (
|
||||
<Text wrap="truncate-end">
|
||||
<Text color={t.color.sessionLabel}>Session: </Text>
|
||||
<Text color={t.color.sessionBorder}>{sid}</Text>
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* ── Tools (expanded by default) ── */}
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<CollapseToggle onToggle={() => setToolsOpen(v => !v)} open={toolsOpen} t={t} title="Available Tools" />
|
||||
{toolsOpen && toolsBody()}
|
||||
{wide ? (
|
||||
<Box justifyContent="center" marginBottom={1}>
|
||||
<Text bold color={t.color.primary}>
|
||||
{t.brand.name}
|
||||
{info.version ? ` v${info.version}` : ''}
|
||||
{info.release_date ? ` (${info.release_date})` : ''}
|
||||
</Text>
|
||||
</Box>
|
||||
) : (
|
||||
// Narrow layout hides the hero column; surface model/cwd/session
|
||||
// here so they aren't lost.
|
||||
<Box flexDirection="column" marginBottom={1}>
|
||||
<Text color={t.color.accent} wrap="truncate-end">
|
||||
{info.model.split('/').pop()}
|
||||
<Text color={t.color.muted}> · Nous Research</Text>
|
||||
</Text>
|
||||
<Text color={t.color.muted} wrap="truncate-end">
|
||||
{info.cwd || process.cwd()}
|
||||
</Text>
|
||||
{sid && (
|
||||
<Text wrap="truncate-end">
|
||||
<Text color={t.color.sessionLabel}>Session: </Text>
|
||||
<Text color={t.color.sessionBorder}>{sid}</Text>
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* ── Skills (collapsed by default) ── */}
|
||||
{/* ── Tools (expanded by default) ── */}
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<CollapseToggle onToggle={() => setToolsOpen(v => !v)} open={toolsOpen} t={t} title="Available Tools" />
|
||||
{toolsOpen && toolsBody()}
|
||||
</Box>
|
||||
|
||||
{/* ── Skills (collapsed by default) ── */}
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<CollapseToggle
|
||||
count={skillsTotal}
|
||||
onToggle={() => setSkillsOpen(v => !v)}
|
||||
open={skillsOpen}
|
||||
suffix={skillsCatCount > 0 ? `in ${skillsCatCount} categor${skillsCatCount === 1 ? 'y' : 'ies'}` : undefined}
|
||||
t={t}
|
||||
title="Available Skills"
|
||||
/>
|
||||
{skillsOpen && skillsBody()}
|
||||
</Box>
|
||||
|
||||
{/* ── System Prompt (collapsed by default) ── */}
|
||||
{sysPromptLen > 0 && (
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<CollapseToggle
|
||||
count={skillsTotal}
|
||||
onToggle={() => setSkillsOpen(v => !v)}
|
||||
open={skillsOpen}
|
||||
suffix={
|
||||
skillsCatCount > 0 ? `in ${skillsCatCount} categor${skillsCatCount === 1 ? 'y' : 'ies'}` : undefined
|
||||
}
|
||||
onToggle={() => setSystemOpen(v => !v)}
|
||||
open={systemOpen}
|
||||
suffix={`— ${sysPromptLen.toLocaleString()} chars`}
|
||||
t={t}
|
||||
title="Available Skills"
|
||||
title="System Prompt"
|
||||
/>
|
||||
{skillsOpen && skillsBody()}
|
||||
{systemOpen && systemBody()}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* ── System Prompt (collapsed by default) ── */}
|
||||
{sysPromptLen > 0 && (
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<CollapseToggle
|
||||
onToggle={() => setSystemOpen(v => !v)}
|
||||
open={systemOpen}
|
||||
suffix={`— ${sysPromptLen.toLocaleString()} chars`}
|
||||
t={t}
|
||||
title="System Prompt"
|
||||
/>
|
||||
{systemOpen && systemBody()}
|
||||
</Box>
|
||||
)}
|
||||
{/* ── MCP Servers (collapsed by default) ── */}
|
||||
{mcpServers.length > 0 && (
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<CollapseToggle
|
||||
count={mcpConnected}
|
||||
onToggle={() => setMcpOpen(v => !v)}
|
||||
open={mcpOpen}
|
||||
suffix="connected"
|
||||
t={t}
|
||||
title="MCP Servers"
|
||||
/>
|
||||
{mcpOpen && mcpBody()}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* ── MCP Servers (collapsed by default) ── */}
|
||||
{mcpServers.length > 0 && (
|
||||
<Box flexDirection="column" marginTop={1}>
|
||||
<CollapseToggle
|
||||
count={mcpConnected}
|
||||
onToggle={() => setMcpOpen(v => !v)}
|
||||
open={mcpOpen}
|
||||
suffix="connected"
|
||||
t={t}
|
||||
title="MCP Servers"
|
||||
/>
|
||||
{mcpOpen && mcpBody()}
|
||||
</Box>
|
||||
)}
|
||||
<Text />
|
||||
|
||||
<Text />
|
||||
<Text color={t.color.text}>
|
||||
{/* Lazy boot: never print "0 tools · 0 skills" while counts load. */}
|
||||
{info.lazy && !toolsTotal ? '… ' : `${toolsTotal} `}tools{' · '}
|
||||
{info.lazy && !skillsTotal ? '… ' : `${skillsTotal} `}skills
|
||||
{mcpConnected ? ` · ${mcpConnected} MCP` : ''}
|
||||
{' · '}
|
||||
<Text color={t.color.muted}>/help for commands</Text>
|
||||
</Text>
|
||||
|
||||
<Text color={t.color.text}>
|
||||
{/* Lazy boot: never print "0 tools · 0 skills" while counts load. */}
|
||||
{info.lazy && !toolsTotal ? '… ' : `${toolsTotal} `}tools{' · '}
|
||||
{info.lazy && !skillsTotal ? '… ' : `${skillsTotal} `}skills
|
||||
{mcpConnected ? ` · ${mcpConnected} MCP` : ''}
|
||||
{' · '}
|
||||
<Text color={t.color.muted}>/help for commands</Text>
|
||||
</Text>
|
||||
|
||||
{typeof info.update_behind === 'number' && info.update_behind > 0 && (
|
||||
{typeof info.update_behind === 'number' && info.update_behind > 0 && (
|
||||
<Text bold color={t.color.warn}>
|
||||
! {info.update_behind} {info.update_behind === 1 ? 'commit' : 'commits'} behind
|
||||
<Text bold={false} color={t.color.warn} dimColor>
|
||||
{' '}
|
||||
- run{' '}
|
||||
</Text>
|
||||
<Text bold color={t.color.warn}>
|
||||
! {info.update_behind} {info.update_behind === 1 ? 'commit' : 'commits'} behind
|
||||
<Text bold={false} color={t.color.warn} dimColor>
|
||||
{' '}
|
||||
- run{' '}
|
||||
</Text>
|
||||
<Text bold color={t.color.warn}>
|
||||
{info.update_command || 'hermes update'}
|
||||
</Text>
|
||||
<Text bold={false} color={t.color.warn} dimColor>
|
||||
{' '}
|
||||
to update
|
||||
</Text>
|
||||
{info.update_command || 'hermes update'}
|
||||
</Text>
|
||||
)}
|
||||
<Text bold={false} color={t.color.warn} dimColor>
|
||||
{' '}
|
||||
to update
|
||||
</Text>
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{info.install_warning && (
|
||||
<Text bold color={t.color.warn} wrap="wrap">
|
||||
! {info.install_warning}
|
||||
</Text>
|
||||
)}
|
||||
{info.install_warning && (
|
||||
<Text bold color={t.color.warn} wrap="wrap">
|
||||
! {info.install_warning}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -90,12 +90,13 @@ const sparkRows = (history: number[], width: number, rows: number): string[] =>
|
|||
|
||||
// ── stream panels ───────────────────────────────────────────────────────────
|
||||
|
||||
const TOKEN_WORDS =
|
||||
(`Hermes streams tokens into the promoted cell while the grid reshapes around it. ` +
|
||||
`Cells are keyed by id, so promotion never resets a panel — history, cursors and ` +
|
||||
`tickers all survive the relayout. Row and column tracks re-solve to integer ` +
|
||||
`terminal cells on every change, spans bridge the gaps they cross, and dense ` +
|
||||
`auto-placement backfills the holes the promoted panel leaves behind. `).split(' ')
|
||||
const TOKEN_WORDS = (
|
||||
`Hermes streams tokens into the promoted cell while the grid reshapes around it. ` +
|
||||
`Cells are keyed by id, so promotion never resets a panel — history, cursors and ` +
|
||||
`tickers all survive the relayout. Row and column tracks re-solve to integer ` +
|
||||
`terminal cells on every change, spans bridge the gaps they cross, and dense ` +
|
||||
`auto-placement backfills the holes the promoted panel leaves behind. `
|
||||
).split(' ')
|
||||
|
||||
function TokenStream({ height, t, width }: { height: number; t: Theme; width: number }) {
|
||||
const tick = useTick(90)
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ function AreasDemo({ cols, state, t }: { cols: number; state: GridTestState; t:
|
|||
|
||||
const rowSpanFirst = state.rows >= 2 ? 2 : 1
|
||||
const colSpanSecond = state.cols >= 2 ? 2 : 1
|
||||
const extraSlots = (rowSpanFirst - 1) + (colSpanSecond - 1)
|
||||
const extraSlots = rowSpanFirst - 1 + (colSpanSecond - 1)
|
||||
const itemCount = Math.max(1, state.rows * state.cols - extraSlots)
|
||||
|
||||
const cursorInside = (cell: GridAreaCell) =>
|
||||
|
|
@ -126,7 +126,9 @@ function AreasDemo({ cols, state, t }: { cols: number; state: GridTestState; t:
|
|||
const widgets: GridAreaWidget[] = Array.from({ length: itemCount }, (_, idx) => ({
|
||||
colSpan: idx === 1 ? colSpanSecond : 1,
|
||||
id: `area-c${idx + 1}`,
|
||||
render: (cell: GridAreaCell) => <AreaDemoCell active={cursorInside(cell)} cell={cell} label={`c${idx + 1}`} t={t} />,
|
||||
render: (cell: GridAreaCell) => (
|
||||
<AreaDemoCell active={cursorInside(cell)} cell={cell} label={`c${idx + 1}`} t={t} />
|
||||
),
|
||||
rowSpan: idx === 0 ? rowSpanFirst : 1
|
||||
}))
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,11 @@ export function MenuRow({ active, index, label, t }: { active: boolean; index: n
|
|||
|
||||
return (
|
||||
<Text>
|
||||
<Text backgroundColor={row.backgroundColor} bold={active} color={active ? (row.color ?? t.color.label) : t.color.muted}>
|
||||
<Text
|
||||
backgroundColor={row.backgroundColor}
|
||||
bold={active}
|
||||
color={active ? (row.color ?? t.color.label) : t.color.muted}
|
||||
>
|
||||
{active ? '▸ ' : ' '}
|
||||
{index}. {label}
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -667,7 +667,9 @@ export function TextInput({
|
|||
}
|
||||
|
||||
if (!display && placeholder) {
|
||||
return hintCursorCell(placeholder[0] ?? ' ', placeholderColor) + colorizeHint(placeholder.slice(1), placeholderColor)
|
||||
return (
|
||||
hintCursorCell(placeholder[0] ?? ' ', placeholderColor) + colorizeHint(placeholder.slice(1), placeholderColor)
|
||||
)
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
|
|
|
|||
|
|
@ -255,17 +255,12 @@ export const GridAreas = memo(function GridAreas({
|
|||
|
||||
const AreaCell = memo(function AreaCell({ cell, widget }: { cell: GridAreaCell; widget?: GridAreaWidget }) {
|
||||
const node =
|
||||
widget?.render?.(cell) ?? (typeof widget?.children === 'function' ? widget.children(cell) : widget?.children) ?? null
|
||||
widget?.render?.(cell) ??
|
||||
(typeof widget?.children === 'function' ? widget.children(cell) : widget?.children) ??
|
||||
null
|
||||
|
||||
return (
|
||||
<Box
|
||||
height={cell.height}
|
||||
left={cell.x}
|
||||
overflow="hidden"
|
||||
position="absolute"
|
||||
top={cell.y}
|
||||
width={cell.width}
|
||||
>
|
||||
<Box height={cell.height} left={cell.x} overflow="hidden" position="absolute" top={cell.y} width={cell.width}>
|
||||
{node}
|
||||
</Box>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -46,8 +46,7 @@ export function parseColor(input: string): Rgb | null {
|
|||
return null
|
||||
}
|
||||
|
||||
export const toHex = (rgb: Rgb): string =>
|
||||
'#' + rgb.map(c => clampChannel(c).toString(16).padStart(2, '0')).join('')
|
||||
export const toHex = (rgb: Rgb): string => '#' + rgb.map(c => clampChannel(c).toString(16).padStart(2, '0')).join('')
|
||||
|
||||
/** sRGB lerp `a → b` by `t` in [0,1]. Unparseable inputs return `a` unchanged. */
|
||||
export function mix(a: string, b: string, t: number): string {
|
||||
|
|
@ -71,7 +70,9 @@ function channelLuminance(value: number): number {
|
|||
export function relativeLuminance(color: string): null | number {
|
||||
const rgb = parseColor(color)
|
||||
|
||||
return rgb ? 0.2126 * channelLuminance(rgb[0]) + 0.7152 * channelLuminance(rgb[1]) + 0.0722 * channelLuminance(rgb[2]) : null
|
||||
return rgb
|
||||
? 0.2126 * channelLuminance(rgb[0]) + 0.7152 * channelLuminance(rgb[1]) + 0.0722 * channelLuminance(rgb[2])
|
||||
: null
|
||||
}
|
||||
|
||||
/** WCAG contrast ratio between two colors (1–21). Null when unparseable. */
|
||||
|
|
|
|||
|
|
@ -52,7 +52,11 @@ const columnCountForWidth = (width: number, minColumnWidth: number, gap: number,
|
|||
}
|
||||
|
||||
const buildColumnWidths = (width: number, columnCount: number, gap: number) =>
|
||||
resolveGridTracks(width, gap, Array.from({ length: Math.max(1, toInt(columnCount, 1)) }, () => ({ fr: 1 })))
|
||||
resolveGridTracks(
|
||||
width,
|
||||
gap,
|
||||
Array.from({ length: Math.max(1, toInt(columnCount, 1)) }, () => ({ fr: 1 }))
|
||||
)
|
||||
|
||||
const spanWidth = (columns: number[], colStart: number, span: number, gap: number) => {
|
||||
const end = Math.min(columns.length, colStart + span)
|
||||
|
|
@ -229,7 +233,10 @@ export function resolveGridTracks(total: number, gap: number, tracks: GridTrackS
|
|||
})
|
||||
|
||||
while (unpinned.length) {
|
||||
const shares = distributeByWeight(Math.max(0, remaining), unpinned.map(idx => trackFr(tracks[idx]!)))
|
||||
const shares = distributeByWeight(
|
||||
Math.max(0, remaining),
|
||||
unpinned.map(idx => trackFr(tracks[idx]!))
|
||||
)
|
||||
const violating = unpinned.filter((idx, i) => shares[i]! < trackMin(tracks[idx]!))
|
||||
|
||||
if (!violating.length) {
|
||||
|
|
@ -467,10 +474,7 @@ export function layoutGridAreas({
|
|||
const explicitRowTracks = rows === undefined ? [] : normalizeTracks(rows, 1)
|
||||
const rowCount = Math.max(1, explicitRowTracks.length, placedRowCount)
|
||||
|
||||
const rowTracks: GridTrackSize[] = Array.from(
|
||||
{ length: rowCount },
|
||||
(_, idx) => explicitRowTracks[idx] ?? { fr: 1 }
|
||||
)
|
||||
const rowTracks: GridTrackSize[] = Array.from({ length: rowCount }, (_, idx) => explicitRowTracks[idx] ?? { fr: 1 })
|
||||
|
||||
const columnSizes = resolveGridTracks(safeWidth, safeGap, columnTracks)
|
||||
const rowSizes = resolveGridTracks(safeHeight, safeRowGap, rowTracks)
|
||||
|
|
|
|||
|
|
@ -580,8 +580,7 @@ export function deriveTones(seeds: {
|
|||
statusFg: grayOf(mix(text, bg, isLight ? 0.3 : 0.24)),
|
||||
surface,
|
||||
activeRow: mix(surface, accent, 0.25),
|
||||
selection:
|
||||
isLight && seeds.shellDollar ? mix(bg, seeds.shellDollar, 0.2) : mix(surface, accent, 0.28),
|
||||
selection: isLight && seeds.shellDollar ? mix(bg, seeds.shellDollar, 0.2) : mix(surface, accent, 0.28),
|
||||
border: mix(accent, bg, 0.25)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue