Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/app/src/pages/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const HOME_ROW_LAYOUT =
const HOME_ROW_BASE = `${HOME_ROW_LAYOUT} border-0`
const HOME_ROW = `${HOME_ROW_BASE} [font-weight:530] text-v2-text-text-muted hover:bg-v2-overlay-simple-overlay-hover focus-visible:bg-v2-overlay-simple-overlay-hover`
const HOME_PROJECT_NAV_LABEL = "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap"
const HOME_PROJECT_NAV_ROW = `${HOME_ROW_LAYOUT} h-7 gap-2 px-1.5 [font-weight:440] text-v2-text-text-muted hover:bg-v2-background-bg-layer-01 hover:text-v2-text-text-base hover:[box-shadow:inset_0_0_0_0.5px_var(--v2-border-border-muted)] data-[selected]:bg-v2-background-bg-layer-02 data-[selected]:text-v2-text-text-base data-[selected]:[box-shadow:inset_0_0_0_0.5px_var(--v2-border-border-muted)] data-[selected]:hover:bg-v2-background-bg-layer-02 focus-visible:bg-v2-background-bg-layer-01 focus-visible:text-v2-text-text-base focus-visible:[box-shadow:inset_0_0_0_0.5px_var(--v2-border-border-muted)]`
const HOME_PROJECT_NAV_ROW = `${HOME_ROW_LAYOUT} h-7 gap-2 px-1.5 [font-weight:440] text-v2-text-text-muted hover:bg-v2-background-bg-layer-01 hover:text-v2-text-text-base hover:[box-shadow:inset_0_0_0_0.5px_var(--v2-border-border-muted)] data-[selected]:bg-v2-background-bg-layer-03 data-[selected]:text-v2-text-text-base data-[selected]:[box-shadow:inset_0_0_0_0.5px_var(--v2-border-border-muted)] data-[selected]:hover:bg-v2-background-bg-layer-03 focus-visible:bg-v2-background-bg-layer-01 focus-visible:text-v2-text-text-base focus-visible:[box-shadow:inset_0_0_0_0.5px_var(--v2-border-border-muted)]`
const HOME_SECTION_LABEL = "text-v2-text-text-muted [font-weight:440]"

