Remove styles dir

This commit is contained in:
Nate Butler
2024-01-04 09:58:09 -05:00
parent e5156d1f85
commit 9fe0168dc9
128 changed files with 0 additions and 13976 deletions
-34
View File
@@ -1,34 +0,0 @@
module.exports = {
env: {
node: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/typescript",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["@typescript-eslint", "import"],
globals: {
module: true,
},
settings: {
"import/parsers": {
"@typescript-eslint/parser": [".ts"],
},
"import/resolver": {
typescript: true,
node: true,
},
"import/extensions": [".ts"],
},
rules: {
"linebreak-style": ["error", "unix"],
"@typescript-eslint/no-explicit-any": "off",
semi: ["error", "never"],
},
}
-2
View File
@@ -1,2 +0,0 @@
node_modules/
coverage/
-3
View File
@@ -1,3 +0,0 @@
package-lock.json
package.json
target
-6
View File
@@ -1,6 +0,0 @@
{
"semi": false,
"printWidth": 80,
"htmlWhitespaceSensitivity": "strict",
"tabWidth": 4
}
-20
View File
@@ -1,20 +0,0 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://docs.zed.dev/configuration/configuring-zed#folder-specific-settings
{
"languages": {
"TypeScript": {
"tab_size": 4
},
"TSX": {
"tab_size": 4
},
"JavaScript": {
"tab_size": 4
},
"JSON": {
"tab_size": 4
}
}
}
-4372
View File
File diff suppressed because it is too large Load Diff
-37
View File
@@ -1,37 +0,0 @@
{
"name": "styles",
"version": "1.0.0",
"description": "Typescript app that builds Zed's themes",
"main": "./src/build_themes.ts",
"scripts": {
"build": "ts-node ./src/build_themes.ts",
"build-licenses": "ts-node ./src/build_licenses.ts",
"build-tokens": "ts-node ./src/build_tokens.ts",
"build-types": "ts-node ./src/build_types.ts",
"test": "vitest"
},
"author": "Zed Industries (https://github.com/zed-industries/)",
"license": "ISC",
"dependencies": {
"@tokens-studio/types": "^0.2.3",
"@types/chroma-js": "^2.4.0",
"@types/node": "^18.14.1",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"@vitest/coverage-v8": "^0.32.0",
"ayu": "^8.0.1",
"chroma-js": "^2.4.2",
"deepmerge": "^4.3.0",
"eslint": "^8.43.0",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.27.5",
"json-schema-to-typescript": "^13.0.2",
"toml": "^3.0.0",
"ts-deepmerge": "^6.0.3",
"ts-node": "^10.9.1",
"typescript": "^5.1.5",
"utility-types": "^3.10.0",
"vitest": "^0.32.0",
"zustand": "^4.3.8"
}
}
-50
View File
@@ -1,50 +0,0 @@
import * as fs from "fs"
import toml from "toml"
import { themes } from "./themes"
import { ThemeConfig } from "./common"
const ACCEPTED_LICENSES_FILE = `${__dirname}/../../script/licenses/zed-licenses.toml`
// Use the cargo-about configuration file as the source of truth for supported licenses.
function parse_accepted_toml(file: string): string[] {
const buffer = fs.readFileSync(file).toString()
const obj = toml.parse(buffer)
if (!Array.isArray(obj.accepted)) {
throw Error("Accepted license source is malformed")
}
return obj.accepted
}
function check_licenses(themes: ThemeConfig[]) {
for (const theme of themes) {
if (!theme.license_file) {
throw Error(`Theme ${theme.name} should have a LICENSE file`)
}
}
}
function generate_license_file(themes: ThemeConfig[]) {
check_licenses(themes)
for (const theme of themes) {
const license_text = fs.readFileSync(theme.license_file).toString()
write_license(theme.name, license_text, theme.license_url)
}
}
function write_license(
theme_name: string,
license_text: string,
license_url?: string
) {
process.stdout.write(
license_url
? `## [${theme_name}](${license_url})\n\n${license_text}\n********************************************************************************\n\n`
: `## ${theme_name}\n\n${license_text}\n********************************************************************************\n\n`
)
}
const accepted_licenses = parse_accepted_toml(ACCEPTED_LICENSES_FILE)
generate_license_file(themes)
-45
View File
@@ -1,45 +0,0 @@
import * as fs from "fs"
import { tmpdir } from "os"
import * as path from "path"
import app from "./style_tree/app"
import { Theme, create_theme } from "./theme/create_theme"
import { themes } from "./themes"
import { useThemeStore } from "./theme"
const assets_directory = `${__dirname}/../../assets`
const temp_directory = fs.mkdtempSync(path.join(tmpdir(), "build-themes"))
function clear_themes(theme_directory: string) {
if (!fs.existsSync(theme_directory)) {
fs.mkdirSync(theme_directory, { recursive: true })
} else {
for (const file of fs.readdirSync(theme_directory)) {
if (file.endsWith(".json")) {
fs.unlinkSync(path.join(theme_directory, file))
}
}
}
}
const all_themes: Theme[] = themes.map((theme) => create_theme(theme))
function write_themes(themes: Theme[], output_directory: string) {
clear_themes(output_directory)
for (const theme of themes) {
const { setTheme } = useThemeStore.getState()
setTheme(theme)
const style_tree = app()
// Nathan: New elements will read directly from the theme colors.
// Adding this during the transition. Afterwards, we can port all themes to Rust.
style_tree.base_theme = theme
const style_tree_json = JSON.stringify(style_tree, null, 2)
const temp_path = path.join(temp_directory, `${theme.name}.json`)
const out_path = path.join(output_directory, `${theme.name}.json`)
fs.writeFileSync(temp_path, style_tree_json)
fs.renameSync(temp_path, out_path)
console.log(`- ${out_path} created`)
}
}
write_themes(all_themes, `${assets_directory}/themes`)
-88
View File
@@ -1,88 +0,0 @@
import * as fs from "fs"
import * as path from "path"
import { Theme, create_theme, useThemeStore } from "./common"
import { themes } from "./themes"
import { slugify } from "./utils/slugify"
import { theme_tokens } from "./theme/tokens/theme"
const TOKENS_DIRECTORY = path.join(__dirname, "..", "target", "tokens")
const TOKENS_FILE = path.join(TOKENS_DIRECTORY, "$themes.json")
const METADATA_FILE = path.join(TOKENS_DIRECTORY, "$metadata.json")
function clear_tokens(tokens_directory: string) {
if (!fs.existsSync(tokens_directory)) {
fs.mkdirSync(tokens_directory, { recursive: true })
} else {
for (const file of fs.readdirSync(tokens_directory)) {
if (file.endsWith(".json")) {
fs.unlinkSync(path.join(tokens_directory, file))
}
}
}
}
type TokenSet = {
id: string
name: string
selected_token_sets: { [key: string]: "enabled" }
}
function build_token_set_order(theme: Theme[]): {
token_set_order: string[]
} {
const token_set_order: string[] = theme.map((scheme) =>
scheme.name.toLowerCase().replace(/\s+/g, "_")
)
return { token_set_order }
}
function build_themes_index(theme: Theme[]): TokenSet[] {
const themes_index: TokenSet[] = theme.map((scheme, index) => {
const id = `${scheme.is_light ? "light" : "dark"}_${scheme.name
.toLowerCase()
.replace(/\s+/g, "_")}_${index}`
const selected_token_sets: { [key: string]: "enabled" } = {}
const token_set = scheme.name.toLowerCase().replace(/\s+/g, "_")
selected_token_sets[token_set] = "enabled"
return {
id,
name: `${scheme.name} - ${scheme.is_light ? "Light" : "Dark"}`,
selected_token_sets,
}
})
return themes_index
}
function write_tokens(themes: Theme[], tokens_directory: string) {
clear_tokens(tokens_directory)
for (const theme of themes) {
const { setTheme } = useThemeStore.getState()
setTheme(theme)
const file_name = slugify(theme.name) + ".json"
const tokens = theme_tokens()
const tokens_json = JSON.stringify(tokens, null, 2)
const out_path = path.join(tokens_directory, file_name)
fs.writeFileSync(out_path, tokens_json, { mode: 0o644 })
console.log(`- ${out_path} created`)
}
const theme_index_data = build_themes_index(themes)
const themes_json = JSON.stringify(theme_index_data, null, 2)
fs.writeFileSync(TOKENS_FILE, themes_json, { mode: 0o644 })
console.log(`- ${TOKENS_FILE} created`)
const token_set_order_data = build_token_set_order(themes)
const metadata_json = JSON.stringify(token_set_order_data, null, 2)
fs.writeFileSync(METADATA_FILE, metadata_json, { mode: 0o644 })
console.log(`- ${METADATA_FILE} created`)
}
const all_themes: Theme[] = themes.map((theme) => create_theme(theme))
write_tokens(all_themes, TOKENS_DIRECTORY)
-62
View File
@@ -1,62 +0,0 @@
import * as fs from "fs/promises"
import * as fsSync from "fs"
import * as path from "path"
import { compile } from "json-schema-to-typescript"
const BANNER = `/*
* This file is autogenerated
*/\n\n`
const dirname = __dirname
async function main() {
const schemas_path = path.join(dirname, "../../", "crates/theme/schemas")
const schema_files = (await fs.readdir(schemas_path)).filter((x) =>
x.endsWith(".json")
)
const compiled_types = new Set()
for (const filename of schema_files) {
const file_path = path.join(schemas_path, filename)
const file_contents = await fs.readFile(file_path)
const schema = JSON.parse(file_contents.toString())
const compiled = await compile(schema, schema.title, {
bannerComment: "",
})
const each_type = compiled.split("export")
for (const type of each_type) {
if (!type) {
continue
}
compiled_types.add("export " + type.trim())
}
}
const output = BANNER + Array.from(compiled_types).join("\n\n")
const output_path = path.join(dirname, "../../styles/src/types/zed.ts")
try {
const existing = await fs.readFile(output_path)
if (existing.toString() == output) {
// Skip writing if it hasn't changed
console.log("Schemas are up to date")
return
}
} catch (e) {
if (e.code !== "ENOENT") {
throw e
}
}
const types_dic = path.dirname(output_path)
if (!fsSync.existsSync(types_dic)) {
await fs.mkdir(types_dic)
}
await fs.writeFile(output_path, output)
console.log(`Wrote Typescript types to ${output_path}`)
}
main().catch((e) => {
console.error(e)
process.exit(1)
})
-34
View File
@@ -1,34 +0,0 @@
import chroma from "chroma-js"
export * from "./theme"
export * from "./theme/theme_config"
export { chroma }
export const font_families = {
ui_sans: "IBM Plex Sans",
sans: "Zed Sans",
mono: "Zed Mono",
}
export const font_sizes = {
"2xs": 10,
xs: 12,
sm: 14,
md: 16,
lg: 18,
}
export type FontWeight = "normal" | "bold"
export const font_weights: { [key: string]: FontWeight } = {
normal: "normal",
bold: "bold",
}
export const sizes = {
px: 1,
xs: 2,
sm: 4,
md: 6,
lg: 8,
xl: 12,
}
-127
View File
@@ -1,127 +0,0 @@
import { font_sizes, useTheme } from "../common"
import { Layer, Theme } from "../theme"
import { TextStyle, background } from "../style_tree/components"
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace Button {
export type Options = {
layer: Layer
background: keyof Theme["lowest"]
color: keyof Theme["lowest"]
variant: Button.Variant
size: Button.Size
shape: Button.Shape
margin: {
top?: number
bottom?: number
left?: number
right?: number
}
states: {
enabled?: boolean
hovered?: boolean
pressed?: boolean
focused?: boolean
disabled?: boolean
}
}
export type ToggleableOptions = Options & {
active_background: keyof Theme["lowest"]
active_color: keyof Theme["lowest"]
}
/** Padding added to each side of a Shape.Rectangle button */
export const RECTANGLE_PADDING = 2
export const FONT_SIZE = font_sizes.sm
export const ICON_SIZE = 14
export const CORNER_RADIUS = 6
export const variant = {
Default: "filled",
Outline: "outline",
Ghost: "ghost",
} as const
export type Variant = (typeof variant)[keyof typeof variant]
export const shape = {
Rectangle: "rectangle",
Square: "square",
} as const
export type Shape = (typeof shape)[keyof typeof shape]
export const size = {
Small: "sm",
Medium: "md",
} as const
export type Size = (typeof size)[keyof typeof size]
export type BaseStyle = {
corder_radius: number
background: string | null
padding: {
top: number
bottom: number
left: number
right: number
}
margin: Button.Options["margin"]
button_height: number
}
export type LabelButtonStyle = BaseStyle & TextStyle
// export type IconButtonStyle = ButtonStyle
export const button_base = (
options: Partial<Button.Options> = {
variant: Button.variant.Default,
shape: Button.shape.Rectangle,
states: {
hovered: true,
pressed: true,
},
}
): BaseStyle => {
const theme = useTheme()
const layer = options.layer ?? theme.middle
const color = options.color ?? "base"
const background_color =
options.variant === Button.variant.Ghost
? null
: background(layer, options.background ?? color)
const m = {
top: options.margin?.top ?? 0,
bottom: options.margin?.bottom ?? 0,
left: options.margin?.left ?? 0,
right: options.margin?.right ?? 0,
}
const size = options.size || Button.size.Medium
const padding = 2
const base: BaseStyle = {
background: background_color,
corder_radius: Button.CORNER_RADIUS,
padding: {
top: padding,
bottom: padding,
left:
options.shape === Button.shape.Rectangle
? padding + Button.RECTANGLE_PADDING
: padding,
right:
options.shape === Button.shape.Rectangle
? padding + Button.RECTANGLE_PADDING
: padding,
},
margin: m,
button_height: 16,
}
return base
}
}
-111
View File
@@ -1,111 +0,0 @@
import { interactive, toggleable } from "../element"
import { background, foreground } from "../style_tree/components"
import { useTheme, Theme, Layer } from "../theme"
import { Button } from "./button"
export type Margin = {
top: number
bottom: number
left: number
right: number
}
interface IconButtonOptions {
layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"]
color?: keyof Theme["lowest"]
background_color?: keyof Theme["lowest"]
margin?: Partial<Margin>
variant?: Button.Variant
size?: Button.Size
}
type ToggleableIconButtonOptions = IconButtonOptions & {
active_color?: keyof Theme["lowest"]
active_background_color?: keyof Theme["lowest"]
active_layer?: Layer
active_variant?: Button.Variant
}
export function icon_button(
{ color, background_color, margin, layer, variant, size }: IconButtonOptions = {
variant: Button.variant.Default,
size: Button.size.Medium,
}
) {
const theme = useTheme()
if (!color) color = "base"
const default_background =
variant === Button.variant.Ghost
? null
: background(layer ?? theme.lowest, background_color ?? color)
const m = {
top: margin?.top ?? 0,
bottom: margin?.bottom ?? 0,
left: margin?.left ?? 0,
right: margin?.right ?? 0,
}
const padding = {
top: size === Button.size.Small ? 2 : 2,
bottom: size === Button.size.Small ? 2 : 2,
left: size === Button.size.Small ? 2 : 4,
right: size === Button.size.Small ? 2 : 4,
}
return interactive({
base: {
corner_radius: 6,
padding: padding,
margin: m,
icon_width: 14,
icon_height: 14,
button_width: size === Button.size.Small ? 16 : 20,
button_height: 14,
},
state: {
default: {
background: default_background,
color: foreground(layer ?? theme.lowest, color),
},
hovered: {
background: background(layer ?? theme.lowest, background_color ?? color, "hovered"),
color: foreground(layer ?? theme.lowest, color, "hovered"),
},
clicked: {
background: background(layer ?? theme.lowest, background_color ?? color, "pressed"),
color: foreground(layer ?? theme.lowest, color, "pressed"),
},
},
})
}
export function toggleable_icon_button({
color,
background_color,
active_color,
active_background_color,
active_variant,
margin,
variant,
size,
active_layer,
}: ToggleableIconButtonOptions) {
if (!color) color = "base"
return toggleable({
state: {
inactive: icon_button({ color, background_color, margin, variant, size }),
active: icon_button({
color: active_color ? active_color : color,
background_color: active_background_color ? active_background_color : background_color,
margin,
layer: active_layer,
variant: active_variant || variant,
size,
}),
},
})
}
-6
View File
@@ -1,6 +0,0 @@
export * from "./icon_button"
export * from "./indicator"
export * from "./input"
export * from "./tab"
export * from "./tab_bar_button"
export * from "./text_button"
-15
View File
@@ -1,15 +0,0 @@
import { foreground } from "../style_tree/components"
import { Layer, StyleSets } from "../theme"
export const indicator = ({
layer,
color,
}: {
layer: Layer
color: StyleSets
}) => ({
corner_radius: 4,
padding: 4,
margin: { top: 12, left: 12 },
background: foreground(layer, color),
})
-23
View File
@@ -1,23 +0,0 @@
import { useTheme } from "../common"
import { background, border, text } from "../style_tree/components"
export const input = () => {
const theme = useTheme()
return {
background: background(theme.highest),
corner_radius: 8,
min_width: 200,
max_width: 500,
placeholder_text: text(theme.highest, "mono", "disabled"),
selection: theme.players[0],
text: text(theme.highest, "mono", "default"),
border: border(theme.highest),
padding: {
top: 3,
bottom: 3,
left: 12,
right: 8,
},
}
}
-73
View File
@@ -1,73 +0,0 @@
import { Layer } from "../common"
import { interactive, toggleable } from "../element"
import { Border, text } from "../style_tree/components"
type TabProps = {
layer: Layer
}
export const tab = ({ layer }: TabProps) => {
const active_color = text(layer, "sans", "base").color
const inactive_border: Border = {
color: "#FFFFFF00",
width: 1,
bottom: true,
left: false,
right: false,
top: false,
}
const active_border: Border = {
...inactive_border,
color: active_color,
}
const base = {
...text(layer, "sans", "variant"),
padding: {
top: 8,
left: 8,
right: 8,
bottom: 6,
},
border: inactive_border,
}
const i = interactive({
state: {
default: {
...base,
},
hovered: {
...base,
...text(layer, "sans", "base", "hovered"),
},
clicked: {
...base,
...text(layer, "sans", "base", "pressed"),
},
},
})
return toggleable({
base: i,
state: {
active: {
default: {
...i,
...text(layer, "sans", "base"),
border: active_border,
},
hovered: {
...i,
...text(layer, "sans", "base", "hovered"),
border: active_border,
},
clicked: {
...i,
...text(layer, "sans", "base", "pressed"),
border: active_border,
},
},
},
})
}
-58
View File
@@ -1,58 +0,0 @@
import { Theme, StyleSets } from "../common"
import { interactive } from "../element"
import { InteractiveState } from "../element/interactive"
import { background, foreground } from "../style_tree/components"
interface TabBarButtonOptions {
icon: string
color?: StyleSets
}
type TabBarButtonProps = TabBarButtonOptions & {
state?: Partial<Record<InteractiveState, Partial<TabBarButtonOptions>>>
}
export function tab_bar_button(
theme: Theme,
{ icon, color = "base" }: TabBarButtonProps
) {
const button_spacing = 8
return interactive({
base: {
icon: {
color: foreground(theme.middle, color),
asset: icon,
dimensions: {
width: 15,
height: 15,
},
},
container: {
corner_radius: 4,
padding: {
top: 4,
bottom: 4,
left: 4,
right: 4,
},
margin: {
left: button_spacing / 2,
right: button_spacing / 2,
},
},
},
state: {
hovered: {
container: {
background: background(theme.middle, color, "hovered"),
},
},
clicked: {
container: {
background: background(theme.middle, color, "pressed"),
},
},
},
})
}
-129
View File
@@ -1,129 +0,0 @@
import { interactive, toggleable } from "../element"
import {
Border,
TextProperties,
background,
foreground,
text,
} from "../style_tree/components"
import { useTheme, Theme } from "../theme"
import { Button } from "./button"
import { Margin } from "./icon_button"
interface TextButtonOptions {
layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"]
variant?: Button.Variant
color?: keyof Theme["lowest"]
margin?: Partial<Margin>
disabled?: boolean
text_properties?: TextProperties
border?: Border
}
type ToggleableTextButtonOptions = TextButtonOptions & {
active_color?: keyof Theme["lowest"]
}
export function text_button({
variant = Button.variant.Default,
color,
layer,
margin,
disabled,
text_properties,
border,
}: TextButtonOptions = {}) {
const theme = useTheme()
if (!color) color = "base"
const background_color =
variant === Button.variant.Ghost
? null
: background(layer ?? theme.lowest, color)
const text_options: TextProperties = {
size: "xs",
weight: "normal",
...text_properties,
}
const m = {
top: margin?.top ?? 0,
bottom: margin?.bottom ?? 0,
left: margin?.left ?? 0,
right: margin?.right ?? 0,
}
return interactive({
base: {
corner_radius: 6,
padding: {
top: 1,
bottom: 1,
left: 6,
right: 6,
},
margin: m,
button_height: 22,
...text(layer ?? theme.lowest, "sans", color, text_options),
},
state: {
default: {
border,
background: background_color,
color: disabled
? foreground(layer ?? theme.lowest, "disabled")
: foreground(layer ?? theme.lowest, color),
},
hovered: disabled
? {}
: {
border,
background: background(
layer ?? theme.lowest,
color,
"hovered"
),
color: foreground(
layer ?? theme.lowest,
color,
"hovered"
),
},
clicked: disabled
? {}
: {
border,
background: background(
layer ?? theme.lowest,
color,
"pressed"
),
color: foreground(
layer ?? theme.lowest,
color,
"pressed"
),
},
},
})
}
export function toggleable_text_button(
theme: Theme,
{ variant, color, active_color, margin }: ToggleableTextButtonOptions = {}
) {
if (!color) color = "base"
return toggleable({
state: {
inactive: text_button({ variant, color, margin }),
active: text_button({
variant,
color: active_color ? active_color : color,
margin,
layer: theme.middle,
}),
},
})
}
-6
View File
@@ -1,6 +0,0 @@
import { interactive, Interactive } from "./interactive"
import { toggleable, Toggleable } from "./toggle"
export * from "./padding"
export * from "./margin"
export { interactive, Interactive, toggleable, Toggleable }
-56
View File
@@ -1,56 +0,0 @@
import {
NOT_ENOUGH_STATES_ERROR,
NO_DEFAULT_OR_BASE_ERROR,
interactive,
} from "./interactive"
import { describe, it, expect } from "vitest"
describe("interactive", () => {
it("creates an Interactive<Element> with base properties and states", () => {
const result = interactive({
base: { font_size: 10, color: "#FFFFFF" },
state: {
hovered: { color: "#EEEEEE" },
clicked: { color: "#CCCCCC" },
},
})
expect(result).toEqual({
default: { color: "#FFFFFF", font_size: 10 },
hovered: { color: "#EEEEEE", font_size: 10 },
clicked: { color: "#CCCCCC", font_size: 10 },
})
})
it("creates an Interactive<Element> with no base properties", () => {
const result = interactive({
state: {
default: { color: "#FFFFFF", font_size: 10 },
hovered: { color: "#EEEEEE" },
clicked: { color: "#CCCCCC" },
},
})
expect(result).toEqual({
default: { color: "#FFFFFF", font_size: 10 },
hovered: { color: "#EEEEEE", font_size: 10 },
clicked: { color: "#CCCCCC", font_size: 10 },
})
})
it("throws error when both default and base are missing", () => {
const state = {
hovered: { color: "blue" },
}
expect(() => interactive({ state })).toThrow(NO_DEFAULT_OR_BASE_ERROR)
})
it("throws error when no other state besides default is present", () => {
const state = {
default: { font_size: 10 },
}
expect(() => interactive({ state })).toThrow(NOT_ENOUGH_STATES_ERROR)
})
})
-97
View File
@@ -1,97 +0,0 @@
import merge from "ts-deepmerge"
import { DeepPartial } from "utility-types"
export type InteractiveState =
| "default"
| "hovered"
| "clicked"
| "selected"
| "disabled"
export type Interactive<T> = {
default: T
hovered?: T
clicked?: T
selected?: T
disabled?: T
}
export const NO_DEFAULT_OR_BASE_ERROR =
"An interactive object must have a default state, or a base property."
export const NOT_ENOUGH_STATES_ERROR =
"An interactive object must have a default and at least one other state."
interface InteractiveProps<T> {
base?: T
state: Partial<Record<InteractiveState, DeepPartial<T>>>
}
/**
* Helper function for creating Interactive<T> objects that works with Toggle<T>-like behavior.
* It takes a default object to be used as the value for `default` field and fills out other fields
* with fields from either `base` or from the `state` object which contains values for specific states.
* Notably, it does not touch `hover`, `clicked`, `selected` and `disabled` states if there are no modifications for them.
*
* @param defaultObj Object to be used as the value for the `default` field.
* @param base Optional object containing base fields to be included in the resulting object.
* @param state Object containing optional modified fields to be included in the resulting object for each state.
* @returns Interactive<T> object with fields from `base` and `state`.
*/
export function interactive<T extends object>({
base,
state,
}: InteractiveProps<T>): Interactive<T> {
if (!base && !state.default) throw new Error(NO_DEFAULT_OR_BASE_ERROR)
let default_state: T
if (state.default && base) {
default_state = merge(base, state.default) as T
} else {
default_state = base ? base : (state.default as T)
}
const interactive_obj: Interactive<T> = {
default: default_state,
}
let state_count = 0
if (state.hovered !== undefined) {
interactive_obj.hovered = merge(
interactive_obj.default,
state.hovered
) as T
state_count++
}
if (state.clicked !== undefined) {
interactive_obj.clicked = merge(
interactive_obj.default,
state.clicked
) as T
state_count++
}
if (state.selected !== undefined) {
interactive_obj.selected = merge(
interactive_obj.default,
state.selected
) as T
state_count++
}
if (state.disabled !== undefined) {
interactive_obj.disabled = merge(
interactive_obj.default,
state.disabled
) as T
state_count++
}
if (state_count < 1) {
throw new Error(NOT_ENOUGH_STATES_ERROR)
}
return interactive_obj
}
-41
View File
@@ -1,41 +0,0 @@
type MarginOptions = {
all?: number
left?: number
right?: number
top?: number
bottom?: number
}
export type MarginStyle = {
top: number
bottom: number
left: number
right: number
}
export const margin_style = (options: MarginOptions): MarginStyle => {
const { all, top, bottom, left, right } = options
if (all !== undefined)
return {
top: all,
bottom: all,
left: all,
right: all,
}
if (
top === undefined &&
bottom === undefined &&
left === undefined &&
right === undefined
)
throw new Error("Margin must have at least one value")
return {
top: top || 0,
bottom: bottom || 0,
left: left || 0,
right: right || 0,
}
}
-41
View File
@@ -1,41 +0,0 @@
type PaddingOptions = {
all?: number
left?: number
right?: number
top?: number
bottom?: number
}
export type PaddingStyle = {
top: number
bottom: number
left: number
right: number
}
export const padding_style = (options: PaddingOptions): PaddingStyle => {
const { all, top, bottom, left, right } = options
if (all !== undefined)
return {
top: all,
bottom: all,
left: all,
right: all,
}
if (
top === undefined &&
bottom === undefined &&
left === undefined &&
right === undefined
)
throw new Error("Padding must have at least one value")
return {
top: top || 0,
bottom: bottom || 0,
left: left || 0,
right: right || 0,
}
}
-52
View File
@@ -1,52 +0,0 @@
import {
NO_ACTIVE_ERROR,
NO_INACTIVE_OR_BASE_ERROR,
toggleable,
} from "./toggle"
import { describe, it, expect } from "vitest"
describe("toggleable", () => {
it("creates a Toggleable<Element> with base properties and states", () => {
const result = toggleable({
base: { background: "#000000", color: "#CCCCCC" },
state: {
active: { color: "#FFFFFF" },
},
})
expect(result).toEqual({
inactive: { background: "#000000", color: "#CCCCCC" },
active: { background: "#000000", color: "#FFFFFF" },
})
})
it("creates a Toggleable<Element> with no base properties", () => {
const result = toggleable({
state: {
inactive: { background: "#000000", color: "#CCCCCC" },
active: { background: "#000000", color: "#FFFFFF" },
},
})
expect(result).toEqual({
inactive: { background: "#000000", color: "#CCCCCC" },
active: { background: "#000000", color: "#FFFFFF" },
})
})
it("throws error when both inactive and base are missing", () => {
const state = {
active: { background: "#000000", color: "#FFFFFF" },
}
expect(() => toggleable({ state })).toThrow(NO_INACTIVE_OR_BASE_ERROR)
})
it("throws error when no active state is present", () => {
const state = {
inactive: { background: "#000000", color: "#CCCCCC" },
}
expect(() => toggleable({ state })).toThrow(NO_ACTIVE_ERROR)
})
})
-47
View File
@@ -1,47 +0,0 @@
import merge from "ts-deepmerge"
import { DeepPartial } from "utility-types"
type ToggleState = "inactive" | "active"
export type Toggleable<T> = Record<ToggleState, T>
export const NO_INACTIVE_OR_BASE_ERROR =
"A toggleable object must have an inactive state, or a base property."
export const NO_ACTIVE_ERROR = "A toggleable object must have an active state."
interface ToggleableProps<T> {
base?: T
state: Partial<Record<ToggleState, DeepPartial<T>>>
}
/**
* Helper function for creating Toggleable objects.
* @template T The type of the object being toggled.
* @param props Object containing the base (inactive) state and state modifications to create the active state.
* @returns A Toggleable object containing both the inactive and active states.
* @example
* ```
* toggleable({
* base: { background: "#000000", text: "#CCCCCC" },
* state: { active: { text: "#CCCCCC" } },
* })
* ```
*/
export function toggleable<T extends object>(
props: ToggleableProps<T>
): Toggleable<T> {
const { base, state } = props
if (!base && !state.inactive) throw new Error(NO_INACTIVE_OR_BASE_ERROR)
if (!state.active) throw new Error(NO_ACTIVE_ERROR)
const inactive_state = base
? ((state.inactive ? merge(base, state.inactive) : base) as T)
: (state.inactive as T)
const toggle_obj: Toggleable<T> = {
inactive: inactive_state,
active: merge(base ?? {}, state.active) as T,
}
return toggle_obj
}
-65
View File
@@ -1,65 +0,0 @@
import command_palette from "./command_palette"
import project_panel from "./project_panel"
import search from "./search"
import picker from "./picker"
import workspace from "./workspace"
import context_menu from "./context_menu"
import shared_screen from "./shared_screen"
import project_diagnostics from "./project_diagnostics"
import contact_notification from "./contact_notification"
import update_notification from "./update_notification"
import simple_message_notification from "./simple_message_notification"
import project_shared_notification from "./project_shared_notification"
import tooltip from "./tooltip"
import terminal from "./terminal"
import chat_panel from "./chat_panel"
import notification_panel from "./notification_panel"
import collab_panel from "./collab_panel"
import toolbar_dropdown_menu from "./toolbar_dropdown_menu"
import incoming_call_notification from "./incoming_call_notification"
import welcome from "./welcome"
import copilot from "./copilot"
import assistant from "./assistant"
import { titlebar } from "./titlebar"
import editor from "./editor"
import feedback from "./feedback"
import component_test from "./component_test"
import { useTheme } from "../common"
export default function app(): any {
const theme = useTheme()
return {
meta: {
name: theme.name,
is_light: theme.is_light,
},
command_palette: command_palette(),
contact_notification: contact_notification(),
project_shared_notification: project_shared_notification(),
incoming_call_notification: incoming_call_notification(),
picker: picker(),
workspace: workspace(),
titlebar: titlebar(),
copilot: copilot(),
welcome: welcome(),
context_menu: context_menu(),
editor: editor(),
project_diagnostics: project_diagnostics(),
project_panel: project_panel(),
collab_panel: collab_panel(),
toolbar_dropdown_menu: toolbar_dropdown_menu(),
search: search(),
shared_screen: shared_screen(),
update_notification: update_notification(),
simple_message_notification: simple_message_notification(),
tooltip: tooltip(),
terminal: terminal(),
assistant: assistant(),
feedback: feedback(),
chat_panel: chat_panel(),
notification_panel: notification_panel(),
component_test: component_test(),
base_theme: theme,
}
}
-398
View File
@@ -1,398 +0,0 @@
import { text, border, background, foreground, TextStyle } from "./components"
import { Interactive, interactive, toggleable } from "../element"
import { tab_bar_button } from "../component/tab_bar_button"
import { StyleSets, useTheme } from "../theme"
type RoleCycleButton = TextStyle & {
background?: string
}
// TODO: Replace these with zed types
type RemainingTokens = TextStyle & {
background: string
margin: { top: number; right: number }
padding: {
right: number
left: number
top: number
bottom: number
}
corner_radius: number
}
export default function assistant(): any {
const theme = useTheme()
const interactive_role = (
color: StyleSets,
): Interactive<RoleCycleButton> => {
return interactive({
base: {
...text(theme.highest, "sans", color, { size: "sm" }),
},
state: {
hovered: {
...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "hovered"),
},
clicked: {
...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "pressed"),
},
},
})
}
const tokens_remaining = (color: StyleSets): RemainingTokens => {
return {
...text(theme.highest, "mono", color, { size: "xs" }),
background: background(theme.highest, "on", "default"),
margin: { top: 12, right: 20 },
padding: { right: 4, left: 4, top: 1, bottom: 1 },
corner_radius: 6,
}
}
return {
container: {
background: background(theme.highest),
padding: { left: 12 },
},
inline: {
background: background(theme.highest),
margin: { top: 3, bottom: 3 },
border: border(theme.lowest, "on", {
top: true,
bottom: true,
overlay: true,
}),
editor: {
text: text(theme.highest, "mono", "default", { size: "sm" }),
placeholder_text: text(theme.highest, "sans", "on", "disabled"),
selection: theme.players[0],
},
disabled_editor: {
text: text(theme.highest, "mono", "disabled", { size: "sm" }),
placeholder_text: text(theme.highest, "sans", "on", "disabled"),
selection: {
cursor: text(theme.highest, "mono", "disabled").color,
selection: theme.players[0].selection,
},
},
pending_edit_background: background(theme.highest, "positive"),
context_status: {
error_icon: {
margin: { left: 8, right: 18 },
color: foreground(theme.highest, "negative"),
width: 12,
},
in_progress_icon: {
margin: { left: 8, right: 18 },
color: foreground(theme.highest, "positive"),
width: 12,
},
complete_icon: {
margin: { left: 8, right: 18 },
color: foreground(theme.highest, "positive"),
width: 12,
},
},
retrieve_context: toggleable({
base: interactive({
base: {
icon_size: 12,
color: foreground(theme.highest, "variant"),
button_width: 12,
background: background(theme.highest, "on"),
corner_radius: 2,
border: {
width: 1,
color: background(theme.highest, "on"),
},
margin: { left: 2 },
padding: {
left: 4,
right: 4,
top: 4,
bottom: 4,
},
},
state: {
hovered: {
...text(
theme.highest,
"mono",
"variant",
"hovered",
),
background: background(
theme.highest,
"on",
"hovered",
),
border: {
width: 1,
color: background(
theme.highest,
"on",
"hovered",
),
},
},
clicked: {
...text(
theme.highest,
"mono",
"variant",
"pressed",
),
background: background(
theme.highest,
"on",
"pressed",
),
border: {
width: 1,
color: background(
theme.highest,
"on",
"pressed",
),
},
},
},
}),
state: {
active: {
default: {
icon_size: 12,
button_width: 12,
color: foreground(theme.highest, "variant"),
background: background(theme.highest, "accent"),
border: border(theme.highest, "accent"),
},
hovered: {
background: background(
theme.highest,
"accent",
"hovered",
),
border: border(theme.highest, "accent", "hovered"),
},
clicked: {
background: background(
theme.highest,
"accent",
"pressed",
),
border: border(theme.highest, "accent", "pressed"),
},
},
},
}),
include_conversation: toggleable({
base: interactive({
base: {
icon_size: 12,
color: foreground(theme.highest, "variant"),
button_width: 12,
background: background(theme.highest, "on"),
corner_radius: 2,
border: {
width: 1,
color: background(theme.highest, "on"),
},
padding: {
left: 4,
right: 4,
top: 4,
bottom: 4,
},
},
state: {
hovered: {
...text(
theme.highest,
"mono",
"variant",
"hovered",
),
background: background(
theme.highest,
"on",
"hovered",
),
border: {
width: 1,
color: background(
theme.highest,
"on",
"hovered",
),
},
},
clicked: {
...text(
theme.highest,
"mono",
"variant",
"pressed",
),
background: background(
theme.highest,
"on",
"pressed",
),
border: {
width: 1,
color: background(
theme.highest,
"on",
"pressed",
),
},
},
},
}),
state: {
active: {
default: {
icon_size: 12,
button_width: 12,
color: foreground(theme.highest, "variant"),
background: background(theme.highest, "accent"),
border: border(theme.highest, "accent"),
},
hovered: {
background: background(
theme.highest,
"accent",
"hovered",
),
border: border(theme.highest, "accent", "hovered"),
},
clicked: {
background: background(
theme.highest,
"accent",
"pressed",
),
border: border(theme.highest, "accent", "pressed"),
},
},
},
}),
},
message_header: {
margin: { bottom: 4, top: 4 },
background: background(theme.highest),
},
hamburger_button: tab_bar_button(theme, {
icon: "icons/menu.svg",
}),
split_button: tab_bar_button(theme, {
icon: "icons/split_message.svg",
}),
quote_button: tab_bar_button(theme, {
icon: "icons/quote.svg",
}),
assist_button: tab_bar_button(theme, {
icon: "icons/magic-wand.svg",
}),
zoom_in_button: tab_bar_button(theme, {
icon: "icons/maximize.svg",
}),
zoom_out_button: tab_bar_button(theme, {
icon: "icons/minimize.svg",
}),
plus_button: tab_bar_button(theme, {
icon: "icons/plus.svg",
}),
title: {
...text(theme.highest, "sans", "default", { size: "xs" }),
},
saved_conversation: {
container: interactive({
base: {
background: background(theme.middle),
padding: { top: 4, bottom: 4 },
border: border(theme.middle, "default", {
top: true,
overlay: true,
}),
},
state: {
hovered: {
background: background(theme.middle, "hovered"),
},
clicked: {
background: background(theme.middle, "pressed"),
},
},
}),
saved_at: {
margin: { left: 8 },
...text(theme.highest, "sans", "variant", { size: "xs" }),
},
title: {
margin: { left: 12 },
...text(theme.highest, "sans", "default", {
size: "sm",
weight: "bold",
}),
},
},
user_sender: interactive_role("base"),
assistant_sender: interactive_role("accent"),
system_sender: interactive_role("warning"),
sent_at: {
margin: { top: 2, left: 8 },
...text(theme.highest, "sans", "variant", { size: "2xs" }),
},
model: interactive({
base: {
background: background(theme.highest),
margin: { left: 12, right: 4, top: 12 },
padding: { right: 4, left: 4, top: 1, bottom: 1 },
corner_radius: 4,
...text(theme.highest, "sans", "default", { size: "xs" }),
},
state: {
hovered: {
background: background(theme.highest, "on", "hovered"),
border: border(theme.highest, "on", { overlay: true }),
},
},
}),
remaining_tokens: tokens_remaining("positive"),
low_remaining_tokens: tokens_remaining("warning"),
no_remaining_tokens: tokens_remaining("negative"),
error_icon: {
margin: { left: 8 },
color: foreground(theme.highest, "negative"),
width: 12,
},
api_key_editor: {
background: background(theme.highest, "on"),
corner_radius: 4,
text: text(theme.highest, "mono", "on"),
placeholder_text: text(theme.highest, "mono", "on", "disabled", {
size: "xs",
}),
selection: theme.players[0],
border: border(theme.highest, "on"),
padding: {
bottom: 4,
left: 8,
right: 8,
top: 4,
},
},
api_key_prompt: {
padding: 10,
...text(theme.highest, "sans", "default", { size: "xs" }),
},
}
}
-160
View File
@@ -1,160 +0,0 @@
import { background, border, foreground, text } from "./components"
import { icon_button } from "../component/icon_button"
import { useTheme, with_opacity } from "../theme"
import { interactive } from "../element"
export default function chat_panel(): any {
const theme = useTheme()
const layer = theme.middle
const SPACING = 12 as const
const channel_name = {
padding: {
left: SPACING,
right: SPACING,
top: 4,
bottom: 4,
},
hash: {
...text(layer, "sans", "base"),
},
name: text(layer, "sans", "base"),
}
return {
background: background(layer),
avatar: {
icon_width: 24,
icon_height: 24,
corner_radius: 4,
outer_width: 24,
outer_corner_radius: 16,
},
avatar_container: {
padding: {
right: 6,
left: 2,
top: 2,
bottom: 2,
},
},
list: {},
channel_select: {
header: {
...channel_name,
border: border(layer, { bottom: true }),
},
item: channel_name,
active_item: {
...channel_name,
background: background(layer, "on", "active"),
},
hovered_item: {
...channel_name,
background: background(layer, "on", "hovered"),
},
menu: {
background: background(layer, "on"),
border: border(layer, { bottom: true }),
},
},
icon_button: icon_button({
variant: "ghost",
color: "variant",
size: "sm",
}),
input_editor: {
background: background(layer, "on"),
corner_radius: 6,
text: text(layer, "sans", "base"),
placeholder_text: text(layer, "sans", "base", "disabled", {
size: "xs",
}),
selection: theme.players[0],
border: border(layer, "on"),
margin: {
left: SPACING,
right: SPACING,
bottom: SPACING,
},
padding: {
bottom: 4,
left: 8,
right: 8,
top: 4,
},
},
rich_text: {
text: text(layer, "sans", "base"),
code_background: with_opacity(foreground(layer, "accent"), 0.1),
mention_highlight: { weight: "bold" },
self_mention_highlight: { weight: "bold" },
self_mention_background: background(layer, "active"),
},
message_sender: {
margin: {
right: 8,
},
...text(layer, "sans", "base", { weight: "bold" }),
},
message_timestamp: text(layer, "sans", "base", "disabled"),
message: {
...interactive({
base: {
margin: { top: SPACING },
padding: {
top: 4,
bottom: 4,
left: SPACING / 2,
right: SPACING / 3,
},
},
state: {
hovered: {
background: background(layer, "hovered"),
},
},
}),
},
last_message_bottom_spacing: SPACING,
continuation_message: {
...interactive({
base: {
padding: {
top: 4,
bottom: 4,
left: SPACING / 2,
right: SPACING / 3,
},
},
state: {
hovered: {
background: background(layer, "hovered"),
},
},
}),
},
pending_message: {
...interactive({
base: {
padding: {
top: 4,
bottom: 4,
left: SPACING / 2,
right: SPACING / 3,
},
},
state: {
hovered: {
background: background(layer, "hovered"),
},
},
}),
},
sign_in_prompt: {
default: text(layer, "sans", "base"),
},
}
}
-176
View File
@@ -1,176 +0,0 @@
import { StyleSets, useTheme } from "../theme"
import { background, border, foreground, text } from "./components"
import picker from "./picker"
import { input } from "../component/input"
import contact_finder from "./contact_finder"
import { tab } from "../component/tab"
import { icon_button } from "../component/icon_button"
import { interactive } from "../element/interactive"
export default function channel_modal(): any {
const theme = useTheme()
const SPACING = 12 as const
const BUTTON_OFFSET = 6 as const
const ITEM_HEIGHT = 36 as const
const contact_button = {
background: background(theme.middle, "variant"),
color: foreground(theme.middle, "variant"),
icon_width: 8,
button_width: 16,
corner_radius: 8,
}
const picker_style = picker()
delete picker_style.shadow
delete picker_style.border
const picker_input = input()
const interactive_text = (styleset: StyleSets) =>
interactive({
base: {
padding: {
left: 8,
top: 8
},
...text(theme.middle, "sans", styleset, "default"),
}, state: {
hovered: {
...text(theme.middle, "sans", styleset, "hovered"),
},
clicked: {
...text(theme.middle, "sans", styleset, "active"),
}
}
})
const member_icon_style = icon_button({
variant: "ghost",
size: "sm",
}).default
return {
contact_finder: contact_finder(),
tabbed_modal: {
tab_button: tab({ layer: theme.middle }),
row_height: ITEM_HEIGHT,
header: {
background: background(theme.lowest),
border: border(theme.middle, {
bottom: true,
top: false,
left: false,
right: false,
}),
padding: {
top: SPACING,
left: SPACING - BUTTON_OFFSET,
right: SPACING - BUTTON_OFFSET,
},
corner_radii: {
top_right: 12,
top_left: 12,
},
},
body: {
background: background(theme.middle),
padding: {
top: SPACING - 4,
left: SPACING,
right: SPACING,
bottom: SPACING,
},
corner_radii: {
bottom_right: 12,
bottom_left: 12,
},
},
modal: {
background: background(theme.middle),
shadow: theme.modal_shadow,
corner_radius: 12,
padding: {
bottom: 0,
left: 0,
right: 0,
top: 0,
},
},
// FIXME: due to a bug in the picker's size calculation, this must be 600
max_height: 600,
max_width: 540,
title: {
...text(theme.middle, "sans", "on", { size: "lg" }),
padding: {
left: BUTTON_OFFSET,
},
},
visibility_toggle: interactive_text("base"),
channel_link: interactive_text("accent"),
picker: {
empty_container: {},
item: {
...picker_style.item,
margin: { left: SPACING, right: SPACING },
},
no_matches: picker_style.no_matches,
input_editor: picker_input,
empty_input_editor: picker_input,
header: picker_style.header,
footer: picker_style.footer,
},
},
channel_modal: {
// This is used for the icons that are rendered to the right of channel Members in both UIs
member_icon: member_icon_style,
// This is used for the icons that are rendered to the right of channel invites in both UIs
invitee_icon: member_icon_style,
remove_member_button: {
...text(theme.middle, "sans", { size: "xs" }),
background: background(theme.middle),
padding: {
left: 7,
right: 7,
},
},
cancel_invite_button: {
...text(theme.middle, "sans", { size: "xs" }),
background: background(theme.middle),
},
member_tag: {
...text(theme.middle, "sans", { size: "xs" }),
border: border(theme.middle, "active"),
background: background(theme.middle),
margin: {
left: 8,
},
padding: {
left: 4,
right: 4,
},
},
contact_avatar: {
corner_radius: 10,
width: 18,
},
contact_username: {
padding: {
left: 8,
},
},
contact_button: {
...contact_button,
hover: {
background: background(theme.middle, "variant", "hovered"),
},
},
disabled_contact_button: {
...contact_button,
background: background(theme.middle, "disabled"),
color: foreground(theme.middle, "disabled"),
},
},
}
}
-427
View File
@@ -1,427 +0,0 @@
import {
background,
border,
border_color,
foreground,
text,
} from "./components"
import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
import collab_modals from "./collab_modals"
import { icon_button, toggleable_icon_button } from "../component/icon_button"
import { indicator } from "../component/indicator"
export default function contacts_panel(): any {
const theme = useTheme()
const CHANNEL_SPACING = 4 as const
const NAME_MARGIN = 6 as const
const SPACING = 12 as const
const INDENT_SIZE = 8 as const
const ITEM_HEIGHT = 28 as const
const layer = theme.middle
const contact_button = {
background: background(layer, "on"),
color: foreground(layer, "on"),
icon_width: 14,
button_width: 16,
corner_radius: 8,
}
const project_row = {
guest_avatar_spacing: 4,
height: 24,
guest_avatar: {
corner_radius: 8,
width: 14,
},
name: {
...text(layer, "sans", { size: "sm" }),
margin: {
left: NAME_MARGIN,
right: 4,
},
},
guests: {
margin: {
left: NAME_MARGIN,
right: NAME_MARGIN,
},
},
padding: {
left: SPACING,
right: SPACING,
},
}
const icon_style = {
color: foreground(layer, "variant"),
width: 14,
}
const header_icon_button = toggleable_icon_button({
variant: "ghost",
size: "sm",
active_layer: theme.lowest,
})
const subheader_row = toggleable({
base: interactive({
base: {
...text(layer, "sans", { size: "sm" }),
padding: {
left: SPACING,
right: SPACING,
},
},
state: {
hovered: {
background: background(layer, "hovered"),
},
clicked: {
background: background(layer, "pressed"),
},
},
}),
state: {
active: {
default: {
...text(theme.lowest, "sans", { size: "sm" }),
background: background(theme.lowest),
},
clicked: {
background: background(layer, "pressed"),
},
},
},
})
const filter_input = {
background: background(layer, "on"),
corner_radius: 6,
text: text(layer, "sans", "base"),
placeholder_text: text(layer, "sans", "base", "disabled", {
size: "xs",
}),
selection: theme.players[0],
border: border(layer, "on"),
padding: {
bottom: 4,
left: 8,
right: 8,
top: 4,
},
margin: {
left: SPACING,
right: SPACING,
},
}
const item_row = toggleable({
base: interactive({
base: {
padding: {
left: SPACING,
right: SPACING,
},
},
state: {
clicked: {
background: background(layer, "pressed"),
},
},
}),
state: {
inactive: {
hovered: {
background: background(layer, "hovered"),
},
},
active: {
default: {
...text(theme.lowest, "sans", { size: "sm" }),
background: background(theme.lowest),
},
clicked: {
background: background(layer, "pressed"),
},
},
},
})
return {
...collab_modals(),
disclosure: {
button: icon_button({ variant: "ghost", size: "sm" }),
spacing: CHANNEL_SPACING,
},
log_in_button: interactive({
base: {
background: background(theme.middle),
border: border(theme.middle, "active"),
corner_radius: 4,
margin: {
top: 4,
left: 16,
right: 16,
},
padding: {
top: 3,
bottom: 3,
left: 7,
right: 7,
},
...text(theme.middle, "sans", "default", { size: "sm" }),
},
state: {
hovered: {
...text(theme.middle, "sans", "default", { size: "sm" }),
background: background(theme.middle, "hovered"),
border: border(theme.middle, "active"),
},
clicked: {
...text(theme.middle, "sans", "default", { size: "sm" }),
background: background(theme.middle, "pressed"),
border: border(theme.middle, "active"),
},
},
}),
background: background(layer),
padding: {
top: SPACING,
},
user_query_editor: filter_input,
channel_hash: icon_style,
channel_note_active_color: foreground(layer, "active"),
user_query_editor_height: 33,
add_contact_button: header_icon_button,
add_channel_button: header_icon_button,
leave_call_button: header_icon_button,
row_height: ITEM_HEIGHT,
channel_indent: INDENT_SIZE * 2 + 2,
section_icon_size: 14,
header_row: {
...text(layer, "sans", { size: "sm", weight: "bold" }),
margin: { top: SPACING },
padding: {
left: SPACING,
right: SPACING,
},
},
dragged_over_header: {
margin: { top: SPACING },
padding: {
left: SPACING,
right: SPACING,
},
background: background(layer, "hovered"),
},
subheader_row,
leave_call: interactive({
base: {
background: background(layer),
border: border(layer),
corner_radius: 6,
margin: {
top: 1,
},
padding: {
top: 1,
bottom: 1,
left: 7,
right: 7,
},
...text(layer, "sans", "variant", { size: "xs" }),
},
state: {
hovered: {
...text(layer, "sans", "hovered", { size: "xs" }),
background: background(layer, "hovered"),
border: border(layer, "hovered"),
},
},
}),
contact_row: toggleable({
base: interactive({
base: {
padding: {
left: SPACING,
right: SPACING,
},
},
state: {
clicked: {
background: background(layer, "pressed"),
},
},
}),
state: {
inactive: {
hovered: {
background: background(layer, "hovered"),
},
},
active: {
default: {
...text(theme.lowest, "sans", { size: "sm" }),
background: background(theme.lowest),
},
clicked: {
background: background(layer, "pressed"),
},
},
},
}),
channel_row: item_row,
channel_name: {
active: {
...text(layer, "sans", { size: "sm", weight: "bold" }),
margin: {
left: CHANNEL_SPACING,
},
},
inactive: {
...text(layer, "sans", { size: "sm" }),
margin: {
left: CHANNEL_SPACING,
},
},
},
list_empty_label_container: {
margin: {
left: NAME_MARGIN,
},
},
list_empty_icon: {
color: foreground(layer, "variant"),
width: 14,
},
list_empty_state: toggleable({
base: interactive({
base: {
...text(layer, "sans", "variant", { size: "sm" }),
padding: {
top: SPACING / 2,
bottom: SPACING / 2,
left: SPACING,
right: SPACING,
},
},
state: {
clicked: {
background: background(layer, "pressed"),
},
},
}),
state: {
inactive: {
hovered: {
background: background(layer, "hovered"),
},
},
active: {
default: {
...text(theme.lowest, "sans", { size: "sm" }),
background: background(theme.lowest),
},
clicked: {
background: background(layer, "pressed"),
},
},
},
}),
contact_avatar: {
corner_radius: 10,
width: 20,
},
channel_avatar: {
corner_radius: 10,
width: 20,
},
extra_participant_label: {
corner_radius: 10,
padding: {
left: 10,
right: 4,
},
background: background(layer, "hovered"),
...text(layer, "sans", "hovered", { size: "xs" }),
},
contact_status_free: indicator({ layer, color: "positive" }),
contact_status_busy: indicator({ layer, color: "negative" }),
contact_username: {
...text(layer, "sans", { size: "sm" }),
margin: {
left: NAME_MARGIN,
},
},
contact_button_spacing: NAME_MARGIN,
contact_button: icon_button({
variant: "ghost",
color: "variant",
size: "sm",
}),
disabled_button: {
...contact_button,
background: background(layer, "on"),
color: foreground(layer, "on"),
},
calling_indicator: {
...text(layer, "sans", "variant", { size: "xs" }),
},
tree_branch: toggleable({
base: interactive({
base: {
color: border_color(layer),
width: 1,
},
state: {
hovered: {
color: border_color(layer),
},
},
}),
state: {
active: {
default: {
color: border_color(layer),
},
},
},
}),
project_row: toggleable({
base: interactive({
base: {
...project_row,
icon: {
margin: { left: NAME_MARGIN },
color: foreground(layer, "variant"),
width: 14,
},
name: {
...project_row.name,
...text(layer, "sans", { size: "sm" }),
},
},
state: {
hovered: {
background: background(layer, "hovered"),
},
},
}),
state: {
active: {
default: { background: background(theme.lowest) },
},
},
}),
face_overlap: 8,
channel_editor: {
padding: {
left: NAME_MARGIN,
},
},
}
}
-46
View File
@@ -1,46 +0,0 @@
import { with_opacity } from "../theme/color"
import { text, background } from "./components"
import { toggleable } from "../element"
import { useTheme } from "../theme"
export default function command_palette(): any {
const theme = useTheme()
const key = toggleable({
base: {
text: text(theme.highest, "mono", "variant", "default", {
size: "xs",
}),
corner_radius: 2,
background: background(theme.highest, "on"),
padding: {
top: 1,
bottom: 1,
left: 6,
right: 6,
},
margin: {
top: 1,
bottom: 1,
left: 2,
},
},
state: {
active: {
text: text(theme.highest, "mono", "on", "default", {
size: "xs",
}),
background: with_opacity(background(theme.highest, "on"), 0.2),
},
},
})
return {
keystroke_spacing: 8,
// TODO: This should be a Toggle<ContainedText> on the rust side so we don't have to do this
key: {
inactive: { ...key.inactive },
active: key.active,
},
}
}
-27
View File
@@ -1,27 +0,0 @@
import { useTheme } from "../common"
import { text_button } from "../component/text_button"
import { icon_button } from "../component/icon_button"
import { text } from "./components"
import { toggleable } from "../element"
export default function contacts_panel(): any {
const theme = useTheme()
return {
button: text_button({}),
toggle: toggleable({
base: text_button({}),
state: {
active: {
...text_button({ color: "accent" }),
},
},
}),
disclosure: {
...text(theme.lowest, "sans", "base"),
button: icon_button({ variant: "ghost" }),
spacing: 4,
padding: 4,
},
}
}
-302
View File
@@ -1,302 +0,0 @@
import { font_families, font_sizes, FontWeight } from "../common"
import { Layer, Styles, StyleSets, Style } from "../theme/create_theme"
function is_style_set(key: any): key is StyleSets {
return [
"base",
"variant",
"on",
"accent",
"positive",
"warning",
"negative",
].includes(key)
}
function is_style(key: any): key is Styles {
return [
"default",
"active",
"disabled",
"hovered",
"pressed",
"inverted",
].includes(key)
}
function get_style(
layer: Layer,
possible_style_set_or_style?: any,
possible_style?: any
): Style {
let style_set: StyleSets = "base"
let style: Styles = "default"
if (is_style_set(possible_style_set_or_style)) {
style_set = possible_style_set_or_style
} else if (is_style(possible_style_set_or_style)) {
style = possible_style_set_or_style
}
if (is_style(possible_style)) {
style = possible_style
}
return layer[style_set][style]
}
export function background(layer: Layer, style?: Styles): string
export function background(
layer: Layer,
style_set?: StyleSets,
style?: Styles
): string
export function background(
layer: Layer,
style_set_or_styles?: StyleSets | Styles,
style?: Styles
): string {
return get_style(layer, style_set_or_styles, style).background
}
export function border_color(layer: Layer, style?: Styles): string
export function border_color(
layer: Layer,
style_set?: StyleSets,
style?: Styles
): string
export function border_color(
layer: Layer,
style_set_or_styles?: StyleSets | Styles,
style?: Styles
): string {
return get_style(layer, style_set_or_styles, style).border
}
export function foreground(layer: Layer, style?: Styles): string
export function foreground(
layer: Layer,
style_set?: StyleSets,
style?: Styles
): string
export function foreground(
layer: Layer,
style_set_or_styles?: StyleSets | Styles,
style?: Styles
): string {
return get_style(layer, style_set_or_styles, style).foreground
}
export interface TextStyle extends Object {
family: keyof typeof font_families
color: string
size: number
weight?: FontWeight
underline?: boolean
}
export interface TextProperties {
size?: keyof typeof font_sizes
weight?: FontWeight
underline?: boolean
color?: string
features?: FontFeatures
}
interface FontFeatures {
/** Contextual Alternates: Applies a second substitution feature based on a match of a character pattern within a context of surrounding patterns */
calt?: boolean
/** Case-Sensitive Forms: Shifts various punctuation marks up to a position that works better with all-capital sequences */
case?: boolean
/** Capital Spacing: Adjusts inter-glyph spacing for all-capital text */
cpsp?: boolean
/** Fractions: Replaces figures separated by a slash with diagonal fractions */
frac?: boolean
/** Standard Ligatures: Replaces a sequence of glyphs with a single glyph which is preferred for typographic purposes */
liga?: boolean
/** Oldstyle Figures: Changes selected figures from the default or lining style to oldstyle form. */
onum?: boolean
/** Ordinals: Replaces default alphabetic glyphs with the corresponding ordinal forms for use after figures */
ordn?: boolean
/** Proportional Figures: Replaces figure glyphs set on uniform (tabular) widths with corresponding glyphs set on proportional widths */
pnum?: boolean
/** Stylistic set 01 */
ss01?: boolean
/** Stylistic set 02 */
ss02?: boolean
/** Stylistic set 03 */
ss03?: boolean
/** Stylistic set 04 */
ss04?: boolean
/** Stylistic set 05 */
ss05?: boolean
/** Stylistic set 06 */
ss06?: boolean
/** Stylistic set 07 */
ss07?: boolean
/** Stylistic set 08 */
ss08?: boolean
/** Stylistic set 09 */
ss09?: boolean
/** Stylistic set 10 */
ss10?: boolean
/** Stylistic set 11 */
ss11?: boolean
/** Stylistic set 12 */
ss12?: boolean
/** Stylistic set 13 */
ss13?: boolean
/** Stylistic set 14 */
ss14?: boolean
/** Stylistic set 15 */
ss15?: boolean
/** Stylistic set 16 */
ss16?: boolean
/** Stylistic set 17 */
ss17?: boolean
/** Stylistic set 18 */
ss18?: boolean
/** Stylistic set 19 */
ss19?: boolean
/** Stylistic set 20 */
ss20?: boolean
/** Subscript: Replaces default glyphs with subscript glyphs */
subs?: boolean
/** Superscript: Replaces default glyphs with superscript glyphs */
sups?: boolean
/** Swash: Replaces default glyphs with swash glyphs for stylistic purposes */
swsh?: boolean
/** Titling: Replaces default glyphs with titling glyphs for use in large-size settings */
titl?: boolean
/** Tabular Figures: Replaces figure glyphs set on proportional widths with corresponding glyphs set on uniform (tabular) widths */
tnum?: boolean
/** Slashed Zero: Replaces default zero with a slashed zero for better distinction between "0" and "O" */
zero?: boolean
}
export function text(
layer: Layer,
font_family: keyof typeof font_families,
style_set: StyleSets,
style: Styles,
properties?: TextProperties
): TextStyle
export function text(
layer: Layer,
font_family: keyof typeof font_families,
style_set: StyleSets,
properties?: TextProperties
): TextStyle
export function text(
layer: Layer,
font_family: keyof typeof font_families,
style: Styles,
properties?: TextProperties
): TextStyle
export function text(
layer: Layer,
font_family: keyof typeof font_families,
properties?: TextProperties
): TextStyle
export function text(
layer: Layer,
font_family: keyof typeof font_families,
style_set_style_or_properties?: StyleSets | Styles | TextProperties,
style_or_properties?: Styles | TextProperties,
properties?: TextProperties
) {
const style = get_style(
layer,
style_set_style_or_properties,
style_or_properties
)
if (typeof style_set_style_or_properties === "object") {
properties = style_set_style_or_properties
}
if (typeof style_or_properties === "object") {
properties = style_or_properties
}
const size = font_sizes[properties?.size || "sm"]
const color = properties?.color || style.foreground
return {
family: font_families[font_family],
...properties,
color,
size,
}
}
export interface Border {
color: string
width: number
top?: boolean
bottom?: boolean
left?: boolean
right?: boolean
overlay?: boolean
}
export interface BorderProperties {
width?: number
top?: boolean
bottom?: boolean
left?: boolean
right?: boolean
overlay?: boolean
}
export function border(
layer: Layer,
style_set: StyleSets,
style: Styles,
properties?: BorderProperties
): Border
export function border(
layer: Layer,
style_set: StyleSets,
properties?: BorderProperties
): Border
export function border(
layer: Layer,
style: Styles,
properties?: BorderProperties
): Border
export function border(layer: Layer, properties?: BorderProperties): Border
export function border(
layer: Layer,
style_set_or_properties?: StyleSets | Styles | BorderProperties,
style_or_properties?: Styles | BorderProperties,
properties?: BorderProperties
): Border {
const style = get_style(layer, style_set_or_properties, style_or_properties)
if (typeof style_set_or_properties === "object") {
properties = style_set_or_properties
}
if (typeof style_or_properties === "object") {
properties = style_or_properties
}
return {
color: style.border,
width: 1,
...properties,
}
}
export function svg(
color: string,
asset: string,
width: number,
height: number
) {
return {
color,
asset,
dimensions: {
width,
height,
},
}
}
-74
View File
@@ -1,74 +0,0 @@
// import picker from "./picker"
import { background, border, foreground, text } from "./components"
import { useTheme } from "../theme"
export default function contact_finder(): any {
const theme = useTheme()
// const side_margin = 6
const contact_button = {
background: background(theme.middle, "variant"),
color: foreground(theme.middle, "variant"),
icon_width: 8,
button_width: 16,
corner_radius: 8,
}
// const picker_style = picker()
// const picker_input = {
// background: background(theme.middle, "on"),
// corner_radius: 6,
// text: text(theme.middle, "mono"),
// placeholder_text: text(theme.middle, "mono", "on", "disabled", {
// size: "xs",
// }),
// selection: theme.players[0],
// border: border(theme.middle),
// padding: {
// bottom: 4,
// left: 8,
// right: 8,
// top: 4,
// },
// margin: {
// left: side_margin,
// right: side_margin,
// },
// }
return {
// picker: {
// empty_container: {},
// item: {
// ...picker_style.item,
// margin: { left: side_margin, right: side_margin },
// },
// no_matches: picker_style.no_matches,
// input_editor: picker_input,
// empty_input_editor: picker_input,
// header: picker_style.header,
// footer: picker_style.footer,
// },
// row_height: 28,
contact_avatar: {
corner_radius: 10,
width: 18,
},
contact_username: {
padding: {
left: 8,
},
},
contact_button: {
...contact_button,
hover: {
background: background(theme.middle, "variant", "hovered"),
},
},
disabled_contact_button: {
...contact_button,
background: background(theme.middle, "disabled"),
color: foreground(theme.middle, "disabled"),
},
}
}
@@ -1,55 +0,0 @@
import { background, foreground, text } from "./components"
import { interactive } from "../element"
import { useTheme } from "../theme"
export default function contact_notification(): any {
const theme = useTheme()
const avatar_size = 12
const header_padding = 8
return {
header_avatar: {
height: avatar_size,
width: avatar_size,
corner_radius: 6,
},
header_message: {
...text(theme.lowest, "sans", { size: "xs" }),
margin: { left: header_padding, right: header_padding },
},
header_height: 18,
body_message: {
...text(theme.lowest, "sans", { size: "xs" }),
margin: { left: avatar_size + header_padding, top: 6, bottom: 6 },
},
button: interactive({
base: {
...text(theme.lowest, "sans", "on", { size: "xs" }),
background: background(theme.lowest, "on"),
padding: 4,
corner_radius: 6,
margin: { left: 6 },
},
state: {
hovered: {
background: background(theme.lowest, "on", "hovered"),
},
},
}),
dismiss_button: {
default: {
color: foreground(theme.lowest, "variant"),
icon_width: 14,
icon_height: 14,
button_width: 14,
button_height: 14,
hover: {
color: foreground(theme.lowest, "hovered"),
},
},
},
}
}
@@ -1,6 +0,0 @@
import { useTheme } from "../theme"
import { background, border } from "./components"
export default function contacts_popover(): any {
const theme = useTheme()
}
-60
View File
@@ -1,60 +0,0 @@
import { background, border, border_color, text } from "./components"
import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
export default function context_menu(): any {
const theme = useTheme()
return {
background: background(theme.middle),
corner_radius: 10,
padding: 4,
shadow: theme.popover_shadow,
border: border(theme.middle),
keystroke_margin: 30,
item: toggleable({
base: interactive({
base: {
icon_spacing: 8,
icon_width: 14,
padding: { left: 6, right: 6, top: 2, bottom: 2 },
corner_radius: 6,
label: text(theme.middle, "sans", { size: "sm" }),
keystroke: {
...text(theme.middle, "sans", "variant", {
size: "sm",
weight: "bold",
}),
padding: { left: 3, right: 3 },
},
},
state: {
hovered: {
background: background(theme.middle, "hovered"),
},
clicked: {
background: background(theme.middle, "pressed"),
},
},
}),
state: {
active: {
default: {
background: background(theme.middle, "active"),
},
hovered: {
background: background(theme.middle, "hovered"),
},
clicked: {
background: background(theme.middle, "pressed"),
},
},
},
}),
separator: {
background: border_color(theme.middle),
margin: { top: 2, bottom: 2 },
},
}
}
-293
View File
@@ -1,293 +0,0 @@
import { background, border, foreground, svg, text } from "./components"
import { interactive } from "../element"
import { useTheme } from "../theme"
export default function copilot(): any {
const theme = useTheme()
const content_width = 264
const cta_button =
// Copied from welcome screen. FIXME: Move this into a ZDS component
interactive({
base: {
background: background(theme.middle),
border: border(theme.middle, "default"),
corner_radius: 4,
margin: {
top: 4,
bottom: 4,
left: 8,
right: 8,
},
padding: {
top: 3,
bottom: 3,
left: 7,
right: 7,
},
...text(theme.middle, "sans", "default", { size: "sm" }),
},
state: {
hovered: {
...text(theme.middle, "sans", "default", { size: "sm" }),
background: background(theme.middle, "hovered"),
border: border(theme.middle, "active"),
},
},
})
return {
out_link_icon: interactive({
base: {
icon: svg(
foreground(theme.middle, "variant"),
"icons/external_link.svg",
12,
12
),
container: {
corner_radius: 6,
padding: { left: 6 },
},
},
state: {
hovered: {
icon: {
color: foreground(theme.middle, "hovered"),
},
},
},
}),
modal: {
title_text: {
default: {
...text(theme.middle, "sans", {
size: "xs",
weight: "bold",
}),
},
},
titlebar: {
background: background(theme.lowest),
border: border(theme.middle, "active"),
padding: {
top: 4,
bottom: 4,
left: 8,
right: 8,
},
},
container: {
background: background(theme.lowest),
padding: {
top: 0,
left: 0,
right: 0,
bottom: 8,
},
},
close_icon: interactive({
base: {
icon: svg(
foreground(theme.middle, "variant"),
"icons/x.svg",
8,
8
),
container: {
corner_radius: 2,
padding: {
top: 4,
bottom: 4,
left: 4,
right: 4,
},
margin: {
right: 0,
},
},
},
state: {
hovered: {
icon: svg(
foreground(theme.middle, "on"),
"icons/x.svg",
8,
8
),
},
clicked: {
icon: svg(
foreground(theme.middle, "base"),
"icons/x.svg",
8,
8
),
},
},
}),
dimensions: {
width: 280,
height: 280,
},
},
auth: {
content_width,
cta_button,
header: {
icon: svg(
foreground(theme.middle, "default"),
"icons/zed_x_copilot.svg",
92,
32
),
container: {
margin: {
top: 35,
bottom: 5,
left: 0,
right: 0,
},
},
},
prompting: {
subheading: {
...text(theme.middle, "sans", { size: "xs" }),
margin: {
top: 6,
bottom: 12,
left: 0,
right: 0,
},
},
hint: {
...text(theme.middle, "sans", {
size: "xs",
color: "#838994",
}),
margin: {
top: 6,
bottom: 2,
},
},
device_code: {
text: text(theme.middle, "mono", { size: "sm" }),
cta: {
...cta_button,
background: background(theme.lowest),
border: border(theme.lowest, "inverted"),
padding: {
top: 0,
bottom: 0,
left: 16,
right: 16,
},
margin: {
left: 16,
right: 16,
},
},
left: content_width / 2,
left_container: {
padding: {
top: 3,
bottom: 3,
left: 0,
right: 6,
},
},
right: (content_width * 1) / 3,
right_container: interactive({
base: {
border: border(theme.lowest, "inverted", {
bottom: false,
right: false,
top: false,
left: true,
}),
padding: {
top: 3,
bottom: 5,
left: 8,
right: 0,
},
},
state: {
hovered: {
border: border(theme.middle, "active", {
bottom: false,
right: false,
top: false,
left: true,
}),
},
},
}),
},
},
not_authorized: {
subheading: {
...text(theme.middle, "sans", { size: "xs" }),
margin: {
top: 16,
bottom: 16,
left: 0,
right: 0,
},
},
warning: {
...text(theme.middle, "sans", {
size: "xs",
color: foreground(theme.middle, "warning"),
}),
border: border(theme.middle, "warning"),
background: background(theme.middle, "warning"),
corner_radius: 2,
padding: {
top: 4,
left: 4,
bottom: 4,
right: 4,
},
margin: {
bottom: 16,
left: 8,
right: 8,
},
},
},
authorized: {
subheading: {
...text(theme.middle, "sans", { size: "xs" }),
margin: {
top: 16,
bottom: 16,
},
},
hint: {
...text(theme.middle, "sans", {
size: "xs",
color: "#838994",
}),
margin: {
top: 24,
bottom: 4,
},
},
},
},
}
}
-327
View File
@@ -1,327 +0,0 @@
import { with_opacity } from "../theme/color"
import { Layer, StyleSets } from "../theme/create_theme"
import {
background,
border,
border_color,
foreground,
text,
} from "./components"
import hover_popover from "./hover_popover"
import { build_syntax } from "../theme/syntax"
import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
export default function editor(): any {
const theme = useTheme()
const { is_light } = theme
const layer = theme.highest
const autocomplete_item = {
corner_radius: 6,
padding: {
bottom: 2,
left: 6,
right: 6,
top: 2,
},
}
function diagnostic(layer: Layer, style_set: StyleSets) {
return {
text_scale_factor: 0.857,
header: {
border: border(layer, {
top: true,
}),
},
message: {
text: text(layer, "sans", style_set, "default", { size: "sm" }),
highlight_text: text(layer, "sans", style_set, "default", {
size: "sm",
weight: "bold",
}),
},
}
}
const syntax = build_syntax()
return {
text_color: syntax.primary.color,
background: background(layer),
active_line_background: with_opacity(background(layer, "on"), 0.75),
highlighted_line_background: background(layer, "on"),
// Inline autocomplete suggestions, Co-pilot suggestions, etc.
hint: syntax.hint,
suggestion: syntax.predictive,
code_actions: {
indicator: toggleable({
base: interactive({
base: {
color: foreground(layer, "variant"),
},
state: {
hovered: {
color: foreground(layer, "variant", "hovered"),
},
clicked: {
color: foreground(layer, "variant", "pressed"),
},
},
}),
state: {
active: {
default: {
color: foreground(layer, "accent"),
},
hovered: {
color: foreground(layer, "accent", "hovered"),
},
clicked: {
color: foreground(layer, "accent", "pressed"),
},
},
},
}),
vertical_scale: 0.55,
},
folds: {
icon_margin_scale: 4,
folded_icon: "icons/chevron_right.svg",
foldable_icon: "icons/chevron_down.svg",
indicator: toggleable({
base: interactive({
base: {
color: foreground(layer, "variant"),
},
state: {
hovered: {
color: foreground(layer, "on"),
},
clicked: {
color: foreground(layer, "base"),
},
},
}),
state: {
active: {
default: {
color: foreground(layer, "default"),
},
hovered: {
color: foreground(layer, "on"),
},
},
},
}),
ellipses: {
text_color: theme.ramps.neutral(0.71).hex(),
corner_radius_factor: 0.15,
background: {
// Copied from hover_popover highlight
default: {
color: theme.ramps.neutral(0.5).alpha(0.0).hex(),
},
hovered: {
color: theme.ramps.neutral(0.5).alpha(0.5).hex(),
},
clicked: {
color: theme.ramps.neutral(0.5).alpha(0.7).hex(),
},
},
},
fold_background: foreground(layer, "variant"),
},
diff: {
deleted: is_light
? theme.ramps.red(0.5).hex()
: theme.ramps.red(0.4).hex(),
modified: is_light
? theme.ramps.yellow(0.5).hex()
: theme.ramps.yellow(0.5).hex(),
inserted: is_light
? theme.ramps.green(0.4).hex()
: theme.ramps.green(0.5).hex(),
removed_width_em: 0.275,
width_em: 0.15,
corner_radius: 0.05,
},
/** Highlights matching occurrences of what is under the cursor
* as well as matched brackets
*/
document_highlight_read_background: with_opacity(
foreground(layer, "accent"),
0.1
),
document_highlight_write_background: theme.ramps
.neutral(0.5)
.alpha(0.4)
.hex(), // TODO: This was blend * 2
error_color: background(layer, "negative"),
gutter_background: background(layer),
gutter_padding_factor: 3.5,
line_number: with_opacity(foreground(layer), 0.35),
line_number_active: foreground(layer),
rename_fade: 0.6,
wrap_guide: with_opacity(foreground(layer), 0.05),
active_wrap_guide: with_opacity(foreground(layer), 0.1),
unnecessary_code_fade: 0.5,
selection: theme.players[0],
whitespace: theme.ramps.neutral(0.5).hex(),
guest_selections: [
theme.players[1],
theme.players[2],
theme.players[3],
theme.players[4],
theme.players[5],
theme.players[6],
theme.players[7],
],
absent_selection: theme.players[7],
autocomplete: {
background: background(theme.middle),
corner_radius: 8,
padding: 4,
margin: {
left: -14,
},
border: border(theme.middle),
shadow: theme.popover_shadow,
match_highlight: foreground(theme.middle, "accent"),
item: autocomplete_item,
hovered_item: {
...autocomplete_item,
match_highlight: foreground(theme.middle, "accent", "hovered"),
background: background(theme.middle, "hovered"),
},
selected_item: {
...autocomplete_item,
match_highlight: foreground(theme.middle, "accent", "active"),
background: background(theme.middle, "active"),
},
completion_min_width: 300,
completion_max_width: 700,
inline_docs_container: { padding: { left: 40 } },
inline_docs_color: text(theme.middle, "sans", "disabled", {}).color,
inline_docs_size_percent: 0.75,
alongside_docs_max_width: 700,
alongside_docs_container: { padding: autocomplete_item.padding }
},
diagnostic_header: {
background: background(theme.middle),
icon_width_factor: 1.5,
text_scale_factor: 0.857,
border: border(theme.middle, {
bottom: true,
top: true,
}),
code: {
...text(theme.middle, "mono", { size: "sm" }),
margin: {
left: 10,
},
},
source: {
text: text(theme.middle, "sans", {
size: "sm",
weight: "bold",
}),
},
message: {
highlight_text: text(theme.middle, "sans", {
size: "sm",
weight: "bold",
}),
text: text(theme.middle, "sans", { size: "sm" }),
},
},
diagnostic_path_header: {
background: background(theme.middle),
text_scale_factor: 0.857,
filename: text(theme.middle, "mono", { size: "sm" }),
path: {
...text(theme.middle, "mono", { size: "sm" }),
margin: {
left: 12,
},
},
},
error_diagnostic: diagnostic(theme.middle, "negative"),
warning_diagnostic: diagnostic(theme.middle, "warning"),
information_diagnostic: diagnostic(theme.middle, "accent"),
hint_diagnostic: diagnostic(theme.middle, "warning"),
invalid_error_diagnostic: diagnostic(theme.middle, "base"),
invalid_hint_diagnostic: diagnostic(theme.middle, "base"),
invalid_information_diagnostic: diagnostic(theme.middle, "base"),
invalid_warning_diagnostic: diagnostic(theme.middle, "base"),
hover_popover: hover_popover(),
link_definition: {
color: syntax.link_uri.color,
underline: syntax.link_uri.underline,
},
jump_icon: interactive({
base: {
color: foreground(layer, "on"),
icon_width: 20,
button_width: 20,
corner_radius: 6,
padding: {
top: 6,
bottom: 6,
left: 6,
right: 6,
},
},
state: {
hovered: {
background: background(layer, "on", "hovered"),
},
},
}),
scrollbar: {
width: 12,
min_height_factor: 1.0,
track: {
border: border(layer, "variant", { left: true }),
},
thumb: {
background: with_opacity(background(layer, "inverted"), 0.3),
border: {
width: 1,
color: border_color(layer, "variant"),
top: false,
right: true,
left: true,
bottom: false,
},
},
git: {
deleted: is_light
? with_opacity(theme.ramps.red(0.5).hex(), 0.8)
: with_opacity(theme.ramps.red(0.4).hex(), 0.8),
modified: is_light
? with_opacity(theme.ramps.yellow(0.5).hex(), 0.8)
: with_opacity(theme.ramps.yellow(0.4).hex(), 0.8),
inserted: is_light
? with_opacity(theme.ramps.green(0.5).hex(), 0.8)
: with_opacity(theme.ramps.green(0.4).hex(), 0.8),
},
selections: foreground(layer, "accent"),
},
composition_mark: {
underline: {
thickness: 1.0,
color: border_color(layer),
},
},
syntax,
}
}
-59
View File
@@ -1,59 +0,0 @@
import { background, border, text } from "./components"
import { interactive } from "../element"
import { useTheme } from "../theme"
export default function feedback(): any {
const theme = useTheme()
return {
submit_button: interactive({
base: {
...text(theme.highest, "mono", "on"),
background: background(theme.highest, "on"),
corner_radius: 6,
border: border(theme.highest, "on"),
padding: {
bottom: 2,
left: 10,
right: 10,
top: 2,
},
},
state: {
clicked: {
...text(theme.highest, "mono", "on", "pressed"),
background: background(theme.highest, "on", "pressed"),
border: border(theme.highest, "on", "pressed"),
},
hovered: {
...text(theme.highest, "mono", "on", "hovered"),
background: background(theme.highest, "on", "hovered"),
border: border(theme.highest, "on", "hovered"),
},
disabled: {
...text(theme.highest, "mono", "on", "disabled"),
background: background(theme.highest, "on", "disabled"),
border: border(theme.highest, "on", "disabled"),
},
},
}),
button_margin: 8,
info_text_default: {
padding: {
left: 4,
right: 4,
},
...text(theme.highest, "sans", "default", {
size: "xs",
})
},
link_text_default: text(theme.highest, "sans", "default", {
size: "xs",
underline: true,
}),
link_text_hover: text(theme.highest, "sans", "hovered", {
size: "xs",
underline: true,
}),
}
}
-49
View File
@@ -1,49 +0,0 @@
import { useTheme } from "../theme"
import { background, border, foreground, text } from "./components"
export default function hover_popover(): any {
const theme = useTheme()
const base_container = {
background: background(theme.middle),
corner_radius: 8,
padding: {
left: 8,
right: 8,
top: 4,
bottom: 4,
},
shadow: theme.popover_shadow,
border: border(theme.middle),
margin: {
left: -8,
},
}
return {
container: base_container,
info_container: {
...base_container,
background: background(theme.middle, "accent"),
border: border(theme.middle, "accent"),
},
warning_container: {
...base_container,
background: background(theme.middle, "warning"),
border: border(theme.middle, "warning"),
},
error_container: {
...base_container,
background: background(theme.middle, "negative"),
border: border(theme.middle, "negative"),
},
block_style: {
padding: { top: 4 },
},
prose: text(theme.middle, "sans", { size: "sm" }),
diagnostic_source_highlight: {
color: foreground(theme.middle, "accent"),
},
highlight: theme.ramps.neutral(0.5).alpha(0.2).hex(), // TODO: blend was used here. Replace with something better
}
}
@@ -1,55 +0,0 @@
import { useTheme } from "../theme"
import { background, border, text } from "./components"
export default function incoming_call_notification(): unknown {
const theme = useTheme()
const avatar_size = 48
return {
window_height: 74,
window_width: 380,
background: background(theme.middle),
caller_container: {
padding: 12,
},
caller_avatar: {
height: avatar_size,
width: avatar_size,
corner_radius: avatar_size / 2,
},
caller_metadata: {
margin: { left: 10 },
},
caller_username: {
...text(theme.middle, "sans", { size: "sm", weight: "bold" }),
margin: { top: -3 },
},
caller_message: {
...text(theme.middle, "sans", "variant", { size: "xs" }),
margin: { top: -3 },
},
worktree_roots: {
...text(theme.middle, "sans", "variant", {
size: "xs",
weight: "bold",
}),
margin: { top: -3 },
},
button_width: 96,
accept_button: {
background: background(theme.middle, "accent"),
border: border(theme.middle, { left: true, bottom: true }),
...text(theme.middle, "sans", "positive", {
size: "xs",
weight: "bold",
}),
},
decline_button: {
border: border(theme.middle, { left: true }),
...text(theme.middle, "sans", "negative", {
size: "xs",
weight: "bold",
}),
},
}
}
@@ -1,75 +0,0 @@
import { background, border, text } from "./components"
import { icon_button } from "../component/icon_button"
import { useTheme, with_opacity } from "../theme"
import { text_button } from "../component"
export default function (): any {
const theme = useTheme()
const layer = theme.middle
const notification_text = {
padding: { top: 4, bottom: 4 },
...text(layer, "sans", "base"),
}
const notification_read_text_color = with_opacity(
theme.middle.base.default.foreground,
0.6
)
return {
background: background(layer),
avatar: {
icon_width: 24,
icon_height: 24,
corner_radius: 12,
outer_width: 24,
outer_corner_radius: 24,
},
title: {
...text(layer, "sans", "default"),
padding: { left: 8, right: 8 },
border: border(layer, { bottom: true }),
},
title_height: 32,
title_icon: {
asset: "icons/feedback.svg",
color: text(theme.lowest, "sans", "default").color,
dimensions: {
width: 16,
height: 16,
},
},
read_text: {
...notification_text,
color: notification_read_text_color,
},
unread_text: notification_text,
button: text_button({
variant: "ghost",
}),
timestamp: text(layer, "sans", "base", "disabled"),
avatar_container: {
padding: {
right: 8,
left: 2,
top: 4,
bottom: 2,
},
},
list: {
padding: {
left: 8,
right: 8,
},
},
icon_button: icon_button({
variant: "ghost",
color: "variant",
size: "sm",
}),
sign_in_prompt: {
default: text(layer, "sans", "base"),
},
}
}
-158
View File
@@ -1,158 +0,0 @@
import { with_opacity } from "../theme/color"
import { background, border, text } from "./components"
import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
export default function picker(): any {
const theme = useTheme()
const container = {
background: background(theme.lowest),
border: border(theme.lowest),
shadow: theme.modal_shadow,
corner_radius: 12,
padding: {
bottom: 4,
},
}
const input_editor = {
placeholder_text: text(theme.lowest, "sans", "on", "disabled"),
selection: theme.players[0],
text: text(theme.lowest, "mono", "on"),
border: border(theme.lowest, { bottom: true }),
padding: {
bottom: 8,
left: 16,
right: 16,
top: 8,
},
margin: {
bottom: 4,
},
}
const empty_input_editor: any = { ...input_editor }
delete empty_input_editor.border
delete empty_input_editor.margin
return {
...container,
empty_container: {
...container,
padding: {},
},
item: toggleable({
base: interactive({
base: {
padding: {
bottom: 4,
left: 12,
right: 12,
top: 4,
},
margin: {
top: 1,
left: 4,
right: 4,
},
corner_radius: 8,
text: text(theme.lowest, "sans", "variant"),
highlight_text: text(theme.lowest, "sans", "accent", {
weight: "bold",
}),
},
state: {
hovered: {
background: with_opacity(
background(theme.lowest, "hovered"),
0.5
),
},
clicked: {
background: with_opacity(
background(theme.lowest, "pressed"),
0.5
),
},
},
}),
state: {
active: {
default: {
background: with_opacity(
background(theme.lowest, "base", "active"),
0.5
),
},
hovered: {
background: with_opacity(
background(theme.lowest, "hovered"),
0.5
),
},
clicked: {
background: with_opacity(
background(theme.lowest, "pressed"),
0.5
),
},
},
},
}),
input_editor,
empty_input_editor,
no_matches: {
text: text(theme.lowest, "sans", "variant"),
padding: {
bottom: 8,
left: 16,
right: 16,
top: 8,
},
},
header: {
text: text(theme.lowest, "sans", "variant", { size: "xs" }),
margin: {
top: 1,
left: 8,
right: 8,
},
},
footer: interactive({
base: {
text: text(theme.lowest, "sans", "base", { size: "xs" }),
padding: {
bottom: 4,
left: 12,
right: 12,
top: 4,
},
margin: {
top: 1,
left: 4,
right: 4,
},
corner_radius: 8,
background: with_opacity(
background(theme.lowest, "active"),
0.5
),
},
state: {
hovered: {
background: with_opacity(
background(theme.lowest, "hovered"),
0.5
),
},
clicked: {
background: with_opacity(
background(theme.lowest, "pressed"),
0.5
),
},
},
}),
}
}
@@ -1,14 +0,0 @@
import { useTheme } from "../theme"
import { background, text } from "./components"
export default function project_diagnostics(): any {
const theme = useTheme()
return {
background: background(theme.highest),
tab_icon_spacing: 4,
tab_icon_width: 13,
tab_summary_spacing: 10,
empty_message: text(theme.highest, "sans", "variant", { size: "md" }),
}
}
-201
View File
@@ -1,201 +0,0 @@
import { with_opacity } from "../theme/color"
import {
Border,
TextStyle,
background,
border,
foreground,
text,
} from "./components"
import { interactive, toggleable } from "../element"
import merge from "ts-deepmerge"
import { useTheme } from "../theme"
export default function project_panel(): any {
const theme = useTheme()
const { is_light } = theme
type EntryStateProps = {
background?: string
border?: Border
text?: TextStyle
icon_color?: string
}
type EntryState = {
default: EntryStateProps
hovered?: EntryStateProps
clicked?: EntryStateProps
}
const entry = (unselected?: EntryState, selected?: EntryState) => {
const git_status = {
git: {
modified: is_light
? theme.ramps.yellow(0.6).hex()
: theme.ramps.yellow(0.5).hex(),
inserted: is_light
? theme.ramps.green(0.45).hex()
: theme.ramps.green(0.5).hex(),
conflict: is_light
? theme.ramps.red(0.6).hex()
: theme.ramps.red(0.5).hex(),
},
}
const base_properties = {
height: 22,
background: background(theme.middle),
chevron_color: foreground(theme.middle, "variant"),
icon_color: with_opacity(foreground(theme.middle, "active"), 0.3),
chevron_size: 7,
icon_size: 14,
icon_spacing: 6,
text: text(theme.middle, "sans", "variant", { size: "sm" }),
status: {
...git_status,
},
}
const selected_style: EntryState | undefined = selected
? selected
: unselected
const unselected_default_style = merge(
base_properties,
unselected?.default ?? {},
{}
)
const unselected_hovered_style = merge(
base_properties,
{ background: background(theme.middle, "hovered") },
unselected?.hovered ?? {}
)
const unselected_clicked_style = merge(
base_properties,
{ background: background(theme.middle, "pressed") },
unselected?.clicked ?? {}
)
const selected_default_style = merge(
base_properties,
{
background: background(theme.lowest),
text: text(theme.lowest, "sans", { size: "sm" }),
},
selected_style?.default ?? {}
)
const selected_hovered_style = merge(
base_properties,
{
background: background(theme.lowest, "hovered"),
text: text(theme.lowest, "sans", { size: "sm" }),
},
selected_style?.hovered ?? {}
)
const selected_clicked_style = merge(
base_properties,
{
background: background(theme.lowest, "pressed"),
text: text(theme.lowest, "sans", { size: "sm" }),
},
selected_style?.clicked ?? {}
)
return toggleable({
state: {
inactive: interactive({
state: {
default: unselected_default_style,
hovered: unselected_hovered_style,
clicked: unselected_clicked_style,
},
}),
active: interactive({
state: {
default: selected_default_style,
hovered: selected_hovered_style,
clicked: selected_clicked_style,
},
}),
},
})
}
const default_entry = entry()
return {
open_project_button: interactive({
base: {
background: background(theme.middle),
border: border(theme.middle, "active"),
corner_radius: 4,
margin: {
top: 16,
left: 16,
right: 16,
},
padding: {
top: 3,
bottom: 3,
left: 7,
right: 7,
},
...text(theme.middle, "sans", "default", { size: "sm" }),
},
state: {
hovered: {
...text(theme.middle, "sans", "default", { size: "sm" }),
background: background(theme.middle, "hovered"),
border: border(theme.middle, "active"),
},
clicked: {
...text(theme.middle, "sans", "default", { size: "sm" }),
background: background(theme.middle, "pressed"),
border: border(theme.middle, "active"),
},
},
}),
background: background(theme.middle),
padding: { left: 6, right: 6, top: 0, bottom: 6 },
indent_width: 20,
entry: default_entry,
dragged_entry: {
...default_entry.inactive.default,
text: text(theme.middle, "sans", "on", { size: "sm" }),
background: with_opacity(background(theme.middle, "on"), 0.9),
border: border(theme.middle),
},
ignored_entry: entry(
{
default: {
text: text(theme.middle, "sans", "disabled"),
},
},
{
default: {
icon_color: foreground(theme.middle, "variant"),
},
}
),
cut_entry: entry(
{
default: {
text: text(theme.middle, "sans", "disabled"),
},
},
{
default: {
background: background(theme.middle, "active"),
text: text(theme.middle, "sans", "disabled", {
size: "sm",
}),
},
}
),
filename_editor: {
background: background(theme.middle, "on"),
text: text(theme.middle, "sans", "on", { size: "sm" }),
selection: theme.players[0],
},
}
}
@@ -1,55 +0,0 @@
import { useTheme } from "../theme"
import { background, border, text } from "./components"
export default function project_shared_notification(): unknown {
const theme = useTheme()
const avatar_size = 48
return {
window_height: 74,
window_width: 380,
background: background(theme.middle),
owner_container: {
padding: 12,
},
owner_avatar: {
height: avatar_size,
width: avatar_size,
corner_radius: avatar_size / 2,
},
owner_metadata: {
margin: { left: 10 },
},
owner_username: {
...text(theme.middle, "sans", { size: "sm", weight: "bold" }),
margin: { top: -3 },
},
message: {
...text(theme.middle, "sans", "variant", { size: "xs" }),
margin: { top: -3 },
},
worktree_roots: {
...text(theme.middle, "sans", "variant", {
size: "xs",
weight: "bold",
}),
margin: { top: -3 },
},
button_width: 96,
open_button: {
background: background(theme.middle, "accent"),
border: border(theme.middle, { left: true, bottom: true }),
...text(theme.middle, "sans", "accent", {
size: "xs",
weight: "bold",
}),
},
dismiss_button: {
border: border(theme.middle, { left: true }),
...text(theme.middle, "sans", "variant", {
size: "xs",
weight: "bold",
}),
},
}
}
-437
View File
@@ -1,437 +0,0 @@
import { with_opacity } from "../theme/color"
import { background, border, foreground, text } from "./components"
import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
const search_results = () => {
const theme = useTheme()
return {
// TODO: Add an activeMatchBackground on the rust side to differentiate between active and inactive
match_background: with_opacity(
foreground(theme.highest, "accent"),
0.4
),
}
}
export default function search(): any {
const theme = useTheme()
const SEARCH_ROW_SPACING = 12
// Search input
const editor = {
background: background(theme.highest),
corner_radius: 8,
min_width: 200,
max_width: 500,
placeholder_text: text(theme.highest, "mono", "disabled"),
selection: theme.players[0],
text: text(theme.highest, "mono", "default"),
border: border(theme.highest),
padding: {
top: 4,
bottom: 4,
left: 10,
right: 4,
},
margin: { right: SEARCH_ROW_SPACING },
}
const include_exclude_editor = {
...editor,
min_width: 100,
max_width: 250,
}
return {
padding: { top: 4, bottom: 4 },
option_button: toggleable({
base: interactive({
base: {
icon_width: 14,
button_width: 32,
color: foreground(theme.highest, "variant"),
background: background(theme.highest, "on"),
corner_radius: 2,
margin: { right: 2 },
border: {
width: 1,
color: background(theme.highest, "on"),
},
padding: {
left: 4,
right: 4,
top: 4,
bottom: 4,
},
},
state: {
hovered: {
...text(theme.highest, "mono", "variant", "hovered"),
background: background(theme.highest, "on", "hovered"),
border: {
width: 1,
color: background(theme.highest, "on", "hovered"),
},
},
clicked: {
...text(theme.highest, "mono", "variant", "pressed"),
background: background(theme.highest, "on", "pressed"),
border: {
width: 1,
color: background(theme.highest, "on", "pressed"),
},
},
},
}),
state: {
active: {
default: {
icon_width: 14,
button_width: 32,
color: foreground(theme.highest, "variant"),
background: background(theme.highest, "accent"),
border: border(theme.highest, "accent"),
},
hovered: {
background: background(
theme.highest,
"accent",
"hovered"
),
border: border(theme.highest, "accent", "hovered"),
},
clicked: {
background: background(
theme.highest,
"accent",
"pressed"
),
border: border(theme.highest, "accent", "pressed"),
},
},
},
}),
option_button_component: toggleable({
base: interactive({
base: {
icon_size: 14,
color: foreground(theme.highest, "variant"),
button_width: 32,
background: background(theme.highest, "on"),
corner_radius: 6,
margin: { right: 2 },
border: {
width: 1,
color: background(theme.highest, "on"),
},
padding: {
left: 4,
right: 4,
top: 4,
bottom: 4,
},
},
state: {
hovered: {
...text(theme.highest, "mono", "variant", "hovered"),
background: background(theme.highest, "on", "hovered"),
border: {
width: 1,
color: background(theme.highest, "on", "hovered"),
},
},
clicked: {
...text(theme.highest, "mono", "variant", "pressed"),
background: background(theme.highest, "on", "pressed"),
border: {
width: 1,
color: background(theme.highest, "on", "pressed"),
},
},
},
}),
state: {
active: {
default: {
icon_size: 14,
button_width: 32,
color: foreground(theme.highest, "variant"),
background: background(theme.highest, "accent"),
border: border(theme.highest, "accent"),
},
hovered: {
background: background(
theme.highest,
"accent",
"hovered"
),
border: border(theme.highest, "accent", "hovered"),
},
clicked: {
background: background(
theme.highest,
"accent",
"pressed"
),
border: border(theme.highest, "accent", "pressed"),
},
},
},
}),
editor,
invalid_editor: {
...editor,
border: border(theme.highest, "negative"),
},
include_exclude_editor,
invalid_include_exclude_editor: {
...include_exclude_editor,
border: border(theme.highest, "negative"),
},
match_index: {
...text(theme.highest, "mono", { size: "sm" }),
padding: {
left: SEARCH_ROW_SPACING,
right: SEARCH_ROW_SPACING,
},
},
option_button_group: {
padding: {
right: SEARCH_ROW_SPACING,
},
},
include_exclude_inputs: {
...text(theme.highest, "mono", "variant"),
padding: {
right: 6,
},
},
major_results_status: {
...text(theme.highest, "mono", "on"),
size: 15,
},
minor_results_status: {
...text(theme.highest, "mono", "variant"),
size: 13,
},
// Input Icon
editor_icon: {
icon: {
color: foreground(theme.highest, "disabled"),
asset: "icons/magnifying_glass.svg",
dimensions: {
width: 14,
height: 14,
},
},
container: {
margin: { right: 4 },
padding: { left: 1, right: 1 },
},
},
// Toggle group buttons - Text | Regex | Semantic
mode_button: toggleable({
base: interactive({
base: {
...text(theme.highest, "mono", "variant", { size: "sm" }),
background: background(theme.highest, "variant"),
border: {
...border(theme.highest, "on"),
left: false,
right: false,
},
margin: {
top: 1,
bottom: 1,
},
padding: {
left: 10,
right: 10,
},
corner_radius: 6,
},
state: {
hovered: {
...text(theme.highest, "mono", "variant", "hovered", {
size: "sm",
}),
background: background(
theme.highest,
"variant",
"hovered"
),
border: border(theme.highest, "on", "hovered"),
},
clicked: {
...text(theme.highest, "mono", "variant", "pressed", {
size: "sm",
}),
background: background(
theme.highest,
"variant",
"pressed"
),
border: border(theme.highest, "on", "pressed"),
},
},
}),
state: {
active: {
default: {
...text(theme.highest, "mono", "on", { size: "sm" }),
background: background(theme.highest, "on"),
},
hovered: {
...text(theme.highest, "mono", "on", "hovered", {
size: "sm",
}),
background: background(theme.highest, "on", "hovered"),
},
clicked: {
...text(theme.highest, "mono", "on", "pressed", {
size: "sm",
}),
background: background(theme.highest, "on", "pressed"),
},
},
},
}),
// Next/Previous Match buttons
// HACK: This is not how disabled elements should be created
// Disabled elements should use a disabled state of an interactive element, not a toggleable element with the inactive state being disabled
nav_button: toggleable({
state: {
inactive: interactive({
base: {
background: background(theme.highest, "disabled"),
text: text(theme.highest, "mono", "disabled"),
corner_radius: 6,
border: {
...border(theme.highest, "disabled"),
left: false,
right: false,
},
margin: {
top: 1,
bottom: 1,
},
padding: {
left: 10,
right: 10,
},
},
state: {
hovered: {},
},
}),
active: interactive({
base: {
text: text(theme.highest, "mono", "on"),
background: background(theme.highest, "on"),
corner_radius: 6,
border: {
...border(theme.highest, "on"),
left: false,
right: false,
},
margin: {
top: 1,
bottom: 1,
},
padding: {
left: 10,
right: 10,
},
},
state: {
hovered: {
...text(theme.highest, "mono", "on", "hovered"),
background: background(
theme.highest,
"on",
"hovered"
),
border: border(theme.highest, "on", "hovered"),
},
clicked: {
...text(theme.highest, "mono", "on", "pressed"),
background: background(
theme.highest,
"on",
"pressed"
),
border: border(theme.highest, "on", "pressed"),
},
},
}),
},
}),
search_bar_row_height: 34,
search_row_spacing: 8,
option_button_height: 22,
modes_container: {
padding: {
right: SEARCH_ROW_SPACING,
},
},
replace_icon: {
icon: {
color: foreground(theme.highest, "disabled"),
asset: "icons/replace.svg",
dimensions: {
width: 14,
height: 14,
},
},
container: {
margin: { right: 4 },
padding: { left: 1, right: 1 },
},
},
action_button: interactive({
base: {
icon_size: 14,
color: foreground(theme.highest, "variant"),
button_width: 32,
background: background(theme.highest, "on"),
corner_radius: 6,
margin: { right: 2 },
border: {
width: 1,
color: background(theme.highest, "on"),
},
padding: {
left: 4,
right: 4,
top: 4,
bottom: 4,
},
},
state: {
hovered: {
...text(theme.highest, "mono", "variant", "hovered"),
background: background(theme.highest, "on", "hovered"),
border: {
width: 1,
color: background(theme.highest, "on", "hovered"),
},
},
clicked: {
...text(theme.highest, "mono", "variant", "pressed"),
background: background(theme.highest, "on", "pressed"),
border: {
width: 1,
color: background(theme.highest, "on", "pressed"),
},
},
},
}),
...search_results(),
}
}
-10
View File
@@ -1,10 +0,0 @@
import { useTheme } from "../theme"
import { background } from "./components"
export default function sharedScreen() {
const theme = useTheme()
return {
background: background(theme.highest),
}
}
@@ -1,52 +0,0 @@
import { background, border, foreground, text } from "./components"
import { interactive } from "../element"
import { useTheme } from "../theme"
export default function simple_message_notification(): any {
const theme = useTheme()
const header_padding = 8
return {
message: {
...text(theme.middle, "sans", { size: "xs" }),
margin: { left: header_padding, right: header_padding },
},
action_message: interactive({
base: {
...text(theme.middle, "sans", { size: "xs" }),
border: border(theme.middle, "active"),
corner_radius: 4,
padding: {
top: 3,
bottom: 3,
left: 7,
right: 7,
},
margin: { left: header_padding, top: 6, bottom: 6 },
},
state: {
hovered: {
...text(theme.middle, "sans", "default", { size: "xs" }),
background: background(theme.middle, "hovered"),
border: border(theme.middle, "active"),
},
},
}),
dismiss_button: interactive({
base: {
color: foreground(theme.middle),
icon_width: 14,
icon_height: 14,
button_width: 14,
button_height: 14,
},
state: {
hovered: {
color: foreground(theme.middle, "hovered"),
},
},
}),
}
}
-161
View File
@@ -1,161 +0,0 @@
import { background, border, foreground, text } from "./components"
import { interactive, toggleable } from "../element"
import { useTheme } from "../common"
import { text_button } from "../component/text_button"
export default function status_bar(): any {
const theme = useTheme()
const layer = theme.lowest
const status_container = {
corner_radius: 6,
padding: { top: 3, bottom: 3, left: 6, right: 6 },
}
const diagnostic_status_container = {
corner_radius: 6,
padding: { top: 1, bottom: 1, left: 6, right: 6 },
}
return {
height: 30,
item_spacing: 8,
padding: {
top: 1,
bottom: 1,
left: 6,
right: 6,
},
border: border(layer, { top: true, overlay: true }),
cursor_position: text(layer, "sans", "base", { size: "xs" }),
vim_mode_indicator: {
margin: { left: 6 },
...text(layer, "mono", "base", { size: "xs" }),
},
active_language: text_button({
color: "base",
}),
auto_update_progress_message: text(layer, "sans", "base", {
size: "xs",
}),
auto_update_done_message: text(layer, "sans", "base", { size: "xs" }),
lsp_status: interactive({
base: {
...diagnostic_status_container,
icon_spacing: 4,
icon_width: 14,
height: 18,
message: text(layer, "sans", { size: "xs" }),
icon_color: foreground(layer),
},
state: {
hovered: {
message: text(layer, "sans", { size: "xs" }),
icon_color: foreground(layer),
background: background(layer, "hovered"),
},
},
}),
diagnostic_message: interactive({
base: {
...text(layer, "sans", { size: "xs" }),
},
state: { hovered: text(layer, "sans", "hovered", { size: "xs" }) },
}),
diagnostic_summary: interactive({
base: {
height: 20,
icon_width: 14,
icon_spacing: 2,
summary_spacing: 6,
text: text(layer, "sans", { size: "sm" }),
icon_color_ok: foreground(layer, "base"),
icon_color_warning: foreground(layer, "warning"),
icon_color_error: foreground(layer, "negative"),
container_ok: {
corner_radius: 6,
padding: { top: 2, bottom: 2, left: 6, right: 6 },
},
container_warning: diagnostic_status_container,
container_error: diagnostic_status_container,
},
state: {
hovered: {
icon_color_ok: foreground(layer, "on"),
container_ok: {
background: background(layer, "hovered"),
},
container_warning: {
background: background(layer, "hovered"),
},
container_error: {
background: background(layer, "hovered"),
},
},
clicked: {
icon_color_ok: foreground(layer, "on"),
container_ok: {
background: background(layer, "pressed"),
},
container_warning: {
background: background(layer, "pressed"),
},
container_error: {
background: background(layer, "pressed"),
},
},
},
}),
panel_buttons: {
group_left: {},
group_bottom: {},
group_right: {},
button: toggleable({
base: interactive({
base: {
...status_container,
icon_size: 14,
icon_color: foreground(layer, "base"),
background: background(layer, "default"),
label: {
margin: { left: 6 },
...text(layer, "sans", { size: "xs" }),
},
},
state: {
hovered: {
background: background(layer, "hovered"),
},
clicked: {
background: background(layer, "pressed"),
},
},
}),
state: {
active: {
default: {
icon_color: foreground(layer, "accent", "default"),
background: background(layer, "default"),
},
hovered: {
icon_color: foreground(layer, "accent", "hovered"),
background: background(layer, "hovered"),
},
clicked: {
icon_color: foreground(layer, "accent", "pressed"),
background: background(layer, "pressed"),
},
},
},
}),
badge: {
corner_radius: 3,
padding: 2,
margin: { bottom: -1, right: -1 },
border: border(layer),
background: background(layer, "accent"),
},
},
}
}
-167
View File
@@ -1,167 +0,0 @@
import { with_opacity } from "../theme/color"
import { text, border, background, foreground } from "./components"
import { interactive, toggleable } from "../element"
import { useTheme } from "../common"
export default function tab_bar(): any {
const theme = useTheme()
const { is_light } = theme
const height = 32
const active_layer = theme.highest
const layer = theme.middle
const tab = {
height,
text: text(layer, "sans", "variant", { size: "sm" }),
background: background(layer),
border: border(layer, {
right: true,
bottom: true,
overlay: true,
}),
padding: {
left: 8,
right: 12,
},
spacing: 8,
// Tab type icons (e.g. Project Search)
type_icon_width: 14,
// Close icons
close_icon_width: 14,
icon_close: foreground(layer, "variant"),
icon_close_active: foreground(layer, "hovered"),
// Indicators
icon_conflict: foreground(layer, "warning"),
icon_dirty: foreground(layer, "accent"),
git: {
modified: is_light
? theme.ramps.yellow(0.6).hex()
: theme.ramps.yellow(0.5).hex(),
inserted: is_light
? theme.ramps.green(0.45).hex()
: theme.ramps.green(0.5).hex(),
conflict: is_light
? theme.ramps.red(0.6).hex()
: theme.ramps.red(0.5).hex(),
},
// When two tabs of the same name are open, a label appears next to them
description: {
margin: { left: 8 },
...text(layer, "sans", "disabled", { size: "2xs" }),
},
}
const active_pane_active_tab = {
...tab,
background: background(active_layer),
text: text(active_layer, "sans", "active", { size: "sm" }),
border: {
...tab.border,
bottom: false,
},
}
const inactive_pane_inactive_tab = {
...tab,
background: background(layer),
text: text(layer, "sans", "variant", { size: "sm" }),
}
const inactive_pane_active_tab = {
...tab,
background: background(active_layer),
text: text(layer, "sans", "variant", { size: "sm" }),
border: {
...tab.border,
bottom: false,
},
}
const nav_button = interactive({
base: {
color: foreground(theme.highest, "on"),
icon_width: 12,
button_width: active_pane_active_tab.height,
border: border(theme.lowest, "on", {
bottom: true,
overlay: true,
}),
},
state: {
hovered: {
color: foreground(theme.highest, "on", "hovered"),
background: background(theme.highest, "on", "hovered"),
},
disabled: {
color: foreground(theme.highest, "on", "disabled"),
},
},
})
const dragged_tab = {
...active_pane_active_tab,
background: with_opacity(tab.background, 0.9),
border: undefined as any,
shadow: theme.popover_shadow,
}
return {
height,
background: background(layer),
active_pane: {
active_tab: active_pane_active_tab,
inactive_tab: tab,
},
inactive_pane: {
active_tab: inactive_pane_active_tab,
inactive_tab: inactive_pane_inactive_tab,
},
dragged_tab,
pane_button: toggleable({
base: interactive({
base: {
color: foreground(layer, "variant"),
icon_width: 12,
button_width: active_pane_active_tab.height,
},
state: {
hovered: {
color: foreground(layer, "hovered"),
},
clicked: {
color: foreground(layer, "pressed"),
},
},
}),
state: {
active: {
default: {
color: foreground(layer, "accent"),
},
hovered: {
color: foreground(layer, "hovered"),
},
clicked: {
color: foreground(layer, "pressed"),
},
},
},
}),
pane_button_container: {
background: tab.background,
border: {
...tab.border,
right: false,
},
},
nav_button: nav_button,
}
}
-54
View File
@@ -1,54 +0,0 @@
import { useTheme } from "../theme"
export default function terminal() {
const theme = useTheme()
/**
* Colors are controlled per-cell in the terminal grid.
* Cells can be set to any of these more 'theme-capable' colors
* or can be set directly with RGB values.
* Here are the common interpretations of these names:
* https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
*/
return {
black: theme.ramps.neutral(0).hex(),
red: theme.ramps.red(0.5).hex(),
green: theme.ramps.green(0.5).hex(),
yellow: theme.ramps.yellow(0.5).hex(),
blue: theme.ramps.blue(0.5).hex(),
magenta: theme.ramps.magenta(0.5).hex(),
cyan: theme.ramps.cyan(0.5).hex(),
white: theme.ramps.neutral(1).hex(),
bright_black: theme.ramps.neutral(0.4).hex(),
bright_red: theme.ramps.red(0.25).hex(),
bright_green: theme.ramps.green(0.25).hex(),
bright_yellow: theme.ramps.yellow(0.25).hex(),
bright_blue: theme.ramps.blue(0.25).hex(),
bright_magenta: theme.ramps.magenta(0.25).hex(),
bright_cyan: theme.ramps.cyan(0.25).hex(),
bright_white: theme.ramps.neutral(1).hex(),
/**
* Default color for characters
*/
foreground: theme.ramps.neutral(1).hex(),
/**
* Default color for the rectangle background of a cell
*/
background: theme.ramps.neutral(0).hex(),
modal_background: theme.ramps.neutral(0.1).hex(),
/**
* Default color for the cursor
*/
cursor: theme.players[0].cursor,
dim_black: theme.ramps.neutral(1).hex(),
dim_red: theme.ramps.red(0.75).hex(),
dim_green: theme.ramps.green(0.75).hex(),
dim_yellow: theme.ramps.yellow(0.75).hex(),
dim_blue: theme.ramps.blue(0.75).hex(),
dim_magenta: theme.ramps.magenta(0.75).hex(),
dim_cyan: theme.ramps.cyan(0.75).hex(),
dim_white: theme.ramps.neutral(0.6).hex(),
bright_foreground: theme.ramps.neutral(1).hex(),
dim_foreground: theme.ramps.neutral(0).hex(),
}
}
-287
View File
@@ -1,287 +0,0 @@
import { icon_button, text_button, toggleable_icon_button, toggleable_text_button } from "../component"
import { interactive, toggleable } from "../element"
import { useTheme, with_opacity } from "../theme"
import { background, border, foreground, text } from "./components"
const ITEM_SPACING = 8
const TITLEBAR_HEIGHT = 32
function build_spacing(
container_height: number,
element_height: number,
spacing: number
) {
return {
group: spacing,
item: spacing / 2,
half_item: spacing / 4,
margin_y: (container_height - element_height) / 2,
margin_x: (container_height - element_height) / 2,
}
}
function call_controls() {
const theme = useTheme()
const button_height = 18
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
const margin_y = {
top: space.margin_y,
bottom: space.margin_y,
}
return {
toggle_microphone_button: toggleable_icon_button({
margin: {
...margin_y,
left: space.group,
right: space.half_item,
},
active_color: "negative",
active_background_color: "negative",
}),
toggle_speakers_button: toggleable_icon_button({
margin: {
...margin_y,
left: space.half_item,
right: space.half_item,
},
}),
screen_share_button: toggleable_icon_button({
margin: {
...margin_y,
left: space.half_item,
right: space.group,
},
active_color: "accent",
active_background_color: "accent",
}),
muted: foreground(theme.lowest, "negative"),
speaking: foreground(theme.lowest, "accent"),
}
}
/**
* Opens the User Menu when toggled
*
* When logged in shows the user's avatar and a chevron,
* When logged out only shows a chevron.
*/
function user_menu() {
const theme = useTheme()
const button_height = 18
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
const build_button = ({ online }: { online: boolean }) => {
const button = toggleable({
base: interactive({
base: {
corner_radius: 6,
height: button_height,
width: 20,
padding: {
top: 2,
bottom: 2,
left: 6,
right: 6,
},
margin: {
left: space.item,
right: space.item,
},
...text(theme.lowest, "sans", { size: "xs" }),
background: background(theme.lowest),
},
state: {
hovered: {
...text(theme.lowest, "sans", "hovered", {
size: "xs",
}),
background: background(theme.lowest, "hovered"),
},
clicked: {
...text(theme.lowest, "sans", "pressed", {
size: "xs",
}),
background: background(theme.lowest, "pressed"),
},
},
}),
state: {
active: {
default: {
...text(theme.lowest, "sans", "active", { size: "xs" }),
background: background(theme.middle),
},
hovered: {
...text(theme.lowest, "sans", "active", { size: "xs" }),
background: background(theme.middle, "hovered"),
},
clicked: {
...text(theme.lowest, "sans", "active", { size: "xs" }),
background: background(theme.middle, "pressed"),
},
},
},
})
return {
user_menu: button,
avatar: {
icon_width: 16,
icon_height: 16,
corner_radius: 4,
outer_width: 16,
outer_corner_radius: 16,
},
icon: {
margin: {
top: 2,
left: online ? space.item : 0,
right: space.group,
bottom: 2,
},
width: 11,
height: 11,
color: foreground(theme.lowest),
},
}
}
return {
user_menu_button_online: build_button({ online: true }),
user_menu_button_offline: build_button({ online: false }),
}
}
export function titlebar(): any {
const theme = useTheme()
const avatar_width = 15
const avatar_outer_width = avatar_width + 4
const follower_avatar_width = 14
const follower_avatar_outer_width = follower_avatar_width + 4
return {
item_spacing: ITEM_SPACING,
face_pile_spacing: 2,
height: TITLEBAR_HEIGHT,
background: background(theme.lowest),
border: border(theme.lowest, { bottom: true }),
padding: {
left: 80,
right: 0,
},
menu: {
width: 300,
height: 400,
},
project_menu_button: toggleable_text_button(theme, {
color: "base"
}),
git_menu_button: toggleable_text_button(theme, {
color: "variant",
}),
project_host: text_button({
text_properties: {
weight: "bold"
}
}),
// Collaborators
leader_avatar: {
width: avatar_width,
outer_width: avatar_outer_width,
corner_radius: avatar_width / 2,
outer_corner_radius: avatar_outer_width / 2,
},
follower_avatar: {
width: follower_avatar_width,
outer_width: follower_avatar_outer_width,
corner_radius: follower_avatar_width / 2,
outer_corner_radius: follower_avatar_outer_width / 2,
},
inactive_avatar_grayscale: true,
follower_avatar_overlap: 8,
leader_selection: {
margin: {
top: 4,
bottom: 4,
},
padding: {
left: 2,
right: 2,
top: 2,
bottom: 2,
},
corner_radius: 6,
},
avatar_ribbon: {
height: 3,
width: 14,
// TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded.
},
sign_in_button: toggleable_text_button(theme, {}),
offline_icon: {
color: foreground(theme.lowest, "variant"),
width: 16,
margin: {
left: ITEM_SPACING,
},
padding: {
right: 4,
},
},
// When the collaboration server is out of date, show a warning
outdated_warning: {
...text(theme.lowest, "sans", "warning", { size: "xs" }),
background: with_opacity(background(theme.lowest, "warning"), 0.3),
border: border(theme.lowest, "warning"),
margin: {
left: ITEM_SPACING,
},
padding: {
left: 8,
right: 8,
},
corner_radius: 6,
},
leave_call_button: icon_button({
margin: {
left: ITEM_SPACING / 2,
right: ITEM_SPACING,
},
}),
...call_controls(),
toggle_contacts_button: toggleable_icon_button({
margin: {
left: ITEM_SPACING,
},
}),
// Jewel that notifies you that there are new contact requests
toggle_contacts_badge: {
corner_radius: 3,
padding: 2,
margin: { top: 3, left: 3 },
border: border(theme.lowest),
background: foreground(theme.lowest, "accent"),
},
share_button: toggleable_text_button(theme, {}),
user_menu: user_menu(),
}
}
-58
View File
@@ -1,58 +0,0 @@
import { useTheme } from "../common"
import { toggleable_icon_button } from "../component/icon_button"
import { interactive, toggleable } from "../element"
import { background, border, foreground, text } from "./components"
import { text_button } from "../component"
export const toolbar = () => {
const theme = useTheme()
return {
height: 42,
padding: { left: 8, right: 8 },
background: background(theme.highest),
border: border(theme.highest, { bottom: true }),
item_spacing: 4,
toggleable_tool: toggleable_icon_button({
margin: { left: 4 },
variant: "ghost",
active_color: "accent",
}),
breadcrumb_height: 24,
breadcrumbs: interactive({
base: {
...text(theme.highest, "sans", "variant"),
corner_radius: 6,
padding: {
left: 4,
right: 4,
}
},
state: {
hovered: {
color: foreground(theme.highest, "on", "hovered"),
background: background(theme.highest, "on", "hovered"),
},
},
}),
toggleable_text_tool: toggleable({
state: {
inactive: text_button({
disabled: true,
variant: "ghost",
layer: theme.highest,
margin: { left: 4 },
text_properties: { size: "sm" },
border: border(theme.middle),
}),
active: text_button({
variant: "ghost",
layer: theme.highest,
margin: { left: 4 },
text_properties: { size: "sm" },
border: border(theme.middle),
}),
}
}),
}
}
@@ -1,66 +0,0 @@
import { background, border, text } from "./components"
import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
export default function dropdown_menu(): any {
const theme = useTheme()
return {
row_height: 30,
background: background(theme.middle),
border: border(theme.middle),
shadow: theme.popover_shadow,
header: interactive({
base: {
...text(theme.middle, "sans", { size: "sm" }),
secondary_text: text(theme.middle, "sans", {
size: "sm",
color: "#aaaaaa",
}),
secondary_text_spacing: 10,
padding: { left: 8, right: 8, top: 2, bottom: 2 },
corner_radius: 6,
background: background(theme.middle, "on"),
},
state: {
hovered: {
background: background(theme.middle, "hovered"),
},
clicked: {
background: background(theme.middle, "pressed"),
},
},
}),
section_header: {
...text(theme.middle, "sans", { size: "sm" }),
padding: { left: 8, right: 8, top: 8, bottom: 8 },
},
item: toggleable({
base: interactive({
base: {
...text(theme.middle, "sans", { size: "sm" }),
secondary_text_spacing: 10,
secondary_text: text(theme.middle, "sans", { size: "sm" }),
padding: { left: 18, right: 18, top: 2, bottom: 2 },
},
state: {
hovered: {
background: background(theme.middle, "hovered"),
...text(theme.middle, "sans", "hovered", {
size: "sm",
}),
},
},
}),
state: {
active: {
default: {
background: background(theme.middle, "active"),
},
hovered: {
background: background(theme.middle, "hovered"),
},
},
},
}),
}
}
-24
View File
@@ -1,24 +0,0 @@
import { useTheme } from "../theme"
import { background, border, text } from "./components"
export default function tooltip(): any {
const theme = useTheme()
return {
background: background(theme.middle),
border: border(theme.middle),
padding: { top: 4, bottom: 4, left: 8, right: 8 },
margin: { top: 6, left: 6 },
shadow: theme.popover_shadow,
corner_radius: 6,
text: text(theme.middle, "sans", { size: "xs" }),
keystroke: {
background: background(theme.middle, "on"),
corner_radius: 4,
margin: { left: 6 },
padding: { left: 4, right: 4 },
...text(theme.middle, "mono", "on", { size: "xs", weight: "bold" }),
},
max_text_width: 200,
}
}
@@ -1,41 +0,0 @@
import { foreground, text } from "./components"
import { interactive } from "../element"
import { useTheme } from "../theme"
export default function update_notification(): any {
const theme = useTheme()
const header_padding = 8
return {
message: {
...text(theme.middle, "sans", { size: "xs" }),
margin: { left: header_padding, right: header_padding },
},
action_message: interactive({
base: {
...text(theme.middle, "sans", { size: "xs" }),
margin: { left: header_padding, top: 6, bottom: 6 },
},
state: {
hovered: {
color: foreground(theme.middle, "hovered"),
},
},
}),
dismiss_button: interactive({
base: {
color: foreground(theme.middle),
icon_width: 14,
icon_height: 14,
button_width: 14,
button_height: 14,
},
state: {
hovered: {
color: foreground(theme.middle, "hovered"),
},
},
}),
}
}
-157
View File
@@ -1,157 +0,0 @@
import { with_opacity } from "../theme/color"
import {
border,
background,
foreground,
text,
TextProperties,
svg,
} from "./components"
import { interactive } from "../element"
import { useTheme } from "../theme"
export default function welcome(): any {
const theme = useTheme()
const checkbox_base = {
corner_radius: 4,
padding: {
left: 3,
right: 3,
top: 3,
bottom: 3,
},
// shadow: theme.popover_shadow,
border: border(theme.highest),
margin: {
right: 8,
top: 5,
bottom: 5,
},
}
const interactive_text_size: TextProperties = { size: "sm" }
return {
page_width: 320,
logo: svg(
foreground(theme.highest, "default"),
"icons/logo_96.svg",
64,
64
),
logo_subheading: {
...text(theme.highest, "sans", "variant", { size: "md" }),
margin: {
top: 10,
bottom: 7,
},
},
button_group: {
margin: {
top: 8,
bottom: 16,
},
},
heading_group: {
margin: {
top: 8,
bottom: 12,
},
},
checkbox_group: {
border: border(theme.highest, "variant"),
background: with_opacity(
background(theme.highest, "hovered"),
0.25
),
corner_radius: 4,
padding: {
left: 12,
top: 2,
bottom: 2,
},
},
button: interactive({
base: {
background: background(theme.highest),
border: border(theme.highest, "active"),
corner_radius: 4,
margin: {
top: 4,
bottom: 4,
},
padding: {
top: 3,
bottom: 3,
left: 7,
right: 7,
},
...text(
theme.highest,
"sans",
"default",
interactive_text_size
),
},
state: {
hovered: {
...text(
theme.highest,
"sans",
"default",
interactive_text_size
),
background: background(theme.highest, "hovered"),
},
},
}),
usage_note: {
...text(theme.highest, "sans", "variant", { size: "2xs" }),
padding: {
top: -4,
},
},
checkbox_container: {
margin: {
top: 4,
},
padding: {
bottom: 8,
},
},
checkbox: {
label: {
...text(theme.highest, "sans", interactive_text_size),
// Also supports margin, container, border, etc.
},
icon: svg(
foreground(theme.highest, "on"),
"icons/check.svg",
12,
12
),
default: {
...checkbox_base,
background: background(theme.highest, "default"),
border: border(theme.highest, "active"),
},
checked: {
...checkbox_base,
background: background(theme.highest, "hovered"),
border: border(theme.highest, "active"),
},
hovered: {
...checkbox_base,
background: background(theme.highest, "hovered"),
border: border(theme.highest, "active"),
},
hovered_and_checked: {
...checkbox_base,
background: background(theme.highest, "hovered"),
border: border(theme.highest, "active"),
},
},
}
}
-153
View File
@@ -1,153 +0,0 @@
import { with_opacity } from "../theme/color"
import {
background,
border,
border_color,
foreground,
svg,
text,
} from "./components"
import statusBar from "./status_bar"
import tabBar from "./tab_bar"
import { interactive } from "../element"
import { titlebar } from "./titlebar"
import { useTheme } from "../theme"
import { toolbar } from "./toolbar"
export default function workspace(): any {
const theme = useTheme()
const { is_light } = theme
return {
background: background(theme.lowest),
blank_pane: {
logo_container: {
width: 256,
height: 256,
},
logo: svg(
with_opacity("#000000", theme.is_light ? 0.6 : 0.8),
"icons/logo_96.svg",
256,
256
),
logo_shadow: svg(
with_opacity(
theme.is_light
? "#FFFFFF"
: theme.lowest.base.default.background,
theme.is_light ? 1 : 0.6
),
"icons/logo_96.svg",
256,
256
),
keyboard_hints: {
margin: {
top: 96,
},
corner_radius: 4,
},
keyboard_hint: interactive({
base: {
...text(theme.lowest, "sans", "variant", { size: "sm" }),
padding: {
top: 3,
left: 8,
right: 8,
bottom: 3,
},
corner_radius: 8,
},
state: {
hovered: {
...text(theme.lowest, "sans", "active", { size: "sm" }),
},
},
}),
keyboard_hint_width: 320,
},
joining_project_avatar: {
corner_radius: 40,
width: 80,
},
joining_project_message: {
padding: 12,
...text(theme.lowest, "sans", { size: "lg" }),
},
external_location_message: {
background: background(theme.middle, "accent"),
border: border(theme.middle, "accent"),
corner_radius: 6,
padding: 12,
margin: { bottom: 8, right: 8 },
...text(theme.middle, "sans", "accent", { size: "xs" }),
},
leader_border_opacity: 0.7,
leader_border_width: 2.0,
tab_bar: tabBar(),
modal: {
margin: {
bottom: 52,
top: 52,
},
cursor: "Arrow",
},
zoomed_background: {
cursor: "Arrow",
background: is_light
? with_opacity(background(theme.lowest), 0.8)
: with_opacity(background(theme.highest), 0.6),
},
zoomed_pane_foreground: {
margin: 16,
shadow: theme.modal_shadow,
border: border(theme.lowest, { overlay: true }),
},
zoomed_panel_foreground: {
margin: 16,
border: border(theme.lowest, { overlay: true }),
},
dock: {
left: {
border: border(theme.lowest, { right: true }),
},
bottom: {
border: border(theme.lowest, { top: true }),
},
right: {
border: border(theme.lowest, { left: true }),
},
},
pane_divider: {
color: border_color(theme.lowest),
width: 1,
},
status_bar: statusBar(),
titlebar: titlebar(),
toolbar: toolbar(),
disconnected_overlay: {
...text(theme.lowest, "sans"),
background: with_opacity(background(theme.lowest), 0.8),
},
notification: {
margin: { top: 10 },
background: background(theme.middle),
corner_radius: 6,
padding: 12,
border: border(theme.middle),
shadow: theme.popover_shadow,
},
notifications: {
width: 400,
margin: { right: 10, bottom: 10 },
},
drop_target_overlay_color: with_opacity(
foreground(theme.lowest, "variant"),
0.5
),
}
}
-5
View File
@@ -1,5 +0,0 @@
import chroma from "chroma-js"
export function with_opacity(color: string, opacity: number): string {
return chroma(color).alpha(opacity).hex()
}
-329
View File
@@ -1,329 +0,0 @@
import { Scale, Color } from "chroma-js"
import { Syntax, ThemeSyntax, SyntaxHighlightStyle } from "./syntax"
export { Syntax, ThemeSyntax, SyntaxHighlightStyle }
import {
ThemeConfig,
ThemeAppearance,
ThemeConfigInputColors,
} from "./theme_config"
import { get_ramps } from "./ramps"
export interface Theme {
name: string
is_light: boolean
/**
* App background, other elements that should sit directly on top of the background.
*/
lowest: Layer
/**
* Panels, tabs, other UI surfaces that sit on top of the background.
*/
middle: Layer
/**
* Editors like code buffers, conversation editors, etc.
*/
highest: Layer
ramps: RampSet
popover_shadow: Shadow
modal_shadow: Shadow
players: Players
syntax?: Partial<ThemeSyntax>
color_family: ColorFamily
}
export interface Meta {
name: string
author: string
url: string
license: License
}
export interface License {
SPDX: SPDXExpression
}
// License name -> License text
export interface Licenses {
[key: string]: string
}
// FIXME: Add support for the SPDX expression syntax
export type SPDXExpression = "MIT"
export interface Player {
cursor: string
selection: string
}
export interface Players {
"0": Player
"1": Player
"2": Player
"3": Player
"4": Player
"5": Player
"6": Player
"7": Player
}
export type ColorFamily = Partial<{ [K in keyof RampSet]: ColorFamilyRange }>
export interface ColorFamilyRange {
low: number
high: number
range: number
scaling_value: number
}
export interface Shadow {
blur: number
color: string
offset: number[]
}
export type StyleSets = keyof Layer
export interface Layer {
base: StyleSet
variant: StyleSet
on: StyleSet
accent: StyleSet
positive: StyleSet
warning: StyleSet
negative: StyleSet
}
export interface RampSet {
neutral: Scale
red: Scale
orange: Scale
yellow: Scale
green: Scale
cyan: Scale
blue: Scale
violet: Scale
magenta: Scale
}
export type Styles = keyof StyleSet
export interface StyleSet {
default: Style
active: Style
disabled: Style
hovered: Style
pressed: Style
inverted: Style
}
export interface Style {
background: string
border: string
foreground: string
}
export function create_theme(theme: ThemeConfig): Theme {
const {
name,
appearance,
input_color,
override: { syntax },
} = theme
const is_light = appearance === ThemeAppearance.Light
const color_ramps: ThemeConfigInputColors = input_color
// Chromajs scales from 0 to 1 flipped if is_light is true
const ramps = get_ramps(is_light, color_ramps)
const lowest = lowest_layer(ramps)
const middle = middle_layer(ramps)
const highest = highest_layer(ramps)
const popover_shadow = {
blur: 4,
color: ramps
.neutral(is_light ? 7 : 0)
.darken()
.alpha(0.2)
.hex(), // TODO used blend previously. Replace with something else
offset: [1, 2],
}
const modal_shadow = {
blur: 16,
color: ramps
.neutral(is_light ? 7 : 0)
.darken()
.alpha(0.2)
.hex(), // TODO used blend previously. Replace with something else
offset: [0, 2],
}
const players = {
"0": player(ramps.blue),
"1": player(ramps.green),
"2": player(ramps.magenta),
"3": player(ramps.orange),
"4": player(ramps.violet),
"5": player(ramps.cyan),
"6": player(ramps.red),
"7": player(ramps.yellow),
}
const color_family = build_color_family(ramps)
return {
name,
is_light,
ramps,
lowest,
middle,
highest,
popover_shadow,
modal_shadow,
players,
syntax,
color_family,
}
}
function player(ramp: Scale): Player {
return {
selection: ramp(0.5).alpha(0.24).hex(),
cursor: ramp(0.5).hex(),
}
}
function build_color_family(ramps: RampSet): ColorFamily {
const color_family: ColorFamily = {}
for (const ramp in ramps) {
const ramp_value = ramps[ramp as keyof RampSet]
const lightnessValues = [
ramp_value(0).get("hsl.l") * 100,
ramp_value(1).get("hsl.l") * 100,
]
const low = Math.min(...lightnessValues)
const high = Math.max(...lightnessValues)
const range = high - low
color_family[ramp as keyof RampSet] = {
low,
high,
range,
scaling_value: 100 / range,
}
}
return color_family
}
function lowest_layer(ramps: RampSet): Layer {
return {
base: build_style_set(ramps.neutral, 0.2, 1),
variant: build_style_set(ramps.neutral, 0.2, 0.7),
on: build_style_set(ramps.neutral, 0.1, 1),
accent: build_style_set(ramps.blue, 0.1, 0.5),
positive: build_style_set(ramps.green, 0.1, 0.5),
warning: build_style_set(ramps.yellow, 0.1, 0.5),
negative: build_style_set(ramps.red, 0.1, 0.5),
}
}
function middle_layer(ramps: RampSet): Layer {
return {
base: build_style_set(ramps.neutral, 0.1, 1),
variant: build_style_set(ramps.neutral, 0.1, 0.7),
on: build_style_set(ramps.neutral, 0, 1),
accent: build_style_set(ramps.blue, 0.1, 0.5),
positive: build_style_set(ramps.green, 0.1, 0.5),
warning: build_style_set(ramps.yellow, 0.1, 0.5),
negative: build_style_set(ramps.red, 0.1, 0.5),
}
}
function highest_layer(ramps: RampSet): Layer {
return {
base: build_style_set(ramps.neutral, 0, 1),
variant: build_style_set(ramps.neutral, 0, 0.7),
on: build_style_set(ramps.neutral, 0.1, 1),
accent: build_style_set(ramps.blue, 0.1, 0.5),
positive: build_style_set(ramps.green, 0.1, 0.5),
warning: build_style_set(ramps.yellow, 0.1, 0.5),
negative: build_style_set(ramps.red, 0.1, 0.5),
}
}
function build_style_set(
ramp: Scale,
background_base: number,
foreground_base: number,
step = 0.08
): StyleSet {
const style_definitions = build_style_definition(
background_base,
foreground_base,
step
)
function color_string(index_or_color: number | Color): string {
if (typeof index_or_color === "number") {
return ramp(index_or_color).hex()
} else {
return index_or_color.hex()
}
}
function build_style(style: Styles): Style {
return {
background: color_string(style_definitions.background[style]),
border: color_string(style_definitions.border[style]),
foreground: color_string(style_definitions.foreground[style]),
}
}
return {
default: build_style("default"),
hovered: build_style("hovered"),
pressed: build_style("pressed"),
active: build_style("active"),
disabled: build_style("disabled"),
inverted: build_style("inverted"),
}
}
function build_style_definition(bg_base: number, fg_base: number, step = 0.08) {
return {
background: {
default: bg_base,
hovered: bg_base + step,
pressed: bg_base + step * 1.5,
active: bg_base + step * 2.2,
disabled: bg_base,
inverted: fg_base + step * 6,
},
border: {
default: bg_base + step * 1,
hovered: bg_base + step,
pressed: bg_base + step,
active: bg_base + step * 3,
disabled: bg_base + step * 0.5,
inverted: bg_base - step * 3,
},
foreground: {
default: fg_base,
hovered: fg_base,
pressed: fg_base,
active: fg_base + step * 6,
disabled: bg_base + step * 4,
inverted: bg_base + step * 2,
},
}
}
-26
View File
@@ -1,26 +0,0 @@
import { create } from "zustand"
import { Theme } from "./create_theme"
type ThemeState = {
theme: Theme | undefined
setTheme: (theme: Theme) => void
}
export const useThemeStore = create<ThemeState>((set) => ({
theme: undefined,
setTheme: (theme) => set(() => ({ theme })),
}))
export const useTheme = (): Theme => {
const { theme } = useThemeStore.getState()
if (!theme) throw new Error("Tried to use theme before it was loaded")
return theme
}
export * from "./create_theme"
export * from "./ramps"
export * from "./syntax"
export * from "./theme_config"
export * from "./color"
-47
View File
@@ -1,47 +0,0 @@
import chroma, { Color, Scale } from "chroma-js"
import { RampSet } from "./create_theme"
import {
ThemeConfigInputColors,
ThemeConfigInputColorsKeys,
} from "./theme_config"
export function color_ramp(color: Color): Scale {
const end_color = color.desaturate(1).brighten(5)
const start_color = color.desaturate(1).darken(4)
return chroma.scale([start_color, color, end_color]).mode("lab")
}
/**
* Chromajs mutates the underlying ramp when you call domain. This causes problems because
we now store the ramps object in the theme so that we can pull colors out of them.
So instead of calling domain and storing the result, we have to construct new ramps for each
theme so that we don't modify the passed in ramps.
This combined with an error in the type definitions for chroma js means we have to cast the colors
function to any in order to get the colors back out from the original ramps.
* @param is_light
* @param color_ramps
* @returns
*/
export function get_ramps(
is_light: boolean,
color_ramps: ThemeConfigInputColors
): RampSet {
const ramps: RampSet = {} as any // eslint-disable-line @typescript-eslint/no-explicit-any
const color_keys = Object.keys(color_ramps) as ThemeConfigInputColorsKeys[]
if (is_light) {
for (const ramp_name of color_keys) {
ramps[ramp_name] = chroma.scale(
color_ramps[ramp_name].colors(100).reverse()
)
}
ramps.neutral = chroma.scale(color_ramps.neutral.colors(100).reverse())
} else {
for (const ramp_name of color_keys) {
ramps[ramp_name] = chroma.scale(color_ramps[ramp_name].colors(100))
}
ramps.neutral = chroma.scale(color_ramps.neutral.colors(100))
}
return ramps
}
-332
View File
@@ -1,332 +0,0 @@
import deepmerge from "deepmerge"
import { FontWeight, font_weights, useTheme } from "../common"
import chroma from "chroma-js"
export interface SyntaxHighlightStyle {
color?: string
weight?: FontWeight
underline?: boolean
italic?: boolean
}
export interface Syntax {
// == Text Styles ====== /
comment: SyntaxHighlightStyle
// elixir: doc comment
"comment.doc": SyntaxHighlightStyle
primary: SyntaxHighlightStyle
predictive: SyntaxHighlightStyle
hint: SyntaxHighlightStyle
// === Formatted Text ====== /
emphasis: SyntaxHighlightStyle
"emphasis.strong": SyntaxHighlightStyle
title: SyntaxHighlightStyle
link_uri: SyntaxHighlightStyle
link_text: SyntaxHighlightStyle
/** md: indented_code_block, fenced_code_block, code_span */
"text.literal": SyntaxHighlightStyle
// == Punctuation ====== /
punctuation: SyntaxHighlightStyle
/** Example: `(`, `[`, `{`...*/
"punctuation.bracket": SyntaxHighlightStyle
/**., ;*/
"punctuation.delimiter": SyntaxHighlightStyle
// js, ts: ${, } in a template literal
// yaml: *, &, ---, ...
"punctuation.special": SyntaxHighlightStyle
// md: list_marker_plus, list_marker_dot, etc
"punctuation.list_marker": SyntaxHighlightStyle
// == Strings ====== /
string: SyntaxHighlightStyle
// css: color_value
// js: this, super
// toml: offset_date_time, local_date_time...
"string.special": SyntaxHighlightStyle
// elixir: atom, quoted_atom, keyword, quoted_keyword
// ruby: simple_symbol, delimited_symbol...
"string.special.symbol"?: SyntaxHighlightStyle
// elixir, python, yaml...: escape_sequence
"string.escape"?: SyntaxHighlightStyle
// Regular expressions
"string.regex"?: SyntaxHighlightStyle
// == Types ====== /
// We allow Function here because all JS objects literals have this property
constructor: SyntaxHighlightStyle | Function // eslint-disable-line @typescript-eslint/ban-types
variant: SyntaxHighlightStyle
type: SyntaxHighlightStyle
// js: predefined_type
"type.builtin"?: SyntaxHighlightStyle
// == Values
variable: SyntaxHighlightStyle
// this, ...
// css: -- (var(--foo))
// lua: self
"variable.special"?: SyntaxHighlightStyle
// c: statement_identifier,
label: SyntaxHighlightStyle
// css: tag_name, nesting_selector, universal_selector...
tag: SyntaxHighlightStyle
// css: attribute, pseudo_element_selector (tag_name),
attribute: SyntaxHighlightStyle
// css: class_name, property_name, namespace_name...
property: SyntaxHighlightStyle
// true, false, null, nullptr
constant: SyntaxHighlightStyle
// css: @media, @import, @supports...
// js: declare, implements, interface, keyof, public...
keyword: SyntaxHighlightStyle
// note: js enum is currently defined as a keyword
enum: SyntaxHighlightStyle
// -, --, ->, !=, &&, ||, <=...
operator: SyntaxHighlightStyle
number: SyntaxHighlightStyle
boolean: SyntaxHighlightStyle
// elixir: __MODULE__, __DIR__, __ENV__, etc
// go: nil, iota
"constant.builtin"?: SyntaxHighlightStyle
// == Functions ====== /
function: SyntaxHighlightStyle
// lua: assert, error, loadfile, tostring, unpack...
"function.builtin"?: SyntaxHighlightStyle
// go: call_expression, method_declaration
// js: call_expression, method_definition, pair (key, arrow function)
// rust: function_item name: (identifier)
"function.definition"?: SyntaxHighlightStyle
// rust: macro_definition name: (identifier)
"function.special.definition"?: SyntaxHighlightStyle
"function.method"?: SyntaxHighlightStyle
// ruby: identifier/"defined?" // Nate note: I don't fully understand this one.
"function.method.builtin"?: SyntaxHighlightStyle
// == Unsorted ====== /
// lua: hash_bang_line
preproc: SyntaxHighlightStyle
// elixir, python: interpolation (ex: foo in ${foo})
// js: template_substitution
embedded: SyntaxHighlightStyle
}
export type ThemeSyntax = Partial<Syntax>
const default_syntax_highlight_style: Omit<SyntaxHighlightStyle, "color"> = {
weight: "normal",
underline: false,
italic: false,
}
function build_default_syntax(): Syntax {
const theme = useTheme()
// Make a temporary object that is allowed to be missing
// the "color" property for each style
const syntax: {
[key: string]: Omit<SyntaxHighlightStyle, "color">
} = {}
// then spread the default to each style
for (const key of Object.keys({} as Syntax)) {
syntax[key as keyof Syntax] = {
...default_syntax_highlight_style,
}
}
// Mix the neutral and blue colors to get a
// predictive color distinct from any other color in the theme
const predictive = chroma
.mix(
theme.ramps.neutral(0.4).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex()
// Mix the neutral and green colors to get a
// hint color distinct from any other color in the theme
const hint = chroma
.mix(
theme.ramps.neutral(0.6).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex()
const color = {
primary: theme.ramps.neutral(1).hex(),
comment: theme.ramps.neutral(0.71).hex(),
punctuation: theme.ramps.neutral(0.86).hex(),
predictive: predictive,
hint: hint,
emphasis: theme.ramps.blue(0.5).hex(),
string: theme.ramps.orange(0.5).hex(),
function: theme.ramps.yellow(0.5).hex(),
type: theme.ramps.cyan(0.5).hex(),
constructor: theme.ramps.blue(0.5).hex(),
variant: theme.ramps.blue(0.5).hex(),
property: theme.ramps.blue(0.5).hex(),
enum: theme.ramps.orange(0.5).hex(),
operator: theme.ramps.orange(0.5).hex(),
number: theme.ramps.green(0.5).hex(),
boolean: theme.ramps.green(0.5).hex(),
constant: theme.ramps.green(0.5).hex(),
keyword: theme.ramps.blue(0.5).hex(),
}
// Then assign colors and use Syntax to enforce each style getting it's own color
const default_syntax: Syntax = {
...syntax,
comment: {
color: color.comment,
},
"comment.doc": {
color: color.comment,
},
primary: {
color: color.primary,
},
predictive: {
color: color.predictive,
italic: true,
},
hint: {
color: color.hint,
weight: font_weights.bold,
},
emphasis: {
color: color.emphasis,
},
"emphasis.strong": {
color: color.emphasis,
weight: font_weights.bold,
},
title: {
color: color.primary,
weight: font_weights.bold,
},
link_uri: {
color: theme.ramps.green(0.5).hex(),
underline: true,
},
link_text: {
color: theme.ramps.orange(0.5).hex(),
italic: true,
},
"text.literal": {
color: color.string,
},
punctuation: {
color: color.punctuation,
},
"punctuation.bracket": {
color: color.punctuation,
},
"punctuation.delimiter": {
color: color.punctuation,
},
"punctuation.special": {
color: theme.ramps.neutral(0.86).hex(),
},
"punctuation.list_marker": {
color: color.punctuation,
},
string: {
color: color.string,
},
"string.special": {
color: color.string,
},
"string.special.symbol": {
color: color.string,
},
"string.escape": {
color: color.comment,
},
"string.regex": {
color: color.string,
},
constructor: {
color: theme.ramps.blue(0.5).hex(),
},
variant: {
color: theme.ramps.blue(0.5).hex(),
},
type: {
color: color.type,
},
variable: {
color: color.primary,
},
label: {
color: theme.ramps.blue(0.5).hex(),
},
tag: {
color: theme.ramps.blue(0.5).hex(),
},
attribute: {
color: theme.ramps.blue(0.5).hex(),
},
property: {
color: theme.ramps.blue(0.5).hex(),
},
constant: {
color: color.constant,
},
keyword: {
color: color.keyword,
},
enum: {
color: color.enum,
},
operator: {
color: color.operator,
},
number: {
color: color.number,
},
boolean: {
color: color.boolean,
},
function: {
color: color.function,
},
preproc: {
color: color.primary,
},
embedded: {
color: color.primary,
},
}
return default_syntax
}
export function build_syntax(): Syntax {
const theme = useTheme()
const default_syntax: Syntax = build_default_syntax()
if (!theme.syntax) {
return default_syntax
}
const syntax = deepmerge<Syntax, Partial<ThemeSyntax>>(
default_syntax,
theme.syntax,
{
arrayMerge: (destinationArray, sourceArray) => [
...destinationArray,
...sourceArray,
],
}
)
return syntax
}
-81
View File
@@ -1,81 +0,0 @@
import { Scale, Color } from "chroma-js"
import { Syntax } from "./syntax"
interface ThemeMeta {
/** The name of the theme */
name: string
/** The theme's appearance. Either `light` or `dark`. */
appearance: ThemeAppearance
/** The author of the theme
*
* Ideally formatted as `Full Name <email>`
*
* Example: `John Doe <john@doe.com>`
*/
author: string
/** SPDX License string
*
* Example: `MIT`
*/
license_type?: string | ThemeLicenseType
license_url?: string
license_file: string
theme_url?: string
}
export type ThemeFamilyMeta = Pick<
ThemeMeta,
"name" | "author" | "license_type" | "license_url"
>
export interface ThemeConfigInputColors {
neutral: Scale<Color>
red: Scale<Color>
orange: Scale<Color>
yellow: Scale<Color>
green: Scale<Color>
cyan: Scale<Color>
blue: Scale<Color>
violet: Scale<Color>
magenta: Scale<Color>
}
export type ThemeConfigInputColorsKeys = keyof ThemeConfigInputColors
/** Allow any part of a syntax highlight style to be overriden by the theme
*
* Example:
* ```ts
* override: {
* syntax: {
* boolean: {
* underline: true,
* },
* },
* }
* ```
*/
export type ThemeConfigInputSyntax = Partial<Syntax>
interface ThemeConfigOverrides {
syntax: ThemeConfigInputSyntax
}
type ThemeConfigProperties = ThemeMeta & {
input_color: ThemeConfigInputColors
override: ThemeConfigOverrides
}
export type ThemeConfig = {
[K in keyof ThemeConfigProperties]: ThemeConfigProperties[K]
}
export enum ThemeAppearance {
Light = "light",
Dark = "dark",
}
export enum ThemeLicenseType {
MIT = "MIT",
Apache2 = "Apache License 2.0",
}
-63
View File
@@ -1,63 +0,0 @@
import { SingleColorToken } from "@tokens-studio/types"
import { Layer, Style, StyleSet } from "../create_theme"
import { color_token } from "./token"
interface StyleToken {
background: SingleColorToken
border: SingleColorToken
foreground: SingleColorToken
}
interface StyleSetToken {
default: StyleToken
active: StyleToken
disabled: StyleToken
hovered: StyleToken
pressed: StyleToken
inverted: StyleToken
}
export interface LayerToken {
base: StyleSetToken
variant: StyleSetToken
on: StyleSetToken
accent: StyleSetToken
positive: StyleSetToken
warning: StyleSetToken
negative: StyleSetToken
}
export const style_token = (style: Style, name: string): StyleToken => {
const token = {
background: color_token(`${name}Background`, style.background),
border: color_token(`${name}Border`, style.border),
foreground: color_token(`${name}Foreground`, style.foreground),
}
return token
}
export const style_set_token = (
style_set: StyleSet,
name: string
): StyleSetToken => {
const token: StyleSetToken = {} as StyleSetToken
for (const style in style_set) {
const s = style as keyof StyleSet
token[s] = style_token(style_set[s], `${name}${style}`)
}
return token
}
export const layer_token = (layer: Layer, name: string): LayerToken => {
const token: LayerToken = {} as LayerToken
for (const style_set in layer) {
const s = style_set as keyof Layer
token[s] = style_set_token(layer[s], `${name}${style_set}`)
}
return token
}
-37
View File
@@ -1,37 +0,0 @@
import { SingleColorToken } from "@tokens-studio/types"
import { color_token } from "./token"
import { Players } from "../create_theme"
import { useTheme } from "../../../src/common"
export type PlayerToken = Record<"selection" | "cursor", SingleColorToken>
export type PlayersToken = Record<keyof Players, PlayerToken>
function build_player_token(index: number): PlayerToken {
const theme = useTheme()
const player_number = index.toString() as keyof Players
return {
selection: color_token(
`player${index}Selection`,
theme.players[player_number].selection
),
cursor: color_token(
`player${index}Cursor`,
theme.players[player_number].cursor
),
}
}
export const players_token = (): PlayersToken => {
return {
"0": build_player_token(0),
"1": build_player_token(1),
"2": build_player_token(2),
"3": build_player_token(3),
"4": build_player_token(4),
"5": build_player_token(5),
"6": build_player_token(6),
"7": build_player_token(7),
}
}
-97
View File
@@ -1,97 +0,0 @@
import {
SingleBoxShadowToken,
SingleColorToken,
SingleOtherToken,
TokenTypes,
} from "@tokens-studio/types"
import { Shadow, SyntaxHighlightStyle, ThemeSyntax } from "../create_theme"
import { LayerToken, layer_token } from "./layer"
import { PlayersToken, players_token } from "./players"
import { color_token } from "./token"
import { Syntax } from "../syntax"
import editor from "../../style_tree/editor"
import { useTheme } from "../../../src/common"
interface ThemeTokens {
name: SingleOtherToken
appearance: SingleOtherToken
lowest: LayerToken
middle: LayerToken
highest: LayerToken
players: PlayersToken
popover_shadow: SingleBoxShadowToken
modal_shadow: SingleBoxShadowToken
syntax?: Partial<ThemeSyntaxColorTokens>
}
const create_shadow_token = (
shadow: Shadow,
token_name: string
): SingleBoxShadowToken => {
return {
name: token_name,
type: TokenTypes.BOX_SHADOW,
value: `${shadow.offset[0]}px ${shadow.offset[1]}px ${shadow.blur}px 0px ${shadow.color}`,
}
}
const popover_shadow_token = (): SingleBoxShadowToken => {
const theme = useTheme()
const shadow = theme.popover_shadow
return create_shadow_token(shadow, "popover_shadow")
}
const modal_shadow_token = (): SingleBoxShadowToken => {
const theme = useTheme()
const shadow = theme.modal_shadow
return create_shadow_token(shadow, "modal_shadow")
}
type ThemeSyntaxColorTokens = Record<keyof ThemeSyntax, SingleColorToken>
function syntax_highlight_style_color_tokens(
syntax: Syntax
): ThemeSyntaxColorTokens {
const style_keys = Object.keys(syntax) as (keyof Syntax)[]
return style_keys.reduce((acc, style_key) => {
// Hack: The type of a style could be "Function"
// This can happen because we have a "constructor" property on the syntax object
// and a "constructor" property on the prototype of the syntax object
// To work around this just assert that the type of the style is not a function
if (!syntax[style_key] || typeof syntax[style_key] === "function")
return acc
const { color } = syntax[style_key] as Required<SyntaxHighlightStyle>
return { ...acc, [style_key]: color_token(style_key, color) }
}, {} as ThemeSyntaxColorTokens)
}
const syntax_tokens = (): ThemeTokens["syntax"] => {
const syntax = editor().syntax
return syntax_highlight_style_color_tokens(syntax)
}
export function theme_tokens(): ThemeTokens {
const theme = useTheme()
return {
name: {
name: "themeName",
value: theme.name,
type: TokenTypes.OTHER,
},
appearance: {
name: "themeAppearance",
value: theme.is_light ? "light" : "dark",
type: TokenTypes.OTHER,
},
lowest: layer_token(theme.lowest, "lowest"),
middle: layer_token(theme.middle, "middle"),
highest: layer_token(theme.highest, "highest"),
popover_shadow: popover_shadow_token(),
modal_shadow: modal_shadow_token(),
players: players_token(),
syntax: syntax_tokens(),
}
}
-19
View File
@@ -1,19 +0,0 @@
import { SingleColorToken, TokenTypes } from "@tokens-studio/types"
export function color_token(
name: string,
value: string,
description?: string
): SingleColorToken {
const token: SingleColorToken = {
name,
type: TokenTypes.COLOR,
value,
description,
}
if (!token.value || token.value === "")
throw new Error("Color token must have a value")
return token
}
-21
View File
@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2017 <eliverlara@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-39
View File
@@ -1,39 +0,0 @@
import {
chroma,
color_ramp,
ThemeAppearance,
ThemeLicenseType,
ThemeConfig,
} from "../../common"
export const dark: ThemeConfig = {
name: "Andromeda",
author: "EliverLara",
appearance: ThemeAppearance.Dark,
license_type: ThemeLicenseType.MIT,
license_url: "https://github.com/EliverLara/Andromeda",
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma
.scale([
"#1E2025",
"#23262E",
"#292E38",
"#2E323C",
"#ACA8AE",
"#CBC9CF",
"#E1DDE4",
"#F7F7F8",
])
.domain([0, 0.15, 0.25, 0.35, 0.7, 0.8, 0.9, 1]),
red: color_ramp(chroma("#F92672")),
orange: color_ramp(chroma("#F39C12")),
yellow: color_ramp(chroma("#FFE66D")),
green: color_ramp(chroma("#96E072")),
cyan: color_ramp(chroma("#00E8C6")),
blue: color_ramp(chroma("#0CA793")),
violet: color_ramp(chroma("#8A3FA6")),
magenta: color_ramp(chroma("#C74DED")),
},
override: { syntax: {} },
}
-21
View File
@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#19171c",
base01: "#26232a",
base02: "#585260",
base03: "#655f6d",
base04: "#7e7887",
base05: "#8b8792",
base06: "#e2dfe7",
base07: "#efecf4",
base08: "#be4678",
base09: "#aa573c",
base0A: "#a06e3b",
base0B: "#2a9292",
base0C: "#398bc6",
base0D: "#576ddb",
base0E: "#955ae7",
base0F: "#bf40bf",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Cave Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#efecf4",
base01: "#e2dfe7",
base02: "#8b8792",
base03: "#7e7887",
base04: "#655f6d",
base05: "#585260",
base06: "#26232a",
base07: "#19171c",
base08: "#be4678",
base09: "#aa573c",
base0A: "#a06e3b",
base0B: "#2a9292",
base0C: "#398bc6",
base0D: "#576ddb",
base0E: "#955ae7",
base0F: "#bf40bf",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Cave Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#20201d",
base01: "#292824",
base02: "#6e6b5e",
base03: "#7d7a68",
base04: "#999580",
base05: "#a6a28c",
base06: "#e8e4cf",
base07: "#fefbec",
base08: "#d73737",
base09: "#b65611",
base0A: "#ae9513",
base0B: "#60ac39",
base0C: "#1fad83",
base0D: "#6684e1",
base0E: "#b854d4",
base0F: "#d43552",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Dune Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#fefbec",
base01: "#e8e4cf",
base02: "#a6a28c",
base03: "#999580",
base04: "#7d7a68",
base05: "#6e6b5e",
base06: "#292824",
base07: "#20201d",
base08: "#d73737",
base09: "#b65611",
base0A: "#ae9513",
base0B: "#60ac39",
base0C: "#1fad83",
base0D: "#6684e1",
base0E: "#b854d4",
base0F: "#d43552",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Dune Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#22221b",
base01: "#302f27",
base02: "#5f5e4e",
base03: "#6c6b5a",
base04: "#878573",
base05: "#929181",
base06: "#e7e6df",
base07: "#f4f3ec",
base08: "#ba6236",
base09: "#ae7313",
base0A: "#a5980d",
base0B: "#7d9726",
base0C: "#5b9d48",
base0D: "#36a166",
base0E: "#5f9182",
base0F: "#9d6c7c",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Estuary Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#f4f3ec",
base01: "#e7e6df",
base02: "#929181",
base03: "#878573",
base04: "#6c6b5a",
base05: "#5f5e4e",
base06: "#302f27",
base07: "#22221b",
base08: "#ba6236",
base09: "#ae7313",
base0A: "#a5980d",
base0B: "#7d9726",
base0C: "#5b9d48",
base0D: "#36a166",
base0E: "#5f9182",
base0F: "#9d6c7c",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Estuary Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#1b1918",
base01: "#2c2421",
base02: "#68615e",
base03: "#766e6b",
base04: "#9c9491",
base05: "#a8a19f",
base06: "#e6e2e0",
base07: "#f1efee",
base08: "#f22c40",
base09: "#df5320",
base0A: "#c38418",
base0B: "#7b9726",
base0C: "#3d97b8",
base0D: "#407ee7",
base0E: "#6666ea",
base0F: "#c33ff3",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Forest Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#f1efee",
base01: "#e6e2e0",
base02: "#a8a19f",
base03: "#9c9491",
base04: "#766e6b",
base05: "#68615e",
base06: "#2c2421",
base07: "#1b1918",
base08: "#f22c40",
base09: "#df5320",
base0A: "#c38418",
base0B: "#7b9726",
base0C: "#3d97b8",
base0D: "#407ee7",
base0E: "#6666ea",
base0F: "#c33ff3",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Forest Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#1b181b",
base01: "#292329",
base02: "#695d69",
base03: "#776977",
base04: "#9e8f9e",
base05: "#ab9bab",
base06: "#d8cad8",
base07: "#f7f3f7",
base08: "#ca402b",
base09: "#a65926",
base0A: "#bb8a35",
base0B: "#918b3b",
base0C: "#159393",
base0D: "#516aec",
base0E: "#7b59c0",
base0F: "#cc33cc",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Heath Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#f7f3f7",
base01: "#d8cad8",
base02: "#ab9bab",
base03: "#9e8f9e",
base04: "#776977",
base05: "#695d69",
base06: "#292329",
base07: "#1b181b",
base08: "#ca402b",
base09: "#a65926",
base0A: "#bb8a35",
base0B: "#918b3b",
base0C: "#159393",
base0D: "#516aec",
base0E: "#7b59c0",
base0F: "#cc33cc",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Heath Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#161b1d",
base01: "#1f292e",
base02: "#516d7b",
base03: "#5a7b8c",
base04: "#7195a8",
base05: "#7ea2b4",
base06: "#c1e4f6",
base07: "#ebf8ff",
base08: "#d22d72",
base09: "#935c25",
base0A: "#8a8a0f",
base0B: "#568c3b",
base0C: "#2d8f6f",
base0D: "#257fad",
base0E: "#6b6bb8",
base0F: "#b72dd2",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Lakeside Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#ebf8ff",
base01: "#c1e4f6",
base02: "#7ea2b4",
base03: "#7195a8",
base04: "#5a7b8c",
base05: "#516d7b",
base06: "#1f292e",
base07: "#161b1d",
base08: "#d22d72",
base09: "#935c25",
base0A: "#8a8a0f",
base0B: "#568c3b",
base0C: "#2d8f6f",
base0D: "#257fad",
base0E: "#6b6bb8",
base0F: "#b72dd2",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Lakeside Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#1b1818",
base01: "#292424",
base02: "#585050",
base03: "#655d5d",
base04: "#7e7777",
base05: "#8a8585",
base06: "#e7dfdf",
base07: "#f4ecec",
base08: "#ca4949",
base09: "#b45a3c",
base0A: "#a06e3b",
base0B: "#4b8b8b",
base0C: "#5485b6",
base0D: "#7272ca",
base0E: "#8464c4",
base0F: "#bd5187",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Plateau Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#f4ecec",
base01: "#e7dfdf",
base02: "#8a8585",
base03: "#7e7777",
base04: "#655d5d",
base05: "#585050",
base06: "#292424",
base07: "#1b1818",
base08: "#ca4949",
base09: "#b45a3c",
base0A: "#a06e3b",
base0B: "#4b8b8b",
base0C: "#5485b6",
base0D: "#7272ca",
base0E: "#8464c4",
base0F: "#bd5187",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Plateau Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#171c19",
base01: "#232a25",
base02: "#526057",
base03: "#5f6d64",
base04: "#78877d",
base05: "#87928a",
base06: "#dfe7e2",
base07: "#ecf4ee",
base08: "#b16139",
base09: "#9f713c",
base0A: "#a07e3b",
base0B: "#489963",
base0C: "#1c9aa0",
base0D: "#478c90",
base0E: "#55859b",
base0F: "#867469",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Savanna Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#ecf4ee",
base01: "#dfe7e2",
base02: "#87928a",
base03: "#78877d",
base04: "#5f6d64",
base05: "#526057",
base06: "#232a25",
base07: "#171c19",
base08: "#b16139",
base09: "#9f713c",
base0A: "#a07e3b",
base0B: "#489963",
base0C: "#1c9aa0",
base0D: "#478c90",
base0E: "#55859b",
base0F: "#867469",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Savanna Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#131513",
base01: "#242924",
base02: "#5e6e5e",
base03: "#687d68",
base04: "#809980",
base05: "#8ca68c",
base06: "#cfe8cf",
base07: "#f4fbf4",
base08: "#e6193c",
base09: "#87711d",
base0A: "#98981b",
base0B: "#29a329",
base0C: "#1999b3",
base0D: "#3d62f5",
base0E: "#ad2bee",
base0F: "#e619c3",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Seaside Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#f4fbf4",
base01: "#cfe8cf",
base02: "#8ca68c",
base03: "#809980",
base04: "#687d68",
base05: "#5e6e5e",
base06: "#242924",
base07: "#131513",
base08: "#e6193c",
base09: "#87711d",
base0A: "#98981b",
base0B: "#29a329",
base0C: "#1999b3",
base0D: "#3d62f5",
base0E: "#ad2bee",
base0F: "#e619c3",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Seaside Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,61 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#202746",
base01: "#293256",
base02: "#5e6687",
base03: "#6b7394",
base04: "#898ea4",
base05: "#979db4",
base06: "#dfe2f1",
base07: "#f5f7ff",
base08: "#c94922",
base09: "#c76b29",
base0A: "#c08b30",
base0B: "#ac9739",
base0C: "#22a2c9",
base0D: "#3d8fd1",
base0E: "#6679cc",
base0F: "#9c637a",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Sulphurpool Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale([
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
]),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
@@ -1,63 +0,0 @@
import { chroma, ThemeAppearance, ThemeConfig, color_ramp } from "../../common"
import { meta, build_syntax, Variant } from "./common"
const variant: Variant = {
colors: {
base00: "#f5f7ff",
base01: "#dfe2f1",
base02: "#979db4",
base03: "#898ea4",
base04: "#6b7394",
base05: "#5e6687",
base06: "#293256",
base07: "#202746",
base08: "#c94922",
base09: "#c76b29",
base0A: "#c08b30",
base0B: "#ac9739",
base0C: "#22a2c9",
base0D: "#3d8fd1",
base0E: "#6679cc",
base0F: "#9c637a",
},
}
const syntax = build_syntax(variant)
const get_theme = (variant: Variant): ThemeConfig => {
const { colors } = variant
return {
name: `${meta.name} Sulphurpool Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: {
neutral: chroma.scale(
[
colors.base00,
colors.base01,
colors.base02,
colors.base03,
colors.base04,
colors.base05,
colors.base06,
colors.base07,
].reverse()
),
red: color_ramp(chroma(colors.base08)),
orange: color_ramp(chroma(colors.base09)),
yellow: color_ramp(chroma(colors.base0A)),
green: color_ramp(chroma(colors.base0B)),
cyan: color_ramp(chroma(colors.base0C)),
blue: color_ramp(chroma(colors.base0D)),
violet: color_ramp(chroma(colors.base0E)),
magenta: color_ramp(chroma(colors.base0F)),
},
override: { syntax },
}
}
export const theme = get_theme(variant)
-56
View File
@@ -1,56 +0,0 @@
import { ThemeLicenseType, ThemeSyntax, ThemeFamilyMeta } from "../../common"
export interface Variant {
colors: {
base00: string
base01: string
base02: string
base03: string
base04: string
base05: string
base06: string
base07: string
base08: string
base09: string
base0A: string
base0B: string
base0C: string
base0D: string
base0E: string
base0F: string
}
}
export const meta: ThemeFamilyMeta = {
name: "Atelier",
author: "Bram de Haan (http://atelierbramdehaan.nl)",
license_type: ThemeLicenseType.MIT,
license_url:
"https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/",
}
export const build_syntax = (variant: Variant): ThemeSyntax => {
const { colors } = variant
return {
primary: { color: colors.base06 },
comment: { color: colors.base03 },
"punctuation.delimiter": { color: colors.base05 },
"punctuation.bracket": { color: colors.base05 },
"punctuation.special": { color: colors.base0F },
"string.special.symbol": { color: colors.base0B },
operator: { color: colors.base05 },
function: { color: colors.base0D },
"function.method": { color: colors.base0D },
"function.special.definition": { color: colors.base0A },
string: { color: colors.base0B },
"string.special": { color: colors.base0F },
"string.regex": { color: colors.base0C },
type: { color: colors.base0A },
number: { color: colors.base09 },
property: { color: colors.base08 },
variable: { color: colors.base06 },
"variable.special": { color: colors.base0E },
variant: { color: colors.base0A },
keyword: { color: colors.base0E },
}
}
-21
View File
@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2016 Ike Ku
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-16
View File
@@ -1,16 +0,0 @@
import { ThemeAppearance, ThemeConfig } from "../../common"
import { ayu, meta, build_theme } from "./common"
const variant = ayu.dark
const { ramps, syntax } = build_theme(variant, false)
export const theme: ThemeConfig = {
name: `${meta.name} Dark`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: ramps,
override: { syntax },
}
-16
View File
@@ -1,16 +0,0 @@
import { ThemeAppearance, ThemeConfig } from "../../common"
import { ayu, meta, build_theme } from "./common"
const variant = ayu.light
const { ramps, syntax } = build_theme(variant, true)
export const theme: ThemeConfig = {
name: `${meta.name} Light`,
author: meta.author,
appearance: ThemeAppearance.Light,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: ramps,
override: { syntax },
}
-16
View File
@@ -1,16 +0,0 @@
import { ThemeAppearance, ThemeConfig } from "../../common"
import { ayu, meta, build_theme } from "./common"
const variant = ayu.mirage
const { ramps, syntax } = build_theme(variant, false)
export const theme: ThemeConfig = {
name: `${meta.name} Mirage`,
author: meta.author,
appearance: ThemeAppearance.Dark,
license_type: meta.license_type,
license_url: meta.license_url,
license_file: `${__dirname}/LICENSE`,
input_color: ramps,
override: { syntax },
}

Some files were not shown because too many files have changed in this diff Show More