From b424cb32a8cb4d2df566db5684799af763e4a3cb Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Tue, 27 Oct 2026 17:50:44 +0800 Subject: [PATCH] feat(themes): Solarized and One theme plugins; plugin themes from the first frame Add two contribution-only theme plugins, each with a light and a dark theme that sets every UI token plus an editor colour scheme with syntax, editor and terminal ANSI colours: - plugins/theme-solarized: Solarized Light, Solarized Dark - plugins/theme-one: One Light, One Dark (Atom One, original HSL values) They replace the partial theme-solarized-dark sample. Each package ships the MIT notice of its palette in LICENSE, which is now copied on install with the files the manifest references. scripts/theme checks every theme plugin in plugins/ against the token list of tokens.css. Theme handling that any theme benefits from: - Start-up: boot.js restores the selected plugin theme's stylesheet and the last resolved frame, text and accent colours before any CSS loads, so the splash and workbench no longer show the built-in theme until the plugin host answers. The UI keeps the boot theme until the first plugin list, and the list now waits for the initial plugin load. - Native windows: the UI reports the plugin theme's resolved frame colour, which the plugin host persists and new project windows open in. - hsl(), color-mix() and var() tokens are resolved to RGB for Tauri's window background, the native Settings window (hex) and Mermaid diagrams. - Mermaid, the terminal and the editor colour scheme follow switches between plugin themes of the same light / dark base; an explicit editor scheme now replaces a plugin theme's editor colours. Supersedes #85. Co-authored-by: bghtyu <3931591+bghtyu@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn --- THIRD_PARTY_LICENSES.md | 11 ++ crates/ide-plugin/src/lib.rs | 71 +++++++- crates/ide-plugin/tests/host.rs | 68 ++++++-- docs/plugins/themes.md | 30 +++- plugins/README.md | 3 +- plugins/theme-one/LICENSE | 60 +++++++ plugins/theme-one/plugin.toml | 17 ++ plugins/theme-one/themes/one-dark.scheme.json | 103 ++++++++++++ plugins/theme-one/themes/one-dark.theme.json | 142 ++++++++++++++++ .../theme-one/themes/one-light.scheme.json | 103 ++++++++++++ plugins/theme-one/themes/one-light.theme.json | 142 ++++++++++++++++ plugins/theme-solarized-dark/plugin.toml | 11 -- .../themes/solarized-dark.json | 64 -------- plugins/theme-solarized/LICENSE | 27 ++++ plugins/theme-solarized/plugin.toml | 17 ++ .../themes/solarized-dark.scheme.json | 103 ++++++++++++ .../themes/solarized-dark.theme.json | 142 ++++++++++++++++ .../themes/solarized-light.scheme.json | 103 ++++++++++++ .../themes/solarized-light.theme.json | 142 ++++++++++++++++ public/boot.js | 27 +++- public/splash.css | 17 +- scripts/theme/theme.test.ts | 69 +++++++- src-tauri/src/commands/mod.rs | 1 + src-tauri/src/commands/plugin.rs | 14 ++ src-tauri/src/windows.rs | 31 +++- src/bindings.ts | 5 + src/editor/core/colorSchemeRuntime.ts | 5 +- .../plugins/__tests__/plugins.test.tsx | 6 +- .../plugins/__tests__/startupTheme.test.ts | 153 ++++++++++++++++++ src/features/plugins/backend.ts | 66 +++++--- src/features/plugins/bridge.ts | 63 +++++++- .../settings/__tests__/dialog.test.tsx | 28 +++- src/features/settings/index.ts | 4 +- src/features/terminal/index.ts | 6 +- src/features/terminal/theme.ts | 31 +--- src/features/viewers/markdown/mermaid.test.ts | 62 ++++++- src/features/viewers/markdown/mermaid.ts | 18 ++- src/platform/colorScheme.test.ts | 34 ++++ src/platform/colorScheme.ts | 5 +- src/platform/cssColor.test.ts | 37 +++++ src/platform/cssColor.ts | 67 ++++++++ src/workbench/theme.test.ts | 44 +++++ src/workbench/theme.ts | 63 ++++++-- 43 files changed, 2035 insertions(+), 180 deletions(-) create mode 100644 plugins/theme-one/LICENSE create mode 100644 plugins/theme-one/plugin.toml create mode 100644 plugins/theme-one/themes/one-dark.scheme.json create mode 100644 plugins/theme-one/themes/one-dark.theme.json create mode 100644 plugins/theme-one/themes/one-light.scheme.json create mode 100644 plugins/theme-one/themes/one-light.theme.json delete mode 100644 plugins/theme-solarized-dark/plugin.toml delete mode 100644 plugins/theme-solarized-dark/themes/solarized-dark.json create mode 100644 plugins/theme-solarized/LICENSE create mode 100644 plugins/theme-solarized/plugin.toml create mode 100644 plugins/theme-solarized/themes/solarized-dark.scheme.json create mode 100644 plugins/theme-solarized/themes/solarized-dark.theme.json create mode 100644 plugins/theme-solarized/themes/solarized-light.scheme.json create mode 100644 plugins/theme-solarized/themes/solarized-light.theme.json create mode 100644 src/features/plugins/__tests__/startupTheme.test.ts create mode 100644 src/platform/cssColor.test.ts create mode 100644 src/platform/cssColor.ts create mode 100644 src/workbench/theme.test.ts diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index 7d02d1e7..ca12804a 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -100,6 +100,17 @@ c → cpp, php_only), node names adapted to the bundled grammar versions definitions re-kinded as `field` / `method`, and missing scopes, definitions and references added; each file's header notes its changes. +## Theme plugin palettes + +The sample theme plugins port MIT-licensed palettes; each package's `LICENSE` +holds the full notice and source revisions: + +- `plugins/theme-solarized/`: [Solarized](https://github.com/altercation/solarized), + Copyright (c) 2011 Ethan Schoonover. +- `plugins/theme-one/`: Atom [One Light](https://github.com/atom/one-light-syntax) / + [One Dark](https://github.com/atom/one-dark-syntax) syntax themes, Copyright (c) 2016 + GitHub Inc., and their UI themes, Copyright (c) 2014 GitHub Inc. + --- Apache License diff --git a/crates/ide-plugin/src/lib.rs b/crates/ide-plugin/src/lib.rs index af60d2be..093ff88d 100644 --- a/crates/ide-plugin/src/lib.rs +++ b/crates/ide-plugin/src/lib.rs @@ -29,14 +29,18 @@ pub use types::*; use ide_core::{IdeError, IdeResult}; use ide_language::LanguageConfig; -use parking_lot::{Mutex, RwLock}; +use parking_lot::{Condvar, Mutex, RwLock}; use runtime::{CallEffects, CallError, PluginEngine, Registrations, Runtime, RuntimeSetup}; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::path::{Path, PathBuf}; use std::sync::Arc; +use std::time::Duration; const STATE_FILE: &str = "state.json"; +/// Top-level files copied with a package on install besides those the manifest references. +const LICENSE_FILES: &[&str] = + &["LICENSE", "LICENSE.md", "LICENSE.txt", "NOTICE", "NOTICE.md", "NOTICE.txt", "COPYING"]; /// Dev plugins live here, relative to a project root. pub const DEV_PLUGINS_DIR: &str = ".openidea/plugins"; @@ -52,6 +56,10 @@ struct PersistedState { struct ThemeRef { plugin: String, theme: String, + /// The theme's window frame colour as the UI resolved it (`#rrggbb[aa]`), so + /// new windows open in it before the plugin is loaded. + #[serde(default, skip_serializing_if = "Option::is_none")] + frame: Option, } struct Meta { @@ -95,6 +103,8 @@ pub struct PluginHost { active_files: Arc>>, /// Serializes loading / unloading so concurrent windows can't race. lifecycle: Mutex<()>, + /// Set once the first [`load_all`](Self::load_all) has finished. + initial_load: (Mutex, Condvar), } impl PluginHost { @@ -114,6 +124,7 @@ impl PluginHost { state: Mutex::new(state), active_files: Arc::default(), lifecycle: Mutex::new(()), + initial_load: (Mutex::new(false), Condvar::new()), }) } @@ -129,9 +140,24 @@ impl PluginHost { self.load_dir(&dir, PluginSource::Installed, None); } } + let (done, cv) = &self.initial_load; + *done.lock() = true; + cv.notify_all(); self.emit(None, PluginEvent::CommandsChanged); } + /// Waits (at most `timeout`) for the first [`load_all`](Self::load_all), so a + /// listing made at startup already holds the installed plugins and the + /// selected theme. Returns whether loading has finished. + pub fn wait_initial_load(&self, timeout: Duration) -> bool { + let (done, cv) = &self.initial_load; + let mut done = done.lock(); + if !*done { + cv.wait_while_for(&mut done, |d| !*d, timeout); + } + *done + } + /// Loads new dev plugins from `/.openidea/plugins/` and unloads vanished ones. pub fn sync_project(&self, root: &Path) { let _guard = self.lifecycle.lock(); @@ -251,6 +277,11 @@ impl PluginHost { } std::fs::copy(src.join(file), to)?; } + for name in LICENSE_FILES { + if src.join(name).is_file() { + std::fs::copy(src.join(name), staging.join(name))?; + } + } if target.exists() { std::fs::remove_dir_all(&target)?; } @@ -345,13 +376,45 @@ impl PluginHost { } } self.state.lock().theme = - selection.map(|(plugin, theme)| ThemeRef { plugin: plugin.into(), theme: theme.into() }); + selection.map(|(plugin, theme)| ThemeRef { plugin: plugin.into(), theme: theme.into(), frame: None }); self.save_state(); let active = self.active_theme(); self.emit(None, PluginEvent::ThemeChanged { theme: active.clone() }); Ok(active) } + /// Records the selected theme's resolved window frame colour (`#rgb`, + /// `#rrggbb` or `#rrggbbaa`); ignored without a selected theme. + pub fn set_theme_frame(&self, frame: Option<&str>) -> IdeResult<()> { + if let Some(f) = frame + && !is_hex_color(f) + { + return Err(IdeError::invalid(format!("not a hex colour: {f:?}"))); + } + let changed = match self.state.lock().theme.as_mut() { + Some(t) if t.frame.as_deref() != frame => { + t.frame = frame.map(str::to_owned); + true + } + _ => false, + }; + if changed { + self.save_state(); + } + Ok(()) + } + + /// Frame colour for a new window: the recorded one of the selected theme, + /// unless its plugin is disabled. Available before plugins are loaded. + pub fn startup_frame(&self) -> Option { + let state = self.state.lock(); + let t = state.theme.as_ref()?; + if state.disabled.contains(&t.plugin) { + return None; + } + t.frame.clone() + } + /// The selected plugin theme, when its plugin is enabled and running. pub fn active_theme(&self) -> Option { let sel = self.state.lock().theme.clone()?; @@ -568,6 +631,10 @@ impl Drop for PluginHost { } } +fn is_hex_color(s: &str) -> bool { + s.strip_prefix('#').is_some_and(|h| matches!(h.len(), 3 | 6 | 8) && h.bytes().all(|b| b.is_ascii_hexdigit())) +} + /// Plugin packages found in `dirs` (first occurrence of an id wins). Invalid /// manifests are skipped; packages with missing files carry a `problem`. pub fn scan_catalog(dirs: &[PathBuf]) -> Vec { diff --git a/crates/ide-plugin/tests/host.rs b/crates/ide-plugin/tests/host.rs index c56414ef..caf0adb4 100644 --- a/crates/ide-plugin/tests/host.rs +++ b/crates/ide-plugin/tests/host.rs @@ -217,10 +217,11 @@ fn runtime_language_and_theme_registration() { #[test] fn contribution_only_plugins() { let f = fixture(Limits::default()); - let theme = f.host.install_from_dir(&sample("theme-solarized-dark")).unwrap(); + let theme = f.host.install_from_dir(&sample("theme-solarized")).unwrap(); assert_eq!(theme.status, PluginStatus::Static); assert!(!theme.has_code); - assert_eq!(theme.themes[0].id, "solarized-dark"); + let ids: Vec<&str> = theme.themes.iter().map(|t| t.id.as_str()).collect(); + assert_eq!(ids, ["solarized-light", "solarized-dark"]); let lang = f.host.install_from_dir(&sample("language-toy")).unwrap(); assert_eq!(lang.status, PluginStatus::Static); assert_eq!(lang.languages[0].id, "toy"); @@ -228,13 +229,14 @@ fn contribution_only_plugins() { assert!(f.run("language-toy", "x", None).unwrap_err().contains("no code")); f.take_events(); - let active = f.host.set_theme(Some(("theme-solarized-dark", "solarized-dark"))).unwrap().unwrap(); + let active = f.host.set_theme(Some(("theme-solarized", "solarized-dark"))).unwrap().unwrap(); assert_eq!(active.theme.tokens["--bg-app"], "#002b36"); + assert_eq!(active.theme.tokens["--syn-string"], "#2aa198"); assert!(f.take_events().iter().any(|(_, e)| matches!(e, PluginEvent::ThemeChanged { theme: Some(_) }))); assert_eq!(f.host.list(None).active_theme, Some(active)); // Disabling the plugin withdraws its theme and language. - f.host.set_enabled("theme-solarized-dark", false).unwrap(); + f.host.set_enabled("theme-solarized", false).unwrap(); assert!(f.host.active_theme().is_none()); assert!(f.take_events().iter().any(|(_, e)| *e == PluginEvent::ThemeChanged { theme: None })); f.host.set_enabled("language-toy", false).unwrap(); @@ -260,6 +262,49 @@ fn theme_template_installs_with_its_editor_scheme() { assert!(tokens.len() > 150); } +#[test] +fn bundled_theme_plugins_install_with_their_licence() { + let f = fixture(Limits::default()); + for (pkg, themes) in + [("theme-solarized", ["solarized-light", "solarized-dark"]), ("theme-one", ["one-light", "one-dark"])] + { + let info = f.host.install_from_dir(&sample(pkg)).unwrap(); + assert_eq!(info.status, PluginStatus::Static, "{pkg}: {:?}", info.error); + assert!(info.authors.iter().any(|a| a.starts_with("bghtyu"))); + let license = std::fs::read_to_string(f.plugins_dir.join(pkg).join("LICENSE")).unwrap(); + assert!(license.contains("MIT License")); + for (theme, kind) in themes.iter().zip([ThemeKind::Light, ThemeKind::Dark]) { + let active = f.host.set_theme(Some((pkg, theme))).unwrap().unwrap(); + assert_eq!(active.theme.kind, kind); + let tokens = &active.theme.tokens; + assert!(["--bg-frame", "--syn-keyword", "--ansi-red"].iter().all(|t| tokens.contains_key(*t))); + } + } +} + +#[test] +fn theme_frame_follows_the_selection() { + let f = fixture(Limits::default()); + f.host.install_from_dir(&sample("theme-one")).unwrap(); + // Nothing to attach it to without a selected theme. + f.host.set_theme_frame(Some("#21252b")).unwrap(); + assert_eq!(f.host.startup_frame(), None); + f.host.set_theme(Some(("theme-one", "one-dark"))).unwrap(); + assert!(f.host.set_theme_frame(Some("hsl(220, 13%, 15%)")).is_err()); + f.host.set_theme_frame(Some("#21252b")).unwrap(); + assert_eq!(f.host.startup_frame().as_deref(), Some("#21252b")); + f.host.set_enabled("theme-one", false).unwrap(); + assert_eq!(f.host.startup_frame(), None); + f.host.set_enabled("theme-one", true).unwrap(); + assert_eq!(f.host.startup_frame().as_deref(), Some("#21252b")); + // A new selection drops the old theme's colour until the UI reports the new one. + f.host.set_theme(Some(("theme-one", "one-light"))).unwrap(); + assert_eq!(f.host.startup_frame(), None); + f.host.set_theme_frame(Some("#eaeaeb")).unwrap(); + f.host.set_theme(None).unwrap(); + assert_eq!(f.host.startup_frame(), None); +} + #[test] fn theme_with_broken_editor_scheme_fails_to_load() { let f = fixture(Limits::default()); @@ -282,12 +327,17 @@ fn theme_with_broken_editor_scheme_fails_to_load() { fn state_persists_across_restarts() { let f = fixture(Limits::default()); f.host.install_from_dir(&sample("hello")).unwrap(); - f.host.install_from_dir(&sample("theme-solarized-dark")).unwrap(); + f.host.install_from_dir(&sample("theme-solarized")).unwrap(); f.host.set_enabled("hello", false).unwrap(); - f.host.set_theme(Some(("theme-solarized-dark", "solarized-dark"))).unwrap(); + f.host.set_theme(Some(("theme-solarized", "solarized-dark"))).unwrap(); + f.host.set_theme_frame(Some("#073642")).unwrap(); let again = PluginHost::new(f.plugins_dir.clone(), Arc::new(|_: Option<&str>, _| {}), Limits::default()).unwrap(); + // Known before the plugins are loaded: new windows open in the theme's frame colour. + assert_eq!(again.startup_frame().as_deref(), Some("#073642")); + assert!(!again.wait_initial_load(Duration::from_millis(1))); again.load_all(); + assert!(again.wait_initial_load(Duration::ZERO)); let list = again.list(None); let hello = list.plugins.iter().find(|p| p.id == "hello").unwrap(); assert!(!hello.enabled); @@ -388,14 +438,14 @@ fn catalog_lists_sample_packages() { let catalog = scan_catalog(&[repo().join("plugins"), tmp.path().to_path_buf()]); let ids: Vec<&str> = catalog.iter().map(|c| c.id.as_str()).collect(); - for id in ["hello", "theme-solarized-dark", "language-toy", "x"] { + for id in ["hello", "theme-solarized", "theme-one", "language-toy", "x"] { assert!(ids.contains(&id), "{id} missing from {ids:?}"); } let hello = catalog.iter().find(|c| c.id == "hello").unwrap(); assert!(hello.has_code && hello.problem.is_none() && hello.change_notes.is_some()); assert_eq!(hello.commands.len(), 2); - let theme = catalog.iter().find(|c| c.id == "theme-solarized-dark").unwrap(); - assert_eq!((theme.theme_count, theme.has_code), (1, false)); + let theme = catalog.iter().find(|c| c.id == "theme-solarized").unwrap(); + assert_eq!((theme.theme_count, theme.has_code), (2, false)); let x = catalog.iter().find(|c| c.id == "x").unwrap(); assert!(x.problem.as_deref().unwrap().contains("plugin.wasm")); } diff --git a/docs/plugins/themes.md b/docs/plugins/themes.md index ea7caa48..767de03a 100644 --- a/docs/plugins/themes.md +++ b/docs/plugins/themes.md @@ -16,6 +16,31 @@ my-theme/ └─ my-theme.scheme.json # editor colours, optional (IntelliJ: .icls) ``` +## Ready-made theme plugins + +The repository's [`plugins/`](../../plugins) folder holds two complete theme +plugins, each with a light and a dark theme and an editor colour scheme +(syntax, editor and terminal ANSI colours): + +| Package | Themes | Palette | +|---|---|---| +| [`plugins/theme-solarized`](../../plugins/theme-solarized) | Solarized Light, Solarized Dark | [Solarized](https://github.com/altercation/solarized) by Ethan Schoonover | +| [`plugins/theme-one`](../../plugins/theme-one) | One Light, One Dark | Atom [One Light](https://github.com/atom/one-light-syntax) / [One Dark](https://github.com/atom/one-dark-syntax) by GitHub | + +Both palettes are MIT-licensed; each package carries the notice in its +`LICENSE`, which is installed with it. To use one: + +1. *Settings › Plugins › ⚙ › Install Plugin from Disk…* and pick the package + folder (`plugins/theme-solarized` or `plugins/theme-one` of a checkout or a + downloaded copy). Development builds also list both on the *Available* + tab, where *Install* does the same. +2. Select the plugin and press *Apply* next to a theme. + +The IDE remembers the theme: the next start-up opens its windows, splash and +workbench in the theme's colours before the plugin host has loaded. + +## Writing a theme plugin + The quickest way to start is to copy [`templates/theme-plugin`](../../templates/theme-plugin). It contains *Harbor Night*, a complete example dark theme that sets every themeable token. The rest of this page covers the file format, the token @@ -282,8 +307,9 @@ A `fontStyle: "italic"` on comments maps to `"--syn-comment-style": "italic"`. - Text should keep at least WCAG AA contrast (4.5:1) on its surfaces. The built-in themes are checked by `src/features/settings/__tests__/contrast.test.ts`. - Repository checks (for changes to this repo): `pnpm vitest run scripts/theme` - validates the template against tokens.css and keeps this reference current, - and `cargo test -p ide-plugin` loads the template through the plugin host. + validates the template and the theme plugins in `plugins/` against + tokens.css and keeps this reference current, and `cargo test -p ide-plugin` + loads them through the plugin host. ## Token reference diff --git a/plugins/README.md b/plugins/README.md index 101f802a..8cf83e55 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -11,7 +11,8 @@ code at all. plugins/ ├─ build.sh # builds Rust plugins into components ├─ hello/ # Rust plugin: two commands -├─ theme-solarized-dark/ # manifest-only: a theme +├─ theme-solarized/ # manifest-only: Solarized Light / Dark themes +├─ theme-one/ # manifest-only: One Light / Dark themes └─ language-toy/ # manifest-only: a language definition ``` diff --git a/plugins/theme-one/LICENSE b/plugins/theme-one/LICENSE new file mode 100644 index 00000000..3c8c405b --- /dev/null +++ b/plugins/theme-one/LICENSE @@ -0,0 +1,60 @@ +The One Light and One Dark palettes are adapted from GitHub's Atom One themes +(styles/colors.less, styles/syntax-variables.less, styles/ui-variables.less): + +- https://github.com/atom/one-light-syntax (revision d84579027410c576086dfca14d934c4bd74b0438) +- https://github.com/atom/one-dark-syntax (revision 9c96f4454362267ac45322063e193ccf9d2debb1) +- https://github.com/atom/one-light-ui (revision a27bce35088ecd323e44f5c2510bcf2d4e9efcf8) +- https://github.com/atom/one-dark-ui (revision 18c2143d41e17b337fff6dc7024562c4d999be17) + +The exact HSL definitions are kept. Atom defines no terminal palette, so the +ANSI slots reuse One's syntax hues. Adapted to OpenIDEA's design tokens by bghtyu. + +## one-light-syntax, one-dark-syntax + +MIT License + +Copyright (c) 2016 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## one-light-ui, one-dark-ui + +MIT License + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/theme-one/plugin.toml b/plugins/theme-one/plugin.toml new file mode 100644 index 00000000..bc5169ca --- /dev/null +++ b/plugins/theme-one/plugin.toml @@ -0,0 +1,17 @@ +# Contribution-only theme plugin: no code, just theme and editor scheme files. +id = "theme-one" +name = "One Themes" +version = "1.0.0" +description = "One Light and One Dark: the Atom One palettes by GitHub for the UI, the editor and the terminal." +authors = ["bghtyu <3931591+bghtyu@users.noreply.github.com>", "GitHub Inc. (Atom One palettes)"] +homepage = "https://github.com/atom/one-dark-syntax" +change-notes = "1.0.0 — One Light and One Dark: UI, editor colour scheme and terminal ANSI colours." +openidea-api = "0.1" + +[[contributes.themes]] +path = "themes/one-light.theme.json" +editor-scheme = "themes/one-light.scheme.json" + +[[contributes.themes]] +path = "themes/one-dark.theme.json" +editor-scheme = "themes/one-dark.scheme.json" diff --git a/plugins/theme-one/themes/one-dark.scheme.json b/plugins/theme-one/themes/one-dark.scheme.json new file mode 100644 index 00000000..b15db467 --- /dev/null +++ b/plugins/theme-one/themes/one-dark.scheme.json @@ -0,0 +1,103 @@ +// Atom One palette by GitHub Inc. (https://github.com/atom/one-dark-syntax and friends), +// MIT licence, see LICENSE. Adapted to OpenIDEA's tokens by bghtyu. +// Editor colour scheme: syntax, editor surfaces and terminal ANSI colours. +{ + "name": "One Dark", + "tokens": { + // Syntax + "--syn-keyword": "hsl(286, 60%, 67%)", + "--syn-string": "hsl(95, 38%, 62%)", + "--syn-type": "hsl(39, 67%, 69%)", + "--syn-function": "hsl(207, 82%, 66%)", + "--syn-function-call": "hsl(207, 82%, 66%)", + "--syn-comment": "hsl(220, 10%, 40%)", + "--syn-comment-style": "italic", + "--syn-doc-comment": "hsl(220, 10%, 40%)", + "--syn-docstring": "hsl(95, 38%, 62%)", + "--syn-annotation": "hsl(29, 54%, 61%)", + "--syn-decorator": "hsl(29, 54%, 61%)", + "--syn-number": "hsl(29, 54%, 61%)", + "--syn-punct": "hsl(220, 14%, 71%)", + "--syn-variable": "hsl(355, 65%, 65%)", + "--syn-param": "hsl(220, 14%, 71%)", + "--syn-property": "hsl(220, 14%, 71%)", + "--syn-constant": "hsl(29, 54%, 61%)", + "--syn-builtin": "hsl(187, 47%, 55%)", + "--syn-self": "hsl(355, 65%, 65%)", + "--syn-keyword-arg": "hsl(355, 65%, 65%)", + "--syn-predefined": "hsl(187, 47%, 55%)", + "--syn-escape": "hsl(187, 47%, 55%)", + "--syn-regexp": "hsl(187, 47%, 55%)", + "--syn-tag": "hsl(355, 65%, 65%)", + "--syn-attribute": "hsl(29, 54%, 61%)", + "--syn-todo": "hsl(286, 60%, 67%)", + "--syn-link": "hsl(207, 82%, 66%)", + "--syn-markup-heading": "hsl(207, 82%, 66%)", + "--syn-markup-code": "hsl(95, 38%, 62%)", + "--syn-invalid": "hsl(355, 65%, 65%)", + "--syn-inline-value": "hsl(220, 9%, 55%)", + "--syn-rainbow-1": "hsl(187, 47%, 55%)", + "--syn-rainbow-2": "hsl(29, 54%, 61%)", + "--syn-rainbow-3": "hsl(95, 38%, 62%)", + "--syn-rainbow-4": "hsl(286, 60%, 67%)", + "--syn-rainbow-5": "hsl(207, 82%, 66%)", + "--syn-bracket-1": "hsl(39, 67%, 69%)", + "--syn-bracket-2": "hsl(286, 60%, 67%)", + "--syn-bracket-3": "hsl(207, 82%, 66%)", + + // Editor + "--fg-editor": "hsl(220, 14%, 71%)", + "--caret": "hsl(220, 100%, 66%)", + "--fg-line-number": "hsl(220, 9%, 55%)", + "--fg-line-number-current": "hsl(220, 14%, 71%)", + "--border-gutter": "hsl(220, 13%, 10.8%)", + "--border-indent-guide": "hsl(220, 13%, 10.8%)", + "--border-indent-guide-active": "hsl(220, 100%, 66%)", + "--border-right-margin": "hsl(220, 13%, 10.8%)", + "--bg-editor-selection": "hsl(220, 13%, 28%)", + "--bg-editor-selection-inactive": "hsl(220, 13%, 28%)", + "--bg-text-search-result": "color-mix(in srgb, hsl(39, 67%, 69%) 22%, hsl(220, 13%, 18%))", + "--bg-text-search-result-current": "color-mix(in srgb, hsl(39, 67%, 69%) 36%, hsl(220, 13%, 18%))", + "--bg-matched-brace": "hsl(220, 13%, 28%)", + "--matched-brace-weight": "var(--fw-code-bold)", + "--bg-matched-tag": "hsl(220, 13%, 28%)", + "--bg-fold-placeholder": "hsl(220, 13%, 15%)", + "--fg-fold-placeholder": "hsl(220, 14%, 71%)", + "--fg-fold-marker": "hsl(220, 9%, 55%)", + "--fg-whitespace": "hsl(220, 9%, 55%)", + "--fg-unused": "hsl(220, 9%, 55%)", + "--bg-identifier-under-caret": "hsl(220, 13%, 28%)", + "--bg-identifier-under-caret-write": "color-mix(in srgb, hsl(355, 65%, 65%) 12%, hsl(220, 13%, 18%))", + "--fg-inlay": "hsl(220, 9%, 55%)", + "--bg-inlay": "hsl(220, 13%, 15%)", + "--wave-error": "hsl(355, 65%, 65%)", + "--wave-warning": "hsl(39, 67%, 69%)", + "--editor-error-decoration": "underline wavy var(--wave-error)", + "--editor-warning-decoration": "underline wavy var(--wave-warning)", + "--editor-warning-background": "color-mix(in srgb, hsl(39, 67%, 69%) 12%, hsl(220, 13%, 18%))", + "--bg-breakpoint-line": "color-mix(in srgb, hsl(355, 65%, 65%) 12%, hsl(220, 13%, 18%))", + "--fg-completion-match": "hsl(207, 82%, 66%)", + "--bg-editor-inline": "hsl(220, 13%, 15%)", + "--bg-editor-banner": "color-mix(in srgb, hsl(207, 82%, 66%) 12%, hsl(220, 13%, 18%))", + "--fg-weak-warning": "hsl(220, 9%, 55%)", + "--fg-bulb": "hsl(39, 67%, 69%)", + + // ANSI palette + "--ansi-black": "hsl(220, 13%, 15%)", + "--ansi-red": "hsl(355, 65%, 65%)", + "--ansi-green": "hsl(95, 38%, 62%)", + "--ansi-yellow": "hsl(39, 67%, 69%)", + "--ansi-blue": "hsl(207, 82%, 66%)", + "--ansi-magenta": "hsl(286, 60%, 67%)", + "--ansi-cyan": "hsl(187, 47%, 55%)", + "--ansi-white": "hsl(220, 14%, 71%)", + "--ansi-bright-black": "hsl(220, 9%, 55%)", + "--ansi-bright-red": "hsl(355, 65%, 65%)", + "--ansi-bright-green": "hsl(95, 38%, 62%)", + "--ansi-bright-yellow": "hsl(39, 67%, 69%)", + "--ansi-bright-blue": "hsl(207, 82%, 66%)", + "--ansi-bright-magenta": "hsl(286, 60%, 67%)", + "--ansi-bright-cyan": "hsl(187, 47%, 55%)", + "--ansi-bright-white": "#ffffff" + } +} diff --git a/plugins/theme-one/themes/one-dark.theme.json b/plugins/theme-one/themes/one-dark.theme.json new file mode 100644 index 00000000..ab397060 --- /dev/null +++ b/plugins/theme-one/themes/one-dark.theme.json @@ -0,0 +1,142 @@ +// Atom One palette by GitHub Inc. (https://github.com/atom/one-dark-syntax and friends), +// MIT licence, see LICENSE. Adapted to OpenIDEA's tokens by bghtyu. +// UI theme; the editor colour scheme is in one-dark.scheme.json. +{ + "id": "one-dark", + "name": "One Dark", + "kind": "dark", + "tokens": { + // Surfaces + "--bg-app": "hsl(220, 13%, 18%)", + "--bg-elev": "hsl(220, 13%, 15%)", + "--bg-popup": "hsl(220, 13%, 16.5%)", + "--bg-hover": "hsl(220, 13%, 22%)", + "--bg-selected": "hsl(220, 13%, 28%)", + "--bg-selected-strong": "hsl(220, 13%, 28%)", + "--bg-current-line": "color-mix(in srgb, hsl(220, 100%, 80%) 4%, hsl(220, 13%, 18%))", + "--bg-debug-line": "color-mix(in srgb, hsl(207, 82%, 66%) 12%, hsl(220, 13%, 18%))", + "--bg-backdrop": "hsl(220, 13%, 15%)", + "--bg-input": "hsl(220, 13%, 18%)", + + // Lines + "--border": "hsl(220, 13%, 10.8%)", + "--border-popup": "hsl(220, 13%, 10.8%)", + "--border-strong": "hsl(220, 9%, 55%)", + "--border-window": "hsl(220, 13%, 10.8%)", + "--control-off": "hsl(220, 9%, 55%)", + + // Text + "--fg-strong": "hsl(220, 14%, 71%)", + "--fg-emphasis": "hsl(220, 14%, 71%)", + "--fg": "hsl(220, 14%, 71%)", + "--fg-secondary": "hsl(220, 9%, 55%)", + "--fg-muted": "hsl(220, 9%, 55%)", + "--fg-subtle": "hsl(220, 9%, 55%)", + "--fg-faint": "hsl(220, 9%, 55%)", + "--fg-gutter": "hsl(220, 9%, 55%)", + "--fg-icon": "hsl(220, 14%, 71%)", + + // Accent + "--accent": "hsl(220, 100%, 66%)", + "--link": "hsl(207, 82%, 66%)", + "--link-hover": "hsl(187, 47%, 55%)", + + // Charts + "--chart-series": "hsl(355, 65%, 65%)", + + // Status + "--danger": "hsl(355, 65%, 65%)", + "--warning": "hsl(39, 67%, 69%)", + "--success": "hsl(95, 38%, 62%)", + "--db-connected": "hsl(95, 38%, 62%)", + "--db-connected-ring": "hsl(95, 38%, 62%)", + "--info": "hsl(207, 82%, 66%)", + + // Vcs + "--vcs-modified": "hsl(207, 82%, 66%)", + "--vcs-added": "hsl(95, 38%, 62%)", + "--vcs-deleted": "hsl(220, 9%, 55%)", + "--vcs-untracked": "hsl(355, 65%, 65%)", + "--vcs-ignored": "hsl(39, 67%, 69%)", + "--vcs-conflict": "hsl(355, 65%, 65%)", + "--gutter-modified": "hsl(207, 82%, 66%)", + "--gutter-added": "hsl(95, 38%, 62%)", + "--gutter-deleted": "hsl(355, 65%, 65%)", + + // Shadows and window controls + "--shadow-popup": "0 4px 16px #00000024", + "--shadow-dialog": "0 10px 36px #00000033", + "--traffic-close": "#ff5f57", + "--traffic-close-border": "#e0443e", + "--traffic-close-pressed": "#bf4942", + "--traffic-glyph": "#4d0000", + "--traffic-off": "hsl(220, 13%, 22%)", + "--traffic-off-border": "hsl(220, 13%, 10.8%)", + + // Additive + "--bg-tooltip": "hsl(220, 13%, 16.5%)", + "--fg-tooltip": "hsl(220, 14%, 71%)", + "--border-tooltip": "hsl(220, 13%, 10.8%)", + "--bg-control": "hsl(220, 13%, 18%)", + "--bg-control-hover": "hsl(220, 13%, 22%)", + "--bg-active": "hsl(220, 13%, 22%)", + "--bg-scrim": "color-mix(in srgb, hsl(220, 13%, 18%) 68%, transparent)", + "--fg-on-accent": "#000000", + "--shadow-tooltip": "0 4px 16px #00000024", + "--shadow-balloon": "0 10px 36px #00000033", + + // Islands contract + "--bg-frame": "hsl(220, 13%, 15%)", + "--bg-island": "hsl(220, 13%, 18%)", + "--bg-stripe-hover": "hsl(220, 13%, 22%)", + "--bg-stripe-selected": "hsl(220, 13%, 28%)", + "--fg-stripe-selected-active": "#000000", + "--fg-stripe-label": "hsl(220, 14%, 71%)", + "--bg-tab-selected": "hsl(220, 13%, 28%)", + "--border-tab-selected": "hsl(220, 100%, 66%)", + "--bg-tab-selected-inactive": "hsl(220, 13%, 15%)", + "--border-tab-selected-inactive": "hsl(220, 13%, 10.8%)", + "--bg-tab-hover": "hsl(220, 13%, 22%)", + "--border-editor-tabs": "hsl(220, 13%, 10.8%)", + "--bg-tree-selected": "hsl(220, 13%, 28%)", + "--bg-tree-selected-inactive": "hsl(220, 13%, 22%)", + "--bg-tree-hover": "hsl(220, 13%, 22%)", + "--bg-toolbar-hover": "hsl(220, 13%, 22%)", + "--bg-toolbar-pressed": "hsl(220, 13%, 28%)", + "--bg-toolbar-selected": "hsl(220, 13%, 28%)", + "--bg-toolbar-selected-hover": "hsl(220, 13%, 28%)", + "--bg-button-primary-hover": "color-mix(in srgb, var(--accent) 86%, hsl(220, 14%, 71%))", + "--fg-button-primary": "#000000", + "--bg-button": "hsl(220, 13%, 18%)", + "--border-button": "hsl(220, 13%, 10.8%)", + "--bg-field": "hsl(220, 13%, 18%)", + "--bg-checkbox": "hsl(220, 13%, 18%)", + "--border-checkbox": "hsl(220, 9%, 55%)", + "--bg-toggle-on": "hsl(95, 38%, 62%)", + "--fg-toggle-on": "#000000", + "--bg-toggle-off": "hsl(220, 13%, 15%)", + "--fg-toggle-off": "hsl(220, 14%, 71%)", + "--border-toggle": "hsl(220, 9%, 55%)", + "--bg-toggle-knob": "hsl(220, 9%, 55%)", + "--focus-ring-soft": "hsl(220, 100%, 66%)", + "--scrollbar-thumb": "color-mix(in srgb, hsl(220, 14%, 71%) 24%, transparent)", + "--scrollbar-thumb-hover": "color-mix(in srgb, hsl(220, 14%, 71%) 42%, transparent)", + "--bg-search-match": "color-mix(in srgb, hsl(39, 67%, 69%) 22%, hsl(220, 13%, 18%))", + "--bg-search-match-current": "color-mix(in srgb, hsl(39, 67%, 69%) 36%, hsl(220, 13%, 18%))", + "--fg-search-match": "hsl(220, 14%, 71%)", + "--bg-dialog": "hsl(220, 13%, 18%)", + "--bg-popup-inline": "hsl(220, 13%, 15%)", + "--bg-popup-advertiser": "hsl(220, 13%, 15%)", + "--bg-feedback-info": "color-mix(in srgb, hsl(207, 82%, 66%) 12%, hsl(220, 13%, 18%))", + "--border-feedback-info": "color-mix(in srgb, hsl(207, 82%, 66%) 55%, hsl(220, 13%, 18%))", + "--bg-feedback-error": "color-mix(in srgb, hsl(355, 65%, 65%) 12%, hsl(220, 13%, 18%))", + "--border-feedback-error": "color-mix(in srgb, hsl(355, 65%, 65%) 55%, hsl(220, 13%, 18%))", + "--bg-feedback-warning": "color-mix(in srgb, hsl(39, 67%, 69%) 12%, hsl(220, 13%, 18%))", + "--border-feedback-warning": "color-mix(in srgb, hsl(39, 67%, 69%) 55%, hsl(220, 13%, 18%))", + "--bg-feedback-success": "color-mix(in srgb, hsl(95, 38%, 62%) 12%, hsl(220, 13%, 18%))", + "--border-feedback-success": "color-mix(in srgb, hsl(95, 38%, 62%) 55%, hsl(220, 13%, 18%))", + "--bg-counter": "hsl(220, 100%, 66%)", + "--fg-counter": "#000000", + "--bg-progress-track": "hsl(220, 13%, 22%)" + } +} diff --git a/plugins/theme-one/themes/one-light.scheme.json b/plugins/theme-one/themes/one-light.scheme.json new file mode 100644 index 00000000..bbabeb5a --- /dev/null +++ b/plugins/theme-one/themes/one-light.scheme.json @@ -0,0 +1,103 @@ +// Atom One palette by GitHub Inc. (https://github.com/atom/one-dark-syntax and friends), +// MIT licence, see LICENSE. Adapted to OpenIDEA's tokens by bghtyu. +// Editor colour scheme: syntax, editor surfaces and terminal ANSI colours. +{ + "name": "One Light", + "tokens": { + // Syntax + "--syn-keyword": "hsl(301, 63%, 40%)", + "--syn-string": "hsl(119, 34%, 47%)", + "--syn-type": "hsl(41, 99%, 38%)", + "--syn-function": "hsl(221, 87%, 60%)", + "--syn-function-call": "hsl(221, 87%, 60%)", + "--syn-comment": "hsl(230, 4%, 64%)", + "--syn-comment-style": "italic", + "--syn-doc-comment": "hsl(230, 4%, 64%)", + "--syn-docstring": "hsl(119, 34%, 47%)", + "--syn-annotation": "hsl(41, 99%, 30%)", + "--syn-decorator": "hsl(41, 99%, 30%)", + "--syn-number": "hsl(41, 99%, 30%)", + "--syn-punct": "hsl(230, 8%, 24%)", + "--syn-variable": "hsl(5, 74%, 59%)", + "--syn-param": "hsl(230, 8%, 24%)", + "--syn-property": "hsl(230, 8%, 24%)", + "--syn-constant": "hsl(41, 99%, 30%)", + "--syn-builtin": "hsl(198, 99%, 37%)", + "--syn-self": "hsl(5, 74%, 59%)", + "--syn-keyword-arg": "hsl(5, 74%, 59%)", + "--syn-predefined": "hsl(198, 99%, 37%)", + "--syn-escape": "hsl(198, 99%, 37%)", + "--syn-regexp": "hsl(198, 99%, 37%)", + "--syn-tag": "hsl(5, 74%, 59%)", + "--syn-attribute": "hsl(41, 99%, 30%)", + "--syn-todo": "hsl(301, 63%, 40%)", + "--syn-link": "hsl(221, 87%, 60%)", + "--syn-markup-heading": "hsl(221, 87%, 60%)", + "--syn-markup-code": "hsl(119, 34%, 47%)", + "--syn-invalid": "hsl(5, 74%, 59%)", + "--syn-inline-value": "hsl(230, 6%, 44%)", + "--syn-rainbow-1": "hsl(198, 99%, 37%)", + "--syn-rainbow-2": "hsl(41, 99%, 30%)", + "--syn-rainbow-3": "hsl(119, 34%, 47%)", + "--syn-rainbow-4": "hsl(301, 63%, 40%)", + "--syn-rainbow-5": "hsl(221, 87%, 60%)", + "--syn-bracket-1": "hsl(41, 99%, 38%)", + "--syn-bracket-2": "hsl(301, 63%, 40%)", + "--syn-bracket-3": "hsl(221, 87%, 60%)", + + // Editor + "--fg-editor": "hsl(230, 8%, 24%)", + "--caret": "hsl(230, 100%, 66%)", + "--fg-line-number": "hsl(230, 6%, 44%)", + "--fg-line-number-current": "hsl(230, 8%, 24%)", + "--border-gutter": "hsl(230, 1%, 86%)", + "--border-indent-guide": "hsl(230, 1%, 86%)", + "--border-indent-guide-active": "hsl(230, 100%, 66%)", + "--border-right-margin": "hsl(230, 1%, 86%)", + "--bg-editor-selection": "hsl(230, 1%, 90%)", + "--bg-editor-selection-inactive": "hsl(230, 1%, 90%)", + "--bg-text-search-result": "color-mix(in srgb, hsl(41, 99%, 38%) 22%, hsl(230, 1%, 98%))", + "--bg-text-search-result-current": "color-mix(in srgb, hsl(41, 99%, 38%) 36%, hsl(230, 1%, 98%))", + "--bg-matched-brace": "hsl(230, 1%, 90%)", + "--matched-brace-weight": "var(--fw-code-bold)", + "--bg-matched-tag": "hsl(230, 1%, 90%)", + "--bg-fold-placeholder": "hsl(230, 1%, 92%)", + "--fg-fold-placeholder": "hsl(230, 8%, 24%)", + "--fg-fold-marker": "hsl(230, 6%, 44%)", + "--fg-whitespace": "hsl(230, 6%, 44%)", + "--fg-unused": "hsl(230, 6%, 44%)", + "--bg-identifier-under-caret": "hsl(230, 1%, 90%)", + "--bg-identifier-under-caret-write": "color-mix(in srgb, hsl(5, 74%, 59%) 12%, hsl(230, 1%, 98%))", + "--fg-inlay": "hsl(230, 6%, 44%)", + "--bg-inlay": "hsl(230, 1%, 92%)", + "--wave-error": "hsl(5, 74%, 59%)", + "--wave-warning": "hsl(41, 99%, 38%)", + "--editor-error-decoration": "underline wavy var(--wave-error)", + "--editor-warning-decoration": "underline wavy var(--wave-warning)", + "--editor-warning-background": "color-mix(in srgb, hsl(41, 99%, 38%) 12%, hsl(230, 1%, 98%))", + "--bg-breakpoint-line": "color-mix(in srgb, hsl(5, 74%, 59%) 12%, hsl(230, 1%, 98%))", + "--fg-completion-match": "hsl(221, 87%, 60%)", + "--bg-editor-inline": "hsl(230, 1%, 92%)", + "--bg-editor-banner": "color-mix(in srgb, hsl(221, 87%, 60%) 12%, hsl(230, 1%, 98%))", + "--fg-weak-warning": "hsl(230, 6%, 44%)", + "--fg-bulb": "hsl(41, 99%, 38%)", + + // ANSI palette + "--ansi-black": "hsl(230, 8%, 24%)", + "--ansi-red": "hsl(5, 74%, 59%)", + "--ansi-green": "hsl(119, 34%, 47%)", + "--ansi-yellow": "hsl(41, 99%, 38%)", + "--ansi-blue": "hsl(221, 87%, 60%)", + "--ansi-magenta": "hsl(301, 63%, 40%)", + "--ansi-cyan": "hsl(198, 99%, 37%)", + "--ansi-white": "hsl(230, 6%, 44%)", + "--ansi-bright-black": "hsl(230, 6%, 44%)", + "--ansi-bright-red": "hsl(5, 74%, 59%)", + "--ansi-bright-green": "hsl(119, 34%, 47%)", + "--ansi-bright-yellow": "hsl(41, 99%, 38%)", + "--ansi-bright-blue": "hsl(221, 87%, 60%)", + "--ansi-bright-magenta": "hsl(301, 63%, 40%)", + "--ansi-bright-cyan": "hsl(198, 99%, 37%)", + "--ansi-bright-white": "hsl(230, 8%, 24%)" + } +} diff --git a/plugins/theme-one/themes/one-light.theme.json b/plugins/theme-one/themes/one-light.theme.json new file mode 100644 index 00000000..ad650187 --- /dev/null +++ b/plugins/theme-one/themes/one-light.theme.json @@ -0,0 +1,142 @@ +// Atom One palette by GitHub Inc. (https://github.com/atom/one-dark-syntax and friends), +// MIT licence, see LICENSE. Adapted to OpenIDEA's tokens by bghtyu. +// UI theme; the editor colour scheme is in one-light.scheme.json. +{ + "id": "one-light", + "name": "One Light", + "kind": "light", + "tokens": { + // Surfaces + "--bg-app": "hsl(230, 1%, 98%)", + "--bg-elev": "hsl(230, 1%, 92%)", + "--bg-popup": "hsl(230, 1%, 95%)", + "--bg-hover": "hsl(230, 1%, 90%)", + "--bg-selected": "hsl(230, 1%, 90%)", + "--bg-selected-strong": "hsl(230, 1%, 90%)", + "--bg-current-line": "color-mix(in srgb, hsl(230, 8%, 24%) 5%, hsl(230, 1%, 98%))", + "--bg-debug-line": "color-mix(in srgb, hsl(221, 87%, 60%) 12%, hsl(230, 1%, 98%))", + "--bg-backdrop": "hsl(230, 1%, 92%)", + "--bg-input": "hsl(230, 1%, 98%)", + + // Lines + "--border": "hsl(230, 1%, 86%)", + "--border-popup": "hsl(230, 1%, 86%)", + "--border-strong": "hsl(230, 6%, 44%)", + "--border-window": "hsl(230, 1%, 86%)", + "--control-off": "hsl(230, 6%, 44%)", + + // Text + "--fg-strong": "hsl(230, 8%, 24%)", + "--fg-emphasis": "hsl(230, 8%, 24%)", + "--fg": "hsl(230, 8%, 24%)", + "--fg-secondary": "hsl(230, 6%, 44%)", + "--fg-muted": "hsl(230, 6%, 44%)", + "--fg-subtle": "hsl(230, 6%, 44%)", + "--fg-faint": "hsl(230, 6%, 44%)", + "--fg-gutter": "hsl(230, 6%, 44%)", + "--fg-icon": "hsl(230, 8%, 24%)", + + // Accent + "--accent": "hsl(230, 100%, 66%)", + "--link": "hsl(221, 87%, 60%)", + "--link-hover": "hsl(198, 99%, 37%)", + + // Charts + "--chart-series": "hsl(5, 74%, 59%)", + + // Status + "--danger": "hsl(5, 74%, 59%)", + "--warning": "hsl(41, 99%, 38%)", + "--success": "hsl(119, 34%, 47%)", + "--db-connected": "hsl(119, 34%, 47%)", + "--db-connected-ring": "hsl(119, 34%, 47%)", + "--info": "hsl(221, 87%, 60%)", + + // Vcs + "--vcs-modified": "hsl(221, 87%, 60%)", + "--vcs-added": "hsl(119, 34%, 47%)", + "--vcs-deleted": "hsl(230, 6%, 44%)", + "--vcs-untracked": "hsl(5, 74%, 59%)", + "--vcs-ignored": "hsl(41, 99%, 38%)", + "--vcs-conflict": "hsl(5, 74%, 59%)", + "--gutter-modified": "hsl(221, 87%, 60%)", + "--gutter-added": "hsl(119, 34%, 47%)", + "--gutter-deleted": "hsl(5, 74%, 59%)", + + // Shadows and window controls + "--shadow-popup": "0 4px 16px #00000024", + "--shadow-dialog": "0 10px 36px #00000033", + "--traffic-close": "#ff5f57", + "--traffic-close-border": "#e0443e", + "--traffic-close-pressed": "#bf4942", + "--traffic-glyph": "#4d0000", + "--traffic-off": "hsl(230, 1%, 90%)", + "--traffic-off-border": "hsl(230, 1%, 86%)", + + // Additive + "--bg-tooltip": "hsl(230, 1%, 95%)", + "--fg-tooltip": "hsl(230, 8%, 24%)", + "--border-tooltip": "hsl(230, 1%, 86%)", + "--bg-control": "hsl(230, 1%, 98%)", + "--bg-control-hover": "hsl(230, 1%, 90%)", + "--bg-active": "hsl(230, 1%, 90%)", + "--bg-scrim": "color-mix(in srgb, hsl(230, 1%, 98%) 68%, transparent)", + "--fg-on-accent": "#ffffff", + "--shadow-tooltip": "0 4px 16px #00000024", + "--shadow-balloon": "0 10px 36px #00000033", + + // Islands contract + "--bg-frame": "hsl(230, 1%, 92%)", + "--bg-island": "hsl(230, 1%, 98%)", + "--bg-stripe-hover": "hsl(230, 1%, 90%)", + "--bg-stripe-selected": "hsl(230, 1%, 90%)", + "--fg-stripe-selected-active": "#ffffff", + "--fg-stripe-label": "hsl(230, 8%, 24%)", + "--bg-tab-selected": "hsl(230, 1%, 90%)", + "--border-tab-selected": "hsl(230, 100%, 66%)", + "--bg-tab-selected-inactive": "hsl(230, 1%, 92%)", + "--border-tab-selected-inactive": "hsl(230, 1%, 86%)", + "--bg-tab-hover": "hsl(230, 1%, 90%)", + "--border-editor-tabs": "hsl(230, 1%, 86%)", + "--bg-tree-selected": "hsl(230, 1%, 90%)", + "--bg-tree-selected-inactive": "hsl(230, 1%, 90%)", + "--bg-tree-hover": "hsl(230, 1%, 90%)", + "--bg-toolbar-hover": "hsl(230, 1%, 90%)", + "--bg-toolbar-pressed": "hsl(230, 1%, 90%)", + "--bg-toolbar-selected": "hsl(230, 1%, 90%)", + "--bg-toolbar-selected-hover": "hsl(230, 1%, 90%)", + "--bg-button-primary-hover": "color-mix(in srgb, var(--accent) 86%, hsl(230, 8%, 24%))", + "--fg-button-primary": "#ffffff", + "--bg-button": "hsl(230, 1%, 98%)", + "--border-button": "hsl(230, 1%, 86%)", + "--bg-field": "hsl(230, 1%, 98%)", + "--bg-checkbox": "hsl(230, 1%, 98%)", + "--border-checkbox": "hsl(230, 6%, 44%)", + "--bg-toggle-on": "hsl(119, 34%, 47%)", + "--fg-toggle-on": "#ffffff", + "--bg-toggle-off": "hsl(230, 1%, 92%)", + "--fg-toggle-off": "hsl(230, 8%, 24%)", + "--border-toggle": "hsl(230, 6%, 44%)", + "--bg-toggle-knob": "hsl(230, 6%, 44%)", + "--focus-ring-soft": "hsl(230, 100%, 66%)", + "--scrollbar-thumb": "color-mix(in srgb, hsl(230, 8%, 24%) 24%, transparent)", + "--scrollbar-thumb-hover": "color-mix(in srgb, hsl(230, 8%, 24%) 42%, transparent)", + "--bg-search-match": "color-mix(in srgb, hsl(41, 99%, 38%) 22%, hsl(230, 1%, 98%))", + "--bg-search-match-current": "color-mix(in srgb, hsl(41, 99%, 38%) 36%, hsl(230, 1%, 98%))", + "--fg-search-match": "hsl(230, 8%, 24%)", + "--bg-dialog": "hsl(230, 1%, 98%)", + "--bg-popup-inline": "hsl(230, 1%, 92%)", + "--bg-popup-advertiser": "hsl(230, 1%, 92%)", + "--bg-feedback-info": "color-mix(in srgb, hsl(221, 87%, 60%) 12%, hsl(230, 1%, 98%))", + "--border-feedback-info": "color-mix(in srgb, hsl(221, 87%, 60%) 55%, hsl(230, 1%, 98%))", + "--bg-feedback-error": "color-mix(in srgb, hsl(5, 74%, 59%) 12%, hsl(230, 1%, 98%))", + "--border-feedback-error": "color-mix(in srgb, hsl(5, 74%, 59%) 55%, hsl(230, 1%, 98%))", + "--bg-feedback-warning": "color-mix(in srgb, hsl(41, 99%, 38%) 12%, hsl(230, 1%, 98%))", + "--border-feedback-warning": "color-mix(in srgb, hsl(41, 99%, 38%) 55%, hsl(230, 1%, 98%))", + "--bg-feedback-success": "color-mix(in srgb, hsl(119, 34%, 47%) 12%, hsl(230, 1%, 98%))", + "--border-feedback-success": "color-mix(in srgb, hsl(119, 34%, 47%) 55%, hsl(230, 1%, 98%))", + "--bg-counter": "hsl(230, 100%, 66%)", + "--fg-counter": "#ffffff", + "--bg-progress-track": "hsl(230, 1%, 90%)" + } +} diff --git a/plugins/theme-solarized-dark/plugin.toml b/plugins/theme-solarized-dark/plugin.toml deleted file mode 100644 index f37fc649..00000000 --- a/plugins/theme-solarized-dark/plugin.toml +++ /dev/null @@ -1,11 +0,0 @@ -# Contribution-only plugin: no code, just a theme file. -id = "theme-solarized-dark" -name = "Solarized Dark Theme" -version = "1.0.0" -description = "Ethan Schoonover's Solarized palette, dark variant." -authors = ["OpenIDEA contributors"] -change-notes = "1.0.0 — Solarized Dark UI and syntax colours." -openidea-api = "0.1" - -[[contributes.themes]] -path = "themes/solarized-dark.json" diff --git a/plugins/theme-solarized-dark/themes/solarized-dark.json b/plugins/theme-solarized-dark/themes/solarized-dark.json deleted file mode 100644 index 87e56a2b..00000000 --- a/plugins/theme-solarized-dark/themes/solarized-dark.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "id": "solarized-dark", - "name": "Solarized Dark", - "kind": "dark", - "tokens": { - "--bg-app": "#002b36", - "--bg-elev": "#03313c", - "--bg-popup": "#073642", - "--bg-hover": "#0a3d4a", - "--bg-selected": "#0d4554", - "--bg-selected-strong": "#104d5d", - "--bg-current-line": "#04323d", - "--bg-debug-line": "#0b3a50", - "--bg-backdrop": "#00212a", - "--bg-tooltip": "#073642", - "--bg-control": "#073642", - "--bg-control-hover": "#0a3d4a", - "--bg-active": "#104d5d", - "--border": "#06323d", - "--border-popup": "#0a3d4a", - "--border-strong": "#124b59", - "--border-window": "#0a3d4a", - "--control-off": "#2c5662", - "--fg-strong": "#eee8d5", - "--fg-emphasis": "#d9d4c1", - "--fg": "#93a1a1", - "--fg-secondary": "#839496", - "--fg-muted": "#839496", - "--fg-subtle": "#657b83", - "--fg-faint": "#586e75", - "--fg-gutter": "#4c636b", - "--fg-tooltip": "#eee8d5", - "--fg-on-accent": "#002b36", - "--accent": "#268bd2", - "--link": "#268bd2", - "--link-hover": "#5fa9e0", - "--danger": "#dc322f", - "--warning": "#b58900", - "--success": "#859900", - "--info": "#268bd2", - "--vcs-modified": "#b58900", - "--vcs-added": "#859900", - "--vcs-deleted": "#657b83", - "--vcs-untracked": "#cb4b16", - "--vcs-ignored": "#586e75", - "--vcs-conflict": "#d33682", - "--gutter-modified": "#268bd2", - "--gutter-added": "#859900", - "--gutter-deleted": "#dc322f", - "--syn-keyword": "#859900", - "--syn-string": "#2aa198", - "--syn-type": "#b58900", - "--syn-function": "#268bd2", - "--syn-comment": "#586e75", - "--syn-annotation": "#6c71c4", - "--syn-number": "#d33682", - "--syn-punct": "#839496", - "--syn-variable": "#93a1a1", - "--syn-property": "#93a1a1", - "--syn-constant": "#cb4b16", - "--syn-invalid": "#dc322f", - "--syn-inline-value": "#657b83" - } -} diff --git a/plugins/theme-solarized/LICENSE b/plugins/theme-solarized/LICENSE new file mode 100644 index 00000000..0e62e915 --- /dev/null +++ b/plugins/theme-solarized/LICENSE @@ -0,0 +1,27 @@ +The Solarized palette is adapted from Ethan Schoonover's Solarized, +https://github.com/altercation/solarized (revision 62f656a02f93c5190a8753159e34b385588d5ff3): +the sixteen sRGB colours of its README, the semantic roles of +vim-colors-solarized/colors/solarized.vim and its iTerm2 ANSI slots. +Adapted to OpenIDEA's design tokens by bghtyu. + +MIT License + +Copyright (c) 2011 Ethan Schoonover + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/plugins/theme-solarized/plugin.toml b/plugins/theme-solarized/plugin.toml new file mode 100644 index 00000000..51223ba0 --- /dev/null +++ b/plugins/theme-solarized/plugin.toml @@ -0,0 +1,17 @@ +# Contribution-only theme plugin: no code, just theme and editor scheme files. +id = "theme-solarized" +name = "Solarized Themes" +version = "1.0.0" +description = "Solarized Light and Solarized Dark: Ethan Schoonover's Solarized palette for the UI, the editor and the terminal." +authors = ["bghtyu <3931591+bghtyu@users.noreply.github.com>", "Ethan Schoonover (Solarized palette)"] +homepage = "https://github.com/altercation/solarized" +change-notes = "1.0.0 — Solarized Light and Solarized Dark: UI, editor colour scheme and terminal ANSI colours." +openidea-api = "0.1" + +[[contributes.themes]] +path = "themes/solarized-light.theme.json" +editor-scheme = "themes/solarized-light.scheme.json" + +[[contributes.themes]] +path = "themes/solarized-dark.theme.json" +editor-scheme = "themes/solarized-dark.scheme.json" diff --git a/plugins/theme-solarized/themes/solarized-dark.scheme.json b/plugins/theme-solarized/themes/solarized-dark.scheme.json new file mode 100644 index 00000000..57721bad --- /dev/null +++ b/plugins/theme-solarized/themes/solarized-dark.scheme.json @@ -0,0 +1,103 @@ +// Solarized palette by Ethan Schoonover (https://github.com/altercation/solarized), +// MIT licence, see LICENSE. Adapted to OpenIDEA's tokens by bghtyu. +// Editor colour scheme: syntax, editor surfaces and terminal ANSI colours. +{ + "name": "Solarized Dark", + "tokens": { + // Syntax + "--syn-keyword": "#859900", + "--syn-string": "#2aa198", + "--syn-type": "#b58900", + "--syn-function": "#268bd2", + "--syn-function-call": "#268bd2", + "--syn-comment": "#586e75", + "--syn-comment-style": "italic", + "--syn-doc-comment": "#586e75", + "--syn-docstring": "#2aa198", + "--syn-annotation": "#cb4b16", + "--syn-decorator": "#cb4b16", + "--syn-number": "#2aa198", + "--syn-punct": "#839496", + "--syn-variable": "#268bd2", + "--syn-param": "#839496", + "--syn-property": "#268bd2", + "--syn-constant": "#2aa198", + "--syn-builtin": "#2aa198", + "--syn-self": "#dc322f", + "--syn-keyword-arg": "#dc322f", + "--syn-predefined": "#2aa198", + "--syn-escape": "#dc322f", + "--syn-regexp": "#2aa198", + "--syn-tag": "#268bd2", + "--syn-attribute": "#cb4b16", + "--syn-todo": "#d33682", + "--syn-link": "#268bd2", + "--syn-markup-heading": "#268bd2", + "--syn-markup-code": "#2aa198", + "--syn-invalid": "#dc322f", + "--syn-inline-value": "#839496", + "--syn-rainbow-1": "#2aa198", + "--syn-rainbow-2": "#cb4b16", + "--syn-rainbow-3": "#859900", + "--syn-rainbow-4": "#d33682", + "--syn-rainbow-5": "#268bd2", + "--syn-bracket-1": "#b58900", + "--syn-bracket-2": "#d33682", + "--syn-bracket-3": "#268bd2", + + // Editor + "--fg-editor": "#839496", + "--caret": "#268bd2", + "--fg-line-number": "#839496", + "--fg-line-number-current": "#839496", + "--border-gutter": "#073642", + "--border-indent-guide": "#073642", + "--border-indent-guide-active": "#268bd2", + "--border-right-margin": "#073642", + "--bg-editor-selection": "#073642", + "--bg-editor-selection-inactive": "#073642", + "--bg-text-search-result": "color-mix(in srgb, #b58900 22%, #002b36)", + "--bg-text-search-result-current": "color-mix(in srgb, #b58900 36%, #002b36)", + "--bg-matched-brace": "#073642", + "--matched-brace-weight": "var(--fw-code-bold)", + "--bg-matched-tag": "#073642", + "--bg-fold-placeholder": "#073642", + "--fg-fold-placeholder": "#839496", + "--fg-fold-marker": "#839496", + "--fg-whitespace": "#839496", + "--fg-unused": "#839496", + "--bg-identifier-under-caret": "#073642", + "--bg-identifier-under-caret-write": "color-mix(in srgb, #dc322f 12%, #002b36)", + "--fg-inlay": "#839496", + "--bg-inlay": "#073642", + "--wave-error": "#dc322f", + "--wave-warning": "#b58900", + "--editor-error-decoration": "underline wavy var(--wave-error)", + "--editor-warning-decoration": "underline wavy var(--wave-warning)", + "--editor-warning-background": "color-mix(in srgb, #b58900 12%, #002b36)", + "--bg-breakpoint-line": "color-mix(in srgb, #dc322f 12%, #002b36)", + "--fg-completion-match": "#268bd2", + "--bg-editor-inline": "#073642", + "--bg-editor-banner": "color-mix(in srgb, #268bd2 12%, #002b36)", + "--fg-weak-warning": "#839496", + "--fg-bulb": "#b58900", + + // ANSI palette + "--ansi-black": "#073642", + "--ansi-red": "#dc322f", + "--ansi-green": "#859900", + "--ansi-yellow": "#b58900", + "--ansi-blue": "#268bd2", + "--ansi-magenta": "#d33682", + "--ansi-cyan": "#2aa198", + "--ansi-white": "#eee8d5", + "--ansi-bright-black": "#002b36", + "--ansi-bright-red": "#cb4b16", + "--ansi-bright-green": "#586e75", + "--ansi-bright-yellow": "#657b83", + "--ansi-bright-blue": "#839496", + "--ansi-bright-magenta": "#6c71c4", + "--ansi-bright-cyan": "#93a1a1", + "--ansi-bright-white": "#fdf6e3" + } +} diff --git a/plugins/theme-solarized/themes/solarized-dark.theme.json b/plugins/theme-solarized/themes/solarized-dark.theme.json new file mode 100644 index 00000000..5f76df9a --- /dev/null +++ b/plugins/theme-solarized/themes/solarized-dark.theme.json @@ -0,0 +1,142 @@ +// Solarized palette by Ethan Schoonover (https://github.com/altercation/solarized), +// MIT licence, see LICENSE. Adapted to OpenIDEA's tokens by bghtyu. +// UI theme; the editor colour scheme is in solarized-dark.scheme.json. +{ + "id": "solarized-dark", + "name": "Solarized Dark", + "kind": "dark", + "tokens": { + // Surfaces + "--bg-app": "#002b36", + "--bg-elev": "#073642", + "--bg-popup": "#073642", + "--bg-hover": "#073642", + "--bg-selected": "#073642", + "--bg-selected-strong": "#073642", + "--bg-current-line": "#073642", + "--bg-debug-line": "color-mix(in srgb, #268bd2 12%, #002b36)", + "--bg-backdrop": "#073642", + "--bg-input": "#002b36", + + // Lines + "--border": "#073642", + "--border-popup": "#073642", + "--border-strong": "#839496", + "--border-window": "#073642", + "--control-off": "#839496", + + // Text + "--fg-strong": "#839496", + "--fg-emphasis": "#839496", + "--fg": "#839496", + "--fg-secondary": "#839496", + "--fg-muted": "#839496", + "--fg-subtle": "#839496", + "--fg-faint": "#839496", + "--fg-gutter": "#839496", + "--fg-icon": "#839496", + + // Accent + "--accent": "#268bd2", + "--link": "#268bd2", + "--link-hover": "#2aa198", + + // Charts + "--chart-series": "#dc322f", + + // Status + "--danger": "#dc322f", + "--warning": "#b58900", + "--success": "#859900", + "--db-connected": "#859900", + "--db-connected-ring": "#859900", + "--info": "#268bd2", + + // Vcs + "--vcs-modified": "#268bd2", + "--vcs-added": "#859900", + "--vcs-deleted": "#839496", + "--vcs-untracked": "#dc322f", + "--vcs-ignored": "#b58900", + "--vcs-conflict": "#dc322f", + "--gutter-modified": "#268bd2", + "--gutter-added": "#859900", + "--gutter-deleted": "#dc322f", + + // Shadows and window controls + "--shadow-popup": "0 4px 16px #00000024", + "--shadow-dialog": "0 10px 36px #00000033", + "--traffic-close": "#ff5f57", + "--traffic-close-border": "#e0443e", + "--traffic-close-pressed": "#bf4942", + "--traffic-glyph": "#4d0000", + "--traffic-off": "#073642", + "--traffic-off-border": "#073642", + + // Additive + "--bg-tooltip": "#073642", + "--fg-tooltip": "#839496", + "--border-tooltip": "#073642", + "--bg-control": "#002b36", + "--bg-control-hover": "#073642", + "--bg-active": "#073642", + "--bg-scrim": "color-mix(in srgb, #002b36 68%, transparent)", + "--fg-on-accent": "#002b36", + "--shadow-tooltip": "0 4px 16px #00000024", + "--shadow-balloon": "0 10px 36px #00000033", + + // Islands contract + "--bg-frame": "#073642", + "--bg-island": "#002b36", + "--bg-stripe-hover": "#073642", + "--bg-stripe-selected": "#073642", + "--fg-stripe-selected-active": "#002b36", + "--fg-stripe-label": "#839496", + "--bg-tab-selected": "#073642", + "--border-tab-selected": "#268bd2", + "--bg-tab-selected-inactive": "#073642", + "--border-tab-selected-inactive": "#073642", + "--bg-tab-hover": "#073642", + "--border-editor-tabs": "#073642", + "--bg-tree-selected": "#073642", + "--bg-tree-selected-inactive": "#073642", + "--bg-tree-hover": "#073642", + "--bg-toolbar-hover": "#073642", + "--bg-toolbar-pressed": "#073642", + "--bg-toolbar-selected": "#073642", + "--bg-toolbar-selected-hover": "#073642", + "--bg-button-primary-hover": "color-mix(in srgb, var(--accent) 86%, #839496)", + "--fg-button-primary": "#002b36", + "--bg-button": "#002b36", + "--border-button": "#073642", + "--bg-field": "#002b36", + "--bg-checkbox": "#002b36", + "--border-checkbox": "#839496", + "--bg-toggle-on": "#859900", + "--fg-toggle-on": "#002b36", + "--bg-toggle-off": "#073642", + "--fg-toggle-off": "#839496", + "--border-toggle": "#839496", + "--bg-toggle-knob": "#839496", + "--focus-ring-soft": "#268bd2", + "--scrollbar-thumb": "color-mix(in srgb, #839496 24%, transparent)", + "--scrollbar-thumb-hover": "color-mix(in srgb, #839496 42%, transparent)", + "--bg-search-match": "color-mix(in srgb, #b58900 22%, #002b36)", + "--bg-search-match-current": "color-mix(in srgb, #b58900 36%, #002b36)", + "--fg-search-match": "#839496", + "--bg-dialog": "#002b36", + "--bg-popup-inline": "#073642", + "--bg-popup-advertiser": "#073642", + "--bg-feedback-info": "color-mix(in srgb, #268bd2 12%, #002b36)", + "--border-feedback-info": "color-mix(in srgb, #268bd2 55%, #002b36)", + "--bg-feedback-error": "color-mix(in srgb, #dc322f 12%, #002b36)", + "--border-feedback-error": "color-mix(in srgb, #dc322f 55%, #002b36)", + "--bg-feedback-warning": "color-mix(in srgb, #b58900 12%, #002b36)", + "--border-feedback-warning": "color-mix(in srgb, #b58900 55%, #002b36)", + "--bg-feedback-success": "color-mix(in srgb, #859900 12%, #002b36)", + "--border-feedback-success": "color-mix(in srgb, #859900 55%, #002b36)", + "--bg-counter": "#268bd2", + "--fg-counter": "#002b36", + "--bg-progress-track": "#073642" + } +} diff --git a/plugins/theme-solarized/themes/solarized-light.scheme.json b/plugins/theme-solarized/themes/solarized-light.scheme.json new file mode 100644 index 00000000..e5c4d7a4 --- /dev/null +++ b/plugins/theme-solarized/themes/solarized-light.scheme.json @@ -0,0 +1,103 @@ +// Solarized palette by Ethan Schoonover (https://github.com/altercation/solarized), +// MIT licence, see LICENSE. Adapted to OpenIDEA's tokens by bghtyu. +// Editor colour scheme: syntax, editor surfaces and terminal ANSI colours. +{ + "name": "Solarized Light", + "tokens": { + // Syntax + "--syn-keyword": "#859900", + "--syn-string": "#2aa198", + "--syn-type": "#b58900", + "--syn-function": "#268bd2", + "--syn-function-call": "#268bd2", + "--syn-comment": "#93a1a1", + "--syn-comment-style": "italic", + "--syn-doc-comment": "#93a1a1", + "--syn-docstring": "#2aa198", + "--syn-annotation": "#cb4b16", + "--syn-decorator": "#cb4b16", + "--syn-number": "#2aa198", + "--syn-punct": "#657b83", + "--syn-variable": "#268bd2", + "--syn-param": "#657b83", + "--syn-property": "#268bd2", + "--syn-constant": "#2aa198", + "--syn-builtin": "#2aa198", + "--syn-self": "#dc322f", + "--syn-keyword-arg": "#dc322f", + "--syn-predefined": "#2aa198", + "--syn-escape": "#dc322f", + "--syn-regexp": "#2aa198", + "--syn-tag": "#268bd2", + "--syn-attribute": "#cb4b16", + "--syn-todo": "#d33682", + "--syn-link": "#268bd2", + "--syn-markup-heading": "#268bd2", + "--syn-markup-code": "#2aa198", + "--syn-invalid": "#dc322f", + "--syn-inline-value": "#657b83", + "--syn-rainbow-1": "#2aa198", + "--syn-rainbow-2": "#cb4b16", + "--syn-rainbow-3": "#859900", + "--syn-rainbow-4": "#d33682", + "--syn-rainbow-5": "#268bd2", + "--syn-bracket-1": "#b58900", + "--syn-bracket-2": "#d33682", + "--syn-bracket-3": "#268bd2", + + // Editor + "--fg-editor": "#657b83", + "--caret": "#268bd2", + "--fg-line-number": "#657b83", + "--fg-line-number-current": "#657b83", + "--border-gutter": "#eee8d5", + "--border-indent-guide": "#eee8d5", + "--border-indent-guide-active": "#268bd2", + "--border-right-margin": "#eee8d5", + "--bg-editor-selection": "#eee8d5", + "--bg-editor-selection-inactive": "#eee8d5", + "--bg-text-search-result": "color-mix(in srgb, #b58900 22%, #fdf6e3)", + "--bg-text-search-result-current": "color-mix(in srgb, #b58900 36%, #fdf6e3)", + "--bg-matched-brace": "#eee8d5", + "--matched-brace-weight": "var(--fw-code-bold)", + "--bg-matched-tag": "#eee8d5", + "--bg-fold-placeholder": "#eee8d5", + "--fg-fold-placeholder": "#657b83", + "--fg-fold-marker": "#657b83", + "--fg-whitespace": "#657b83", + "--fg-unused": "#657b83", + "--bg-identifier-under-caret": "#eee8d5", + "--bg-identifier-under-caret-write": "color-mix(in srgb, #dc322f 12%, #fdf6e3)", + "--fg-inlay": "#657b83", + "--bg-inlay": "#eee8d5", + "--wave-error": "#dc322f", + "--wave-warning": "#b58900", + "--editor-error-decoration": "underline wavy var(--wave-error)", + "--editor-warning-decoration": "underline wavy var(--wave-warning)", + "--editor-warning-background": "color-mix(in srgb, #b58900 12%, #fdf6e3)", + "--bg-breakpoint-line": "color-mix(in srgb, #dc322f 12%, #fdf6e3)", + "--fg-completion-match": "#268bd2", + "--bg-editor-inline": "#eee8d5", + "--bg-editor-banner": "color-mix(in srgb, #268bd2 12%, #fdf6e3)", + "--fg-weak-warning": "#657b83", + "--fg-bulb": "#b58900", + + // ANSI palette + "--ansi-black": "#073642", + "--ansi-red": "#dc322f", + "--ansi-green": "#859900", + "--ansi-yellow": "#b58900", + "--ansi-blue": "#268bd2", + "--ansi-magenta": "#d33682", + "--ansi-cyan": "#2aa198", + "--ansi-white": "#eee8d5", + "--ansi-bright-black": "#002b36", + "--ansi-bright-red": "#cb4b16", + "--ansi-bright-green": "#586e75", + "--ansi-bright-yellow": "#657b83", + "--ansi-bright-blue": "#839496", + "--ansi-bright-magenta": "#6c71c4", + "--ansi-bright-cyan": "#93a1a1", + "--ansi-bright-white": "#fdf6e3" + } +} diff --git a/plugins/theme-solarized/themes/solarized-light.theme.json b/plugins/theme-solarized/themes/solarized-light.theme.json new file mode 100644 index 00000000..d1750b3c --- /dev/null +++ b/plugins/theme-solarized/themes/solarized-light.theme.json @@ -0,0 +1,142 @@ +// Solarized palette by Ethan Schoonover (https://github.com/altercation/solarized), +// MIT licence, see LICENSE. Adapted to OpenIDEA's tokens by bghtyu. +// UI theme; the editor colour scheme is in solarized-light.scheme.json. +{ + "id": "solarized-light", + "name": "Solarized Light", + "kind": "light", + "tokens": { + // Surfaces + "--bg-app": "#fdf6e3", + "--bg-elev": "#eee8d5", + "--bg-popup": "#fdf6e3", + "--bg-hover": "#eee8d5", + "--bg-selected": "#eee8d5", + "--bg-selected-strong": "#eee8d5", + "--bg-current-line": "#eee8d5", + "--bg-debug-line": "color-mix(in srgb, #268bd2 12%, #fdf6e3)", + "--bg-backdrop": "#eee8d5", + "--bg-input": "#fdf6e3", + + // Lines + "--border": "#eee8d5", + "--border-popup": "#eee8d5", + "--border-strong": "#657b83", + "--border-window": "#eee8d5", + "--control-off": "#657b83", + + // Text + "--fg-strong": "#657b83", + "--fg-emphasis": "#657b83", + "--fg": "#657b83", + "--fg-secondary": "#657b83", + "--fg-muted": "#657b83", + "--fg-subtle": "#657b83", + "--fg-faint": "#657b83", + "--fg-gutter": "#657b83", + "--fg-icon": "#657b83", + + // Accent + "--accent": "#268bd2", + "--link": "#268bd2", + "--link-hover": "#2aa198", + + // Charts + "--chart-series": "#dc322f", + + // Status + "--danger": "#dc322f", + "--warning": "#b58900", + "--success": "#859900", + "--db-connected": "#859900", + "--db-connected-ring": "#859900", + "--info": "#268bd2", + + // Vcs + "--vcs-modified": "#268bd2", + "--vcs-added": "#859900", + "--vcs-deleted": "#657b83", + "--vcs-untracked": "#dc322f", + "--vcs-ignored": "#b58900", + "--vcs-conflict": "#dc322f", + "--gutter-modified": "#268bd2", + "--gutter-added": "#859900", + "--gutter-deleted": "#dc322f", + + // Shadows and window controls + "--shadow-popup": "0 4px 16px #00000024", + "--shadow-dialog": "0 10px 36px #00000033", + "--traffic-close": "#ff5f57", + "--traffic-close-border": "#e0443e", + "--traffic-close-pressed": "#bf4942", + "--traffic-glyph": "#4d0000", + "--traffic-off": "#eee8d5", + "--traffic-off-border": "#eee8d5", + + // Additive + "--bg-tooltip": "#fdf6e3", + "--fg-tooltip": "#657b83", + "--border-tooltip": "#eee8d5", + "--bg-control": "#fdf6e3", + "--bg-control-hover": "#eee8d5", + "--bg-active": "#eee8d5", + "--bg-scrim": "color-mix(in srgb, #fdf6e3 68%, transparent)", + "--fg-on-accent": "#002b36", + "--shadow-tooltip": "0 4px 16px #00000024", + "--shadow-balloon": "0 10px 36px #00000033", + + // Islands contract + "--bg-frame": "#eee8d5", + "--bg-island": "#fdf6e3", + "--bg-stripe-hover": "#eee8d5", + "--bg-stripe-selected": "#eee8d5", + "--fg-stripe-selected-active": "#002b36", + "--fg-stripe-label": "#657b83", + "--bg-tab-selected": "#eee8d5", + "--border-tab-selected": "#268bd2", + "--bg-tab-selected-inactive": "#eee8d5", + "--border-tab-selected-inactive": "#eee8d5", + "--bg-tab-hover": "#eee8d5", + "--border-editor-tabs": "#eee8d5", + "--bg-tree-selected": "#eee8d5", + "--bg-tree-selected-inactive": "#eee8d5", + "--bg-tree-hover": "#eee8d5", + "--bg-toolbar-hover": "#eee8d5", + "--bg-toolbar-pressed": "#eee8d5", + "--bg-toolbar-selected": "#eee8d5", + "--bg-toolbar-selected-hover": "#eee8d5", + "--bg-button-primary-hover": "color-mix(in srgb, var(--accent) 86%, #657b83)", + "--fg-button-primary": "#002b36", + "--bg-button": "#fdf6e3", + "--border-button": "#eee8d5", + "--bg-field": "#fdf6e3", + "--bg-checkbox": "#fdf6e3", + "--border-checkbox": "#657b83", + "--bg-toggle-on": "#859900", + "--fg-toggle-on": "#002b36", + "--bg-toggle-off": "#eee8d5", + "--fg-toggle-off": "#657b83", + "--border-toggle": "#657b83", + "--bg-toggle-knob": "#657b83", + "--focus-ring-soft": "#268bd2", + "--scrollbar-thumb": "color-mix(in srgb, #657b83 24%, transparent)", + "--scrollbar-thumb-hover": "color-mix(in srgb, #657b83 42%, transparent)", + "--bg-search-match": "color-mix(in srgb, #b58900 22%, #fdf6e3)", + "--bg-search-match-current": "color-mix(in srgb, #b58900 36%, #fdf6e3)", + "--fg-search-match": "#657b83", + "--bg-dialog": "#fdf6e3", + "--bg-popup-inline": "#eee8d5", + "--bg-popup-advertiser": "#eee8d5", + "--bg-feedback-info": "color-mix(in srgb, #268bd2 12%, #fdf6e3)", + "--border-feedback-info": "color-mix(in srgb, #268bd2 55%, #fdf6e3)", + "--bg-feedback-error": "color-mix(in srgb, #dc322f 12%, #fdf6e3)", + "--border-feedback-error": "color-mix(in srgb, #dc322f 55%, #fdf6e3)", + "--bg-feedback-warning": "color-mix(in srgb, #b58900 12%, #fdf6e3)", + "--border-feedback-warning": "color-mix(in srgb, #b58900 55%, #fdf6e3)", + "--bg-feedback-success": "color-mix(in srgb, #859900 12%, #fdf6e3)", + "--border-feedback-success": "color-mix(in srgb, #859900 55%, #fdf6e3)", + "--bg-counter": "#268bd2", + "--fg-counter": "#002b36", + "--bg-progress-track": "#eee8d5" + } +} diff --git a/public/boot.js b/public/boot.js index 60076f18..28052db0 100644 --- a/public/boot.js +++ b/public/boot.js @@ -3,9 +3,32 @@ // so a new window starts in it instead of flashing the light default. // An external file because the CSP forbids inline scripts. try { + const root = document.documentElement; + const addStyle = (id, css) => { + const style = document.createElement("style"); + style.id = id; + style.textContent = css; + document.head.appendChild(style); + }; const last = JSON.parse(localStorage.getItem("openidea.theme") ?? "null"); - if (last?.theme) document.documentElement.dataset.theme = last.theme; - if (last?.contrast) document.documentElement.dataset.contrast = last.contrast; + if (last?.theme) root.dataset.theme = last.theme; + if (last?.contrast) root.dataset.contrast = last.contrast; + // A plugin theme's stylesheet (plugins/bridge.ts), so the workbench doesn't + // show the built-in theme until the plugin host answers. + const plugin = JSON.parse(localStorage.getItem("openidea.pluginTheme") ?? "null"); + if (typeof plugin?.id === "string" && typeof plugin.css === "string" && !/[<\\]|url\(/i.test(plugin.css)) { + addStyle("openidea-plugin-theme", plugin.css); + root.dataset.pluginTheme = plugin.id; + root.dataset.pluginThemeKind = root.dataset.theme = plugin.kind === "light" ? "light" : "dark"; + delete root.dataset.contrast; + } + // The splash's frame, text and accent colours, resolved by theme.ts (splash.css). + const colors = [ + ["--boot-frame", last?.frame], + ["--boot-fg", last?.fg], + ["--boot-accent", last?.accent], + ].filter(([, v]) => typeof v === "string" && /^#[0-9a-f]{3,8}$/i.test(v)); + if (colors.length) addStyle("openidea-boot-colors", `:root { ${colors.map(([k, v]) => `${k}: ${v};`).join(" ")} }`); } catch { /* storage unavailable */ } diff --git a/public/splash.css b/public/splash.css index 217b6cb7..6bafd18f 100644 --- a/public/splash.css +++ b/public/splash.css @@ -1,11 +1,14 @@ /* Linked, not inlined in index.html: release builds hash inline