Start on TypeScript-based styling system

Co-Authored-By: Nate Butler <1714999+iamnbutler@users.noreply.github.com>
This commit is contained in:
Nathan Sobo 2022-03-29 13:08:00 -06:00
parent cc9843c90e
commit 1615c6150a
8 changed files with 955 additions and 0 deletions

1
.gitignore vendored
View file

@ -2,6 +2,7 @@
/zed.xcworkspace
.DS_Store
/script/node_modules
/styles/node_modules
/crates/server/.env.toml
/crates/server/static/styles.css
/vendor/bin

632
styles/app.ts Normal file
View file

@ -0,0 +1,632 @@
import { selectorModal } from "./selector-modal";
import Theme from "./theme";
export default function app(theme: Theme): Object {
return {
selector: selectorModal(theme),
workspace: {
background: "$surface.500",
leaderBorderOpacity: 0.7,
leader_border_width: 2.0,
active_tab: {
background: "$surface.300",
extends: "$workspace.tab",
text: "$text.primary",
border: {
bottom: false,
},
},
left_sidebar: {
extends: "$workspace.sidebar",
border: {
color: "$border.primary",
right: true,
width: 1,
},
},
pane_divider: {
color: "$border.primary",
width: 1,
},
right_sidebar: {
extends: "$workspace.sidebar",
border: {
color: "$border.primary",
left: true,
width: 1,
},
},
sidebar: {
width: 30,
active_item: {
extends: "$workspace.sidebar.item",
icon_color: "$text.primary.color",
},
border: {
color: "$border.primary",
right: true,
width: 1,
},
item: {
height: "$workspace.tab.height",
icon_color: "$text.muted.color",
icon_size: 18,
},
resize_handle: {
background: "$border.primary",
padding: {
left: 1,
},
},
},
status_bar: {
cursor_position: "$text.muted",
diagnostic_message: "$text.muted",
height: 24,
item_spacing: 8,
lsp_message: "$text.muted",
padding: {
left: 6,
right: 6,
},
},
tab: {
height: 34,
icon_close: "$text.muted.color",
icon_close_active: "$text.primary.color",
icon_conflict: "$status.warn",
icon_dirty: "$status.info",
icon_width: 8,
spacing: 10,
text: "$text.muted",
border: {
bottom: true,
color: "$border.primary",
left: true,
overlay: true,
width: 1,
},
padding: {
left: 12,
right: 12,
},
},
titlebar: {
avatar_width: 18,
height: 32,
share_icon_active_color: "$text.primary.color",
share_icon_color: "$text.muted.color",
title: "$text.primary",
avatar: {
corner_radius: 10,
border: {
color: "#00000088",
width: 1,
},
},
avatar_ribbon: {
background: "#ff0000",
height: 3,
width: 12,
},
border: {
bottom: true,
color: "$border.primary",
width: 1,
},
hovered_sign_in_prompt: {
color: "$text.secondary.color",
extends: "$workspace.titlebar.sign_in_prompt",
},
offline_icon: {
color: "$text.muted.color",
width: 16,
padding: {
right: 4,
},
},
outdated_warning: {
extends: "$text.muted",
size: 13,
},
sign_in_prompt: {
extends: "$text.muted",
size: 13,
underline: true,
padding: {
right: 8,
},
},
},
toolbar: {
height: 44,
},
},
chat_panel: {
extends: "$panel",
channel_name: {
extends: "$text.primary",
weight: "bold",
},
channel_name_hash: {
text: "$text.muted",
padding: {
right: 8,
},
},
channel_select: {
active_item: {
extends: "$chat_panel.channel_select.item",
name: "$text.primary",
},
header: {
extends: "$chat_panel.channel_select.active_item",
padding: {
bottom: 4,
left: 0,
},
},
hovered_active_item: {
extends: "$chat_panel.channel_select.hovered_item",
name: "$text.primary",
},
hovered_item: {
background: "$state.hover",
corner_radius: 6,
extends: "$chat_panel.channel_select.item",
},
item: {
name: "$text.secondary",
padding: 4,
hash: {
extends: "$text.muted",
margin: {
right: 8,
},
},
},
menu: {
background: "$surface.500",
corner_radius: 6,
padding: 4,
border: {
color: "$border.primary",
width: 1,
},
shadow: {
blur: 16,
color: "$shadow.0",
offset: [0, 2],
},
},
},
hovered_sign_in_prompt: {
color: "$text.secondary.color",
extends: "$chat_panel.sign_in_prompt",
},
input_editor: {
background: "$surface.300",
corner_radius: 6,
placeholder_text: "$text.muted",
selection: "$selection.host",
text: "$text.primary",
border: {
color: "$border.primary",
width: 1,
},
padding: {
bottom: 7,
left: 8,
right: 8,
top: 7,
},
},
message: {
body: "$text.secondary",
timestamp: "$text.muted",
padding: {
bottom: 6,
},
sender: {
extends: "$text.primary",
weight: "bold",
margin: {
right: 8,
},
},
},
pending_message: {
extends: "$chat_panel.message",
body: {
color: "$text.muted.color",
},
sender: {
color: "$text.muted.color",
},
timestamp: {
color: "$text.muted.color",
},
},
sign_in_prompt: {
extends: "$text.primary",
underline: true,
},
},
contacts_panel: {
extends: "$panel",
host_row_height: 28,
tree_branch_color: "$surface.100",
tree_branch_width: 1,
host_avatar: {
corner_radius: 10,
width: 18,
},
host_username: {
extends: "$text.primary",
padding: {
left: 8,
},
},
hovered_shared_project: {
background: "$state.hover",
corner_radius: 6,
extends: "$contacts_panel.shared_project",
},
hovered_unshared_project: {
background: "$state.hover",
corner_radius: 6,
extends: "$contacts_panel.unshared_project",
},
project: {
guest_avatar_spacing: 4,
height: 24,
guest_avatar: {
corner_radius: 8,
width: 14,
},
name: {
extends: "$text.secondary",
margin: {
right: 6,
},
},
padding: {
left: 8,
},
},
shared_project: {
extends: "$contacts_panel.project",
name: {
color: "$text.primary.color",
},
},
unshared_project: {
extends: "$contacts_panel.project",
},
},
editor: {
active_line_background: "$state.active_line",
background: "$surface.300",
code_actions_indicator: "$text.muted.color",
diff_background_deleted: "$state.deleted_line",
diff_background_inserted: "$state.inserted_line",
document_highlight_read_background: "#99999920",
document_highlight_write_background: "#99999916",
error_color: "$status.bad",
guest_selections: "$selection.guests",
gutter_background: "$surface.300",
gutter_padding_factor: 2.5,
highlighted_line_background: "$state.highlighted_line",
line_number: "$text.muted.color",
line_number_active: "$text.primary.color",
rename_fade: 0.6,
selection: "$selection.host",
text_color: "$text.secondary.color",
unnecessary_code_fade: 0.5,
autocomplete: {
background: "$surface.100",
corner_radius: 6,
padding: 6,
border: {
color: "$border.secondary",
width: 2,
},
hovered_item: {
background: "$state.hover",
extends: "$editor.autocomplete.item",
},
item: {
corner_radius: 6,
padding: {
bottom: 2,
left: 6,
right: 6,
top: 2,
},
},
margin: {
left: -14,
},
match_highlight: {
color: "$editor.syntax.keyword.color",
weight: "$editor.syntax.keyword.weight",
},
selected_item: {
background: "$state.selected",
extends: "$editor.autocomplete.item",
},
},
diagnostic_header: {
background: "$editor.background",
icon_width_factor: 1.5,
text_scale_factor: 0.857,
border: {
bottom: true,
color: "$border.secondary",
top: true,
width: 1,
},
code: {
extends: "$text.muted",
size: 14,
margin: {
left: 10,
},
},
message: {
highlight_text: {
extends: "$text.primary",
size: 14,
weight: "bold",
},
text: {
extends: "$text.secondary",
size: 14,
},
},
},
diagnostic_path_header: {
background: "$state.active_line",
text_scale_factor: 0.857,
filename: {
extends: "$text.primary",
size: 14,
},
path: {
extends: "$text.muted",
size: 14,
margin: {
left: 12,
},
},
},
error_diagnostic: {
text_scale_factor: 0.857,
header: {
border: {
color: "$border.primary",
top: true,
width: 1,
},
},
message: {
highlight_text: {
color: "$status.bad",
extends: "$text.secondary",
size: 14,
weight: "bold",
},
text: {
color: "$status.bad",
extends: "$text.secondary",
size: 14,
},
},
},
hint_diagnostic: {
extends: "$editor.error_diagnostic",
message: {
highlight_text: {
color: "$status.info",
},
text: {
color: "$status.info",
},
},
},
information_diagnostic: {
extends: "$editor.error_diagnostic",
message: {
highlight_text: {
color: "$status.info",
},
text: {
color: "$status.info",
},
},
},
invalid_error_diagnostic: {
extends: "$editor.error_diagnostic",
message: {
highlight_text: {
color: "$text.muted.color",
},
text: {
color: "$text.muted.color",
},
},
},
invalid_hint_diagnostic: {
extends: "$editor.hint_diagnostic",
message: {
highlight_text: {
color: "$text.muted.color",
},
text: {
color: "$text.muted.color",
},
},
},
invalid_information_diagnostic: {
extends: "$editor.information_diagnostic",
message: {
highlight_text: {
color: "$text.muted.color",
},
text: {
color: "$text.muted.color",
},
},
},
invalid_warning_diagnostic: {
extends: "$editor.warning_diagnostic",
message: {
highlight_text: {
color: "$text.muted.color",
},
text: {
color: "$text.muted.color",
},
},
},
warning_diagnostic: {
extends: "$editor.error_diagnostic",
message: {
highlight_text: {
color: "$status.warn",
},
text: {
color: "$status.warn",
},
},
},
},
project_diagnostics: {
background: "$surface.300",
tab_icon_spacing: 4,
tab_icon_width: 13,
tab_summary_spacing: 10,
empty_message: {
extends: "$text.primary",
size: 18,
},
status_bar_item: {
extends: "$text.muted",
margin: {
right: 10,
},
},
},
project_panel: {
extends: "$panel",
entry: {
height: 22,
icon_color: "$text.muted.color",
icon_size: 8,
icon_spacing: 8,
text: "$text.secondary",
},
hovered_entry: {
background: "$state.hover",
extends: "$project_panel.entry",
},
hovered_selected_entry: {
extends: "$project_panel.hovered_entry",
text: {
extends: "$text.primary",
},
},
padding: {
top: 6,
},
selected_entry: {
extends: "$project_panel.entry",
text: {
extends: "$text.primary",
},
},
},
search: {
background: "$surface.300",
match_background: "$state.highlighted_line",
tab_icon_spacing: 4,
tab_icon_width: 14,
active_hovered_option_button: {
background: "$surface.100",
extends: "$search.option_button",
},
active_option_button: {
background: "$surface.100",
extends: "$search.option_button",
},
editor: {
background: "$surface.500",
corner_radius: 6,
max_width: 400,
placeholder_text: "$text.muted",
selection: "$selection.host",
text: "$text.primary",
border: {
color: "$border.primary",
width: 1,
},
margin: {
bottom: 5,
left: 5,
right: 5,
top: 5,
},
padding: {
bottom: 3,
left: 13,
right: 13,
top: 3,
},
},
hovered_option_button: {
background: "$surface.100",
extends: "$search.option_button",
},
invalid_editor: {
extends: "$search.editor",
border: {
color: "$status.bad",
width: 1,
},
},
match_index: {
extends: "$text.secondary",
padding: 6,
},
option_button: {
background: "$surface.300",
corner_radius: 6,
extends: "$text.secondary",
border: {
color: "$border.primary",
width: 1,
},
margin: {
left: 1,
right: 1,
},
padding: {
bottom: 1,
left: 6,
right: 6,
top: 1,
},
},
option_button_group: {
padding: {
left: 2,
right: 2,
},
},
results_status: {
extends: "$text.primary",
size: 18,
},
},
};
}

