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:
co-authored by
Claude Sonnet 5
parent
f20359e655
commit
d6b7f7dfb6
+12
-30
@@ -39,21 +39,16 @@ pub enum ColorScheme {
|
||||
System,
|
||||
}
|
||||
|
||||
/// A single CSS entry: content ottyl stores itself ("imported") or a reference to an external path/URL ("linked", not deletable via the API). `is_theme` marks it as a selectable colour-scheme theme rather than always-injected CSS.
|
||||
/// A single CSS entry: content ottyl stores itself ("imported") or a reference to an external
|
||||
/// path/URL ("linked", not deletable via the API). Every entry is always a selectable
|
||||
/// colour-scheme theme (ticket 020 removed the "use as theme"/always-on-overlay distinction);
|
||||
/// an entry persisted before that change with a stored `is_theme: false` still loads fine (the
|
||||
/// field is simply ignored) and becomes selectable like any other entry.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum CssEntry {
|
||||
Imported {
|
||||
id: String,
|
||||
filename: String,
|
||||
#[serde(default)]
|
||||
is_theme: bool,
|
||||
},
|
||||
Linked {
|
||||
path_or_url: String,
|
||||
#[serde(default)]
|
||||
is_theme: bool,
|
||||
},
|
||||
Imported { id: String, filename: String },
|
||||
Linked { path_or_url: String },
|
||||
}
|
||||
|
||||
/// Tracks known profile names and which one is active; the profile files themselves live elsewhere.
|
||||
@@ -228,7 +223,6 @@ impl Settings {
|
||||
css_dir: &Path,
|
||||
filename: String,
|
||||
content: &str,
|
||||
is_theme: bool,
|
||||
) -> Result<String, CssError> {
|
||||
fs::create_dir_all(css_dir)?;
|
||||
let id = generate_imported_css_id(&filename, content);
|
||||
@@ -236,23 +230,14 @@ impl Settings {
|
||||
self.css_entries.push(CssEntry::Imported {
|
||||
id: id.clone(),
|
||||
filename,
|
||||
is_theme,
|
||||
});
|
||||
self.save(settings_path)?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
/// Registers a reference to an external CSS path/URL without copying its content, and persists settings.
|
||||
pub fn link_css(
|
||||
&mut self,
|
||||
settings_path: &Path,
|
||||
path_or_url: String,
|
||||
is_theme: bool,
|
||||
) -> Result<(), CssError> {
|
||||
self.css_entries.push(CssEntry::Linked {
|
||||
path_or_url,
|
||||
is_theme,
|
||||
});
|
||||
pub fn link_css(&mut self, settings_path: &Path, path_or_url: String) -> Result<(), CssError> {
|
||||
self.css_entries.push(CssEntry::Linked { path_or_url });
|
||||
self.save(settings_path)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -340,11 +325,9 @@ mod tests {
|
||||
settings.css_entries.push(CssEntry::Imported {
|
||||
id: "abc123".to_string(),
|
||||
filename: "theme.css".to_string(),
|
||||
is_theme: false,
|
||||
});
|
||||
settings.css_entries.push(CssEntry::Linked {
|
||||
path_or_url: "https://example.com/style.css".to_string(),
|
||||
is_theme: false,
|
||||
});
|
||||
settings.profiles.names.push("default".to_string());
|
||||
settings.profiles.active_profile = Some("default".to_string());
|
||||
@@ -388,7 +371,6 @@ mod tests {
|
||||
&css_dir,
|
||||
"theme.css".to_string(),
|
||||
"body { color: red; }",
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -418,7 +400,7 @@ mod tests {
|
||||
|
||||
let mut settings = Settings::load(&settings_path);
|
||||
let id = settings
|
||||
.import_css(&settings_path, &css_dir, "a.css".to_string(), "a{}", false)
|
||||
.import_css(&settings_path, &css_dir, "a.css".to_string(), "a{}")
|
||||
.unwrap();
|
||||
let css_file = css_dir.join(format!("{id}.css"));
|
||||
assert!(css_file.exists());
|
||||
@@ -440,7 +422,7 @@ mod tests {
|
||||
|
||||
let mut settings = Settings::load(&settings_path);
|
||||
settings
|
||||
.link_css(&settings_path, "https://example.com/style.css".to_string(), false)
|
||||
.link_css(&settings_path, "https://example.com/style.css".to_string())
|
||||
.unwrap();
|
||||
let linked_id = css_entry_id(&settings.css_entries[0]);
|
||||
|
||||
@@ -469,7 +451,7 @@ mod tests {
|
||||
|
||||
let mut settings = Settings::load(&settings_path);
|
||||
settings
|
||||
.link_css(&settings_path, "https://example.com/style.css".to_string(), false)
|
||||
.link_css(&settings_path, "https://example.com/style.css".to_string())
|
||||
.unwrap();
|
||||
let linked_id = css_entry_id(&settings.css_entries[0]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user