Use theme store to pass color_scheme directly to components

This commit is contained in:
Nate Butler 2023-07-04 00:13:04 -04:00
parent f8316dd127
commit d5acfe8fc1
36 changed files with 280 additions and 136 deletions

View File

@ -27,7 +27,8 @@
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"typescript": "^5.1.5", "typescript": "^5.1.5",
"utility-types": "^3.10.0", "utility-types": "^3.10.0",
"vitest": "^0.32.0" "vitest": "^0.32.0",
"zustand": "^4.3.8"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -2595,6 +2596,12 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"peer": true
},
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
@ -2706,6 +2713,18 @@
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
}, },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"peer": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/loupe": { "node_modules/loupe": {
"version": "2.3.6", "version": "2.3.6",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
@ -3292,6 +3311,18 @@
} }
] ]
}, },
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@ -4025,6 +4056,14 @@
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"node_modules/use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/utility-types": { "node_modules/utility-types": {
"version": "3.10.0", "version": "3.10.0",
"resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
@ -4305,6 +4344,29 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
},
"node_modules/zustand": {
"version": "4.3.8",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.8.tgz",
"integrity": "sha512-4h28KCkHg5ii/wcFFJ5Fp+k1J3gJoasaIbppdgZFO4BPJnsNxL0mQXBSFgOgAdCdBj35aDTPvdAJReTMntFPGg==",
"dependencies": {
"use-sync-external-store": "1.2.0"
},
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"immer": ">=9.0",
"react": ">=16.8"
},
"peerDependenciesMeta": {
"immer": {
"optional": true
},
"react": {
"optional": true
}
}
} }
} }
} }

View File

@ -16,21 +16,22 @@
"@tokens-studio/types": "^0.2.3", "@tokens-studio/types": "^0.2.3",
"@types/chroma-js": "^2.4.0", "@types/chroma-js": "^2.4.0",
"@types/node": "^18.14.1", "@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", "ayu": "^8.0.1",
"chroma-js": "^2.4.2", "chroma-js": "^2.4.2",
"deepmerge": "^4.3.0", "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", "json-schema-to-typescript": "^13.0.2",
"toml": "^3.0.0", "toml": "^3.0.0",
"ts-deepmerge": "^6.0.3", "ts-deepmerge": "^6.0.3",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"typescript": "^5.1.5",
"utility-types": "^3.10.0", "utility-types": "^3.10.0",
"vitest": "^0.32.0", "vitest": "^0.32.0",
"@typescript-eslint/eslint-plugin": "^5.60.1", "zustand": "^4.3.8"
"@typescript-eslint/parser": "^5.60.1",
"@vitest/coverage-v8": "^0.32.0",
"eslint": "^8.43.0",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.27.5",
"typescript": "^5.1.5"
} }
} }

View File

