feat: update Makelore modules and conversations
This commit is contained in:
@@ -12,15 +12,15 @@ import { cn } from '@/lib/utils';
|
||||
|
||||
function statusClass(state: string): string {
|
||||
if (state === 'running') {
|
||||
return 'border-emerald-500/20 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300';
|
||||
return 'border-emerald-500/20 bg-emerald-500/10 text-emerald-700';
|
||||
}
|
||||
if (state === 'error') {
|
||||
return 'border-red-500/20 bg-red-500/10 text-red-700 dark:text-red-300';
|
||||
return 'border-red-500/20 bg-red-500/10 text-red-700';
|
||||
}
|
||||
if (state === 'starting') {
|
||||
return 'border-amber-500/20 bg-amber-500/10 text-amber-700 dark:text-amber-300';
|
||||
return 'border-amber-500/20 bg-amber-500/10 text-amber-700';
|
||||
}
|
||||
return 'border-black/10 bg-black/5 text-muted-foreground dark:border-white/10 dark:bg-white/5';
|
||||
return 'border-border bg-surface-subtle text-muted-foreground';
|
||||
}
|
||||
|
||||
export function OpencodeRuntimePanel() {
|
||||
@@ -58,7 +58,7 @@ export function OpencodeRuntimePanel() {
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<ServerCog className="h-5 w-5 text-foreground/70" aria-hidden="true" />
|
||||
<h2 className="text-3xl font-serif text-foreground font-normal tracking-tight">
|
||||
<h2 className="text-2xl font-semibold tracking-[-0.03em] text-foreground">
|
||||
{t('opencodeRuntime.title', 'Makelore runtime')}
|
||||
</h2>
|
||||
</div>
|
||||
@@ -71,7 +71,7 @@ export function OpencodeRuntimePanel() {
|
||||
aria-label={isStopped
|
||||
? t('opencodeRuntime.start', 'Start runtime')
|
||||
: t('opencodeRuntime.restart', 'Restart runtime')}
|
||||
className="h-10 rounded-xl border-black/10 bg-transparent px-4 hover:bg-black/5 dark:border-white/10 dark:hover:bg-white/5"
|
||||
className="h-10 rounded-xl border-border bg-transparent px-4 hover:bg-surface-subtle"
|
||||
>
|
||||
{isStopped ? (
|
||||
<Play className="mr-2 h-4 w-4" aria-hidden="true" />
|
||||
@@ -85,7 +85,7 @@ export function OpencodeRuntimePanel() {
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 sm:grid-cols-3">
|
||||
<div className="rounded-2xl border border-black/10 bg-transparent p-4 dark:border-white/10">
|
||||
<div className="surface-card rounded-2xl border border-border/70 bg-background p-4 shadow-none">
|
||||
<p className="text-xs font-semibold uppercase text-muted-foreground">
|
||||
{t('opencodeRuntime.status', 'Status')}
|
||||
</p>
|
||||
@@ -94,7 +94,7 @@ export function OpencodeRuntimePanel() {
|
||||
{status.state}
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-black/10 bg-transparent p-4 dark:border-white/10">
|
||||
<div className="surface-card rounded-2xl border border-border/70 bg-background p-4 shadow-none">
|
||||
<p className="text-xs font-semibold uppercase text-muted-foreground">
|
||||
{t('opencodeRuntime.port', 'Port')}
|
||||
</p>
|
||||
@@ -102,7 +102,7 @@ export function OpencodeRuntimePanel() {
|
||||
{status.port}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-black/10 bg-transparent p-4 dark:border-white/10">
|
||||
<div className="surface-card rounded-2xl border border-border/70 bg-background p-4 shadow-none">
|
||||
<p className="text-xs font-semibold uppercase text-muted-foreground">
|
||||
{t('opencodeRuntime.providers', 'Providers')}
|
||||
</p>
|
||||
@@ -112,7 +112,7 @@ export function OpencodeRuntimePanel() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl border border-black/10 bg-black/5 p-4 dark:border-white/10 dark:bg-white/5">
|
||||
<div className="surface-card rounded-2xl border border-border/70 bg-background p-4 shadow-none">
|
||||
<p className="text-xs font-semibold uppercase text-muted-foreground">
|
||||
{t('opencodeRuntime.defaultModel', 'Default model')}
|
||||
</p>
|
||||
@@ -122,7 +122,7 @@ export function OpencodeRuntimePanel() {
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<p className="rounded-xl border border-red-500/20 bg-red-500/10 px-4 py-3 text-sm font-medium text-red-700 dark:text-red-300">
|
||||
<p className="rounded-xl border border-red-500/20 bg-red-500/10 px-4 py-3 text-sm font-medium text-red-700">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -273,13 +273,13 @@ export function Models() {
|
||||
const usageRefreshing = runtimeRunning && fetchState.status === 'loading' && visibleUsageHistory.length > 0;
|
||||
|
||||
return (
|
||||
<div data-testid="models-page" className="flex flex-col -m-6 dark:bg-background h-[calc(100vh-2.5rem)] overflow-hidden">
|
||||
<div className="w-full max-w-5xl mx-auto flex flex-col h-full p-10 pt-16">
|
||||
<div data-testid="models-page" className="flex h-[calc(100vh-2.5rem)] flex-col -m-6 overflow-hidden bg-background">
|
||||
<div className="mx-auto flex h-full w-full max-w-5xl flex-col p-8 pt-10 lg:p-10 lg:pt-12">
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row md:items-start justify-between mb-12 shrink-0 gap-4">
|
||||
<div className="mb-10 flex shrink-0 flex-col justify-between gap-4 md:flex-row md:items-start">
|
||||
<div>
|
||||
<h1 data-testid="models-page-title" className="text-5xl md:text-6xl font-serif text-foreground mb-3 font-normal tracking-tight">
|
||||
<h1 data-testid="models-page-title" className="mb-3 text-4xl font-semibold leading-[1.02] tracking-[-0.05em] text-foreground md:text-5xl">
|
||||
{t('dashboard:models.title')}
|
||||
</h1>
|
||||
<p className="text-subtitle text-foreground/70 font-medium">
|
||||
@@ -289,7 +289,7 @@ export function Models() {
|
||||
</div>
|
||||
|
||||
{/* Content Area */}
|
||||
<div className="flex-1 overflow-y-auto pr-2 pb-10 min-h-0 -mr-2 space-y-12">
|
||||
<div className="-mr-2 min-h-0 flex-1 space-y-10 overflow-y-auto pb-10 pr-2">
|
||||
<OpencodeRuntimePanel />
|
||||
|
||||
{/* AI Providers Section */}
|
||||
@@ -297,27 +297,27 @@ export function Models() {
|
||||
|
||||
{/* Token Usage History Section */}
|
||||
<div>
|
||||
<h2 className="text-3xl font-serif text-foreground mb-6 font-normal tracking-tight">
|
||||
<h2 className="mb-5 text-2xl font-semibold tracking-[-0.03em] text-foreground">
|
||||
{t('dashboard:recentTokenHistory.title', 'Token Usage History')}
|
||||
</h2>
|
||||
<div>
|
||||
{usageLoading ? (
|
||||
<div className="flex items-center justify-center py-12 text-muted-foreground bg-black/5 dark:bg-white/5 rounded-3xl border border-transparent border-dashed">
|
||||
<div className="flex items-center justify-center rounded-2xl border border-dashed border-border bg-surface-subtle py-12 text-muted-foreground">
|
||||
<FeedbackState state="loading" title={t('dashboard:recentTokenHistory.loading')} />
|
||||
</div>
|
||||
) : visibleUsageHistory.length === 0 ? (
|
||||
<div className="flex items-center justify-center py-12 text-muted-foreground bg-black/5 dark:bg-white/5 rounded-3xl border border-transparent border-dashed">
|
||||
<div className="flex items-center justify-center rounded-2xl border border-dashed border-border bg-surface-subtle py-12 text-muted-foreground">
|
||||
<FeedbackState state="empty" title={t('dashboard:recentTokenHistory.empty')} />
|
||||
</div>
|
||||
) : filteredUsageHistory.length === 0 ? (
|
||||
<div className="flex items-center justify-center py-12 text-muted-foreground bg-black/5 dark:bg-white/5 rounded-3xl border border-transparent border-dashed">
|
||||
<div className="flex items-center justify-center rounded-2xl border border-dashed border-border bg-surface-subtle py-12 text-muted-foreground">
|
||||
<FeedbackState state="empty" title={t('dashboard:recentTokenHistory.emptyForWindow')} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<div className="flex rounded-xl bg-transparent p-1 border border-black/10 dark:border-white/10">
|
||||
<div className="flex rounded-xl border border-border/70 bg-surface-subtle p-1">
|
||||
<Button
|
||||
variant={usageGroupBy === 'model' ? 'secondary' : 'ghost'}
|
||||
size="sm"
|
||||
@@ -325,7 +325,7 @@ export function Models() {
|
||||
setUsageGroupBy('model');
|
||||
setUsagePage(1);
|
||||
}}
|
||||
className={usageGroupBy === 'model' ? "rounded-lg bg-black/5 dark:bg-white/10 text-foreground" : "rounded-lg text-muted-foreground"}
|
||||
className={usageGroupBy === 'model' ? "rounded-lg bg-background text-foreground shadow-soft" : "rounded-lg text-muted-foreground"}
|
||||
>
|
||||
{t('dashboard:recentTokenHistory.groupByModel')}
|
||||
</Button>
|
||||
@@ -336,12 +336,12 @@ export function Models() {
|
||||
setUsageGroupBy('day');
|
||||
setUsagePage(1);
|
||||
}}
|
||||
className={usageGroupBy === 'day' ? "rounded-lg bg-black/5 dark:bg-white/10 text-foreground" : "rounded-lg text-muted-foreground"}
|
||||
className={usageGroupBy === 'day' ? "rounded-lg bg-background text-foreground shadow-soft" : "rounded-lg text-muted-foreground"}
|
||||
>
|
||||
{t('dashboard:recentTokenHistory.groupByTime')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex rounded-xl bg-transparent p-1 border border-black/10 dark:border-white/10">
|
||||
<div className="flex rounded-xl border border-border/70 bg-surface-subtle p-1">
|
||||
<Button
|
||||
variant={usageWindow === '7d' ? 'secondary' : 'ghost'}
|
||||
size="sm"
|
||||
@@ -349,7 +349,7 @@ export function Models() {
|
||||
setUsageWindow('7d');
|
||||
setUsagePage(1);
|
||||
}}
|
||||
className={usageWindow === '7d' ? "rounded-lg bg-black/5 dark:bg-white/10 text-foreground" : "rounded-lg text-muted-foreground"}
|
||||
className={usageWindow === '7d' ? "rounded-lg bg-background text-foreground shadow-soft" : "rounded-lg text-muted-foreground"}
|
||||
>
|
||||
{t('dashboard:recentTokenHistory.last7Days')}
|
||||
</Button>
|
||||
@@ -360,7 +360,7 @@ export function Models() {
|
||||
setUsageWindow('30d');
|
||||
setUsagePage(1);
|
||||
}}
|
||||
className={usageWindow === '30d' ? "rounded-lg bg-black/5 dark:bg-white/10 text-foreground" : "rounded-lg text-muted-foreground"}
|
||||
className={usageWindow === '30d' ? "rounded-lg bg-background text-foreground shadow-soft" : "rounded-lg text-muted-foreground"}
|
||||
>
|
||||
{t('dashboard:recentTokenHistory.last30Days')}
|
||||
</Button>
|
||||
@@ -371,7 +371,7 @@ export function Models() {
|
||||
setUsageWindow('all');
|
||||
setUsagePage(1);
|
||||
}}
|
||||
className={usageWindow === 'all' ? "rounded-lg bg-black/5 dark:bg-white/10 text-foreground" : "rounded-lg text-muted-foreground"}
|
||||
className={usageWindow === 'all' ? "rounded-lg bg-background text-foreground shadow-soft" : "rounded-lg text-muted-foreground"}
|
||||
>
|
||||
{t('dashboard:recentTokenHistory.allTime')}
|
||||
</Button>
|
||||
@@ -398,7 +398,7 @@ export function Models() {
|
||||
<div
|
||||
key={`${entry.sessionId}-${entry.timestamp}`}
|
||||
data-testid="token-usage-entry"
|
||||
className="rounded-2xl bg-transparent border border-black/10 dark:border-white/10 p-5 hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
|
||||
className="surface-card motion-press rounded-2xl border border-border/70 bg-background p-5 shadow-none hover:bg-surface-subtle hover:shadow-soft"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
@@ -419,7 +419,7 @@ export function Models() {
|
||||
</p>
|
||||
)}
|
||||
{entry.usageStatus === 'error' && (
|
||||
<p className="text-xs text-red-500 dark:text-red-400 mt-0.5">
|
||||
<p className="text-xs text-red-500 text-red-700 mt-0.5">
|
||||
{t('dashboard:recentTokenHistory.usageParseError')}
|
||||
</p>
|
||||
)}
|
||||
@@ -431,7 +431,7 @@ export function Models() {
|
||||
<div className="mt-3 flex flex-wrap gap-x-4 gap-y-1.5 text-meta font-medium text-muted-foreground">
|
||||
{entry.usageStatus === 'available' || entry.usageStatus === undefined ? (
|
||||
<>
|
||||
<span className="flex items-center gap-1.5"><div className="w-2 h-2 rounded-full bg-sky-500"></div>{t('dashboard:recentTokenHistory.input', { value: formatTokenCount(entry.inputTokens) })}</span>
|
||||
<span className="flex items-center gap-1.5"><div className="w-2 h-2 rounded-full bg-accent"></div>{t('dashboard:recentTokenHistory.input', { value: formatTokenCount(entry.inputTokens) })}</span>
|
||||
<span className="flex items-center gap-1.5"><div className="w-2 h-2 rounded-full bg-violet-500"></div>{t('dashboard:recentTokenHistory.output', { value: formatTokenCount(entry.outputTokens) })}</span>
|
||||
{entry.cacheReadTokens > 0 && (
|
||||
<span className="flex items-center gap-1.5"><div className="w-2 h-2 rounded-full bg-amber-500"></div>{t('dashboard:recentTokenHistory.cacheRead', { value: formatTokenCount(entry.cacheReadTokens) })}</span>
|
||||
@@ -448,13 +448,13 @@ export function Models() {
|
||||
</span>
|
||||
)}
|
||||
{typeof entry.costUsd === 'number' && Number.isFinite(entry.costUsd) && (
|
||||
<span className="flex items-center gap-1.5 ml-auto text-foreground/80 bg-black/5 dark:bg-white/5 px-2 py-0.5 rounded-md">{t('dashboard:recentTokenHistory.cost', { amount: entry.costUsd.toFixed(4) })}</span>
|
||||
<span className="flex items-center gap-1.5 ml-auto text-foreground/80 bg-surface-subtle px-2 py-0.5 rounded-md">{t('dashboard:recentTokenHistory.cost', { amount: entry.costUsd.toFixed(4) })}</span>
|
||||
)}
|
||||
{devModeUnlocked && entry.content && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-6 rounded-full px-2.5 text-tiny border-black/10 dark:border-white/10"
|
||||
className="h-6 rounded-full px-2.5 text-tiny border-border/70"
|
||||
onClick={() => setSelectedUsageEntry(entry)}
|
||||
>
|
||||
{t('dashboard:recentTokenHistory.viewContent')}
|
||||
@@ -475,7 +475,7 @@ export function Models() {
|
||||
size="sm"
|
||||
onClick={() => setUsagePage((page) => Math.max(1, page - 1))}
|
||||
disabled={safeUsagePage <= 1}
|
||||
className="rounded-full px-4 h-9 border-black/10 dark:border-white/10 bg-transparent hover:bg-black/5 dark:hover:bg-white/5"
|
||||
className="rounded-full px-4 h-9 border-border/70 bg-transparent hover:bg-surface-subtle"
|
||||
>
|
||||
<ChevronLeft className="h-4 w-4 mr-1" />
|
||||
{t('dashboard:recentTokenHistory.prev')}
|
||||
@@ -485,7 +485,7 @@ export function Models() {
|
||||
size="sm"
|
||||
onClick={() => setUsagePage((page) => Math.min(usageTotalPages, page + 1))}
|
||||
disabled={safeUsagePage >= usageTotalPages}
|
||||
className="rounded-full px-4 h-9 border-black/10 dark:border-white/10 bg-transparent hover:bg-black/5 dark:hover:bg-white/5"
|
||||
className="rounded-full px-4 h-9 border-border/70 bg-transparent hover:bg-surface-subtle"
|
||||
>
|
||||
{t('dashboard:recentTokenHistory.next')}
|
||||
<ChevronRight className="h-4 w-4 ml-1" />
|
||||
@@ -519,7 +519,7 @@ function formatTokenCount(value: number): string {
|
||||
function getUsageTotalClass(entry: UsageHistoryEntry): string {
|
||||
if (entry.usageStatus === 'error') return '!';
|
||||
if (entry.usageStatus === 'missing') return '-';
|
||||
return 'font-bold text-sm';
|
||||
return 'font-medium text-sm';
|
||||
}
|
||||
|
||||
function formatUsageTotal(entry: UsageHistoryEntry): string {
|
||||
@@ -562,7 +562,7 @@ function UsageBarChart({
|
||||
}) {
|
||||
if (groups.length === 0) {
|
||||
return (
|
||||
<div className="rounded-2xl border border-dashed border-black/10 dark:border-white/10 p-8 text-center text-sm font-medium text-muted-foreground">
|
||||
<div className="rounded-2xl border border-dashed border-border/70 p-8 text-center text-sm font-medium text-muted-foreground">
|
||||
{emptyLabel}
|
||||
</div>
|
||||
);
|
||||
@@ -571,10 +571,10 @@ function UsageBarChart({
|
||||
const maxTokens = Math.max(...groups.map((group) => group.totalTokens), 1);
|
||||
|
||||
return (
|
||||
<div className="space-y-4 bg-transparent p-5 rounded-2xl border border-black/10 dark:border-white/10">
|
||||
<div className="space-y-4 bg-transparent p-5 rounded-2xl border border-border/70">
|
||||
<div className="flex flex-wrap gap-4 text-meta font-medium text-muted-foreground mb-2">
|
||||
<span className="inline-flex items-center gap-2">
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-sky-500" />
|
||||
<span className="h-2.5 w-2.5 rounded-full bg-accent" />
|
||||
{inputLabel}
|
||||
</span>
|
||||
<span className="inline-flex items-center gap-2">
|
||||
@@ -594,7 +594,7 @@ function UsageBarChart({
|
||||
{totalLabel}: {formatTokenCount(group.totalTokens)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-3.5 overflow-hidden rounded-full bg-black/5 dark:bg-white/5">
|
||||
<div className="h-3.5 overflow-hidden rounded-full bg-surface-subtle">
|
||||
<div
|
||||
className="flex h-full overflow-hidden rounded-full"
|
||||
style={{
|
||||
@@ -605,7 +605,7 @@ function UsageBarChart({
|
||||
>
|
||||
{group.inputTokens > 0 && (
|
||||
<div
|
||||
className="h-full bg-sky-500"
|
||||
className="h-full bg-accent"
|
||||
style={{ width: `${(group.inputTokens / group.totalTokens) * 100}%` }}
|
||||
/>
|
||||
)}
|
||||
@@ -645,9 +645,9 @@ function UsageContentPopup({
|
||||
unknownModelLabel: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4" role="dialog" aria-modal="true">
|
||||
<div className="w-full max-w-3xl rounded-2xl border border-black/10 dark:border-white/10 bg-background shadow-xl">
|
||||
<div className="flex items-start justify-between gap-3 border-b border-black/10 dark:border-white/10 px-5 py-4">
|
||||
<div className="glass-surface fixed inset-0 z-50 flex items-center justify-center bg-foreground/15 px-4" role="dialog" aria-modal="true">
|
||||
<div className="surface-card w-full max-w-3xl rounded-2xl border border-border/80 bg-background shadow-float">
|
||||
<div className="flex items-start justify-between gap-3 border-b border-border/70 px-5 py-4">
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-semibold text-foreground">{title}</p>
|
||||
<p className="text-xs text-muted-foreground truncate mt-0.5">
|
||||
@@ -669,7 +669,7 @@ function UsageContentPopup({
|
||||
{entry.content}
|
||||
</pre>
|
||||
</div>
|
||||
<div className="flex justify-end border-t border-black/10 dark:border-white/10 px-5 py-3">
|
||||
<div className="flex justify-end border-t border-border/70 px-5 py-3">
|
||||
<Button variant="outline" onClick={onClose}>
|
||||
{closeLabel}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user