wip(share): more styling

This commit is contained in:
Adam 2025-11-24 11:56:00 -06:00
parent 3fb57044d1
commit acf1dd8500
No known key found for this signature in database
GPG key ID: 9CB48779AF150E75
30 changed files with 266 additions and 192 deletions

View file

@ -339,7 +339,7 @@ export default function Page() {
<div class="flex items-start justify-start h-full min-h-0">
<Show when={session.messages.user().length > 1}>
<MessageNav
classList={{ "mt-1.5 mr-3": wide(), "mt-3 mr-8": !wide() }}
classList={{ "mt-0.5 mr-3 absolute right-full": wide(), "mt-3 mr-8": !wide() }}
messages={session.messages.user()}
current={session.messages.active()}
onMessageSelect={session.messages.setActive}

View file

@ -1,18 +1 @@
@import "@opencode-ai/ui/styles/tailwind";
:root {
--background-rgb: 214, 219, 220;
--foreground-rgb: 0, 0, 0;
}
@media (prefers-color-scheme: dark) {
:root {
--background-rgb: 0, 0, 0;
--foreground-rgb: 255, 255, 255;
}
}
body {
/* background: rgb(var(--background-rgb)); */
/* color: rgb(var(--foreground-rgb)); */
}

View file

@ -1,6 +1,5 @@
import { Router } from "@solidjs/router"
import { FileRoutes } from "@solidjs/start/router"
import { Suspense } from "solid-js"
import { Fonts } from "@opencode-ai/ui/fonts"
import { MetaProvider } from "@solidjs/meta"
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
@ -10,16 +9,12 @@ export default function App() {
return (
<Router
root={(props) => (
<>
<Suspense>
<MarkedProvider>
<MetaProvider>
<Fonts />
{props.children}
</MetaProvider>
</MarkedProvider>
</Suspense>
</>
<MarkedProvider>
<MetaProvider>
<Fonts />
{props.children}
</MetaProvider>
</MarkedProvider>
)}
>
<FileRoutes />

View file

@ -3,15 +3,26 @@ import { SessionTurn } from "@opencode-ai/ui/session-turn"
import { SessionReview } from "@opencode-ai/ui/session-review"
import { DataProvider } from "@opencode-ai/ui/context"
import { createAsync, query, RouteDefinition, useParams } from "@solidjs/router"
import { createMemo, Show } from "solid-js"
import { createMemo, ErrorBoundary, Show } from "solid-js"
import { Share } from "~/core/share"
import { Logo, Mark } from "@opencode-ai/ui/logo"
import { IconButton } from "@opencode-ai/ui/icon-button"
import { iife } from "@opencode-ai/util/iife"
import { Binary } from "@opencode-ai/util/binary"
import { NamedError } from "@opencode-ai/util/error"
import { DateTime } from "luxon"
import { MessageNav } from "@opencode-ai/ui/message-nav"
import { createStore } from "solid-js/store"
import z from "zod"
import NotFound from "../[...404]"
const SessionDataMissingError = NamedError.create(
"SessionDataMissingError",
z.object({
sessionID: z.string(),
message: z.string().optional(),
}),
)
const getData = query(async (sessionID) => {
const data = await Share.data(sessionID)
@ -70,6 +81,8 @@ const getData = query(async (sessionID) => {
break
}
}
const match = Binary.search(result.session, sessionID!, (s) => s.id)
if (!match.found) throw new SessionDataMissingError({ sessionID })
return result
}, "getShareData")
@ -80,126 +93,172 @@ export const route = {
export default function () {
const params = useParams()
const data = createAsync(async () => {
if (!params.sessionID) return
if (!params.sessionID) throw new Error("Missing sessionID")
return getData(params.sessionID)
})
return (
<Show when={data()}>
{(data) => (
<DataProvider data={data()}>
{iife(() => {
const [store, setStore] = createStore({
messageId: undefined as string | undefined,
})
const match = createMemo(() => Binary.search(data().session, params.sessionID!, (s) => s.id))
if (!match().found) throw new Error(`Session ${params.sessionID} not found`)
const info = createMemo(() => data().session[match().index])
const messages = createMemo(() =>
params.sessionID ? (data().message[params.sessionID]?.filter((m) => m.role === "user") ?? []) : [],
)
const firstUserMessage = createMemo(() => messages().at(0))
const activeMessage = createMemo(
() => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(),
)
function setActiveMessage(message: UserMessage | undefined) {
if (message) {
setStore("messageId", message.id)
} else {
setStore("messageId", undefined)
<ErrorBoundary
fallback={(e) => {
return (
<Show when={e.message === "SessionDataMissingError"}>
<NotFound />
</Show>
)
}}
>
<Show when={data()}>
{(data) => (
<DataProvider data={data()}>
{iife(() => {
const [store, setStore] = createStore({
messageId: undefined as string | undefined,
})
const match = createMemo(() => Binary.search(data().session, params.sessionID!, (s) => s.id))
if (!match().found) throw new Error(`Session ${params.sessionID} not found`)
const info = createMemo(() => data().session[match().index])
const messages = createMemo(() =>
params.sessionID
? (data().message[params.sessionID]?.filter((m) => m.role === "user") ?? []).sort(
(a, b) => b.time.created - a.time.created,
)
: [],
)
const firstUserMessage = createMemo(() => messages().at(0))
const activeMessage = createMemo(
() => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(),
)
function setActiveMessage(message: UserMessage | undefined) {
if (message) {
setStore("messageId", message.id)
} else {
setStore("messageId", undefined)
}
}
}
const provider = createMemo(() => activeMessage()?.model?.providerID)
const modelID = createMemo(() => activeMessage()?.model?.modelID)
const model = createMemo(() => data().model[params.sessionID!]?.find((m) => m.id === modelID()))
const diffs = createMemo(() => data().session_diff[params.sessionID!] ?? [])
const provider = createMemo(() => activeMessage()?.model?.providerID)
const modelID = createMemo(() => activeMessage()?.model?.modelID)
const model = createMemo(() => data().model[params.sessionID!]?.find((m) => m.id === modelID()))
const diffs = createMemo(() => data().session_diff[params.sessionID!] ?? [])
return (
<div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col">
<header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base">
<div class="">
<a href="https://opencode.ai">
<Mark />
</a>
</div>
<div class="flex gap-3 items-center">
<IconButton
as={"a"}
href="https://github.com/sst/opencode"
target="_blank"
icon="github"
variant="ghost"
/>
<IconButton
as={"a"}
href="https://opencode.ai/discord"
target="_blank"
icon="discord"
variant="ghost"
/>
</div>
</header>
<div class="select-text flex flex-col flex-1 min-h-0">
<div class="w-full flex-1 min-h-0 flex">
<div
classList={{
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full mx-auto": true,
"px-21 @4xl:px-6 max-w-2xl": diffs().length > 0,
"px-6 max-w-2xl": diffs().length === 0,
}}
>
<div class="flex flex-col gap-4 shrink-0">
<div class="h-8 flex gap-4 items-center justify-start self-stretch">
<div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
<Mark class="shrink-0 w-3 my-0.5" />
<div class="text-12-mono text-text-base">v{info().version}</div>
</div>
<div class="flex gap-2 items-center">
<img
src={`https://models.dev/logos/${provider()}.svg`}
class="size-4 shrink-0 dark:invert"
/>
<div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
</div>
<div class="text-12-regular text-text-weaker">
{DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
</div>
</div>
<div class="text-left text-16-medium text-text-strong">{info().title}</div>
</div>
<div class="flex items-start justify-start h-full min-h-0">
<Show when={messages().length > 1}>
<MessageNav
classList={{ "mt-2 mr-3": true }}
messages={messages()}
current={activeMessage()}
onMessageSelect={setActiveMessage}
size={!diffs().length ? "normal" : "compact"}
/>
</Show>
<SessionTurn
sessionID={params.sessionID!}
messageID={store.messageId ?? firstUserMessage()!.id!}
classes={{ root: "grow", content: "flex flex-col justify-between", container: "pb-20" }}
>
<div class="flex items-center justify-center pb-8 shrink-0">
<Logo class="w-58.5 opacity-12" />
</div>
</SessionTurn>
</div>
const title = (
<div class="flex flex-col gap-4 shrink-0">
<div class="h-8 flex gap-4 items-center justify-start self-stretch">
<div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
<Mark class="shrink-0 w-3 my-0.5" />
<div class="text-12-mono text-text-base">v{info().version}</div>
</div>
<Show when={diffs().length}>
<div class="relative grow px-6 pt-14 flex-1 min-h-0 border-l border-border-weak-base">
<SessionReview diffs={diffs()} class="pb-20" />
<div class="flex gap-2 items-center">
<img src={`https://models.dev/logos/${provider()}.svg`} class="size-3.5 shrink-0 dark:invert" />
<div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
</div>
<div class="text-12-regular text-text-weaker">
{DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
</div>
</div>
<div class="text-left text-16-medium text-text-strong">{info().title}</div>
</div>
)
return (
<div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col">
<header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base">
<div class="">
<a href="https://opencode.ai">
<Mark />
</a>
</div>
<div class="flex gap-3 items-center">
<IconButton
as={"a"}
href="https://github.com/sst/opencode"
target="_blank"
icon="github"
variant="ghost"
/>
<IconButton
as={"a"}
href="https://opencode.ai/discord"
target="_blank"
icon="discord"
variant="ghost"
/>
</div>
</header>
<div class="select-text flex flex-col flex-1 min-h-0">
<div class="w-full flex-1 min-h-0 flex">
<div
classList={{
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full mx-auto": true,
"px-21 @4xl:px-6 max-w-2xl": diffs().length > 0,
"px-6 max-w-2xl": diffs().length === 0,
}}
>
{title}
<div class="flex items-start justify-start h-full min-h-0">
<Show when={messages().length > 1}>
<>
<div
classList={{
"xl:hidden": true,
"absolute right-[90%]": diffs().length > 0,
"absolute right-full": diffs().length === 0,
}}
>
<MessageNav
classList={{
"mt-0.5 mr-8": diffs().length === 0,
"mt-2.5 mr-3": diffs().length > 0,
}}
messages={messages()}
current={activeMessage()}
onMessageSelect={setActiveMessage}
size={!diffs().length ? "normal" : "compact"}
/>
</div>
<div
classList={{
"hidden xl:block": true,
"absolute right-[90%]": diffs().length > 0,
"absolute right-full": diffs().length === 0,
}}
>
<MessageNav
classList={{
"mt-0.5 mr-8": diffs().length === 0,
"mt-2.5 mr-3": diffs().length > 0,
}}
messages={messages()}
current={activeMessage()}
onMessageSelect={setActiveMessage}
size={!diffs().length ? "normal" : "compact"}
/>
</div>
</>
</Show>
<SessionTurn
sessionID={params.sessionID!}
messageID={store.messageId ?? firstUserMessage()!.id!}
classes={{ root: "grow", content: "flex flex-col justify-between", container: "pb-20" }}
>
<div class="flex items-center justify-center pb-8 shrink-0">
<Logo class="w-58.5 opacity-12" />
</div>
</SessionTurn>
</div>
</div>
</Show>
<Show when={diffs().length}>
<div class="relative grow px-6 pt-14 flex-1 min-h-0 border-l border-border-weak-base">
<SessionReview diffs={diffs()} class="pb-20" />
</div>
</Show>
</div>
</div>
</div>
</div>
)
})}
</DataProvider>
)}
</Show>
)
})}
</DataProvider>
)}
</Show>
</ErrorBoundary>
)
}

View file

@ -2,7 +2,7 @@ import z from "zod"
import { Global } from "../global"
import { Log } from "../util/log"
import path from "path"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { readableStreamToText } from "bun"
import { createRequire } from "module"
import { Lock } from "../util/lock"

View file

@ -1,6 +1,6 @@
import z from "zod"
import { EOL } from "os"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
export namespace UI {
const LOGO = [

View file

@ -8,7 +8,7 @@ import { mergeDeep, pipe } from "remeda"
import { Global } from "../global"
import fs from "fs/promises"
import { lazy } from "../util/lazy"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { Flag } from "../flag/flag"
import { Auth } from "../auth"
import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser"

View file

@ -1,4 +1,4 @@
import { NamedError } from "@/util/error"
import { NamedError } from "@opencode-ai/util/error"
import matter from "gray-matter"
import { z } from "zod"

View file

@ -2,7 +2,7 @@ import path from "path"
import { Global } from "../global"
import fs from "fs/promises"
import z from "zod"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { lazy } from "../util/lazy"
import { Log } from "../util/log"
import { ZipReader, BlobReader, BlobWriter } from "@zip.js/zip.js"

View file

@ -3,7 +3,7 @@ import path from "path"
import { Global } from "../global"
import fs from "fs/promises"
import z from "zod"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { lazy } from "../util/lazy"
import { $ } from "bun"

View file

@ -1,6 +1,6 @@
import { spawn } from "bun"
import z from "zod"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { Log } from "../util/log"
import { Bus } from "../bus"

View file

@ -9,7 +9,7 @@ import { UpgradeCommand } from "./cli/cmd/upgrade"
import { ModelsCommand } from "./cli/cmd/models"
import { UI } from "./cli/ui"
import { Installation } from "./installation"
import { NamedError } from "./util/error"
import { NamedError } from "@opencode-ai/util/error"
import { FormatError } from "./cli/error"
import { ServeCommand } from "./cli/cmd/serve"
import { DebugCommand } from "./cli/cmd/debug"

View file

@ -1,7 +1,7 @@
import path from "path"
import { $ } from "bun"
import z from "zod"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { Bus } from "../bus"
import { Log } from "../util/log"

View file

@ -6,7 +6,7 @@ import { LANGUAGE_EXTENSIONS } from "./language"
import { Bus } from "../bus"
import z from "zod"
import type { LSPServer } from "./server"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { withTimeout } from "../util/timeout"
import { Instance } from "../project/instance"

View file

@ -5,7 +5,7 @@ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
import { Config } from "../config/config"
import { Log } from "../util/log"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import z from "zod/v4"
import { Instance } from "../project/instance"
import { withTimeout } from "@/util/timeout"

View file

@ -4,7 +4,7 @@ import { map, filter, pipe, fromEntries, mapValues } from "remeda"
import z from "zod"
import { fn } from "@/util/fn"
import type { AuthOuathResult, Hooks } from "@opencode-ai/plugin"
import { NamedError } from "@/util/error"
import { NamedError } from "@opencode-ai/util/error"
import { Auth } from "@/auth"
export namespace ProviderAuth {

View file

@ -7,7 +7,7 @@ import { Log } from "../util/log"
import { BunProc } from "../bun"
import { Plugin } from "../plugin"
import { ModelsDev } from "./models"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { Auth } from "../auth"
import { Instance } from "../project/instance"
import { Flag } from "../flag/flag"

View file

@ -9,7 +9,7 @@ import { Session } from "../session"
import z from "zod"
import { Provider } from "../provider/provider"
import { mapValues } from "remeda"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { ModelsDev } from "../provider/models"
import { Ripgrep } from "../file/ripgrep"
import { Config } from "../config/config"

View file

@ -1,6 +1,6 @@
import z from "zod"
import { Bus } from "../bus"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
import { Message } from "./message"
import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai"
import { Identifier } from "../id/id"

View file

@ -1,5 +1,5 @@
import z from "zod"
import { NamedError } from "../util/error"
import { NamedError } from "@opencode-ai/util/error"
export namespace Message {
export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))

View file

@ -43,7 +43,7 @@ import { Command } from "../command"
import { $, fileURLToPath } from "bun"
import { ConfigMarkdown } from "../config/markdown"
import { SessionSummary } from "./summary"
import { NamedError } from "@/util/error"
import { NamedError } from "@opencode-ai/util/error"
import { fn } from "@/util/fn"
import { SessionProcessor } from "./processor"
import { TaskTool } from "@/tool/task"

View file

@ -5,7 +5,7 @@ import { Global } from "../global"
import { lazy } from "../util/lazy"
import { Lock } from "../util/lock"
import { $ } from "bun"
import { NamedError } from "@/util/error"
import { NamedError } from "@opencode-ai/util/error"
import z from "zod"
export namespace Storage {

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,6 +1,6 @@
import { Style, Link } from "@solidjs/meta"
import geist from "../assets/fonts/geist.woff2"
import geistMono from "../assets/fonts/geist-mono.woff2"
import tx02 from "../assets/fonts/tx-02.woff2"
export const Fonts = () => {
return (
@ -22,14 +22,14 @@ export const Fonts = () => {
line-gap-override: 1%;
}
@font-face {
font-family: "Geist Mono";
src: url("${geistMono}") format("woff2-variations");
font-family: "Berkeley Mono";
src: url("${tx02}") format("woff2-variations");
font-display: swap;
font-style: normal;
font-weight: 100 900;
font-weight: 400 700;
}
@font-face {
font-family: "Geist Mono Fallback";
font-family: "Berkeley Mono Fallback";
src: local("Courier New");
size-adjust: 100%;
ascent-override: 97%;
@ -38,7 +38,7 @@ export const Fonts = () => {
}
`}</Style>
<Link rel="preload" href={geist} as="font" type="font/woff2" crossorigin="anonymous" />
<Link rel="preload" href={geistMono} as="font" type="font/woff2" crossorigin="anonymous" />
<Link rel="preload" href={tx02} as="font" type="font/woff2" crossorigin="anonymous" />
</>
)
}

View file

@ -1,6 +1,4 @@
[data-component="message-nav"] {
/* margin-right: 32px; */
/* margin-top: 12px; */
flex-shrink: 0;
display: flex;
flex-direction: column;
@ -9,15 +7,8 @@
list-style: none;
&[data-size="normal"] {
position: absolute;
right: 100%;
width: 240px;
/* margin-top: 12px; */
@media (min-width: 80rem) {
gap: 8px;
/* margin-top: 4px; */
}
gap: 4px;
}
}
@ -36,10 +27,8 @@
display: flex;
align-items: center;
justify-content: flex-start;
height: 8px;
width: 32px;
/* margin-right: -12px; */
cursor: pointer;
height: 12px;
width: 24px;
border: none;
background: none;
padding: 0;
@ -52,7 +41,7 @@
[data-slot="message-nav-tick-line"] {
height: 1px;
width: 20px;
width: 16px;
background-color: var(--icon-base);
transition:
width 0.2s,
@ -69,11 +58,12 @@
align-items: center;
align-self: stretch;
width: 100%;
column-gap: 8px;
column-gap: 12px;
cursor: default;
border: none;
background: none;
padding: 0;
padding: 4px 12px;
border-radius: var(--radius-sm);
}
[data-slot="message-nav-title-preview"] {
@ -90,6 +80,37 @@
}
}
[data-slot="message-nav-item"]:hover [data-slot="message-nav-title-preview"] {
[data-slot="message-nav-item"]:hover [data-slot="message-nav-message-button"] {
background-color: var(--surface-base);
}
[data-slot="message-nav-item"]:active [data-slot="message-nav-message-button"] {
background-color: var(--surface-base-active);
}
[data-slot="message-nav-item"]:active [data-slot="message-nav-title-preview"] {
color: var(--text-base);
}
[data-slot="message-nav-tooltip"] {
z-index: 1000;
}
[data-slot="message-nav-tooltip-content"] {
display: flex;
padding: 4px 4px 6px 4px;
justify-content: center;
align-items: center;
border-radius: var(--radius-md);
background: var(--surface-raised-stronger-non-alpha);
/* border/shadow-xs/base */
box-shadow:
0 0 0 1px var(--border-weak-base, rgba(17, 0, 0, 0.12)),
0 1px 2px -1px rgba(19, 16, 16, 0.04),
0 1px 2px 0 rgba(19, 16, 16, 0.06),
0 1px 3px 0 rgba(19, 16, 16, 0.08);
* {
margin: 0 !important;
}
}

View file

@ -2,6 +2,8 @@ import { UserMessage } from "@opencode-ai/sdk"
import { ComponentProps, createMemo, For, Match, Show, splitProps, Switch } from "solid-js"
import { DiffChanges } from "./diff-changes"
import { Spinner } from "./spinner"
import { HoverCard } from "@kobalte/core/hover-card"
import { Tooltip } from "@kobalte/core/tooltip"
export function MessageNav(
props: ComponentProps<"ul"> & {
@ -17,7 +19,7 @@ export function MessageNav(
return local.messages?.at(0)
})
return (
const content = (
<ul role="list" data-component="message-nav" data-size={local.size} {...others}>
<For each={local.messages}>
{(message) => {
@ -28,13 +30,9 @@ export function MessageNav(
<li data-slot="message-nav-item">
<Switch>
<Match when={local.size === "compact"}>
<button
data-slot="message-nav-tick-button"
data-active={message.id === local.current?.id || undefined}
onClick={handleClick}
>
<div data-slot="message-nav-tick-button" data-active={message.id === local.current?.id || undefined}>
<div data-slot="message-nav-tick-line" />
</button>
</div>
</Match>
<Match when={local.size === "normal"}>
<button data-slot="message-nav-message-button" onClick={handleClick}>
@ -63,4 +61,22 @@ export function MessageNav(
</For>
</ul>
)
return (
<Switch>
<Match when={local.size === "compact"}>
<Tooltip openDelay={0} closeDelay={0} placement="top-start" gutter={-65} shift={-16} overlap>
<Tooltip.Trigger as="div">{content}</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content data-slot="message-nav-tooltip">
<div data-slot="message-nav-tooltip-content">
<MessageNav {...props} size="normal" />
</div>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip>
</Match>
<Match when={local.size === "normal"}>{content}</Match>
</Switch>
)
}

View file

@ -1,8 +1,8 @@
:root {
--font-family-sans: "Geist", "Geist Fallback";
--font-family-sans--font-feature-settings: "ss03" 1;
--font-family-mono: "Geist Mono", "Geist Mono Fallback";
--font-family-mono--font-feature-settings: "ss02" 1;
--font-family-mono: "Berkeley Mono", "Berkeley Mono Fallback";
--font-family-mono--font-feature-settings: "ss01" 1;
--font-size-small: 12px;
--font-size-base: 14px;