Move style source files to src and build to dist

Co-authored-by: Nate Butler <nate@zed.dev>
This commit is contained in:
Keith Simmons 2022-04-04 14:39:28 -07:00
parent 58dee75ff0
commit 05a05157fa
35 changed files with 5540 additions and 4169 deletions

View 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)
}
}

View file

@ -1,115 +0,0 @@
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";
let themes = [
dark,
light
];
// 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 = {
core: coreTokens,
dark: themeTokens(dark),
light: themeTokens(light)
}
// Create core.json
const corePath = path.resolve(`${__dirname}/figma/core.json`);
const coreJSON = JSON.stringify(coreTokens, null, 2);
fs.writeFileSync(corePath, coreJSON);
console.log(`- Core: core.json created`);
// Create {theme}.json
const themePath = path.resolve(`${__dirname}/figma`);
themes.forEach((theme) => {
const tokenJSON = JSON.stringify(themeTokens(theme), null, 2);
fs.writeFileSync(`${themePath}/${theme.name}.json`, tokenJSON);
console.log(`- Theme: ${theme.name}.json created`);
});
// Create combined tokens.json
const combinedPath = path.resolve(`${__dirname}/figma/tokens.json`);
const combinedJSON = JSON.stringify(combinedTokens, null, 2);
fs.writeFileSync(combinedPath, combinedJSON);
console.log(`- Combined: tokens.json created`);

1155
styles/dist/figma/core.json vendored Normal file

File diff suppressed because it is too large Load diff

5154
styles/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,21 @@
{ {
"name": "styles", "name": "styles",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"build": "ts-node buildThemes.ts", "build-themes": "ts-node ./src/buildThemes.ts",
"watch": "nodemon" "build-figma": "ts-node ./src/buildFigmaTokens.ts",
}, "watch": "nodemon"
"author": "", },
"license": "ISC", "author": "",
"dependencies": { "license": "ISC",
"@types/chroma-js": "^2.1.3", "dependencies": {
"@types/node": "^17.0.23", "@types/chroma-js": "^2.1.3",
"case-anything": "^2.1.10", "@types/node": "^17.0.23",
"chroma-js": "^2.4.2", "case-anything": "^2.1.10",
"ts-node": "^10.7.0" "chroma-js": "^2.4.2",
}, "ts-node": "^10.7.0",
"devDependencies": { "nodemon": "^2.0.15"
"nodemon": "^2.0.15" }
}
} }

View 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 = {
core: coreTokens,
}
// Create core.json
const corePath = path.resolve(`${__dirname}/../dist/figma/core.json`);
const coreJSON = JSON.stringify(coreTokens, null, 2);
fs.writeFileSync(corePath, coreJSON);
console.log(`- Core: core.json created`);
// Create {theme}.json
let themes = [dark, light];
const themePath = path.resolve(`${__dirname}/figma`);
themes.forEach((theme) => {
const tokenJSON = JSON.stringify(themeTokens(theme), null, 2);
fs.writeFileSync(`${themePath}/${theme.name}.json`, tokenJSON);
console.log(`- Theme: ${theme.name}.json created`);
combinedTokens[theme.name] = themeTokens(theme);
});
// Create combined tokens.json
const combinedPath = path.resolve(`${__dirname}/figma/tokens.json`);
const combinedJSON = JSON.stringify(combinedTokens, null, 2);
fs.writeFileSync(combinedPath, combinedJSON);
console.log(`- Combined: tokens.json created`);

View file

