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
7 changes: 7 additions & 0 deletions changelog/unreleased/account-type-picker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### English

- Choose an account type from cards instead of a dropdown, with a Codex mark and a scrollable list that keeps the dialog width stable.

### 中文

- 新建账号改为卡片选择渠道,补上 Codex 图标;渠道过多时列表在固定高度内滚动,弹窗保持加宽后的宽度。
48 changes: 3 additions & 45 deletions frontend/src/components/AddAccountModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react'
import { Button, Description, Input, Label, ListBox, Modal, NumberField, Select, Skeleton, TextArea } from '@heroui/react'
import { Button, Input, Modal, NumberField, Skeleton, TextArea } from '@heroui/react'
import { ArrowSquareOut, CaretLeft, CaretRight, CheckCircle, FileCode, Key, ShieldCheck, X } from '@phosphor-icons/react'
import { BrandMark } from '@/components/BrandMark'
import { ProviderMark } from '@/components/ProviderMark'
Expand Down Expand Up @@ -123,7 +123,6 @@ type Phase = 'idle' | 'busy' | 'polling' | 'done'

const POLL_ATTEMPTS = 90
const POLL_INTERVAL = 2000
const TILE_LIMIT = 6

export function AddAccountModal({ isOpen, onClose, onAdded }: Props) {
const { t } = useI18n()
Expand Down Expand Up @@ -412,7 +411,6 @@ export function AddAccountModal({ isOpen, onClose, onAdded }: Props) {
}

const tabPending = (key: TabKey) => busy && tab === key
const useTypeSelect = providerOptions.length > TILE_LIMIT
const typeOptions = providerOptions.map((option) => ({
value: option.id,
label: optionLabel(option, t),
Expand Down Expand Up @@ -442,7 +440,7 @@ export function AddAccountModal({ isOpen, onClose, onAdded }: Props) {
return (
<Modal.Root isOpen={isOpen} onOpenChange={(next: boolean) => { if (!next) close() }}>
<Modal.Backdrop variant="blur" isDismissable={!busy}>
<Modal.Container size="lg" scroll="inside">
<Modal.Container size="lg" scroll="inside" className="sm:max-w-3xl">
<Modal.Dialog>
<Modal.Header className="items-start justify-between gap-4 px-5 pt-5">
<div className="min-w-0">
Expand All @@ -467,47 +465,6 @@ export function AddAccountModal({ isOpen, onClose, onAdded }: Props) {
<span className="text-sm font-medium text-muted">{t('accountType')}</span>
<p className="rounded-lg border border-separator bg-surface-secondary/45 px-3.5 py-3 text-xs leading-5 text-muted">{t('accountTypeHint')}</p>
</>
) : useTypeSelect ? (
<Select
fullWidth
aria-label={t('accountType')}
value={accountType}
isDisabled={settingsLocked}
onChange={(next) => {
if (typeof next === 'string' && next && !settingsLocked) setAccountType(next)
}}
>
<Label className="text-sm font-medium text-muted">{t('accountType')}</Label>
<Select.Trigger className="items-center">
<Select.Value className="min-w-0 truncate">
{({ defaultChildren, isPlaceholder }) => {
const selected = typeOptions.find((option) => option.value === accountType)
if (isPlaceholder || !selected) return defaultChildren
return (
<span className="flex min-w-0 items-center gap-2">
<span className="grid size-5 shrink-0 place-items-center">{selected.icon}</span>
<span className="truncate">{selected.label}</span>
</span>
)
}}
</Select.Value>
<Select.Indicator />
</Select.Trigger>
<Select.Popover className="max-h-72">
<ListBox>
{typeOptions.map((option) => (
<ListBox.Item key={option.value} id={option.value} textValue={option.label}>
<span className="grid size-5 shrink-0 place-items-center">{option.icon}</span>
<div className="min-w-0 flex-1">
<Label className="block truncate">{option.label}</Label>
{option.hint ? <Description className="truncate">{option.hint}</Description> : null}
</div>
<ListBox.ItemIndicator />
</ListBox.Item>
))}
</ListBox>
</Select.Popover>
</Select>
) : (
<>
<span className="text-sm font-medium text-muted">{t('accountType')}</span>
Expand All @@ -517,6 +474,7 @@ export function AddAccountModal({ isOpen, onClose, onAdded }: Props) {
value={accountType}
onChange={(next) => { if (!settingsLocked) setAccountType(next) }}
options={typeOptions}
className="max-h-72 overflow-y-auto overscroll-contain pr-1"
/>
</>
)}
Expand Down
16 changes: 11 additions & 5 deletions frontend/src/components/CodexMark.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ type Props = {
className?: string
}

// OpenAI blossom. A letter would collide with Command's "C".
export function CodexMark({ size = 16, className = '' }: Props) {
return (
<span
className={`inline-flex shrink-0 items-center justify-center rounded-[22%] bg-black text-white ${className}`.trim()}
style={{ width: size, height: size, fontSize: Math.max(9, Math.round(size * 0.5)), fontWeight: 700, lineHeight: 1 }}
<svg
width={size}
height={size}
viewBox="0 0 24 24"
className={`block shrink-0 text-foreground ${className}`.trim()}
aria-hidden="true"
>
C
</span>
<path
fill="currentColor"
d="M22.28 9.82a5.98 5.98 0 0 0-.52-4.91 6.05 6.05 0 0 0-6.51-2.9A6.07 6.07 0 0 0 4.98 4.18a5.98 5.98 0 0 0-4 2.9 6.05 6.05 0 0 0 .74 7.1 5.98 5.98 0 0 0 .51 4.91 6.05 6.05 0 0 0 6.51 2.9 5.98 5.98 0 0 0 4.51 2.02 6.06 6.06 0 0 0 5.77-4.21 5.98 5.98 0 0 0 4-2.9 6.06 6.06 0 0 0-.74-7.08zM13.26 21.2a4.48 4.48 0 0 1-2.88-.99l.14-6.32 5.02 2.9a.57.57 0 0 0 .28.08.55.55 0 0 0 .48-.28.56.56 0 0 0-.2-.77l-4.94-2.85.03-2.43 6.47 3.74c.07.04.16.06.24.06a.55.55 0 0 0 .27-1.03l-5.96-3.44 2.73-4.72a.56.56 0 0 0-.96-.56l-2.76 4.78-2.76-4.78a.56.56 0 0 0-.96.56l2.73 4.72-5.96 3.44a.55.55 0 0 0-.28 1.03c.08 0 .17-.02.24-.06l6.47-3.74.03 2.43-4.94 2.85a.56.56 0 0 0-.2.77.55.55 0 0 0 .76.2l5.02-2.9.14 6.32a4.48 4.48 0 0 1-2.88.99 4.49 4.49 0 0 1-4.27-3.08 4.5 4.5 0 0 1 2.06-5.18l2.6 1.5-2.15 3.72a.56.56 0 0 0 .2.77.55.55 0 0 0 .76-.2l2.18-3.78 2.18 3.78a.55.55 0 0 0 .76.2.56.56 0 0 0 .2-.77l-2.15-3.72 2.6-1.5a4.5 4.5 0 0 1 2.06 5.18 4.49 4.49 0 0 1-4.27 3.08z"
/>
</svg>
)
}
4 changes: 3 additions & 1 deletion frontend/src/components/ui/OptionTiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type Props<T extends string> = {
onChange: (value: T) => void
ariaLabel: string
columns?: 1 | 2 | 3
className?: string
}

const columnClass = {
Expand All @@ -29,6 +30,7 @@ export function OptionTiles<T extends string>({
onChange,
ariaLabel,
columns = 2,
className = '',
}: Props<T>) {
return (
<RadioGroup
Expand All @@ -37,7 +39,7 @@ export function OptionTiles<T extends string>({
onChange={(next) => {
if (typeof next === 'string' && next) onChange(next as T)
}}
className={`grid gap-2 ${columnClass[columns]}`}
className={`grid gap-2 ${columnClass[columns]} ${className}`.trim()}
>
{options.map((option) => (
<Radio
Expand Down

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions internal/webui/static/assets/index-2slrySyr.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

28 changes: 0 additions & 28 deletions internal/webui/static/assets/index-DOe_Z27O.js

This file was deleted.

4 changes: 2 additions & 2 deletions internal/webui/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet" />
<script type="module" crossorigin src="/assets/index-DOe_Z27O.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CgxCaPsN.css">
<script type="module" crossorigin src="/assets/index-2slrySyr.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BjsOfFoj.css">
</head>
<body>
<div id="root"></div>
Expand Down
Loading