Skip to content
Merged
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
19 changes: 19 additions & 0 deletions packages/app/src/components/session-context-usage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Match, Show, Switch, createMemo } from "solid-js"
import { Tooltip, type TooltipProps } from "@opencode-ai/ui/tooltip"
import { ProgressCircle } from "@opencode-ai/ui/progress-circle"
import { ProgressCircleV2 } from "@opencode-ai/ui/v2/progress-circle-v2"
import { Button } from "@opencode-ai/ui/button"
import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"

import { useFile } from "@/context/file"
import { useLayout } from "@/context/layout"
Expand All @@ -15,6 +17,7 @@ import { createSessionTabs } from "@/pages/session/helpers"

interface SessionContextUsageProps {
variant?: "button" | "indicator"
buttonAppearance?: "default" | "v2"
placement?: TooltipProps["placement"]
}

Expand All @@ -39,6 +42,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
const { params, tabs, view } = useSessionLayout()

const variant = createMemo(() => props.variant ?? "button")
const buttonAppearance = createMemo(() => props.buttonAppearance ?? "default")
const tabState = createSessionTabs({
tabs,
pathFromTab: file.pathFromTab,
Expand Down Expand Up @@ -79,6 +83,11 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
<ProgressCircle size={16} strokeWidth={2} percentage={context()?.usage ?? 0} />
</div>
)
const circleV2 = () => (
<div class="flex items-center justify-center">
<ProgressCircleV2 percentage={context()?.usage ?? 0} />
</div>
)

const tooltipValue = () => (
<div>
Expand Down Expand Up @@ -108,6 +117,16 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
<Tooltip value={tooltipValue()} placement={props.placement ?? "top"}>
<Switch>
<Match when={variant() === "indicator"}>{circle()}</Match>
<Match when={buttonAppearance() === "v2"}>
<IconButtonV2
type="button"
variant="ghost-muted"
size="large"
icon={circleV2()}
onClick={openContext}
aria-label={language.t("context.usage.view")}
/>
</Match>
<Match when={true}>
<Button
type="button"
Expand Down
446 changes: 337 additions & 109 deletions packages/app/src/pages/session/timeline/message-timeline.tsx

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions packages/ui/src/v2/components/button-v2.css
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,26 @@
cursor: not-allowed;
}

/* Outline */
[data-component="button-v2"][data-variant="outline"] {
background-color: transparent;
color: var(--v2-text-text-base);
box-shadow: inset 0 0 0 1px var(--v2-border-border-muted);
}

[data-component="button-v2"][data-variant="outline"]:is(:hover, [data-state="hover"]):not(:disabled) {
background-color: var(--v2-overlay-simple-overlay-hover);
}

[data-component="button-v2"][data-variant="outline"]:is(:active, [data-state="pressed"]):not(:disabled) {
background-color: var(--v2-overlay-simple-overlay-pressed);
}

[data-component="button-v2"][data-variant="outline"]:is(:disabled, [data-state="disabled"]) {
opacity: 0.5;
cursor: not-allowed;
}

/* Contrast */
[data-component="button-v2"][data-variant="contrast"] {
background-image:
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/v2/components/button-v2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface ButtonV2Props
extends ComponentProps<typeof Kobalte>,
Pick<ComponentProps<"button">, "class" | "classList" | "children"> {
size?: "small" | "normal" | "large"
variant?: "neutral" | "danger" | "contrast" | "ghost" | "ghost-muted"
variant?: "neutral" | "danger" | "contrast" | "ghost" | "ghost-muted" | "outline"
icon?: IconProps["name"]
}

Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/v2/components/dialog-v2.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
margin: 0;
flex: 1;
min-width: 0;
user-select: none;
font-weight: 530;
font-size: 13px;
line-height: 16px;
Expand All @@ -80,6 +81,7 @@
margin: 0;
flex: none;
flex-grow: 0;
user-select: none;
font-weight: 530;
font-size: 15px;
line-height: 20px;
Expand All @@ -91,6 +93,7 @@
[data-slot="dialog-description"] {
flex: none;
flex-grow: 0;
user-select: none;
font-weight: 440;
font-size: 13px;
line-height: 20px;
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/v2/components/dialog-v2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,5 @@ export function Dialog(props: DialogProps) {
</div>
)
}

export const DialogV2 = Dialog
8 changes: 8 additions & 0 deletions packages/ui/src/v2/components/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ const icons = {
viewBox: "0 0 16 16",
body: `<path d="M2.5 7.5H3.5V8.5H2.5V7.5Z" stroke="currentColor"/><path d="M7.5 7.5H8.5V8.5H7.5V7.5Z" stroke="currentColor"/><path d="M12.5 7.5H13.5V8.5H12.5V7.5Z" stroke="currentColor"/>`,
},
"outline-copy": {
viewBox: "0 0 16 16",
body: `<path d="M4.14908 11.0081H1.76282V1.51758H9.1038V2.55588M14.2225 4.99681H6.75397V14.4873H14.2225V4.99681Z" stroke="currentColor"/>`,
},
"outline-square-arrow": {
viewBox: "0 0 16 16",
body: `<path d="M13.5555 6.66656V2.44434H9.33326M13.5555 2.44434L7.99993 7.99989M13.5555 9.33324V13.5555C13.5555 13.5555 12.7599 13.5555 11.7777 13.5555H2.44438C2.44438 13.5555 2.44438 12.7599 2.44438 11.7777V4.22213C2.44438 3.2399 2.44434 2.44435 2.44434 2.44435H6.66661" stroke="currentColor"/>`,
},
archive: {
viewBox: "0 0 16 16",
body: `<path d="M13.1112 13.5555V14.0555H13.6112V13.5555H13.1112ZM2.889 13.5555H2.389L2.389 14.0555H2.889V13.5555ZM3.38901 5.55546L3.38901 5.05546L2.38901 5.05546L2.38901 5.55546L2.88901 5.55546L3.38901 5.55546ZM14.4446 2.44434H14.9446V1.94434L14.4446 1.94434L14.4446 2.44434ZM14.4446 5.55545L14.4446 6.05545L14.9446 6.05545V5.55545H14.4446ZM1.55566 5.55546L1.05566 5.55545L1.05566 6.05546L1.55566 6.05546L1.55566 5.55546ZM1.5557 2.44436L1.5557 1.94436L1.05571 1.94436L1.0557 2.44435L1.5557 2.44436ZM13.1112 5.55546H12.6112V13.5555H13.1112H13.6112V5.55546H13.1112ZM2.889 13.5555H3.389L3.38901 5.55546L2.88901 5.55546L2.38901 5.55546L2.389 13.5555H2.889ZM14.4446 2.44434H13.9446V5.55545H14.4446H14.9446V2.44434H14.4446ZM1.55566 5.55546L2.05566 5.55547L2.0557 2.44436L1.5557 2.44436L1.0557 2.44435L1.05566 5.55545L1.55566 5.55546ZM6.22234 8.22213V8.72213H9.7779V8.22213V7.72213H6.22234V8.22213ZM13.1112 13.5555V13.0555H2.889V13.5555V14.0555H13.1112V13.5555ZM1.5557 2.44436L1.5557 2.94436L14.4446 2.94434L14.4446 2.44434L14.4446 1.94434L1.5557 1.94436L1.5557 2.44436ZM14.4446 5.55545L14.4446 5.05545L1.55566 5.05546L1.55566 5.55546L1.55566 6.05546L14.4446 6.05545L14.4446 5.55545Z" fill="currentColor"/>`,
Expand Down
13 changes: 13 additions & 0 deletions packages/ui/src/v2/components/progress-circle-v2.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[data-component="progress-circle-v2"] {
display: block;
transform: rotate(-90deg);
}

[data-component="progress-circle-v2"] [data-slot="progress-circle-v2-background"] {
stroke: var(--v2-background-bg-layer-04);
}

[data-component="progress-circle-v2"] [data-slot="progress-circle-v2-progress"] {
stroke: var(--v2-icon-icon-muted);
transition: stroke-dashoffset 0.35s cubic-bezier(0.65, 0, 0.35, 1);
}
46 changes: 46 additions & 0 deletions packages/ui/src/v2/components/progress-circle-v2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { type ComponentProps, createMemo, splitProps } from "solid-js"
import "./progress-circle-v2.css"

export interface ProgressCircleV2Props extends Pick<ComponentProps<"svg">, "class" | "classList"> {
percentage: number
size?: number
strokeWidth?: number
}

export function ProgressCircleV2(props: ProgressCircleV2Props) {
const [split, rest] = splitProps(props, ["percentage", "size", "strokeWidth", "class", "classList"])

const size = () => split.size ?? 14
const strokeWidth = () => split.strokeWidth ?? 1.5
const viewBoxSize = 14
const center = viewBoxSize / 2
const radius = () => center - strokeWidth() / 2
const circumference = createMemo(() => 2 * Math.PI * radius())
const offset = createMemo(() => circumference() * (1 - Math.max(0, Math.min(100, split.percentage || 0)) / 100))

return (
<svg
{...rest}
width={size()}
height={size()}
viewBox={`0 0 ${viewBoxSize} ${viewBoxSize}`}
fill="none"
data-component="progress-circle-v2"
classList={{
...split.classList,
[split.class ?? ""]: !!split.class,
}}
>
<circle cx={center} cy={center} r={radius()} data-slot="progress-circle-v2-background" stroke-width={strokeWidth()} />
<circle
cx={center}
cy={center}
r={radius()}
data-slot="progress-circle-v2-progress"
stroke-width={strokeWidth()}
stroke-dasharray={circumference().toString()}
stroke-dashoffset={offset()}
/>
</svg>
)
}
Loading