style(studio): elevate CloudFileBrowser to SaaS Premium

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
senke 2026-02-07 15:20:44 +01:00
parent 8cf22aa90c
commit cdc9890257
6 changed files with 72 additions and 72 deletions

View file

@ -19,22 +19,22 @@ export function CloudFileBrowserSkeleton({
return (
<div className={cn('space-y-8 h-full flex flex-col', className)}>
{/* Toolbar skeleton */}
<div className="flex flex-col xl:flex-row gap-4 justify-between items-start xl:items-center bg-kodo-ink/50 p-4 rounded-xl border border-kodo-steel/50 animate-pulse">
<div className="flex flex-col xl:flex-row gap-4 justify-between items-start xl:items-center bg-card/50 p-4 rounded-xl border border-border animate-pulse">
<div className="flex flex-col sm:flex-row gap-4 w-full xl:w-auto">
<div className="h-10 w-full sm:w-64 rounded-lg bg-kodo-steel/50" />
<div className="h-10 w-full sm:w-64 rounded-lg bg-muted" />
<div className="flex items-center gap-2">
<div className="h-4 w-4 rounded bg-kodo-steel/50 shrink-0" />
<div className="h-4 w-4 rounded bg-muted shrink-0" />
<div className="flex gap-2">
{[1, 2, 3, 4, 5].map((i) => (
<div key={i} className="h-6 w-16 rounded bg-kodo-steel/50" />
<div key={i} className="h-6 w-16 rounded bg-muted" />
))}
</div>
</div>
</div>
<div className="flex gap-2 w-full xl:w-auto justify-end">
<div className="h-10 w-24 rounded-lg bg-kodo-steel/50" />
<div className="h-10 w-32 rounded-lg bg-kodo-steel/50" />
<div className="h-10 w-20 rounded-lg bg-kodo-steel/50" />
<div className="h-10 w-24 rounded-lg bg-muted" />
<div className="h-10 w-32 rounded-lg bg-muted" />
<div className="h-10 w-20 rounded-lg bg-muted" />
</div>
</div>
@ -42,24 +42,24 @@ export function CloudFileBrowserSkeleton({
<div className="flex-1 overflow-hidden min-h-layout-page-sm">
{viewMode === 'list' ? (
<div className="bg-kodo-graphite border border-kodo-steel rounded-xl overflow-hidden">
<div className="border-b border-kodo-steel/30 p-4 flex gap-4">
<div className="h-4 w-10 rounded bg-kodo-steel/50" />
<div className="h-4 flex-1 rounded bg-kodo-steel/50" />
<div className="h-4 w-16 rounded bg-kodo-steel/50" />
<div className="h-4 w-12 rounded bg-kodo-steel/50" />
<div className="h-4 w-20 rounded bg-kodo-steel/50" />
<div className="border-b border-border p-4 flex gap-4">
<div className="h-4 w-10 rounded bg-muted" />
<div className="h-4 flex-1 rounded bg-muted" />
<div className="h-4 w-16 rounded bg-muted" />
<div className="h-4 w-12 rounded bg-muted" />
<div className="h-4 w-20 rounded bg-muted" />
</div>
<div className="divide-y divide-kodo-steel/30">
{Array.from({ length: ROW_COUNT }).map((_, i) => (
<div key={i} className="p-4 flex gap-4 items-center">
<div className="h-4 w-4 rounded bg-kodo-steel/50 shrink-0" />
<div className="h-4 w-4 rounded bg-muted shrink-0" />
<div className="flex items-center gap-4 flex-1 min-w-0">
<div className="h-5 w-5 rounded bg-kodo-steel/50 shrink-0" />
<div className="h-4 w-40 rounded bg-kodo-steel/50" />
<div className="h-5 w-5 rounded bg-muted shrink-0" />
<div className="h-4 w-40 rounded bg-muted" />
</div>
<div className="h-4 w-24 rounded bg-kodo-steel/50" />
<div className="h-4 w-12 rounded bg-kodo-steel/50" />
<div className="h-4 w-20 rounded bg-kodo-steel/50" />
<div className="h-4 w-24 rounded bg-muted" />
<div className="h-4 w-12 rounded bg-muted" />
<div className="h-4 w-20 rounded bg-muted" />
</div>
))}
</div>
@ -69,14 +69,14 @@ export function CloudFileBrowserSkeleton({
{Array.from({ length: 8 }).map((_, i) => (
<div
key={i}
className="p-4 flex flex-col items-center gap-4 rounded-xl border border-kodo-steel bg-kodo-graphite animate-pulse"
className="p-4 flex flex-col items-center gap-4 rounded-xl border border-border bg-card animate-pulse"
>
<div className="w-16 h-16 rounded-2xl bg-kodo-steel/50" />
<div className="w-16 h-16 rounded-2xl bg-muted" />
<div className="w-full space-y-2">
<div className="h-4 w-full rounded bg-kodo-steel/50" />
<div className="h-4 w-full rounded bg-muted" />
<div className="flex justify-center gap-1">
<div className="h-3 w-12 rounded bg-kodo-steel/50" />
<div className="h-3 w-10 rounded bg-kodo-steel/50" />
<div className="h-3 w-12 rounded bg-muted" />
<div className="h-3 w-10 rounded bg-muted" />
</div>
</div>
</div>

View file

@ -48,7 +48,7 @@ export function FileGrid({
return (
<div
className={cn(
'min-h-layout-page-sm flex items-center justify-center text-kodo-content-dim text-sm',
'min-h-layout-page-sm flex items-center justify-center text-muted-foreground text-sm',
className
)}
>

View file

@ -15,9 +15,9 @@ export interface FileGridCardProps {
function FileTypeIcon({ type, size = 'md' }: { type: CloudFileNode['type']; size?: 'md' | 'lg' }) {
const cl = size === 'lg' ? 'w-8 h-8' : 'w-5 h-5';
if (type === 'folder') return <Folder className={cn(cl, 'text-kodo-gold')} />;
if (type === 'folder') return <Folder className={cn(cl, 'text-warning')} />;
if (type === 'audio') return <Music className={cn(cl, 'text-kodo-steel')} />;
if (type === 'image') return <ImageIcon className={cn(cl, 'text-kodo-magenta')} />;
if (type === 'image') return <ImageIcon className={cn(cl, 'text-primary')} />;
if (['document', 'archive', 'project'].includes(type)) {
return <File className={cn(cl, 'text-kodo-content-dim')} />;
}
@ -41,12 +41,12 @@ export function FileGridCard({
className
)}
>
<div className="w-16 h-16 rounded-2xl bg-kodo-steel/50" />
<div className="w-16 h-16 rounded-2xl bg-muted" />
<div className="w-full space-y-2">
<div className="h-4 w-full rounded bg-kodo-steel/50" />
<div className="h-4 w-full rounded bg-muted" />
<div className="flex justify-center gap-1">
<div className="h-3 w-12 rounded bg-kodo-steel/50" />
<div className="h-3 w-10 rounded bg-kodo-steel/50" />
<div className="h-3 w-12 rounded bg-muted" />
<div className="h-3 w-10 rounded bg-muted" />
</div>
</div>
</Card>
@ -57,8 +57,8 @@ export function FileGridCard({
<Card
variant="default"
className={cn(
'p-4 flex flex-col items-center text-center gap-4 cursor-pointer hover:border-kodo-steel/50 transition-all group relative',
selected && 'border-kodo-cyan bg-kodo-cyan/5',
'p-4 flex flex-col items-center text-center gap-4 cursor-pointer hover:border-primary/50 transition-all duration-[var(--duration-normal)] group relative',
selected && 'border-primary bg-primary/5',
className
)}
onClick={() => onClick(file)}
@ -73,9 +73,9 @@ export function FileGridCard({
aria-label={selected ? 'Désélectionner' : 'Sélectionner'}
>
{selected ? (
<CheckSquare className="w-4 h-4 text-kodo-cyan" />
<CheckSquare className="w-4 h-4 text-primary" />
) : (
<Square className="w-4 h-4 text-kodo-content-dim hover:text-white" />
<Square className="w-4 h-4 text-muted-foreground hover:text-foreground" />
)}
</button>

View file

@ -34,7 +34,7 @@ export function FileTable({
return (
<div
className={cn(
'bg-kodo-graphite border border-kodo-steel rounded-xl overflow-hidden',
'bg-card border border-border rounded-xl overflow-hidden',
className
)}
>
@ -45,31 +45,31 @@ export function FileTable({
<button
type="button"
onClick={onSelectAll}
className="cursor-pointer hover:text-white"
className="cursor-pointer hover:text-foreground"
aria-label={allSelected ? 'Désélectionner tout' : 'Tout sélectionner'}
>
{allSelected ? (
<CheckSquare className="w-4 h-4 text-kodo-cyan" />
<CheckSquare className="w-4 h-4 text-primary" />
) : (
<Square className="w-4 h-4" />
)}
</button>
</th>
<th
className="p-4 cursor-pointer hover:text-white"
className="p-4 cursor-pointer hover:text-foreground"
onClick={() => onSort('name')}
>
Name
</th>
<th className="p-4">Tags</th>
<th
className="p-4 cursor-pointer hover:text-white"
className="p-4 cursor-pointer hover:text-foreground"
onClick={() => onSort('size')}
>
Size
</th>
<th
className="p-4 cursor-pointer hover:text-white"
className="p-4 cursor-pointer hover:text-foreground"
onClick={() => onSort('modified')}
>
Modified
@ -94,7 +94,7 @@ export function FileTable({
<tr>
<td
colSpan={6}
className="p-8 text-center text-kodo-content-dim text-sm"
className="p-8 text-center text-muted-foreground text-sm"
>
No files match your filters.
</td>

View file

@ -24,13 +24,13 @@ export interface FileTableRowProps {
}
function FileTypeIcon({ type }: { type: CloudFileNode['type'] }) {
if (type === 'folder') return <Folder className="w-5 h-5 text-kodo-gold" />;
if (type === 'audio') return <Music className="w-5 h-5 text-kodo-steel" />;
if (type === 'image') return <ImageIcon className="w-5 h-5 text-kodo-magenta" />;
if (type === 'folder') return <Folder className="w-5 h-5 text-warning" />;
if (type === 'audio') return <Music className="w-5 h-5 text-muted-foreground" />;
if (type === 'image') return <ImageIcon className="w-5 h-5 text-primary" />;
if (['document', 'archive', 'project'].includes(type)) {
return <File className="w-5 h-5 text-kodo-content-dim" />;
return <File className="w-5 h-5 text-muted-foreground" />;
}
return <File className="w-5 h-5 text-kodo-content-dim" />;
return <File className="w-5 h-5 text-muted-foreground" />;
}
export function FileTableRow({
@ -45,28 +45,28 @@ export function FileTableRow({
return (
<tr className="animate-pulse">
<td className="p-4 w-10">
<div className="h-4 w-4 rounded bg-kodo-steel/50" />
<div className="h-4 w-4 rounded bg-muted" />
</td>
<td className="p-4">
<div className="flex items-center gap-4">
<div className="h-5 w-5 rounded bg-kodo-steel/50 shrink-0" />
<div className="h-4 w-32 rounded bg-kodo-steel/50" />
<div className="h-5 w-5 rounded bg-muted shrink-0" />
<div className="h-4 w-32 rounded bg-muted" />
</div>
</td>
<td className="p-4">
<div className="flex gap-1">
<div className="h-4 w-12 rounded bg-kodo-steel/50" />
<div className="h-4 w-10 rounded bg-kodo-steel/50" />
<div className="h-4 w-12 rounded bg-muted" />
<div className="h-4 w-10 rounded bg-muted" />
</div>
</td>
<td className="p-4">
<div className="h-4 w-12 rounded bg-kodo-steel/50 font-mono text-xs" />
<div className="h-4 w-12 rounded bg-muted font-mono text-xs" />
</td>
<td className="p-4">
<div className="h-4 w-20 rounded bg-kodo-steel/50 text-xs" />
<div className="h-4 w-20 rounded bg-muted text-xs" />
</td>
<td className="p-4 text-right">
<div className="h-8 w-8 rounded bg-kodo-steel/50 ml-auto" />
<div className="h-8 w-8 rounded bg-muted ml-auto" />
</td>
</tr>
);
@ -76,18 +76,18 @@ export function FileTableRow({
<tr
className={cn(
'group hover:bg-white/5 transition-colors',
selected && 'bg-kodo-cyan/5'
selected && 'bg-primary/5'
)}
>
<td className="p-4">
<button
type="button"
onClick={() => onToggleSelect(file.id)}
className="cursor-pointer text-kodo-content-dim hover:text-white"
className="cursor-pointer text-muted-foreground hover:text-foreground"
aria-label={selected ? 'Désélectionner' : 'Sélectionner'}
>
{selected ? (
<CheckSquare className="w-4 h-4 text-kodo-cyan" />
<CheckSquare className="w-4 h-4 text-primary" />
) : (
<Square className="w-4 h-4" />
)}
@ -100,7 +100,7 @@ export function FileTableRow({
onClick={() => onFileClick(file)}
>
<FileTypeIcon type={file.type} />
<span className="font-medium text-kodo-text-main group-hover:text-white transition-colors">
<span className="font-medium text-foreground group-hover:text-foreground transition-colors">
{file.name}
</span>
</button>
@ -110,7 +110,7 @@ export function FileTableRow({
{file.tags?.map((t) => (
<span
key={t}
className="text-xs bg-kodo-slate px-1.5 py-0.5 rounded text-kodo-content-dim border border-kodo-steel"
className="text-xs bg-muted px-1.5 py-0.5 rounded text-muted-foreground border border-border"
>
{t}
</span>
@ -125,7 +125,7 @@ export function FileTableRow({
<Button
variant="ghost"
size="icon"
className="p-1.5 text-kodo-steel"
className="p-1.5 text-muted-foreground"
title="Process with AI"
onClick={() => onAction?.('ai', file)}
>

View file

@ -68,7 +68,7 @@ export function FileToolbar({
return (
<div
className={cn(
'flex flex-col xl:flex-row gap-4 justify-between items-start xl:items-center bg-kodo-ink/50 p-4 rounded-xl border border-kodo-steel/50 animate-pulse',
'flex flex-col xl:flex-row gap-4 justify-between items-start xl:items-center bg-card/50 p-4 rounded-xl border border-border animate-pulse',
className
)}
>
@ -95,7 +95,7 @@ export function FileToolbar({
return (
<div
className={cn(
'flex flex-col xl:flex-row gap-4 justify-between items-start xl:items-center bg-kodo-ink/50 p-4 rounded-xl border border-kodo-steel/50',
'flex flex-col xl:flex-row gap-4 justify-between items-start xl:items-center bg-card/50 p-4 rounded-xl border border-border',
className
)}
>
@ -108,7 +108,7 @@ export function FileToolbar({
/>
</div>
<div className="flex items-center gap-2 overflow-x-auto no-scrollbar pb-2 sm:pb-0">
<Filter className="w-4 h-4 text-kodo-content-dim shrink-0" />
<Filter className="w-4 h-4 text-muted-foreground shrink-0" />
{tagsToShow.map((tag) => (
<button
key={tag}
@ -152,7 +152,7 @@ export function FileToolbar({
variant="ghost"
size="icon"
onClick={onBulkDelete}
className="text-kodo-red hover:bg-kodo-red/10"
className="text-destructive hover:bg-destructive/10"
aria-label="Supprimer"
>
<Trash2 className="w-4 h-4" />
@ -182,7 +182,7 @@ export function FileToolbar({
Sort:
</span>
<select
className="bg-transparent text-xs text-white outline-none"
className="bg-transparent text-xs text-foreground outline-none"
value={sortField}
onChange={(e) => onSortFieldChange(e.target.value as SortField)}
aria-label="Sort by"
@ -195,7 +195,7 @@ export function FileToolbar({
<button
type="button"
onClick={onSortOrderToggle}
className="ml-2 p-1 hover:text-white text-kodo-content-dim"
className="ml-2 p-1 hover:text-foreground text-muted-foreground"
aria-label="Toggle sort order"
>
{sortOrder === 'asc' ? (
@ -206,13 +206,13 @@ export function FileToolbar({
</button>
</div>
<div className="bg-kodo-void p-1 rounded-lg border border-kodo-steel flex">
<div className="bg-muted p-1 rounded-xl border border-border flex">
<button
type="button"
onClick={() => onViewModeChange('list')}
className={cn(
'p-2 rounded',
viewMode === 'list' ? 'bg-kodo-slate text-white' : 'text-kodo-content-dim hover:text-white'
'p-2 rounded-lg transition-colors duration-[var(--duration-normal)]',
viewMode === 'list' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:text-foreground'
)}
aria-label="List view"
>
@ -222,8 +222,8 @@ export function FileToolbar({
type="button"
onClick={() => onViewModeChange('grid')}
className={cn(
'p-2 rounded',
viewMode === 'grid' ? 'bg-kodo-slate text-white' : 'text-kodo-content-dim hover:text-white'
'p-2 rounded-lg transition-colors duration-[var(--duration-normal)]',
viewMode === 'grid' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:text-foreground'
)}
aria-label="Grid view"
>