62
styles/components.ts Normal file
View file

@ -0,0 +1,62 @@
import chroma from "chroma-js";
import core, { Color } from "./core";
import Theme, { BackgroundColor, Weight } from "./theme";
export function text(
theme: Theme,
fontFamily: keyof typeof core.fontFamily,
color: keyof Theme["textColor"],
properties?: { size?: keyof typeof core["fontSize"]; weight?: Weight }
) {
const sizeKey = properties.size || fontFamily === "sans" ? "sm" : "md";
const size = core.fontSize[sizeKey].value;
return {
family: core.fontFamily[fontFamily],
color: theme.textColor[color].value,
...properties,
size,
};
}
export function border(theme: Theme, color: keyof Theme["borderColor"]) {
return {
color: theme.borderColor[color].value,
width: 1,
};
}
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) {
return {
blur: 16,
color: chroma("black").alpha(theme.shadowAlpha.value).hex(),
offset: [0, 2],
};
}

38
styles/core.ts Normal file
View file

@ -0,0 +1,38 @@
export type Color = string;
export default {
fontFamily: {
sans: "Zed Sans",
mono: "Zed Mono",
},
fontSize: {
"3xs": {
value: "8",
type: "fontSizes",
},
"2xs": {
value: "10",
type: "fontSizes",
},
xs: {
value: "12",
type: "fontSizes",
},
sm: {
value: "14",
type: "fontSizes",
},
md: {
value: "16",
type: "fontSizes",
},
lg: {
value: "18",
type: "fontSizes",
},
xl: {
value: "20",
type: "fontSizes",
},
},
};