type HomeSessionRecord = {
Expand Down Expand Up @@ -890,7 +890,7 @@ function HomeSessionSearch(props: {
<label
class="relative z-20 flex h-9 w-full items-center gap-2 rounded-[6px] py-1 pl-3 pr-2 text-v2-icon-icon-muted transition-[background-color,box-shadow] duration-[120ms] ease-in-out"
classList={{
"bg-v2-background-bg-deep focus-within:bg-v2-background-bg-base focus-within:shadow-[0_0_0_0.5px_var(--v2-border-border-focus),var(--v2-elevation-raised)]":
"bg-v2-background-bg-layer-03 focus-within:bg-v2-background-bg-layer-03 focus-within:shadow-[0_0_0_0.5px_var(--v2-border-border-focus),var(--v2-elevation-raised)]":
!props.open,
"bg-transparent shadow-[0_0_0_0.5px_var(--v2-border-border-focus)]": props.open,
}}
Expand Down
28 changes: 14 additions & 14 deletions packages/ui/script/colors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -228,29 +228,29 @@
--button-ghost-hover: var(--smoke-light-alpha-2);
--button-ghost-hover2: var(--smoke-light-alpha-3);

--v2-background-bg-base: var(--v2-grey-100);
--v2-background-bg-deep: var(--v2-grey-200);
--v2-background-bg-layer-01: var(--v2-grey-200);
--v2-background-bg-layer-02: var(--v2-grey-300);
--v2-background-bg-layer-03: var(--v2-grey-400);
--v2-background-bg-layer-04: var(--v2-grey-600);
--v2-background-bg-inverse: var(--v2-grey-1000);
--v2-background-bg-contrast: var(--v2-grey-900);
--v2-background-bg-button-neutral: var(--v2-grey-100);
--v2-background-bg-base: var(--v2-grey-50);
--v2-background-bg-deep: var(--v2-grey-100);
--v2-background-bg-layer-01: var(--v2-grey-100);
--v2-background-bg-layer-02: var(--v2-grey-200);
--v2-background-bg-layer-03: var(--v2-grey-300);
--v2-background-bg-layer-04: var(--v2-grey-400);
--v2-background-bg-inverse: var(--v2-grey-1100);
--v2-background-bg-contrast: var(--v2-grey-1000);
--v2-background-bg-button-neutral: var(--v2-grey-50);
--v2-background-bg-accent: var(--v2-blue-600);

--v2-text-text-base: var(--v2-grey-1000);
--v2-text-text-base: var(--v2-grey-1100);
--v2-text-text-muted: var(--v2-grey-700);
--v2-text-text-faint: var(--v2-grey-600);
--v2-text-text-inverse: var(--v2-grey-100);
--v2-text-text-contrast: var(--v2-grey-100);
--v2-text-text-inverse: var(--v2-grey-50);
--v2-text-text-contrast: var(--v2-grey-50);
--v2-text-text-accent: var(--v2-blue-600);
--v2-text-text-accent-hover: var(--v2-blue-700);

--v2-icon-icon-base: var(--v2-grey-800);
--v2-icon-icon-muted: var(--v2-grey-600);
--v2-icon-icon-inverse: var(--v2-grey-100);
--v2-icon-icon-contrast: var(--v2-grey-200);
--v2-icon-icon-inverse: var(--v2-grey-50);
--v2-icon-icon-contrast: var(--v2-grey-100);
--v2-icon-icon-accent: var(--v2-blue-600);
--v2-icon-icon-accent-hover: var(--v2-blue-700);

Expand Down
13 changes: 13 additions & 0 deletions packages/ui/src/theme/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,19 @@ export function shift(color: HexColor, value: { l?: number; c?: number; h?: numb
})
}

export function contrastRatio(foreground: HexColor, background: HexColor) {
const linear = (c: number) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4)
const luminance = (hex: HexColor) => {
const { r, g, b } = hexToRgb(hex)
return 0.2126 * linear(r) + 0.587 * linear(g) + 0.0722 * linear(b)
}
const fg = luminance(foreground)
const bg = luminance(background)
const lighter = Math.max(fg, bg)
const darker = Math.min(fg, bg)
return (lighter + 0.05) / (darker + 0.05)
}

export function blend(color: HexColor, background: HexColor, alpha: number): HexColor {
const fg = hexToRgb(color)
const bg = hexToRgb(background)
Expand Down
78 changes: 40 additions & 38 deletions packages/ui/src/theme/themes/oc-2.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,19 @@
"surface-critical-base": "#FFF2F0"
},
"v2Overrides": {
"v2-grey-100": "#ffffffff",
"v2-grey-200": "#fafafaff",
"v2-grey-50": "#ffffffff",
"v2-grey-100": "#fafafaff",
"v2-grey-200": "#f2f2f2ff",
"v2-grey-300": "#eeeeeeff",
"v2-grey-400": "#d4d4d4ff",
"v2-grey-400": "#dbdbdbff",
"v2-grey-500": "#aeaeaeff",
"v2-grey-600": "#808080ff",
"v2-grey-700": "#5c5c5cff",
"v2-grey-800": "#3a3a3aff",
"v2-grey-900": "#242424ff",
"v2-grey-1000": "#161616ff",
"v2-grey-1100": "#080808ff",
"v2-grey-1200": "#000000ff",
"v2-grey-900": "#2e2e2eff",
"v2-grey-1000": "#242424ff",
"v2-grey-1100": "#161616ff",
"v2-grey-1200": "#080808ff",
"v2-red-100": "#fcecebff",
"v2-red-200": "#f6d5d3ff",
"v2-red-300": "#f2bbb7ff",
Expand Down Expand Up @@ -152,27 +153,27 @@
"v2-pink-1000": "#8c2d61ff",
"v2-pink-1100": "#6f284fff",
"v2-pink-1200": "#5c1d3fff",
"v2-background-bg-base": "var(--v2-grey-100)",
"v2-background-bg-deep": "var(--v2-grey-200)",
"v2-background-bg-layer-01": "var(--v2-grey-200)",
"v2-background-bg-layer-02": "var(--v2-grey-300)",
"v2-background-bg-layer-03": "var(--v2-grey-400)",
"v2-background-bg-base": "var(--v2-grey-50)",
"v2-background-bg-deep": "var(--v2-grey-100)",
"v2-background-bg-layer-01": "var(--v2-grey-100)",
"v2-background-bg-layer-02": "var(--v2-grey-200)",
"v2-background-bg-layer-03": "var(--v2-grey-300)",
"v2-background-bg-layer-04": "var(--v2-grey-400)",
"v2-background-bg-inverse": "var(--v2-grey-1000)",
"v2-background-bg-contrast": "var(--v2-grey-900)",
"v2-background-bg-button-neutral": "var(--v2-grey-100)",
"v2-background-bg-inverse": "var(--v2-grey-1100)",
"v2-background-bg-contrast": "var(--v2-grey-1000)",
"v2-background-bg-button-neutral": "var(--v2-grey-50)",
"v2-background-bg-accent": "var(--v2-blue-600)",
"v2-text-text-base": "var(--v2-grey-1000)",
"v2-text-text-base": "var(--v2-grey-1100)",
"v2-text-text-muted": "var(--v2-grey-700)",
"v2-text-text-faint": "var(--v2-grey-600)",
"v2-text-text-inverse": "var(--v2-grey-100)",
"v2-text-text-contrast": "var(--v2-grey-100)",
"v2-text-text-inverse": "var(--v2-grey-50)",
"v2-text-text-contrast": "var(--v2-grey-50)",
"v2-text-text-accent": "var(--v2-blue-600)",
"v2-text-text-accent-hover": "var(--v2-blue-700)",
"v2-icon-icon-base": "var(--v2-grey-800)",
"v2-icon-icon-muted": "var(--v2-grey-600)",
"v2-icon-icon-inverse": "var(--v2-grey-100)",
"v2-icon-icon-contrast": "var(--v2-grey-200)",
"v2-icon-icon-inverse": "var(--v2-grey-50)",
"v2-icon-icon-contrast": "var(--v2-grey-100)",
"v2-icon-icon-accent": "var(--v2-blue-600)",
"v2-icon-icon-accent-hover": "var(--v2-blue-700)",
"v2-border-border-muted": "var(--v2-alpha-dark-8)",
Expand Down Expand Up @@ -274,18 +275,19 @@
"surface-critical-base": "#1F0603"
},
"v2Overrides": {
"v2-grey-100": "#ffffffff",
"v2-grey-200": "#fafafaff",
"v2-grey-50": "#ffffffff",
"v2-grey-100": "#fafafaff",
"v2-grey-200": "#f2f2f2ff",
"v2-grey-300": "#eeeeeeff",
"v2-grey-400": "#d4d4d4ff",
"v2-grey-400": "#dbdbdbff",
"v2-grey-500": "#aeaeaeff",
"v2-grey-600": "#808080ff",
"v2-grey-700": "#5c5c5cff",
"v2-grey-800": "#3a3a3aff",
"v2-grey-900": "#242424ff",
"v2-grey-1000": "#161616ff",
"v2-grey-1100": "#080808ff",
"v2-grey-1200": "#000000ff",
"v2-grey-900": "#2e2e2eff",
"v2-grey-1000": "#242424ff",
"v2-grey-1100": "#161616ff",
"v2-grey-1200": "#080808ff",
"v2-red-100": "#fcecebff",
"v2-red-200": "#f6d5d3ff",
"v2-red-300": "#f2bbb7ff",
Expand Down Expand Up @@ -382,27 +384,27 @@
"v2-pink-1000": "#8c2d61ff",
"v2-pink-1100": "#6f284fff",
"v2-pink-1200": "#5c1d3fff",
"v2-background-bg-base": "var(--v2-grey-1000)",
"v2-background-bg-deep": "var(--v2-grey-1100)",
"v2-background-bg-layer-01": "var(--v2-grey-900)",
"v2-background-bg-layer-02": "var(--v2-grey-800)",
"v2-background-bg-layer-03": "var(--v2-grey-700)",
"v2-background-bg-base": "var(--v2-grey-1100)",
"v2-background-bg-deep": "var(--v2-grey-1200)",
"v2-background-bg-layer-01": "var(--v2-grey-1000)",
"v2-background-bg-layer-02": "var(--v2-grey-900)",
"v2-background-bg-layer-03": "var(--v2-grey-800)",
"v2-background-bg-layer-04": "var(--v2-grey-700)",
"v2-background-bg-inverse": "var(--v2-grey-100)",
"v2-background-bg-inverse": "var(--v2-grey-50)",
"v2-background-bg-contrast": "var(--v2-grey-700)",
"v2-background-bg-button-neutral": "var(--v2-alpha-light-6)",
"v2-background-bg-accent": "var(--v2-blue-600)",
"v2-text-text-base": "var(--v2-grey-200)",
"v2-text-text-base": "var(--v2-grey-100)",
"v2-text-text-muted": "var(--v2-grey-500)",
"v2-text-text-faint": "var(--v2-grey-600)",
"v2-text-text-inverse": "var(--v2-grey-1000)",
"v2-text-text-contrast": "var(--v2-grey-100)",
"v2-text-text-inverse": "var(--v2-grey-1100)",
"v2-text-text-contrast": "var(--v2-grey-50)",
"v2-text-text-accent": "var(--v2-blue-400)",
"v2-text-text-accent-hover": "var(--v2-blue-300)",
"v2-icon-icon-base": "var(--v2-grey-400)",
"v2-icon-icon-muted": "var(--v2-grey-600)",
"v2-icon-icon-inverse": "var(--v2-grey-1000)",
"v2-icon-icon-contrast": "var(--v2-grey-200)",
"v2-icon-icon-inverse": "var(--v2-grey-1100)",
"v2-icon-icon-contrast": "var(--v2-grey-100)",
"v2-icon-icon-accent": "var(--v2-blue-400)",
"v2-icon-icon-accent-hover": "var(--v2-blue-300)",
"v2-border-border-muted": "var(--v2-alpha-light-8)",
Expand Down
15 changes: 8 additions & 7 deletions packages/ui/src/theme/v2/default-primitives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import type { V2ColorValue } from "../types"

/** Default v2 hue ramps from `v2/styles/colors.css` (OC-2). Alpha ramps live in CSS only. */
export const V2_PRIMITIVES_DEFAULT: Record<string, V2ColorValue> = {
"v2-grey-100": "#ffffffff",
"v2-grey-200": "#fafafaff",
"v2-grey-50": "#ffffffff",
"v2-grey-100": "#fafafaff",
"v2-grey-200": "#f2f2f2ff",
"v2-grey-300": "#eeeeeeff",
"v2-grey-400": "#d4d4d4ff",
"v2-grey-400": "#dbdbdbff",
"v2-grey-500": "#aeaeaeff",
"v2-grey-600": "#808080ff",
"v2-grey-700": "#5c5c5cff",
"v2-grey-800": "#3a3a3aff",
"v2-grey-900": "#242424ff",
"v2-grey-1000": "#161616ff",
"v2-grey-1100": "#080808ff",
"v2-grey-1200": "#000000ff",
"v2-grey-900": "#2e2e2eff",
"v2-grey-1000": "#242424ff",
"v2-grey-1100": "#161616ff",
"v2-grey-1200": "#080808ff",
"v2-red-100": "#fcecebff",
"v2-red-200": "#f6d5d3ff",
"v2-red-300": "#f2bbb7ff",
Expand Down
47 changes: 46 additions & 1 deletion packages/ui/src/theme/v2/foreground.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
import { blend, hexToOklch, shift } from "../color"
import { blend, contrastRatio, hexToOklch, shift } from "../color"
import { mapV2Semantics } from "./mapping"
import type { ColorValue, HexColor, V2ColorValue } from "../types"

const GREY_STEPS = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200] as const

const greyRef = (step: number): V2ColorValue => `var(--v2-grey-${step})`

function greyHex(primitives: Record<string, V2ColorValue>, step: number) {
const hex = primitives[`v2-grey-${step}`]
if (typeof hex === "string" && hex.startsWith("#")) return hex as HexColor
}

function resolveGreyRef(value: V2ColorValue, primitives: Record<string, V2ColorValue>) {
const step = value.match(/^var\(--v2-grey-(\d+)\)$/)?.[1]
if (!step) throw new Error(`Expected grey primitive ref, got ${value}`)
const hex = greyHex(primitives, Number(step))
if (!hex) throw new Error(`Missing grey primitive v2-grey-${step}`)
return hex
}

function pickGrey(
primitives: Record<string, V2ColorValue>,
background: HexColor,
minContrast: number,
target: number,
) {
const matches = GREY_STEPS.filter((step) => {
const hex = greyHex(primitives, step)
return hex && contrastRatio(hex, background) >= minContrast
})
if (matches.length === 0) return target
return matches.reduce((best, step) => (Math.abs(step - target) < Math.abs(best - target) ? step : best))
}

export function mapV2Foreground(
ink: HexColor,
isDark: boolean,
primitives: Record<string, V2ColorValue>,
overrides: Record<string, ColorValue> = {},
): Record<string, V2ColorValue> {
const tint = hexToOklch(ink)
Expand All @@ -12,9 +45,21 @@ export function mapV2Foreground(
c: isDark ? 1.04 : 1.02,
})

const semantics = mapV2Semantics(isDark)
const bgBase = resolveGreyRef(semantics["v2-background-bg-base"], primitives)
const bgContrast = resolveGreyRef(semantics["v2-background-bg-contrast"], primitives)
const bgInverse = resolveGreyRef(semantics["v2-background-bg-inverse"], primitives)
const inverseTarget = hexToOklch(bgInverse).l > 0.55 ? 1100 : greyHex(primitives, 50) ? 50 : 100

return {
"v2-text-text-base": isDark ? blend("#ffffff", body, 0.9) : shift(body, { l: -0.07, c: 1.04 }),
"v2-text-text-muted": overrides["text-weak"] ?? shift(body, { l: isDark ? -0.11 : 0.11, c: 0.9 }),
"v2-text-text-faint": shift(body, { l: isDark ? -0.2 : 0.21, c: isDark ? 0.78 : 0.72 }),
"v2-icon-icon-base": greyRef(pickGrey(primitives, bgBase, 7, isDark ? 400 : 800)),
"v2-icon-icon-muted": greyRef(pickGrey(primitives, bgBase, 3, 600)),
"v2-icon-icon-inverse": greyRef(pickGrey(primitives, bgInverse, 7, inverseTarget)),
"v2-icon-icon-contrast": greyRef(pickGrey(primitives, bgContrast, 7, 100)),
"v2-icon-icon-accent": isDark ? "var(--v2-blue-400)" : "var(--v2-blue-600)",
"v2-icon-icon-accent-hover": isDark ? "var(--v2-blue-300)" : "var(--v2-blue-700)",
}
}
12 changes: 0 additions & 12 deletions packages/ui/src/theme/v2/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ const light: Record<string, V2ColorValue> = {
"v2-text-text-contrast": ref("v2-grey-100"),
"v2-text-text-accent": ref("v2-blue-600"),
"v2-text-text-accent-hover": ref("v2-blue-700"),
"v2-icon-icon-base": ref("v2-grey-1000"),
"v2-icon-icon-muted": ref("v2-grey-800"),
"v2-icon-icon-inverse": ref("v2-grey-100"),
"v2-icon-icon-contrast": ref("v2-grey-200"),
"v2-icon-icon-accent": ref("v2-blue-600"),
"v2-icon-icon-accent-hover": ref("v2-blue-700"),
"v2-border-border-muted": ref("v2-alpha-dark-8"),
"v2-border-border-base": ref("v2-alpha-dark-10"),
"v2-border-border-strong": ref("v2-alpha-dark-20"),
Expand Down Expand Up @@ -87,12 +81,6 @@ const dark: Record<string, V2ColorValue> = {
"v2-text-text-contrast": ref("v2-grey-100"),
"v2-text-text-accent": ref("v2-blue-400"),
"v2-text-text-accent-hover": ref("v2-blue-300"),
"v2-icon-icon-base": ref("v2-grey-300"),
"v2-icon-icon-muted": ref("v2-grey-400"),
"v2-icon-icon-inverse": ref("v2-grey-1000"),
"v2-icon-icon-contrast": ref("v2-grey-200"),
"v2-icon-icon-accent": ref("v2-blue-400"),
"v2-icon-icon-accent-hover": ref("v2-blue-300"),
"v2-border-border-muted": ref("v2-alpha-light-8"),
"v2-border-border-base": ref("v2-alpha-light-10"),
"v2-border-border-strong": ref("v2-alpha-light-20"),
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/theme/v2/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export function generateV2Primitives(variant: ThemeVariant, isDark: boolean): Re
export function resolveThemeVariantV2(variant: ThemeVariant, isDark: boolean): ResolvedV2Theme {
const primitives = generateV2Primitives(variant, isDark)
const semantics = mapV2Semantics(isDark)
const foreground = mapV2Foreground(readPalette(variant).ink, isDark, variant.overrides)
const foreground = mapV2Foreground(readPalette(variant).ink, isDark, primitives, variant.overrides)
return mergeV2Tokens(primitives, semantics, foreground, variant.v2Overrides ?? {})
}

Expand Down
7 changes: 4 additions & 3 deletions packages/ui/src/v2/components/tabs-v2.css
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,14 @@

[data-component="tabs-v2"][data-variant="pill"][data-orientation="horizontal"]
[data-slot="tabs-v2-trigger-wrapper"]:hover:not(:disabled):not(:has([data-selected])) {
background-color: var(--v2-background-bg-layer-01);
background-color: var(--v2-background-bg-layer-03);
color: var(--v2-text-text-base);
border: 0.5px solid var(--v2-border-border-muted);
}

[data-component="tabs-v2"][data-variant="pill"][data-orientation="horizontal"]
[data-slot="tabs-v2-trigger-wrapper"]:has([data-selected]) {
background-color: var(--v2-background-bg-layer-02);
background-color: var(--v2-background-bg-layer-03);
color: var(--v2-text-text-base);
border: 0.5px solid var(--v2-border-border-muted);
}
Expand Down Expand Up @@ -211,12 +211,13 @@

[data-component="tabs-v2"][data-variant="settings"][data-orientation="vertical"]
[data-slot="tabs-v2-trigger-wrapper"]:hover:not(:disabled):not(:has([data-selected])) {
background-color: var(--v2-background-bg-layer-03);
color: var(--v2-text-text-base);
}

[data-component="tabs-v2"][data-variant="settings"][data-orientation="vertical"]
[data-slot="tabs-v2-trigger-wrapper"]:has([data-selected]) {
background-color: var(--v2-background-bg-layer-02);
background-color: var(--v2-background-bg-layer-03);
color: var(--v2-text-text-base);
border: 0.5px solid var(--v2-border-border-muted);
}
Loading
Loading