From caf2d506a7ece72b9857c95976d4c3d5494edd31 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Thu, 5 Feb 2026 12:19:47 -0700 Subject: [PATCH] feat(themes): add decoupled CSS theme system with lightningcss bundling - Add 6 syntax highlighting themes (dracula, gruvbox, nord, github) - Rewrite css.rs to use lightningcss bundler for @import resolution - Theme CSS is inlined at build time, producing single bundled output --- docs/static/style.css | 124 +------------- src/css.rs | 126 +++++++++----- src/error.rs | 4 + src/main.rs | 19 +-- themes/default.css | 282 +++++++++++++++++++++++++++++++ themes/dracula.css | 341 ++++++++++++++++++++++++++++++++++++++ themes/github_dark.css | 332 +++++++++++++++++++++++++++++++++++++ themes/github_light.css | 332 +++++++++++++++++++++++++++++++++++++ themes/gruvbox.css | 340 ++++++++++++++++++++++++++++++++++++++ themes/nord.css | 355 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 2083 insertions(+), 172 deletions(-) create mode 100644 themes/default.css create mode 100644 themes/dracula.css create mode 100644 themes/github_dark.css create mode 100644 themes/github_light.css create mode 100644 themes/gruvbox.css create mode 100644 themes/nord.css diff --git a/docs/static/style.css b/docs/static/style.css index b98670d..f7be9a7 100644 --- a/docs/static/style.css +++ b/docs/static/style.css @@ -1,4 +1,6 @@ /* sukr docs — clean documentation theme */ +@import "../../themes/default.css"; +/* Syntax highlighting theme - lightningcss inlines this at build time */ :root { --bg: #0d1117; @@ -313,128 +315,6 @@ pre code { padding: 0; } -/* Syntax highlighting (tree-sitter classes) - * Dracula-inspired color scheme with full coverage - * All colors chosen to work well on dark backgrounds - */ - -/* Keywords: control flow, declarations - Pink */ -.hl-keyword { - color: #ff79c6; -} - -/* Strings and literals - Yellow */ -.hl-string, -.hl-string-special { - color: #f1fa8c; -} - -.hl-string-escape { - color: #ffb86c; -} - -.hl-string-special-path, -.hl-string-special-uri { - color: #8be9fd; - text-decoration: underline; -} - -/* Functions and methods - Green */ -.hl-function, -.hl-function-builtin { - color: #50fa7b; -} - -/* Comments - Muted blue-gray */ -.hl-comment { - color: #6272a4; - font-style: italic; -} - -/* Numbers and constants - Purple */ -.hl-number, -.hl-constant, -.hl-constant-builtin { - color: #bd93f9; -} - -/* Operators - Pink (same as keywords for visual consistency) */ -.hl-operator { - color: #ff79c6; -} - -/* Punctuation - Subtle muted */ -.hl-punctuation, -.hl-punctuation-bracket, -.hl-punctuation-delimiter { - color: var(--fg-muted); -} - -.hl-punctuation-special { - color: #ff79c6; -} - -/* Types - Cyan */ -.hl-type, -.hl-type-builtin { - color: #8be9fd; -} - -/* Variables - Light foreground */ -.hl-variable { - color: var(--fg); -} - -.hl-variable-builtin { - color: #ffb86c; -} - -.hl-variable-parameter { - color: #ffb86c; - font-style: italic; -} - -/* Properties and attributes - Cyan */ -.hl-property, -.hl-attribute { - color: #8be9fd; -} - -/* Constructors - Green */ -.hl-constructor { - color: #50fa7b; -} - -/* HTML/XML tags - Pink */ -.hl-tag { - color: #ff79c6; -} - -/* Embedded/escape content - Orange */ -.hl-embedded, -.hl-escape { - color: #ffb86c; -} - -/* Markdown-specific text highlighting */ -.hl-text-title { - color: #ff79c6; - font-weight: bold; -} - -.hl-text-literal { - color: #8be9fd; -} - -.hl-text-uri { - color: #8be9fd; - text-decoration: underline; -} - -.hl-text-reference { - color: #bd93f9; -} - /* Mermaid diagrams */ .mermaid-diagram { margin: 1.5rem 0; diff --git a/src/css.rs b/src/css.rs index 48c1bbd..81bccf2 100644 --- a/src/css.rs +++ b/src/css.rs @@ -1,31 +1,38 @@ //! CSS processing via lightningcss. +//! +//! Provides CSS bundling and minification. The bundler resolves `@import` +//! rules at build time, inlining imported files into a single output. -use lightningcss::stylesheet::{MinifyOptions, ParserOptions, PrinterOptions, StyleSheet}; +use lightningcss::bundler::{Bundler, FileProvider}; +use lightningcss::stylesheet::{MinifyOptions, ParserOptions, PrinterOptions}; +use std::path::Path; -/// Minify CSS content. +/// Bundle and minify a CSS file, resolving all `@import` rules. /// -/// Returns minified CSS string on success, or the original input on error. -pub fn minify_css(css: &str) -> String { - match try_minify(css) { - Ok(minified) => minified, - Err(_) => css.to_string(), - } -} +/// This function: +/// 1. Reads the CSS file at `path` +/// 2. Resolves and inlines all `@import` rules (relative to source file) +/// 3. Minifies the combined output +/// +/// Returns minified CSS string on success, or an error message on failure. +pub fn bundle_css(path: &Path) -> Result { + let fs = FileProvider::new(); + let mut bundler = Bundler::new(&fs, None, ParserOptions::default()); -fn try_minify(css: &str) -> Result> { - let mut stylesheet = StyleSheet::parse(css, ParserOptions::default()) - .map_err(|e| format!("parse error: {:?}", e))?; + let mut stylesheet = bundler + .bundle(path) + .map_err(|e| format!("bundle error: {e}"))?; stylesheet .minify(MinifyOptions::default()) - .map_err(|e| format!("minify error: {:?}", e))?; + .map_err(|e| format!("minify error: {e}"))?; let result = stylesheet .to_css(PrinterOptions { minify: true, ..Default::default() }) - .map_err(|e| format!("print error: {:?}", e))?; + .map_err(|e| format!("print error: {e}"))?; Ok(result.code) } @@ -33,48 +40,89 @@ fn try_minify(css: &str) -> Result> { #[cfg(test)] mod tests { use super::*; + use std::fs; + use tempfile::TempDir; #[test] - fn test_minify_removes_whitespace() { - let input = r#" + fn test_bundle_minifies() { + let dir = TempDir::new().unwrap(); + let css_path = dir.path().join("test.css"); + fs::write( + &css_path, + r#" .foo { color: red; } - "#; - let output = minify_css(input); + "#, + ) + .unwrap(); - // Should be smaller (whitespace removed) - assert!(output.len() < input.len()); - // Should still contain the essential content + let output = bundle_css(&css_path).unwrap(); + + // Should be minified (whitespace removed) assert!(output.contains(".foo")); - assert!(output.contains("color")); assert!(output.contains("red")); + assert!(!output.contains('\n')); } #[test] - fn test_minify_removes_comments() { - let input = r#" + fn test_bundle_resolves_imports() { + let dir = TempDir::new().unwrap(); + + // Create imported file + let imported_path = dir.path().join("colors.css"); + fs::write( + &imported_path, + r#" + :root { + --primary: blue; + } + "#, + ) + .unwrap(); + + // Create main file that imports colors.css + let main_path = dir.path().join("main.css"); + fs::write( + &main_path, + r#" + @import "colors.css"; + + .btn { + color: var(--primary); + } + "#, + ) + .unwrap(); + + let output = bundle_css(&main_path).unwrap(); + + // Should contain content from both files + assert!(output.contains("--primary")); + assert!(output.contains("blue")); + assert!(output.contains(".btn")); + // Should NOT contain @import directive + assert!(!output.contains("@import")); + } + + #[test] + fn test_bundle_removes_comments() { + let dir = TempDir::new().unwrap(); + let css_path = dir.path().join("test.css"); + fs::write( + &css_path, + r#" /* This is a comment */ .bar { background: blue; } - "#; - let output = minify_css(input); + "#, + ) + .unwrap(); + + let output = bundle_css(&css_path).unwrap(); // Comment should be removed assert!(!output.contains("This is a comment")); // Rule should remain assert!(output.contains(".bar")); } - - #[test] - fn test_minify_merges_selectors() { - let input = r#" - .foo { color: red; } - .bar { color: red; } - "#; - let output = minify_css(input); - - // Should merge identical rules - // Either ".foo,.bar" or ".bar,.foo" pattern - assert!(output.contains(",")); - } } diff --git a/src/error.rs b/src/error.rs index 3e9c81d..f20c1a5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -52,6 +52,10 @@ pub enum Error { #[source] source: tera::Error, }, + + /// Failed to bundle CSS. + #[error("CSS bundle error: {0}")] + CssBundle(String), } /// Result type alias for compiler operations. diff --git a/src/main.rs b/src/main.rs index 888b1bb..312c6f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -338,7 +338,7 @@ fn write_output( /// Copy static assets (CSS, images, etc.) to output directory. /// CSS files are minified before writing. fn copy_static_assets(static_dir: &Path, output_dir: &Path) -> Result<()> { - use crate::css::minify_css; + use crate::css::bundle_css; if !static_dir.exists() { return Ok(()); // No static dir is fine @@ -365,23 +365,20 @@ fn copy_static_assets(static_dir: &Path, output_dir: &Path) -> Result<()> { })?; } - // Minify CSS files, copy others directly + // Bundle CSS files (resolves @imports), copy others directly if src.extension().is_some_and(|ext| ext == "css") { - let css = fs::read_to_string(src).map_err(|e| Error::ReadFile { - path: src.to_path_buf(), - source: e, - })?; - let minified = minify_css(&css); - fs::write(&dest, &minified).map_err(|e| Error::WriteFile { + let original_size = fs::metadata(src).map(|m| m.len()).unwrap_or(0); + let bundled = bundle_css(src).map_err(Error::CssBundle)?; + fs::write(&dest, &bundled).map_err(|e| Error::WriteFile { path: dest.clone(), source: e, })?; eprintln!( - "minifying: {} → {} ({} → {} bytes)", + "bundling: {} → {} ({} → {} bytes)", src.display(), dest.display(), - css.len(), - minified.len() + original_size, + bundled.len() ); } else { fs::copy(src, &dest).map_err(|e| Error::WriteFile { diff --git a/themes/default.css b/themes/default.css new file mode 100644 index 0000000..acd489c --- /dev/null +++ b/themes/default.css @@ -0,0 +1,282 @@ +/* Sukr Default Theme (Dracula-inspired) + * Syntax highlighting for code blocks + * + * Use with: @import 'themes/default.css'; + * Or copy to your site's static/style.css + */ + +:root { + /* Dracula Palette */ + --hl-bg: #282a36; + --hl-fg: #f8f8f2; + --hl-comment: #6272a4; + --hl-cyan: #8be9fd; + --hl-green: #50fa7b; + --hl-orange: #ffb86c; + --hl-pink: #ff79c6; + --hl-purple: #bd93f9; + --hl-red: #ff5555; + --hl-yellow: #f1fa8c; +} + +/* Keywords */ +.hl-keyword { + color: var(--hl-pink); +} +.hl-keyword-control { + color: var(--hl-pink); +} +.hl-keyword-control-conditional { + color: var(--hl-pink); +} +.hl-keyword-control-repeat { + color: var(--hl-pink); +} +.hl-keyword-control-import { + color: var(--hl-pink); +} +.hl-keyword-control-return { + color: var(--hl-pink); +} +.hl-keyword-control-exception { + color: var(--hl-purple); +} +.hl-keyword-operator { + color: var(--hl-pink); +} +.hl-keyword-directive { + color: var(--hl-green); +} +.hl-keyword-function { + color: var(--hl-pink); +} +.hl-keyword-return { + color: var(--hl-pink); +} +.hl-keyword-storage { + color: var(--hl-pink); +} +.hl-keyword-storage-type { + color: var(--hl-cyan); + font-style: italic; +} +.hl-keyword-storage-modifier { + color: var(--hl-pink); +} +.hl-keyword-storage-modifier-mut { + color: var(--hl-pink); +} +.hl-keyword-storage-modifier-ref { + color: var(--hl-pink); +} +.hl-keyword-special { + color: var(--hl-pink); +} + +/* Functions */ +.hl-function { + color: var(--hl-green); +} +.hl-function-builtin { + color: var(--hl-green); +} +.hl-function-call { + color: var(--hl-green); +} +.hl-function-macro { + color: var(--hl-purple); +} +.hl-function-method { + color: var(--hl-green); +} + +/* Types */ +.hl-type { + color: var(--hl-cyan); + font-style: italic; +} +.hl-type-builtin { + color: var(--hl-cyan); +} +.hl-type-parameter { + color: var(--hl-cyan); + font-style: italic; +} +.hl-type-enum-variant { + color: var(--hl-fg); + font-style: italic; +} +.hl-type-enum-variant-builtin { + color: var(--hl-fg); + font-style: italic; +} + +/* Constants */ +.hl-constant { + color: var(--hl-purple); +} +.hl-constant-builtin { + color: var(--hl-purple); +} +.hl-constant-builtin-boolean { + color: var(--hl-purple); +} +.hl-constant-character { + color: var(--hl-cyan); +} +.hl-constant-character-escape { + color: var(--hl-pink); +} +.hl-constant-macro { + color: var(--hl-purple); +} +.hl-constant-numeric { + color: var(--hl-purple); +} +.hl-constant-numeric-integer { + color: var(--hl-purple); +} +.hl-constant-numeric-float { + color: var(--hl-purple); +} + +/* Strings */ +.hl-string { + color: var(--hl-yellow); +} +.hl-string-regexp { + color: var(--hl-red); +} +.hl-string-special { + color: var(--hl-orange); +} +.hl-string-special-path { + color: var(--hl-orange); +} +.hl-string-special-symbol { + color: var(--hl-yellow); +} + +/* Variables */ +.hl-variable { + color: var(--hl-fg); +} +.hl-variable-builtin { + color: var(--hl-purple); + font-style: italic; +} +.hl-variable-parameter { + color: var(--hl-orange); + font-style: italic; +} +.hl-variable-other { + color: var(--hl-fg); +} +.hl-variable-other-member { + color: var(--hl-fg); +} + +/* Comments */ +.hl-comment { + color: var(--hl-comment); +} +.hl-comment-line { + color: var(--hl-comment); +} +.hl-comment-block { + color: var(--hl-comment); +} +.hl-comment-block-documentation { + color: var(--hl-comment); +} +.hl-comment-line-documentation { + color: var(--hl-comment); +} +.hl-comment-unused { + color: var(--hl-comment); + opacity: 0.6; +} + +/* Punctuation */ +.hl-punctuation { + color: var(--hl-fg); +} +.hl-punctuation-bracket { + color: var(--hl-fg); +} +.hl-punctuation-delimiter { + color: var(--hl-fg); +} +.hl-punctuation-special { + color: var(--hl-pink); +} + +/* Operators */ +.hl-operator { + color: var(--hl-pink); +} + +/* Other */ +.hl-attribute { + color: var(--hl-green); + font-style: italic; +} +.hl-label { + color: var(--hl-cyan); +} +.hl-namespace { + color: var(--hl-fg); +} +.hl-constructor { + color: var(--hl-purple); +} +.hl-special { + color: var(--hl-pink); +} +.hl-tag { + color: var(--hl-pink); +} +.hl-tag-attribute { + color: var(--hl-purple); +} +.hl-tag-delimiter { + color: var(--hl-fg); +} + +/* Markup (Markdown) */ +.hl-markup-bold { + color: var(--hl-orange); + font-weight: bold; +} +.hl-markup-italic { + color: var(--hl-yellow); + font-style: italic; +} +.hl-markup-strikethrough { + text-decoration: line-through; +} +.hl-markup-heading { + color: var(--hl-purple); + font-weight: bold; +} +.hl-markup-link-text { + color: var(--hl-pink); +} +.hl-markup-link-url { + color: var(--hl-cyan); +} +.hl-markup-list { + color: var(--hl-cyan); +} +.hl-markup-quote { + color: var(--hl-yellow); + font-style: italic; +} +.hl-markup-raw { + color: var(--hl-fg); +} + +/* Unknown scope fallback */ +.hl-unknown { + color: var(--hl-fg); +} diff --git a/themes/dracula.css b/themes/dracula.css new file mode 100644 index 0000000..adf97a0 --- /dev/null +++ b/themes/dracula.css @@ -0,0 +1,341 @@ +/* Dracula Theme for Sukr + * Based on https://draculatheme.com/ + * Ported from Helix editor theme + */ + +:root { + --hl-bg: #282a36; + --hl-fg: #f8f8f2; + --hl-comment: #6272a4; + --hl-cyan: #8be9fd; + --hl-green: #50fa7b; + --hl-orange: #ffb86c; + --hl-pink: #ff79c6; + --hl-purple: #bd93f9; + --hl-red: #ff5555; + --hl-yellow: #f1fa8c; +} + +/* Keywords */ +.hl-keyword { + color: var(--hl-pink); +} + +.hl-keyword-control { + color: var(--hl-pink); +} + +.hl-keyword-control-conditional { + color: var(--hl-pink); +} + +.hl-keyword-control-repeat { + color: var(--hl-pink); +} + +.hl-keyword-control-import { + color: var(--hl-pink); +} + +.hl-keyword-control-return { + color: var(--hl-pink); +} + +.hl-keyword-control-exception { + color: var(--hl-purple); +} + +.hl-keyword-operator { + color: var(--hl-pink); +} + +.hl-keyword-directive { + color: var(--hl-green); +} + +.hl-keyword-function { + color: var(--hl-pink); +} + +.hl-keyword-return { + color: var(--hl-pink); +} + +.hl-keyword-storage { + color: var(--hl-pink); +} + +.hl-keyword-storage-type { + color: var(--hl-cyan); + font-style: italic; +} + +.hl-keyword-storage-modifier { + color: var(--hl-pink); +} + +.hl-keyword-storage-modifier-mut { + color: var(--hl-pink); +} + +.hl-keyword-storage-modifier-ref { + color: var(--hl-pink); +} + +.hl-keyword-special { + color: var(--hl-pink); +} + +/* Functions */ +.hl-function { + color: var(--hl-green); +} + +.hl-function-builtin { + color: var(--hl-green); +} + +.hl-function-call { + color: var(--hl-green); +} + +.hl-function-macro { + color: var(--hl-purple); +} + +.hl-function-method { + color: var(--hl-green); +} + +/* Types */ +.hl-type { + color: var(--hl-cyan); + font-style: italic; +} + +.hl-type-builtin { + color: var(--hl-cyan); +} + +.hl-type-parameter { + color: var(--hl-cyan); + font-style: italic; +} + +.hl-type-enum-variant { + color: var(--hl-fg); + font-style: italic; +} + +.hl-type-enum-variant-builtin { + color: var(--hl-fg); + font-style: italic; +} + +/* Constants */ +.hl-constant { + color: var(--hl-purple); +} + +.hl-constant-builtin { + color: var(--hl-purple); +} + +.hl-constant-builtin-boolean { + color: var(--hl-purple); +} + +.hl-constant-character { + color: var(--hl-cyan); +} + +.hl-constant-character-escape { + color: var(--hl-pink); +} + +.hl-constant-macro { + color: var(--hl-purple); +} + +.hl-constant-numeric { + color: var(--hl-purple); +} + +.hl-constant-numeric-integer { + color: var(--hl-purple); +} + +.hl-constant-numeric-float { + color: var(--hl-purple); +} + +/* Strings */ +.hl-string { + color: var(--hl-yellow); +} + +.hl-string-regexp { + color: var(--hl-red); +} + +.hl-string-special { + color: var(--hl-orange); +} + +.hl-string-special-path { + color: var(--hl-orange); +} + +.hl-string-special-symbol { + color: var(--hl-yellow); +} + +/* Variables */ +.hl-variable { + color: var(--hl-fg); +} + +.hl-variable-builtin { + color: var(--hl-purple); + font-style: italic; +} + +.hl-variable-parameter { + color: var(--hl-orange); + font-style: italic; +} + +.hl-variable-other { + color: var(--hl-fg); +} + +.hl-variable-other-member { + color: var(--hl-fg); +} + +/* Comments */ +.hl-comment { + color: var(--hl-comment); +} + +.hl-comment-line { + color: var(--hl-comment); +} + +.hl-comment-block { + color: var(--hl-comment); +} + +.hl-comment-block-documentation { + color: var(--hl-comment); +} + +.hl-comment-line-documentation { + color: var(--hl-comment); +} + +.hl-comment-unused { + color: var(--hl-comment); + opacity: 0.6; +} + +/* Punctuation */ +.hl-punctuation { + color: var(--hl-fg); +} + +.hl-punctuation-bracket { + color: var(--hl-fg); +} + +.hl-punctuation-delimiter { + color: var(--hl-fg); +} + +.hl-punctuation-special { + color: var(--hl-pink); +} + +/* Operators */ +.hl-operator { + color: var(--hl-pink); +} + +/* Other */ +.hl-attribute { + color: var(--hl-green); + font-style: italic; +} + +.hl-label { + color: var(--hl-cyan); +} + +.hl-namespace { + color: var(--hl-fg); +} + +.hl-constructor { + color: var(--hl-purple); +} + +.hl-special { + color: var(--hl-pink); +} + +.hl-tag { + color: var(--hl-pink); +} + +.hl-tag-attribute { + color: var(--hl-purple); +} + +.hl-tag-delimiter { + color: var(--hl-fg); +} + +/* Markup */ +.hl-markup-bold { + color: var(--hl-orange); + font-weight: bold; +} + +.hl-markup-italic { + color: var(--hl-yellow); + font-style: italic; +} + +.hl-markup-strikethrough { + text-decoration: line-through; +} + +.hl-markup-heading { + color: var(--hl-purple); + font-weight: bold; +} + +.hl-markup-link-text { + color: var(--hl-pink); +} + +.hl-markup-link-url { + color: var(--hl-cyan); +} + +.hl-markup-list { + color: var(--hl-cyan); +} + +.hl-markup-quote { + color: var(--hl-yellow); + font-style: italic; +} + +.hl-markup-raw { + color: var(--hl-fg); +} + +.hl-unknown { + color: var(--hl-fg); +} diff --git a/themes/github_dark.css b/themes/github_dark.css new file mode 100644 index 0000000..440f2cb --- /dev/null +++ b/themes/github_dark.css @@ -0,0 +1,332 @@ +/* GitHub Dark Theme for Sukr + * Based on https://primer.style/primitives/colors + * Ported from Helix editor theme + */ + +:root { + /* GitHub Dark Palette */ + --hl-bg: #0d1117; + --hl-fg: #c9d1d9; + --hl-muted: #8b949e; + --hl-red: #ff7b72; + --hl-orange: #ffa657; + --hl-blue-light: #a5d6ff; + --hl-blue: #79c0ff; + --hl-purple: #d2a8ff; + --hl-green: #7ee787; +} + +/* Keywords */ +.hl-keyword { + color: var(--hl-red); +} + +.hl-keyword-control { + color: var(--hl-red); +} + +.hl-keyword-control-conditional { + color: var(--hl-red); +} + +.hl-keyword-control-repeat { + color: var(--hl-red); +} + +.hl-keyword-control-import { + color: var(--hl-red); +} + +.hl-keyword-control-return { + color: var(--hl-red); +} + +.hl-keyword-control-exception { + color: var(--hl-red); +} + +.hl-keyword-operator { + color: var(--hl-red); +} + +.hl-keyword-directive { + color: var(--hl-red); +} + +.hl-keyword-function { + color: var(--hl-red); +} + +.hl-keyword-return { + color: var(--hl-red); +} + +.hl-keyword-storage { + color: var(--hl-red); +} + +.hl-keyword-storage-type { + color: var(--hl-blue); +} + +.hl-keyword-storage-modifier { + color: var(--hl-red); +} + +.hl-keyword-storage-modifier-mut { + color: var(--hl-red); +} + +.hl-keyword-storage-modifier-ref { + color: var(--hl-red); +} + +.hl-keyword-special { + color: var(--hl-red); +} + +/* Functions */ +.hl-function { + color: var(--hl-purple); +} + +.hl-function-builtin { + color: var(--hl-purple); +} + +.hl-function-call { + color: var(--hl-purple); +} + +.hl-function-macro { + color: var(--hl-purple); +} + +.hl-function-method { + color: var(--hl-purple); +} + +/* Types */ +.hl-type { + color: var(--hl-orange); +} + +.hl-type-builtin { + color: var(--hl-blue); +} + +.hl-type-parameter { + color: var(--hl-orange); +} + +.hl-type-enum-variant { + color: var(--hl-fg); + font-style: italic; +} + +.hl-type-enum-variant-builtin { + color: var(--hl-fg); + font-style: italic; +} + +/* Constants */ +.hl-constant { + color: var(--hl-blue); +} + +.hl-constant-builtin { + color: var(--hl-blue); +} + +.hl-constant-builtin-boolean { + color: var(--hl-blue); +} + +.hl-constant-character { + color: var(--hl-blue); +} + +.hl-constant-character-escape { + color: var(--hl-blue); +} + +.hl-constant-macro { + color: var(--hl-blue); +} + +.hl-constant-numeric { + color: var(--hl-blue); +} + +.hl-constant-numeric-integer { + color: var(--hl-blue); +} + +.hl-constant-numeric-float { + color: var(--hl-blue); +} + +/* Strings */ +.hl-string { + color: var(--hl-blue-light); +} + +.hl-string-regexp { + color: var(--hl-blue-light); +} + +.hl-string-special { + color: var(--hl-blue-light); +} + +.hl-string-special-path { + color: var(--hl-blue-light); +} + +.hl-string-special-symbol { + color: var(--hl-blue-light); +} + +/* Variables */ +.hl-variable { + color: var(--hl-fg); +} + +.hl-variable-builtin { + color: var(--hl-red); +} + +.hl-variable-parameter { + color: var(--hl-orange); +} + +.hl-variable-other { + color: var(--hl-fg); +} + +.hl-variable-other-member { + color: var(--hl-blue-light); +} + +/* Comments */ +.hl-comment { + color: var(--hl-muted); +} + +.hl-comment-line { + color: var(--hl-muted); +} + +.hl-comment-block { + color: var(--hl-muted); +} + +.hl-comment-block-documentation { + color: var(--hl-muted); +} + +.hl-comment-line-documentation { + color: var(--hl-muted); +} + +.hl-comment-unused { + color: var(--hl-muted); + opacity: 0.6; +} + +/* Punctuation */ +.hl-punctuation { + color: var(--hl-fg); +} + +.hl-punctuation-bracket { + color: var(--hl-fg); +} + +.hl-punctuation-delimiter { + color: var(--hl-fg); +} + +.hl-punctuation-special { + color: var(--hl-blue-light); +} + +/* Operators */ +.hl-operator { + color: var(--hl-blue-light); +} + +/* Other */ +.hl-attribute { + color: var(--hl-fg); +} + +.hl-label { + color: var(--hl-red); +} + +.hl-namespace { + color: var(--hl-orange); +} + +.hl-constructor { + color: var(--hl-purple); +} + +.hl-special { + color: var(--hl-blue-light); +} + +.hl-tag { + color: var(--hl-green); +} + +.hl-tag-attribute { + color: var(--hl-purple); +} + +.hl-tag-delimiter { + color: var(--hl-fg); +} + +/* Markup */ +.hl-markup-bold { + font-weight: bold; +} + +.hl-markup-italic { + font-style: italic; +} + +.hl-markup-strikethrough { + text-decoration: line-through; +} + +.hl-markup-heading { + color: var(--hl-blue); +} + +.hl-markup-link-text { + color: var(--hl-blue-light); + text-decoration: underline; +} + +.hl-markup-link-url { + text-decoration: underline; +} + +.hl-markup-list { + color: var(--hl-red); +} + +.hl-markup-quote { + font-style: italic; +} + +.hl-markup-raw { + color: var(--hl-blue); +} + +.hl-unknown { + color: var(--hl-fg); +} diff --git a/themes/github_light.css b/themes/github_light.css new file mode 100644 index 0000000..189bbf5 --- /dev/null +++ b/themes/github_light.css @@ -0,0 +1,332 @@ +/* GitHub Light Theme for Sukr + * Based on https://primer.style/primitives/colors + * Ported from Helix editor theme + */ + +:root { + /* GitHub Light Palette */ + --hl-bg: #ffffff; + --hl-fg: #24292f; + --hl-muted: #57606a; + --hl-red: #cf222e; + --hl-orange: #953800; + --hl-blue: #0550ae; + --hl-blue-dark: #0a3069; + --hl-purple: #8250df; + --hl-green: #116329; +} + +/* Keywords */ +.hl-keyword { + color: var(--hl-red); +} + +.hl-keyword-control { + color: var(--hl-red); +} + +.hl-keyword-control-conditional { + color: var(--hl-red); +} + +.hl-keyword-control-repeat { + color: var(--hl-red); +} + +.hl-keyword-control-import { + color: var(--hl-red); +} + +.hl-keyword-control-return { + color: var(--hl-red); +} + +.hl-keyword-control-exception { + color: var(--hl-red); +} + +.hl-keyword-operator { + color: var(--hl-red); +} + +.hl-keyword-directive { + color: var(--hl-red); +} + +.hl-keyword-function { + color: var(--hl-red); +} + +.hl-keyword-return { + color: var(--hl-red); +} + +.hl-keyword-storage { + color: var(--hl-red); +} + +.hl-keyword-storage-type { + color: var(--hl-blue); +} + +.hl-keyword-storage-modifier { + color: var(--hl-red); +} + +.hl-keyword-storage-modifier-mut { + color: var(--hl-red); +} + +.hl-keyword-storage-modifier-ref { + color: var(--hl-red); +} + +.hl-keyword-special { + color: var(--hl-red); +} + +/* Functions */ +.hl-function { + color: var(--hl-purple); +} + +.hl-function-builtin { + color: var(--hl-purple); +} + +.hl-function-call { + color: var(--hl-purple); +} + +.hl-function-macro { + color: var(--hl-purple); +} + +.hl-function-method { + color: var(--hl-purple); +} + +/* Types */ +.hl-type { + color: var(--hl-orange); +} + +.hl-type-builtin { + color: var(--hl-blue); +} + +.hl-type-parameter { + color: var(--hl-orange); +} + +.hl-type-enum-variant { + color: var(--hl-fg); + font-style: italic; +} + +.hl-type-enum-variant-builtin { + color: var(--hl-fg); + font-style: italic; +} + +/* Constants */ +.hl-constant { + color: var(--hl-blue); +} + +.hl-constant-builtin { + color: var(--hl-blue); +} + +.hl-constant-builtin-boolean { + color: var(--hl-blue); +} + +.hl-constant-character { + color: var(--hl-blue); +} + +.hl-constant-character-escape { + color: var(--hl-blue); +} + +.hl-constant-macro { + color: var(--hl-blue); +} + +.hl-constant-numeric { + color: var(--hl-blue); +} + +.hl-constant-numeric-integer { + color: var(--hl-blue); +} + +.hl-constant-numeric-float { + color: var(--hl-blue); +} + +/* Strings */ +.hl-string { + color: var(--hl-blue-dark); +} + +.hl-string-regexp { + color: var(--hl-blue-dark); +} + +.hl-string-special { + color: var(--hl-blue-dark); +} + +.hl-string-special-path { + color: var(--hl-blue-dark); +} + +.hl-string-special-symbol { + color: var(--hl-blue-dark); +} + +/* Variables */ +.hl-variable { + color: var(--hl-fg); +} + +.hl-variable-builtin { + color: var(--hl-red); +} + +.hl-variable-parameter { + color: var(--hl-orange); +} + +.hl-variable-other { + color: var(--hl-fg); +} + +.hl-variable-other-member { + color: var(--hl-blue-dark); +} + +/* Comments */ +.hl-comment { + color: var(--hl-muted); +} + +.hl-comment-line { + color: var(--hl-muted); +} + +.hl-comment-block { + color: var(--hl-muted); +} + +.hl-comment-block-documentation { + color: var(--hl-muted); +} + +.hl-comment-line-documentation { + color: var(--hl-muted); +} + +.hl-comment-unused { + color: var(--hl-muted); + opacity: 0.6; +} + +/* Punctuation */ +.hl-punctuation { + color: var(--hl-fg); +} + +.hl-punctuation-bracket { + color: var(--hl-fg); +} + +.hl-punctuation-delimiter { + color: var(--hl-fg); +} + +.hl-punctuation-special { + color: var(--hl-blue-dark); +} + +/* Operators */ +.hl-operator { + color: var(--hl-blue-dark); +} + +/* Other */ +.hl-attribute { + color: var(--hl-fg); +} + +.hl-label { + color: var(--hl-red); +} + +.hl-namespace { + color: var(--hl-orange); +} + +.hl-constructor { + color: var(--hl-purple); +} + +.hl-special { + color: var(--hl-blue-dark); +} + +.hl-tag { + color: var(--hl-green); +} + +.hl-tag-attribute { + color: var(--hl-purple); +} + +.hl-tag-delimiter { + color: var(--hl-fg); +} + +/* Markup */ +.hl-markup-bold { + font-weight: bold; +} + +.hl-markup-italic { + font-style: italic; +} + +.hl-markup-strikethrough { + text-decoration: line-through; +} + +.hl-markup-heading { + color: var(--hl-blue); +} + +.hl-markup-link-text { + color: var(--hl-blue-dark); + text-decoration: underline; +} + +.hl-markup-link-url { + text-decoration: underline; +} + +.hl-markup-list { + color: var(--hl-red); +} + +.hl-markup-quote { + font-style: italic; +} + +.hl-markup-raw { + color: var(--hl-blue); +} + +.hl-unknown { + color: var(--hl-fg); +} diff --git a/themes/gruvbox.css b/themes/gruvbox.css new file mode 100644 index 0000000..e56bd3a --- /dev/null +++ b/themes/gruvbox.css @@ -0,0 +1,340 @@ +/* Gruvbox Theme for Sukr + * Based on https://github.com/morhetz/gruvbox + * Ported from Helix editor theme + */ + +:root { + --hl-bg: #282828; + --hl-fg: #ebdbb2; + --hl-gray: #928374; + --hl-red: #fb4934; + --hl-green: #b8bb26; + --hl-yellow: #fabd2f; + --hl-blue: #83a598; + --hl-purple: #d3869b; + --hl-aqua: #8ec07c; + --hl-orange: #fe8019; +} + +/* Keywords */ +.hl-keyword { + color: var(--hl-red); +} + +.hl-keyword-control { + color: var(--hl-red); +} + +.hl-keyword-control-conditional { + color: var(--hl-red); +} + +.hl-keyword-control-repeat { + color: var(--hl-red); +} + +.hl-keyword-control-import { + color: var(--hl-aqua); +} + +.hl-keyword-control-return { + color: var(--hl-red); +} + +.hl-keyword-control-exception { + color: var(--hl-red); +} + +.hl-keyword-operator { + color: var(--hl-red); +} + +.hl-keyword-directive { + color: var(--hl-aqua); +} + +.hl-keyword-function { + color: var(--hl-red); +} + +.hl-keyword-return { + color: var(--hl-red); +} + +.hl-keyword-storage { + color: var(--hl-red); +} + +.hl-keyword-storage-type { + color: var(--hl-yellow); +} + +.hl-keyword-storage-modifier { + color: var(--hl-red); +} + +.hl-keyword-storage-modifier-mut { + color: var(--hl-red); +} + +.hl-keyword-storage-modifier-ref { + color: var(--hl-red); +} + +.hl-keyword-special { + color: var(--hl-red); +} + +/* Functions */ +.hl-function { + color: var(--hl-green); +} + +.hl-function-builtin { + color: var(--hl-yellow); +} + +.hl-function-call { + color: var(--hl-green); +} + +.hl-function-macro { + color: var(--hl-blue); +} + +.hl-function-method { + color: var(--hl-green); +} + +/* Types */ +.hl-type { + color: var(--hl-yellow); +} + +.hl-type-builtin { + color: var(--hl-yellow); +} + +.hl-type-parameter { + color: var(--hl-yellow); +} + +.hl-type-enum-variant { + color: var(--hl-fg); + font-style: italic; +} + +.hl-type-enum-variant-builtin { + color: var(--hl-fg); + font-style: italic; +} + +/* Constants */ +.hl-constant { + color: var(--hl-purple); +} + +.hl-constant-builtin { + color: var(--hl-purple); +} + +.hl-constant-builtin-boolean { + color: var(--hl-purple); +} + +.hl-constant-character { + color: var(--hl-aqua); +} + +.hl-constant-character-escape { + color: var(--hl-orange); +} + +.hl-constant-macro { + color: var(--hl-aqua); +} + +.hl-constant-numeric { + color: var(--hl-purple); +} + +.hl-constant-numeric-integer { + color: var(--hl-purple); +} + +.hl-constant-numeric-float { + color: var(--hl-purple); +} + +/* Strings */ +.hl-string { + color: var(--hl-green); +} + +.hl-string-regexp { + color: var(--hl-orange); +} + +.hl-string-special { + color: var(--hl-orange); +} + +.hl-string-special-path { + color: var(--hl-orange); +} + +.hl-string-special-symbol { + color: var(--hl-yellow); +} + +/* Variables */ +.hl-variable { + color: var(--hl-fg); +} + +.hl-variable-builtin { + color: var(--hl-orange); + font-style: italic; +} + +.hl-variable-parameter { + color: var(--hl-blue); + font-style: italic; +} + +.hl-variable-other { + color: var(--hl-fg); +} + +.hl-variable-other-member { + color: var(--hl-blue); +} + +/* Comments */ +.hl-comment { + color: var(--hl-gray); + font-style: italic; +} + +.hl-comment-line { + color: var(--hl-gray); + font-style: italic; +} + +.hl-comment-block { + color: var(--hl-gray); + font-style: italic; +} + +.hl-comment-block-documentation { + color: var(--hl-gray); + font-style: italic; +} + +.hl-comment-line-documentation { + color: var(--hl-gray); + font-style: italic; +} + +.hl-comment-unused { + color: var(--hl-gray); + opacity: 0.6; +} + +/* Punctuation */ +.hl-punctuation { + color: var(--hl-orange); +} + +.hl-punctuation-bracket { + color: var(--hl-orange); +} + +.hl-punctuation-delimiter { + color: var(--hl-orange); +} + +.hl-punctuation-special { + color: var(--hl-orange); +} + +/* Operators */ +.hl-operator { + color: var(--hl-purple); +} + +/* Other */ +.hl-attribute { + color: var(--hl-aqua); + font-style: italic; +} + +.hl-label { + color: var(--hl-red); +} + +.hl-namespace { + color: var(--hl-fg); +} + +.hl-constructor { + color: var(--hl-purple); +} + +.hl-special { + color: var(--hl-purple); +} + +.hl-tag { + color: var(--hl-aqua); +} + +.hl-tag-attribute { + color: var(--hl-aqua); +} + +.hl-tag-delimiter { + color: var(--hl-fg); +} + +/* Markup */ +.hl-markup-bold { + font-weight: bold; +} + +.hl-markup-italic { + font-style: italic; +} + +.hl-markup-strikethrough { + text-decoration: line-through; +} + +.hl-markup-heading { + color: var(--hl-aqua); +} + +.hl-markup-link-text { + color: var(--hl-red); +} + +.hl-markup-link-url { + color: var(--hl-green); + text-decoration: underline; +} + +.hl-markup-list { + color: var(--hl-aqua); +} + +.hl-markup-quote { + font-style: italic; +} + +.hl-markup-raw { + color: var(--hl-red); +} + +.hl-unknown { + color: var(--hl-fg); +} diff --git a/themes/nord.css b/themes/nord.css new file mode 100644 index 0000000..a2d41db --- /dev/null +++ b/themes/nord.css @@ -0,0 +1,355 @@ +/* Nord Theme for Sukr + * Based on https://www.nordtheme.com/ + * Ported from Helix editor theme + */ + +:root { + /* Polar Night */ + --hl-nord0: #2e3440; + --hl-nord1: #3b4252; + --hl-nord2: #434c5e; + --hl-nord3: #4c566a; + --hl-nord3-bright: #616e88; + + /* Snow Storm */ + --hl-nord4: #d8dee9; + --hl-nord5: #e5e9f0; + --hl-nord6: #eceff4; + + /* Frost */ + --hl-nord7: #8fbcbb; + --hl-nord8: #88c0d0; + --hl-nord9: #81a1c1; + --hl-nord10: #5e81ac; + + /* Aurora */ + --hl-nord11: #bf616a; + --hl-nord12: #d08770; + --hl-nord13: #ebcb8b; + --hl-nord14: #a3be8c; + --hl-nord15: #b48ead; + + /* Semantic aliases */ + --hl-bg: var(--hl-nord0); + --hl-fg: var(--hl-nord4); + --hl-comment: var(--hl-nord3-bright); +} + +/* Keywords */ +.hl-keyword { + color: var(--hl-nord9); +} + +.hl-keyword-control { + color: var(--hl-nord9); +} + +.hl-keyword-control-conditional { + color: var(--hl-nord9); +} + +.hl-keyword-control-repeat { + color: var(--hl-nord9); +} + +.hl-keyword-control-import { + color: var(--hl-nord9); +} + +.hl-keyword-control-return { + color: var(--hl-nord9); +} + +.hl-keyword-control-exception { + color: var(--hl-nord9); +} + +.hl-keyword-operator { + color: var(--hl-nord9); +} + +.hl-keyword-directive { + color: var(--hl-nord9); +} + +.hl-keyword-function { + color: var(--hl-nord9); +} + +.hl-keyword-return { + color: var(--hl-nord9); +} + +.hl-keyword-storage { + color: var(--hl-nord9); +} + +.hl-keyword-storage-type { + color: var(--hl-nord9); +} + +.hl-keyword-storage-modifier { + color: var(--hl-nord9); +} + +.hl-keyword-storage-modifier-mut { + color: var(--hl-nord9); +} + +.hl-keyword-storage-modifier-ref { + color: var(--hl-nord9); +} + +.hl-keyword-special { + color: var(--hl-nord9); +} + +/* Functions */ +.hl-function { + color: var(--hl-nord8); +} + +.hl-function-builtin { + color: var(--hl-nord7); +} + +.hl-function-call { + color: var(--hl-nord8); +} + +.hl-function-macro { + color: var(--hl-nord9); +} + +.hl-function-method { + color: var(--hl-nord8); +} + +/* Types */ +.hl-type { + color: var(--hl-nord7); +} + +.hl-type-builtin { + color: var(--hl-nord7); +} + +.hl-type-parameter { + color: var(--hl-nord7); +} + +.hl-type-enum-variant { + color: var(--hl-nord4); + font-style: italic; +} + +.hl-type-enum-variant-builtin { + color: var(--hl-nord4); + font-style: italic; +} + +/* Constants */ +.hl-constant { + color: var(--hl-nord4); +} + +.hl-constant-builtin { + color: var(--hl-nord9); +} + +.hl-constant-builtin-boolean { + color: var(--hl-nord9); +} + +.hl-constant-character { + color: var(--hl-nord15); +} + +.hl-constant-character-escape { + color: var(--hl-nord13); +} + +.hl-constant-macro { + color: var(--hl-nord9); +} + +.hl-constant-numeric { + color: var(--hl-nord15); +} + +.hl-constant-numeric-integer { + color: var(--hl-nord15); +} + +.hl-constant-numeric-float { + color: var(--hl-nord15); +} + +/* Strings */ +.hl-string { + color: var(--hl-nord14); +} + +.hl-string-regexp { + color: var(--hl-nord13); +} + +.hl-string-special { + color: var(--hl-nord13); +} + +.hl-string-special-path { + color: var(--hl-nord13); +} + +.hl-string-special-symbol { + color: var(--hl-nord13); +} + +/* Variables */ +.hl-variable { + color: var(--hl-nord4); +} + +.hl-variable-builtin { + color: var(--hl-nord9); +} + +.hl-variable-parameter { + color: var(--hl-nord8); +} + +.hl-variable-other { + color: var(--hl-nord4); +} + +.hl-variable-other-member { + color: var(--hl-nord4); +} + +/* Comments */ +.hl-comment { + color: var(--hl-nord3-bright); + font-style: italic; +} + +.hl-comment-line { + color: var(--hl-nord3-bright); + font-style: italic; +} + +.hl-comment-block { + color: var(--hl-nord3-bright); + font-style: italic; +} + +.hl-comment-block-documentation { + color: var(--hl-nord3-bright); + font-style: italic; +} + +.hl-comment-line-documentation { + color: var(--hl-nord3-bright); + font-style: italic; +} + +.hl-comment-unused { + color: var(--hl-nord3-bright); + opacity: 0.6; +} + +/* Punctuation */ +.hl-punctuation { + color: var(--hl-nord6); +} + +.hl-punctuation-bracket { + color: var(--hl-nord6); +} + +.hl-punctuation-delimiter { + color: var(--hl-nord6); +} + +.hl-punctuation-special { + color: var(--hl-nord9); +} + +/* Operators */ +.hl-operator { + color: var(--hl-nord9); +} + +/* Other */ +.hl-attribute { + color: var(--hl-nord9); +} + +.hl-label { + color: var(--hl-nord7); +} + +.hl-namespace { + color: var(--hl-nord4); +} + +.hl-constructor { + color: var(--hl-nord8); +} + +.hl-special { + color: var(--hl-nord9); +} + +.hl-tag { + color: var(--hl-nord7); +} + +.hl-tag-attribute { + color: var(--hl-nord9); +} + +.hl-tag-delimiter { + color: var(--hl-nord6); +} + +/* Markup */ +.hl-markup-bold { + font-weight: bold; +} + +.hl-markup-italic { + font-style: italic; +} + +.hl-markup-strikethrough { + text-decoration: line-through; +} + +.hl-markup-heading { + color: var(--hl-nord8); +} + +.hl-markup-link-text { + color: var(--hl-nord8); +} + +.hl-markup-link-url { + color: var(--hl-nord9); +} + +.hl-markup-list { + color: var(--hl-nord9); +} + +.hl-markup-quote { + font-style: italic; +} + +.hl-markup-raw { + color: var(--hl-nord7); +} + +.hl-unknown { + color: var(--hl-nord4); +}