28
styles/package-lock.json generated Normal file
View file

@ -0,0 +1,28 @@
{
"name": "styles",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "styles",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"chroma-js": "^2.4.2"
}
},
"node_modules/chroma-js": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
}
},
"dependencies": {
"chroma-js": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
}
}
}

14
styles/package.json Normal file
View file

@ -0,0 +1,14 @@
{
"name": "styles",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"chroma-js": "^2.4.2"
}
}

59
styles/selector-modal.ts Normal file
View file

@ -0,0 +1,59 @@
import { backgroundColor, border, player, shadow, text } from "./components";
import Theme from "./theme";
export 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, 500, "active"),
text: text(theme, "sans", "primary"),
};
return {
background: backgroundColor(theme, 500),
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, 300),
corner_radius: 6,
placeholderText: text(theme, "sans", "placeholder"),
selection: player(theme, 1).selection,
text: text(theme, "mono", "primary"),
border: border(theme, "primary"),
padding: {
bottom: 7,
left: 16,
right: 16,
top: 7,
},
},
margin: {
bottom: 52,
top: 52,
},
shadow: shadow(theme),
};
}

121
styles/theme.ts Normal file
View file

@ -0,0 +1,121 @@
export type Color = string;
export type Weight =
| "thin"
| "extra_light"
| "light"
| "normal"
| "medium"
| "semibold"
| "bold"
| "extra_bold"
| "black";
interface SyntaxHighlightStyle {
color: { value: Color };
weight: { value: Weight };
}
interface Player {
baseColor: {
value: Color;
};
cursorColor: {
value: Color;
};
selectionColor: {
value: Color;
};
borderColor: {
value: Color;
};
}
export interface BackgroundColor {
base: {
value: Color;
};
hover: {
value: Color;
};
active: {
value: Color;
};
focused: {
value: Color;
};
}
export default interface Theme {
backgroundColor: {
100: BackgroundColor;
300: BackgroundColor;
500: BackgroundColor;
};
borderColor: {
primary: {
value: Color;
};
secondary: {
value: Color;
};
muted: {
value: Color;
};
focused: {
value: Color;
};
active: {
value: Color;
};
};
textColor: {
primary: {
value: Color;
};
secondary: {
value: Color;
};
muted: {
value: Color;
};
placeholder: {
value: Color;
};
active: {
value: Color;
};
feature: {
value: Color;
};
};
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;
};
player: {
1: Player;
2: Player;
3: Player;
4: Player;
5: Player;
6: Player;
7: Player;
8: Player;
};
shadowAlpha: {
value: number;
};
}