Merge pull request #747 from zed-industries/styles-in-typescript
Style the Zed app using Typescript styleTrees and Design Tokens
This commit is contained in:
commit
e21f90fec5
40 changed files with 11785 additions and 1336 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,6 +2,7 @@
|
||||||
/zed.xcworkspace
|
/zed.xcworkspace
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/script/node_modules
|
/script/node_modules
|
||||||
|
/styles/node_modules
|
||||||
/crates/server/.env.toml
|
/crates/server/.env.toml
|
||||||
/crates/server/static/styles.css
|
/crates/server/static/styles.css
|
||||||
/vendor/bin
|
/vendor/bin
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
collaborators = ["nathansobo", "as-cii", "maxbrunsfeld", "iamnbutler", "Kethku"]
|
collaborators = ["nathansobo", "as-cii", "maxbrunsfeld", "iamnbutler", "gibusu", "Kethku"]
|
||||||
|
|
272
crates/editor/src/context_menu.rs
Normal file
272
crates/editor/src/context_menu.rs
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
pub enum ContextMenu {
|
||||||
|
Completions(CompletionsMenu),
|
||||||
|
CodeActions(CodeActionsMenu),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextMenu {
|
||||||
|
pub fn select_prev(&mut self, cx: &mut ViewContext<Editor>) -> bool {
|
||||||
|
if self.visible() {
|
||||||
|
match self {
|
||||||
|
ContextMenu::Completions(menu) => menu.select_prev(cx),
|
||||||
|
ContextMenu::CodeActions(menu) => menu.select_prev(cx),
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_next(&mut self, cx: &mut ViewContext<Editor>) -> bool {
|
||||||
|
if self.visible() {
|
||||||
|
match self {
|
||||||
|
ContextMenu::Completions(menu) => menu.select_next(cx),
|
||||||
|
ContextMenu::CodeActions(menu) => menu.select_next(cx),
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visible(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ContextMenu::Completions(menu) => menu.visible(),
|
||||||
|
ContextMenu::CodeActions(menu) => menu.visible(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(
|
||||||
|
&self,
|
||||||
|
cursor_position: DisplayPoint,
|
||||||
|
style: EditorStyle,
|
||||||
|
cx: &AppContext,
|
||||||
|
) -> (DisplayPoint, ElementBox) {
|
||||||
|
match self {
|
||||||
|
ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
|
||||||
|
ContextMenu::CodeActions(menu) => menu.render(cursor_position, style),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CompletionsMenu {
|
||||||
|
id: CompletionId,
|
||||||
|
initial_position: Anchor,
|
||||||
|
buffer: ModelHandle<Buffer>,
|
||||||
|
completions: Arc<[Completion]>,
|
||||||
|
match_candidates: Vec<StringMatchCandidate>,
|
||||||
|
matches: Arc<[StringMatch]>,
|
||||||
|
selected_item: usize,
|
||||||
|
list: UniformListState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompletionsMenu {
|
||||||
|
fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
|
||||||
|
if self.selected_item > 0 {
|
||||||
|
self.selected_item -= 1;
|
||||||
|
self.list.scroll_to(ScrollTarget::Show(self.selected_item));
|
||||||
|
}
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
|
||||||
|
if self.selected_item + 1 < self.matches.len() {
|
||||||
|
self.selected_item += 1;
|
||||||
|
self.list.scroll_to(ScrollTarget::Show(self.selected_item));
|
||||||
|
}
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visible(&self) -> bool {
|
||||||
|
!self.matches.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&self, style: EditorStyle, _: &AppContext) -> ElementBox {
|
||||||
|
enum CompletionTag {}
|
||||||
|
|
||||||
|
let completions = self.completions.clone();
|
||||||
|
let matches = self.matches.clone();
|
||||||
|
let selected_item = self.selected_item;
|
||||||
|
let container_style = style.autocomplete.container;
|
||||||
|
UniformList::new(self.list.clone(), matches.len(), move |range, items, cx| {
|
||||||
|
let start_ix = range.start;
|
||||||
|
for (ix, mat) in matches[range].iter().enumerate() {
|
||||||
|
let completion = &completions[mat.candidate_id];
|
||||||
|
let item_ix = start_ix + ix;
|
||||||
|
items.push(
|
||||||
|
MouseEventHandler::new::<CompletionTag, _, _>(
|
||||||
|
mat.candidate_id,
|
||||||
|
cx,
|
||||||
|
|state, _| {
|
||||||
|
let item_style = if item_ix == selected_item {
|
||||||
|
style.autocomplete.selected_item
|
||||||
|
} else if state.hovered {
|
||||||
|
style.autocomplete.hovered_item
|
||||||
|
} else {
|
||||||
|
style.autocomplete.item
|
||||||
|
};
|
||||||
|
|
||||||
|
Text::new(completion.label.text.clone(), style.text.clone())
|
||||||
|
.with_soft_wrap(false)
|
||||||
|
.with_highlights(combine_syntax_and_fuzzy_match_highlights(
|
||||||
|
&completion.label.text,
|
||||||
|
style.text.color.into(),
|
||||||
|
styled_runs_for_code_label(&completion.label, &style.syntax),
|
||||||
|
&mat.positions,
|
||||||
|
))
|
||||||
|
.contained()
|
||||||
|
.with_style(item_style)
|
||||||
|
.boxed()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
|
.on_mouse_down(move |cx| {
|
||||||
|
cx.dispatch_action(ConfirmCompletion(Some(item_ix)));
|
||||||
|
})
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.with_width_from_item(
|
||||||
|
self.matches
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.max_by_key(|(_, mat)| {
|
||||||
|
self.completions[mat.candidate_id]
|
||||||
|
.label
|
||||||
|
.text
|
||||||
|
.chars()
|
||||||
|
.count()
|
||||||
|
})
|
||||||
|
.map(|(ix, _)| ix),
|
||||||
|
)
|
||||||
|
.contained()
|
||||||
|
.with_style(container_style)
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn filter(&mut self, query: Option<&str>, executor: Arc<executor::Background>) {
|
||||||
|
let mut matches = if let Some(query) = query {
|
||||||
|
fuzzy::match_strings(
|
||||||
|
&self.match_candidates,
|
||||||
|
query,
|
||||||
|
false,
|
||||||
|
100,
|
||||||
|
&Default::default(),
|
||||||
|
executor,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
self.match_candidates
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(candidate_id, candidate)| StringMatch {
|
||||||
|
candidate_id,
|
||||||
|
score: Default::default(),
|
||||||
|
positions: Default::default(),
|
||||||
|
string: candidate.string.clone(),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
matches.sort_unstable_by_key(|mat| {
|
||||||
|
(
|
||||||
|
Reverse(OrderedFloat(mat.score)),
|
||||||
|
self.completions[mat.candidate_id].sort_key(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
for mat in &mut matches {
|
||||||
|
let filter_start = self.completions[mat.candidate_id].label.filter_range.start;
|
||||||
|
for position in &mut mat.positions {
|
||||||
|
*position += filter_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.matches = matches.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct CodeActionsMenu {
|
||||||
|
actions: Arc<[CodeAction]>,
|
||||||
|
buffer: ModelHandle<Buffer>,
|
||||||
|
selected_item: usize,
|
||||||
|
list: UniformListState,
|
||||||
|
deployed_from_indicator: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeActionsMenu {
|
||||||
|
fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
|
||||||
|
if self.selected_item > 0 {
|
||||||
|
self.selected_item -= 1;
|
||||||
|
cx.notify()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
|
||||||
|
if self.selected_item + 1 < self.actions.len() {
|
||||||
|
self.selected_item += 1;
|
||||||
|
cx.notify()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visible(&self) -> bool {
|
||||||
|
!self.actions.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(
|
||||||
|
&self,
|
||||||
|
mut cursor_position: DisplayPoint,
|
||||||
|
style: EditorStyle,
|
||||||
|
) -> (DisplayPoint, ElementBox) {
|
||||||
|
enum ActionTag {}
|
||||||
|
|
||||||
|
let container_style = style.autocomplete.container;
|
||||||
|
let actions = self.actions.clone();
|
||||||
|
let selected_item = self.selected_item;
|
||||||
|
let element =
|
||||||
|
UniformList::new(self.list.clone(), actions.len(), move |range, items, cx| {
|
||||||
|
let start_ix = range.start;
|
||||||
|
for (ix, action) in actions[range].iter().enumerate() {
|
||||||
|
let item_ix = start_ix + ix;
|
||||||
|
items.push(
|
||||||
|
MouseEventHandler::new::<ActionTag, _, _>(item_ix, cx, |state, _| {
|
||||||
|
let item_style = if item_ix == selected_item {
|
||||||
|
style.autocomplete.selected_item
|
||||||
|
} else if state.hovered {
|
||||||
|
style.autocomplete.hovered_item
|
||||||
|
} else {
|
||||||
|
style.autocomplete.item
|
||||||
|
};
|
||||||
|
|
||||||
|
Text::new(action.lsp_action.title.clone(), style.text.clone())
|
||||||
|
.with_soft_wrap(false)
|
||||||
|
.contained()
|
||||||
|
.with_style(item_style)
|
||||||
|
.boxed()
|
||||||
|
})
|
||||||
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
|
.on_mouse_down(move |cx| {
|
||||||
|
cx.dispatch_action(ConfirmCodeAction(Some(item_ix)));
|
||||||
|
})
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.with_width_from_item(
|
||||||
|
self.actions
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.max_by_key(|(_, action)| action.lsp_action.title.chars().count())
|
||||||
|
.map(|(ix, _)| ix),
|
||||||
|
)
|
||||||
|
.contained()
|
||||||
|
.with_style(container_style)
|
||||||
|
.boxed();
|
||||||
|
|
||||||
|
if self.deployed_from_indicator {
|
||||||
|
*cursor_position.column_mut() = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
(cursor_position, element)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
mod theme_registry;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
|
@ -12,7 +11,7 @@ use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
pub use theme_registry::*;
|
pub use theme_registry::*;
|
||||||
|
|
||||||
pub const DEFAULT_THEME_NAME: &'static str = "black";
|
pub const DEFAULT_THEME_NAME: &'static str = "dark";
|
||||||
|
|
||||||
#[derive(Deserialize, Default)]
|
#[derive(Deserialize, Default)]
|
||||||
pub struct Theme {
|
pub struct Theme {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{resolution::resolve_references, Theme};
|
use crate::Theme;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use gpui::{fonts, AssetSource, FontCache};
|
use gpui::{fonts, AssetSource, FontCache};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::Value;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
pub struct ThemeRegistry {
|
pub struct ThemeRegistry {
|
||||||
|
@ -25,12 +25,8 @@ impl ThemeRegistry {
|
||||||
pub fn list(&self) -> impl Iterator<Item = String> {
|
pub fn list(&self) -> impl Iterator<Item = String> {
|
||||||
self.assets.list("themes/").into_iter().filter_map(|path| {
|
self.assets.list("themes/").into_iter().filter_map(|path| {
|
||||||
let filename = path.strip_prefix("themes/")?;
|
let filename = path.strip_prefix("themes/")?;
|
||||||
let theme_name = filename.strip_suffix(".toml")?;
|
let theme_name = filename.strip_suffix(".json")?;
|
||||||
if theme_name.starts_with('_') {
|
Some(theme_name.to_string())
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(theme_name.to_string())
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,9 +40,14 @@ impl ThemeRegistry {
|
||||||
return Ok(theme.clone());
|
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(), || {
|
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();
|
theme.name = name.into();
|
||||||
|
@ -54,217 +55,4 @@ impl ThemeRegistry {
|
||||||
self.themes.lock().insert(name.to_string(), theme.clone());
|
self.themes.lock().insert(name.to_string(), theme.clone());
|
||||||
Ok(theme)
|
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"
|
|
1285
crates/zed/assets/themes/dark.json
Normal file
1285
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"
|
|
1285
crates/zed/assets/themes/light.json
Normal file
1285
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"
|
|
|
@ -1001,7 +1001,8 @@ mod tests {
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref DEFAULT_THEME: parking_lot::Mutex<Option<Arc<Theme>>> = Default::default();
|
static ref DEFAULT_THEME: parking_lot::Mutex<Option<Arc<Theme>>> = Default::default();
|
||||||
static ref FONTS: Vec<Arc<Vec<u8>>> = vec![
|
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
script/build-themes
Executable file
7
script/build-themes
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd styles
|
||||||
|
npm install
|
||||||
|
npm run build
|
1
styles/.gitignore
vendored
Normal file
1
styles/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules/
|
1155
styles/dist/core.json
vendored
Normal file
1155
styles/dist/core.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
637
styles/dist/dark.json
vendored
Normal file
637
styles/dist/dark.json
vendored
Normal file
|
@ -0,0 +1,637 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"themeName": "dark"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#f1f1f1",
|
||||||
|
"step": 50,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"secondary": {
|
||||||
|
"value": "#9c9c9c",
|
||||||
|
"step": 350,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"muted": {
|
||||||
|
"value": "#808080",
|
||||||
|
"step": 450,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"value": "#474747",
|
||||||
|
"step": 650,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#ffffff",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"feature": {
|
||||||
|
"value": "#1096d3",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"value": "#1b9447",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"value": "#f15656",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"value": "#f7bb57",
|
||||||
|
"step": 300,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#c6c6c6",
|
||||||
|
"step": 200,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"secondary": {
|
||||||
|
"value": "#9c9c9c",
|
||||||
|
"step": 350,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"muted": {
|
||||||
|
"value": "#555555",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"value": "#393939",
|
||||||
|
"step": 700,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#ffffff",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"feature": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"value": "#1b9447",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"value": "#eb2d2d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"value": "#f6a724",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"value": "#135acd",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"100": {
|
||||||
|
"base": {
|
||||||
|
"value": "#2b2b2b",
|
||||||
|
"step": 750,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#323232",
|
||||||
|
"step": 725,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#1c1c1c",
|
||||||
|
"step": 800,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#404040",
|
||||||
|
"step": 675,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"300": {
|
||||||
|
"base": {
|
||||||
|
"value": "#1c1c1c",
|
||||||
|
"step": 800,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#232323",
|
||||||
|
"step": 775,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#2b2b2b",
|
||||||
|
"step": 750,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#232323",
|
||||||
|
"step": 775,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"base": {
|
||||||
|
"value": "#000000",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#ffffff14",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#ffffff1f",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#151515",
|
||||||
|
"step": 825,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"base": {
|
||||||
|
"value": "#1b9447",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#1b9447",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#1b9447",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#1b9447",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"base": {
|
||||||
|
"value": "#f15656",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#f15656",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#f15656",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#f15656",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"base": {
|
||||||
|
"value": "#f7bb57",
|
||||||
|
"step": 300,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#f7bb57",
|
||||||
|
"step": 300,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#f7bb57",
|
||||||
|
"step": 300,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#f7bb57",
|
||||||
|
"step": 300,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"base": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"border": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#070707",
|
||||||
|
"step": 875,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"secondary": {
|
||||||
|
"value": "#232323",
|
||||||
|
"step": 775,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"muted": {
|
||||||
|
"value": "#404040",
|
||||||
|
"step": 675,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#717171",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#000000",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"value": "#20b456",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"value": "#eb2d2d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"value": "#de900c",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"editor": {
|
||||||
|
"background": {
|
||||||
|
"value": "#000000",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"indent_guide": {
|
||||||
|
"value": "#404040",
|
||||||
|
"step": 675,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"indent_guide_active": {
|
||||||
|
"value": "#232323",
|
||||||
|
"step": 775,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"line": {
|
||||||
|
"active": {
|
||||||
|
"value": "#ffffff12",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"highlighted": {
|
||||||
|
"value": "#ffffff1f",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"inserted": {
|
||||||
|
"value": "#1b9447",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"deleted": {
|
||||||
|
"value": "#f15656",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"modified": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"highlight": {
|
||||||
|
"selection": {
|
||||||
|
"value": "#2472f23d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"occurrence": {
|
||||||
|
"value": "#ffffff1f",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"activeOccurrence": {
|
||||||
|
"value": "#ffffff29",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"matchingBracket": {
|
||||||
|
"value": "#ffffff1f",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"match": {
|
||||||
|
"value": "#1096d329",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"activeMatch": {
|
||||||
|
"value": "#0e415852",
|
||||||
|
"step": 800,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"related": {
|
||||||
|
"value": "#151515",
|
||||||
|
"step": 825,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gutter": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#474747",
|
||||||
|
"step": 650,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#ffffff",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"syntax": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#d5d5d5",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
"value": "#aaaaaa",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"keyword": {
|
||||||
|
"value": "#4f8ff7",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"function": {
|
||||||
|
"value": "#f9da82",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"value": "#3eeeda",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"variant": {
|
||||||
|
"value": "#53c1f5",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"value": "#4f8ff7",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"enum": {
|
||||||
|
"value": "#ee670a",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"operator": {
|
||||||
|
"value": "#ee670a",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"string": {
|
||||||
|
"value": "#f99d5f",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"number": {
|
||||||
|
"value": "#aeef4b",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"boolean": {
|
||||||
|
"value": "#aeef4b",
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"player": {
|
||||||
|
"1": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#2472f23d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#2472f2cc",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#79ba16",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#79ba16",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#79ba163d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#79ba16cc",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#d430e0",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#d430e0",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#d430e03d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#d430e0cc",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#ee670a",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#ee670a",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#ee670a3d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#ee670acc",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#993bf3",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#993bf3",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#993bf33d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#993bf3cc",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#16d6c1",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#16d6c1",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#16d6c13d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#16d6c1cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#ef59a3",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#ef59a3",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#ef59a33d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#ef59a3cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#f7bf17",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#f7bf17",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#f7bf173d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#f7bf17cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shadowAlpha": {
|
||||||
|
"value": 0.32,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
637
styles/dist/light.json
vendored
Normal file
637
styles/dist/light.json
vendored
Normal file
|
@ -0,0 +1,637 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"themeName": "light"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#2b2b2b",
|
||||||
|
"step": 750,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"secondary": {
|
||||||
|
"value": "#474747",
|
||||||
|
"step": 650,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"muted": {
|
||||||
|
"value": "#636363",
|
||||||
|
"step": 550,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"value": "#808080",
|
||||||
|
"step": 450,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#000000",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"feature": {
|
||||||
|
"value": "#484bed",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"value": "#20b456",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"value": "#eb2d2d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"value": "#d3a20b",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#393939",
|
||||||
|
"step": 700,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"secondary": {
|
||||||
|
"value": "#717171",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"muted": {
|
||||||
|
"value": "#9c9c9c",
|
||||||
|
"step": 350,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"value": "#aaaaaa",
|
||||||
|
"step": 300,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#000000",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"feature": {
|
||||||
|
"value": "#484bed",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"value": "#1b9447",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"value": "#c91818",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"value": "#f7bf17",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"value": "#135acd",
|
||||||
|
"step": 600,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"100": {
|
||||||
|
"base": {
|
||||||
|
"value": "#eaeaea",
|
||||||
|
"step": 75,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#e3e3e3",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#d5d5d5",
|
||||||
|
"step": 150,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#e3e3e3",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"300": {
|
||||||
|
"base": {
|
||||||
|
"value": "#f8f8f8",
|
||||||
|
"step": 25,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#eaeaea",
|
||||||
|
"step": 75,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#dcdcdc",
|
||||||
|
"step": 125,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#eaeaea",
|
||||||
|
"step": 75,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"base": {
|
||||||
|
"value": "#ffffff",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#00000008",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#0000000f",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#f1f1f1",
|
||||||
|
"step": 50,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"base": {
|
||||||
|
"value": "#b7f9ce",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#b7f9ce",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#b7f9ce",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#b7f9ce",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"base": {
|
||||||
|
"value": "#fcc6c6",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#fcc6c6",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#fcc6c6",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#fcc6c6",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"base": {
|
||||||
|
"value": "#fce9b7",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#fce9b7",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#fce9b7",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#fce9b7",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"base": {
|
||||||
|
"value": "#c5dafc",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"hovered": {
|
||||||
|
"value": "#c5dafc",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#c5dafc",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#c5dafc",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"border": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#d5d5d5",
|
||||||
|
"step": 150,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"secondary": {
|
||||||
|
"value": "#d5d5d5",
|
||||||
|
"step": 150,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"muted": {
|
||||||
|
"value": "#e3e3e3",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"focused": {
|
||||||
|
"value": "#e3e3e3",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#b8b8b8",
|
||||||
|
"step": 250,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"ok": {
|
||||||
|
"value": "#84f2ab",
|
||||||
|
"step": 200,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"value": "#f9a0a0",
|
||||||
|
"step": 200,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"value": "#f9da82",
|
||||||
|
"step": 200,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"value": "#9ec1fa",
|
||||||
|
"step": 200,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"editor": {
|
||||||
|
"background": {
|
||||||
|
"value": "#ffffff",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"indent_guide": {
|
||||||
|
"value": "#e3e3e3",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"indent_guide_active": {
|
||||||
|
"value": "#d5d5d5",
|
||||||
|
"step": 150,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"line": {
|
||||||
|
"active": {
|
||||||
|
"value": "#0000000f",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"highlighted": {
|
||||||
|
"value": "#0000001f",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"inserted": {
|
||||||
|
"value": "#b7f9ce",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"deleted": {
|
||||||
|
"value": "#fcc6c6",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"modified": {
|
||||||
|
"value": "#c5dafc",
|
||||||
|
"step": 100,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"highlight": {
|
||||||
|
"selection": {
|
||||||
|
"value": "#2472f23d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"occurrence": {
|
||||||
|
"value": "#0000000f",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"activeOccurrence": {
|
||||||
|
"value": "#00000029",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"matchingBracket": {
|
||||||
|
"value": "#ffffff",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"match": {
|
||||||
|
"value": "#eb2d2d33",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"activeMatch": {
|
||||||
|
"value": "#7274f35c",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"related": {
|
||||||
|
"value": "#ffffff",
|
||||||
|
"step": 0,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gutter": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#aaaaaa",
|
||||||
|
"step": 300,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"value": "#000000",
|
||||||
|
"step": 900,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"syntax": {
|
||||||
|
"primary": {
|
||||||
|
"value": "#1c1c1c",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
"value": "#717171",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"keyword": {
|
||||||
|
"value": "#1819a1",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"function": {
|
||||||
|
"value": "#f9812e",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"value": "#de900c",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"variant": {
|
||||||
|
"value": "#1096d3",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"value": "#118a62",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"enum": {
|
||||||
|
"value": "#eb2d2d",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"operator": {
|
||||||
|
"value": "#eb2d2d",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"string": {
|
||||||
|
"value": "#eb2d2d",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"number": {
|
||||||
|
"value": "#484bed",
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"boolean": {
|
||||||
|
"value": "#eb2d2d",
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"player": {
|
||||||
|
"1": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#2472f2",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#2472f23d",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#2472f2cc",
|
||||||
|
"step": 500,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#12d796",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#12d796",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#12d7963d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#12d796cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#de57e8",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#de57e8",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#de57e83d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#de57e8cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#f9812e",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#f9812e",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#f9812e3d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#f9812ecc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#b066f8",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#b066f8",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#b066f83d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#b066f8cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#16d6c1",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#16d6c1",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#16d6c13d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#16d6c1cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#ef59a3",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#ef59a3",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#ef59a33d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#ef59a3cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"baseColor": {
|
||||||
|
"value": "#f7bf17",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"cursorColor": {
|
||||||
|
"value": "#f7bf17",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"selectionColor": {
|
||||||
|
"value": "#f7bf173d",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
},
|
||||||
|
"borderColor": {
|
||||||
|
"value": "#f7bf17cc",
|
||||||
|
"step": 400,
|
||||||
|
"type": "color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shadowAlpha": {
|
||||||
|
"value": 0.12,
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
2431
styles/dist/tokens.json
vendored
Normal file
2431
styles/dist/tokens.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
8
styles/nodemon.json
Normal file
8
styles/nodemon.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"watch": [
|
||||||
|
"./**/*"
|
||||||
|
],
|
||||||
|
"ext": "ts",
|
||||||
|
"ignore": [],
|
||||||
|
"exec": "ts-node src/buildThemes.ts"
|
||||||
|
}
|
2321
styles/package-lock.json
generated
Normal file
2321
styles/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
22
styles/package.json
Normal file
22
styles/package.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"name": "styles",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "npm run build-themes && npm run build-tokens",
|
||||||
|
"build-themes": "ts-node ./src/buildThemes.ts",
|
||||||
|
"build-tokens": "ts-node ./src/buildTokens.ts",
|
||||||
|
"watch": "nodemon"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/chroma-js": "^2.1.3",
|
||||||
|
"@types/node": "^17.0.23",
|
||||||
|
"case-anything": "^2.1.10",
|
||||||
|
"chroma-js": "^2.4.2",
|
||||||
|
"ts-node": "^10.7.0",
|
||||||
|
"nodemon": "^2.0.15"
|
||||||
|
}
|
||||||
|
}
|
17
styles/src/buildThemes.ts
Normal file
17
styles/src/buildThemes.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
import app from "./styleTree/app";
|
||||||
|
import dark from "./themes/dark";
|
||||||
|
import light from "./themes/light";
|
||||||
|
import snakeCase from "./utils/snakeCase";
|
||||||
|
|
||||||
|
const themes = [dark, light];
|
||||||
|
for (let theme of themes) {
|
||||||
|
let styleTree = snakeCase(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(`- ${outPath} created`);
|
||||||
|
}
|
110
styles/src/buildTokens.ts
Normal file
110
styles/src/buildTokens.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
import dark from "./themes/dark";
|
||||||
|
import light from "./themes/light";
|
||||||
|
import Theme from "./themes/theme";
|
||||||
|
import { colors, fontFamilies, fontSizes, fontWeights } from "./tokens";
|
||||||
|
|
||||||
|
// Organize theme tokens
|
||||||
|
function themeTokens(theme: Theme) {
|
||||||
|
return {
|
||||||
|
meta: {
|
||||||
|
themeName: theme.name,
|
||||||
|
},
|
||||||
|
text: theme.textColor,
|
||||||
|
icon: theme.iconColor,
|
||||||
|
background: theme.backgroundColor,
|
||||||
|
border: theme.borderColor,
|
||||||
|
editor: theme.editor,
|
||||||
|
syntax: {
|
||||||
|
primary: {
|
||||||
|
value: theme.syntax.primary.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
value: theme.syntax.comment.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
keyword: {
|
||||||
|
value: theme.syntax.keyword.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
function: {
|
||||||
|
value: theme.syntax.function.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
value: theme.syntax.type.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
value: theme.syntax.variant.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
property: {
|
||||||
|
value: theme.syntax.property.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
enum: {
|
||||||
|
value: theme.syntax.enum.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
operator: {
|
||||||
|
value: theme.syntax.operator.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
string: {
|
||||||
|
value: theme.syntax.string.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
value: theme.syntax.number.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
boolean: {
|
||||||
|
value: theme.syntax.boolean.color.value,
|
||||||
|
type: "color",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
player: theme.player,
|
||||||
|
shadowAlpha: theme.shadowAlpha,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Organize core tokens
|
||||||
|
const coreTokens = {
|
||||||
|
color: {
|
||||||
|
...colors,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
family: fontFamilies,
|
||||||
|
weight: fontWeights,
|
||||||
|
},
|
||||||
|
size: fontSizes,
|
||||||
|
};
|
||||||
|
|
||||||
|
const combinedTokens: any = {};
|
||||||
|
|
||||||
|
const distPath = path.resolve(`${__dirname}/../dist`);
|
||||||
|
|
||||||
|
// Add core tokens to the combined tokens and write `core.json`.
|
||||||
|
// We write `core.json` as a separate file for the design team's convenience, but it isn't consumed by Figma Tokens directly.
|
||||||
|
const corePath = path.join(distPath, "core.json");
|
||||||
|
fs.writeFileSync(corePath, JSON.stringify(coreTokens, null, 2));
|
||||||
|
console.log(`- ${corePath} created`);
|
||||||
|
combinedTokens.core = coreTokens;
|
||||||
|
|
||||||
|
// Add each theme to the combined tokens and write ${theme}.json.
|
||||||
|
// We write `${theme}.json` as a separate file for the design team's convenience, but it isn't consumed by Figma Tokens directly.
|
||||||
|
let themes = [dark, light];
|
||||||
|
themes.forEach((theme) => {
|
||||||
|
const themePath = `${distPath}/${theme.name}.json`
|
||||||
|
fs.writeFileSync(themePath, JSON.stringify(themeTokens(theme), null, 2));
|
||||||
|
console.log(`- ${themePath} created`);
|
||||||
|
combinedTokens[theme.name] = themeTokens(theme);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Write combined tokens to `tokens.json`. This file is consumed by the Figma Tokens plugin to keep our designs consistent with the app.
|
||||||
|
const combinedPath = path.resolve(`${distPath}/tokens.json`);
|
||||||
|
fs.writeFileSync(combinedPath, JSON.stringify(combinedTokens, null, 2));
|
||||||
|
console.log(`- ${combinedPath} created`);
|
43
styles/src/styleTree/app.ts
Normal file
43
styles/src/styleTree/app.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import Theme from "../themes/theme";
|
||||||
|
import chatPanel from "./chatPanel";
|
||||||
|
import { text } from "./components";
|
||||||
|
import contactsPanel from "./contactsPanel";
|
||||||
|
import editor from "./editor";
|
||||||
|
import projectPanel from "./projectPanel";
|
||||||
|
import search from "./search";
|
||||||
|
import selectorModal from "./selectorModal";
|
||||||
|
import workspace from "./workspace";
|
||||||
|
|
||||||
|
export const panel = {
|
||||||
|
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: {
|
||||||
|
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: contactsPanel(theme),
|
||||||
|
search: search(theme),
|
||||||
|
breadcrumbs: {
|
||||||
|
...text(theme, "sans", "primary"),
|
||||||
|
padding: {
|
||||||
|
left: 6,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
108
styles/src/styleTree/chatPanel.ts
Normal file
108
styles/src/styleTree/chatPanel.ts
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import Theme from "../themes/theme";
|
||||||
|
import { panel } from "./app";
|
||||||
|
import {
|
||||||
|
backgroundColor,
|
||||||
|
border,
|
||||||
|
player,
|
||||||
|
shadow,
|
||||||
|
text,
|
||||||
|
TextColor
|
||||||
|
} from "./components";
|
||||||
|
|
||||||
|
export default function chatPanel(theme: Theme) {
|
||||||
|
function channelSelectItem(
|
||||||
|
theme: Theme,
|
||||||
|
textColor: TextColor,
|
||||||
|
hovered: boolean
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
name: text(theme, "sans", textColor),
|
||||||
|
padding: 4,
|
||||||
|
hash: {
|
||||||
|
...text(theme, "sans", "muted"),
|
||||||
|
margin: {
|
||||||
|
right: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
background: hovered ? backgroundColor(theme, 300, "hovered") : undefined,
|
||||||
|
cornerRadius: hovered ? 6 : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = {
|
||||||
|
body: text(theme, "sans", "secondary"),
|
||||||
|
timestamp: text(theme, "sans", "muted", { size: "sm" }),
|
||||||
|
padding: {
|
||||||
|
bottom: 6,
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
...text(theme, "sans", "primary", { weight: "bold" }),
|
||||||
|
margin: {
|
||||||
|
right: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...panel,
|
||||||
|
channelName: text(theme, "sans", "primary", { weight: "bold" }),
|
||||||
|
channelNameHash: {
|
||||||
|
...text(theme, "sans", "muted"),
|
||||||
|
padding: {
|
||||||
|
right: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
channelSelect: {
|
||||||
|
header: {
|
||||||
|
...channelSelectItem(theme, "primary", false),
|
||||||
|
padding: {
|
||||||
|
bottom: 4,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
item: channelSelectItem(theme, "secondary", false),
|
||||||
|
hoveredItem: channelSelectItem(theme, "secondary", true),
|
||||||
|
activeItem: channelSelectItem(theme, "primary", false),
|
||||||
|
hoveredActiveItem: channelSelectItem(theme, "primary", true),
|
||||||
|
menu: {
|
||||||
|
background: backgroundColor(theme, 500),
|
||||||
|
cornerRadius: 6,
|
||||||
|
padding: 4,
|
||||||
|
border: border(theme, "primary"),
|
||||||
|
shadow: shadow(theme),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
signInPrompt: text(theme, "sans", "secondary", { underline: true }),
|
||||||
|
hoveredSignInPrompt: text(theme, "sans", "primary", { underline: true }),
|
||||||
|
message,
|
||||||
|
pendingMessage: {
|
||||||
|
...message,
|
||||||
|
body: {
|
||||||
|
...message.body,
|
||||||
|
color: theme.textColor.muted.value,
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
...message.sender,
|
||||||
|
color: theme.textColor.muted.value,
|
||||||
|
},
|
||||||
|
timestamp: {
|
||||||
|
...message.timestamp,
|
||||||
|
color: theme.textColor.muted.value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputEditor: {
|
||||||
|
background: backgroundColor(theme, 500),
|
||||||
|
cornerRadius: 6,
|
||||||
|
text: text(theme, "mono", "primary"),
|
||||||
|
placeholderText: text(theme, "mono", "placeholder", { size: "sm" }),
|
||||||
|
selection: player(theme, 1).selection,
|
||||||
|
border: border(theme, "secondary"),
|
||||||
|
padding: {
|
||||||
|
bottom: 7,
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
top: 7,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
93
styles/src/styleTree/components.ts
Normal file
93
styles/src/styleTree/components.ts
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import chroma from "chroma-js";
|
||||||
|
import Theme, { BackgroundColorSet } 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 fontFamilies,
|
||||||
|
color: TextColor,
|
||||||
|
properties?: {
|
||||||
|
size?: keyof typeof fontSizes;
|
||||||
|
weight?: FontWeight;
|
||||||
|
underline?: boolean;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
let size = fontSizes[properties?.size || "sm"].value;
|
||||||
|
return {
|
||||||
|
family: fontFamilies[fontFamily].value,
|
||||||
|
color: theme.textColor[color].value,
|
||||||
|
...properties,
|
||||||
|
size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function textColor(theme: Theme, color: TextColor) {
|
||||||
|
return theme.textColor[color].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BorderColor = keyof Theme["borderColor"];
|
||||||
|
export interface BorderOptions {
|
||||||
|
width?: number;
|
||||||
|
top?: boolean;
|
||||||
|
bottom?: boolean;
|
||||||
|
left?: boolean;
|
||||||
|
right?: boolean;
|
||||||
|
overlay?: boolean;
|
||||||
|
}
|
||||||
|
export function border(
|
||||||
|
theme: Theme,
|
||||||
|
color: BorderColor,
|
||||||
|
options?: BorderOptions
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
color: borderColor(theme, color),
|
||||||
|
width: 1,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function borderColor(theme: Theme, color: BorderColor) {
|
||||||
|
return theme.borderColor[color].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IconColor = keyof Theme["iconColor"];
|
||||||
|
export function iconColor(theme: Theme, color: IconColor) {
|
||||||
|
return theme.iconColor[color].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PlayerIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||||
|
export interface Player {
|
||||||
|
selection: {
|
||||||
|
cursor: Color;
|
||||||
|
selection: Color;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export function player(
|
||||||
|
theme: Theme,
|
||||||
|
playerNumber: PlayerIndex,
|
||||||
|
): Player {
|
||||||
|
return {
|
||||||
|
selection: {
|
||||||
|
cursor: theme.player[playerNumber].cursorColor.value,
|
||||||
|
selection: theme.player[playerNumber].selectionColor.value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BackgroundColor = keyof Theme["backgroundColor"];
|
||||||
|
export type BackgroundState = keyof BackgroundColorSet;
|
||||||
|
export function backgroundColor(
|
||||||
|
theme: Theme,
|
||||||
|
name: BackgroundColor,
|
||||||
|
state?: BackgroundState,
|
||||||
|
): Color {
|
||||||
|
return theme.backgroundColor[name][state || "base"].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shadow(theme: Theme) {
|
||||||
|
return {
|
||||||
|
blur: 16,
|
||||||
|
color: chroma("black").alpha(theme.shadowAlpha.value).hex(),
|
||||||
|
offset: [0, 2],
|
||||||
|
};
|
||||||
|
}
|
62
styles/src/styleTree/contactsPanel.ts
Normal file
62
styles/src/styleTree/contactsPanel.ts
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import Theme from "../themes/theme";
|
||||||
|
import { panel } from "./app";
|
||||||
|
import { backgroundColor, borderColor, text } from "./components";
|
||||||
|
|
||||||
|
export default function(theme: Theme) {
|
||||||
|
const project = {
|
||||||
|
guestAvatarSpacing: 4,
|
||||||
|
height: 24,
|
||||||
|
guestAvatar: {
|
||||||
|
cornerRadius: 8,
|
||||||
|
width: 14,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
...text(theme, "mono", "placeholder", { size: "sm" }),
|
||||||
|
margin: {
|
||||||
|
right: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
left: 8,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const sharedProject = {
|
||||||
|
...project,
|
||||||
|
background: backgroundColor(theme, 300),
|
||||||
|
cornerRadius: 6,
|
||||||
|
name: {
|
||||||
|
...project.name,
|
||||||
|
...text(theme, "mono", "secondary", { size: "sm" }),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...panel,
|
||||||
|
hostRowHeight: 28,
|
||||||
|
treeBranchColor: borderColor(theme, "muted"),
|
||||||
|
treeBranchWidth: 1,
|
||||||
|
hostAvatar: {
|
||||||
|
cornerRadius: 10,
|
||||||
|
width: 18,
|
||||||
|
},
|
||||||
|
hostUsername: {
|
||||||
|
...text(theme, "mono", "primary", { size: "sm" }),
|
||||||
|
padding: {
|
||||||
|
left: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
project,
|
||||||
|
sharedProject,
|
||||||
|
hoveredSharedProject: {
|
||||||
|
...sharedProject,
|
||||||
|
background: backgroundColor(theme, 300, "hovered"),
|
||||||
|
cornerRadius: 6,
|
||||||
|
},
|
||||||
|
unsharedProject: project,
|
||||||
|
hoveredUnsharedProject: {
|
||||||
|
...project,
|
||||||
|
cornerRadius: 6,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
146
styles/src/styleTree/editor.ts
Normal file
146
styles/src/styleTree/editor.ts
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
import Theme from "../themes/theme";
|
||||||
|
import {
|
||||||
|
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",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
// textColor: theme.syntax.primary.color,
|
||||||
|
textColor: theme.syntax.primary.color.value,
|
||||||
|
background: backgroundColor(theme, 500),
|
||||||
|
activeLineBackground: theme.editor.line.active.value,
|
||||||
|
codeActionsIndicator: iconColor(theme, "muted"),
|
||||||
|
diffBackgroundDeleted: backgroundColor(theme, "error"),
|
||||||
|
diffBackgroundInserted: backgroundColor(theme, "ok"),
|
||||||
|
documentHighlightReadBackground: theme.editor.highlight.occurrence.value,
|
||||||
|
documentHighlightWriteBackground: theme.editor.highlight.activeOccurrence.value,
|
||||||
|
errorColor: theme.textColor.error.value,
|
||||||
|
gutterBackground: backgroundColor(theme, 500),
|
||||||
|
gutterPaddingFactor: 3.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, 500),
|
||||||
|
cornerRadius: 6,
|
||||||
|
padding: 6,
|
||||||
|
border: border(theme, "secondary"),
|
||||||
|
item: autocompleteItem,
|
||||||
|
hoveredItem: {
|
||||||
|
...autocompleteItem,
|
||||||
|
background: backgroundColor(theme, 500, "hovered"),
|
||||||
|
},
|
||||||
|
margin: {
|
||||||
|
left: -14,
|
||||||
|
},
|
||||||
|
matchHighlight: text(theme, "mono", "feature"),
|
||||||
|
selectedItem: {
|
||||||
|
...autocompleteItem,
|
||||||
|
background: backgroundColor(theme, 500, "active"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
diagnosticHeader: {
|
||||||
|
background: backgroundColor(theme, 300),
|
||||||
|
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" }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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: {
|
||||||
|
keyword: theme.syntax.keyword.color.value,
|
||||||
|
function: theme.syntax.function.color.value,
|
||||||
|
string: theme.syntax.string.color.value,
|
||||||
|
type: theme.syntax.type.color.value,
|
||||||
|
number: theme.syntax.number.color.value,
|
||||||
|
comment: theme.syntax.comment.color.value,
|
||||||
|
property: theme.syntax.property.color.value,
|
||||||
|
variant: theme.syntax.variant.color.value,
|
||||||
|
constant: theme.syntax.constant.color.value,
|
||||||
|
title: { color: theme.syntax.title.color.value, weight: "bold" },
|
||||||
|
emphasis: theme.textColor.feature.value,
|
||||||
|
"emphasis.strong": { color: theme.textColor.feature.value, weight: "bold" },
|
||||||
|
link_uri: { color: theme.syntax.linkUrl.color.value, underline: true },
|
||||||
|
link_text: { color: theme.syntax.linkText.color.value, italic: true },
|
||||||
|
list_marker: theme.syntax.punctuation.color.value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
37
styles/src/styleTree/projectPanel.ts
Normal file
37
styles/src/styleTree/projectPanel.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import Theme from "../themes/theme";
|
||||||
|
import { Color } from "../utils/color";
|
||||||
|
import { panel } from "./app";
|
||||||
|
import { backgroundColor, iconColor, text, TextColor } from "./components";
|
||||||
|
|
||||||
|
export default function projectPanel(theme: Theme) {
|
||||||
|
function entry(theme: Theme, textColor: TextColor, background?: Color) {
|
||||||
|
return {
|
||||||
|
height: 22,
|
||||||
|
background,
|
||||||
|
iconColor: iconColor(theme, "muted"),
|
||||||
|
iconSize: 8,
|
||||||
|
iconSpacing: 8,
|
||||||
|
text: text(theme, "mono", textColor, { size: "sm" }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...panel,
|
||||||
|
entry: entry(theme, "secondary"),
|
||||||
|
hoveredEntry: entry(
|
||||||
|
theme,
|
||||||
|
"secondary",
|
||||||
|
backgroundColor(theme, 300, "hovered")
|
||||||
|
),
|
||||||
|
selectedEntry: entry(theme, "primary"),
|
||||||
|
hoveredSelectedEntry: entry(
|
||||||
|
theme,
|
||||||
|
"primary",
|
||||||
|
backgroundColor(theme, 300, "hovered")
|
||||||
|
),
|
||||||
|
padding: {
|
||||||
|
top: 6,
|
||||||
|
left: 12,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
79
styles/src/styleTree/search.ts
Normal file
79
styles/src/styleTree/search.ts
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import Theme from "../themes/theme";
|
||||||
|
import { backgroundColor, border, player, text } from "./components";
|
||||||
|
|
||||||
|
export default function search(theme: Theme) {
|
||||||
|
const optionButton = {
|
||||||
|
...text(theme, "mono", "secondary"),
|
||||||
|
background: backgroundColor(theme, 300),
|
||||||
|
cornerRadius: 6,
|
||||||
|
border: border(theme, "primary"),
|
||||||
|
margin: {
|
||||||
|
left: 1,
|
||||||
|
right: 1,
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
bottom: 1,
|
||||||
|
left: 6,
|
||||||
|
right: 6,
|
||||||
|
top: 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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, "secondary"),
|
||||||
|
margin: {
|
||||||
|
right: 5,
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
top: 3,
|
||||||
|
bottom: 3,
|
||||||
|
left: 14,
|
||||||
|
right: 14,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
matchBackground: theme.editor.highlight.match.value,
|
||||||
|
tabIconSpacing: 4,
|
||||||
|
tabIconWidth: 14,
|
||||||
|
activeHoveredOptionButton: {
|
||||||
|
...optionButton,
|
||||||
|
background: backgroundColor(theme, 100),
|
||||||
|
},
|
||||||
|
activeOptionButton: {
|
||||||
|
...optionButton,
|
||||||
|
background: backgroundColor(theme, 100),
|
||||||
|
},
|
||||||
|
editor,
|
||||||
|
hoveredOptionButton: {
|
||||||
|
...optionButton,
|
||||||
|
background: backgroundColor(theme, 100),
|
||||||
|
},
|
||||||
|
invalidEditor: {
|
||||||
|
...editor,
|
||||||
|
border: border(theme, "error"),
|
||||||
|
},
|
||||||
|
matchIndex: {
|
||||||
|
...text(theme, "mono", "muted"),
|
||||||
|
padding: 6,
|
||||||
|
},
|
||||||
|
optionButton,
|
||||||
|
optionButtonGroup: {
|
||||||
|
padding: {
|
||||||
|
left: 2,
|
||||||
|
right: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resultsStatus: {
|
||||||
|
...text(theme, "mono", "primary"),
|
||||||
|
size: 18,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
59
styles/src/styleTree/selectorModal.ts
Normal file
59
styles/src/styleTree/selectorModal.ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import Theme from "../themes/theme";
|
||||||
|
import { backgroundColor, border, player, shadow, text } from "./components";
|
||||||
|
|
||||||
|
export default function selectorModal(theme: Theme): Object {
|
||||||
|
const item = {
|
||||||
|
padding: {
|
||||||
|
bottom: 4,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
top: 4,
|
||||||
|
},
|
||||||
|
cornerRadius: 6,
|
||||||
|
text: text(theme, "sans", "secondary"),
|
||||||
|
highlightText: text(theme, "sans", "feature", { weight: "bold" }),
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeItem = {
|
||||||
|
...item,
|
||||||
|
background: backgroundColor(theme, 300, "active"),
|
||||||
|
text: text(theme, "sans", "primary"),
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
background: backgroundColor(theme, 300),
|
||||||
|
cornerRadius: 6,
|
||||||
|
padding: 8,
|
||||||
|
item,
|
||||||
|
activeItem,
|
||||||
|
border: border(theme, "primary"),
|
||||||
|
empty: {
|
||||||
|
text: text(theme, "sans", "placeholder"),
|
||||||
|
padding: {
|
||||||
|
bottom: 4,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
top: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputEditor: {
|
||||||
|
background: backgroundColor(theme, 500),
|
||||||
|
corner_radius: 6,
|
||||||
|
placeholderText: text(theme, "sans", "placeholder"),
|
||||||
|
selection: player(theme, 1).selection,
|
||||||
|
text: text(theme, "mono", "primary"),
|
||||||
|
border: border(theme, "secondary"),
|
||||||
|
padding: {
|
||||||
|
bottom: 7,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
top: 7,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
margin: {
|
||||||
|
bottom: 52,
|
||||||
|
top: 52,
|
||||||
|
},
|
||||||
|
shadow: shadow(theme),
|
||||||
|
};
|
||||||
|
}
|
150
styles/src/styleTree/workspace.ts
Normal file
150
styles/src/styleTree/workspace.ts
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
import Theme from "../themes/theme";
|
||||||
|
import { backgroundColor, border, borderColor, iconColor, text } from "./components";
|
||||||
|
|
||||||
|
export default function workspace(theme: Theme) {
|
||||||
|
const signInPrompt = {
|
||||||
|
...text(theme, "sans", "secondary", { size: "xs" }),
|
||||||
|
underline: true,
|
||||||
|
padding: {
|
||||||
|
right: 8,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const tab = {
|
||||||
|
height: 32,
|
||||||
|
background: backgroundColor(theme, 300),
|
||||||
|
iconClose: iconColor(theme, "muted"),
|
||||||
|
iconCloseActive: iconColor(theme, "active"),
|
||||||
|
iconConflict: iconColor(theme, "warning"),
|
||||||
|
iconDirty: iconColor(theme, "info"),
|
||||||
|
iconWidth: 8,
|
||||||
|
spacing: 10,
|
||||||
|
text: text(theme, "mono", "secondary", { size: "sm" }),
|
||||||
|
border: border(theme, "primary", {
|
||||||
|
left: true,
|
||||||
|
bottom: true,
|
||||||
|
overlay: true,
|
||||||
|
}),
|
||||||
|
padding: {
|
||||||
|
left: 12,
|
||||||
|
right: 12,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeTab = {
|
||||||
|
...tab,
|
||||||
|
background: backgroundColor(theme, 500),
|
||||||
|
text: text(theme, "mono", "active", { size: "sm" }),
|
||||||
|
border: {
|
||||||
|
...tab.border,
|
||||||
|
bottom: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const sidebarItem = {
|
||||||
|
height: 32,
|
||||||
|
iconColor: iconColor(theme, "secondary"),
|
||||||
|
iconSize: 18,
|
||||||
|
};
|
||||||
|
const sidebar = {
|
||||||
|
width: 30,
|
||||||
|
background: backgroundColor(theme, 300),
|
||||||
|
border: border(theme, "primary", { right: true }),
|
||||||
|
item: sidebarItem,
|
||||||
|
activeItem: {
|
||||||
|
...sidebarItem,
|
||||||
|
iconColor: iconColor(theme, "active"),
|
||||||
|
},
|
||||||
|
resizeHandle: {
|
||||||
|
background: border(theme, "primary").color,
|
||||||
|
padding: {
|
||||||
|
left: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
background: backgroundColor(theme, 300),
|
||||||
|
leaderBorderOpacity: 0.7,
|
||||||
|
leaderBorderWidth: 2.0,
|
||||||
|
tab,
|
||||||
|
activeTab,
|
||||||
|
leftSidebar: {
|
||||||
|
...sidebar,
|
||||||
|
border: border(theme, "primary", { right: true }),
|
||||||
|
},
|
||||||
|
rightSidebar: {
|
||||||
|
...sidebar,
|
||||||
|
border: border(theme, "primary", { left: true }),
|
||||||
|
},
|
||||||
|
paneDivider: {
|
||||||
|
color: border(theme, "secondary").color,
|
||||||
|
width: 1,
|
||||||
|
},
|
||||||
|
status_bar: {
|
||||||
|
height: 24,
|
||||||
|
itemSpacing: 8,
|
||||||
|
padding: {
|
||||||
|
left: 6,
|
||||||
|
right: 6,
|
||||||
|
},
|
||||||
|
border: border(theme, "primary", { top: true, overlay: true }),
|
||||||
|
cursorPosition: text(theme, "sans", "muted"),
|
||||||
|
diagnosticMessage: text(theme, "sans", "muted"),
|
||||||
|
lspMessage: text(theme, "sans", "muted"),
|
||||||
|
},
|
||||||
|
titlebar: {
|
||||||
|
avatarWidth: 18,
|
||||||
|
height: 32,
|
||||||
|
background: backgroundColor(theme, 100),
|
||||||
|
shareIconColor: iconColor(theme, "secondary"),
|
||||||
|
shareIconActiveColor: iconColor(theme, "feature"),
|
||||||
|
title: text(theme, "sans", "primary"),
|
||||||
|
avatar: {
|
||||||
|
cornerRadius: 10,
|
||||||
|
border: {
|
||||||
|
color: "#00000088",
|
||||||
|
width: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
avatarRibbon: {
|
||||||
|
height: 3,
|
||||||
|
width: 12,
|
||||||
|
// TODO: The background for this ideally should be
|
||||||
|
// set with a token, not hardcoded in rust
|
||||||
|
},
|
||||||
|
border: border(theme, "primary", { bottom: true }),
|
||||||
|
signInPrompt,
|
||||||
|
hoveredSignInPrompt: {
|
||||||
|
...signInPrompt,
|
||||||
|
...text(theme, "sans", "active", { size: "xs" }),
|
||||||
|
},
|
||||||
|
offlineIcon: {
|
||||||
|
color: iconColor(theme, "secondary"),
|
||||||
|
width: 16,
|
||||||
|
padding: {
|
||||||
|
right: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
outdatedWarning: {
|
||||||
|
...text(theme, "sans", "warning"),
|
||||||
|
size: 13,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
height: 34,
|
||||||
|
background: backgroundColor(theme, 500),
|
||||||
|
border: border(theme, "secondary", { bottom: true }),
|
||||||
|
itemSpacing: 8,
|
||||||
|
padding: { left: 16, right: 8, top: 4, bottom: 4 },
|
||||||
|
},
|
||||||
|
breadcrumbs: {
|
||||||
|
...text(theme, "mono", "secondary"),
|
||||||
|
padding: { left: 6 },
|
||||||
|
},
|
||||||
|
disconnectedOverlay: {
|
||||||
|
...text(theme, "sans", "active"),
|
||||||
|
background: "#000000aa",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
229
styles/src/themes/dark.ts
Normal file
229
styles/src/themes/dark.ts
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
import { colors, fontWeights, NumberToken } from "../tokens";
|
||||||
|
import { withOpacity } from "../utils/color";
|
||||||
|
import Theme, { buildPlayer, Syntax } from "./theme";
|
||||||
|
|
||||||
|
const backgroundColor = {
|
||||||
|
100: {
|
||||||
|
base: colors.neutral[750],
|
||||||
|
hovered: colors.neutral[725],
|
||||||
|
active: colors.neutral[800],
|
||||||
|
focused: colors.neutral[675],
|
||||||
|
},
|
||||||
|
300: {
|
||||||
|
base: colors.neutral[800],
|
||||||
|
hovered: colors.neutral[775],
|
||||||
|
active: colors.neutral[750],
|
||||||
|
focused: colors.neutral[775],
|
||||||
|
},
|
||||||
|
500: {
|
||||||
|
base: colors.neutral[900],
|
||||||
|
hovered: withOpacity(colors.neutral[0], 0.08),
|
||||||
|
active: withOpacity(colors.neutral[0], 0.12),
|
||||||
|
focused: colors.neutral[825],
|
||||||
|
},
|
||||||
|
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: colors.neutral[875],
|
||||||
|
secondary: colors.neutral[775],
|
||||||
|
muted: colors.neutral[675],
|
||||||
|
focused: colors.neutral[500],
|
||||||
|
active: colors.neutral[900],
|
||||||
|
ok: colors.green[500],
|
||||||
|
error: colors.red[500],
|
||||||
|
warning: colors.amber[500],
|
||||||
|
info: colors.blue[500],
|
||||||
|
};
|
||||||
|
|
||||||
|
const textColor = {
|
||||||
|
primary: colors.neutral[50],
|
||||||
|
secondary: colors.neutral[350],
|
||||||
|
muted: colors.neutral[450],
|
||||||
|
placeholder: colors.neutral[650],
|
||||||
|
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: colors.neutral[200],
|
||||||
|
secondary: colors.neutral[350],
|
||||||
|
muted: colors.neutral[600],
|
||||||
|
placeholder: colors.neutral[700],
|
||||||
|
active: colors.neutral[0],
|
||||||
|
//TODO: (design) define feature and it's correct value
|
||||||
|
feature: colors.blue[500],
|
||||||
|
ok: colors.green[600],
|
||||||
|
error: colors.red[500],
|
||||||
|
warning: colors.amber[400],
|
||||||
|
info: colors.blue[600],
|
||||||
|
};
|
||||||
|
|
||||||
|
const player = {
|
||||||
|
1: buildPlayer(colors.blue[500]),
|
||||||
|
2: buildPlayer(colors.lime[500]),
|
||||||
|
3: buildPlayer(colors.fuschia[500]),
|
||||||
|
4: buildPlayer(colors.orange[500]),
|
||||||
|
5: buildPlayer(colors.purple[500]),
|
||||||
|
6: buildPlayer(colors.teal[400]),
|
||||||
|
7: buildPlayer(colors.pink[400]),
|
||||||
|
8: buildPlayer(colors.yellow[400]),
|
||||||
|
};
|
||||||
|
|
||||||
|
const editor = {
|
||||||
|
background: backgroundColor[500].base,
|
||||||
|
indent_guide: borderColor.muted,
|
||||||
|
indent_guide_active: borderColor.secondary,
|
||||||
|
line: {
|
||||||
|
active: withOpacity(colors.neutral[0], 0.07),
|
||||||
|
highlighted: withOpacity(colors.neutral[0], 0.12),
|
||||||
|
inserted: backgroundColor.ok.active,
|
||||||
|
deleted: backgroundColor.error.active,
|
||||||
|
modified: backgroundColor.info.active,
|
||||||
|
},
|
||||||
|
highlight: {
|
||||||
|
selection: player[1].selectionColor,
|
||||||
|
occurrence: withOpacity(colors.neutral[0], 0.12),
|
||||||
|
activeOccurrence: withOpacity(colors.neutral[0], 0.16), // TODO: This is not correctly hooked up to occurences on the rust side
|
||||||
|
matchingBracket: backgroundColor[500].active,
|
||||||
|
match: withOpacity(colors.sky[500], 0.16),
|
||||||
|
activeMatch: withOpacity(colors.sky[800], 0.32),
|
||||||
|
related: backgroundColor[500].focused,
|
||||||
|
},
|
||||||
|
gutter: {
|
||||||
|
primary: textColor.placeholder,
|
||||||
|
active: textColor.active,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const syntax: Syntax = {
|
||||||
|
primary: {
|
||||||
|
color: colors.neutral[150],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
color: colors.neutral[300],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
punctuation: {
|
||||||
|
color: colors.neutral[200],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
constant: {
|
||||||
|
color: colors.neutral[150],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
keyword: {
|
||||||
|
color: colors.blue[400],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
function: {
|
||||||
|
color: colors.yellow[200],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
color: colors.teal[300],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
color: colors.sky[300],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
property: {
|
||||||
|
color: colors.blue[400],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
enum: {
|
||||||
|
color: colors.orange[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
operator: {
|
||||||
|
color: colors.orange[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
string: {
|
||||||
|
color: colors.orange[300],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
color: colors.lime[300],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
boolean: {
|
||||||
|
color: colors.lime[300],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
predictive: {
|
||||||
|
color: textColor.muted,
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
color: colors.amber[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
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const shadowAlpha: NumberToken = {
|
||||||
|
value: 0.32,
|
||||||
|
type: "number",
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme: Theme = {
|
||||||
|
name: "dark",
|
||||||
|
backgroundColor,
|
||||||
|
borderColor,
|
||||||
|
textColor,
|
||||||
|
iconColor,
|
||||||
|
editor,
|
||||||
|
syntax,
|
||||||
|
player,
|
||||||
|
shadowAlpha,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default theme;
|
227
styles/src/themes/light.ts
Normal file
227
styles/src/themes/light.ts
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
import { colors, fontWeights, NumberToken } from "../tokens";
|
||||||
|
import { withOpacity } from "../utils/color";
|
||||||
|
import Theme, { buildPlayer, Syntax } from "./theme";
|
||||||
|
|
||||||
|
const backgroundColor = {
|
||||||
|
100: {
|
||||||
|
base: colors.neutral[75],
|
||||||
|
hovered: colors.neutral[100],
|
||||||
|
active: colors.neutral[150],
|
||||||
|
focused: colors.neutral[100],
|
||||||
|
},
|
||||||
|
300: {
|
||||||
|
base: colors.neutral[25],
|
||||||
|
hovered: colors.neutral[75],
|
||||||
|
active: colors.neutral[125],
|
||||||
|
focused: colors.neutral[75],
|
||||||
|
},
|
||||||
|
500: {
|
||||||
|
base: colors.neutral[0],
|
||||||
|
hovered: withOpacity(colors.neutral[900], 0.03),
|
||||||
|
active: withOpacity(colors.neutral[900], 0.06),
|
||||||
|
focused: colors.neutral[50],
|
||||||
|
},
|
||||||
|
ok: {
|
||||||
|
base: colors.green[100],
|
||||||
|
hovered: colors.green[100],
|
||||||
|
active: colors.green[100],
|
||||||
|
focused: colors.green[100],
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
base: colors.red[100],
|
||||||
|
hovered: colors.red[100],
|
||||||
|
active: colors.red[100],
|
||||||
|
focused: colors.red[100],
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
base: colors.yellow[100],
|
||||||
|
hovered: colors.yellow[100],
|
||||||
|
active: colors.yellow[100],
|
||||||
|
focused: colors.yellow[100],
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
base: colors.blue[100],
|
||||||
|
hovered: colors.blue[100],
|
||||||
|
active: colors.blue[100],
|
||||||
|
focused: colors.blue[100],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const borderColor = {
|
||||||
|
primary: colors.neutral[150],
|
||||||
|
secondary: colors.neutral[150],
|
||||||
|
muted: colors.neutral[100],
|
||||||
|
focused: colors.neutral[100],
|
||||||
|
active: colors.neutral[250],
|
||||||
|
ok: colors.green[200],
|
||||||
|
error: colors.red[200],
|
||||||
|
warning: colors.yellow[200],
|
||||||
|
info: colors.blue[200],
|
||||||
|
};
|
||||||
|
|
||||||
|
const textColor = {
|
||||||
|
primary: colors.neutral[750],
|
||||||
|
secondary: colors.neutral[650],
|
||||||
|
muted: colors.neutral[550],
|
||||||
|
placeholder: colors.neutral[450],
|
||||||
|
active: colors.neutral[900],
|
||||||
|
feature: colors.indigo[600],
|
||||||
|
ok: colors.green[500],
|
||||||
|
error: colors.red[500],
|
||||||
|
warning: colors.yellow[500],
|
||||||
|
info: colors.blue[500],
|
||||||
|
};
|
||||||
|
|
||||||
|
const iconColor = {
|
||||||
|
primary: colors.neutral[700],
|
||||||
|
secondary: colors.neutral[500],
|
||||||
|
muted: colors.neutral[350],
|
||||||
|
placeholder: colors.neutral[300],
|
||||||
|
active: colors.neutral[900],
|
||||||
|
feature: colors.indigo[500],
|
||||||
|
ok: colors.green[600],
|
||||||
|
error: colors.red[600],
|
||||||
|
warning: colors.yellow[400],
|
||||||
|
info: colors.blue[600],
|
||||||
|
};
|
||||||
|
|
||||||
|
const player = {
|
||||||
|
1: buildPlayer(colors.blue[500]),
|
||||||
|
2: buildPlayer(colors.emerald[400]),
|
||||||
|
3: buildPlayer(colors.fuschia[400]),
|
||||||
|
4: buildPlayer(colors.orange[400]),
|
||||||
|
5: buildPlayer(colors.purple[400]),
|
||||||
|
6: buildPlayer(colors.teal[400]),
|
||||||
|
7: buildPlayer(colors.pink[400]),
|
||||||
|
8: buildPlayer(colors.yellow[400]),
|
||||||
|
};
|
||||||
|
|
||||||
|
const editor = {
|
||||||
|
background: backgroundColor[500].base,
|
||||||
|
indent_guide: borderColor.muted,
|
||||||
|
indent_guide_active: borderColor.secondary,
|
||||||
|
line: {
|
||||||
|
active: withOpacity(colors.neutral[900], 0.06),
|
||||||
|
highlighted: withOpacity(colors.neutral[900], 0.12),
|
||||||
|
inserted: backgroundColor.ok.active,
|
||||||
|
deleted: backgroundColor.error.active,
|
||||||
|
modified: backgroundColor.info.active,
|
||||||
|
},
|
||||||
|
highlight: {
|
||||||
|
selection: player[1].selectionColor,
|
||||||
|
occurrence: withOpacity(colors.neutral[900], 0.06),
|
||||||
|
activeOccurrence: withOpacity(colors.neutral[900], 0.16), // TODO: This is not hooked up to occurences on the rust side
|
||||||
|
matchingBracket: colors.neutral[0],
|
||||||
|
match: withOpacity(colors.red[500], 0.2),
|
||||||
|
activeMatch: withOpacity(colors.indigo[400], 0.36), // TODO: This is not hooked up to occurences on the rust side
|
||||||
|
related: colors.neutral[0],
|
||||||
|
},
|
||||||
|
gutter: {
|
||||||
|
primary: colors.neutral[300],
|
||||||
|
active: textColor.active,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const syntax: Syntax = {
|
||||||
|
primary: {
|
||||||
|
color: colors.neutral[800],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
comment: {
|
||||||
|
color: colors.neutral[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
punctuation: {
|
||||||
|
color: colors.neutral[600],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
constant: {
|
||||||
|
color: colors.neutral[800],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
keyword: {
|
||||||
|
color: colors.indigo[700],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
function: {
|
||||||
|
color: colors.orange[600],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
color: colors.yellow[600],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
color: colors.rose[700],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
property: {
|
||||||
|
color: colors.emerald[700],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
enum: {
|
||||||
|
color: colors.red[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
operator: {
|
||||||
|
color: colors.red[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
string: {
|
||||||
|
color: colors.red[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
color: colors.indigo[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
boolean: {
|
||||||
|
color: colors.red[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
},
|
||||||
|
predictive: {
|
||||||
|
color: textColor.placeholder,
|
||||||
|
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.red[500],
|
||||||
|
weight: fontWeights.normal,
|
||||||
|
// TODO: add italic
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const shadowAlpha: NumberToken = {
|
||||||
|
value: 0.12,
|
||||||
|
type: "number",
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme: Theme = {
|
||||||
|
name: "light",
|
||||||
|
backgroundColor,
|
||||||
|
borderColor,
|
||||||
|
textColor,
|
||||||
|
iconColor,
|
||||||
|
editor,
|
||||||
|
syntax,
|
||||||
|
player,
|
||||||
|
shadowAlpha,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default theme;
|
145
styles/src/themes/theme.ts
Normal file
145
styles/src/themes/theme.ts
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
import { ColorToken, FontWeightToken, NumberToken } from "../tokens";
|
||||||
|
import { withOpacity } from "../utils/color";
|
||||||
|
|
||||||
|
export interface SyntaxHighlightStyle {
|
||||||
|
color: ColorToken;
|
||||||
|
weight: FontWeightToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Player {
|
||||||
|
baseColor: ColorToken;
|
||||||
|
cursorColor: ColorToken;
|
||||||
|
selectionColor: ColorToken;
|
||||||
|
borderColor: ColorToken;
|
||||||
|
}
|
||||||
|
export function buildPlayer(
|
||||||
|
color: ColorToken,
|
||||||
|
cursorOpacity?: number,
|
||||||
|
selectionOpacity?: number,
|
||||||
|
borderOpacity?: number
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
baseColor: color,
|
||||||
|
cursorColor: withOpacity(color, cursorOpacity || 1.0),
|
||||||
|
selectionColor: withOpacity(color, selectionOpacity || 0.24),
|
||||||
|
borderColor: withOpacity(color, borderOpacity || 0.8),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BackgroundColorSet {
|
||||||
|
base: ColorToken;
|
||||||
|
hovered: ColorToken;
|
||||||
|
active: ColorToken;
|
||||||
|
focused: ColorToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Syntax {
|
||||||
|
primary: SyntaxHighlightStyle;
|
||||||
|
comment: SyntaxHighlightStyle;
|
||||||
|
punctuation: SyntaxHighlightStyle;
|
||||||
|
constant: SyntaxHighlightStyle;
|
||||||
|
keyword: SyntaxHighlightStyle;
|
||||||
|
function: SyntaxHighlightStyle;
|
||||||
|
type: SyntaxHighlightStyle;
|
||||||
|
variant: SyntaxHighlightStyle;
|
||||||
|
property: SyntaxHighlightStyle;
|
||||||
|
enum: SyntaxHighlightStyle;
|
||||||
|
operator: SyntaxHighlightStyle;
|
||||||
|
string: SyntaxHighlightStyle;
|
||||||
|
number: SyntaxHighlightStyle;
|
||||||
|
boolean: SyntaxHighlightStyle;
|
||||||
|
predictive: SyntaxHighlightStyle;
|
||||||
|
// TODO: Either move the following or rename
|
||||||
|
title: SyntaxHighlightStyle;
|
||||||
|
emphasis: SyntaxHighlightStyle;
|
||||||
|
emphasisStrong: SyntaxHighlightStyle;
|
||||||
|
linkUrl: SyntaxHighlightStyle;
|
||||||
|
linkText: SyntaxHighlightStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default interface Theme {
|
||||||
|
name: string;
|
||||||
|
backgroundColor: {
|
||||||
|
100: BackgroundColorSet;
|
||||||
|
300: BackgroundColorSet;
|
||||||
|
500: BackgroundColorSet;
|
||||||
|
ok: BackgroundColorSet;
|
||||||
|
error: BackgroundColorSet;
|
||||||
|
warning: BackgroundColorSet;
|
||||||
|
info: BackgroundColorSet;
|
||||||
|
};
|
||||||
|
borderColor: {
|
||||||
|
primary: ColorToken;
|
||||||
|
secondary: ColorToken;
|
||||||
|
muted: ColorToken;
|
||||||
|
focused: ColorToken;
|
||||||
|
active: ColorToken;
|
||||||
|
ok: ColorToken;
|
||||||
|
error: ColorToken;
|
||||||
|
warning: ColorToken;
|
||||||
|
info: ColorToken;
|
||||||
|
};
|
||||||
|
textColor: {
|
||||||
|
primary: ColorToken;
|
||||||
|
secondary: ColorToken;
|
||||||
|
muted: ColorToken;
|
||||||
|
placeholder: ColorToken;
|
||||||
|
active: ColorToken;
|
||||||
|
feature: ColorToken;
|
||||||
|
ok: ColorToken;
|
||||||
|
error: ColorToken;
|
||||||
|
warning: ColorToken;
|
||||||
|
info: ColorToken;
|
||||||
|
};
|
||||||
|
iconColor: {
|
||||||
|
primary: ColorToken;
|
||||||
|
secondary: ColorToken;
|
||||||
|
muted: ColorToken;
|
||||||
|
placeholder: ColorToken;
|
||||||
|
active: ColorToken;
|
||||||
|
feature: ColorToken;
|
||||||
|
ok: ColorToken;
|
||||||
|
error: ColorToken;
|
||||||
|
warning: ColorToken;
|
||||||
|
info: ColorToken;
|
||||||
|
};
|
||||||
|
editor: {
|
||||||
|
background: ColorToken;
|
||||||
|
indent_guide: ColorToken;
|
||||||
|
indent_guide_active: ColorToken;
|
||||||
|
line: {
|
||||||
|
active: ColorToken;
|
||||||
|
highlighted: ColorToken;
|
||||||
|
inserted: ColorToken;
|
||||||
|
deleted: ColorToken;
|
||||||
|
modified: ColorToken;
|
||||||
|
};
|
||||||
|
highlight: {
|
||||||
|
selection: ColorToken;
|
||||||
|
occurrence: ColorToken;
|
||||||
|
activeOccurrence: ColorToken;
|
||||||
|
matchingBracket: ColorToken;
|
||||||
|
match: ColorToken;
|
||||||
|
activeMatch: ColorToken;
|
||||||
|
related: ColorToken;
|
||||||
|
};
|
||||||
|
gutter: {
|
||||||
|
primary: ColorToken;
|
||||||
|
active: ColorToken;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
syntax: Syntax,
|
||||||
|
|
||||||
|
player: {
|
||||||
|
1: Player;
|
||||||
|
2: Player;
|
||||||
|
3: Player;
|
||||||
|
4: Player;
|
||||||
|
5: Player;
|
||||||
|
6: Player;
|
||||||
|
7: Player;
|
||||||
|
8: Player;
|
||||||
|
};
|
||||||
|
shadowAlpha: NumberToken;
|
||||||
|
}
|
102
styles/src/tokens.ts
Normal file
102
styles/src/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(["white", "black"], { steps: 37, increment: 25 }), // (900/25) + 1
|
||||||
|
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,
|
||||||
|
};
|
52
styles/src/utils/color.ts
Normal file
52
styles/src/utils/color.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import chroma, { Scale } from "chroma-js";
|
||||||
|
import { ColorToken } from "../tokens";
|
||||||
|
|
||||||
|
export type Color = string;
|
||||||
|
export type ColorRampStep = { value: Color; type: "color"; step: number };
|
||||||
|
export type ColorRamp = {
|
||||||
|
[index: number]: ColorRampStep;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function colorRamp(
|
||||||
|
color: Color | [Color, Color],
|
||||||
|
options?: { steps?: number; increment?: number; }
|
||||||
|
): ColorRamp {
|
||||||
|
let scale: Scale;
|
||||||
|
if (Array.isArray(color)) {
|
||||||
|
const [startColor, endColor] = color;
|
||||||
|
scale = chroma.scale([startColor, endColor]);
|
||||||
|
} else {
|
||||||
|
let hue = Math.round(chroma(color).hsl()[0]);
|
||||||
|
let startColor = chroma.hsl(hue, 0.88, 0.96);
|
||||||
|
let endColor = chroma.hsl(hue, 0.68, 0.12);
|
||||||
|
scale = chroma
|
||||||
|
.scale([startColor, color, endColor])
|
||||||
|
.domain([0, 0.5, 1])
|
||||||
|
.mode("hsl")
|
||||||
|
.gamma(1)
|
||||||
|
// .correctLightness(true)
|
||||||
|
.padding([0, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ramp: ColorRamp = {};
|
||||||
|
const steps = options?.steps || 10;
|
||||||
|
const increment = options?.increment || 100;
|
||||||
|
|
||||||
|
scale.colors(steps, "hex").forEach((color, ix) => {
|
||||||
|
const step = ix * increment;
|
||||||
|
ramp[step] = {
|
||||||
|
value: color,
|
||||||
|
step,
|
||||||
|
type: "color",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return ramp;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withOpacity(color: ColorToken, opacity: number): ColorToken {
|
||||||
|
return {
|
||||||
|
...color,
|
||||||
|
value: chroma(color.value).alpha(opacity).hex()
|
||||||
|
};
|
||||||
|
}
|
35
styles/src/utils/snakeCase.ts
Normal file
35
styles/src/utils/snakeCase.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { snakeCase } from "case-anything";
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/60269936/typescript-convert-generic-object-from-snake-to-camel-case
|
||||||
|
|
||||||
|
// Typescript magic to convert any string from camelCase to snake_case at compile time
|
||||||
|
type SnakeCase<S> =
|
||||||
|
S extends string ?
|
||||||
|
S extends `${infer T}${infer U}` ?
|
||||||
|
`${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${SnakeCase<U>}` :
|
||||||
|
S :
|
||||||
|
S;
|
||||||
|
|
||||||
|
type SnakeCased<Type> = {
|
||||||
|
[Property in keyof Type as SnakeCase<Property>]: SnakeCased<Type[Property]>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function snakeCaseTree<T>(object: T): SnakeCased<T> {
|
||||||
|
const snakeObject: any = {};
|
||||||
|
for (const key in object) {
|
||||||
|
snakeObject[snakeCase(key)] = snakeCaseValue(object[key]);
|
||||||
|
}
|
||||||
|
return snakeObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
function snakeCaseValue(value: any): any {
|
||||||
|
if (typeof value === "object") {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map(snakeCaseValue);
|
||||||
|
} else {
|
||||||
|
return snakeCaseTree(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
14
styles/tsconfig.json
Normal file
14
styles/tsconfig.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2015",
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"removeComments": true,
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue