working jump to definition with tests

This commit is contained in:
Keith Simmons
2022-06-24 15:09:31 -07:00
parent 848445455d
commit 92ab107fc9
26 changed files with 956 additions and 564 deletions
-74
View File
@@ -1,74 +0,0 @@
import * as fs from "fs";
import * as path from "path";
import themes from "./themes";
import Theme from "./themes/common/theme";
import { colors, fontFamilies, fontSizes, fontWeights, sizes } 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: theme.syntax.primary.color,
comment: theme.syntax.comment.color,
keyword: theme.syntax.keyword.color,
function: theme.syntax.function.color,
type: theme.syntax.type.color,
variant: theme.syntax.variant.color,
property: theme.syntax.property.color,
enum: theme.syntax.enum.color,
operator: theme.syntax.operator.color,
string: theme.syntax.string.color,
number: theme.syntax.number.color,
boolean: theme.syntax.boolean.color,
},
player: theme.player,
shadow: theme.shadow,
};
}
// Organize core tokens
const coreTokens = {
color: colors,
text: {
family: fontFamilies,
weight: fontWeights,
},
size: sizes,
fontSize: fontSizes,
};
const combinedTokens: any = {};
const distPath = path.resolve(`${__dirname}/../dist`);
for (const file of fs.readdirSync(distPath)) {
fs.unlinkSync(path.join(distPath, file));
}
// Add core tokens to the combined tokens and write `core.json`.
// We write `core.json` as a separate file for the design team's convenience, but it isn't consumed by Figma Tokens directly.
const corePath = path.join(distPath, "core.json");
fs.writeFileSync(corePath, JSON.stringify(coreTokens, null, 2));
console.log(`- ${corePath} created`);
combinedTokens.core = coreTokens;
// Add each theme to the combined tokens and write ${theme}.json.
// We write `${theme}.json` as a separate file for the design team's convenience, but it isn't consumed by Figma Tokens directly.
themes.forEach((theme) => {
const themePath = `${distPath}/${theme.name}.json`
fs.writeFileSync(themePath, JSON.stringify(themeTokens(theme), null, 2));
console.log(`- ${themePath} created`);
combinedTokens[theme.name] = themeTokens(theme);
});
// Write combined tokens to `tokens.json`. This file is consumed by the Figma Tokens plugin to keep our designs consistent with the app.
const combinedPath = path.resolve(`${distPath}/tokens.json`);
fs.writeFileSync(combinedPath, JSON.stringify(combinedTokens, null, 2));
console.log(`- ${combinedPath} created`);
+65
View File
@@ -0,0 +1,65 @@
export const fontFamilies = {
sans: "Zed Sans",
mono: "Zed Mono",
}
export const fontSizes = {
"3xs": 8,
"2xs": 10,
xs: 12,
sm: 14,
md: 16,
lg: 18,
xl: 20,
};
export type FontWeight = "thin"
| "extra_light"
| "light"
| "normal"
| "medium"
| "semibold"
| "bold"
| "extra_bold"
| "black";
export const fontWeights: { [key: string]: FontWeight } = {
thin: "thin",
extra_light: "extra_light",
light: "light",
normal: "normal",
medium: "medium",
semibold: "semibold",
bold: "bold",
extra_bold: "extra_bold",
black: "black"
};
export const sizes = {
px: 1,
xs: 2,
sm: 4,
md: 6,
lg: 8,
xl: 12,
};
// export const colors = {
// neutral: colorRamp(["white", "black"], { steps: 37, increment: 25 }), // (900/25) + 1
// rose: colorRamp("#F43F5EFF"),
// red: colorRamp("#EF4444FF"),
// orange: colorRamp("#F97316FF"),
// amber: colorRamp("#F59E0BFF"),
// yellow: colorRamp("#EAB308FF"),
// lime: colorRamp("#84CC16FF"),
// green: colorRamp("#22C55EFF"),
// emerald: colorRamp("#10B981FF"),
// teal: colorRamp("#14B8A6FF"),
// cyan: colorRamp("#06BBD4FF"),
// sky: colorRamp("#0EA5E9FF"),
// blue: colorRamp("#3B82F6FF"),
// indigo: colorRamp("#6366F1FF"),
// violet: colorRamp("#8B5CF6FF"),
// purple: colorRamp("#A855F7FF"),
// fuschia: colorRamp("#D946E4FF"),
// pink: colorRamp("#EC4899FF"),
// }
+3 -4
View File
@@ -4,7 +4,6 @@ import {
backgroundColor,
border,
player,
modalShadow,
text,
TextColor,
popoverShadow
@@ -80,15 +79,15 @@ export default function chatPanel(theme: Theme) {
...message,
body: {
...message.body,
color: theme.textColor.muted.value,
color: theme.textColor.muted,
},
sender: {
...message.sender,
color: theme.textColor.muted.value,
color: theme.textColor.muted,
},
timestamp: {
...message.timestamp,
color: theme.textColor.muted.value,
color: theme.textColor.muted,
},
},
inputEditor: {
+15 -18
View File
@@ -1,8 +1,5 @@
import chroma from "chroma-js";
import { isIPv4 } from "net";
import Theme, { BackgroundColorSet } from "../themes/common/theme";
import { fontFamilies, fontSizes, FontWeight } from "../tokens";
import { Color } from "../utils/color";
import { fontFamilies, fontSizes, FontWeight } from "../common";
export type TextColor = keyof Theme["textColor"];
export function text(
@@ -15,16 +12,16 @@ export function text(
underline?: boolean;
}
) {
let size = fontSizes[properties?.size || "sm"].value;
let size = fontSizes[properties?.size || "sm"];
return {
family: fontFamilies[fontFamily].value,
color: theme.textColor[color].value,
family: fontFamilies[fontFamily],
color: theme.textColor[color],
...properties,
size,
};
}
export function textColor(theme: Theme, color: TextColor) {
return theme.textColor[color].value;
return theme.textColor[color];
}
export type BorderColor = keyof Theme["borderColor"];
@@ -48,19 +45,19 @@ export function border(
};
}
export function borderColor(theme: Theme, color: BorderColor) {
return theme.borderColor[color].value;
return theme.borderColor[color];
}
export type IconColor = keyof Theme["iconColor"];
export function iconColor(theme: Theme, color: IconColor) {
return theme.iconColor[color].value;
return theme.iconColor[color];
}
export type PlayerIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
export interface Player {
selection: {
cursor: Color;
selection: Color;
cursor: string;
selection: string;
};
}
export function player(
@@ -69,8 +66,8 @@ export function player(
): Player {
return {
selection: {
cursor: theme.player[playerNumber].cursorColor.value,
selection: theme.player[playerNumber].selectionColor.value,
cursor: theme.player[playerNumber].cursorColor,
selection: theme.player[playerNumber].selectionColor,
},
};
}
@@ -81,14 +78,14 @@ export function backgroundColor(
theme: Theme,
name: BackgroundColor,
state?: BackgroundState,
): Color {
return theme.backgroundColor[name][state || "base"].value;
): string {
return theme.backgroundColor[name][state || "base"];
}
export function modalShadow(theme: Theme) {
return {
blur: 16,
color: theme.shadow.value,
color: theme.shadow,
offset: [0, 2],
};
}
@@ -96,7 +93,7 @@ export function modalShadow(theme: Theme) {
export function popoverShadow(theme: Theme) {
return {
blur: 4,
color: theme.shadow.value,
color: theme.shadow,
offset: [1, 2],
};
}
+15 -11
View File
@@ -43,28 +43,28 @@ export default function editor(theme: Theme) {
for (const syntaxKey in theme.syntax) {
const style = theme.syntax[syntaxKey];
syntax[syntaxKey] = {
color: style.color.value,
weight: style.weight.value,
color: style.color,
weight: style.weight,
underline: style.underline,
italic: style.italic,
};
}
return {
textColor: theme.syntax.primary.color.value,
textColor: theme.syntax.primary.color,
background: backgroundColor(theme, 500),
activeLineBackground: theme.editor.line.active.value,
activeLineBackground: theme.editor.line.active,
codeActionsIndicator: iconColor(theme, "muted"),
diffBackgroundDeleted: backgroundColor(theme, "error"),
diffBackgroundInserted: backgroundColor(theme, "ok"),
documentHighlightReadBackground: theme.editor.highlight.occurrence.value,
documentHighlightWriteBackground: theme.editor.highlight.activeOccurrence.value,
errorColor: theme.textColor.error.value,
documentHighlightReadBackground: theme.editor.highlight.occurrence,
documentHighlightWriteBackground: theme.editor.highlight.activeOccurrence,
errorColor: theme.textColor.error,
gutterBackground: backgroundColor(theme, 500),
gutterPaddingFactor: 3.5,
highlightedLineBackground: theme.editor.line.highlighted.value,
lineNumber: theme.editor.gutter.primary.value,
lineNumberActive: theme.editor.gutter.active.value,
highlightedLineBackground: theme.editor.line.highlighted,
lineNumber: theme.editor.gutter.primary,
lineNumberActive: theme.editor.gutter.active,
renameFade: 0.6,
unnecessaryCodeFade: 0.5,
selection: player(theme, 1).selection,
@@ -120,7 +120,7 @@ export default function editor(theme: Theme) {
},
},
diagnosticPathHeader: {
background: theme.editor.line.active.value,
background: theme.editor.line.active,
textScaleFactor: 0.857,
filename: text(theme, "mono", "primary", { size: "sm" }),
path: {
@@ -139,6 +139,10 @@ export default function editor(theme: Theme) {
invalidInformationDiagnostic: diagnostic(theme, "muted"),
invalidWarningDiagnostic: diagnostic(theme, "muted"),
hover_popover: hoverPopover(theme),
link_definition: {
color: theme.syntax.linkUri.color,
underline: theme.syntax.linkUri.underline,
},
jumpIcon: {
color: iconColor(theme, "muted"),
iconWidth: 20,
+1 -1
View File
@@ -22,6 +22,6 @@ export default function HoverPopover(theme: Theme) {
padding: { top: 4 },
},
prose: text(theme, "sans", "primary", { "size": "sm" }),
highlight: theme.editor.highlight.occurrence.value,
highlight: theme.editor.highlight.occurrence,
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ export default function search(theme: Theme) {
};
return {
matchBackground: theme.editor.highlight.match.value,
matchBackground: theme.editor.highlight.match,
tabIconSpacing: 8,
tabIconWidth: 14,
optionButton: {
+1 -1
View File
@@ -13,7 +13,7 @@ export default function updateNotification(theme: Theme): Object {
...text(theme, "sans", "secondary", { size: "xs" }),
margin: { left: headerPadding, top: 6, bottom: 6 },
hover: {
color: theme.textColor["active"].value
color: theme.textColor["active"]
}
},
dismissButton: {
+1 -1
View File
@@ -147,7 +147,7 @@ export default function workspace(theme: Theme) {
},
disconnectedOverlay: {
...text(theme, "sans", "active"),
background: withOpacity(theme.backgroundColor[500].base, 0.8).value,
background: withOpacity(theme.backgroundColor[500].base, 0.8),
},
notification: {
margin: { top: 10 },
+5 -5
View File
@@ -1,5 +1,5 @@
import chroma, { Color, Scale } from "chroma-js";
import { color, ColorToken, fontWeights, NumberToken } from "../../tokens";
import { fontWeights, } from "../../common";
import { withOpacity } from "../../utils/color";
import Theme, { buildPlayer, Syntax } from "./theme";
@@ -26,10 +26,10 @@ export function createTheme(
let blend = isLight ? 0.12 : 0.24;
function sample(ramp: Scale, index: number): ColorToken {
return color(ramp(index).hex());
function sample(ramp: Scale, index: number): string {
return ramp(index).hex();
}
const darkest = color(ramps.neutral(isLight ? 7 : 0).hex());
const darkest = ramps.neutral(isLight ? 7 : 0).hex();
const backgroundColor = {
// Title bar
@@ -232,7 +232,7 @@ export function createTheme(
};
const shadow = withOpacity(
color(ramps.neutral(isLight ? 7 : 0).darken().hex()),
ramps.neutral(isLight ? 7 : 0).darken().hex(),
blend);
return {
+56 -56
View File
@@ -1,21 +1,21 @@
import { ColorToken, FontWeightToken, NumberToken } from "../../tokens";
import { FontWeight } from "../../common";
import { withOpacity } from "../../utils/color";
export interface SyntaxHighlightStyle {
color: ColorToken;
weight?: FontWeightToken;
color: string;
weight?: FontWeight;
underline?: boolean;
italic?: boolean;
}
export interface Player {
baseColor: ColorToken;
cursorColor: ColorToken;
selectionColor: ColorToken;
borderColor: ColorToken;
baseColor: string;
cursorColor: string;
selectionColor: string;
borderColor: string;
}
export function buildPlayer(
color: ColorToken,
color: string,
cursorOpacity?: number,
selectionOpacity?: number,
borderOpacity?: number
@@ -29,9 +29,9 @@ export function buildPlayer(
}
export interface BackgroundColorSet {
base: ColorToken;
hovered: ColorToken;
active: ColorToken;
base: string;
hovered: string;
active: string;
}
export interface Syntax {
@@ -81,64 +81,64 @@ export default interface Theme {
info: BackgroundColorSet;
};
borderColor: {
primary: ColorToken;
secondary: ColorToken;
muted: ColorToken;
active: ColorToken;
primary: string;
secondary: string;
muted: string;
active: string;
/**
* Used for rendering borders on top of media like avatars, images, video, etc.
*/
onMedia: ColorToken;
ok: ColorToken;
error: ColorToken;
warning: ColorToken;
info: ColorToken;
onMedia: string;
ok: string;
error: string;
warning: string;
info: string;
};
textColor: {
primary: ColorToken;
secondary: ColorToken;
muted: ColorToken;
placeholder: ColorToken;
active: ColorToken;
feature: ColorToken;
ok: ColorToken;
error: ColorToken;
warning: ColorToken;
info: ColorToken;
onMedia: ColorToken;
primary: string;
secondary: string;
muted: string;
placeholder: string;
active: string;
feature: string;
ok: string;
error: string;
warning: string;
info: string;
onMedia: string;
};
iconColor: {
primary: ColorToken;
secondary: ColorToken;
muted: ColorToken;
placeholder: ColorToken;
active: ColorToken;
feature: ColorToken;
ok: ColorToken;
error: ColorToken;
warning: ColorToken;
info: ColorToken;
primary: string;
secondary: string;
muted: string;
placeholder: string;
active: string;
feature: string;
ok: string;
error: string;
warning: string;
info: string;
};
editor: {
background: ColorToken;
indent_guide: ColorToken;
indent_guide_active: ColorToken;
background: string;
indent_guide: string;
indent_guide_active: string;
line: {
active: ColorToken;
highlighted: ColorToken;
active: string;
highlighted: string;
};
highlight: {
selection: ColorToken;
occurrence: ColorToken;
activeOccurrence: ColorToken;
matchingBracket: ColorToken;
match: ColorToken;
activeMatch: ColorToken;
related: ColorToken;
selection: string;
occurrence: string;
activeOccurrence: string;
matchingBracket: string;
match: string;
activeMatch: string;
related: string;
};
gutter: {
primary: ColorToken;
active: ColorToken;
primary: string;
active: string;
};
};
@@ -154,5 +154,5 @@ export default interface Theme {
7: Player;
8: Player;
},
shadow: ColorToken;
shadow: string;
}
-130
View File
@@ -1,130 +0,0 @@
import { colorRamp } from "./utils/color";
interface Token<V, T> {
value: V,
type: T
}
export type FontFamily = string;
export type FontFamilyToken = Token<FontFamily, "fontFamily">;
function fontFamily(value: FontFamily): FontFamilyToken {
return {
value,
type: "fontFamily"
}
}
export const fontFamilies = {
sans: fontFamily("Zed Sans"),
mono: fontFamily("Zed Mono"),
}
export type FontSize = number;
export type FontSizeToken = Token<FontSize, "fontSize">;
function fontSize(value: FontSize) {
return {
value,
type: "fontSize"
};
}
export const fontSizes = {
"3xs": fontSize(8),
"2xs": fontSize(10),
xs: fontSize(12),
sm: fontSize(14),
md: fontSize(16),
lg: fontSize(18),
xl: fontSize(20),
};
export type FontWeight =
| "thin"
| "extra_light"
| "light"
| "normal"
| "medium"
| "semibold"
| "bold"
| "extra_bold"
| "black";
export type FontWeightToken = Token<FontWeight, "fontWeight">;
function fontWeight(value: FontWeight): FontWeightToken {
return {
value,
type: "fontWeight"
};
}
export const fontWeights = {
"thin": fontWeight("thin"),
"extra_light": fontWeight("extra_light"),
"light": fontWeight("light"),
"normal": fontWeight("normal"),
"medium": fontWeight("medium"),
"semibold": fontWeight("semibold"),
"bold": fontWeight("bold"),
"extra_bold": fontWeight("extra_bold"),
"black": fontWeight("black"),
}
// Standard size unit used for paddings, margins, borders, etc.
export type Size = number
export type SizeToken = Token<Size, "size">;
function size(value: Size): SizeToken {
return {
value,
type: "size"
};
}
export const sizes = {
px: size(1),
xs: size(2),
sm: size(4),
md: size(6),
lg: size(8),
xl: size(12),
};
export type Color = string;
export interface ColorToken {
value: Color,
type: "color",
step?: number,
}
export function color(value: string): ColorToken {
return {
value,
type: "color",
};
}
export const colors = {
neutral: colorRamp(["white", "black"], { steps: 37, increment: 25 }), // (900/25) + 1
rose: colorRamp("#F43F5EFF"),
red: colorRamp("#EF4444FF"),
orange: colorRamp("#F97316FF"),
amber: colorRamp("#F59E0BFF"),
yellow: colorRamp("#EAB308FF"),
lime: colorRamp("#84CC16FF"),
green: colorRamp("#22C55EFF"),
emerald: colorRamp("#10B981FF"),
teal: colorRamp("#14B8A6FF"),
cyan: colorRamp("#06BBD4FF"),
sky: colorRamp("#0EA5E9FF"),
blue: colorRamp("#3B82F6FF"),
indigo: colorRamp("#6366F1FF"),
violet: colorRamp("#8B5CF6FF"),
purple: colorRamp("#A855F7FF"),
fuschia: colorRamp("#D946E4FF"),
pink: colorRamp("#EC4899FF"),
}
export type NumberToken = Token<number, "number">;
export default {
fontFamilies,
fontSizes,
fontWeights,
size,
colors,
};
+3 -50
View File
@@ -1,52 +1,5 @@
import chroma, { Scale } from "chroma-js";
import { ColorToken } from "../tokens";
import chroma from "chroma-js";
export type Color = string;
export type ColorRampStep = { value: Color; type: "color"; description: string };
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,
description: `Step: ${step}`,
type: "color",
};
});
return ramp;
}
export function withOpacity(color: ColorToken, opacity: number): ColorToken {
return {
...color,
value: chroma(color.value).alpha(opacity).hex()
};
export function withOpacity(color: string, opacity: number): string {
return chroma(color).alpha(opacity).hex();
}