@ -4,6 +4,7 @@ import * as path from "path"
import app from "./style_tree/app" import app from "./style_tree/app"
import { ColorScheme, create_color_scheme } from "./theme/color_scheme" import { ColorScheme, create_color_scheme } from "./theme/color_scheme"
import { themes } from "./themes" import { themes } from "./themes"
import { useThemeStore } from "./theme"
const assets_directory = `${__dirname}/../../assets` const assets_directory = `${__dirname}/../../assets`
const temp_directory = fs.mkdtempSync(path.join(tmpdir(), "build-themes")) const temp_directory = fs.mkdtempSync(path.join(tmpdir(), "build-themes"))
@ -20,10 +21,17 @@ function clear_themes(theme_directory: string) {
} }
} }
const all_themes: ColorScheme[] = themes.map((theme) =>
create_color_scheme(theme)
)
function write_themes(themes: ColorScheme[], output_directory: string) { function write_themes(themes: ColorScheme[], output_directory: string) {
clear_themes(output_directory) clear_themes(output_directory)
for (const color_scheme of themes) { for (const color_scheme of themes) {
const style_tree = app(color_scheme) const { setTheme } = useThemeStore.getState()
setTheme(color_scheme)
const style_tree = app()
const style_tree_json = JSON.stringify(style_tree, null, 2) const style_tree_json = JSON.stringify(style_tree, null, 2)
const temp_path = path.join(temp_directory, `${color_scheme.name}.json`) const temp_path = path.join(temp_directory, `${color_scheme.name}.json`)
const out_path = path.join( const out_path = path.join(
@ -36,8 +44,4 @@ function write_themes(themes: ColorScheme[], output_directory: string) {
} }
} }
const all_themes: ColorScheme[] = themes.map((theme) =>
create_color_scheme(theme)
)
write_themes(all_themes, `${assets_directory}/themes`) write_themes(all_themes, `${assets_directory}/themes`)

View File

@ -1,6 +1,6 @@
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import { background, foreground } from "../style_tree/components" import { background, foreground } from "../style_tree/components"
import { ColorScheme } from "../theme/color_scheme" import { useTheme, ColorScheme } from "../theme"
export type Margin = { export type Margin = {
top: number top: number
@ -22,10 +22,9 @@ type ToggleableIconButtonOptions = IconButtonOptions & {
active_color?: keyof ColorScheme["lowest"] active_color?: keyof ColorScheme["lowest"]
} }
export function icon_button( export function icon_button({ color, margin, layer }: IconButtonOptions) {
theme: ColorScheme, const theme = useTheme()
{ color, margin, layer }: IconButtonOptions
) {
if (!color) color = "base" if (!color) color = "base"
const m = { const m = {
@ -75,8 +74,8 @@ export function toggleable_icon_button(
return toggleable({ return toggleable({
state: { state: {
inactive: icon_button(theme, { color, margin }), inactive: icon_button({ color, margin }),
active: icon_button(theme, { active: icon_button({
color: active_color ? active_color : color, color: active_color ? active_color : color,
margin, margin,
layer: theme.middle, layer: theme.middle,

View File

@ -5,7 +5,7 @@ import {
foreground, foreground,
text, text,
} from "../style_tree/components" } from "../style_tree/components"
import { ColorScheme } from "../theme/color_scheme" import { useTheme, ColorScheme } from "../theme"
import { Margin } from "./icon_button" import { Margin } from "./icon_button"
interface TextButtonOptions { interface TextButtonOptions {
@ -22,10 +22,13 @@ type ToggleableTextButtonOptions = TextButtonOptions & {
active_color?: keyof ColorScheme["lowest"] active_color?: keyof ColorScheme["lowest"]
} }
export function text_button( export function text_button({
theme: ColorScheme, color,
{ color, layer, margin, text_properties }: TextButtonOptions layer,
) { margin,
text_properties,
}: TextButtonOptions) {
const theme = useTheme()
if (!color) color = "base" if (!color) color = "base"
const text_options: TextProperties = { const text_options: TextProperties = {
@ -79,8 +82,8 @@ export function toggleable_text_button(
return toggleable({ return toggleable({
state: { state: {
inactive: text_button(theme, { color, margin }), inactive: text_button({ color, margin }),
active: text_button(theme, { active: text_button({
color: active_color ? active_color : color, color: active_color ? active_color : color,
margin, margin,
layer: theme.middle, layer: theme.middle,

View File

@ -17,45 +17,47 @@ import terminal from "./terminal"
import contact_list from "./contact_list" import contact_list from "./contact_list"
import toolbar_dropdown_menu from "./toolbar_dropdown_menu" import toolbar_dropdown_menu from "./toolbar_dropdown_menu"
import incoming_call_notification from "./incoming_call_notification" import incoming_call_notification from "./incoming_call_notification"
import { ColorScheme } from "../theme/color_scheme"
import welcome from "./welcome" import welcome from "./welcome"
import copilot from "./copilot" import copilot from "./copilot"
import assistant from "./assistant" import assistant from "./assistant"
import { titlebar } from "./titlebar" import { titlebar } from "./titlebar"
import editor from "./editor" import editor from "./editor"
import feedback from "./feedback" import feedback from "./feedback"
import { useTheme } from "../common"
export default function app(): any {
const theme = useTheme()
export default function app(theme: ColorScheme): any {
return { return {
meta: { meta: {
name: theme.name, name: theme.name,
is_light: theme.is_light, is_light: theme.is_light,
}, },
command_palette: command_palette(theme), command_palette: command_palette(),
contact_notification: contact_notification(theme), contact_notification: contact_notification(),
project_shared_notification: project_shared_notification(theme), project_shared_notification: project_shared_notification(),
incoming_call_notification: incoming_call_notification(theme), incoming_call_notification: incoming_call_notification(),
picker: picker(theme), picker: picker(),
workspace: workspace(theme), workspace: workspace(),
titlebar: titlebar(theme), titlebar: titlebar(),
copilot: copilot(theme), copilot: copilot(),
welcome: welcome(theme), welcome: welcome(),
context_menu: context_menu(theme), context_menu: context_menu(),
editor: editor(theme), editor: editor(),
project_diagnostics: project_diagnostics(theme), project_diagnostics: project_diagnostics(),
project_panel: project_panel(theme), project_panel: project_panel(),
contacts_popover: contacts_popover(theme), contacts_popover: contacts_popover(),
contact_finder: contact_finder(theme), contact_finder: contact_finder(),
contact_list: contact_list(theme), contact_list: contact_list(),
toolbar_dropdown_menu: toolbar_dropdown_menu(theme), toolbar_dropdown_menu: toolbar_dropdown_menu(),
search: search(theme), search: search(),
shared_screen: shared_screen(theme), shared_screen: shared_screen(),
update_notification: update_notification(theme), update_notification: update_notification(),
simple_message_notification: simple_message_notification(theme), simple_message_notification: simple_message_notification(),
tooltip: tooltip(theme), tooltip: tooltip(),
terminal: terminal(theme), terminal: terminal(),
assistant: assistant(theme), assistant: assistant(),
feedback: feedback(theme), feedback: feedback(),
color_scheme: { color_scheme: {
...theme, ...theme,
players: Object.values(theme.players), players: Object.values(theme.players),

View File

@ -1,8 +1,10 @@
import { ColorScheme } from "../theme/color_scheme"
import { text, border, background, foreground } from "./components" import { text, border, background, foreground } from "./components"
import { interactive } from "../element" import { interactive } from "../element"
import { useTheme } from "../theme"
export default function assistant(): any {
const theme = useTheme()
export default function assistant(theme: ColorScheme): any {
return { return {
container: { container: {
background: background(theme.highest), background: background(theme.highest),

View File

@ -1,9 +1,11 @@
import { ColorScheme } from "../theme/color_scheme"
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { text, background } from "./components" import { text, background } from "./components"
import { toggleable } from "../element" import { toggleable } from "../element"
import { useTheme } from "../theme"
export default function command_palette(): any {
const theme = useTheme()
export default function command_palette(theme: ColorScheme): any {
const key = toggleable({ const key = toggleable({
base: { base: {
text: text(theme.highest, "mono", "variant", "default", { text: text(theme.highest, "mono", "variant", "default", {

View File

@ -1,8 +1,10 @@
import picker from "./picker" import picker from "./picker"
import { ColorScheme } from "../theme/color_scheme"
import { background, border, foreground, text } from "./components" import { background, border, foreground, text } from "./components"
import { useTheme } from "../theme"
export default function contact_finder(): any {
const theme = useTheme()
export default function contact_finder(theme: ColorScheme): any {
const side_margin = 6 const side_margin = 6
const contact_button = { const contact_button = {
background: background(theme.middle, "variant"), background: background(theme.middle, "variant"),
@ -12,7 +14,7 @@ export default function contact_finder(theme: ColorScheme): any {
corner_radius: 8, corner_radius: 8,
} }
const picker_style = picker(theme) const picker_style = picker()
const picker_input = { const picker_input = {
background: background(theme.middle, "on"), background: background(theme.middle, "on"),
corner_radius: 6, corner_radius: 6,

View File

@ -1,4 +1,3 @@
import { ColorScheme } from "../theme/color_scheme"
import { import {
background, background,
border, border,
@ -7,7 +6,10 @@ import {
text, text,
} from "./components" } from "./components"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
export default function contacts_panel(theme: ColorScheme): any { import { useTheme } from "../theme"
export default function contacts_panel(): any {
const theme = useTheme()
const name_margin = 8 const name_margin = 8
const side_padding = 12 const side_padding = 12

View File

@ -1,8 +1,10 @@
import { ColorScheme } from "../theme/color_scheme"
import { background, foreground, text } from "./components" import { background, foreground, text } from "./components"
import { interactive } from "../element" import { interactive } from "../element"
import { useTheme } from "../theme"
export default function contact_notification(): any {
const theme = useTheme()
export default function contact_notification(theme: ColorScheme): any {
const avatar_size = 12 const avatar_size = 12
const header_padding = 8 const header_padding = 8

View File

@ -1,7 +1,9 @@
import { ColorScheme } from "../theme/color_scheme" import { useTheme } from "../theme"
import { background, border } from "./components" import { background, border } from "./components"
export default function contacts_popover(theme: ColorScheme): any { export default function contacts_popover(): any {
const theme = useTheme()
return { return {
background: background(theme.middle), background: background(theme.middle),
corner_radius: 6, corner_radius: 6,

View File

@ -1,8 +1,10 @@
import { ColorScheme } from "../theme/color_scheme"
import { background, border, border_color, text } from "./components" import { background, border, border_color, text } from "./components"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
export default function context_menu(): any {
const theme = useTheme()
export default function context_menu(theme: ColorScheme): any {
return { return {
background: background(theme.middle), background: background(theme.middle),
corner_radius: 10, corner_radius: 10,

View File

@ -1,7 +1,9 @@
import { ColorScheme } from "../theme/color_scheme"
import { background, border, foreground, svg, text } from "./components" import { background, border, foreground, svg, text } from "./components"
import { interactive } from "../element" import { interactive } from "../element"
export default function copilot(theme: ColorScheme): any { import { useTheme } from "../theme"
export default function copilot(): any {
const theme = useTheme()
const content_width = 264 const content_width = 264
const cta_button = const cta_button =

View File

@ -1,5 +1,5 @@
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { ColorScheme, Layer, StyleSets } from "../theme/color_scheme" import { Layer, StyleSets } from "../theme/color_scheme"
import { import {
background, background,
border, border,
@ -11,8 +11,11 @@ import hover_popover from "./hover_popover"
import { build_syntax } from "../theme/syntax" import { build_syntax } from "../theme/syntax"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
export default function editor(): any {
const theme = useTheme()
export default function editor(theme: ColorScheme): any {
const { is_light } = theme const { is_light } = theme
const layer = theme.highest const layer = theme.highest
@ -248,7 +251,7 @@ export default function editor(theme: ColorScheme): any {
invalid_hint_diagnostic: diagnostic(theme.middle, "base"), invalid_hint_diagnostic: diagnostic(theme.middle, "base"),
invalid_information_diagnostic: diagnostic(theme.middle, "base"), invalid_information_diagnostic: diagnostic(theme.middle, "base"),
invalid_warning_diagnostic: diagnostic(theme.middle, "base"), invalid_warning_diagnostic: diagnostic(theme.middle, "base"),
hover_popover: hover_popover(theme), hover_popover: hover_popover(),
link_definition: { link_definition: {
color: syntax.link_uri.color, color: syntax.link_uri.color,
underline: syntax.link_uri.underline, underline: syntax.link_uri.underline,

View File

@ -1,8 +1,10 @@
import { ColorScheme } from "../theme/color_scheme"
import { background, border, text } from "./components" import { background, border, text } from "./components"
import { interactive } from "../element" import { interactive } from "../element"
import { useTheme } from "../theme"
export default function feedback(): any {
const theme = useTheme()
export default function feedback(theme: ColorScheme): any {
return { return {
submit_button: interactive({ submit_button: interactive({
base: { base: {

View File

@ -1,7 +1,9 @@
import { ColorScheme } from "../theme/color_scheme" import { useTheme } from "../theme"
import { background, border, foreground, text } from "./components" import { background, border, foreground, text } from "./components"
export default function hover_popover(theme: ColorScheme): any { export default function hover_popover(): any {
const theme = useTheme()
const base_container = { const base_container = {
background: background(theme.middle), background: background(theme.middle),
corner_radius: 8, corner_radius: 8,

View File

@ -1,9 +1,9 @@
import { ColorScheme } from "../theme/color_scheme" import { useTheme } from "../theme"
import { background, border, text } from "./components" import { background, border, text } from "./components"
export default function incoming_call_notification( export default function incoming_call_notification(): unknown {
theme: ColorScheme const theme = useTheme()
): unknown {
const avatar_size = 48 const avatar_size = 48
return { return {
window_height: 74, window_height: 74,

View File

@ -1,9 +1,11 @@
import { ColorScheme } from "../theme/color_scheme"
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { background, border, text } from "./components" import { background, border, text } from "./components"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
export default function picker(): any {
const theme = useTheme()
export default function picker(theme: ColorScheme): any {
const container = { const container = {
background: background(theme.lowest), background: background(theme.lowest),
border: border(theme.lowest), border: border(theme.lowest),

View File

@ -1,7 +1,9 @@
import { ColorScheme } from "../theme/color_scheme" import { useTheme } from "../theme"
import { background, text } from "./components" import { background, text } from "./components"
export default function project_diagnostics(theme: ColorScheme): any { export default function project_diagnostics(): any {
const theme = useTheme()
return { return {
background: background(theme.highest), background: background(theme.highest),
tab_icon_spacing: 4, tab_icon_spacing: 4,

View File

@ -1,4 +1,3 @@
import { ColorScheme } from "../theme/color_scheme"
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { import {
Border, Border,
@ -10,7 +9,10 @@ import {
} from "./components" } from "./components"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import merge from "ts-deepmerge" import merge from "ts-deepmerge"
export default function project_panel(theme: ColorScheme): any { import { useTheme } from "../theme"
export default function project_panel(): any {
const theme = useTheme()
const { is_light } = theme const { is_light } = theme
type EntryStateProps = { type EntryStateProps = {
@ -65,13 +67,12 @@ export default function project_panel(theme: ColorScheme): any {
const unselected_hovered_style = merge( const unselected_hovered_style = merge(
base_properties, base_properties,
{ background: background(theme.middle, "hovered") }, { background: background(theme.middle, "hovered") },
unselected?.hovered ?? {}, unselected?.hovered ?? {}
) )
const unselected_clicked_style = merge( const unselected_clicked_style = merge(
base_properties, base_properties,
{ background: background(theme.middle, "pressed"), } { background: background(theme.middle, "pressed") },
, unselected?.clicked ?? {}
unselected?.clicked ?? {},
) )
const selected_default_style = merge( const selected_default_style = merge(
base_properties, base_properties,
@ -79,18 +80,15 @@ export default function project_panel(theme: ColorScheme): any {
background: background(theme.lowest), background: background(theme.lowest),
text: text(theme.lowest, "sans", { size: "sm" }), text: text(theme.lowest, "sans", { size: "sm" }),
}, },
selected_style?.default ?? {}, selected_style?.default ?? {}
) )
const selected_hovered_style = merge( const selected_hovered_style = merge(
base_properties, base_properties,
{ {
background: background(theme.lowest, "hovered"), background: background(theme.lowest, "hovered"),
text: text(theme.lowest, "sans", { size: "sm" }), text: text(theme.lowest, "sans", { size: "sm" }),
}, },
selected_style?.hovered ?? {}, selected_style?.hovered ?? {}
) )
const selected_clicked_style = merge( const selected_clicked_style = merge(
base_properties, base_properties,
@ -98,8 +96,7 @@ export default function project_panel(theme: ColorScheme): any {
background: background(theme.lowest, "pressed"), background: background(theme.lowest, "pressed"),
text: text(theme.lowest, "sans", { size: "sm" }), text: text(theme.lowest, "sans", { size: "sm" }),
}, },
selected_style?.clicked ?? {}, selected_style?.clicked ?? {}
) )
return toggleable({ return toggleable({

View File

@ -1,9 +1,9 @@
import { ColorScheme } from "../theme/color_scheme" import { useTheme } from "../theme"
import { background, border, text } from "./components" import { background, border, text } from "./components"
export default function project_shared_notification( export default function project_shared_notification(): unknown {
theme: ColorScheme const theme = useTheme()
): unknown {
const avatar_size = 48 const avatar_size = 48
return { return {
window_height: 74, window_height: 74,

View File

@ -1,9 +1,11 @@
import { ColorScheme } from "../theme/color_scheme"
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { background, border, foreground, text } from "./components" import { background, border, foreground, text } from "./components"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
export default function search(): any {
const theme = useTheme()
export default function search(theme: ColorScheme): any {
// Search input // Search input
const editor = { const editor = {
background: background(theme.highest), background: background(theme.highest),

View File

@ -1,7 +1,9 @@
import { ColorScheme } from "../theme/color_scheme" import { useTheme } from "../theme"
import { background } from "./components" import { background } from "./components"
export default function sharedScreen(theme: ColorScheme) { export default function sharedScreen() {
const theme = useTheme()
return { return {
background: background(theme.highest), background: background(theme.highest),
} }

View File

@ -1,8 +1,10 @@
import { ColorScheme } from "../theme/color_scheme"
import { background, border, foreground, text } from "./components" import { background, border, foreground, text } from "./components"
import { interactive } from "../element" import { interactive } from "../element"
import { useTheme } from "../theme"
export default function simple_message_notification(): any {
const theme = useTheme()
export default function simple_message_notification(theme: ColorScheme): any {
const header_padding = 8 const header_padding = 8
return { return {

View File

@ -1,7 +1,9 @@
import { ColorScheme } from "../theme/color_scheme"
import { background, border, foreground, text } from "./components" import { background, border, foreground, text } from "./components"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
export default function status_bar(theme: ColorScheme): any { import { useTheme } from "../common"
export default function status_bar(): any {
const theme = useTheme()
const layer = theme.lowest const layer = theme.lowest
const status_container = { const status_container = {

View File

@ -1,9 +1,11 @@
import { ColorScheme } from "../theme/color_scheme"
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { text, border, background, foreground } from "./components" import { text, border, background, foreground } from "./components"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import { useTheme } from "../common"
export default function tab_bar(): any {
const theme = useTheme()
export default function tab_bar(theme: ColorScheme): any {
const height = 32 const height = 32
const active_layer = theme.highest const active_layer = theme.highest

View File

@ -1,6 +1,8 @@
import { ColorScheme } from "../theme/color_scheme" import { useTheme } from "../theme"
export default function terminal() {
const theme = useTheme()
export default function terminal(theme: ColorScheme) {
/** /**
* Colors are controlled per-cell in the terminal grid. * Colors are controlled per-cell in the terminal grid.
* Cells can be set to any of these more 'theme-capable' colors * Cells can be set to any of these more 'theme-capable' colors

View File

@ -1,7 +1,7 @@
import { ColorScheme } from "../common"
import { icon_button, toggleable_icon_button } from "../component/icon_button" import { icon_button, toggleable_icon_button } from "../component/icon_button"
import { toggleable_text_button } from "../component/text_button" import { toggleable_text_button } from "../component/text_button"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import { useTheme } from "../theme"
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { background, border, foreground, text } from "./components" import { background, border, foreground, text } from "./components"
@ -22,7 +22,9 @@ function build_spacing(
} }
} }
function call_controls(theme: ColorScheme) { function call_controls() {
const theme = useTheme()
const button_height = 18 const button_height = 18
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING) const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
@ -69,7 +71,9 @@ function call_controls(theme: ColorScheme) {
* When logged in shows the user's avatar and a chevron, * When logged in shows the user's avatar and a chevron,
* When logged out only shows a chevron. * When logged out only shows a chevron.
*/ */
function user_menu(theme: ColorScheme) { function user_menu() {
const theme = useTheme()
const button_height = 18 const button_height = 18
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING) const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
@ -155,7 +159,9 @@ function user_menu(theme: ColorScheme) {
} }
} }
export function titlebar(theme: ColorScheme): any { export function titlebar(): any {
const theme = useTheme()
const avatar_width = 15 const avatar_width = 15
const avatar_outer_width = avatar_width + 4 const avatar_outer_width = avatar_width + 4
const follower_avatar_width = 14 const follower_avatar_width = 14
@ -237,14 +243,14 @@ export function titlebar(theme: ColorScheme): any {
corner_radius: 6, corner_radius: 6,
}, },
leave_call_button: icon_button(theme, { leave_call_button: icon_button({
margin: { margin: {
left: ITEM_SPACING / 2, left: ITEM_SPACING / 2,
right: ITEM_SPACING, right: ITEM_SPACING,
}, },
}), }),
...call_controls(theme), ...call_controls(),
toggle_contacts_button: toggleable_icon_button(theme, { toggle_contacts_button: toggleable_icon_button(theme, {
margin: { margin: {
@ -261,6 +267,6 @@ export function titlebar(theme: ColorScheme): any {
background: foreground(theme.lowest, "accent"), background: foreground(theme.lowest, "accent"),
}, },
share_button: toggleable_text_button(theme, {}), share_button: toggleable_text_button(theme, {}),
user_menu: user_menu(theme), user_menu: user_menu(),
} }
} }

View File

@ -1,7 +1,9 @@
import { ColorScheme } from "../theme/color_scheme"
import { background, border, text } from "./components" import { background, border, text } from "./components"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
export default function dropdown_menu(theme: ColorScheme): any { import { useTheme } from "../theme"
export default function dropdown_menu(): any {
const theme = useTheme()
return { return {
row_height: 30, row_height: 30,
background: background(theme.middle), background: background(theme.middle),

View File

@ -1,7 +1,9 @@
import { ColorScheme } from "../theme/color_scheme" import { useTheme } from "../theme"
import { background, border, text } from "./components" import { background, border, text } from "./components"
export default function tooltip(theme: ColorScheme): any { export default function tooltip(): any {
const theme = useTheme()
return { return {
background: background(theme.middle), background: background(theme.middle),
border: border(theme.middle), border: border(theme.middle),

View File

@ -1,8 +1,10 @@
import { ColorScheme } from "../theme/color_scheme"
import { foreground, text } from "./components" import { foreground, text } from "./components"
import { interactive } from "../element" import { interactive } from "../element"
import { useTheme } from "../theme"
export default function update_notification(): any {
const theme = useTheme()
export default function update_notification(theme: ColorScheme): any {
const header_padding = 8 const header_padding = 8
return { return {

View File

@ -1,4 +1,3 @@
import { ColorScheme } from "../theme/color_scheme"
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { import {
border, border,
@ -9,8 +8,11 @@ import {
svg, svg,
} from "./components" } from "./components"
import { interactive } from "../element" import { interactive } from "../element"
import { useTheme } from "../theme"
export default function welcome(): any {
const theme = useTheme()
export default function welcome(theme: ColorScheme): any {
const checkbox_base = { const checkbox_base = {
corner_radius: 4, corner_radius: 4,
padding: { padding: {

View File

@ -1,4 +1,3 @@
import { ColorScheme } from "../theme/color_scheme"
import { with_opacity } from "../theme/color" import { with_opacity } from "../theme/color"
import { import {
background, background,
@ -11,9 +10,12 @@ import {
import statusBar from "./status_bar" import statusBar from "./status_bar"
import tabBar from "./tab_bar" import tabBar from "./tab_bar"
import { interactive } from "../element" import { interactive } from "../element"
import { titlebar } from "./titlebar" import { titlebar } from "./titlebar"
export default function workspace(theme: ColorScheme): any { import { useTheme } from "../theme"
export default function workspace(): any {
const theme = useTheme()
const { is_light } = theme const { is_light } = theme
return { return {
@ -85,7 +87,7 @@ export default function workspace(theme: ColorScheme): any {
}, },
leader_border_opacity: 0.7, leader_border_opacity: 0.7,
leader_border_width: 2.0, leader_border_width: 2.0,
tab_bar: tabBar(theme), tab_bar: tabBar(),
modal: { modal: {
margin: { margin: {
bottom: 52, bottom: 52,
@ -123,8 +125,8 @@ export default function workspace(theme: ColorScheme): any {
color: border_color(theme.lowest), color: border_color(theme.lowest),
width: 1, width: 1,
}, },
status_bar: statusBar(theme), status_bar: statusBar(),
titlebar: titlebar(theme), titlebar: titlebar(),
toolbar: { toolbar: {
height: 34, height: 34,
background: background(theme.highest), background: background(theme.highest),

View File

@ -1,3 +1,24 @@
import { create } from "zustand"
import { ColorScheme } from "./color_scheme"
type ThemeState = {
theme: ColorScheme | undefined
setTheme: (theme: ColorScheme) => void
}
export const useThemeStore = create<ThemeState>((set) => ({
theme: undefined,
setTheme: (theme) => set(() => ({ theme })),
}))
export const useTheme = (): ColorScheme => {
const { theme } = useThemeStore.getState()
if (!theme) throw new Error("Tried to use theme before it was loaded")
return theme
}
export * from "./color_scheme" export * from "./color_scheme"
export * from "./ramps" export * from "./ramps"
export * from "./syntax" export * from "./syntax"