mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-13 19:46:16 +03:00
fix(app): fit titlebar update pill to translated labels (#57422)
Co-authored-by: neriousy <34747899+neriousy@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
3bc6413d8c
commit
5c95abcf34
@@ -0,0 +1,58 @@
|
||||
import { For } from "solid-js"
|
||||
import type { TitlebarItem } from "@opencode/gui-extensions/sdk"
|
||||
import { TitlebarItems } from "./titlebar-items"
|
||||
|
||||
const catalogs = import.meta.glob<{ default: Record<string, string> }>(
|
||||
"../../../../gui-extensions/src/updater/i18n/*.ts",
|
||||
{ eager: true },
|
||||
)
|
||||
|
||||
const rtl = new Set(["ar", "dv", "fa", "he", "ur"])
|
||||
|
||||
const locales = Object.entries(catalogs)
|
||||
.map(([file, module]) => ({
|
||||
locale: file.split("/").pop()!.replace(".ts", ""),
|
||||
label: module.default["status.label"]!,
|
||||
}))
|
||||
.sort((a, b) => a.locale.localeCompare(b.locale))
|
||||
|
||||
const items = (label: string) => {
|
||||
const item: TitlebarItem = { id: "update", label, run: () => {} }
|
||||
|
||||
return { ids: () => [item.id], item: () => item }
|
||||
}
|
||||
|
||||
export default {
|
||||
title: "App/Titlebar/Items",
|
||||
id: "app-titlebar-items",
|
||||
component: TitlebarItems,
|
||||
}
|
||||
|
||||
/** The update pill in every updater locale; hover or focus a pill to expand its label. */
|
||||
export const UpdateLabels = {
|
||||
render: () => (
|
||||
<div class="flex flex-col gap-1 bg-v2-background-bg-base p-4">
|
||||
<For each={locales}>
|
||||
{(entry) => (
|
||||
<div data-locale={entry.locale} dir={rtl.has(entry.locale) ? "rtl" : "ltr"} class="flex items-center gap-4">
|
||||
<span class="w-10 shrink-0 font-mono text-[11px] text-v2-text-text-weak">{entry.locale}</span>
|
||||
<div
|
||||
data-slot="story-horizontal"
|
||||
class="flex h-10 w-[320px] shrink-0 items-center justify-end rounded-md bg-v2-background-bg-deep/60"
|
||||
>
|
||||
<div class="relative z-20 flex shrink-0 items-center justify-end overflow-visible">
|
||||
<TitlebarItems items={items(entry.label)} />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
data-slot="story-vertical"
|
||||
class="flex w-[220px] shrink-0 flex-col rounded-md bg-v2-background-bg-deep/60 p-2"
|
||||
>
|
||||
<TitlebarItems items={items(entry.label)} vertical />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
),
|
||||
}
|
||||
@@ -35,7 +35,7 @@ export function TitlebarItems(props: { items: ReturnType<typeof useTitlebarItems
|
||||
function TitlebarItemButton(props: { item: TitlebarItem; vertical?: boolean }) {
|
||||
const label = () => (
|
||||
<span
|
||||
class="shrink-0 text-[11px] leading-4 text-v2-text-text-accent [font-weight:530] opacity-0 motion-safe:transition-all duration-150 ease-out group-hover:opacity-100 group-hover:translate-x-0 group-focus-within:opacity-100 group-focus-within:translate-x-0 motion-reduce:translate-x-0"
|
||||
class="shrink-0 whitespace-nowrap text-[11px] leading-4 text-v2-text-text-accent [font-weight:530] opacity-0 motion-safe:transition-all duration-150 ease-out group-hover:opacity-100 group-hover:translate-x-0 group-focus-within:opacity-100 group-focus-within:translate-x-0 motion-reduce:translate-x-0"
|
||||
classList={{
|
||||
"ms-px me-4 -translate-x-2 rtl:translate-x-2": props.vertical,
|
||||
"ms-2 me-px translate-x-2 rtl:-translate-x-2": !props.vertical,
|
||||
@@ -45,19 +45,20 @@ function TitlebarItemButton(props: { item: TitlebarItem; vertical?: boolean }) {
|
||||
</span>
|
||||
)
|
||||
|
||||
// The pill grows to fit its label, so translated labels of any length show in full.
|
||||
return (
|
||||
<div
|
||||
data-slot="titlebar-update"
|
||||
class="group relative shrink-0 rounded-full bg-v2-background-bg-deep transition-[width] duration-150 ease-out hover:z-30 focus-within:z-30 motion-reduce:transition-none"
|
||||
class="group relative shrink-0 rounded-full bg-v2-background-bg-deep transition-[width] duration-150 ease-out [interpolate-size:allow-keywords] hover:z-30 hover:w-fit focus-within:z-30 focus-within:w-fit motion-reduce:transition-none"
|
||||
classList={{
|
||||
"h-7 w-7 self-start hover:w-[84px] focus-within:w-[84px]": props.vertical,
|
||||
"me-3 h-5 w-5 hover:w-[68px] focus-within:w-[68px]": !props.vertical,
|
||||
"h-7 w-7 self-start": props.vertical,
|
||||
"me-3 h-5 w-5": !props.vertical,
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute top-0 z-10 flex h-full w-full items-center overflow-hidden rounded-full bg-v2-icon-icon-accent/20 text-v2-icon-icon-accent transition-[background-color] duration-150 ease-out group-hover:bg-[color-mix(in_srgb,var(--v2-icon-icon-accent)_20%,var(--v2-background-bg-deep))] group-focus-within:bg-[color-mix(in_srgb,var(--v2-icon-icon-accent)_20%,var(--v2-background-bg-deep))] focus-visible:outline-none disabled:opacity-60 motion-reduce:transition-none [app-region:no-drag]"
|
||||
classList={{ "start-0 justify-start": props.vertical, "end-0 justify-end": !props.vertical }}
|
||||
class="relative z-10 flex h-full w-full items-center overflow-hidden rounded-full bg-v2-icon-icon-accent/20 text-v2-icon-icon-accent transition-[background-color] duration-150 ease-out group-hover:bg-[color-mix(in_srgb,var(--v2-icon-icon-accent)_20%,var(--v2-background-bg-deep))] group-focus-within:bg-[color-mix(in_srgb,var(--v2-icon-icon-accent)_20%,var(--v2-background-bg-deep))] focus-visible:outline-none disabled:opacity-60 motion-reduce:transition-none [app-region:no-drag]"
|
||||
classList={{ "justify-start": props.vertical, "justify-end": !props.vertical }}
|
||||
onClick={() => props.item.run?.()}
|
||||
disabled={!!props.item.busy}
|
||||
aria-busy={!!props.item.busy}
|
||||
|
||||
Reference in New Issue
Block a user