) {
+ const globalSync = useServerSync()
+ const notification = useNotification()
+ const permission = usePermission()
+ const hasPermissions = createMemo(() => {
+ const [store] = globalSync.child(directory(), { bootstrap: false })
+ return !!sessionPermissionRequest(store.session, store.permission, sessionId(), (item) => {
+ return !permission.autoResponds(item, directory())
+ })
+ })
+ const unread = createMemo(() => hasPermissions() || notification.session.unseenCount(sessionId()) > 0)
+ const loading = createMemo(() => {
+ if (hasPermissions()) return false
+ const [store] = globalSync.child(directory(), { bootstrap: false })
+ return store.session_working(sessionId())
+ })
+ return { unread, loading }
+}
diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx
index 312b5c3a4d8e..63c83dd41594 100644
--- a/packages/app/src/pages/session.tsx
+++ b/packages/app/src/pages/session.tsx
@@ -28,7 +28,7 @@ import { Tabs } from "@opencode-ai/ui/tabs"
import { createAutoScroll } from "@opencode-ai/ui/hooks"
import { previewSelectedLines } from "@opencode-ai/ui/pierre/selection-bridge"
import { Button } from "@opencode-ai/ui/button"
-import { showToast } from "@opencode-ai/ui/toast"
+import { showToast } from "@/utils/toast"
import { checksum } from "@opencode-ai/core/util/encode"
import { useLocation, useSearchParams } from "@solidjs/router"
import { NewSessionDesignView, NewSessionView, SessionHeader } from "@/components/session"
diff --git a/packages/app/src/pages/session/composer/session-composer-region.tsx b/packages/app/src/pages/session/composer/session-composer-region.tsx
index 6f731234c410..5ff5e99a4577 100644
--- a/packages/app/src/pages/session/composer/session-composer-region.tsx
+++ b/packages/app/src/pages/session/composer/session-composer-region.tsx
@@ -17,6 +17,7 @@ import type { SessionComposerState } from "@/pages/session/composer/session-comp
import { SessionTodoDock } from "@/pages/session/composer/session-todo-dock"
import type { FollowupDraft } from "@/components/prompt-input/submit"
import { createResizeObserver } from "@solid-primitives/resize-observer"
+import { NEW_SESSION_CONTENT_WIDTH } from "@/pages/session/new-session-layout"
export function SessionComposerRegion(props: {
state: SessionComposerState
@@ -150,8 +151,9 @@ export function SessionComposerRegion(props: {
>
diff --git a/packages/app/src/pages/session/composer/session-composer-state.ts b/packages/app/src/pages/session/composer/session-composer-state.ts
index 2287fd674b3d..0fbbee82436e 100644
--- a/packages/app/src/pages/session/composer/session-composer-state.ts
+++ b/packages/app/src/pages/session/composer/session-composer-state.ts
@@ -2,7 +2,7 @@ import { createEffect, createMemo, on, onCleanup } from "solid-js"
import { createStore } from "solid-js/store"
import type { PermissionRequest, QuestionRequest, Todo } from "@opencode-ai/sdk/v2"
import { useParams } from "@solidjs/router"
-import { showToast } from "@opencode-ai/ui/toast"
+import { showToast } from "@/utils/toast"
import { useServerSync } from "@/context/server-sync"
import { useLanguage } from "@/context/language"
import { usePermission } from "@/context/permission"
diff --git a/packages/app/src/pages/session/composer/session-question-dock.tsx b/packages/app/src/pages/session/composer/session-question-dock.tsx
index 03a66ea3a7dd..8fe3c0352cf6 100644
--- a/packages/app/src/pages/session/composer/session-question-dock.tsx
+++ b/packages/app/src/pages/session/composer/session-question-dock.tsx
@@ -4,7 +4,7 @@ import { useMutation } from "@tanstack/solid-query"
import { Button } from "@opencode-ai/ui/button"
import { DockPrompt } from "@opencode-ai/ui/dock-prompt"
import { Icon } from "@opencode-ai/ui/icon"
-import { showToast } from "@opencode-ai/ui/toast"
+import { showToast } from "@/utils/toast"
import type { QuestionAnswer, QuestionRequest } from "@opencode-ai/sdk/v2"
import { useLanguage } from "@/context/language"
import { useSDK } from "@/context/sdk"
diff --git a/packages/app/src/pages/session/file-tabs.tsx b/packages/app/src/pages/session/file-tabs.tsx
index 65b076d7c630..364760eab0bc 100644
--- a/packages/app/src/pages/session/file-tabs.tsx
+++ b/packages/app/src/pages/session/file-tabs.tsx
@@ -11,7 +11,7 @@ import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
import { IconButton } from "@opencode-ai/ui/icon-button"
import { Tabs } from "@opencode-ai/ui/tabs"
import { ScrollView } from "@opencode-ai/ui/scroll-view"
-import { showToast } from "@opencode-ai/ui/toast"
+import { showToast } from "@/utils/toast"
import { selectionFromLines, useFile, type FileSelection, type SelectedLineRange } from "@/context/file"
import { useComments } from "@/context/comments"
import { useLanguage } from "@/context/language"
diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx
index e071597c8ab1..e4ae4a23e364 100644
--- a/packages/app/src/pages/session/message-timeline.tsx
+++ b/packages/app/src/pages/session/message-timeline.tsx
@@ -48,7 +48,7 @@ import type {
ToolPart,
UserMessage,
} from "@opencode-ai/sdk/v2"
-import { showToast } from "@opencode-ai/ui/toast"
+import { showToast } from "@/utils/toast"
import { Binary } from "@opencode-ai/core/util/binary"
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
import { Popover as KobaltePopover } from "@kobalte/core/popover"
diff --git a/packages/app/src/pages/session/new-session-layout.ts b/packages/app/src/pages/session/new-session-layout.ts
index f99558ddfef0..7429c7c7e888 100644
--- a/packages/app/src/pages/session/new-session-layout.ts
+++ b/packages/app/src/pages/session/new-session-layout.ts
@@ -1,3 +1,6 @@
+/** Inline new-session content width — keep in sync with session composer `placement === "inline"`. */
+export const NEW_SESSION_CONTENT_WIDTH = "w-full max-w-[720px] px-0"
+
export function shouldUseV2NewSessionPage(input: { newLayoutDesigns: boolean; sessionID?: string }) {
return input.newLayoutDesigns && !input.sessionID
}
diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx
index a0252eb8d6ff..73307c108957 100644
--- a/packages/app/src/pages/session/use-session-commands.tsx
+++ b/packages/app/src/pages/session/use-session-commands.tsx
@@ -13,7 +13,7 @@ import { useSDK } from "@/context/sdk"
import { useSettings } from "@/context/settings"
import { useSync } from "@/context/sync"
import { useTerminal } from "@/context/terminal"
-import { showToast } from "@opencode-ai/ui/toast"
+import { showToast } from "@/utils/toast"
import { findLast } from "@opencode-ai/core/util/array"
import { createSessionTabs } from "@/pages/session/helpers"
import { extractPromptFromParts } from "@/utils/prompt"
diff --git a/packages/app/src/utils/toast.tsx b/packages/app/src/utils/toast.tsx
new file mode 100644
index 000000000000..e44454850823
--- /dev/null
+++ b/packages/app/src/utils/toast.tsx
@@ -0,0 +1,34 @@
+import { Icon, type IconProps } from "@opencode-ai/ui/icon"
+import { Toast, showToast as showLegacyToast, type ToastOptions, type ToastVariant } from "@opencode-ai/ui/toast"
+import { ToastV2, showToastV2 } from "@opencode-ai/ui/v2/toast-v2"
+
+let v2 = false
+
+export function setV2Toast(value: boolean) {
+ v2 = value
+}
+
+export function ToastRegion(props: { v2: boolean }) {
+ if (props.v2) return
+ return
+}
+
+export function showToast(options: ToastOptions | string) {
+ if (!v2) return showLegacyToast(options)
+ if (typeof options === "string") return showToastV2(options)
+
+ return showToastV2({
+ ...options,
+ icon: resolveIcon(options.icon, options.variant),
+ actions: options.actions?.map((action) => ({
+ ...action,
+ variant: action.onClick === "dismiss" ? "secondary" : "primary",
+ })),
+ })
+}
+
+function resolveIcon(icon: IconProps["name"] | undefined, variant: ToastVariant | undefined) {
+ const name = icon ?? (variant === "success" ? "check" : undefined)
+ if (!name) return
+ return
+}
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 8f2275ce51bb..fae1ea3d8192 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -23,7 +23,8 @@
"./icons/app": "./src/components/app-icons/types.ts",
"./fonts/*": "./src/assets/fonts/*",
"./audio/*": "./src/assets/audio/*",
- "./v2/*": "./src/v2/*"
+ "./v2/*": "./src/v2/components/*.tsx",
+ "./v2/styles/*": "./src/v2/styles/*"
},
"scripts": {
"typecheck": "tsgo --noEmit",
@@ -47,8 +48,8 @@
},
"dependencies": {
"@kobalte/core": "catalog:",
- "@opencode-ai/sdk": "workspace:*",
"@opencode-ai/core": "workspace:*",
+ "@opencode-ai/sdk": "workspace:*",
"@pierre/diffs": "catalog:",
"@shikijs/transformers": "3.9.2",
"@solid-primitives/bounds": "0.1.3",
diff --git a/packages/ui/src/components/select-v2.css b/packages/ui/src/components/select-v2.css
new file mode 100644
index 000000000000..b148debfa3da
--- /dev/null
+++ b/packages/ui/src/components/select-v2.css
@@ -0,0 +1,87 @@
+[data-component="select"][data-trigger-style="settings-v2"] [data-slot="select-select-trigger"] {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 4px;
+ width: fit-content;
+ height: 24px;
+ padding: 4px 4px 4px 8px;
+ border: 0;
+ border-radius: 4px;
+ background: transparent;
+ color: var(--v2-text-text-base);
+ cursor: pointer;
+}
+
+[data-component="select"][data-trigger-style="settings-v2"] [data-slot="select-select-trigger-value"] {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ width: fit-content;
+ height: 13px;
+ padding: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-style: normal;
+ font-weight: 530;
+ font-size: 13px;
+ line-height: 1;
+ letter-spacing: -0.04px;
+ font-variant-numeric: tabular-nums;
+ font-variation-settings: "slnt" 0;
+}
+
+[data-component="select"][data-trigger-style="settings-v2"] [data-slot="select-select-trigger"]:focus-visible {
+ outline: 2px solid var(--v2-border-border-focus);
+ outline-offset: 2.5px;
+}
+
+[data-component="select"][data-trigger-style="settings-v2"]
+ [data-slot="select-select-trigger"]:is(:hover, [data-state="hover"]):not(:disabled) {
+ background-color: var(--v2-overlay-simple-overlay-hover);
+}
+
+[data-component="select"][data-trigger-style="settings-v2"]
+ [data-slot="select-select-trigger"]:is(:active, [data-state="pressed"]):not(:disabled) {
+ background-color: var(--v2-overlay-simple-overlay-pressed);
+}
+
+[data-component="select"][data-trigger-style="settings-v2"] [data-slot="select-select-trigger"]:disabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
+
+[data-component="select"][data-trigger-style="settings-v2"] [data-slot="select-select-trigger-icon"] {
+ display: flex;
+ width: 16px;
+ height: 16px;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+}
+
+[data-component="select"][data-trigger-style="settings-v2"]
+ [data-slot="select-select-trigger-icon"]
+ [data-slot="icon-svg"] {
+ margin-inline: -5px;
+ color: #3a3a3a;
+}
+
+[data-component="select-content"][data-trigger-style="settings-v2"] {
+ min-width: 160px;
+ border-radius: 8px;
+ padding: 0;
+
+ [data-slot="select-select-content-list"] {
+ padding: 4px;
+ }
+
+ [data-slot="select-select-item"] {
+ font-size: var(--font-size-base);
+ font-style: normal;
+ font-weight: var(--font-weight-regular);
+ line-height: var(--line-height-large);
+ letter-spacing: var(--letter-spacing-normal);
+ }
+}
diff --git a/packages/ui/src/components/select-v2.stories.tsx b/packages/ui/src/components/select-v2.stories.tsx
new file mode 100644
index 000000000000..c5941ada1276
--- /dev/null
+++ b/packages/ui/src/components/select-v2.stories.tsx
@@ -0,0 +1,22 @@
+// @ts-nocheck
+import * as mod from "./select-v2"
+import { create } from "../storybook/scaffold"
+
+const story = create({
+ title: "UI/SelectV2",
+ mod,
+ args: {
+ options: ["One", "Two", "Three"],
+ current: "One",
+ placeholder: "Choose...",
+ },
+})
+
+export default {
+ title: "UI/SelectV2",
+ id: "components-select-v2",
+ component: story.meta.component,
+ tags: ["autodocs"],
+}
+
+export const Basic = story.Basic
diff --git a/packages/ui/src/components/select-v2.tsx b/packages/ui/src/components/select-v2.tsx
new file mode 100644
index 000000000000..f737d57e4d7b
--- /dev/null
+++ b/packages/ui/src/components/select-v2.tsx
@@ -0,0 +1,171 @@
+import { Select as Kobalte } from "@kobalte/core/select"
+import { createMemo, onCleanup, splitProps, type ComponentProps, type JSX } from "solid-js"
+import { pipe, groupBy, entries, map } from "remeda"
+import { Icon as IconV2 } from "../v2/components/icon"
+import { Icon } from "./icon"
+import "./select-v2.css"
+
+export type SelectV2Props = Omit>, "value" | "onSelect" | "children"> & {
+ placeholder?: string
+ options: T[]
+ current?: T
+ value?: (x: T) => string
+ label?: (x: T) => string
+ groupBy?: (x: T) => string
+ valueClass?: ComponentProps<"div">["class"]
+ onSelect?: (value: T | undefined) => void
+ onHighlight?: (value: T | undefined) => (() => void) | void
+ class?: ComponentProps<"div">["class"]
+ classList?: ComponentProps<"div">["classList"]
+ children?: (item: T | undefined) => JSX.Element
+ triggerStyle?: JSX.CSSProperties
+ triggerProps?: Record
+}
+
+export function SelectV2(props: SelectV2Props & { disabled?: boolean }) {
+ const [local, others] = splitProps(props, [
+ "class",
+ "classList",
+ "placeholder",
+ "options",
+ "current",
+ "value",
+ "label",
+ "groupBy",
+ "valueClass",
+ "onSelect",
+ "onHighlight",
+ "onOpenChange",
+ "children",
+ "triggerStyle",
+ "triggerProps",
+ ])
+
+ const state = {
+ key: undefined as string | undefined,
+ cleanup: undefined as (() => void) | void,
+ }
+
+ const stop = () => {
+ state.cleanup?.()
+ state.cleanup = undefined
+ state.key = undefined
+ }
+
+ const keyFor = (item: T) => (local.value ? local.value(item) : (item as string))
+
+ const move = (item: T | undefined) => {
+ if (!local.onHighlight) return
+ if (!item) {
+ stop()
+ return
+ }
+
+ const key = keyFor(item)
+ if (state.key === key) return
+ state.cleanup?.()
+ state.cleanup = local.onHighlight(item)
+ state.key = key
+ }
+
+ onCleanup(stop)
+
+ const grouped = createMemo(() => {
+ const result = pipe(
+ local.options,
+ groupBy((x) => (local.groupBy ? local.groupBy(x) : "")),
+ entries(),
+ map(([k, v]) => ({ category: k, options: v })),
+ )
+ return result
+ })
+
+ return (
+ // @ts-ignore
+
+ {...others}
+ data-component="select"
+ data-trigger-style="settings-v2"
+ placement="bottom-end"
+ gutter={4}
+ value={local.current}
+ options={grouped()}
+ optionValue={(x) => (local.value ? local.value(x) : (x as string))}
+ optionTextValue={(x) => (local.label ? local.label(x) : (x as string))}
+ optionGroupChildren="options"
+ placeholder={local.placeholder}
+ sectionComponent={(local) => (
+ {local.section.rawValue.category}
+ )}
+ itemComponent={(itemProps) => (
+ move(itemProps.item.rawValue)}
+ onPointerMove={() => move(itemProps.item.rawValue)}
+ onFocus={() => move(itemProps.item.rawValue)}
+ >
+
+ {local.children
+ ? local.children(itemProps.item.rawValue)
+ : local.label
+ ? local.label(itemProps.item.rawValue)
+ : (itemProps.item.rawValue as string)}
+
+
+
+
+
+ )}
+ onChange={(v) => {
+ local.onSelect?.(v ?? undefined)
+ stop()
+ }}
+ onOpenChange={(open) => {
+ local.onOpenChange?.(open)
+ if (!open) stop()
+ }}
+ >
+
+ data-slot="select-select-trigger-value" class={local.valueClass}>
+ {(state) => {
+ const selected = state.selectedOption() ?? local.current
+ if (!selected) return local.placeholder || ""
+ if (local.label) return local.label(selected)
+ return selected as string
+ }}
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/packages/ui/src/v2/components/accordion-v2.css b/packages/ui/src/v2/components/accordion-v2.css
index 73d9ebbc1d2d..3bf4b39df3dd 100644
--- a/packages/ui/src/v2/components/accordion-v2.css
+++ b/packages/ui/src/v2/components/accordion-v2.css
@@ -15,7 +15,6 @@
box-shadow: 0 0 0 0.5px var(--accordion-v2-border);
overflow: hidden;
- font-family: var(--v2-font-family-sans), "Inter", system-ui, sans-serif;
color: var(--accordion-v2-fg);
-webkit-font-smoothing: antialiased;
@@ -59,7 +58,6 @@
cursor: default;
user-select: none;
- font-family: inherit;
font-size: 13px;
font-weight: 440;
line-height: 100%;
diff --git a/packages/ui/src/v2/components/avatar-v2.css b/packages/ui/src/v2/components/avatar-v2.css
index 50c3509fcc95..8d717afbe1ef 100644
--- a/packages/ui/src/v2/components/avatar-v2.css
+++ b/packages/ui/src/v2/components/avatar-v2.css
@@ -14,7 +14,6 @@
height: 28px;
border-radius: var(--avatar-radius);
border: 0.5px solid var(--v2-border-border-base);
- font-family: var(--v2-font-family-sans);
font-weight: 530;
font-size: var(--avatar-font-size);
line-height: 1;
diff --git a/packages/ui/src/v2/components/badge-v2.css b/packages/ui/src/v2/components/badge-v2.css
index 300903fcb5dd..748c08a7116f 100644
--- a/packages/ui/src/v2/components/badge-v2.css
+++ b/packages/ui/src/v2/components/badge-v2.css
@@ -10,19 +10,18 @@
user-select: none;
border-radius: 2px;
- border: 0.5px solid var(--border-border-base);
- background: var(--background-bg-layer-02);
+ border: 0.5px solid var(--v2-border-border-base);
+ background: var(--v2-background-bg-layer-02);
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 530;
font-size: 11px;
line-height: 1;
letter-spacing: 0.05px;
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
font-variant-numeric: tabular-nums;
}
[data-component="tag"][data-high-contrast] {
- border-color: var(--border-border-strong);
+ border-color: var(--v2-border-border-strong);
}
diff --git a/packages/ui/src/v2/components/basic-tool-v2.css b/packages/ui/src/v2/components/basic-tool-v2.css
index 73ac7de79334..256552ab1b0e 100644
--- a/packages/ui/src/v2/components/basic-tool-v2.css
+++ b/packages/ui/src/v2/components/basic-tool-v2.css
@@ -21,7 +21,6 @@
gap: 8px;
min-width: 0;
width: 100%;
- font-family: var(--v2-font-family-sans), var(--sans), system-ui, sans-serif;
font-variant-numeric: tabular-nums;
[data-slot="basic-tool-v2-trigger"] {
diff --git a/packages/ui/src/v2/components/button-v2.css b/packages/ui/src/v2/components/button-v2.css
index 2e4364057ee9..975dc2cc288b 100644
--- a/packages/ui/src/v2/components/button-v2.css
+++ b/packages/ui/src/v2/components/button-v2.css
@@ -11,7 +11,6 @@
justify-content: center;
gap: 6px;
border-radius: 6px;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 530;
font-size: 13px;
@@ -145,3 +144,26 @@
opacity: 0.5;
cursor: not-allowed;
}
+
+/* Ghost muted */
+[data-component="button-v2"][data-variant="ghost-muted"] {
+ background-color: transparent;
+ color: var(--v2-text-text-muted);
+}
+
+[data-component="button-v2"][data-variant="ghost-muted"] [data-slot="icon-svg"] {
+ color: var(--v2-icon-icon-muted);
+}
+
+[data-component="button-v2"][data-variant="ghost-muted"]:is(:hover, [data-state="hover"]):not(:disabled) {
+ background-color: var(--v2-overlay-simple-overlay-hover);
+}
+
+[data-component="button-v2"][data-variant="ghost-muted"]:is(:active, [data-state="pressed"]):not(:disabled) {
+ background-color: var(--v2-overlay-simple-overlay-pressed);
+}
+
+[data-component="button-v2"][data-variant="ghost-muted"]:is(:disabled, [data-state="disabled"]) {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
diff --git a/packages/ui/src/v2/components/button-v2.stories.tsx b/packages/ui/src/v2/components/button-v2.stories.tsx
index b00c1e68cf98..17aefb79f8f2 100644
--- a/packages/ui/src/v2/components/button-v2.stories.tsx
+++ b/packages/ui/src/v2/components/button-v2.stories.tsx
@@ -4,7 +4,7 @@ const docs = `### Overview
Button v2 with three visual variants and two sizes.
### API
-- \`variant\`: "neutral" | "contrast" | "ghost".
+- \`variant\`: "neutral" | "contrast" | "ghost" | "ghost-muted".
- \`size\`: "normal" | "large".
- \`icon\`: Optional icon name.
- Inherits Kobalte Button props and native button attributes.
@@ -39,7 +39,7 @@ export default {
},
variant: {
control: "select",
- options: ["neutral", "contrast", "ghost"],
+ options: ["neutral", "contrast", "ghost", "ghost-muted"],
},
size: {
control: "select",
@@ -63,6 +63,9 @@ export const Variants = {
Neutral
Contrast
Ghost
+
+ Ghost muted
+
),
}
@@ -112,7 +115,7 @@ export const Icon = {
export const AllStates = {
render: () => {
- const variants = ["neutral", "contrast", "ghost"] as const
+ const variants = ["neutral", "contrast", "ghost", "ghost-muted"] as const
const states = ["default", "hover", "pressed", "focus", "disabled"] as const
const toTitleCase = (value: string) => value.charAt(0).toUpperCase() + value.slice(1)
return (
diff --git a/packages/ui/src/v2/components/button-v2.tsx b/packages/ui/src/v2/components/button-v2.tsx
index ce9129d40082..8146549e3878 100644
--- a/packages/ui/src/v2/components/button-v2.tsx
+++ b/packages/ui/src/v2/components/button-v2.tsx
@@ -7,7 +7,7 @@ export interface ButtonV2Props
extends ComponentProps,
Pick, "class" | "classList" | "children"> {
size?: "small" | "normal" | "large"
- variant?: "neutral" | "contrast" | "ghost"
+ variant?: "neutral" | "contrast" | "ghost" | "ghost-muted"
icon?: IconProps["name"]
}
@@ -27,7 +27,7 @@ export function ButtonV2(props: ButtonV2Props) {
}}
>
-
+
{props.children}
diff --git a/packages/ui/src/v2/components/checkbox-v2.css b/packages/ui/src/v2/components/checkbox-v2.css
index 07df3970e394..49d7ea56f927 100644
--- a/packages/ui/src/v2/components/checkbox-v2.css
+++ b/packages/ui/src/v2/components/checkbox-v2.css
@@ -10,7 +10,6 @@
[data-slot="checkbox-v2-error"] {
color: var(--state-fg-danger);
- font-family: var(--v2-font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
@@ -90,7 +89,6 @@
display: inline-flex;
user-select: none;
color: inherit;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 440;
font-variant-numeric: tabular-nums;
@@ -109,7 +107,6 @@
[data-slot="checkbox-v2-description"] {
color: var(--text-text-muted);
- font-family: var(--v2-font-family-sans);
font-size: 11px;
font-weight: 440;
line-height: 1;
diff --git a/packages/ui/src/v2/components/dialog-v2.css b/packages/ui/src/v2/components/dialog-v2.css
index 066017f9561e..e7d0f60f39c1 100644
--- a/packages/ui/src/v2/components/dialog-v2.css
+++ b/packages/ui/src/v2/components/dialog-v2.css
@@ -4,7 +4,7 @@
position: fixed;
inset: 0;
z-index: 50;
- background-color: var(--overlay-simple-overlay-scrim);
+ background-color: var(--v2-overlay-simple-overlay-scrim);
}
[data-component="dialog"] {
@@ -22,8 +22,8 @@
align-items: flex-start;
width: 480px;
height: 368px;
- background: var(--background-bg-layer-01);
- box-shadow: var(--elevation-overlay);
+ background: var(--v2-background-bg-layer-01);
+ box-shadow: var(--v2-elevation-overlay);
border-radius: 6px;
overflow: visible;
pointer-events: auto;
@@ -64,22 +64,20 @@
[data-slot="dialog-title"] {
margin: 0;
- font-family: "Inter", var(--v2-font-family-sans);
font-weight: 530;
font-size: 15px;
line-height: 100%;
letter-spacing: -0.13px;
- color: var(--text-text-base);
+ color: var(--v2-text-text-base);
font-variation-settings: "slnt" 0;
}
[data-slot="dialog-description"] {
- font-family: "Inter", var(--v2-font-family-sans);
font-weight: 440;
font-size: 13px;
line-height: 100%;
letter-spacing: -0.04px;
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
font-variation-settings: "slnt" 0;
}
@@ -94,7 +92,7 @@
cursor: pointer;
&:hover {
- background: var(--overlay-simple-overlay-hover);
+ background: var(--v2-overlay-simple-overlay-hover);
}
}
}
diff --git a/packages/ui/src/v2/components/diff-changes-v2.css b/packages/ui/src/v2/components/diff-changes-v2.css
index 82397ccd2ca3..a4405dc0c0dd 100644
--- a/packages/ui/src/v2/components/diff-changes-v2.css
+++ b/packages/ui/src/v2/components/diff-changes-v2.css
@@ -6,7 +6,6 @@
[data-slot="diff-changes-additions"],
[data-slot="diff-changes-deletions"] {
- font-family: var(--v2-font-family-sans);
font-size: 11px;
font-style: normal;
font-weight: 440;
diff --git a/packages/ui/src/v2/components/field-v2.css b/packages/ui/src/v2/components/field-v2.css
index dd1715204a51..853d5da6fc91 100644
--- a/packages/ui/src/v2/components/field-v2.css
+++ b/packages/ui/src/v2/components/field-v2.css
@@ -17,7 +17,6 @@
margin: 0;
padding: 0;
border: 0;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 530;
font-size: 13px;
@@ -76,7 +75,6 @@
align-self: stretch;
width: 100%;
min-height: 11px;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 440;
font-size: 11px;
diff --git a/packages/ui/src/v2/components/icon.tsx b/packages/ui/src/v2/components/icon.tsx
index 09aaea2e59b0..60202a85c8a7 100644
--- a/packages/ui/src/v2/components/icon.tsx
+++ b/packages/ui/src/v2/components/icon.tsx
@@ -2,20 +2,20 @@ import { onMount, type ComponentProps, splitProps } from "solid-js"
const icons = {
edit: {
- viewBox: "0 0 20 20",
- body: ``,
+ viewBox: "0 0 16 16",
+ body: ``,
},
"folder-add-left": {
- viewBox: "0 0 20 20",
- body: ``,
+ viewBox: "0 0 16 16",
+ body: ``,
},
"grid-plus": {
viewBox: "0 0 16 16",
body: ``,
},
help: {
- viewBox: "0 0 20 20",
- body: ``,
+ viewBox: "0 0 16 16",
+ body: ``,
},
"sidebar-right": {
viewBox: "0 0 20 20",
@@ -31,7 +31,7 @@ const icons = {
},
"magnifying-glass": {
viewBox: "0 0 16 16",
- body: ``,
+ body: ``,
},
menu: {
viewBox: "0 0 16 16",
@@ -42,8 +42,16 @@ const icons = {
body: ``,
},
"settings-gear": {
+ viewBox: "0 0 16 16",
+ body: ``,
+ },
+ "chevron-down": {
+ viewBox: "0 0 16 16",
+ body: ``,
+ },
+ close: {
viewBox: "0 0 20 20",
- body: ``,
+ body: ``,
},
"xmark-small": {
viewBox: "0 0 16 16",
diff --git a/packages/ui/src/v2/components/inline-input-v2.css b/packages/ui/src/v2/components/inline-input-v2.css
index 861628160466..71297af5a8fb 100644
--- a/packages/ui/src/v2/components/inline-input-v2.css
+++ b/packages/ui/src/v2/components/inline-input-v2.css
@@ -81,7 +81,6 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 440;
font-size: 13px;
@@ -138,7 +137,6 @@
border: 0;
background: transparent;
outline: none;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 440;
font-size: 13px;
diff --git a/packages/ui/src/v2/components/keybind-v2.css b/packages/ui/src/v2/components/keybind-v2.css
index 9eac86c1ffa6..82e84127062b 100644
--- a/packages/ui/src/v2/components/keybind-v2.css
+++ b/packages/ui/src/v2/components/keybind-v2.css
@@ -6,13 +6,13 @@
[data-component="keybind-v2"] {
box-sizing: border-box;
- font-family: var(--v2-font-family-sans), var(--sans), system-ui, sans-serif;
font-variant-numeric: tabular-nums;
display: inline-flex;
flex-direction: row;
align-items: center;
- padding: 0px;
+ padding: 0;
gap: 2px;
+ flex-shrink: 0;
}
[data-component="keybind-v2"] *,
@@ -26,9 +26,9 @@
flex-direction: row;
justify-content: center;
align-items: center;
- padding: 0px;
+ padding: 0;
gap: 4px;
- width: 14px;
+ min-width: 14px;
height: 14px;
border-radius: 2px;
flex: none;
@@ -36,7 +36,7 @@
}
[data-component="keybind-v2"][data-variant="neutral"] [data-slot="keybind-v2-key"] {
- background: var(--background-bg-layer-03);
+ background: var(--v2-background-bg-layer-03);
}
[data-component="keybind-v2"][data-variant="ghost"] [data-slot="keybind-v2-key"] {
@@ -48,26 +48,27 @@
flex-direction: row;
justify-content: center;
align-items: center;
- width: 14px;
- height: 14px;
- padding: 0px;
- flex: 1 1 auto;
- align-self: stretch;
- font-family: "Inter", var(--v2-font-family-sans), var(--sans), system-ui, sans-serif;
+ min-width: 14px;
+ height: 11px;
+ padding: 0;
+ flex: none;
font-style: normal;
font-weight: 530;
font-size: 11px;
- line-height: 100%;
+ line-height: 1;
text-align: center;
letter-spacing: 0.05px;
+ text-transform: uppercase;
+ font-variant-numeric: tabular-nums;
+ font-feature-settings: "tnum" on, "lnum" on;
font-variation-settings: "slnt" 0;
user-select: none;
}
[data-component="keybind-v2"][data-variant="neutral"] [data-slot="keybind-v2-label"] {
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
}
[data-component="keybind-v2"][data-variant="ghost"] [data-slot="keybind-v2-label"] {
- color: var(--text-text-faint);
+ color: var(--v2-text-text-faint);
}
diff --git a/packages/ui/src/v2/components/line-comment-v2.css b/packages/ui/src/v2/components/line-comment-v2.css
index 8a97f063734e..e0843d836789 100644
--- a/packages/ui/src/v2/components/line-comment-v2.css
+++ b/packages/ui/src/v2/components/line-comment-v2.css
@@ -6,7 +6,6 @@
[data-component="line-comment-v2"] {
box-sizing: border-box;
- font-family: var(--v2-font-family-sans), var(--sans), system-ui, sans-serif;
font-variant-numeric: tabular-nums;
min-width: 0;
width: 100%;
@@ -155,7 +154,6 @@
border: 1px solid var(--border-border-base);
border-radius: 6px;
background: linear-gradient(180deg, var(--alpha-light-2) 0%, var(--alpha-light-0) 100%), var(--background-bg-base);
- font-family: inherit;
font-size: 13px;
font-style: normal;
font-weight: 440;
diff --git a/packages/ui/src/v2/components/menu-v2.css b/packages/ui/src/v2/components/menu-v2.css
index 10fb97d631ad..471f545e4bee 100644
--- a/packages/ui/src/v2/components/menu-v2.css
+++ b/packages/ui/src/v2/components/menu-v2.css
@@ -6,12 +6,11 @@
padding: 2px;
min-width: 160px;
- background: var(--v2-background-bg-layer-01);
+ background: var(--background-bg-layer-01);
border-radius: 6px;
- box-shadow: var(--v2-elevation-floating);
+ box-shadow: var(--elevation-floating);
outline: none;
- font-family: var(--v2-font-family-sans), "Inter", system-ui, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -31,9 +30,9 @@
--menu-v2-fg-subtle: var(--text-text-muted);
--menu-v2-icon: var(--icon-icon-base);
--menu-v2-accent: var(--text-text-accent);
- --menu-v2-badge-bg: var(--v2-background-bg-layer-02);
- --menu-v2-badge-border: var(--v2-border-border-base);
- --menu-v2-hover: var(--v2-overlay-simple-overlay-hover);
+ --menu-v2-badge-bg: var(--background-bg-layer-02);
+ --menu-v2-badge-border: var(--border-border-base);
+ --menu-v2-hover: var(--overlay-simple-overlay-hover);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -52,7 +51,6 @@
cursor: default;
user-select: none;
- font-family: var(--v2-font-family-sans), "Inter", system-ui, sans-serif;
font-variation-settings: "slnt" 0;
font-variant-numeric: tabular-nums;
color: var(--menu-v2-fg);
@@ -153,7 +151,7 @@
height: 1px;
width: calc(100% + 4px);
margin: 2px -2px;
- background: var(--v2-border-border-muted);
+ background: var(--border-border-muted);
border: none;
}
@@ -164,7 +162,6 @@
height: 28px;
padding: 0 12px;
- font-family: var(--v2-font-family-sans), "Inter", system-ui, sans-serif;
font-size: 11px;
font-weight: 530;
line-height: 100%;
diff --git a/packages/ui/src/v2/components/project-avatar-v2.css b/packages/ui/src/v2/components/project-avatar-v2.css
new file mode 100644
index 000000000000..c150f0b79901
--- /dev/null
+++ b/packages/ui/src/v2/components/project-avatar-v2.css
@@ -0,0 +1,128 @@
+[data-component="project-avatar-v2"] {
+ --project-avatar-bg: var(--v2-avatar-bg-gray);
+ --project-avatar-border: var(--v2-avatar-border-gray);
+ position: relative;
+ box-sizing: border-box;
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+ width: 16px;
+ height: 16px;
+ overflow: hidden;
+ border-radius: 4px;
+ background:
+ linear-gradient(180deg, var(--v2-alpha-light-16) 0%, var(--v2-alpha-light-0) 100%), var(--project-avatar-bg);
+ box-shadow: inset 0 0 0 0.5px var(--project-avatar-border);
+ font-weight: 530;
+ font-size: 11px;
+ line-height: 1;
+ letter-spacing: 0.05px;
+ font-variant-numeric: tabular-nums;
+ text-transform: uppercase;
+ color: var(--v2-grey-100);
+ text-shadow: 0 0 4px var(--v2-alpha-dark-20);
+ user-select: none;
+ -webkit-user-select: none;
+}
+
+[data-component="project-avatar-v2"][data-variant="orange"] {
+ --project-avatar-bg: var(--v2-avatar-bg-orange);
+ --project-avatar-border: var(--v2-avatar-border-orange);
+}
+
+[data-component="project-avatar-v2"][data-variant="yellow"] {
+ --project-avatar-bg: var(--v2-avatar-bg-yellow);
+ --project-avatar-border: var(--v2-avatar-border-yellow);
+}
+
+[data-component="project-avatar-v2"][data-variant="cyan"] {
+ --project-avatar-bg: var(--v2-avatar-bg-cyan);
+ --project-avatar-border: var(--v2-avatar-border-cyan);
+}
+
+[data-component="project-avatar-v2"][data-variant="green"] {
+ --project-avatar-bg: var(--v2-avatar-bg-green);
+ --project-avatar-border: var(--v2-avatar-border-green);
+}
+
+[data-component="project-avatar-v2"][data-variant="red"] {
+ --project-avatar-bg: var(--v2-avatar-bg-red);
+ --project-avatar-border: var(--v2-avatar-border-red);
+}
+
+[data-component="project-avatar-v2"][data-variant="pink"] {
+ --project-avatar-bg: var(--v2-avatar-bg-pink);
+ --project-avatar-border: var(--v2-avatar-border-pink);
+}
+
+[data-component="project-avatar-v2"][data-variant="blue"] {
+ --project-avatar-bg: var(--v2-avatar-bg-blue);
+ --project-avatar-border: var(--v2-avatar-border-blue);
+}
+
+[data-component="project-avatar-v2"][data-variant="purple"] {
+ --project-avatar-bg: var(--v2-avatar-bg-purple);
+ --project-avatar-border: var(--v2-avatar-border-purple);
+}
+
+[data-component="project-avatar-v2"][data-variant="gray"] {
+ --project-avatar-bg: var(--v2-avatar-bg-gray);
+ --project-avatar-border: var(--v2-avatar-border-gray);
+}
+
+[data-component="project-avatar-v2"][data-has-image] {
+ background: var(--project-avatar-bg);
+}
+
+[data-component="project-avatar-v2"] [data-slot="project-avatar-image"] {
+ position: relative;
+ z-index: 1;
+ display: block;
+ width: 100%;
+ height: 100%;
+ border-radius: inherit;
+ object-fit: cover;
+ user-select: none;
+ -webkit-user-select: none;
+ -webkit-user-drag: none;
+}
+
+[data-component="project-avatar-v2"] [data-slot="project-avatar-loader"] {
+ position: absolute;
+ inset: 0;
+ z-index: 2;
+ border-radius: 4px;
+ background: conic-gradient(
+ from 180deg at 50% 50%,
+ var(--v2-grey-100) 0deg,
+ var(--v2-grey-1200) 0.04deg,
+ var(--v2-alpha-dark-50) 90deg,
+ var(--v2-grey-100) 360deg
+ );
+ mix-blend-mode: soft-light;
+ pointer-events: none;
+ animation: project-avatar-v2-loader-spin 1.2s linear infinite;
+}
+
+@keyframes project-avatar-v2-loader-spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+[data-slot="project-avatar-slot"] {
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+ width: 22px;
+ height: 22px;
+ overflow: visible;
+}
+
+[data-component="project-avatar-v2"][data-unread] {
+ overflow: visible;
+ outline: 2px solid var(--v2-background-bg-accent);
+ outline-offset: 1px;
+}
diff --git a/packages/ui/src/v2/components/project-avatar-v2.stories.tsx b/packages/ui/src/v2/components/project-avatar-v2.stories.tsx
new file mode 100644
index 000000000000..1fab4f57b7f1
--- /dev/null
+++ b/packages/ui/src/v2/components/project-avatar-v2.stories.tsx
@@ -0,0 +1,88 @@
+// @ts-nocheck
+import { For } from "solid-js"
+import { ProjectAvatar, PROJECT_AVATAR_VARIANTS } from "./project-avatar-v2"
+
+const docs = `### Overview
+Saturated 16px project avatar with color variants and optional unread ring.
+
+### API
+- Required: \`fallback\` string.
+- Optional: \`src\`, \`variant\`, \`unread\`.
+
+### Variants
+- Color: orange, yellow, cyan, green, red, pink, blue, purple, gray.
+- Image vs initial content state.
+- Unread ring when \`unread\` is set.
+
+### Theming
+- Uses \`--v2-avatar-bg-*\` and \`--v2-avatar-border-*\` tokens with inset box-shadow borders.
+`
+
+export default {
+ title: "UI V2/ProjectAvatar",
+ id: "components-project-avatar-v2",
+ component: ProjectAvatar,
+ tags: ["autodocs"],
+ parameters: {
+ docs: {
+ description: {
+ component: docs,
+ },
+ },
+ },
+ argTypes: {
+ variant: {
+ control: "select",
+ options: [...PROJECT_AVATAR_VARIANTS],
+ },
+ },
+ args: {
+ fallback: "O",
+ variant: "orange",
+ },
+}
+
+export const Basic = {}
+
+export const WithImage = {
+ args: {
+ src: "https://placehold.co/32x32/png",
+ fallback: "O",
+ variant: "blue",
+ },
+}
+
+export const AllVariants = {
+ render: () => (
+
+ ),
+}
+
+export const Unread = {
+ args: {
+ fallback: "O",
+ variant: "orange",
+ unread: true,
+ },
+}
+
+export const Loading = {
+ args: {
+ fallback: "O",
+ variant: "orange",
+ loading: true,
+ },
+}
+
+export const LoadingAndUnread = {
+ args: {
+ fallback: "O",
+ variant: "blue",
+ loading: true,
+ unread: true,
+ },
+}
diff --git a/packages/ui/src/v2/components/project-avatar-v2.tsx b/packages/ui/src/v2/components/project-avatar-v2.tsx
new file mode 100644
index 000000000000..926f2e1ffb36
--- /dev/null
+++ b/packages/ui/src/v2/components/project-avatar-v2.tsx
@@ -0,0 +1,71 @@
+import { type ComponentProps, splitProps, Show } from "solid-js"
+import "./project-avatar-v2.css"
+
+const segmenter =
+ typeof Intl !== "undefined" && "Segmenter" in Intl
+ ? new Intl.Segmenter(undefined, { granularity: "grapheme" })
+ : undefined
+
+function first(value: string) {
+ if (!value) return ""
+ if (!segmenter) return Array.from(value)[0] ?? ""
+ return segmenter.segment(value)[Symbol.iterator]().next().value?.segment ?? Array.from(value)[0] ?? ""
+}
+
+export const PROJECT_AVATAR_VARIANTS = [
+ "orange",
+ "yellow",
+ "cyan",
+ "green",
+ "red",
+ "pink",
+ "blue",
+ "purple",
+ "gray",
+] as const
+
+export type ProjectAvatarVariant = (typeof PROJECT_AVATAR_VARIANTS)[number]
+
+export interface ProjectAvatarProps extends ComponentProps<"div"> {
+ fallback: string
+ src?: string
+ variant?: ProjectAvatarVariant
+ unread?: boolean
+ loading?: boolean
+}
+
+export function ProjectAvatar(props: ProjectAvatarProps) {
+ const [split, rest] = splitProps(props, [
+ "fallback",
+ "src",
+ "variant",
+ "unread",
+ "loading",
+ "class",
+ "classList",
+ "style",
+ ])
+ const src = split.src
+ return (
+
+
+ {(value) =>
}
+
+
+
+
+
+ )
+}
diff --git a/packages/ui/src/v2/components/radio-v2.css b/packages/ui/src/v2/components/radio-v2.css
index 1bf248632417..b9f954d301b3 100644
--- a/packages/ui/src/v2/components/radio-v2.css
+++ b/packages/ui/src/v2/components/radio-v2.css
@@ -9,7 +9,6 @@
align-items: center;
user-select: none;
color: var(--text-text-faint);
- font-family: var(--v2-font-family-sans);
font-size: 11px;
font-style: normal;
font-weight: 440;
@@ -20,7 +19,6 @@
[data-slot="radio-v2-description"] {
color: var(--text-text-faint);
- font-family: var(--v2-font-family-sans);
font-size: 11px;
font-weight: 440;
line-height: 1.2;
@@ -35,7 +33,6 @@
[data-slot="radio-v2-error"] {
color: var(--state-fg-danger);
- font-family: var(--v2-font-family-sans);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
@@ -167,7 +164,6 @@
display: inline-flex;
user-select: none;
color: inherit;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 440;
font-variant-numeric: tabular-nums;
@@ -186,7 +182,6 @@
[data-slot="radio-v2-item-description"] {
color: var(--text-text-muted);
- font-family: var(--v2-font-family-sans);
font-size: 11px;
font-weight: 440;
line-height: 1;
diff --git a/packages/ui/src/v2/components/segmented-control-v2.css b/packages/ui/src/v2/components/segmented-control-v2.css
index 0692e184acf9..6303a357ff04 100644
--- a/packages/ui/src/v2/components/segmented-control-v2.css
+++ b/packages/ui/src/v2/components/segmented-control-v2.css
@@ -34,7 +34,6 @@
background: transparent;
box-shadow: none;
cursor: pointer;
- font-family: var(--v2-font-family-sans), var(--sans);
font-style: normal;
font-weight: 440;
font-size: 13px;
diff --git a/packages/ui/src/v2/components/select-v2.css b/packages/ui/src/v2/components/select-v2.css
index 553f8afcd47e..85343eb02ed0 100644
--- a/packages/ui/src/v2/components/select-v2.css
+++ b/packages/ui/src/v2/components/select-v2.css
@@ -110,7 +110,6 @@
background: transparent;
outline: none;
text-align: left;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 440;
font-size: 13px;
diff --git a/packages/ui/src/v2/components/switch-v2.css b/packages/ui/src/v2/components/switch-v2.css
index 1459abf62418..f5aadefe5451 100644
--- a/packages/ui/src/v2/components/switch-v2.css
+++ b/packages/ui/src/v2/components/switch-v2.css
@@ -29,8 +29,8 @@
border-radius: 4px;
border: none;
background:
- linear-gradient(180deg, var(--alpha-light-0) 0%, var(--alpha-light-20) 100%), var(--background-bg-layer-03);
- box-shadow: var(--elevation-switch-off);
+ linear-gradient(180deg, var(--v2-alpha-light-0) 0%, var(--v2-alpha-light-20) 100%), var(--v2-background-bg-layer-03);
+ box-shadow: var(--v2-elevation-switch-off);
transition:
background 90ms ease-out,
opacity 90ms ease-out,
@@ -43,15 +43,15 @@
height: 12px;
transform: translateX(0);
border-radius: 2px;
- border: 0.5px solid var(--overlay-gradient-depth-overlay-depth-top);
+ border: 0.5px solid var(--v2-overlay-gradient-depth-overlay-depth-top);
background:
linear-gradient(
180deg,
- var(--overlay-gradient-depth-overlay-depth-top) 0%,
- var(--overlay-gradient-depth-overlay-depth-bot) 100%
+ var(--v2-overlay-gradient-depth-overlay-depth-top) 0%,
+ var(--v2-overlay-gradient-depth-overlay-depth-bot) 100%
),
- var(--grey-200);
- box-shadow: var(--elevation-elements);
+ var(--v2-grey-200);
+ box-shadow: var(--v2-elevation-elements);
transition:
transform 90ms ease-out,
width 90ms ease-out,
@@ -64,8 +64,7 @@
align-items: center;
height: 16px;
user-select: none;
- color: var(--text-text-faint);
- font-family: var(--v2-font-family-sans);
+ color: var(--v2-text-text-faint);
font-size: 11px;
font-style: normal;
font-weight: 440;
@@ -75,8 +74,7 @@
}
[data-slot="switch-error"] {
- color: var(--state-fg-danger);
- font-family: var(--v2-font-family-sans);
+ color: var(--v2-state-fg-danger);
font-size: 12px;
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
@@ -89,8 +87,8 @@
&:hover:not([data-disabled], [data-readonly]) [data-slot="switch-control"] {
background:
- linear-gradient(0deg, var(--overlay-simple-overlay-hover), var(--overlay-simple-overlay-hover)),
- linear-gradient(180deg, var(--alpha-light-0) 0%, var(--alpha-light-20) 100%), var(--background-bg-layer-03);
+ linear-gradient(0deg, var(--v2-overlay-simple-overlay-hover), var(--v2-overlay-simple-overlay-hover)),
+ linear-gradient(180deg, var(--v2-alpha-light-0) 0%, var(--v2-alpha-light-20) 100%), var(--v2-background-bg-layer-03);
}
&:hover:not([data-disabled], [data-readonly]) [data-slot="switch-thumb"] {
@@ -99,14 +97,14 @@
}
&:not([data-readonly]) [data-slot="switch-input"]:focus-visible ~ [data-slot="switch-control"] {
- outline: 2px solid var(--border-border-focus);
+ outline: 2px solid var(--v2-border-border-focus);
outline-offset: 1px;
}
&[data-checked] [data-slot="switch-control"] {
background:
- linear-gradient(180deg, var(--alpha-light-0) 0%, var(--alpha-light-10) 100%), var(--background-bg-accent);
- box-shadow: var(--elevation-switch-on);
+ linear-gradient(180deg, var(--v2-alpha-light-0) 0%, var(--v2-alpha-light-10) 100%), var(--v2-background-bg-accent);
+ box-shadow: var(--v2-elevation-switch-on);
}
&[data-checked] [data-slot="switch-thumb"] {
@@ -115,16 +113,16 @@
background:
linear-gradient(
180deg,
- var(--overlay-gradient-depth-overlay-depth-top) 0%,
- var(--overlay-gradient-depth-overlay-depth-bot) 100%
+ var(--v2-overlay-gradient-depth-overlay-depth-top) 0%,
+ var(--v2-overlay-gradient-depth-overlay-depth-bot) 100%
),
- var(--grey-300);
+ var(--v2-grey-300);
}
&[data-checked]:hover:not([data-disabled], [data-readonly]) [data-slot="switch-control"] {
background:
- linear-gradient(0deg, var(--overlay-simple-overlay-contrast-hover), var(--overlay-simple-overlay-contrast-hover)),
- linear-gradient(180deg, var(--alpha-light-0) 0%, var(--alpha-light-10) 100%), var(--background-bg-accent);
+ linear-gradient(0deg, var(--v2-overlay-simple-overlay-contrast-hover), var(--v2-overlay-simple-overlay-contrast-hover)),
+ linear-gradient(180deg, var(--v2-alpha-light-0) 0%, var(--v2-alpha-light-10) 100%), var(--v2-background-bg-accent);
}
&[data-checked]:hover:not([data-disabled], [data-readonly]) [data-slot="switch-thumb"] {
@@ -140,7 +138,7 @@
}
&[data-invalid] [data-slot="switch-control"] {
- border-color: var(--state-border-danger);
+ border-color: var(--v2-state-border-danger);
}
&[data-readonly] {
diff --git a/packages/ui/src/v2/components/tab-state-indicator.tsx b/packages/ui/src/v2/components/tab-state-indicator.tsx
new file mode 100644
index 000000000000..90b814d776ca
--- /dev/null
+++ b/packages/ui/src/v2/components/tab-state-indicator.tsx
@@ -0,0 +1,37 @@
+import { splitProps, type ComponentProps } from "solid-js"
+
+export function TabStateIndicator(props: ComponentProps<"svg">) {
+ const [local, rest] = splitProps(props, ["class", "classList", "width", "height"])
+ return (
+
+ )
+}
diff --git a/packages/ui/src/v2/components/tabs-v2.css b/packages/ui/src/v2/components/tabs-v2.css
index 83706aa71eb8..10e4261bae17 100644
--- a/packages/ui/src/v2/components/tabs-v2.css
+++ b/packages/ui/src/v2/components/tabs-v2.css
@@ -9,7 +9,6 @@
height: 100%;
display: flex;
overflow: clip;
- font-family: var(--v2-font-family-sans);
}
[data-component="tabs-v2"][data-orientation="horizontal"] {
@@ -75,11 +74,11 @@
display: flex;
align-items: center;
justify-content: center;
- color: var(--text-text-faint);
+ color: var(--v2-text-text-faint);
}
[data-component="tabs-v2"] [data-slot="tabs-v2-close-button"]:hover {
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
}
[data-component="tabs-v2"] [data-component="icon-button"] {
@@ -88,7 +87,7 @@
[data-component="tabs-v2"] [data-slot="tabs-v2-trigger-wrapper"]:disabled {
pointer-events: none;
- color: var(--text-text-faint);
+ color: var(--v2-text-text-faint);
}
[data-component="tabs-v2"][data-variant="normal"][data-orientation="horizontal"] [data-slot="tabs-v2-list"],
@@ -105,7 +104,7 @@
height: 1px;
content: "";
width: calc(100% + 16px);
- background-color: var(--border-border-base);
+ background-color: var(--v2-border-border-base);
position: absolute;
bottom: 0px;
left: -8px;
@@ -119,7 +118,7 @@
[data-component="tabs-v2"][data-variant="normal"][data-orientation="horizontal"] [data-slot="tabs-v2-trigger-wrapper"] {
height: 100%;
gap: 4px;
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
border-bottom: 1px solid transparent;
}
@@ -130,18 +129,18 @@
[data-component="tabs-v2"][data-variant="normal"][data-orientation="horizontal"]
[data-slot="tabs-v2-trigger-wrapper"]:hover:not(:disabled):not([data-selected]) {
- color: var(--text-text-base);
+ color: var(--v2-text-text-base);
}
[data-component="tabs-v2"][data-variant="normal"][data-orientation="horizontal"]
[data-slot="tabs-v2-trigger-wrapper"]:has([data-selected]) {
- border-bottom-color: var(--text-text-faint);
- color: var(--text-text-base);
+ border-bottom-color: var(--v2-text-text-faint);
+ color: var(--v2-text-text-base);
}
[data-component="tabs-v2"][data-variant="normal"][data-orientation="horizontal"]
[data-slot="tabs-v2-trigger-wrapper"]:not(:has([data-selected])) {
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
}
[data-component="tabs-v2"][data-variant="pill"][data-orientation="horizontal"] [data-slot="tabs-v2-trigger-wrapper"] {
@@ -149,7 +148,7 @@
border-radius: 4px;
border: 0.5px solid transparent;
box-sizing: border-box;
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
}
[data-component="tabs-v2"][data-variant="pill"][data-orientation="horizontal"] [data-slot="tabs-v2-trigger"] {
@@ -162,16 +161,16 @@
[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(--background-bg-layer-01);
- color: var(--text-text-base);
- border: 0.5px solid var(--border-border-muted);
+ background-color: var(--v2-background-bg-layer-01);
+ 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(--background-bg-layer-02);
- color: var(--text-text-base);
- border: 0.5px solid var(--border-border-muted);
+ background-color: var(--v2-background-bg-layer-02);
+ color: var(--v2-text-text-base);
+ border: 0.5px solid var(--v2-border-border-muted);
}
[data-component="tabs-v2"][data-variant="settings"][data-orientation="vertical"] [data-slot="tabs-v2-list"] {
@@ -182,13 +181,13 @@
padding: 12px;
gap: 4px;
overflow-y: auto;
- border-right: 1px solid var(--border-border-base);
+ border-right: 1px solid var(--v2-border-border-base);
}
[data-component="tabs-v2"][data-variant="settings"][data-orientation="vertical"] [data-slot="tabs-v2-section-title"] {
width: 100%;
padding-left: 4px;
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
font-size: 12px;
font-weight: 500;
}
@@ -199,7 +198,7 @@
border-radius: 4px;
border: 0.5px solid transparent;
box-sizing: border-box;
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
}
[data-component="tabs-v2"][data-variant="settings"][data-orientation="vertical"] [data-slot="tabs-v2-trigger"] {
@@ -212,12 +211,12 @@
[data-component="tabs-v2"][data-variant="settings"][data-orientation="vertical"]
[data-slot="tabs-v2-trigger-wrapper"]:hover:not(:disabled):not(:has([data-selected])) {
- color: var(--text-text-base);
+ 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(--background-bg-layer-02);
- color: var(--text-text-base);
- border: 0.5px solid var(--border-border-muted);
+ background-color: var(--v2-background-bg-layer-02);
+ color: var(--v2-text-text-base);
+ border: 0.5px solid var(--v2-border-border-muted);
}
diff --git a/packages/ui/src/v2/components/text-input-v2.css b/packages/ui/src/v2/components/text-input-v2.css
index 287f7f70a789..c6bcafaf1e53 100644
--- a/packages/ui/src/v2/components/text-input-v2.css
+++ b/packages/ui/src/v2/components/text-input-v2.css
@@ -11,8 +11,9 @@
border-radius: 6px;
outline: 1px solid transparent;
outline-offset: 0;
- background: linear-gradient(180deg, var(--alpha-light-2) 0%, var(--alpha-light-0) 100%), var(--background-bg-base);
- box-shadow: var(--elevation-button-neutral);
+ background:
+ linear-gradient(180deg, var(--v2-alpha-light-2) 0%, var(--v2-alpha-light-0) 100%), var(--v2-background-bg-base);
+ box-shadow: var(--v2-elevation-button-neutral);
flex: none;
align-self: stretch;
transition:
@@ -27,17 +28,17 @@
[data-component="text-input-v2"]:where(:hover):not([data-disabled], [data-invalid]):not(:focus-within) {
background:
- linear-gradient(0deg, var(--overlay-simple-overlay-hover), var(--overlay-simple-overlay-hover)),
- linear-gradient(180deg, var(--alpha-light-2) 0%, var(--alpha-light-0) 100%), var(--background-bg-base);
+ linear-gradient(0deg, var(--v2-overlay-simple-overlay-hover), var(--v2-overlay-simple-overlay-hover)),
+ linear-gradient(180deg, var(--v2-alpha-light-2) 0%, var(--v2-alpha-light-0) 100%), var(--v2-background-bg-base);
}
[data-component="text-input-v2"]:where(:focus-within):not([data-disabled], [data-invalid]) {
- outline-color: var(--border-border-focus);
+ outline-color: var(--v2-border-border-focus);
box-shadow: none;
}
[data-component="text-input-v2"]:where([data-invalid]):not([data-disabled]) {
- outline-color: var(--state-fg-danger);
+ outline-color: var(--v2-state-fg-danger);
box-shadow: none;
}
@@ -67,18 +68,17 @@
border: 0;
background: transparent;
outline: none;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 440;
font-size: 13px;
line-height: 1;
letter-spacing: -0.04px;
- color: var(--text-text-base);
+ color: var(--v2-text-text-base);
font-variation-settings: "slnt" 0;
}
[data-component="text-input-v2"] [data-slot="text-input-v2-input"]::placeholder {
- color: var(--text-text-faint);
+ color: var(--v2-text-text-faint);
}
[data-component="text-input-v2"][data-numeric] [data-slot="text-input-v2-input"] {
@@ -99,19 +99,19 @@
border: 0;
border-radius: 4px;
background: transparent;
- color: var(--icon-icon-muted);
+ color: var(--v2-icon-icon-muted);
cursor: pointer;
outline: none;
}
[data-component="text-input-v2"]
[data-slot="text-input-v2-icon-button"]:is(:hover, [data-state="hover"]):not(:disabled) {
- background-color: var(--overlay-simple-overlay-hover);
+ background-color: var(--v2-overlay-simple-overlay-hover);
}
[data-component="text-input-v2"]
[data-slot="text-input-v2-icon-button"]:is(:active, [data-state="pressed"]):not(:disabled) {
- background-color: var(--overlay-simple-overlay-pressed);
+ background-color: var(--v2-overlay-simple-overlay-pressed);
}
[data-component="text-input-v2"] [data-slot="text-input-v2-icon-button"]:focus {
@@ -119,7 +119,7 @@
}
[data-component="text-input-v2"] [data-slot="text-input-v2-icon-button"]:focus-visible {
- outline: 2px solid var(--border-border-focus);
+ outline: 2px solid var(--v2-border-border-focus);
outline-offset: 1px;
}
@@ -135,11 +135,11 @@
}
[data-component="text-input-v2"][data-invalid]:not([data-disabled]) [data-slot="text-input-v2-input"] {
- color: var(--state-fg-danger);
- caret-color: var(--state-fg-danger);
+ color: var(--v2-state-fg-danger);
+ caret-color: var(--v2-state-fg-danger);
}
[data-component="text-input-v2"][data-invalid]:not([data-disabled]) [data-slot="text-input-v2-input"]::placeholder {
- color: var(--state-fg-danger);
+ color: var(--v2-state-fg-danger);
opacity: 1;
}
diff --git a/packages/ui/src/v2/components/text-input-v2.stories.tsx b/packages/ui/src/v2/components/text-input-v2.stories.tsx
index 5e218bb82e70..8a77b891a8b7 100644
--- a/packages/ui/src/v2/components/text-input-v2.stories.tsx
+++ b/packages/ui/src/v2/components/text-input-v2.stories.tsx
@@ -19,7 +19,7 @@ Compact single-line text field with neutral elevation, optional trailing copy ac
- **Focus** (\`:focus-within\`): focus border, elevation removed.
- **Invalid**: danger border and text.
- **Disabled**: 50% opacity.
-- Uses \`data-component="text-input-v2"\` with \`--background-bg-base\`, \`--elevation-button-neutral\`, \`--text-text-faint\` (placeholder), and \`--icon-icon-muted\` (copy icon).
+- Uses \`data-component="text-input-v2"\` with \`--v2-background-bg-base\`, \`--v2-elevation-button-neutral\`, \`--v2-text-text-faint\` (placeholder), and \`--v2-icon-icon-muted\` (copy icon).
### Field
Compose with \`Field\` for label, helper prefix/suffix, and tooltip — see the **Field** story.
diff --git a/packages/ui/src/v2/components/textarea-v2.css b/packages/ui/src/v2/components/textarea-v2.css
index e43e18e9eef6..17bad60ed181 100644
--- a/packages/ui/src/v2/components/textarea-v2.css
+++ b/packages/ui/src/v2/components/textarea-v2.css
@@ -53,7 +53,6 @@
background: transparent;
outline: none;
resize: vertical;
- font-family: var(--v2-font-family-sans);
font-style: normal;
font-weight: 440;
font-size: 13px;
diff --git a/packages/ui/src/v2/components/toast-v2.css b/packages/ui/src/v2/components/toast-v2.css
index de777cf93192..5bce87dbdc7c 100644
--- a/packages/ui/src/v2/components/toast-v2.css
+++ b/packages/ui/src/v2/components/toast-v2.css
@@ -43,9 +43,9 @@
transition: transform 140ms ease-out;
border-radius: 8px;
- color: var(--text-text-base);
- background: var(--background-bg-layer-01);
- box-shadow: var(--elevation-floating);
+ color: var(--v2-text-text-base);
+ background: var(--v2-background-bg-layer-01);
+ box-shadow: var(--v2-elevation-floating);
&[data-opened] {
animation: toastV2PopIn 140ms ease-out;
@@ -71,9 +71,10 @@
height: 20px;
min-width: 16px;
min-height: 20px;
+ color: var(--v2-icon-icon-base);
[data-component="icon"] {
- color: var(--text-text-base);
+ color: var(--v2-icon-icon-base);
width: 16px;
height: 16px;
display: inline-flex;
@@ -109,11 +110,10 @@
}
[data-slot="toast-v2-title"] {
- color: var(--text-text-base);
+ color: var(--v2-text-text-base);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- font-family: "Inter Variable";
font-size: 13px;
font-style: normal;
font-weight: 530;
@@ -124,11 +124,10 @@
}
[data-slot="toast-v2-description"] {
- color: var(--text-text-muted);
+ color: var(--v2-text-text-muted);
text-wrap-style: pretty;
overflow-wrap: anywhere;
word-break: break-word;
- font-family: "Inter Variable";
font-size: 13px;
font-style: normal;
font-weight: 440;
@@ -147,7 +146,6 @@
[data-slot="toast-v2-actions"] [data-component="button-v2"] {
min-height: 24px;
- font-family: "Inter Variable";
font-size: 13px;
font-style: normal;
font-weight: 530;
@@ -166,10 +164,26 @@
border: 0;
border-radius: 4px;
background: transparent;
+ color: var(--v2-icon-icon-muted);
+ cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
+ &:hover {
+ background: var(--v2-overlay-simple-overlay-hover);
+ color: var(--v2-icon-icon-base);
+ }
+
+ &:active {
+ background: var(--v2-overlay-simple-overlay-pressed);
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--v2-border-border-focus);
+ outline-offset: 2px;
+ }
+
svg {
width: 16px;
height: 16px;
diff --git a/packages/ui/src/v2/components/toast-v2.tsx b/packages/ui/src/v2/components/toast-v2.tsx
index 15a5c985430e..67eb23b7fc27 100644
--- a/packages/ui/src/v2/components/toast-v2.tsx
+++ b/packages/ui/src/v2/components/toast-v2.tsx
@@ -61,8 +61,8 @@ function ToastV2CloseButton(props: ToastCloseButtonProps & ComponentProps<"butto
return (
)
diff --git a/packages/ui/src/v2/components/tool-error-card-v2.css b/packages/ui/src/v2/components/tool-error-card-v2.css
index 7622226d2bfd..2eaa3c4276b8 100644
--- a/packages/ui/src/v2/components/tool-error-card-v2.css
+++ b/packages/ui/src/v2/components/tool-error-card-v2.css
@@ -16,7 +16,6 @@
padding: 0 0 0 10px;
gap: 8px;
border-left: 2px solid var(--tec-border);
- font-family: var(--v2-font-family-sans), var(--sans), system-ui, sans-serif;
font-variant-numeric: tabular-nums;
[data-slot="tool-error-card-trigger"] {
diff --git a/packages/ui/src/v2/components/tooltip-v2.css b/packages/ui/src/v2/components/tooltip-v2.css
index e3dc298aa78e..19f17f1b617b 100644
--- a/packages/ui/src/v2/components/tooltip-v2.css
+++ b/packages/ui/src/v2/components/tooltip-v2.css
@@ -10,7 +10,6 @@
box-shadow: var(--elevation-floating);
border-radius: 4px;
- font-family: "Inter Variable";
font-style: normal;
font-weight: 530;
font-size: 11px;
diff --git a/packages/ui/src/v2/styles/theme.css b/packages/ui/src/v2/styles/theme.css
index 6bd3c0f6c9e6..24fe43300ba0 100644
--- a/packages/ui/src/v2/styles/theme.css
+++ b/packages/ui/src/v2/styles/theme.css
@@ -63,6 +63,26 @@
--v2-state-fg-info: var(--v2-blue-800);
--v2-state-border-info: var(--v2-blue-300);
+ /* ── Project avatar ── */
+ --v2-avatar-bg-orange: var(--v2-orange-700);
+ --v2-avatar-border-orange: var(--v2-orange-800);
+ --v2-avatar-bg-yellow: var(--v2-yellow-700);
+ --v2-avatar-border-yellow: var(--v2-yellow-800);
+ --v2-avatar-bg-cyan: var(--v2-cyan-700);
+ --v2-avatar-border-cyan: var(--v2-cyan-800);
+ --v2-avatar-bg-green: var(--v2-green-700);
+ --v2-avatar-border-green: var(--v2-green-800);
+ --v2-avatar-bg-red: var(--v2-red-700);
+ --v2-avatar-border-red: var(--v2-red-800);
+ --v2-avatar-bg-pink: var(--v2-pink-700);
+ --v2-avatar-border-pink: var(--v2-pink-800);
+ --v2-avatar-bg-blue: var(--v2-blue-700);
+ --v2-avatar-border-blue: var(--v2-blue-800);
+ --v2-avatar-bg-purple: var(--v2-purple-700);
+ --v2-avatar-border-purple: var(--v2-purple-800);
+ --v2-avatar-bg-gray: var(--v2-grey-700);
+ --v2-avatar-border-gray: var(--v2-grey-800);
+
/* ── Elevation ── */
--v2-elevation-raised:
0px 2px 4px 0px var(--v2-alpha-dark-4), 0px 1px 2px -1px var(--v2-alpha-dark-8),
@@ -285,6 +305,25 @@
--v2-illustration-illustration-layer-01: var(--v2-grey-300);
--v2-illustration-illustration-layer-02: var(--v2-grey-400);
--v2-illustration-illustration-layer-03: var(--v2-grey-500);
+
+ --v2-avatar-bg-orange: var(--v2-orange-700);
+ --v2-avatar-border-orange: var(--v2-orange-800);
+ --v2-avatar-bg-yellow: var(--v2-yellow-700);
+ --v2-avatar-border-yellow: var(--v2-yellow-800);
+ --v2-avatar-bg-cyan: var(--v2-cyan-700);
+ --v2-avatar-border-cyan: var(--v2-cyan-800);
+ --v2-avatar-bg-green: var(--v2-green-700);
+ --v2-avatar-border-green: var(--v2-green-800);
+ --v2-avatar-bg-red: var(--v2-red-700);
+ --v2-avatar-border-red: var(--v2-red-800);
+ --v2-avatar-bg-pink: var(--v2-pink-700);
+ --v2-avatar-border-pink: var(--v2-pink-800);
+ --v2-avatar-bg-blue: var(--v2-blue-700);
+ --v2-avatar-border-blue: var(--v2-blue-800);
+ --v2-avatar-bg-purple: var(--v2-purple-700);
+ --v2-avatar-border-purple: var(--v2-purple-800);
+ --v2-avatar-bg-gray: var(--v2-grey-700);
+ --v2-avatar-border-gray: var(--v2-grey-800);
}
/* Explicit dark mode via data attribute (Storybook toggle, runtime JS) */
@@ -346,6 +385,25 @@
--v2-state-fg-info: var(--v2-blue-500);
--v2-state-border-info: var(--v2-blue-900);
+ --v2-avatar-bg-orange: var(--v2-orange-1100);
+ --v2-avatar-border-orange: var(--v2-orange-600);
+ --v2-avatar-bg-yellow: var(--v2-yellow-1100);
+ --v2-avatar-border-yellow: var(--v2-yellow-700);
+ --v2-avatar-bg-cyan: var(--v2-cyan-1000);
+ --v2-avatar-border-cyan: var(--v2-cyan-700);
+ --v2-avatar-bg-green: var(--v2-green-1000);
+ --v2-avatar-border-green: var(--v2-green-600);
+ --v2-avatar-bg-red: var(--v2-red-1000);
+ --v2-avatar-border-red: var(--v2-red-700);
+ --v2-avatar-bg-pink: var(--v2-pink-1000);
+ --v2-avatar-border-pink: var(--v2-pink-700);
+ --v2-avatar-bg-blue: var(--v2-blue-900);
+ --v2-avatar-border-blue: var(--v2-blue-500);
+ --v2-avatar-bg-purple: var(--v2-purple-1000);
+ --v2-avatar-border-purple: var(--v2-purple-600);
+ --v2-avatar-bg-gray: var(--v2-grey-700);
+ --v2-avatar-border-gray: var(--v2-grey-500);
+
--v2-elevation-raised:
0px 2px 4px 0px var(--v2-alpha-dark-30), 0px 1px 2px 0px var(--v2-alpha-dark-30),
0px 0px 0px 0.5px var(--v2-alpha-light-16), 0px -0.5px 0px 0px var(--v2-alpha-light-6);