Start loading new theme JSON format instead of TOML
Replaced remaining extends with javascript object extension. Moved tokens/core.ts to tokens.ts and massaged the types to make it more obvious when types don't match up. Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
371ea7c552
commit
391aed3d66
23 changed files with 3283 additions and 2008 deletions
|
@ -1,497 +0,0 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use indexmap::IndexMap;
|
||||
use serde_json::Value;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
mem,
|
||||
rc::{Rc, Weak},
|
||||
};
|
||||
|
||||
pub fn resolve_references(value: Value) -> Result<Value> {
|
||||
let tree = Tree::from_json(value)?;
|
||||
tree.resolve()?;
|
||||
tree.to_json()
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Node {
|
||||
Reference {
|
||||
path: String,
|
||||
parent: Option<Weak<RefCell<Node>>>,
|
||||
},
|
||||
Object {
|
||||
base: Option<String>,
|
||||
children: IndexMap<String, Tree>,
|
||||
resolved: bool,
|
||||
parent: Option<Weak<RefCell<Node>>>,
|
||||
},
|
||||
Array {
|
||||
children: Vec<Tree>,
|
||||
resolved: bool,
|
||||
parent: Option<Weak<RefCell<Node>>>,
|
||||
},
|
||||
String {
|
||||
value: String,
|
||||
parent: Option<Weak<RefCell<Node>>>,
|
||||
},
|
||||
Number {
|
||||
value: serde_json::Number,
|
||||
parent: Option<Weak<RefCell<Node>>>,
|
||||
},
|
||||
Bool {
|
||||
value: bool,
|
||||
parent: Option<Weak<RefCell<Node>>>,
|
||||
},
|
||||
Null {
|
||||
parent: Option<Weak<RefCell<Node>>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Tree(Rc<RefCell<Node>>);
|
||||
|
||||
impl Tree {
|
||||
pub fn new(node: Node) -> Self {
|
||||
Self(Rc::new(RefCell::new(node)))
|
||||
}
|
||||
|
||||
fn from_json(value: Value) -> Result<Self> {
|
||||
match value {
|
||||
Value::String(value) => {
|
||||
if let Some(path) = value.strip_prefix("$") {
|
||||
Ok(Self::new(Node::Reference {
|
||||
path: path.to_string(),
|
||||
parent: None,
|
||||
}))
|
||||
} else {
|
||||
Ok(Self::new(Node::String {
|
||||
value,
|
||||
parent: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
Value::Number(value) => Ok(Self::new(Node::Number {
|
||||
value,
|
||||
parent: None,
|
||||
})),
|
||||
Value::Bool(value) => Ok(Self::new(Node::Bool {
|
||||
value,
|
||||
parent: None,
|
||||
})),
|
||||
Value::Null => Ok(Self::new(Node::Null { parent: None })),
|
||||
Value::Object(object) => {
|
||||
let tree = Self::new(Node::Object {
|
||||
base: Default::default(),
|
||||
children: Default::default(),
|
||||
resolved: false,
|
||||
parent: None,
|
||||
});
|
||||
let mut children = IndexMap::new();
|
||||
let mut resolved = true;
|
||||
let mut base = None;
|
||||
for (key, value) in object.into_iter() {
|
||||
let value = if key == "extends" {
|
||||
if value.is_string() {
|
||||
if let Value::String(value) = value {
|
||||
base = value.strip_prefix("$").map(str::to_string);
|
||||
resolved = false;
|
||||
Self::new(Node::String {
|
||||
value,
|
||||
parent: None,
|
||||
})
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
} else {
|
||||
Tree::from_json(value)?
|
||||
}
|
||||
} else {
|
||||
Tree::from_json(value)?
|
||||
};
|
||||
value
|
||||
.0
|
||||
.borrow_mut()
|
||||
.set_parent(Some(Rc::downgrade(&tree.0)));
|
||||
resolved &= value.is_resolved();
|
||||
children.insert(key.clone(), value);
|
||||
}
|
||||
|
||||
*tree.0.borrow_mut() = Node::Object {
|
||||
base,
|
||||
children,
|
||||
resolved,
|
||||
parent: None,
|
||||
};
|
||||
Ok(tree)
|
||||
}
|
||||
Value::Array(elements) => {
|
||||
let tree = Self::new(Node::Array {
|
||||
children: Default::default(),
|
||||
resolved: false,
|
||||
parent: None,
|
||||
});
|
||||
|
||||
let mut children = Vec::new();
|
||||
let mut resolved = true;
|
||||
for element in elements {
|
||||
let child = Tree::from_json(element)?;
|
||||
child
|
||||
.0
|
||||
.borrow_mut()
|
||||
.set_parent(Some(Rc::downgrade(&tree.0)));
|
||||
resolved &= child.is_resolved();
|
||||
children.push(child);
|
||||
}
|
||||
|
||||
*tree.0.borrow_mut() = Node::Array {
|
||||
children,
|
||||
resolved,
|
||||
parent: None,
|
||||
};
|
||||
Ok(tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_json(&self) -> Result<Value> {
|
||||
match &*self.0.borrow() {
|
||||
Node::Reference { .. } => Err(anyhow!("unresolved tree")),
|
||||
Node::String { value, .. } => Ok(Value::String(value.clone())),
|
||||
Node::Number { value, .. } => Ok(Value::Number(value.clone())),
|
||||
Node::Bool { value, .. } => Ok(Value::Bool(*value)),
|
||||
Node::Null { .. } => Ok(Value::Null),
|
||||
Node::Object { children, .. } => {
|
||||
let mut json_children = serde_json::Map::new();
|
||||
for (key, value) in children {
|
||||
json_children.insert(key.clone(), value.to_json()?);
|
||||
}
|
||||
Ok(Value::Object(json_children))
|
||||
}
|
||||
Node::Array { children, .. } => {
|
||||
let mut json_children = Vec::new();
|
||||
for child in children {
|
||||
json_children.push(child.to_json()?);
|
||||
}
|
||||
Ok(Value::Array(json_children))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Tree> {
|
||||
match &*self.0.borrow() {
|
||||
Node::Reference { parent, .. }
|
||||
| Node::Object { parent, .. }
|
||||
| Node::Array { parent, .. }
|
||||
| Node::String { parent, .. }
|
||||
| Node::Number { parent, .. }
|
||||
| Node::Bool { parent, .. }
|
||||
| Node::Null { parent } => parent.as_ref().and_then(|p| p.upgrade()).map(Tree),
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, path: &str) -> Result<Option<Tree>> {
|
||||
let mut tree = self.clone();
|
||||
for component in path.split('.') {
|
||||
let node = tree.0.borrow();
|
||||
match &*node {
|
||||
Node::Object { children, .. } => {
|
||||
if let Some(subtree) = children.get(component).cloned() {
|
||||
drop(node);
|
||||
tree = subtree;
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"key \"{}\" does not exist in path \"{}\"",
|
||||
component,
|
||||
path
|
||||
));
|
||||
}
|
||||
}
|
||||
Node::Reference { .. } => return Ok(None),
|
||||
Node::Array { .. }
|
||||
| Node::String { .. }
|
||||
| Node::Number { .. }
|
||||
| Node::Bool { .. }
|
||||
| Node::Null { .. } => {
|
||||
return Err(anyhow!(
|
||||
"key \"{}\" in path \"{}\" is not an object",
|
||||
component,
|
||||
path
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(tree))
|
||||
}
|
||||
|
||||
fn is_resolved(&self) -> bool {
|
||||
match &*self.0.borrow() {
|
||||
Node::Reference { .. } => false,
|
||||
Node::Object { resolved, .. } | Node::Array { resolved, .. } => *resolved,
|
||||
Node::String { .. } | Node::Number { .. } | Node::Bool { .. } | Node::Null { .. } => {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_resolved(&self) {
|
||||
match &mut *self.0.borrow_mut() {
|
||||
Node::Object {
|
||||
resolved,
|
||||
base,
|
||||
children,
|
||||
..
|
||||
} => {
|
||||
*resolved = base.is_none() && children.values().all(|c| c.is_resolved());
|
||||
}
|
||||
Node::Array {
|
||||
resolved, children, ..
|
||||
} => {
|
||||
*resolved = children.iter().all(|c| c.is_resolved());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(&self) -> Result<()> {
|
||||
let mut unresolved = vec![self.clone()];
|
||||
let mut made_progress = true;
|
||||
|
||||
while made_progress && !unresolved.is_empty() {
|
||||
made_progress = false;
|
||||
for mut tree in mem::take(&mut unresolved) {
|
||||
made_progress |= tree.resolve_subtree(self, &mut unresolved)?;
|
||||
if tree.is_resolved() {
|
||||
while let Some(parent) = tree.parent() {
|
||||
parent.update_resolved();
|
||||
if !parent.is_resolved() {
|
||||
break;
|
||||
}
|
||||
tree = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if unresolved.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("tree contains cycles"))
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_subtree(&self, root: &Tree, unresolved: &mut Vec<Tree>) -> Result<bool> {
|
||||
let node = self.0.borrow();
|
||||
match &*node {
|
||||
Node::Reference { path, parent } => {
|
||||
if let Some(subtree) = root.get(&path)? {
|
||||
if subtree.is_resolved() {
|
||||
let parent = parent.clone();
|
||||
drop(node);
|
||||
let mut new_node = subtree.0.borrow().clone();
|
||||
new_node.set_parent(parent);
|
||||
*self.0.borrow_mut() = new_node;
|
||||
Ok(true)
|
||||
} else {
|
||||
unresolved.push(self.clone());
|
||||
Ok(false)
|
||||
}
|
||||
} else {
|
||||
unresolved.push(self.clone());
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
Node::Object {
|
||||
base,
|
||||
children,
|
||||
resolved,
|
||||
..
|
||||
} => {
|
||||
if *resolved {
|
||||
Ok(false)
|
||||
} else {
|
||||
let mut made_progress = false;
|
||||
let mut children_resolved = true;
|
||||
for child in children.values() {
|
||||
made_progress |= child.resolve_subtree(root, unresolved)?;
|
||||
children_resolved &= child.is_resolved();
|
||||
}
|
||||
|
||||
if children_resolved {
|
||||
let mut has_base = false;
|
||||
let mut resolved_base = None;
|
||||
if let Some(base) = base {
|
||||
has_base = true;
|
||||
if let Some(base) = root.get(base)? {
|
||||
if base.is_resolved() {
|
||||
resolved_base = Some(base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drop(node);
|
||||
|
||||
if let Some(base) = resolved_base.as_ref() {
|
||||
self.extend_from(&base);
|
||||
made_progress = true;
|
||||
}
|
||||
|
||||
if let Node::Object { resolved, base, .. } = &mut *self.0.borrow_mut() {
|
||||
if has_base {
|
||||
if resolved_base.is_some() {
|
||||
base.take();
|
||||
*resolved = true;
|
||||
} else {
|
||||
unresolved.push(self.clone());
|
||||
}
|
||||
} else {
|
||||
*resolved = true;
|
||||
}
|
||||
}
|
||||
} else if base.is_some() {
|
||||
unresolved.push(self.clone());
|
||||
}
|
||||
|
||||
Ok(made_progress)
|
||||
}
|
||||
}
|
||||
Node::Array {
|
||||
children, resolved, ..
|
||||
} => {
|
||||
if *resolved {
|
||||
Ok(false)
|
||||
} else {
|
||||
let mut made_progress = false;
|
||||
let mut children_resolved = true;
|
||||
for child in children.iter() {
|
||||
made_progress |= child.resolve_subtree(root, unresolved)?;
|
||||
children_resolved &= child.is_resolved();
|
||||
}
|
||||
|
||||
if children_resolved {
|
||||
drop(node);
|
||||
|
||||
if let Node::Array { resolved, .. } = &mut *self.0.borrow_mut() {
|
||||
*resolved = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(made_progress)
|
||||
}
|
||||
}
|
||||
Node::String { .. } | Node::Number { .. } | Node::Bool { .. } | Node::Null { .. } => {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_from(&self, base: &Tree) {
|
||||
if Rc::ptr_eq(&self.0, &base.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let (
|
||||
Node::Object { children, .. },
|
||||
Node::Object {
|
||||
children: base_children,
|
||||
..
|
||||
},
|
||||
) = (&mut *self.0.borrow_mut(), &*base.0.borrow())
|
||||
{
|
||||
for (key, base_value) in base_children {
|
||||
if let Some(value) = children.get(key) {
|
||||
value.extend_from(base_value);
|
||||
} else {
|
||||
let base_value = base_value.clone();
|
||||
base_value
|
||||
.0
|
||||
.borrow_mut()
|
||||
.set_parent(Some(Rc::downgrade(&self.0)));
|
||||
children.insert(key.clone(), base_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn set_parent(&mut self, new_parent: Option<Weak<RefCell<Node>>>) {
|
||||
match self {
|
||||
Node::Reference { parent, .. }
|
||||
| Node::Object { parent, .. }
|
||||
| Node::Array { parent, .. }
|
||||
| Node::String { parent, .. }
|
||||
| Node::Number { parent, .. }
|
||||
| Node::Bool { parent, .. }
|
||||
| Node::Null { parent } => *parent = new_parent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_references() {
|
||||
let json = serde_json::json!({
|
||||
"a": {
|
||||
"extends": "$g",
|
||||
"x": "$b.d"
|
||||
},
|
||||
"b": {
|
||||
"c": "$a",
|
||||
"d": "$e.f"
|
||||
},
|
||||
"e": {
|
||||
"extends": "$a",
|
||||
"f": "1"
|
||||
},
|
||||
"g": {
|
||||
"h": 2
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
resolve_references(json).unwrap(),
|
||||
serde_json::json!({
|
||||
"a": {
|
||||
"extends": "$g",
|
||||
"x": "1",
|
||||
"h": 2
|
||||
},
|
||||
"b": {
|
||||
"c": {
|
||||
"extends": "$g",
|
||||
"x": "1",
|
||||
"h": 2
|
||||
},
|
||||
"d": "1"
|
||||
},
|
||||
"e": {
|
||||
"extends": "$a",
|
||||
"f": "1",
|
||||
"x": "1",
|
||||
"h": 2
|
||||
},
|
||||
"g": {
|
||||
"h": 2
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cycles() {
|
||||
let json = serde_json::json!({
|
||||
"a": {
|
||||
"b": "$c.d"
|
||||
},
|
||||
"c": {
|
||||
"d": "$a.b",
|
||||
},
|
||||
});
|
||||
|
||||
assert!(resolve_references(json).is_err());
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
mod resolution;
|
||||
mod theme_registry;
|
||||
|
||||
use gpui::{
|
||||
|
@ -12,7 +11,7 @@ use std::{collections::HashMap, sync::Arc};
|
|||
|
||||
pub use theme_registry::*;
|
||||
|
||||
pub const DEFAULT_THEME_NAME: &'static str = "black";
|
||||
pub const DEFAULT_THEME_NAME: &'static str = "dark";
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct Theme {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::{resolution::resolve_references, Theme};
|
||||
use crate::Theme;
|
||||
use anyhow::{Context, Result};
|
||||
use gpui::{fonts, AssetSource, FontCache};
|
||||
use parking_lot::Mutex;
|
||||
use serde_json::{Map, Value};
|
||||
use serde_json::Value;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
pub struct ThemeRegistry {
|
||||
|
@ -25,12 +25,8 @@ impl ThemeRegistry {
|
|||
pub fn list(&self) -> impl Iterator<Item = String> {
|
||||
self.assets.list("themes/").into_iter().filter_map(|path| {
|
||||
let filename = path.strip_prefix("themes/")?;
|
||||
let theme_name = filename.strip_suffix(".toml")?;
|
||||
if theme_name.starts_with('_') {
|
||||
None
|
||||
} else {
|
||||
Some(theme_name.to_string())
|
||||
}
|
||||
let theme_name = filename.strip_suffix(".json")?;
|
||||
Some(theme_name.to_string())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -44,9 +40,14 @@ impl ThemeRegistry {
|
|||
return Ok(theme.clone());
|
||||
}
|
||||
|
||||
let theme_data = self.load(name, true)?;
|
||||
let asset_path = format!("themes/{}.json", name);
|
||||
let theme_json = self
|
||||
.assets
|
||||
.load(&asset_path)
|
||||
.with_context(|| format!("failed to load theme file {}", asset_path))?;
|
||||
|
||||
let mut theme: Theme = fonts::with_font_cache(self.font_cache.clone(), || {
|
||||
serde_path_to_error::deserialize(theme_data.as_ref())
|
||||
serde_path_to_error::deserialize(&mut serde_json::Deserializer::from_slice(&theme_json))
|
||||
})?;
|
||||
|
||||
theme.name = name.into();
|
||||
|
@ -54,217 +55,4 @@ impl ThemeRegistry {
|
|||
self.themes.lock().insert(name.to_string(), theme.clone());
|
||||
Ok(theme)
|
||||
}
|
||||
|
||||
fn load(&self, name: &str, evaluate_references: bool) -> Result<Arc<Value>> {
|
||||
if let Some(data) = self.theme_data.lock().get(name) {
|
||||
return Ok(data.clone());
|
||||
}
|
||||
|
||||
let asset_path = format!("themes/{}.toml", name);
|
||||
let source_code = self
|
||||
.assets
|
||||
.load(&asset_path)
|
||||
.with_context(|| format!("failed to load theme file {}", asset_path))?;
|
||||
|
||||
let mut theme_data: Map<String, Value> = toml::from_slice(source_code.as_ref())
|
||||
.with_context(|| format!("failed to parse {}.toml", name))?;
|
||||
|
||||
// If this theme extends another base theme, deeply merge it into the base theme's data
|
||||
if let Some(base_name) = theme_data
|
||||
.get("extends")
|
||||
.and_then(|name| name.as_str())
|
||||
.map(str::to_string)
|
||||
{
|
||||
let base_theme_data = self
|
||||
.load(&base_name, false)
|
||||
.with_context(|| format!("failed to load base theme {}", base_name))?
|
||||
.as_ref()
|
||||
.clone();
|
||||
if let Value::Object(mut base_theme_object) = base_theme_data {
|
||||
deep_merge_json(&mut base_theme_object, theme_data);
|
||||
theme_data = base_theme_object;
|
||||
}
|
||||
}
|
||||
|
||||
let mut theme_data = Value::Object(theme_data);
|
||||
|
||||
// Find all of the key path references in the object, and then sort them according
|
||||
// to their dependencies.
|
||||
if evaluate_references {
|
||||
theme_data = resolve_references(theme_data)?;
|
||||
}
|
||||
|
||||
let result = Arc::new(theme_data);
|
||||
self.theme_data
|
||||
.lock()
|
||||
.insert(name.to_string(), result.clone());
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
fn deep_merge_json(base: &mut Map<String, Value>, extension: Map<String, Value>) {
|
||||
for (key, extension_value) in extension {
|
||||
if let Value::Object(extension_object) = extension_value {
|
||||
if let Some(base_object) = base.get_mut(&key).and_then(|value| value.as_object_mut()) {
|
||||
deep_merge_json(base_object, extension_object);
|
||||
} else {
|
||||
base.insert(key, Value::Object(extension_object));
|
||||
}
|
||||
} else {
|
||||
base.insert(key, extension_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use anyhow::anyhow;
|
||||
use gpui::MutableAppContext;
|
||||
|
||||
#[gpui::test]
|
||||
fn test_theme_extension(cx: &mut MutableAppContext) {
|
||||
let assets = TestAssets(&[
|
||||
(
|
||||
"themes/_base.toml",
|
||||
r##"
|
||||
[ui.active_tab]
|
||||
extends = "$ui.tab"
|
||||
border.color = "#666666"
|
||||
text = "$text_colors.bright"
|
||||
|
||||
[ui.tab]
|
||||
extends = "$ui.element"
|
||||
text = "$text_colors.dull"
|
||||
|
||||
[ui.element]
|
||||
background = "#111111"
|
||||
border = {width = 2.0, color = "#00000000"}
|
||||
|
||||
[editor]
|
||||
background = "#222222"
|
||||
default_text = "$text_colors.regular"
|
||||
"##,
|
||||
),
|
||||
(
|
||||
"themes/light.toml",
|
||||
r##"
|
||||
extends = "_base"
|
||||
|
||||
[text_colors]
|
||||
bright = "#ffffff"
|
||||
regular = "#eeeeee"
|
||||
dull = "#dddddd"
|
||||
|
||||
[editor]
|
||||
background = "#232323"
|
||||
"##,
|
||||
),
|
||||
]);
|
||||
|
||||
let registry = ThemeRegistry::new(assets, cx.font_cache().clone());
|
||||
let theme_data = registry.load("light", true).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
theme_data.as_ref(),
|
||||
&serde_json::json!({
|
||||
"ui": {
|
||||
"active_tab": {
|
||||
"background": "#111111",
|
||||
"border": {
|
||||
"width": 2.0,
|
||||
"color": "#666666"
|
||||
},
|
||||
"extends": "$ui.tab",
|
||||
"text": "#ffffff"
|
||||
},
|
||||
"tab": {
|
||||
"background": "#111111",
|
||||
"border": {
|
||||
"width": 2.0,
|
||||
"color": "#00000000"
|
||||
},
|
||||
"extends": "$ui.element",
|
||||
"text": "#dddddd"
|
||||
},
|
||||
"element": {
|
||||
"background": "#111111",
|
||||
"border": {
|
||||
"width": 2.0,
|
||||
"color": "#00000000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"background": "#232323",
|
||||
"default_text": "#eeeeee"
|
||||
},
|
||||
"extends": "_base",
|
||||
"text_colors": {
|
||||
"bright": "#ffffff",
|
||||
"regular": "#eeeeee",
|
||||
"dull": "#dddddd"
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_nested_extension(cx: &mut MutableAppContext) {
|
||||
let assets = TestAssets(&[(
|
||||
"themes/theme.toml",
|
||||
r##"
|
||||
[a]
|
||||
text = { extends = "$text.0" }
|
||||
|
||||
[b]
|
||||
extends = "$a"
|
||||
text = { extends = "$text.1" }
|
||||
|
||||
[text]
|
||||
0 = { color = "red" }
|
||||
1 = { color = "blue" }
|
||||
"##,
|
||||
)]);
|
||||
|
||||
let registry = ThemeRegistry::new(assets, cx.font_cache().clone());
|
||||
let theme_data = registry.load("theme", true).unwrap();
|
||||
assert_eq!(
|
||||
theme_data
|
||||
.get("b")
|
||||
.unwrap()
|
||||
.get("text")
|
||||
.unwrap()
|
||||
.get("color")
|
||||
.unwrap(),
|
||||
"blue"
|
||||
);
|
||||
}
|
||||
|
||||
struct TestAssets(&'static [(&'static str, &'static str)]);
|
||||
|
||||
impl AssetSource for TestAssets {
|
||||
fn load(&self, path: &str) -> Result<std::borrow::Cow<[u8]>> {
|
||||
if let Some(row) = self.0.iter().find(|e| e.0 == path) {
|
||||
Ok(row.1.as_bytes().into())
|
||||
} else {
|
||||
Err(anyhow!("no such path {}", path))
|
||||
}
|
||||
}
|
||||
|
||||
fn list(&self, prefix: &str) -> Vec<std::borrow::Cow<'static, str>> {
|
||||
self.0
|
||||
.iter()
|
||||
.copied()
|
||||
.filter_map(|(path, _)| {
|
||||
if path.starts_with(prefix) {
|
||||
Some(path.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,411 +0,0 @@
|
|||
[text]
|
||||
base = { family = "Zed Sans", size = 14 }
|
||||
|
||||
[workspace]
|
||||
background = "$surface.0"
|
||||
pane_divider = { width = 1, color = "$border.0" }
|
||||
leader_border_opacity = 0.7
|
||||
leader_border_width = 2.0
|
||||
|
||||
[workspace.titlebar]
|
||||
height = 32
|
||||
border = { width = 1, bottom = true, color = "$border.0" }
|
||||
title = "$text.0"
|
||||
avatar_width = 18
|
||||
avatar = { corner_radius = 10, border = { width = 1, color = "#00000088" } }
|
||||
avatar_ribbon = { background = "#ff0000", height = 3, width = 12 }
|
||||
outdated_warning = { extends = "$text.2", size = 13 }
|
||||
share_icon_color = "$text.2.color"
|
||||
share_icon_active_color = "$text.0.color"
|
||||
|
||||
[workspace.titlebar.sign_in_prompt]
|
||||
extends = "$text.2"
|
||||
size = 13
|
||||
underline = true
|
||||
padding = { right = 8 }
|
||||
|
||||
[workspace.titlebar.hovered_sign_in_prompt]
|
||||
extends = "$workspace.titlebar.sign_in_prompt"
|
||||
color = "$text.1.color"
|
||||
|
||||
[workspace.titlebar.offline_icon]
|
||||
padding = { right = 4 }
|
||||
width = 16
|
||||
color = "$text.2.color"
|
||||
|
||||
[workspace.tab]
|
||||
height = 34
|
||||
text = "$text.2"
|
||||
padding = { left = 12, right = 12 }
|
||||
icon_width = 8
|
||||
spacing = 10
|
||||
icon_close = "$text.2.color"
|
||||
icon_close_active = "$text.0.color"
|
||||
icon_dirty = "$status.info"
|
||||
icon_conflict = "$status.warn"
|
||||
border = { left = true, bottom = true, width = 1, color = "$border.0", overlay = true }
|
||||
|
||||
[workspace.active_tab]
|
||||
extends = "$workspace.tab"
|
||||
border.bottom = false
|
||||
background = "$surface.1"
|
||||
text = "$text.0"
|
||||
|
||||
[workspace.sidebar]
|
||||
width = 30
|
||||
border = { right = true, width = 1, color = "$border.0" }
|
||||
|
||||
[workspace.sidebar.resize_handle]
|
||||
padding = { left = 1 }
|
||||
background = "$border.0"
|
||||
|
||||
[workspace.sidebar.item]
|
||||
icon_color = "$text.2.color"
|
||||
icon_size = 18
|
||||
height = "$workspace.tab.height"
|
||||
|
||||
[workspace.sidebar.active_item]
|
||||
extends = "$workspace.sidebar.item"
|
||||
icon_color = "$text.0.color"
|
||||
|
||||
[workspace.left_sidebar]
|
||||
extends = "$workspace.sidebar"
|
||||
border = { width = 1, color = "$border.0", right = true }
|
||||
|
||||
[workspace.right_sidebar]
|
||||
extends = "$workspace.sidebar"
|
||||
border = { width = 1, color = "$border.0", left = true }
|
||||
|
||||
[workspace.status_bar]
|
||||
padding = { left = 6, right = 6 }
|
||||
height = 24
|
||||
item_spacing = 8
|
||||
cursor_position = "$text.2"
|
||||
diagnostic_message = "$text.2"
|
||||
lsp_message = "$text.2"
|
||||
|
||||
[workspace.toolbar]
|
||||
background = "$surface.1"
|
||||
border = { color = "$border.0", width = 1, left = false, right = false, bottom = true, top = false }
|
||||
height = 34
|
||||
item_spacing = 8
|
||||
padding = { left = 16, right = 8, top = 4, bottom = 4 }
|
||||
|
||||
[breadcrumbs]
|
||||
extends = "$text.1"
|
||||
padding = { left = 6 }
|
||||
|
||||
[panel]
|
||||
padding = { top = 12, left = 12, bottom = 12, right = 12 }
|
||||
|
||||
[chat_panel]
|
||||
extends = "$panel"
|
||||
channel_name = { extends = "$text.0", weight = "bold" }
|
||||
channel_name_hash = { text = "$text.2", padding.right = 8 }
|
||||
|
||||
[chat_panel.message]
|
||||
body = "$text.1"
|
||||
sender = { extends = "$text.0", weight = "bold", margin.right = 8 }
|
||||
timestamp = "$text.2"
|
||||
padding.bottom = 6
|
||||
|
||||
[chat_panel.pending_message]
|
||||
extends = "$chat_panel.message"
|
||||
body = { color = "$text.3.color" }
|
||||
sender = { color = "$text.3.color" }
|
||||
timestamp = { color = "$text.3.color" }
|
||||
|
||||
[chat_panel.channel_select.item]
|
||||
padding = 4
|
||||
name = "$text.1"
|
||||
hash = { extends = "$text.2", margin.right = 8 }
|
||||
|
||||
[chat_panel.channel_select.hovered_item]
|
||||
extends = "$chat_panel.channel_select.item"
|
||||
background = "$state.hover"
|
||||
corner_radius = 6
|
||||
|
||||
[chat_panel.channel_select.active_item]
|
||||
extends = "$chat_panel.channel_select.item"
|
||||
name = "$text.0"
|
||||
|
||||
[chat_panel.channel_select.hovered_active_item]
|
||||
extends = "$chat_panel.channel_select.hovered_item"
|
||||
name = "$text.0"
|
||||
|
||||
[chat_panel.channel_select.header]
|
||||
extends = "$chat_panel.channel_select.active_item"
|
||||
padding.bottom = 4
|
||||
padding.left = 0
|
||||
|
||||
[chat_panel.channel_select.menu]
|
||||
padding = 4
|
||||
corner_radius = 6
|
||||
border = { color = "$border.0", width = 1 }
|
||||
background = "$surface.0"
|
||||
shadow = { offset = [0, 2], blur = 16, color = "$shadow.0" }
|
||||
|
||||
[chat_panel.input_editor]
|
||||
background = "$surface.1"
|
||||
corner_radius = 6
|
||||
padding = { left = 8, right = 8, top = 7, bottom = 7 }
|
||||
text = "$text.0"
|
||||
placeholder_text = "$text.2"
|
||||
selection = "$selection.host"
|
||||
border = { width = 1, color = "$border.0" }
|
||||
|
||||
[chat_panel.sign_in_prompt]
|
||||
extends = "$text.0"
|
||||
underline = true
|
||||
|
||||
[chat_panel.hovered_sign_in_prompt]
|
||||
extends = "$chat_panel.sign_in_prompt"
|
||||
color = "$text.1.color"
|
||||
|
||||
[contacts_panel]
|
||||
extends = "$panel"
|
||||
host_row_height = 28
|
||||
host_avatar = { corner_radius = 10, width = 18 }
|
||||
host_username = { extends = "$text.0", padding.left = 8 }
|
||||
tree_branch_width = 1
|
||||
tree_branch_color = "$surface.2"
|
||||
|
||||
[contacts_panel.project]
|
||||
height = 24
|
||||
padding = { left = 8 }
|
||||
guest_avatar = { corner_radius = 8, width = 14 }
|
||||
guest_avatar_spacing = 4
|
||||
|
||||
[contacts_panel.project.name]
|
||||
extends = "$text.1"
|
||||
margin = { right = 6 }
|
||||
|
||||
[contacts_panel.unshared_project]
|
||||
extends = "$contacts_panel.project"
|
||||
|
||||
[contacts_panel.hovered_unshared_project]
|
||||
extends = "$contacts_panel.unshared_project"
|
||||
background = "$state.hover"
|
||||
corner_radius = 6
|
||||
|
||||
[contacts_panel.shared_project]
|
||||
extends = "$contacts_panel.project"
|
||||
name.color = "$text.0.color"
|
||||
|
||||
[contacts_panel.hovered_shared_project]
|
||||
extends = "$contacts_panel.shared_project"
|
||||
background = "$state.hover"
|
||||
corner_radius = 6
|
||||
|
||||
[project_panel]
|
||||
extends = "$panel"
|
||||
padding.top = 6 # ($workspace.tab.height - $project_panel.entry.height) / 2
|
||||
|
||||
[project_panel.entry]
|
||||
text = "$text.1"
|
||||
height = 22
|
||||
icon_color = "$text.3.color"
|
||||
icon_size = 8
|
||||
icon_spacing = 8
|
||||
|
||||
[project_panel.hovered_entry]
|
||||
extends = "$project_panel.entry"
|
||||
background = "$state.hover"
|
||||
|
||||
[project_panel.selected_entry]
|
||||
extends = "$project_panel.entry"
|
||||
text = { extends = "$text.0" }
|
||||
|
||||
[project_panel.hovered_selected_entry]
|
||||
extends = "$project_panel.hovered_entry"
|
||||
text = { extends = "$text.0" }
|
||||
|
||||
[selector]
|
||||
background = "$surface.0"
|
||||
padding = 8
|
||||
margin = { top = 52, bottom = 52 }
|
||||
corner_radius = 6
|
||||
shadow = { offset = [0, 2], blur = 16, color = "$shadow.0" }
|
||||
border = { width = 1, color = "$border.0" }
|
||||
|
||||
[selector.input_editor]
|
||||
background = "$surface.1"
|
||||
corner_radius = 6
|
||||
padding = { left = 16, right = 16, top = 7, bottom = 7 }
|
||||
text = "$text.0"
|
||||
placeholder_text = "$text.2"
|
||||
selection = "$selection.host"
|
||||
border = { width = 1, color = "$border.0" }
|
||||
|
||||
[selector.empty]
|
||||
text = "$text.2"
|
||||
padding = { left = 16, right = 16, top = 8, bottom = 4 }
|
||||
|
||||
[selector.item]
|
||||
text = "$text.1"
|
||||
highlight_text = { extends = "$text.base", color = "$editor.syntax.keyword.color", weight = "$editor.syntax.keyword.weight" }
|
||||
padding = { left = 16, right = 16, top = 4, bottom = 4 }
|
||||
corner_radius = 6
|
||||
|
||||
[selector.active_item]
|
||||
extends = "$selector.item"
|
||||
background = "$state.hover"
|
||||
text = "$text.0"
|
||||
|
||||
[editor]
|
||||
text_color = "$text.1.color"
|
||||
background = "$surface.1"
|
||||
gutter_background = "$surface.1"
|
||||
gutter_padding_factor = 2.5
|
||||
active_line_background = "$state.active_line"
|
||||
highlighted_line_background = "$state.highlighted_line"
|
||||
rename_fade = 0.6
|
||||
unnecessary_code_fade = 0.5
|
||||
document_highlight_read_background = "#99999920"
|
||||
document_highlight_write_background = "#99999916"
|
||||
diff_background_deleted = "$state.deleted_line"
|
||||
diff_background_inserted = "$state.inserted_line"
|
||||
line_number = "$text.2.color"
|
||||
line_number_active = "$text.0.color"
|
||||
selection = "$selection.host"
|
||||
guest_selections = "$selection.guests"
|
||||
error_color = "$status.bad"
|
||||
code_actions_indicator = "$text.3.color"
|
||||
|
||||
[editor.diagnostic_path_header]
|
||||
background = "$state.active_line"
|
||||
filename = { extends = "$text.0", size = 14 }
|
||||
path = { extends = "$text.2", size = 14, margin.left = 12 }
|
||||
text_scale_factor = 0.857
|
||||
|
||||
[editor.diagnostic_header]
|
||||
background = "$editor.background"
|
||||
border = { width = 1, top = true, bottom = true, color = "$border.1" }
|
||||
code = { extends = "$text.2", size = 14, margin.left = 10 }
|
||||
icon_width_factor = 1.5
|
||||
text_scale_factor = 0.857
|
||||
|
||||
[editor.diagnostic_header.message]
|
||||
text = { extends = "$text.1", size = 14 }
|
||||
highlight_text = { extends = "$text.0", size = 14, weight = "bold" }
|
||||
|
||||
[editor.error_diagnostic]
|
||||
header.border = { width = 1, top = true, color = "$border.0" }
|
||||
text_scale_factor = 0.857
|
||||
|
||||
[editor.error_diagnostic.message]
|
||||
text = { extends = "$text.1", size = 14, color = "$status.bad" }
|
||||
highlight_text = { extends = "$text.1", size = 14, color = "$status.bad", weight = "bold" }
|
||||
|
||||
[editor.warning_diagnostic]
|
||||
extends = "$editor.error_diagnostic"
|
||||
message.text.color = "$status.warn"
|
||||
message.highlight_text.color = "$status.warn"
|
||||
|
||||
[editor.information_diagnostic]
|
||||
extends = "$editor.error_diagnostic"
|
||||
message.text.color = "$status.info"
|
||||
message.highlight_text.color = "$status.info"
|
||||
|
||||
[editor.hint_diagnostic]
|
||||
extends = "$editor.error_diagnostic"
|
||||
message.text.color = "$status.info"
|
||||
message.highlight_text.color = "$status.info"
|
||||
|
||||
[editor.invalid_error_diagnostic]
|
||||
extends = "$editor.error_diagnostic"
|
||||
message.text.color = "$text.3.color"
|
||||
message.highlight_text.color = "$text.3.color"
|
||||
|
||||
[editor.invalid_warning_diagnostic]
|
||||
extends = "$editor.warning_diagnostic"
|
||||
message.text.color = "$text.3.color"
|
||||
message.highlight_text.color = "$text.3.color"
|
||||
|
||||
[editor.invalid_information_diagnostic]
|
||||
extends = "$editor.information_diagnostic"
|
||||
message.text.color = "$text.3.color"
|
||||
message.highlight_text.color = "$text.3.color"
|
||||
|
||||
[editor.invalid_hint_diagnostic]
|
||||
extends = "$editor.hint_diagnostic"
|
||||
message.text.color = "$text.3.color"
|
||||
message.highlight_text.color = "$text.3.color"
|
||||
|
||||
[editor.autocomplete]
|
||||
background = "$surface.2"
|
||||
border = { width = 2, color = "$border.1" }
|
||||
corner_radius = 6
|
||||
padding = 6
|
||||
match_highlight = { color = "$editor.syntax.keyword.color", weight = "$editor.syntax.keyword.weight" }
|
||||
margin.left = -14
|
||||
|
||||
[editor.autocomplete.item]
|
||||
padding = { left = 6, right = 6, top = 2, bottom = 2 }
|
||||
corner_radius = 6
|
||||
|
||||
[editor.autocomplete.selected_item]
|
||||
extends = "$editor.autocomplete.item"
|
||||
background = "$state.selected"
|
||||
|
||||
[editor.autocomplete.hovered_item]
|
||||
extends = "$editor.autocomplete.item"
|
||||
background = "$state.hover"
|
||||
|
||||
[project_diagnostics]
|
||||
background = "$surface.1"
|
||||
empty_message = { extends = "$text.0", size = 18 }
|
||||
status_bar_item = { extends = "$text.2", margin.right = 10 }
|
||||
tab_icon_width = 13
|
||||
tab_icon_spacing = 4
|
||||
tab_summary_spacing = 10
|
||||
|
||||
[search]
|
||||
match_background = "$state.highlighted_line"
|
||||
results_status = { extends = "$text.0", size = 18 }
|
||||
tab_icon_width = 14
|
||||
tab_icon_spacing = 4
|
||||
|
||||
[search.option_button]
|
||||
extends = "$text.1"
|
||||
padding = { left = 6, right = 6, top = 1, bottom = 1 }
|
||||
corner_radius = 6
|
||||
background = "$surface.1"
|
||||
border = { width = 1, color = "$border.0" }
|
||||
margin.left = 1
|
||||
margin.right = 1
|
||||
|
||||
[search.option_button_group]
|
||||
padding = { left = 2, right = 2 }
|
||||
|
||||
[search.active_option_button]
|
||||
extends = "$search.option_button"
|
||||
background = "$surface.2"
|
||||
|
||||
[search.hovered_option_button]
|
||||
extends = "$search.option_button"
|
||||
background = "$surface.2"
|
||||
|
||||
[search.active_hovered_option_button]
|
||||
extends = "$search.option_button"
|
||||
background = "$surface.2"
|
||||
|
||||
[search.match_index]
|
||||
extends = "$text.2"
|
||||
padding = 6
|
||||
|
||||
[search.editor]
|
||||
min_width = 200
|
||||
max_width = 500
|
||||
background = "$surface.0"
|
||||
corner_radius = 6
|
||||
padding = { left = 14, right = 14, top = 3, bottom = 3 }
|
||||
margin = { right = 5 }
|
||||
text = "$text.0"
|
||||
placeholder_text = "$text.2"
|
||||
selection = "$selection.host"
|
||||
border = { width = 1, color = "$border.0" }
|
||||
|
||||
[search.invalid_editor]
|
||||
extends = "$search.editor"
|
||||
border = { width = 1, color = "$status.bad" }
|
|
@ -1,67 +0,0 @@
|
|||
extends = "_base"
|
||||
|
||||
[surface]
|
||||
0 = "#222222"
|
||||
1 = "#0f0b0c"
|
||||
2 = "#131415"
|
||||
|
||||
[border]
|
||||
0 = "#000000B2"
|
||||
1 = "#FFFFFF20"
|
||||
|
||||
[text]
|
||||
0 = { extends = "$text.base", color = "#ffffff" }
|
||||
1 = { extends = "$text.base", color = "#b3b3b3" }
|
||||
2 = { extends = "$text.base", color = "#7b7d80" }
|
||||
3 = { extends = "$text.base", color = "#66686A" }
|
||||
|
||||
[shadow]
|
||||
0 = "#00000052"
|
||||
|
||||
[selection]
|
||||
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||
guests = [
|
||||
{ selection = "#FDF35133", cursor = "#FDF351" },
|
||||
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
||||
{ selection = "#D0453B33", cursor = "#D0453B" },
|
||||
{ selection = "#3B874B33", cursor = "#3B874B" },
|
||||
{ selection = "#BD7CB433", cursor = "#BD7CB4" },
|
||||
{ selection = "#EE823133", cursor = "#EE8231" },
|
||||
{ selection = "#5A2B9233", cursor = "#5A2B92" },
|
||||
]
|
||||
|
||||
[status]
|
||||
good = "#4fac63"
|
||||
info = "#3c5dd4"
|
||||
warn = "#faca50"
|
||||
bad = "#b7372e"
|
||||
|
||||
[state]
|
||||
active_line = "#161313"
|
||||
highlighted_line = "#faca5033"
|
||||
deleted_line = "#dd000036"
|
||||
inserted_line = "#00dd0036"
|
||||
hover = "#00000033"
|
||||
selected = "#00000088"
|
||||
|
||||
[editor.syntax]
|
||||
keyword = { color = "#0086c0", weight = "bold" }
|
||||
function = "#dcdcaa"
|
||||
string = "#cb8f77"
|
||||
type = "#4ec9b0"
|
||||
number = "#b5cea8"
|
||||
comment = "#6a9955"
|
||||
property = "#4e94ce"
|
||||
variant = "#4fc1ff"
|
||||
constant = "#9cdcfe"
|
||||
title = { color = "#9cdcfe", weight = "bold" }
|
||||
emphasis = "#4ec9b0"
|
||||
"emphasis.strong" = { color = "#4ec9b0", weight = "bold" }
|
||||
link_uri = { color = "#6a9955", underline = true }
|
||||
link_text = { color = "#cb8f77", italic = true }
|
||||
list_marker = "#4e94ce"
|
||||
|
||||
[workspace.disconnected_overlay]
|
||||
extends = "$text.base"
|
||||
color = "#ffffff"
|
||||
background = "#000000aa"
|
1245
crates/zed/assets/themes/dark.json
Normal file
1245
crates/zed/assets/themes/dark.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,67 +0,0 @@
|
|||
extends = "_base"
|
||||
|
||||
[surface]
|
||||
0 = "#283340"
|
||||
1 = "#1C2733"
|
||||
2 = "#1C2733"
|
||||
|
||||
[border]
|
||||
0 = "#1B222B"
|
||||
1 = "#FFFFFF20"
|
||||
|
||||
[text]
|
||||
0 = { extends = "$text.base", color = "#FFFFFF" }
|
||||
1 = { extends = "$text.base", color = "#CDD1E2" }
|
||||
2 = { extends = "$text.base", color = "#9BA8BE" }
|
||||
3 = { extends = "$text.base", color = "#6E7483" }
|
||||
|
||||
[shadow]
|
||||
0 = "#00000052"
|
||||
|
||||
[selection]
|
||||
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||
guests = [
|
||||
{ selection = "#FDF35133", cursor = "#FDF351" },
|
||||
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
||||
{ selection = "#D0453B33", cursor = "#D0453B" },
|
||||
{ selection = "#3B874B33", cursor = "#3B874B" },
|
||||
{ selection = "#BD7CB433", cursor = "#BD7CB4" },
|
||||
{ selection = "#EE823133", cursor = "#EE8231" },
|
||||
{ selection = "#5A2B9233", cursor = "#5A2B92" },
|
||||
]
|
||||
|
||||
[status]
|
||||
good = "#4fac63"
|
||||
info = "#3c5dd4"
|
||||
warn = "#faca50"
|
||||
bad = "#b7372e"
|
||||
|
||||
[state]
|
||||
active_line = "#00000022"
|
||||
highlighted_line = "#faca5033"
|
||||
deleted_line = "#dd000036"
|
||||
inserted_line = "#00dd0036"
|
||||
hover = "#00000033"
|
||||
selected = "#00000088"
|
||||
|
||||
[editor.syntax]
|
||||
keyword = { color = "#0086c0", weight = "bold" }
|
||||
function = "#dcdcaa"
|
||||
string = "#cb8f77"
|
||||
type = "#4ec9b0"
|
||||
number = "#b5cea8"
|
||||
comment = "#6a9955"
|
||||
property = "#4e94ce"
|
||||
variant = "#4fc1ff"
|
||||
constant = "#9cdcfe"
|
||||
title = { color = "#9cdcfe", weight = "bold" }
|
||||
emphasis = "#4ec9b0"
|
||||
"emphasis.strong" = { color = "#4ec9b0", weight = "bold" }
|
||||
link_uri = { color = "#6a9955", underline = true }
|
||||
link_text = { color = "#cb8f77", italic = true }
|
||||
list_marker = "#4e94ce"
|
||||
|
||||
[workspace.disconnected_overlay]
|
||||
extends = "$text.base"
|
||||
color = "#ffffff"
|
||||
background = "#000000aa"
|
1245
crates/zed/assets/themes/light.json
Normal file
1245
crates/zed/assets/themes/light.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,67 +0,0 @@
|
|||
extends = "_base"
|
||||
|
||||
[surface]
|
||||
0 = "#EAEAEB"
|
||||
1 = "#FAFAFA"
|
||||
2 = "#FFFFFF"
|
||||
|
||||
[border]
|
||||
0 = "#DDDDDC"
|
||||
1 = "#0000000F"
|
||||
|
||||
[text]
|
||||
0 = { extends = "$text.base", color = "#000000" }
|
||||
1 = { extends = "$text.base", color = "#29292B" }
|
||||
2 = { extends = "$text.base", color = "#7E7E83" }
|
||||
3 = { extends = "$text.base", color = "#939393" }
|
||||
|
||||
[shadow]
|
||||
0 = "#0000000D"
|
||||
|
||||
[selection]
|
||||
host = { selection = "#3B57BC55", cursor = "$text.0.color" }
|
||||
guests = [
|
||||
{ selection = "#D0453B33", cursor = "#D0453B" },
|
||||
{ selection = "#3B874B33", cursor = "#3B874B" },
|
||||
{ selection = "#BD7CB433", cursor = "#BD7CB4" },
|
||||
{ selection = "#EE823133", cursor = "#EE8231" },
|
||||
{ selection = "#5A2B9233", cursor = "#5A2B92" },
|
||||
{ selection = "#FDF35133", cursor = "#FDF351" },
|
||||
{ selection = "#4EACAD33", cursor = "#4EACAD" },
|
||||
]
|
||||
|
||||
[status]
|
||||
good = "#4fac63"
|
||||
info = "#3c5dd4"
|
||||
warn = "#faca50"
|
||||
bad = "#b7372e"
|
||||
|
||||
[state]
|
||||
active_line = "#00000008"
|
||||
highlighted_line = "#faca5033"
|
||||
deleted_line = "#dd000036"
|
||||
inserted_line = "#00dd0036"
|
||||
hover = "#0000000D"
|
||||
selected = "#0000001c"
|
||||
|
||||
[editor.syntax]
|
||||
keyword = { color = "#0000fa", weight = "bold" }
|
||||
function = "#795e26"
|
||||
string = "#a82121"
|
||||
type = "#267f29"
|
||||
number = "#b5cea8"
|
||||
comment = "#6a9955"
|
||||
property = "#4e94ce"
|
||||
variant = "#4fc1ff"
|
||||
constant = "#5a9ccc"
|
||||
title = { color = "#5a9ccc", weight = "bold" }
|
||||
emphasis = "#267f29"
|
||||
"emphasis.strong" = { color = "#267f29", weight = "bold" }
|
||||
link_uri = { color = "#6a9955", underline = true }
|
||||
link_text = { color = "#a82121", italic = true }
|
||||
list_marker = "#4e94ce"
|
||||
|
||||
[workspace.disconnected_overlay]
|
||||
extends = "$text.base"
|
||||
color = "#ffffff"
|
||||
background = "#000000cc"
|
|
@ -988,7 +988,8 @@ mod tests {
|
|||
lazy_static::lazy_static! {
|
||||
static ref DEFAULT_THEME: parking_lot::Mutex<Option<Arc<Theme>>> = Default::default();
|
||||
static ref FONTS: Vec<Arc<Vec<u8>>> = vec![
|
||||
Assets.load("fonts/zed-sans/zed-sans-extended.ttf").unwrap().to_vec().into()
|
||||
Assets.load("fonts/zed-sans/zed-sans-extended.ttf").unwrap().to_vec().into(),
|
||||
Assets.load("fonts/zed-mono/zed-mono-extended.ttf").unwrap().to_vec().into(),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ import decamelizeTree from "./utils/decamelizeTree";
|
|||
|
||||
const themes = [dark, light];
|
||||
for (let theme of themes) {
|
||||
let styleTree = decamelizeTree(app(theme));
|
||||
let styleTreeJSON = JSON.stringify(styleTree, null, 2);
|
||||
let outPath = path.resolve(
|
||||
`${__dirname}/../crates/zed/assets/themes/${theme.name}.json`
|
||||
);
|
||||
fs.writeFileSync(outPath, styleTreeJSON);
|
||||
console.log(`Generated ${outPath}`);
|
||||
let styleTree = decamelizeTree(app(theme));
|
||||
let styleTreeJSON = JSON.stringify(styleTree, null, 2);
|
||||
let outPath = path.resolve(
|
||||
`${__dirname}/../crates/zed/assets/themes/${theme.name}.json`
|
||||
);
|
||||
fs.writeFileSync(outPath, styleTreeJSON);
|
||||
console.log(`Generated ${outPath}`);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Theme from "../themes/theme";
|
||||
import chatPanel from "./chatPanel";
|
||||
import { backgroundColor, borderColor, text } from "./components";
|
||||
import contactsPanel from "./contactsPanel";
|
||||
import editor from "./editor";
|
||||
import projectPanel from "./projectPanel";
|
||||
import search from "./search";
|
||||
|
@ -8,83 +9,38 @@ import selectorModal from "./selectorModal";
|
|||
import workspace from "./workspace";
|
||||
|
||||
export const panel = {
|
||||
padding: { top: 12, left: 12, bottom: 12, right: 12 },
|
||||
padding: { top: 12, left: 12, bottom: 12, right: 12 },
|
||||
};
|
||||
|
||||
export default function app(theme: Theme): Object {
|
||||
return {
|
||||
selector: selectorModal(theme),
|
||||
workspace: workspace(theme),
|
||||
editor: editor(theme),
|
||||
projectDiagnostics: {
|
||||
background: backgroundColor(theme, 300),
|
||||
tabIconSpacing: 4,
|
||||
tabIconWidth: 13,
|
||||
tabSummarySpacing: 10,
|
||||
emptyMessage: {
|
||||
...text(theme, "sans", "primary", { size: "lg" }),
|
||||
},
|
||||
statusBarItem: {
|
||||
...text(theme, "sans", "muted"),
|
||||
margin: {
|
||||
right: 10,
|
||||
return {
|
||||
selector: selectorModal(theme),
|
||||
workspace: workspace(theme),
|
||||
editor: editor(theme),
|
||||
projectDiagnostics: {
|
||||
background: backgroundColor(theme, 300),
|
||||
tabIconSpacing: 4,
|
||||
tabIconWidth: 13,
|
||||
tabSummarySpacing: 10,
|
||||
emptyMessage: {
|
||||
...text(theme, "sans", "primary", { size: "lg" }),
|
||||
},
|
||||
statusBarItem: {
|
||||
...text(theme, "sans", "muted"),
|
||||
margin: {
|
||||
right: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
projectPanel: projectPanel(theme),
|
||||
chatPanel: chatPanel(theme),
|
||||
contactsPanel: {
|
||||
...panel,
|
||||
hostRowHeight: 28,
|
||||
treeBranchColor: borderColor(theme, "muted"),
|
||||
treeBranchWidth: 1,
|
||||
hostAvatar: {
|
||||
cornerRadius: 10,
|
||||
width: 18,
|
||||
},
|
||||
hostUsername: {
|
||||
...text(theme, "mono", "muted"),
|
||||
padding: {
|
||||
left: 8,
|
||||
},
|
||||
},
|
||||
hoveredSharedProject: {
|
||||
extends: "$contacts_panel.sharedProject",
|
||||
background: theme.editor.line.active.value,
|
||||
cornerRadius: 6,
|
||||
},
|
||||
hoveredUnsharedProject: {
|
||||
extends: "$contacts_panel.unsharedProject",
|
||||
background: theme.editor.line.active.value,
|
||||
cornerRadius: 6,
|
||||
},
|
||||
project: {
|
||||
guestAvatarSpacing: 4,
|
||||
height: 24,
|
||||
guestAvatar: {
|
||||
cornerRadius: 8,
|
||||
width: 14,
|
||||
},
|
||||
name: {
|
||||
extends: text(theme, "mono", "secondary"),
|
||||
margin: {
|
||||
right: 6,
|
||||
},
|
||||
},
|
||||
padding: {
|
||||
left: 8,
|
||||
},
|
||||
},
|
||||
sharedProject: {
|
||||
extends: "$contactsPanel.project",
|
||||
name: {
|
||||
color: text(theme, "mono", "primary"),
|
||||
},
|
||||
},
|
||||
unsharedProject: {
|
||||
extends: "$contactsPanel.project",
|
||||
},
|
||||
},
|
||||
search: search(theme),
|
||||
};
|
||||
projectPanel: projectPanel(theme),
|
||||
chatPanel: chatPanel(theme),
|
||||
contactsPanel: contactsPanel(theme),
|
||||
search: search(theme),
|
||||
breadcrumbs: {
|
||||
...text(theme, "sans", "primary"),
|
||||
padding: {
|
||||
left: 6,
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import chroma from "chroma-js";
|
||||
import Theme, { BackgroundColor, Weight } from "../themes/theme";
|
||||
import core from "../tokens/core";
|
||||
import Theme, { BackgroundColor } from "../themes/theme";
|
||||
import { fontFamilies, fontSizes, FontWeight } from "../tokens";
|
||||
import { Color } from "../utils/color";
|
||||
|
||||
export type TextColor = keyof Theme["textColor"];
|
||||
|
||||
export function text(
|
||||
theme: Theme,
|
||||
fontFamily: keyof typeof core.fontFamily,
|
||||
fontFamily: keyof typeof fontFamilies,
|
||||
color: TextColor,
|
||||
properties?: {
|
||||
size?: keyof typeof core["fontSize"];
|
||||
weight?: Weight;
|
||||
size?: keyof typeof fontSizes;
|
||||
weight?: FontWeight;
|
||||
underline?: boolean;
|
||||
}
|
||||
) {
|
||||
const sizeKey = properties?.size || fontFamily === "sans" ? "sm" : "md";
|
||||
const size = core.fontSize[sizeKey].value;
|
||||
const size = fontSizes[sizeKey].value;
|
||||
|
||||
return {
|
||||
family: core.fontFamily[fontFamily],
|
||||
family: fontFamilies[fontFamily].value,
|
||||
color: theme.textColor[color].value,
|
||||
...properties,
|
||||
size,
|
||||
|
|
61
styles/styleTree/contactsPanel.ts
Normal file
61
styles/styleTree/contactsPanel.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
import Theme from "../themes/theme";
|
||||
import { panel } from "./app";
|
||||
import { borderColor, text } from "./components";
|
||||
|
||||
export default function(theme: Theme) {
|
||||
const project = {
|
||||
guestAvatarSpacing: 4,
|
||||
height: 24,
|
||||
guestAvatar: {
|
||||
cornerRadius: 8,
|
||||
width: 14,
|
||||
},
|
||||
name: {
|
||||
...text(theme, "mono", "secondary"),
|
||||
margin: {
|
||||
right: 6,
|
||||
},
|
||||
},
|
||||
padding: {
|
||||
left: 8,
|
||||
},
|
||||
};
|
||||
|
||||
const sharedProject = {
|
||||
...project,
|
||||
name: {
|
||||
...project.name,
|
||||
...text(theme, "mono", "primary"),
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
...panel,
|
||||
hostRowHeight: 28,
|
||||
treeBranchColor: borderColor(theme, "muted"),
|
||||
treeBranchWidth: 1,
|
||||
hostAvatar: {
|
||||
cornerRadius: 10,
|
||||
width: 18,
|
||||
},
|
||||
hostUsername: {
|
||||
...text(theme, "mono", "muted"),
|
||||
padding: {
|
||||
left: 8,
|
||||
},
|
||||
},
|
||||
project,
|
||||
sharedProject,
|
||||
hoveredSharedProject: {
|
||||
...sharedProject,
|
||||
background: theme.editor.line.active.value,
|
||||
cornerRadius: 6,
|
||||
},
|
||||
unsharedProject: project,
|
||||
hoveredUnsharedProject: {
|
||||
...project,
|
||||
background: theme.editor.line.active.value,
|
||||
cornerRadius: 6,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -1,131 +1,134 @@
|
|||
import Theme from "../themes/theme";
|
||||
import {
|
||||
backgroundColor,
|
||||
border,
|
||||
iconColor,
|
||||
player,
|
||||
text,
|
||||
TextColor
|
||||
backgroundColor,
|
||||
border,
|
||||
iconColor,
|
||||
player,
|
||||
text,
|
||||
TextColor,
|
||||
} from "./components";
|
||||
|
||||
export default function editor(theme: Theme) {
|
||||
const autocompleteItem = {
|
||||
cornerRadius: 6,
|
||||
padding: {
|
||||
bottom: 2,
|
||||
left: 6,
|
||||
right: 6,
|
||||
top: 2,
|
||||
},
|
||||
};
|
||||
|
||||
function diagnostic(theme: Theme, color: TextColor) {
|
||||
return {
|
||||
textScaleFactor: 0.857,
|
||||
header: {
|
||||
border: border(theme, "primary", {
|
||||
top: true,
|
||||
}),
|
||||
},
|
||||
message: {
|
||||
text: text(theme, "sans", color, { size: "sm" }),
|
||||
highlightText: text(theme, "sans", color, {
|
||||
size: "sm",
|
||||
weight: "bold",
|
||||
}),
|
||||
},
|
||||
const autocompleteItem = {
|
||||
cornerRadius: 6,
|
||||
padding: {
|
||||
bottom: 2,
|
||||
left: 6,
|
||||
right: 6,
|
||||
top: 2,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
textColor: theme.textColor.secondary.value,
|
||||
background: backgroundColor(theme, 300),
|
||||
activeLineBackground: theme.editor.line.active.value,
|
||||
codeActionsIndicator: iconColor(theme, "secondary"),
|
||||
diffBackgroundDeleted: backgroundColor(theme, "error"),
|
||||
diffBackgroundInserted: backgroundColor(theme, "ok"),
|
||||
documentHighlightReadBackground: theme.editor.highlight.occurrence.value,
|
||||
documentHighlightWriteBackground: theme.editor.highlight.occurrence.value,
|
||||
errorColor: theme.textColor.error,
|
||||
gutterBackground: backgroundColor(theme, 300),
|
||||
gutterPaddingFactor: 2.5,
|
||||
highlightedLineBackground: theme.editor.line.highlighted.value,
|
||||
lineNumber: theme.editor.gutter.primary.value,
|
||||
lineNumberActive: theme.editor.gutter.active,
|
||||
renameFade: 0.6,
|
||||
unnecessaryCodeFade: 0.5,
|
||||
selection: player(theme, 1).selection,
|
||||
guestSelections: [
|
||||
player(theme, 2).selection,
|
||||
player(theme, 3).selection,
|
||||
player(theme, 4).selection,
|
||||
player(theme, 5).selection,
|
||||
player(theme, 6).selection,
|
||||
player(theme, 7).selection,
|
||||
player(theme, 8).selection,
|
||||
],
|
||||
autocomplete: {
|
||||
background: backgroundColor(theme, 100),
|
||||
cornerRadius: 6,
|
||||
padding: 6,
|
||||
border: border(theme, "secondary"),
|
||||
item: autocompleteItem,
|
||||
hoveredItem: {
|
||||
...autocompleteItem,
|
||||
background: backgroundColor(theme, 100, "hovered"),
|
||||
},
|
||||
margin: {
|
||||
left: -14,
|
||||
},
|
||||
matchHighlight: {
|
||||
color: theme.syntax.keyword.color.value,
|
||||
weight: theme.syntax.keyword.weight.value,
|
||||
},
|
||||
selectedItem: {
|
||||
...autocompleteItem,
|
||||
background: backgroundColor(theme, 100, "active"),
|
||||
},
|
||||
},
|
||||
diagnosticHeader: {
|
||||
background: theme.editor.background.value,
|
||||
iconWidthFactor: 1.5,
|
||||
textScaleFactor: 0.857, // NateQ: Will we need dynamic sizing for text? If so let's create tokens for these.
|
||||
border: border(theme, "secondary", {
|
||||
bottom: true,
|
||||
top: true,
|
||||
}),
|
||||
code: {
|
||||
...text(theme, "mono", "muted", { size: "sm" }),
|
||||
margin: {
|
||||
left: 10,
|
||||
function diagnostic(theme: Theme, color: TextColor) {
|
||||
return {
|
||||
textScaleFactor: 0.857,
|
||||
header: {
|
||||
border: border(theme, "primary", {
|
||||
top: true,
|
||||
}),
|
||||
},
|
||||
message: {
|
||||
text: text(theme, "sans", color, { size: "sm" }),
|
||||
highlightText: text(theme, "sans", color, {
|
||||
size: "sm",
|
||||
weight: "bold",
|
||||
}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
textColor: theme.textColor.secondary.value,
|
||||
background: backgroundColor(theme, 300),
|
||||
activeLineBackground: theme.editor.line.active.value,
|
||||
codeActionsIndicator: iconColor(theme, "secondary"),
|
||||
diffBackgroundDeleted: backgroundColor(theme, "error"),
|
||||
diffBackgroundInserted: backgroundColor(theme, "ok"),
|
||||
documentHighlightReadBackground: theme.editor.highlight.occurrence.value,
|
||||
documentHighlightWriteBackground: theme.editor.highlight.occurrence.value,
|
||||
errorColor: theme.textColor.error.value,
|
||||
gutterBackground: backgroundColor(theme, 300),
|
||||
gutterPaddingFactor: 2.5,
|
||||
highlightedLineBackground: theme.editor.line.highlighted.value,
|
||||
lineNumber: theme.editor.gutter.primary.value,
|
||||
lineNumberActive: theme.editor.gutter.active.value,
|
||||
renameFade: 0.6,
|
||||
unnecessaryCodeFade: 0.5,
|
||||
selection: player(theme, 1).selection,
|
||||
guestSelections: [
|
||||
player(theme, 2).selection,
|
||||
player(theme, 3).selection,
|
||||
player(theme, 4).selection,
|
||||
player(theme, 5).selection,
|
||||
player(theme, 6).selection,
|
||||
player(theme, 7).selection,
|
||||
player(theme, 8).selection,
|
||||
],
|
||||
autocomplete: {
|
||||
background: backgroundColor(theme, 100),
|
||||
cornerRadius: 6,
|
||||
padding: 6,
|
||||
border: border(theme, "secondary"),
|
||||
item: autocompleteItem,
|
||||
hoveredItem: {
|
||||
...autocompleteItem,
|
||||
background: backgroundColor(theme, 100, "hovered"),
|
||||
},
|
||||
margin: {
|
||||
left: -14,
|
||||
},
|
||||
matchHighlight: {
|
||||
color: theme.syntax.keyword.color.value,
|
||||
weight: theme.syntax.keyword.weight.value,
|
||||
},
|
||||
selectedItem: {
|
||||
...autocompleteItem,
|
||||
background: backgroundColor(theme, 100, "active"),
|
||||
},
|
||||
},
|
||||
},
|
||||
message: {
|
||||
highlightText: text(theme, "sans", "primary", {
|
||||
size: "sm",
|
||||
weight: "bold",
|
||||
}),
|
||||
text: text(theme, "sans", "secondary", { size: "sm" }),
|
||||
},
|
||||
},
|
||||
diagnosticPathHeader: {
|
||||
background: theme.editor.line.active,
|
||||
textScaleFactor: 0.857,
|
||||
filename: text(theme, "mono", "primary", { size: "sm" }),
|
||||
path: {
|
||||
...text(theme, "mono", "muted", { size: "sm" }),
|
||||
margin: {
|
||||
left: 12,
|
||||
diagnosticHeader: {
|
||||
background: theme.editor.background.value,
|
||||
iconWidthFactor: 1.5,
|
||||
textScaleFactor: 0.857, // NateQ: Will we need dynamic sizing for text? If so let's create tokens for these.
|
||||
border: border(theme, "secondary", {
|
||||
bottom: true,
|
||||
top: true,
|
||||
}),
|
||||
code: {
|
||||
...text(theme, "mono", "muted", { size: "sm" }),
|
||||
margin: {
|
||||
left: 10,
|
||||
},
|
||||
},
|
||||
message: {
|
||||
highlightText: text(theme, "sans", "primary", {
|
||||
size: "sm",
|
||||
weight: "bold",
|
||||
}),
|
||||
text: text(theme, "sans", "secondary", { size: "sm" }),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
errorDiagnostic: diagnostic(theme, "error"),
|
||||
warningDiagnostic: diagnostic(theme, "warning"),
|
||||
informationDiagnostic: diagnostic(theme, "info"),
|
||||
hintDiagnostic: diagnostic(theme, "info"),
|
||||
invalidErrorDiagnostic: diagnostic(theme, "muted"),
|
||||
invalidHintDiagnostic: diagnostic(theme, "muted"),
|
||||
invalidInformationDiagnostic: diagnostic(theme, "muted"),
|
||||
invalidWarningDiagnostic: diagnostic(theme, "muted"),
|
||||
};
|
||||
diagnosticPathHeader: {
|
||||
background: theme.editor.line.active.value,
|
||||
textScaleFactor: 0.857,
|
||||
filename: text(theme, "mono", "primary", { size: "sm" }),
|
||||
path: {
|
||||
...text(theme, "mono", "muted", { size: "sm" }),
|
||||
margin: {
|
||||
left: 12,
|
||||
},
|
||||
},
|
||||
},
|
||||
errorDiagnostic: diagnostic(theme, "error"),
|
||||
warningDiagnostic: diagnostic(theme, "warning"),
|
||||
informationDiagnostic: diagnostic(theme, "info"),
|
||||
hintDiagnostic: diagnostic(theme, "info"),
|
||||
invalidErrorDiagnostic: diagnostic(theme, "muted"),
|
||||
invalidHintDiagnostic: diagnostic(theme, "muted"),
|
||||
invalidInformationDiagnostic: diagnostic(theme, "muted"),
|
||||
invalidWarningDiagnostic: diagnostic(theme, "muted"),
|
||||
syntax: {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -24,7 +24,11 @@ export default function projectPanel(theme: Theme) {
|
|||
backgroundColor(theme, 300, "hovered")
|
||||
),
|
||||
selectedEntry: entry(theme, "primary"),
|
||||
hoveredSelectedEntry: entry(theme, "primary", "hovered"),
|
||||
hoveredSelectedEntry: entry(
|
||||
theme,
|
||||
"primary",
|
||||
backgroundColor(theme, 300, "hovered")
|
||||
),
|
||||
padding: {
|
||||
top: 6,
|
||||
},
|
||||
|
|
|
@ -19,8 +19,28 @@ export default function search(theme: Theme) {
|
|||
},
|
||||
};
|
||||
|
||||
const editor = {
|
||||
background: backgroundColor(theme, 500),
|
||||
cornerRadius: 6,
|
||||
minWidth: 200,
|
||||
maxWidth: 500,
|
||||
placeholderText: text(theme, "mono", "placeholder"),
|
||||
selection: player(theme, 1).selection,
|
||||
text: text(theme, "mono", "primary"),
|
||||
border: border(theme, "primary"),
|
||||
margin: {
|
||||
right: 5,
|
||||
},
|
||||
padding: {
|
||||
top: 3,
|
||||
bottom: 3,
|
||||
left: 14,
|
||||
right: 14,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
matchBackground: theme.editor.highlight.match,
|
||||
matchBackground: theme.editor.highlight.match.value,
|
||||
tabIconSpacing: 4,
|
||||
tabIconWidth: 14,
|
||||
activeHoveredOptionButton: {
|
||||
|
@ -31,31 +51,13 @@ export default function search(theme: Theme) {
|
|||
...optionButton,
|
||||
background: backgroundColor(theme, 100),
|
||||
},
|
||||
editor: {
|
||||
background: backgroundColor(theme, 500),
|
||||
cornerRadius: 6,
|
||||
minWidth: 200,
|
||||
maxWidth: 500,
|
||||
placeholderText: text(theme, "mono", "placeholder"),
|
||||
selection: player(theme, 1).selection,
|
||||
text: text(theme, "mono", "primary"),
|
||||
border: border(theme, "primary"),
|
||||
margin: {
|
||||
right: 5,
|
||||
},
|
||||
padding: {
|
||||
top: 3,
|
||||
bottom: 3,
|
||||
left: 14,
|
||||
right: 14,
|
||||
},
|
||||
},
|
||||
editor,
|
||||
hoveredOptionButton: {
|
||||
...optionButton,
|
||||
background: backgroundColor(theme, 100),
|
||||
},
|
||||
invalidEditor: {
|
||||
extends: "$search.editor",
|
||||
...editor,
|
||||
border: border(theme, "error"),
|
||||
},
|
||||
matchIndex: {
|
||||
|
|
|
@ -137,5 +137,10 @@ export default function workspace(theme: Theme) {
|
|||
...text(theme, "mono", "secondary"),
|
||||
padding: { left: 6 },
|
||||
},
|
||||
disconnectedOverlay: {
|
||||
...text(theme, "sans", "primary"),
|
||||
color: "#ffffff",
|
||||
background: "#000000aa",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,249 +1,273 @@
|
|||
import core from "../tokens/core";
|
||||
import Theme, { NumberToken, Syntax } from "./theme";
|
||||
|
||||
const { color } = core;
|
||||
import { colors, fontWeights, NumberToken } from "../tokens";
|
||||
import Theme, { Syntax } from "./theme";
|
||||
|
||||
const backgroundColor = {
|
||||
100: {
|
||||
base: color.neutral[750],
|
||||
hovered: color.neutral[750],
|
||||
active: color.neutral[750],
|
||||
focused: color.neutral[750],
|
||||
},
|
||||
300: {
|
||||
base: color.neutral[800],
|
||||
hovered: color.neutral[800],
|
||||
active: color.neutral[800],
|
||||
focused: color.neutral[800],
|
||||
},
|
||||
500: {
|
||||
base: color.neutral[900],
|
||||
hovered: color.neutral[900],
|
||||
active: color.neutral[900],
|
||||
focused: color.neutral[900],
|
||||
},
|
||||
ok: {
|
||||
base: color.green[600],
|
||||
hovered: color.green[600],
|
||||
active: color.green[600],
|
||||
focused: color.green[600],
|
||||
},
|
||||
error: {
|
||||
base: color.red[400],
|
||||
hovered: color.red[400],
|
||||
active: color.red[400],
|
||||
focused: color.red[400],
|
||||
},
|
||||
warning: {
|
||||
base: color.amber[300],
|
||||
hovered: color.amber[300],
|
||||
active: color.amber[300],
|
||||
focused: color.amber[300],
|
||||
},
|
||||
info: {
|
||||
base: color.blue[500],
|
||||
hovered: color.blue[500],
|
||||
active: color.blue[500],
|
||||
focused: color.blue[500],
|
||||
},
|
||||
100: {
|
||||
base: colors.neutral[750],
|
||||
hovered: colors.neutral[750],
|
||||
active: colors.neutral[750],
|
||||
focused: colors.neutral[750],
|
||||
},
|
||||
300: {
|
||||
base: colors.neutral[800],
|
||||
hovered: colors.neutral[800],
|
||||
active: colors.neutral[800],
|
||||
focused: colors.neutral[800],
|
||||
},
|
||||
500: {
|
||||
base: colors.neutral[900],
|
||||
hovered: colors.neutral[900],
|
||||
active: colors.neutral[900],
|
||||
focused: colors.neutral[900],
|
||||
},
|
||||
ok: {
|
||||
base: colors.green[600],
|
||||
hovered: colors.green[600],
|
||||
active: colors.green[600],
|
||||
focused: colors.green[600],
|
||||
},
|
||||
error: {
|
||||
base: colors.red[400],
|
||||
hovered: colors.red[400],
|
||||
active: colors.red[400],
|
||||
focused: colors.red[400],
|
||||
},
|
||||
warning: {
|
||||
base: colors.amber[300],
|
||||
hovered: colors.amber[300],
|
||||
active: colors.amber[300],
|
||||
focused: colors.amber[300],
|
||||
},
|
||||
info: {
|
||||
base: colors.blue[500],
|
||||
hovered: colors.blue[500],
|
||||
active: colors.blue[500],
|
||||
focused: colors.blue[500],
|
||||
},
|
||||
};
|
||||
|
||||
const borderColor = {
|
||||
primary: color.neutral[850],
|
||||
secondary: color.neutral[700],
|
||||
muted: color.neutral[750],
|
||||
focused: color.neutral[100],
|
||||
active: color.neutral[500],
|
||||
ok: color.neutral[1000],
|
||||
error: color.neutral[1000],
|
||||
warning: color.neutral[1000],
|
||||
info: color.neutral[1000],
|
||||
primary: colors.neutral[850],
|
||||
secondary: colors.neutral[700],
|
||||
muted: colors.neutral[750],
|
||||
focused: colors.neutral[100],
|
||||
active: colors.neutral[500],
|
||||
ok: colors.neutral[1000],
|
||||
error: colors.neutral[1000],
|
||||
warning: colors.neutral[1000],
|
||||
info: colors.neutral[1000],
|
||||
};
|
||||
|
||||
const textColor = {
|
||||
primary: color.neutral[150],
|
||||
secondary: color.neutral[350],
|
||||
muted: color.neutral[550],
|
||||
placeholder: color.neutral[750],
|
||||
active: color.neutral[0],
|
||||
//TODO: (design) define feature and it's correct value
|
||||
feature: color.sky[500],
|
||||
ok: color.green[600],
|
||||
error: color.red[400],
|
||||
warning: color.amber[300],
|
||||
info: color.blue[500],
|
||||
primary: colors.neutral[150],
|
||||
secondary: colors.neutral[350],
|
||||
muted: colors.neutral[550],
|
||||
placeholder: colors.neutral[750],
|
||||
active: colors.neutral[0],
|
||||
//TODO: (design) define feature and it's correct value
|
||||
feature: colors.sky[500],
|
||||
ok: colors.green[600],
|
||||
error: colors.red[400],
|
||||
warning: colors.amber[300],
|
||||
info: colors.blue[500],
|
||||
};
|
||||
|
||||
const iconColor = {
|
||||
primary: color.neutral[300],
|
||||
secondary: color.neutral[500],
|
||||
muted: color.neutral[600],
|
||||
placeholder: color.neutral[700],
|
||||
active: color.neutral[50],
|
||||
//TODO: (design) define feature and it's correct value
|
||||
feature: color.sky[500],
|
||||
ok: color.green[600],
|
||||
error: color.red[400],
|
||||
warning: color.amber[300],
|
||||
info: color.blue[500],
|
||||
primary: colors.neutral[300],
|
||||
secondary: colors.neutral[500],
|
||||
muted: colors.neutral[600],
|
||||
placeholder: colors.neutral[700],
|
||||
active: colors.neutral[50],
|
||||
//TODO: (design) define feature and it's correct value
|
||||
feature: colors.sky[500],
|
||||
ok: colors.green[600],
|
||||
error: colors.red[400],
|
||||
warning: colors.amber[300],
|
||||
info: colors.blue[500],
|
||||
};
|
||||
|
||||
const player = {
|
||||
1: {
|
||||
baseColor: color.blue[600],
|
||||
cursorColor: color.blue[600],
|
||||
selectionColor: color.blue[600],
|
||||
borderColor: color.blue[600],
|
||||
},
|
||||
2: {
|
||||
baseColor: color.indigo[500],
|
||||
cursorColor: color.indigo[500],
|
||||
selectionColor: color.indigo[500],
|
||||
borderColor: color.indigo[500],
|
||||
},
|
||||
3: {
|
||||
baseColor: color.green[500],
|
||||
cursorColor: color.green[500],
|
||||
selectionColor: color.green[500],
|
||||
borderColor: color.green[500],
|
||||
},
|
||||
4: {
|
||||
baseColor: color.orange[500],
|
||||
cursorColor: color.orange[500],
|
||||
selectionColor: color.orange[500],
|
||||
borderColor: color.orange[500],
|
||||
},
|
||||
5: {
|
||||
baseColor: color.purple[500],
|
||||
cursorColor: color.purple[500],
|
||||
selectionColor: color.purple[500],
|
||||
borderColor: color.purple[500],
|
||||
},
|
||||
6: {
|
||||
baseColor: color.teal[400],
|
||||
cursorColor: color.teal[400],
|
||||
selectionColor: color.teal[400],
|
||||
borderColor: color.teal[400],
|
||||
},
|
||||
7: {
|
||||
baseColor: color.pink[400],
|
||||
cursorColor: color.pink[400],
|
||||
selectionColor: color.pink[400],
|
||||
borderColor: color.pink[400],
|
||||
},
|
||||
8: {
|
||||
baseColor: color.yellow[400],
|
||||
cursorColor: color.yellow[400],
|
||||
selectionColor: color.yellow[400],
|
||||
borderColor: color.yellow[400],
|
||||
},
|
||||
1: {
|
||||
baseColor: colors.blue[600],
|
||||
cursorColor: colors.blue[600],
|
||||
selectionColor: colors.blue[600],
|
||||
borderColor: colors.blue[600],
|
||||
},
|
||||
2: {
|
||||
baseColor: colors.indigo[500],
|
||||
cursorColor: colors.indigo[500],
|
||||
selectionColor: colors.indigo[500],
|
||||
borderColor: colors.indigo[500],
|
||||
},
|
||||
3: {
|
||||
baseColor: colors.green[500],
|
||||
cursorColor: colors.green[500],
|
||||
selectionColor: colors.green[500],
|
||||
borderColor: colors.green[500],
|
||||
},
|
||||
4: {
|
||||
baseColor: colors.orange[500],
|
||||
cursorColor: colors.orange[500],
|
||||
selectionColor: colors.orange[500],
|
||||
borderColor: colors.orange[500],
|
||||
},
|
||||
5: {
|
||||
baseColor: colors.purple[500],
|
||||
cursorColor: colors.purple[500],
|
||||
selectionColor: colors.purple[500],
|
||||
borderColor: colors.purple[500],
|
||||
},
|
||||
6: {
|
||||
baseColor: colors.teal[400],
|
||||
cursorColor: colors.teal[400],
|
||||
selectionColor: colors.teal[400],
|
||||
borderColor: colors.teal[400],
|
||||
},
|
||||
7: {
|
||||
baseColor: colors.pink[400],
|
||||
cursorColor: colors.pink[400],
|
||||
selectionColor: colors.pink[400],
|
||||
borderColor: colors.pink[400],
|
||||
},
|
||||
8: {
|
||||
baseColor: colors.yellow[400],
|
||||
cursorColor: colors.yellow[400],
|
||||
selectionColor: colors.yellow[400],
|
||||
borderColor: colors.yellow[400],
|
||||
},
|
||||
};
|
||||
|
||||
// TODO: Fixup
|
||||
const editor = {
|
||||
background: backgroundColor[500].base,
|
||||
indent_guide: borderColor.muted,
|
||||
indent_guide_active: borderColor.secondary,
|
||||
line: {
|
||||
active: color.neutral[0],
|
||||
highlighted: color.neutral[0],
|
||||
inserted: backgroundColor.ok.active,
|
||||
deleted: backgroundColor.error.active,
|
||||
modified: backgroundColor.info.active,
|
||||
},
|
||||
highlight: {
|
||||
selection: player[1].selectionColor,
|
||||
occurrence: backgroundColor[500].active,
|
||||
activeOccurrence: color.neutral[0],
|
||||
matchingBracket: color.neutral[0],
|
||||
match: color.neutral[0],
|
||||
activeMatch: color.neutral[0],
|
||||
related: color.neutral[0],
|
||||
},
|
||||
gutter: {
|
||||
primary: color.neutral[0],
|
||||
active: color.neutral[0],
|
||||
},
|
||||
background: backgroundColor[500].base,
|
||||
indent_guide: borderColor.muted,
|
||||
indent_guide_active: borderColor.secondary,
|
||||
line: {
|
||||
active: colors.neutral[0],
|
||||
highlighted: colors.neutral[0],
|
||||
inserted: backgroundColor.ok.active,
|
||||
deleted: backgroundColor.error.active,
|
||||
modified: backgroundColor.info.active,
|
||||
},
|
||||
highlight: {
|
||||
selection: player[1].selectionColor,
|
||||
occurrence: backgroundColor[500].active,
|
||||
activeOccurrence: colors.neutral[0],
|
||||
matchingBracket: colors.neutral[0],
|
||||
match: colors.neutral[0],
|
||||
activeMatch: colors.neutral[0],
|
||||
related: colors.neutral[0],
|
||||
},
|
||||
gutter: {
|
||||
primary: colors.neutral[0],
|
||||
active: colors.neutral[0],
|
||||
},
|
||||
};
|
||||
|
||||
const syntax: Syntax = {
|
||||
primary: {
|
||||
color: textColor.primary,
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
comment: {
|
||||
color: color.lime[200],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
punctuation: {
|
||||
color: textColor.primary,
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
constant: {
|
||||
color: color.neutral[150],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
keyword: {
|
||||
color: color.sky[400],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
function: {
|
||||
color: color.yellow[200],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
type: {
|
||||
color: color.teal[300],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
variant: {
|
||||
color: color.teal[300],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
property: {
|
||||
color: color.sky[300],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
enum: {
|
||||
color: color.sky[400],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
operator: {
|
||||
color: color.sky[400],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
string: {
|
||||
color: color.orange[300],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
number: {
|
||||
color: color.neutral[150],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
boolean: {
|
||||
color: color.neutral[150],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
predictive: {
|
||||
color: textColor.muted,
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
},
|
||||
primary: {
|
||||
color: textColor.primary,
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
comment: {
|
||||
color: colors.lime[200],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
punctuation: {
|
||||
color: textColor.primary,
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
constant: {
|
||||
color: colors.neutral[150],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
keyword: {
|
||||
color: colors.sky[400],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
function: {
|
||||
color: colors.yellow[200],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
type: {
|
||||
color: colors.teal[300],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
variant: {
|
||||
color: colors.teal[300],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
property: {
|
||||
color: colors.sky[300],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
enum: {
|
||||
color: colors.sky[400],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
operator: {
|
||||
color: colors.sky[400],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
string: {
|
||||
color: colors.orange[300],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
number: {
|
||||
color: colors.neutral[150],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
boolean: {
|
||||
color: colors.neutral[150],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
predictive: {
|
||||
color: textColor.muted,
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
title: {
|
||||
color: colors.sky[500],
|
||||
weight: fontWeights.bold,
|
||||
},
|
||||
emphasis: {
|
||||
color: textColor.active,
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
emphasisStrong: {
|
||||
color: textColor.active,
|
||||
weight: fontWeights.bold,
|
||||
},
|
||||
linkUrl: {
|
||||
color: colors.lime[500],
|
||||
weight: fontWeights.normal,
|
||||
// TODO: add underline
|
||||
},
|
||||
linkText: {
|
||||
color: colors.orange[500],
|
||||
weight: fontWeights.normal,
|
||||
// TODO: add italic
|
||||
},
|
||||
listMarker: {
|
||||
color: colors.sky[400],
|
||||
weight: fontWeights.normal,
|
||||
}
|
||||
};
|
||||
|
||||
const shadowAlpha: NumberToken = {
|
||||
value: 0.32,
|
||||
type: "number",
|
||||
value: 0.32,
|
||||
type: "number",
|
||||
};
|
||||
|
||||
const theme: Theme = {
|
||||
name: "dark",
|
||||
backgroundColor,
|
||||
borderColor,
|
||||
textColor,
|
||||
iconColor,
|
||||
editor,
|
||||
syntax,
|
||||
player,
|
||||
shadowAlpha,
|
||||
name: "dark",
|
||||
backgroundColor,
|
||||
borderColor,
|
||||
textColor,
|
||||
iconColor,
|
||||
editor,
|
||||
syntax,
|
||||
player,
|
||||
shadowAlpha,
|
||||
};
|
||||
|
||||
export default theme;
|
||||
|
|
|
@ -1,143 +1,141 @@
|
|||
import core from "../tokens/core";
|
||||
import Theme, { NumberToken, Syntax } from "./theme";
|
||||
|
||||
const { color } = core;
|
||||
import { colors, fontWeights, NumberToken } from "../tokens";
|
||||
import Theme, { Syntax } from "./theme";
|
||||
|
||||
// TODO: Replace with light values
|
||||
|
||||
const backgroundColor = {
|
||||
100: {
|
||||
base: color.neutral[750],
|
||||
hovered: color.neutral[750],
|
||||
active: color.neutral[750],
|
||||
focused: color.neutral[750],
|
||||
base: colors.neutral[750],
|
||||
hovered: colors.neutral[750],
|
||||
active: colors.neutral[750],
|
||||
focused: colors.neutral[750],
|
||||
},
|
||||
300: {
|
||||
base: color.neutral[800],
|
||||
hovered: color.neutral[800],
|
||||
active: color.neutral[800],
|
||||
focused: color.neutral[800],
|
||||
base: colors.neutral[800],
|
||||
hovered: colors.neutral[800],
|
||||
active: colors.neutral[800],
|
||||
focused: colors.neutral[800],
|
||||
},
|
||||
500: {
|
||||
base: color.neutral[900],
|
||||
hovered: color.neutral[900],
|
||||
active: color.neutral[900],
|
||||
focused: color.neutral[900],
|
||||
base: colors.neutral[900],
|
||||
hovered: colors.neutral[900],
|
||||
active: colors.neutral[900],
|
||||
focused: colors.neutral[900],
|
||||
},
|
||||
ok: {
|
||||
base: color.green[600],
|
||||
hovered: color.green[600],
|
||||
active: color.green[600],
|
||||
focused: color.green[600],
|
||||
base: colors.green[600],
|
||||
hovered: colors.green[600],
|
||||
active: colors.green[600],
|
||||
focused: colors.green[600],
|
||||
},
|
||||
error: {
|
||||
base: color.red[400],
|
||||
hovered: color.red[400],
|
||||
active: color.red[400],
|
||||
focused: color.red[400],
|
||||
base: colors.red[400],
|
||||
hovered: colors.red[400],
|
||||
active: colors.red[400],
|
||||
focused: colors.red[400],
|
||||
},
|
||||
warning: {
|
||||
base: color.amber[300],
|
||||
hovered: color.amber[300],
|
||||
active: color.amber[300],
|
||||
focused: color.amber[300],
|
||||
base: colors.amber[300],
|
||||
hovered: colors.amber[300],
|
||||
active: colors.amber[300],
|
||||
focused: colors.amber[300],
|
||||
},
|
||||
info: {
|
||||
base: color.blue[500],
|
||||
hovered: color.blue[500],
|
||||
active: color.blue[500],
|
||||
focused: color.blue[500],
|
||||
base: colors.blue[500],
|
||||
hovered: colors.blue[500],
|
||||
active: colors.blue[500],
|
||||
focused: colors.blue[500],
|
||||
},
|
||||
};
|
||||
|
||||
const borderColor = {
|
||||
primary: color.neutral[850],
|
||||
secondary: color.neutral[700],
|
||||
muted: color.neutral[750],
|
||||
focused: color.neutral[100],
|
||||
active: color.neutral[500],
|
||||
ok: color.neutral[1000],
|
||||
error: color.neutral[1000],
|
||||
warning: color.neutral[1000],
|
||||
info: color.neutral[1000],
|
||||
primary: colors.neutral[850],
|
||||
secondary: colors.neutral[700],
|
||||
muted: colors.neutral[750],
|
||||
focused: colors.neutral[100],
|
||||
active: colors.neutral[500],
|
||||
ok: colors.neutral[1000],
|
||||
error: colors.neutral[1000],
|
||||
warning: colors.neutral[1000],
|
||||
info: colors.neutral[1000],
|
||||
};
|
||||
|
||||
const textColor = {
|
||||
primary: color.neutral[150],
|
||||
secondary: color.neutral[350],
|
||||
muted: color.neutral[550],
|
||||
placeholder: color.neutral[750],
|
||||
active: color.neutral[0],
|
||||
primary: colors.neutral[150],
|
||||
secondary: colors.neutral[350],
|
||||
muted: colors.neutral[550],
|
||||
placeholder: colors.neutral[750],
|
||||
active: colors.neutral[0],
|
||||
//TODO: (design) define feature and it's correct value
|
||||
feature: color.sky[500],
|
||||
ok: color.green[600],
|
||||
error: color.red[400],
|
||||
warning: color.amber[300],
|
||||
info: color.blue[500],
|
||||
feature: colors.sky[500],
|
||||
ok: colors.green[600],
|
||||
error: colors.red[400],
|
||||
warning: colors.amber[300],
|
||||
info: colors.blue[500],
|
||||
};
|
||||
|
||||
const iconColor = {
|
||||
primary: color.neutral[300],
|
||||
secondary: color.neutral[500],
|
||||
muted: color.neutral[600],
|
||||
placeholder: color.neutral[700],
|
||||
active: color.neutral[50],
|
||||
primary: colors.neutral[300],
|
||||
secondary: colors.neutral[500],
|
||||
muted: colors.neutral[600],
|
||||
placeholder: colors.neutral[700],
|
||||
active: colors.neutral[50],
|
||||
//TODO: (design) define feature and it's correct value
|
||||
feature: color.sky[500],
|
||||
ok: color.green[600],
|
||||
error: color.red[400],
|
||||
warning: color.amber[300],
|
||||
info: color.blue[500],
|
||||
feature: colors.sky[500],
|
||||
ok: colors.green[600],
|
||||
error: colors.red[400],
|
||||
warning: colors.amber[300],
|
||||
info: colors.blue[500],
|
||||
};
|
||||
|
||||
const player = {
|
||||
1: {
|
||||
baseColor: color.blue[600],
|
||||
cursorColor: color.blue[600],
|
||||
selectionColor: color.blue[600],
|
||||
borderColor: color.blue[600],
|
||||
baseColor: colors.blue[600],
|
||||
cursorColor: colors.blue[600],
|
||||
selectionColor: colors.blue[600],
|
||||
borderColor: colors.blue[600],
|
||||
},
|
||||
2: {
|
||||
baseColor: color.indigo[500],
|
||||
cursorColor: color.indigo[500],
|
||||
selectionColor: color.indigo[500],
|
||||
borderColor: color.indigo[500],
|
||||
baseColor: colors.indigo[500],
|
||||
cursorColor: colors.indigo[500],
|
||||
selectionColor: colors.indigo[500],
|
||||
borderColor: colors.indigo[500],
|
||||
},
|
||||
3: {
|
||||
baseColor: color.green[500],
|
||||
cursorColor: color.green[500],
|
||||
selectionColor: color.green[500],
|
||||
borderColor: color.green[500],
|
||||
baseColor: colors.green[500],
|
||||
cursorColor: colors.green[500],
|
||||
selectionColor: colors.green[500],
|
||||
borderColor: colors.green[500],
|
||||
},
|
||||
4: {
|
||||
baseColor: color.orange[500],
|
||||
cursorColor: color.orange[500],
|
||||
selectionColor: color.orange[500],
|
||||
borderColor: color.orange[500],
|
||||
baseColor: colors.orange[500],
|
||||
cursorColor: colors.orange[500],
|
||||
selectionColor: colors.orange[500],
|
||||
borderColor: colors.orange[500],
|
||||
},
|
||||
5: {
|
||||
baseColor: color.purple[500],
|
||||
cursorColor: color.purple[500],
|
||||
selectionColor: color.purple[500],
|
||||
borderColor: color.purple[500],
|
||||
baseColor: colors.purple[500],
|
||||
cursorColor: colors.purple[500],
|
||||
selectionColor: colors.purple[500],
|
||||
borderColor: colors.purple[500],
|
||||
},
|
||||
6: {
|
||||
baseColor: color.teal[400],
|
||||
cursorColor: color.teal[400],
|
||||
selectionColor: color.teal[400],
|
||||
borderColor: color.teal[400],
|
||||
baseColor: colors.teal[400],
|
||||
cursorColor: colors.teal[400],
|
||||
selectionColor: colors.teal[400],
|
||||
borderColor: colors.teal[400],
|
||||
},
|
||||
7: {
|
||||
baseColor: color.pink[400],
|
||||
cursorColor: color.pink[400],
|
||||
selectionColor: color.pink[400],
|
||||
borderColor: color.pink[400],
|
||||
baseColor: colors.pink[400],
|
||||
cursorColor: colors.pink[400],
|
||||
selectionColor: colors.pink[400],
|
||||
borderColor: colors.pink[400],
|
||||
},
|
||||
8: {
|
||||
baseColor: color.yellow[400],
|
||||
cursorColor: color.yellow[400],
|
||||
selectionColor: color.yellow[400],
|
||||
borderColor: color.yellow[400],
|
||||
baseColor: colors.yellow[400],
|
||||
cursorColor: colors.yellow[400],
|
||||
selectionColor: colors.yellow[400],
|
||||
borderColor: colors.yellow[400],
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -147,88 +145,114 @@ const editor = {
|
|||
indent_guide: borderColor.muted,
|
||||
indent_guide_active: borderColor.secondary,
|
||||
line: {
|
||||
active: color.neutral[0],
|
||||
highlighted: color.neutral[0],
|
||||
inserted: backgroundColor.ok.active,
|
||||
deleted: backgroundColor.error.active,
|
||||
modified: backgroundColor.info.active,
|
||||
active: colors.neutral[0],
|
||||
highlighted: colors.neutral[0],
|
||||
inserted: backgroundColor.ok.active,
|
||||
deleted: backgroundColor.error.active,
|
||||
modified: backgroundColor.info.active,
|
||||
},
|
||||
highlight: {
|
||||
selection: player[1].selectionColor,
|
||||
occurrence: backgroundColor[500].active,
|
||||
activeOccurrence: color.neutral[0],
|
||||
matchingBracket: color.neutral[0],
|
||||
match: color.neutral[0],
|
||||
activeMatch: color.neutral[0],
|
||||
related: color.neutral[0],
|
||||
selection: player[1].selectionColor,
|
||||
occurrence: backgroundColor[500].active,
|
||||
activeOccurrence: colors.neutral[0],
|
||||
matchingBracket: colors.neutral[0],
|
||||
match: colors.neutral[0],
|
||||
activeMatch: colors.neutral[0],
|
||||
related: colors.neutral[0],
|
||||
},
|
||||
gutter: {
|
||||
primary: color.neutral[0],
|
||||
active: color.neutral[0],
|
||||
primary: colors.neutral[0],
|
||||
active: colors.neutral[0],
|
||||
},
|
||||
};
|
||||
|
||||
const syntax: Syntax = {
|
||||
primary: {
|
||||
color: textColor.primary,
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: textColor.primary,
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
comment: {
|
||||
color: color.lime[200],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.lime[200],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
punctuation: {
|
||||
color: textColor.primary,
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: textColor.primary,
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
constant: {
|
||||
color: color.neutral[150],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.neutral[150],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
keyword: {
|
||||
color: color.sky[400],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.sky[400],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
function: {
|
||||
color: color.yellow[200],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.yellow[200],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
type: {
|
||||
color: color.teal[300],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.teal[300],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
variant: {
|
||||
color: color.teal[300],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.teal[300],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
property: {
|
||||
color: color.sky[300],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.sky[300],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
enum: {
|
||||
color: color.sky[400],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.sky[400],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
operator: {
|
||||
color: color.sky[400],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.sky[400],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
string: {
|
||||
color: color.orange[300],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.orange[300],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
number: {
|
||||
color: color.neutral[150],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.neutral[150],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
boolean: {
|
||||
color: color.neutral[150],
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: colors.neutral[150],
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
predictive: {
|
||||
color: textColor.muted,
|
||||
weight: { value: "normal", type: "fontWeight" },
|
||||
color: textColor.muted,
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
title: {
|
||||
color: colors.sky[500],
|
||||
weight: fontWeights.bold,
|
||||
},
|
||||
emphasis: {
|
||||
color: textColor.active,
|
||||
weight: fontWeights.normal,
|
||||
},
|
||||
emphasisStrong: {
|
||||
color: textColor.active,
|
||||
weight: fontWeights.bold,
|
||||
},
|
||||
linkUrl: {
|
||||
color: colors.lime[500],
|
||||
weight: fontWeights.normal,
|
||||
// TODO: add underline
|
||||
},
|
||||
linkText: {
|
||||
color: colors.orange[500],
|
||||
weight: fontWeights.normal,
|
||||
// TODO: add italic
|
||||
},
|
||||
listMarker: {
|
||||
color: colors.sky[400],
|
||||
weight: fontWeights.normal,
|
||||
}
|
||||
};
|
||||
|
||||
const shadowAlpha: NumberToken = {
|
||||
|
|
|
@ -1,32 +1,8 @@
|
|||
export interface NumberToken {
|
||||
value: number,
|
||||
type: "number"
|
||||
}
|
||||
|
||||
export type Color = string;
|
||||
export interface ColorToken {
|
||||
value: Color;
|
||||
type: "color";
|
||||
step?: number
|
||||
}
|
||||
export type Weight =
|
||||
| "thin"
|
||||
| "extra_light"
|
||||
| "light"
|
||||
| "normal"
|
||||
| "medium"
|
||||
| "semibold"
|
||||
| "bold"
|
||||
| "extra_bold"
|
||||
| "black";
|
||||
export interface WeightToken {
|
||||
value: Weight,
|
||||
type: "fontWeight"
|
||||
}
|
||||
import { FontWeightToken, ColorToken, NumberToken } from "../tokens";
|
||||
|
||||
export interface SyntaxHighlightStyle {
|
||||
color: ColorToken;
|
||||
weight: WeightToken;
|
||||
weight: FontWeightToken;
|
||||
}
|
||||
|
||||
export interface Player {
|
||||
|
@ -43,7 +19,7 @@ export interface BackgroundColor {
|
|||
focused: ColorToken;
|
||||
}
|
||||
|
||||
export interface Syntax {
|
||||
export interface Syntax {
|
||||
primary: SyntaxHighlightStyle;
|
||||
comment: SyntaxHighlightStyle;
|
||||
punctuation: SyntaxHighlightStyle;
|
||||
|
@ -59,6 +35,13 @@ export interface Syntax {
|
|||
number: SyntaxHighlightStyle;
|
||||
boolean: SyntaxHighlightStyle;
|
||||
predictive: SyntaxHighlightStyle;
|
||||
// TODO: Either move the following or rename
|
||||
title: SyntaxHighlightStyle;
|
||||
emphasis: SyntaxHighlightStyle;
|
||||
emphasisStrong: SyntaxHighlightStyle;
|
||||
linkUrl: SyntaxHighlightStyle;
|
||||
linkText: SyntaxHighlightStyle;
|
||||
listMarker: SyntaxHighlightStyle;
|
||||
};
|
||||
|
||||
export default interface Theme {
|
||||
|
|
102
styles/tokens.ts
Normal file
102
styles/tokens.ts
Normal file
|
@ -0,0 +1,102 @@
|
|||
import { colorRamp } from "./utils/color";
|
||||
|
||||
interface Token<V, T> {
|
||||
value: V,
|
||||
type: T
|
||||
}
|
||||
|
||||
export type FontFamily = string;
|
||||
export type FontFamilyToken = Token<FontFamily, "fontFamily">;
|
||||
function fontFamily(value: FontFamily): FontFamilyToken {
|
||||
return {
|
||||
value,
|
||||
type: "fontFamily"
|
||||
}
|
||||
}
|
||||
export const fontFamilies = {
|
||||
sans: fontFamily("Zed Sans"),
|
||||
mono: fontFamily("Zed Mono"),
|
||||
}
|
||||
|
||||
export type FontSize = number;
|
||||
export type FontSizeToken = Token<FontSize, "fontSize">;
|
||||
function fontSize(value: FontSize) {
|
||||
return {
|
||||
value,
|
||||
type: "fontSize"
|
||||
};
|
||||
}
|
||||
export const fontSizes = {
|
||||
"3xs": fontSize(8),
|
||||
"2xs": fontSize(10),
|
||||
xs: fontSize(12),
|
||||
sm: fontSize(14),
|
||||
md: fontSize(16),
|
||||
lg: fontSize(18),
|
||||
xl: fontSize(20),
|
||||
};
|
||||
|
||||
export type FontWeight =
|
||||
| "thin"
|
||||
| "extra_light"
|
||||
| "light"
|
||||
| "normal"
|
||||
| "medium"
|
||||
| "semibold"
|
||||
| "bold"
|
||||
| "extra_bold"
|
||||
| "black";
|
||||
export type FontWeightToken = Token<FontWeight, "fontWeight">;
|
||||
function fontWeight(value: FontWeight): FontWeightToken {
|
||||
return {
|
||||
value,
|
||||
type: "fontWeight"
|
||||
};
|
||||
}
|
||||
export const fontWeights = {
|
||||
"thin": fontWeight("thin"),
|
||||
"extra_light": fontWeight("extra_light"),
|
||||
"light": fontWeight("light"),
|
||||
"normal": fontWeight("normal"),
|
||||
"medium": fontWeight("medium"),
|
||||
"semibold": fontWeight("semibold"),
|
||||
"bold": fontWeight("bold"),
|
||||
"extra_bold": fontWeight("extra_bold"),
|
||||
"black": fontWeight("black"),
|
||||
}
|
||||
|
||||
export type Color = string;
|
||||
export interface ColorToken {
|
||||
value: Color,
|
||||
type: "color",
|
||||
step?: number,
|
||||
}
|
||||
export const colors = {
|
||||
neutral: colorRamp(["black", "white"], { steps: 21, increment: 50 }),
|
||||
rose: colorRamp("#F43F5EFF"),
|
||||
red: colorRamp("#EF4444FF"),
|
||||
orange: colorRamp("#F97316FF"),
|
||||
amber: colorRamp("#F59E0BFF"),
|
||||
yellow: colorRamp("#EAB308FF"),
|
||||
lime: colorRamp("#84CC16FF"),
|
||||
green: colorRamp("#22C55EFF"),
|
||||
emerald: colorRamp("#10B981FF"),
|
||||
teal: colorRamp("#14B8A6FF"),
|
||||
cyan: colorRamp("#06BBD4FF"),
|
||||
sky: colorRamp("#0EA5E9FF"),
|
||||
blue: colorRamp("#3B82F6FF"),
|
||||
indigo: colorRamp("#6366F1FF"),
|
||||
violet: colorRamp("#8B5CF6FF"),
|
||||
purple: colorRamp("#A855F7FF"),
|
||||
fuschia: colorRamp("#D946E4FF"),
|
||||
pink: colorRamp("#EC4899FF"),
|
||||
}
|
||||
|
||||
export type NumberToken = Token<number, "number">;
|
||||
|
||||
export default {
|
||||
fontFamilies,
|
||||
fontSizes,
|
||||
fontWeights,
|
||||
colors,
|
||||
};
|
|
@ -1,58 +0,0 @@
|
|||
import { colorRamp } from "../utils/color";
|
||||
|
||||
export default {
|
||||
fontFamily: {
|
||||
sans: "Zed Sans",
|
||||
mono: "Zed Mono",
|
||||
},
|
||||
fontSize: {
|
||||
"3xs": {
|
||||
value: "8",
|
||||
type: "fontSizes",
|
||||
},
|
||||
"2xs": {
|
||||
value: "10",
|
||||
type: "fontSizes",
|
||||
},
|
||||
xs: {
|
||||
value: "12",
|
||||
type: "fontSizes",
|
||||
},
|
||||
sm: {
|
||||
value: "14",
|
||||
type: "fontSizes",
|
||||
},
|
||||
md: {
|
||||
value: "16",
|
||||
type: "fontSizes",
|
||||
},
|
||||
lg: {
|
||||
value: "18",
|
||||
type: "fontSizes",
|
||||
},
|
||||
xl: {
|
||||
value: "20",
|
||||
type: "fontSizes",
|
||||
},
|
||||
},
|
||||
color: {
|
||||
neutral: colorRamp(["black", "white"], { steps: 21, increment: 50 }),
|
||||
rose: colorRamp("#F43F5EFF"),
|
||||
red: colorRamp("#EF4444FF"),
|
||||
orange: colorRamp("#F97316FF"),
|
||||
amber: colorRamp("#F59E0BFF"),
|
||||
yellow: colorRamp("#EAB308FF"),
|
||||
lime: colorRamp("#84CC16FF"),
|
||||
green: colorRamp("#22C55EFF"),
|
||||
emerald: colorRamp("#10B981FF"),
|
||||
teal: colorRamp("#14B8A6FF"),
|
||||
cyan: colorRamp("#06BBD4FF"),
|
||||
sky: colorRamp("#0EA5E9FF"),
|
||||
blue: colorRamp("#3B82F6FF"),
|
||||
indigo: colorRamp("#6366F1FF"),
|
||||
violet: colorRamp("#8B5CF6FF"),
|
||||
purple: colorRamp("#A855F7FF"),
|
||||
fuschia: colorRamp("#D946E4FF"),
|
||||
pink: colorRamp("#EC4899FF"),
|
||||
},
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue