Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license

This commit is contained in:
2026-09-05 13:26:46 +03:00
commit 03634b1ca3
11340 changed files with 3442369 additions and 0 deletions
@@ -0,0 +1,267 @@
import type { ComponentProps, ReactNode } from 'react'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Skeleton } from '@/components/ui/skeleton'
import { Switch } from '@/components/ui/switch'
import { triggerHaptic } from '@/lib/haptics'
import type { IconComponent } from '@/lib/icons'
import { cn } from '@/lib/utils'
import { PAGE_INSET_X } from '../layout-constants'
// `bare` drops the page gutters + tall bottom pad for embedding in a tighter
// surface (e.g. the boot-failure recovery card owns its own padding).
export function SettingsContent({ children, bare = false }: { children: ReactNode; bare?: boolean }) {
return (
<section className="min-h-0 overflow-hidden">
<div className={cn('h-full min-h-0 overflow-y-auto', bare ? 'px-5 pb-6' : cn('pb-20', PAGE_INSET_X))}>
{children}
</div>
</section>
)
}
const PILL_VARIANT = {
muted: 'muted',
primary: 'default',
success: 'success',
warn: 'warn',
destructive: 'destructive'
} as const
// Rest props spread through to the Badge's DOM node — REQUIRED for Radix
// `asChild` composition (wrapping a Pill in `Tip` clones it with the hover
// handlers and ref as props; swallowing them left every tooltip on a Pill
// silently dead).
export function Pill({
tone = 'muted',
children,
...props
}: { tone?: keyof typeof PILL_VARIANT; children: ReactNode } & Omit<ComponentProps<typeof Badge>, 'variant'>) {
return (
<Badge variant={PILL_VARIANT[tone]} {...props}>
{children}
</Badge>
)
}
export function SectionHeading({
aside,
icon: Icon,
meta,
title
}: {
// Right-aligned trailing content on the heading row (e.g. a compact status +
// action), so a single-item section needn't repeat its own label as a row.
aside?: ReactNode
icon: IconComponent
meta?: string
title: string
}) {
return (
<div className="mb-2.5 flex items-center gap-2 pt-2 text-[length:var(--conversation-text-font-size)] font-medium">
<Icon className="size-4 shrink-0 text-muted-foreground" />
<span>{title}</span>
{meta && <Pill>{meta}</Pill>}
{aside && <div className="ml-auto flex min-w-0 items-center">{aside}</div>}
</div>
)
}
// A titled section: heading + body with the shared vertical rhythm. Keeps the
// heading and its content welded together so pages stop hand-rolling
// `<div className="mb-…"><SectionHeading/>…</div>` at every call site.
export function SettingsSection({
aside,
children,
icon,
meta,
title
}: {
aside?: ReactNode
children: ReactNode
icon: IconComponent
meta?: string
title: string
}) {
return (
<section className="mb-6">
<SectionHeading aside={aside} icon={icon} meta={meta} title={title} />
{children}
</section>
)
}
export function NavLink({
icon: Icon,
label,
active,
onClick
}: {
icon: IconComponent
label: string
active: boolean
onClick: () => void
}) {
return (
<Button
className={cn(
'flex min-h-7 w-full justify-start gap-2 rounded-md px-2 text-left text-[length:var(--conversation-text-font-size)] transition',
active
? 'bg-(--ui-bg-tertiary) text-foreground'
: 'text-(--ui-text-secondary) hover:bg-(--chrome-action-hover) hover:text-foreground'
)}
onClick={onClick}
size="sm"
type="button"
variant="ghost"
>
<Icon className="size-4 shrink-0" />
<span className="min-w-0 flex-1 truncate">{label}</span>
</Button>
)
}
export function ListRow({
title,
description,
hint,
action,
below,
'data-tour': dataTour,
id,
wide = false,
className
}: {
title: ReactNode
description?: ReactNode
hint?: ReactNode
action?: ReactNode
below?: ReactNode
/** Durable handle for tours (see lib/tour) — usually the field's schema key. */
'data-tour'?: string
id?: string
wide?: boolean
className?: string
}) {
return (
// Container-queried, not viewport-queried: the label/control split keys on
// the row's own pane width, so a narrow detail column (messaging, split
// views) stacks instead of squishing the label against minmax(15rem,…).
<div className={cn('@container', className)} data-tour={dataTour} id={id}>
<div
className={cn(
'grid gap-3 py-3',
!wide && '@2xl:grid-cols-[minmax(0,1fr)_minmax(15rem,22rem)] @2xl:items-center'
)}
>
<div className="min-w-0">
<div className="text-[length:var(--conversation-text-font-size)] font-medium text-foreground">{title}</div>
{description && (
<div className="mt-1 text-[length:var(--conversation-caption-font-size)] leading-(--conversation-caption-line-height) text-(--ui-text-tertiary)">
{description}
</div>
)}
{hint && <div className="mt-1 block font-mono text-[0.68rem] text-muted-foreground/45">{hint}</div>}
{below}
</div>
{action && <div className={cn('min-w-0', !wide && '@2xl:justify-self-end')}>{action}</div>}
</div>
</div>
)
}
// A labelled on/off row — the canonical device-pref switch (haptic baked in).
export function ToggleRow({
checked,
description,
disabled,
label,
onChange
}: {
checked: boolean
description?: string
disabled?: boolean
label: string
onChange: (on: boolean) => void
}) {
return (
<ListRow
action={
<Switch
aria-label={label}
checked={checked}
disabled={disabled}
onCheckedChange={on => {
triggerHaptic('selection')
onChange(on)
}}
/>
}
description={description}
title={label}
/>
)
}
// Skeleton primitives mirroring the settings layout rhythm — a loading page keeps
// its shape (like ModelSettings) instead of collapsing to a centered spinner.
export function SectionHeadingSkeleton() {
return (
<div className="mb-2.5 flex items-center gap-2 pt-2">
<Skeleton className="size-4" />
<Skeleton className="h-4 w-36 max-w-full" />
</div>
)
}
export function ListRowSkeleton({ wide = false }: { wide?: boolean }) {
return (
<div className="@container">
<div
className={cn(
'grid gap-3 py-3',
!wide && '@2xl:grid-cols-[minmax(0,1fr)_minmax(15rem,22rem)] @2xl:items-center'
)}
>
<div className="min-w-0 space-y-1.5">
<Skeleton className="h-3.5 w-40 max-w-full" />
<Skeleton className="h-3 w-64 max-w-full" />
</div>
{!wide && <Skeleton className="h-8 w-full @2xl:w-72 @2xl:justify-self-end" />}
</div>
</div>
)
}
// A full settings page in its loading shape: an optional leading search field
// over one or more sections, each an optional heading above a run of rows.
// `<SettingsSkeleton search sections={[{ heading, rows }]} />`.
export function SettingsSkeleton({
search = false,
sections = [{ rows: 4 }]
}: {
search?: boolean
sections?: { heading?: boolean; rows: number }[]
}) {
return (
<SettingsContent>
{search && <Skeleton className="mb-3 h-8 w-full" />}
{sections.map((section, i) => (
<section className={cn(i > 0 && 'mt-6')} key={i}>
{section.heading && <SectionHeadingSkeleton />}
<div className="grid gap-1">
{Array.from({ length: section.rows }, (_, r) => (
<ListRowSkeleton key={r} />
))}
</div>
</section>
))}
</SettingsContent>
)
}
// Canonical implementation lives in components/ui; re-exported so the many
// settings call sites keep their import path.
export { EmptyState } from '@/components/ui/empty-state'