@ -3,14 +3,14 @@ import * as path from "path";
import app from "./styleTree/app"; import app from "./styleTree/app";
import dark from "./themes/dark"; import dark from "./themes/dark";
import light from "./themes/light"; import light from "./themes/light";
import decamelizeTree from "./utils/decamelizeTree"; import snakeCase from "./utils/snakeCase";
const themes = [dark, light]; const themes = [dark, light];
for (let theme of themes) { for (let theme of themes) {
let styleTree = decamelizeTree(app(theme)); let styleTree = snakeCase(app(theme));
let styleTreeJSON = JSON.stringify(styleTree, null, 2); let styleTreeJSON = JSON.stringify(styleTree, null, 2);
let outPath = path.resolve( let outPath = path.resolve(
`${__dirname}/../crates/zed/assets/themes/${theme.name}.json` `${__dirname}/../../crates/zed/assets/themes/${theme.name}.json`
); );
fs.writeFileSync(outPath, styleTreeJSON); fs.writeFileSync(outPath, styleTreeJSON);
console.log(`Generated ${outPath}`); console.log(`Generated ${outPath}`);

View file

@ -29,27 +29,27 @@
"type": "color" "type": "color"
}, },
"feature": { "feature": {
"value": "#2db4f3", "value": "#1096d3",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"ok": { "ok": {
"value": "#22c55e", "value": "#1b9447",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"error": { "error": {
"value": "#f78c8c", "value": "#f15656",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"warning": { "warning": {
"value": "#f8c570", "value": "#f7bb57",
"step": 300, "step": 300,
"type": "color" "type": "color"
}, },
"info": { "info": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
@ -81,27 +81,27 @@
"type": "color" "type": "color"
}, },
"feature": { "feature": {
"value": "#2db4f3", "value": "#1096d3",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"ok": { "ok": {
"value": "#22c55e", "value": "#1b9447",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"error": { "error": {
"value": "#f47171", "value": "#eb2d2d",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"warning": { "warning": {
"value": "#f7b241", "value": "#f6a724",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"info": { "info": {
"value": "#4287f6", "value": "#135acd",
"step": 600, "step": 600,
"type": "color" "type": "color"
} }
@ -175,88 +175,88 @@
}, },
"ok": { "ok": {
"base": { "base": {
"value": "#22c55e", "value": "#1b9447",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#22c55e", "value": "#1b9447",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#22c55e", "value": "#1b9447",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#22c55e", "value": "#1b9447",
"step": 600, "step": 600,
"type": "color" "type": "color"
} }
}, },
"error": { "error": {
"base": { "base": {
"value": "#f78c8c", "value": "#f15656",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#f78c8c", "value": "#f15656",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#f78c8c", "value": "#f15656",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#f78c8c", "value": "#f15656",
"step": 400, "step": 400,
"type": "color" "type": "color"
} }
}, },
"warning": { "warning": {
"base": { "base": {
"value": "#f8c570", "value": "#f7bb57",
"step": 300, "step": 300,
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#f8c570", "value": "#f7bb57",
"step": 300, "step": 300,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#f8c570", "value": "#f7bb57",
"step": 300, "step": 300,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#f8c570", "value": "#f7bb57",
"step": 300, "step": 300,
"type": "color" "type": "color"
} }
}, },
"info": { "info": {
"base": { "base": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
@ -289,22 +289,22 @@
"type": "color" "type": "color"
}, },
"ok": { "ok": {
"value": "#23d464", "value": "#20b456",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"error": { "error": {
"value": "#f47171", "value": "#eb2d2d",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"warning": { "warning": {
"value": "#f59f0c", "value": "#de900c",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"info": { "info": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
@ -337,35 +337,35 @@
"type": "color" "type": "color"
}, },
"inserted": { "inserted": {
"value": "#22c55e", "value": "#1b9447",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"deleted": { "deleted": {
"value": "#f78c8c", "value": "#f15656",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"modified": { "modified": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"highlight": { "highlight": {
"selection": { "selection": {
"value": "#d0e2fd", "value": "#103063",
"step": 100, "step": 800,
"type": "color" "type": "color"
}, },
"occurrence": { "occurrence": {
"value": "#777af4", "value": "#2b2b2b",
"step": 500, "step": 750,
"type": "color" "type": "color"
}, },
"activeOccurrence": { "activeOccurrence": {
"value": "#8f90f6", "value": "#393939",
"step": 400, "step": 700,
"type": "color" "type": "color"
}, },
"matchingBracket": { "matchingBracket": {
@ -374,13 +374,13 @@
"type": "color" "type": "color"
}, },
"match": { "match": {
"value": "#87d116", "value": "#0a2633",
"step": 500, "step": 900,
"type": "color" "type": "color"
}, },
"activeMatch": { "activeMatch": {
"value": "#90df17", "value": "#0e4158",
"step": 400, "step": 800,
"type": "color" "type": "color"
}, },
"related": { "related": {
@ -404,227 +404,227 @@
}, },
"syntax": { "syntax": {
"primary": { "primary": {
"value": "#f1f1f1", "value": "#d5d5d5",
"type": "color" "type": "color"
}, },
"comment": { "comment": {
"value": "#bdf36b", "value": "#aaaaaa",
"type": "color" "type": "color"
}, },
"keyword": { "keyword": {
"value": "#59c3f5", "value": "#4f8ff7",
"type": "color" "type": "color"
}, },
"function": { "function": {
"value": "#fadc89", "value": "#f9da82",
"type": "color" "type": "color"
}, },
"type": { "type": {
"value": "#26ebd5", "value": "#3eeeda",
"type": "color" "type": "color"
}, },
"variant": { "variant": {
"value": "#26ebd5", "value": "#53c1f5",
"type": "color" "type": "color"
}, },
"property": { "property": {
"value": "#81d2f8", "value": "#4f8ff7",
"type": "color" "type": "color"
}, },
"enum": { "enum": {
"value": "#59c3f5", "value": "#ee670a",
"type": "color" "type": "color"
}, },
"operator": { "operator": {
"value": "#59c3f5", "value": "#ee670a",
"type": "color" "type": "color"
}, },
"string": { "string": {
"value": "#fab78b", "value": "#f99d5f",
"type": "color" "type": "color"
}, },
"number": { "number": {
"value": "#d5d5d5", "value": "#aeef4b",
"type": "color" "type": "color"
}, },
"boolean": { "boolean": {
"value": "#d5d5d5", "value": "#aeef4b",
"type": "color" "type": "color"
} }
}, },
"player": { "player": {
"1": { "1": {
"baseColor": { "baseColor": {
"value": "#4287f6", "value": "#2472f2",
"step": 600, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#4287f6", "value": "#2472f2",
"step": 600, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#d0e2fd", "value": "#103063",
"step": 100, "step": 800,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#4287f6", "value": "#103063",
"step": 600, "step": 800,
"type": "color" "type": "color"
} }
}, },
"2": { "2": {
"baseColor": { "baseColor": {
"value": "#87d116", "value": "#79ba16",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#87d116", "value": "#79ba16",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#dbf9ac", "value": "#38530f",
"step": 100, "step": 800,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#87d116", "value": "#79ba16",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"3": { "3": {
"baseColor": { "baseColor": {
"value": "#777af4", "value": "#484bed",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#777af4", "value": "#484bed",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#d4d5fd", "value": "#121269",
"step": 100, "step": 800,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#777af4", "value": "#484bed",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"4": { "4": {
"baseColor": { "baseColor": {
"value": "#f98a3d", "value": "#ee670a",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#f98a3d", "value": "#ee670a",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#fde0cd", "value": "#5d2f0e",
"step": 100, "step": 800,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#f98a3d", "value": "#ee670a",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"5": { "5": {
"baseColor": { "baseColor": {
"value": "#b671f8", "value": "#993bf3",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#b671f8", "value": "#993bf3",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#e9d4fd", "value": "#3e1169",
"step": 100, "step": 800,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#b671f8", "value": "#993bf3",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"6": { "6": {
"baseColor": { "baseColor": {
"value": "#16ddc7", "value": "#16d6c1",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#16ddc7", "value": "#16d6c1",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#b4faf2", "value": "#0e4f48",
"step": 100, "step": 800,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#16ddc7", "value": "#16d6c1",
"step": 400, "step": 400,
"type": "color" "type": "color"
} }
}, },
"7": { "7": {
"baseColor": { "baseColor": {
"value": "#f58ac0", "value": "#ef59a3",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#f58ac0", "value": "#ef59a3",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#fcd4e8", "value": "#fbc6e1",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#f58ac0", "value": "#ef59a3",
"step": 400, "step": 400,
"type": "color" "type": "color"
} }
}, },
"8": { "8": {
"baseColor": { "baseColor": {
"value": "#f6bc09", "value": "#f7bf17",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#f6bc09", "value": "#f7bf17",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#fceabc", "value": "#fce9b7",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#f6bc09", "value": "#f7bf17",
"step": 400, "step": 400,
"type": "color" "type": "color"
} }

View file

@ -29,27 +29,27 @@
"type": "color" "type": "color"
}, },
"feature": { "feature": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"ok": { "ok": {
"value": "#23d464", "value": "#20b456",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"error": { "error": {
"value": "#f47171", "value": "#eb2d2d",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"warning": { "warning": {
"value": "#e5af09", "value": "#d3a20b",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"info": { "info": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
@ -81,27 +81,27 @@
"type": "color" "type": "color"
}, },
"feature": { "feature": {
"value": "#0ea5e8", "value": "#1179a8",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"ok": { "ok": {
"value": "#22c55e", "value": "#1b9447",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"error": { "error": {
"value": "#f15252", "value": "#c91818",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"warning": { "warning": {
"value": "#f6bc09", "value": "#f7bf17",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"info": { "info": {
"value": "#4287f6", "value": "#135acd",
"step": 600, "step": 600,
"type": "color" "type": "color"
} }
@ -158,105 +158,105 @@
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#f1f1f1", "value": "#f8f8f8",
"step": 50, "step": 25,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#e3e3e3", "value": "#f1f1f1",
"step": 100, "step": 50,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#f1f1f1", "value": "#eaeaea",
"step": 50, "step": 75,
"type": "color" "type": "color"
} }
}, },
"ok": { "ok": {
"base": { "base": {
"value": "#befad2", "value": "#b7f9ce",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#befad2", "value": "#b7f9ce",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#befad2", "value": "#b7f9ce",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#befad2", "value": "#b7f9ce",
"step": 100, "step": 100,
"type": "color" "type": "color"
} }
}, },
"error": { "error": {
"base": { "base": {
"value": "#fdd4d4", "value": "#fcc6c6",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#fdd4d4", "value": "#fcc6c6",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#fdd4d4", "value": "#fcc6c6",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#fdd4d4", "value": "#fcc6c6",
"step": 100, "step": 100,
"type": "color" "type": "color"
} }
}, },
"warning": { "warning": {
"base": { "base": {
"value": "#fceabc", "value": "#fce9b7",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#fceabc", "value": "#fce9b7",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#fceabc", "value": "#fce9b7",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#fceabc", "value": "#fce9b7",
"step": 100, "step": 100,
"type": "color" "type": "color"
} }
}, },
"info": { "info": {
"base": { "base": {
"value": "#d0e2fd", "value": "#c5dafc",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"hovered": { "hovered": {
"value": "#d0e2fd", "value": "#c5dafc",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"active": { "active": {
"value": "#d0e2fd", "value": "#c5dafc",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"focused": { "focused": {
"value": "#d0e2fd", "value": "#c5dafc",
"step": 100, "step": 100,
"type": "color" "type": "color"
} }
@ -289,22 +289,22 @@
"type": "color" "type": "color"
}, },
"ok": { "ok": {
"value": "#8ff4b2", "value": "#84f2ab",
"step": 200, "step": 200,
"type": "color" "type": "color"
}, },
"error": { "error": {
"value": "#fbbdbd", "value": "#f9a0a0",
"step": 200, "step": 200,
"type": "color" "type": "color"
}, },
"warning": { "warning": {
"value": "#fadc89", "value": "#f9da82",
"step": 200, "step": 200,
"type": "color" "type": "color"
}, },
"info": { "info": {
"value": "#b4cffb", "value": "#9ec1fa",
"step": 200, "step": 200,
"type": "color" "type": "color"
} }
@ -327,40 +327,40 @@
}, },
"line": { "line": {
"active": { "active": {
"value": "#e3e3e3", "value": "#f1f1f1",
"step": 100, "step": 50,
"type": "color" "type": "color"
}, },
"highlighted": { "highlighted": {
"value": "#e3e3e3", "value": "#f1f1f1",
"step": 100, "step": 50,
"type": "color" "type": "color"
}, },
"inserted": { "inserted": {
"value": "#befad2", "value": "#b7f9ce",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"deleted": { "deleted": {
"value": "#fdd4d4", "value": "#fcc6c6",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"modified": { "modified": {
"value": "#d0e2fd", "value": "#c5dafc",
"step": 100, "step": 100,
"type": "color" "type": "color"
} }
}, },
"highlight": { "highlight": {
"selection": { "selection": {
"value": "#d0e2fd", "value": "#c5dafc",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"occurrence": { "occurrence": {
"value": "#e3e3e3", "value": "#f1f1f1",
"step": 100, "step": 50,
"type": "color" "type": "color"
}, },
"activeOccurrence": { "activeOccurrence": {
@ -391,8 +391,8 @@
}, },
"gutter": { "gutter": {
"primary": { "primary": {
"value": "#808080", "value": "#aaaaaa",
"step": 450, "step": 300,
"type": "color" "type": "color"
}, },
"active": { "active": {
@ -408,223 +408,223 @@
"type": "color" "type": "color"
}, },
"comment": { "comment": {
"value": "#bdf36b", "value": "#555555",
"type": "color" "type": "color"
}, },
"keyword": { "keyword": {
"value": "#59c3f5", "value": "#103063",
"type": "color" "type": "color"
}, },
"function": { "function": {
"value": "#fadc89", "value": "#1b9447",
"type": "color" "type": "color"
}, },
"type": { "type": {
"value": "#26ebd5", "value": "#138a7d",
"type": "color" "type": "color"
}, },
"variant": { "variant": {
"value": "#26ebd5", "value": "#1179a8",
"type": "color" "type": "color"
}, },
"property": { "property": {
"value": "#81d2f8", "value": "#134697",
"type": "color" "type": "color"
}, },
"enum": { "enum": {
"value": "#59c3f5", "value": "#bb550e",
"type": "color" "type": "color"
}, },
"operator": { "operator": {
"value": "#59c3f5", "value": "#bb550e",
"type": "color" "type": "color"
}, },
"string": { "string": {
"value": "#fab78b", "value": "#bb550e",
"type": "color" "type": "color"
}, },
"number": { "number": {
"value": "#d5d5d5", "value": "#14a898",
"type": "color" "type": "color"
}, },
"boolean": { "boolean": {
"value": "#d5d5d5", "value": "#b0740f",
"type": "color" "type": "color"
} }
}, },
"player": { "player": {
"1": { "1": {
"baseColor": { "baseColor": {
"value": "#4287f6", "value": "#135acd",
"step": 600, "step": 600,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#d0e2fd", "value": "#c5dafc",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#6099f7", "value": "#2472f2",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"2": { "2": {
"baseColor": { "baseColor": {
"value": "#87d116", "value": "#79ba16",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#87d116", "value": "#79ba16",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#dbf9ac", "value": "#dffab5",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#87d116", "value": "#79ba16",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"3": { "3": {
"baseColor": { "baseColor": {
"value": "#777af4", "value": "#484bed",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#777af4", "value": "#484bed",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#d4d5fd", "value": "#cdcdfc",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#777af4", "value": "#484bed",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"4": { "4": {
"baseColor": { "baseColor": {
"value": "#f98a3d", "value": "#ee670a",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#f98a3d", "value": "#ee670a",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#fde0cd", "value": "#fcd6bd",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#f98a3d", "value": "#ee670a",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"5": { "5": {
"baseColor": { "baseColor": {
"value": "#b671f8", "value": "#993bf3",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#b671f8", "value": "#993bf3",
"step": 500, "step": 500,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#e9d4fd", "value": "#e4cbfc",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#b671f8", "value": "#993bf3",
"step": 500, "step": 500,
"type": "color" "type": "color"
} }
}, },
"6": { "6": {
"baseColor": { "baseColor": {
"value": "#16ddc7", "value": "#16d6c1",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#16ddc7", "value": "#16d6c1",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#b4faf2", "value": "#b1faf2",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#16ddc7", "value": "#16d6c1",
"step": 400, "step": 400,
"type": "color" "type": "color"
} }
}, },
"7": { "7": {
"baseColor": { "baseColor": {
"value": "#f58ac0", "value": "#ef59a3",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#f58ac0", "value": "#ef59a3",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#fcd4e8", "value": "#fbc6e1",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#f58ac0", "value": "#ef59a3",
"step": 400, "step": 400,
"type": "color" "type": "color"
} }
}, },
"8": { "8": {
"baseColor": { "baseColor": {
"value": "#f6bc09", "value": "#f7bf17",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"cursorColor": { "cursorColor": {
"value": "#f6bc09", "value": "#f7bf17",
"step": 400, "step": 400,
"type": "color" "type": "color"
}, },
"selectionColor": { "selectionColor": {
"value": "#fceabc", "value": "#fce9b7",
"step": 100, "step": 100,
"type": "color" "type": "color"
}, },
"borderColor": { "borderColor": {
"value": "#f6bc09", "value": "#f7bf17",
"step": 400, "step": 400,
"type": "color" "type": "color"
} }

File diff suppressed because it is too large Load diff

View file

@ -21,9 +21,7 @@ export default function app(theme: Theme): Object {
tabIconSpacing: 4, tabIconSpacing: 4,
tabIconWidth: 13, tabIconWidth: 13,
tabSummarySpacing: 10, tabSummarySpacing: 10,
emptyMessage: { emptyMessage: text(theme, "sans", "primary", { size: "lg" }),
...text(theme, "sans", "primary", { size: "lg" }),
},
statusBarItem: { statusBarItem: {
...text(theme, "sans", "muted"), ...text(theme, "sans", "muted"),
margin: { margin: {

View 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,
},
},
};
}

View file

@ -0,0 +1,96 @@
import chroma from "chroma-js";
import Theme, { BackgroundColor } from "../themes/theme";
import { fontFamilies, fontSizes, FontFamily, FontWeight, FontSize } from "../tokens";
import { Color } from "../utils/color";
export type TextColor = keyof Theme["textColor"];
export interface Text {
family: FontFamily,
color: Color,
size: FontSize,
weight?: FontWeight,
underline?: boolean,
}
export function text(
theme: Theme,
fontFamily: keyof typeof fontFamilies,
color: TextColor,
properties?: {
size?: keyof typeof fontSizes;
weight?: FontWeight;
underline?: boolean;
}
): Text {
let extraProperties = {
...properties,
size: fontSizes[properties.size || "sm"].value,
};
return {
family: fontFamilies[fontFamily].value,
color: theme.textColor[color].value,
...extraProperties,
};
}
export interface BorderOptions {
width?: number;
top?: boolean;
bottom?: boolean;
left?: boolean;
right?: boolean;
overlay?: boolean;
}
export function border(
theme: Theme,
color: keyof Theme["borderColor"],
options?: BorderOptions
) {
return {
color: borderColor(theme, color),
width: 1,
...options,
};
}
export function borderColor(theme: Theme, color: keyof Theme["borderColor"]) {
return theme.borderColor[color].value;
}
export function iconColor(theme: Theme, color: keyof Theme["iconColor"]) {
return theme.iconColor[color].value;
}
export interface Player {
selection: {
cursor: Color;
selection: Color;
};
}
export function player(
theme: Theme,
playerNumber: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
): Player {
return {
selection: {
cursor: theme.player[playerNumber].cursorColor.value,
selection: theme.player[playerNumber].selectionColor.value,
},
};
}
export function backgroundColor(
theme: Theme,
name: keyof Theme["backgroundColor"],
state?: keyof BackgroundColor
): 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],
};
}

View file

@ -46,7 +46,7 @@ export default function editor(theme: Theme) {
diffBackgroundDeleted: backgroundColor(theme, "error"), diffBackgroundDeleted: backgroundColor(theme, "error"),
diffBackgroundInserted: backgroundColor(theme, "ok"), diffBackgroundInserted: backgroundColor(theme, "ok"),
documentHighlightReadBackground: theme.editor.highlight.occurrence.value, documentHighlightReadBackground: theme.editor.highlight.occurrence.value,
documentHighlightWriteBackground: theme.editor.highlight.occurrence.value, documentHighlightWriteBackground: theme.editor.highlight.activeOccurrence.value,
errorColor: theme.textColor.error.value, errorColor: theme.textColor.error.value,
gutterBackground: backgroundColor(theme, 500), gutterBackground: backgroundColor(theme, 500),
gutterPaddingFactor: 3.5, gutterPaddingFactor: 3.5,
@ -129,7 +129,7 @@ export default function editor(theme: Theme) {
invalidInformationDiagnostic: diagnostic(theme, "muted"), invalidInformationDiagnostic: diagnostic(theme, "muted"),
invalidWarningDiagnostic: diagnostic(theme, "muted"), invalidWarningDiagnostic: diagnostic(theme, "muted"),
syntax: { syntax: {
keyword: theme.syntax.keyword.color.value, keyword: theme.syntax.keyword.color.value,
function: theme.syntax.function.color.value, function: theme.syntax.function.color.value,
string: theme.syntax.string.color.value, string: theme.syntax.string.color.value,
type: theme.syntax.type.color.value, type: theme.syntax.type.color.value,
@ -143,7 +143,7 @@ export default function editor(theme: Theme) {
"emphasis.strong": { color: theme.textColor.feature.value, weight: "bold" }, "emphasis.strong": { color: theme.textColor.feature.value, weight: "bold" },
link_uri: { color: theme.syntax.linkUrl.color.value, underline: true }, link_uri: { color: theme.syntax.linkUrl.color.value, underline: true },
link_text: { color: theme.syntax.linkText.color.value, italic: true }, link_text: { color: theme.syntax.linkText.color.value, italic: true },
list_marker: theme.syntax.listMarker.color.value, list_marker: theme.syntax.punctuation.color.value,
}, },
}; };
} }

View 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,
},
};
}

View 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, "primary"),
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,
},
};
}

View 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", "muted"),
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),
};
}

View file

@ -0,0 +1,151 @@
import Theme from "../themes/theme";
import { backgroundColor, border, iconColor, text } from "./components";
export default function workspace(theme: Theme) {
const signInPrompt = {
...text(theme, "sans", "secondary"),
size: 13,
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, "primary").color,
width: 1,
},
status_bar: {
height: 24,
itemSpacing: 8,
padding: {
left: 6,
right: 6,
},
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, "active"),
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, "mono", "active"),
size: 13,
},
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",
},
};
}

View file

@ -1,5 +1,6 @@
import { colors, fontWeights, NumberToken } from "../tokens"; import { Color, colors, fontWeights, NumberToken } from "../tokens";
import Theme, { Syntax } from "./theme"; import { withOpacity } from "../utils/color";
import Theme, { buildPlayer, Syntax } from "./theme";
const backgroundColor = { const backgroundColor = {
100: { 100: {
@ -87,57 +88,16 @@ const iconColor = {
}; };
const player = { const player = {
1: { 1: buildPlayer(colors.blue[500]),
baseColor: colors.blue[500], 2: buildPlayer(colors.lime[500]),
cursorColor: colors.blue[500], 3: buildPlayer(colors.indigo[500]),
selectionColor: colors.blue[800], 4: buildPlayer(colors.orange[500]),
borderColor: colors.blue[800], 5: buildPlayer(colors.purple[500]),
}, 6: buildPlayer(colors.teal[400]),
2: { 7: buildPlayer(colors.pink[400]),
baseColor: colors.lime[500], 8: buildPlayer(colors.yellow[400]),
cursorColor: colors.lime[500],
selectionColor: colors.lime[800],
borderColor: colors.lime[500],
},
3: {
baseColor: colors.indigo[500],
cursorColor: colors.indigo[500],
selectionColor: colors.indigo[800],
borderColor: colors.indigo[500],
},
4: {
baseColor: colors.orange[500],
cursorColor: colors.orange[500],
selectionColor: colors.orange[800],
borderColor: colors.orange[500],
},
5: {
baseColor: colors.purple[500],
cursorColor: colors.purple[500],
selectionColor: colors.purple[800],
borderColor: colors.purple[500],
},
6: {
baseColor: colors.teal[400],
cursorColor: colors.teal[400],
selectionColor: colors.teal[800],
borderColor: colors.teal[400],
},
7: {
baseColor: colors.pink[400],
cursorColor: colors.pink[400],
selectionColor: colors.pink[100],
borderColor: colors.pink[400],
},
8: {
baseColor: colors.yellow[400],
cursorColor: colors.yellow[400],
selectionColor: colors.yellow[100],
borderColor: colors.yellow[400],
},
}; };
// TODO: Fixup
const editor = { const editor = {
background: backgroundColor[500].base, background: backgroundColor[500].base,
indent_guide: borderColor.muted, indent_guide: borderColor.muted,
@ -151,11 +111,11 @@ const editor = {
}, },
highlight: { highlight: {
selection: player[1].selectionColor, selection: player[1].selectionColor,
occurrence: colors.neutral[750], occurrence: withOpacity(colors.teal[500], 0.16),
activeOccurrence: colors.neutral[700], activeOccurrence: withOpacity(colors.teal[500], 0.32),
matchingBracket: backgroundColor[500].active, matchingBracket: backgroundColor[500].active,
match: colors.sky[900], match: withOpacity(colors.sky[500], 0.16),
activeMatch: colors.sky[800], activeMatch: withOpacity(colors.sky[800], 0.32),
related: backgroundColor[500].focused, related: backgroundColor[500].focused,
}, },
gutter: { gutter: {
@ -247,10 +207,6 @@ const syntax: Syntax = {
weight: fontWeights.normal, weight: fontWeights.normal,
// TODO: add italic // TODO: add italic
}, },
listMarker: {
color: colors.sky[400],
weight: fontWeights.normal,
}
}; };
const shadowAlpha: NumberToken = { const shadowAlpha: NumberToken = {

228
styles/src/themes/light.ts Normal file
View file

@ -0,0 +1,228 @@
import { colors, fontWeights, NumberToken } from "../tokens";
import { withOpacity } from "../utils/color";
import Theme, { buildPlayer, Syntax } from "./theme";
const backgroundColor = {
100: {
base: colors.neutral[100],
hovered: colors.neutral[150],
active: colors.neutral[200],
focused: colors.neutral[150],
},
300: {
base: colors.neutral[50],
hovered: colors.neutral[100],
active: colors.neutral[150],
focused: colors.neutral[100],
},
500: {
base: colors.neutral[0],
hovered: colors.neutral[25],
active: colors.neutral[50],
focused: colors.neutral[75],
},
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[200],
secondary: colors.neutral[100],
muted: colors.neutral[50],
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[600],
muted: colors.neutral[450],
placeholder: colors.neutral[300],
active: colors.neutral[900],
feature: colors.blue[500],
ok: colors.green[500],
error: colors.red[500],
warning: colors.yellow[500],
info: colors.blue[500],
};
const iconColor = {
primary: colors.neutral[300],
secondary: colors.neutral[500],
muted: colors.neutral[600],
placeholder: colors.neutral[700],
active: colors.neutral[900],
feature: colors.sky[600],
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.lime[500]),
3: buildPlayer(colors.indigo[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]),
};
// TODO: Fixup
const editor = {
background: backgroundColor[500].base,
indent_guide: borderColor.muted,
indent_guide_active: borderColor.secondary,
line: {
active: backgroundColor[500].active,
highlighted: backgroundColor[500].active,
inserted: backgroundColor.ok.active,
deleted: backgroundColor.error.active,
modified: backgroundColor.info.active,
},
highlight: {
selection: player[1].selectionColor,
occurrence: withOpacity(colors.teal[500], 0.16),
activeOccurrence: withOpacity(colors.teal[500], 0.32),
matchingBracket: colors.neutral[0],
match: withOpacity(colors.sky[500], 0.16),
activeMatch: withOpacity(colors.sky[800], 0.32),
related: colors.neutral[0],
},
gutter: {
primary: colors.neutral[300],
active: textColor.active,
},
};
const syntax: Syntax = {
primary: {
color: colors.neutral[750],
weight: fontWeights.normal,
},
comment: {
color: colors.neutral[600],
weight: fontWeights.normal,
},
punctuation: {
color: colors.neutral[700],
weight: fontWeights.normal,
},
constant: {
color: colors.neutral[700],
weight: fontWeights.normal,
},
keyword: {
color: colors.blue[800],
weight: fontWeights.normal,
},
function: {
color: colors.green[600],
weight: fontWeights.normal,
},
type: {
color: colors.teal[600],
weight: fontWeights.normal,
},
variant: {
color: colors.sky[600],
weight: fontWeights.normal,
},
property: {
color: colors.blue[700],
weight: fontWeights.normal,
},
enum: {
color: colors.orange[600],
weight: fontWeights.normal,
},
operator: {
color: colors.orange[600],
weight: fontWeights.normal,
},
string: {
color: colors.orange[600],
weight: fontWeights.normal,
},
number: {
color: colors.teal[500],
weight: fontWeights.normal,
},
boolean: {
color: colors.amber[600],
weight: fontWeights.normal,
},
predictive: {
color: textColor.muted,
weight: fontWeights.normal,
},
title: {
color: colors.sky[500],
weight: fontWeights.bold,
},
emphasis: {
color: textColor.active,
weight: fontWeights.normal,
},
emphasisStrong: {
color: textColor.active,
weight: fontWeights.bold,
},
linkUrl: {
color: colors.teal[500],
weight: fontWeights.normal,
// TODO: add underline
},
linkText: {
color: colors.orange[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;

View file

@ -1,4 +1,5 @@
import { ColorToken, FontWeightToken, NumberToken } from "../tokens"; import { ColorToken, FontWeightToken, NumberToken } from "../tokens";
import { Color, withOpacity } from "../utils/color";
export interface SyntaxHighlightStyle { export interface SyntaxHighlightStyle {
color: ColorToken; color: ColorToken;
@ -11,6 +12,19 @@ export interface Player {
selectionColor: ColorToken; selectionColor: ColorToken;
borderColor: 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.1),
borderColor: withOpacity(color, borderOpacity || 0.8),
}
}
export interface BackgroundColor { export interface BackgroundColor {
base: ColorToken; base: ColorToken;

52
styles/src/utils/color.ts Normal file
View 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()
};
}

View 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;
}
}

View file

@ -1,108 +0,0 @@
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,
},
},
};
}

View file

@ -1,91 +0,0 @@
import chroma from "chroma-js";
import Theme, { BackgroundColor } from "../themes/theme";
import { fontFamilies, fontSizes, FontWeight } from "../tokens";
import { Color } from "../utils/color";
export type TextColor = keyof Theme["textColor"];
export function text(
theme: Theme,
fontFamily: keyof typeof fontFamilies,
color: TextColor,
properties?: {
size?: keyof typeof fontSizes;
weight?: FontWeight;
underline?: boolean;
}
) {
const sizeKey = properties?.size || fontFamily === "sans" ? "sm" : "md";
const size = fontSizes[sizeKey].value;
return {
family: fontFamilies[fontFamily].value,
color: theme.textColor[color].value,
...properties,
size,
};
}
export interface BorderOptions {
width?: number;
top?: boolean;
bottom?: boolean;
left?: boolean;
right?: boolean;
overlay?: boolean;
}
export function border(
theme: Theme,
color: keyof Theme["borderColor"],
options?: BorderOptions
) {
return {
color: borderColor(theme, color),
width: 1,
...options,
};
}
export function borderColor(theme: Theme, color: keyof Theme["borderColor"]) {
return theme.borderColor[color].value;
}
export function iconColor(theme: Theme, color: keyof Theme["iconColor"]) {
return theme.iconColor[color].value;
}
export interface Player {
selection: {
cursor: Color;
selection: Color;
};
}
export function player(
theme: Theme,
playerNumber: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
): Player {
return {
selection: {
cursor: theme.player[playerNumber].cursorColor.value,
selection: theme.player[playerNumber].selectionColor.value,
},
};
}
export function backgroundColor(
theme: Theme,
name: keyof Theme["backgroundColor"],
state?: keyof BackgroundColor
): 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],
};
}

View file

@ -1,37 +0,0 @@
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,
},
};
}

View file

@ -1,79 +0,0 @@
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, "primary"),
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,
},
};
}

View file

@ -1,59 +0,0 @@
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", "muted"),
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),
};
}

View file

@ -1,151 +0,0 @@
import Theme from "../themes/theme";
import { backgroundColor, border, iconColor, text } from "./components";
export default function workspace(theme: Theme) {
const signInPrompt = {
...text(theme, "sans", "secondary"),
size: 13,
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, "primary").color,
width: 1,
},
status_bar: {
height: 24,
itemSpacing: 8,
padding: {
left: 6,
right: 6,
},
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, "active"),
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, "mono", "active"),
size: 13,
},
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",
},
};
}

View file

@ -1,273 +0,0 @@
import { colors, fontWeights, NumberToken } from "../tokens";
import Theme, { Syntax } from "./theme";
// TODO: Replace with light values
const backgroundColor = {
100: {
base: colors.neutral[100],
hovered: colors.neutral[150],
active: colors.neutral[200],
focused: colors.neutral[150],
},
300: {
base: colors.neutral[50],
hovered: colors.neutral[100],
active: colors.neutral[150],
focused: colors.neutral[100],
},
500: {
base: colors.neutral[0],
hovered: colors.neutral[25],
active: colors.neutral[50],
focused: colors.neutral[75],
},
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[200],
secondary: colors.neutral[100],
muted: colors.neutral[50],
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[600],
muted: colors.neutral[450],
placeholder: colors.neutral[300],
active: colors.neutral[900],
feature: colors.blue[500],
ok: colors.green[500],
error: colors.red[500],
warning: colors.yellow[500],
info: colors.blue[500],
};
const iconColor = {
primary: colors.neutral[300],
secondary: colors.neutral[500],
muted: colors.neutral[600],
placeholder: colors.neutral[700],
active: colors.neutral[900],
feature: colors.sky[600],
ok: colors.green[600],
error: colors.red[600],
warning: colors.yellow[400],
info: colors.blue[600],
};
const player = {
1: {
baseColor: colors.blue[600],
cursorColor: colors.blue[500],
selectionColor: colors.blue[100],
borderColor: colors.blue[500],
},
2: {
baseColor: colors.lime[500],
cursorColor: colors.lime[500],
selectionColor: colors.lime[100],
borderColor: colors.lime[500],
},
3: {
baseColor: colors.indigo[500],
cursorColor: colors.indigo[500],
selectionColor: colors.indigo[100],
borderColor: colors.indigo[500],
},
4: {
baseColor: colors.orange[500],
cursorColor: colors.orange[500],
selectionColor: colors.orange[100],
borderColor: colors.orange[500],
},
5: {
baseColor: colors.purple[500],
cursorColor: colors.purple[500],
selectionColor: colors.purple[100],
borderColor: colors.purple[500],
},
6: {
baseColor: colors.teal[400],
cursorColor: colors.teal[400],
selectionColor: colors.teal[100],
borderColor: colors.teal[400],
},
7: {
baseColor: colors.pink[400],
cursorColor: colors.pink[400],
selectionColor: colors.pink[100],
borderColor: colors.pink[400],
},
8: {
baseColor: colors.yellow[400],
cursorColor: colors.yellow[400],
selectionColor: colors.yellow[100],
borderColor: colors.yellow[400],
},
};
// TODO: Fixup
const editor = {
background: backgroundColor[500].base,
indent_guide: borderColor.muted,
indent_guide_active: borderColor.secondary,
line: {
active: backgroundColor[500].active,
highlighted: backgroundColor[500].active,
inserted: backgroundColor.ok.active,
deleted: backgroundColor.error.active,
modified: backgroundColor.info.active,
},
highlight: {
selection: player[1].selectionColor,
occurrence: backgroundColor[500].active,
activeOccurrence: colors.neutral[0],
matchingBracket: colors.neutral[0],
match: colors.neutral[0],
activeMatch: colors.neutral[0],
related: colors.neutral[0],
},
gutter: {
primary: colors.neutral[300],
active: textColor.active,
},
};
const syntax: Syntax = {
primary: {
color: colors.neutral[750],
weight: fontWeights.normal,
},
comment: {
color: colors.neutral[600],
weight: fontWeights.normal,
},
punctuation: {
color: colors.neutral[700],
weight: fontWeights.normal,
},
constant: {
color: colors.neutral[700],
weight: fontWeights.normal,
},
keyword: {
color: colors.blue[800],
weight: fontWeights.normal,
},
function: {
color: colors.green[600],
weight: fontWeights.normal,
},
type: {
color: colors.teal[600],
weight: fontWeights.normal,
},
variant: {
color: colors.sky[600],
weight: fontWeights.normal,
},
property: {
color: colors.blue[700],
weight: fontWeights.normal,
},
enum: {
color: colors.orange[600],
weight: fontWeights.normal,
},
operator: {
color: colors.orange[600],
weight: fontWeights.normal,
},
string: {
color: colors.orange[600],
weight: fontWeights.normal,
},
number: {
color: colors.teal[500],
weight: fontWeights.normal,
},
boolean: {
color: colors.amber[600],
weight: fontWeights.normal,
},
predictive: {
color: textColor.muted,
weight: fontWeights.normal,
},
title: {
color: colors.sky[500],
weight: fontWeights.bold,
},
emphasis: {
color: textColor.active,
weight: fontWeights.normal,
},
emphasisStrong: {
color: textColor.active,
weight: fontWeights.bold,
},
linkUrl: {
color: colors.teal[500],
weight: fontWeights.normal,
// TODO: add underline
},
linkText: {
color: colors.orange[500],
weight: fontWeights.normal,
// TODO: add italic
},
listMarker: {
color: colors.sky[400],
weight: fontWeights.normal,
},
};
const shadowAlpha: NumberToken = {
value: 0.12,
type: "number",
};
const theme: Theme = {
name: "light",
backgroundColor,
borderColor,
textColor,
iconColor,
editor,
syntax,
player,
shadowAlpha,
};
export default theme;

View file

@ -1,44 +0,0 @@
import chroma, { Scale } from "chroma-js";
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;
}

View file

@ -1,21 +0,0 @@
import { snakeCase } from "case-anything";
export default function decamelizeTree(object: { [key: string]: any }) {
const snakeObject: { [key: string]: any } = {};
for (const key in object) {
snakeObject[snakeCase(key)] = decamelizeValue(object[key]);
}
return snakeObject;
}
function decamelizeValue(value: any): any {
if (typeof value === "object") {
if (Array.isArray(value)) {
return value.map(decamelizeValue);
} else {
return decamelizeTree(value);
}
} else {
return value;
}
}