Make imported/linked CSS always a full theme replacement (ticket 020)

Removes the "Use as theme" checkbox/is_theme distinction from
NavMenu.tsx's CSS import and link forms — every imported/linked
stylesheet is now always validated against the canonical --c-*
variable set and becomes a selectable theme, same as today's
is_theme:true path. Drops is_theme entirely from the backend
(CssEntry, ImportCssRequest, LinkCssRequest, CssEntryDto) and from
the frontend CssEntry type; an existing settings.json with a stored
is_theme:false entry still deserializes fine (the field is simply
unknown/ignored) and that entry becomes selectable like any other,
so no migration step is needed. Also drops the now-dead
always-on-overlay CSS injection path from useSettingsPanel.ts, and
changes the CSS filename placeholder from "name.css" to "enter name".

Implemented directly against main rather than merging the dispatched
worktree branch for this ticket, since that branch's base predated
ticket 012 (the custom-themes/imported-CSS consolidation) and its
NavMenu structure no longer matched current main.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
Hugh Kaznowski
2026-09-05 19:51:17 +01:00
co-authored by Claude Sonnet 5
parent f20359e655
commit d6b7f7dfb6
7 changed files with 52 additions and 145 deletions
+4 -10
View File
@@ -122,21 +122,18 @@ pub struct ErrorDto {
pub error: String,
}
/// `is_theme` marks this as a selectable colour-scheme theme rather than arbitrary CSS; defaults to false.
/// Every imported CSS entry is a selectable theme (ticket 020) — there's no separate
/// always-on-overlay mode to opt into.
#[derive(Debug, Deserialize)]
pub struct ImportCssRequest {
pub filename: String,
pub content: String,
#[serde(default)]
pub is_theme: bool,
}
/// A reference to an external CSS path/URL that ottyl doesn't copy or own.
#[derive(Debug, Deserialize)]
pub struct LinkCssRequest {
pub path_or_url: String,
#[serde(default)]
pub is_theme: bool,
}
/// `id` is the real id for `Imported` entries or a stable id derived from the path/URL for `Linked` ones, so the frontend can key both kinds uniformly (only `Imported` entries are deletable/content-fetchable).
@@ -146,7 +143,6 @@ pub struct CssEntryDto {
pub kind: CssEntryKind,
pub filename: Option<String>,
pub path_or_url: Option<String>,
pub is_theme: bool,
}
#[derive(Debug, Clone, Copy, Serialize)]
@@ -159,19 +155,17 @@ pub enum CssEntryKind {
impl From<&CssEntry> for CssEntryDto {
fn from(entry: &CssEntry) -> Self {
match entry {
CssEntry::Imported { id, filename, is_theme } => CssEntryDto {
CssEntry::Imported { id, filename } => CssEntryDto {
id: id.clone(),
kind: CssEntryKind::Imported,
filename: Some(filename.clone()),
path_or_url: None,
is_theme: *is_theme,
},
CssEntry::Linked { path_or_url, is_theme } => CssEntryDto {
CssEntry::Linked { path_or_url } => CssEntryDto {
id: crate::settings::css_entry_id(entry),
kind: CssEntryKind::Linked,
filename: None,
path_or_url: Some(path_or_url.clone()),
is_theme: *is_theme,
},
}
}