Add downloadable/re-uploadable custom themes (ticket 033)
Themes download as a small `:root { --c-*: ...; }` CSS file (full
canonical variable set); uploading validates that set is complete and
registers the file as a CssEntry the theme picker can select. A new
`is_theme` flag on CssEntry distinguishes theme entries from arbitrary
imported/linked CSS so they don't leak into the page unconditionally
like the existing "Configured CSS" list does — a selected custom
theme's CSS is injected only while active, with built-in html.<scheme>
classes removed so its :root override isn't outranked in the cascade.
Linked (URL) custom themes reuse the existing CSS link mechanism and
inherit its non-deletable semantics.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
7bf323dd50
commit
41c9a3660b
+13
-2
@@ -103,6 +103,8 @@ export interface Settings {
|
||||
active_profile: string | null
|
||||
/** Maximum ingested logs kept in memory; `null` means unlimited. */
|
||||
max_logs: number | null
|
||||
/** Id of the selected custom theme entry (ticket 033), or `null` if `color_scheme` alone applies. */
|
||||
custom_theme_id: string | null
|
||||
}
|
||||
|
||||
export type CssEntryKind = 'imported' | 'linked'
|
||||
@@ -112,6 +114,8 @@ export interface CssEntry {
|
||||
kind: CssEntryKind
|
||||
filename: string | null
|
||||
path_or_url: string | null
|
||||
/** Whether this entry is a selectable colour-scheme theme (ticket 033) rather than arbitrary CSS. */
|
||||
is_theme: boolean
|
||||
}
|
||||
|
||||
export interface ProfileSummary {
|
||||
@@ -304,9 +308,12 @@ export function updateSettings(update: {
|
||||
colorScheme?: ColorScheme
|
||||
/** Omit to leave unchanged; `null` clears the cap back to unlimited. */
|
||||
maxLogs?: number | null
|
||||
/** Omit to leave unchanged; `null` clears the selection (falls back to `colorScheme`). */
|
||||
customThemeId?: string | null
|
||||
}): Promise<Settings> {
|
||||
const body: Record<string, unknown> = { color_scheme: update.colorScheme }
|
||||
if ('maxLogs' in update) body.max_logs = update.maxLogs
|
||||
if ('customThemeId' in update) body.custom_theme_id = update.customThemeId
|
||||
return sendJson('/api/settings', 'PATCH', body)
|
||||
}
|
||||
|
||||
@@ -314,8 +321,12 @@ export function fetchCssEntries(): Promise<CssEntry[]> {
|
||||
return getJson('/api/settings/css')
|
||||
}
|
||||
|
||||
export function importCss(filename: string, content: string): Promise<CssEntry> {
|
||||
return sendJson('/api/settings/css', 'POST', { filename, content })
|
||||
export function importCss(filename: string, content: string, isTheme = false): Promise<CssEntry> {
|
||||
return sendJson('/api/settings/css', 'POST', { filename, content, is_theme: isTheme })
|
||||
}
|
||||
|
||||
export function linkCss(pathOrUrl: string, isTheme = false): Promise<CssEntry> {
|
||||
return sendJson('/api/settings/css/link', 'POST', { path_or_url: pathOrUrl, is_theme: isTheme })
|
||||
}
|
||||
|
||||
export function deleteCssEntry(id: string): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user