refactor(tokens): complete design token migration to semantic system
Sprint 3.1 — Default colors → semantic (~15 files, ~99 replacements): - lime-500 → success, red-500 → destructive, cyan-500 → primary Sprint 3.2 — Hardcoded colors → semantic (~13 files, ~99 replacements): - text-white → text-foreground, bg-black → bg-background, bg-white → bg-card Sprint 3.3 — Legacy kodo-* → semantic (~27 files, ~122 replacements): - bg-kodo-ink → bg-card, bg-kodo-void → bg-background, text-kodo-steel → text-muted-foreground - Preserved kodo-cyan/magenta/lime/gold palette accents and gradients Sprint 3.4 — Arbitrary values → Tailwind scale (5 replacements): - min-h-[600px] → min-h-layout-page, min-h-[400px] → min-h-layout-page-sm - left-[50%] → left-1/2, min-h-[80px] → min-h-20, min-h-[40px] → min-h-10 Sprint 3.5 — Border-radius standardization (4 replacements): - Modal/dialog skeletons: rounded-lg → rounded-xl (convention) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
503e6f00b6
commit
bfdc785ccc
49 changed files with 208 additions and 206 deletions
|
|
@ -92,7 +92,7 @@ export function RateLimitIndicator() {
|
|||
className={cn(
|
||||
'flex items-center gap-2 px-4 py-1.5 rounded-lg text-xs font-medium transition-all',
|
||||
isCritical
|
||||
? 'bg-kodo-red/10 text-destructive border border-kodo-red/30'
|
||||
? 'bg-destructive/10 text-destructive border border-destructive/30'
|
||||
: 'bg-warning/10 text-warning border border-warning/30',
|
||||
)}
|
||||
role="alert"
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export function AdminDashboardHeader({
|
|||
</h2>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-lime-500 animate-pulse shadow-glow-lime" />
|
||||
<div className="w-2 h-2 rounded-full bg-success animate-pulse shadow-glow-lime" />
|
||||
<span className="text-muted-foreground text-xs font-mono tracking-widest uppercase">
|
||||
Nodes Online
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ import { cn } from '@/lib/utils';
|
|||
import type { StatCardProps } from './types';
|
||||
|
||||
const colorClasses: Record<StatCardProps['color'], string> = {
|
||||
cyan: 'bg-cyan-500',
|
||||
cyan: 'bg-primary',
|
||||
gold: 'bg-gold-500',
|
||||
lime: 'bg-lime-500',
|
||||
red: 'bg-red-500',
|
||||
lime: 'bg-success',
|
||||
red: 'bg-destructive',
|
||||
};
|
||||
|
||||
const textColorClasses: Record<StatCardProps['color'], string> = {
|
||||
cyan: 'text-cyan-500',
|
||||
cyan: 'text-primary',
|
||||
gold: 'text-gold-500',
|
||||
lime: 'text-lime-500',
|
||||
lime: 'text-success',
|
||||
red: 'text-destructive',
|
||||
};
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ export function AdminDashboardStatCard({
|
|||
<span
|
||||
className={cn(
|
||||
'text-xs font-mono font-bold px-2 py-0.5 rounded-full border tracking-tighter',
|
||||
trend > 0 && 'text-lime-500 border-lime-500/20 bg-lime-500/10',
|
||||
trend > 0 && 'text-success border-success/20 bg-success/10',
|
||||
trend < 0 && 'text-destructive border-destructive/20 bg-destructive/10',
|
||||
trend === 0 && 'text-muted-foreground border-border bg-muted/30',
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export function AdminDashboardTabs({
|
|||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="border-lime-500/20 text-lime-500 hover:bg-lime-500/10"
|
||||
className="border-success/20 text-success hover:bg-success/10"
|
||||
onClick={() => onReportAction(r.id, 'cleared')}
|
||||
>
|
||||
APPROVE
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export const TrackAnalyticsView: React.FC<TrackAnalyticsViewProps> = ({
|
|||
<ArrowLeft className="w-5 h-5" />
|
||||
</Button>
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white">{trackData.title}</h2>
|
||||
<h2 className="text-2xl font-bold text-foreground">{trackData.title}</h2>
|
||||
<p className="text-muted-foreground text-sm">Analytics Report</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -97,7 +97,7 @@ export const TrackAnalyticsView: React.FC<TrackAnalyticsViewProps> = ({
|
|||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* Plays Over Time Graph Placeholder */}
|
||||
<Card variant="default">
|
||||
<h3 className="font-bold text-white mb-6">
|
||||
<h3 className="font-bold text-foreground mb-6">
|
||||
Plays Over Time (30 Days)
|
||||
</h3>
|
||||
<div className="h-64 flex items-end gap-2 px-4 pb-4">
|
||||
|
|
@ -109,7 +109,7 @@ export const TrackAnalyticsView: React.FC<TrackAnalyticsViewProps> = ({
|
|||
className="flex-1 bg-muted/20 hover:bg-muted/50 transition-colors rounded-t relative group"
|
||||
style={{ height: `${h}%` }}
|
||||
>
|
||||
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 bg-black text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none">
|
||||
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 bg-background text-foreground text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none">
|
||||
{Math.floor(h * 10)} plays
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -121,7 +121,7 @@ export const TrackAnalyticsView: React.FC<TrackAnalyticsViewProps> = ({
|
|||
{/* Demographics & Geo */}
|
||||
<div className="space-y-6">
|
||||
<Card variant="default">
|
||||
<h3 className="font-bold text-white mb-4 flex items-center gap-2">
|
||||
<h3 className="font-bold text-foreground mb-4 flex items-center gap-2">
|
||||
<Map className="w-4 h-4 text-kodo-magenta" /> Top Locations
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
|
|
@ -134,7 +134,7 @@ export const TrackAnalyticsView: React.FC<TrackAnalyticsViewProps> = ({
|
|||
style={{ width: `${g.percent}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<div className="w-12 text-right text-sm font-bold text-white">
|
||||
<div className="w-12 text-right text-sm font-bold text-foreground">
|
||||
{g.percent}%
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -143,7 +143,7 @@ export const TrackAnalyticsView: React.FC<TrackAnalyticsViewProps> = ({
|
|||
</Card>
|
||||
|
||||
<Card variant="default">
|
||||
<h3 className="font-bold text-white mb-4 flex items-center gap-2">
|
||||
<h3 className="font-bold text-foreground mb-4 flex items-center gap-2">
|
||||
<Users className="w-4 h-4 text-warning" /> Listeners Age
|
||||
</h3>
|
||||
<div className="flex gap-2 h-8">
|
||||
|
|
@ -161,7 +161,7 @@ export const TrackAnalyticsView: React.FC<TrackAnalyticsViewProps> = ({
|
|||
: '#1F2833',
|
||||
}}
|
||||
>
|
||||
<div className="absolute inset-0 flex items-center justify-center text-xs font-bold text-black opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<div className="absolute inset-0 flex items-center justify-center text-xs font-bold text-foreground opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
{range}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export const OrderSummary: React.FC<OrderSummaryProps> = ({
|
|||
</div>
|
||||
|
||||
{discount && (
|
||||
<div className="flex justify-between text-lime-500 font-mono uppercase text-xs bg-lime-500/5 p-2 rounded border border-lime-500/20">
|
||||
<div className="flex justify-between text-success font-mono uppercase text-xs bg-success/5 p-2 rounded border border-success/20">
|
||||
<span className="flex items-center gap-2">
|
||||
<Tag className="w-3 h-3" /> Protocol: {discount.code}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function Timeline({
|
|||
>
|
||||
{/* Ligne horizontale */}
|
||||
{index < items.length - 1 && (
|
||||
<div className="absolute left-[50%] top-6 h-0.5 w-full translate-x-1/2 bg-border" />
|
||||
<div className="absolute left-1/2 top-6 h-0.5 w-full translate-x-1/2 bg-border" />
|
||||
)}
|
||||
|
||||
{/* Icône */}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ export const DeveloperDashboardView: React.FC = () => {
|
|||
if (loading)
|
||||
return (
|
||||
<div className="flex justify-center py-24">
|
||||
<Loader2 className="w-10 h-10 text-kodo-steel animate-spin" />
|
||||
<Loader2 className="w-10 h-10 text-muted-foreground animate-spin" />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ export const DeveloperDashboardView: React.FC = () => {
|
|||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-end gap-4 border-b border-border/50 pb-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-display font-bold text-white mb-2">
|
||||
<h1 className="text-3xl font-display font-bold text-foreground mb-2">
|
||||
DEVELOPER PORTAL
|
||||
</h1>
|
||||
<p className="text-muted-foreground font-mono text-sm">
|
||||
|
|
@ -162,7 +162,7 @@ export const DeveloperDashboardView: React.FC = () => {
|
|||
|
||||
{/* API Keys List */}
|
||||
<Card variant="default">
|
||||
<h3 className="font-bold text-white mb-6">Active API Keys</h3>
|
||||
<h3 className="font-bold text-foreground mb-6">Active API Keys</h3>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left">
|
||||
<thead>
|
||||
|
|
@ -178,19 +178,19 @@ export const DeveloperDashboardView: React.FC = () => {
|
|||
{keys.map((key) => (
|
||||
<tr
|
||||
key={key.id}
|
||||
className="border-b border-border/20 hover:bg-white/5 transition-colors"
|
||||
className="border-b border-border/20 hover:bg-foreground/5 transition-colors"
|
||||
>
|
||||
<td className="py-4 pl-4 font-bold text-white">{key.name}</td>
|
||||
<td className="py-4 pl-4 font-bold text-foreground">{key.name}</td>
|
||||
<td className="py-4 font-mono text-warning">
|
||||
{key.prefix}
|
||||
</td>
|
||||
<td className="py-4 text-muted-foreground">{key.created}</td>
|
||||
<td className="py-4 text-kodo-text-main">{key.lastUsed}</td>
|
||||
<td className="py-4 text-foreground">{key.lastUsed}</td>
|
||||
<td className="py-4 text-right pr-4 flex justify-end gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 text-muted-foreground hover:text-white"
|
||||
className="h-8 w-8 text-muted-foreground hover:text-foreground"
|
||||
onClick={() => addToast('Full key hidden for security')}
|
||||
title="View Key"
|
||||
>
|
||||
|
|
@ -200,7 +200,7 @@ export const DeveloperDashboardView: React.FC = () => {
|
|||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 text-destructive hover:bg-kodo-red/10"
|
||||
className="h-8 w-8 text-destructive hover:bg-destructive/10"
|
||||
onClick={() => handleRevoke(key.id)}
|
||||
title="Revoke Key"
|
||||
>
|
||||
|
|
@ -210,7 +210,7 @@ export const DeveloperDashboardView: React.FC = () => {
|
|||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-8 w-8 text-muted-foreground hover:text-white hover:bg-white/10"
|
||||
className="h-8 w-8 text-muted-foreground hover:text-foreground hover:bg-foreground/10"
|
||||
onClick={() => handleDelete(key.id)}
|
||||
title="Delete Permanently"
|
||||
>
|
||||
|
|
@ -234,7 +234,7 @@ export const DeveloperDashboardView: React.FC = () => {
|
|||
</TabsContent>
|
||||
|
||||
<TabsContent value="docs">
|
||||
<Card variant="default" className="p-0 overflow-hidden bg-black/80">
|
||||
<Card variant="default" className="p-0 overflow-hidden bg-background/80">
|
||||
{/* Use iframe mode for better compatibility if JSON fetching has issues CORS/Auth */}
|
||||
<SwaggerUIDoc useIframe={false} />
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ export function SwaggerUIDoc({ specUrl, spec, useIframe = false }: SwaggerUIProp
|
|||
if (error) {
|
||||
const swaggerUiUrl = getSwaggerUIUrl();
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center p-12 min-h-[600px]">
|
||||
<div className="flex flex-col items-center justify-center p-12 min-h-layout-page">
|
||||
<AlertCircle className="w-16 h-16 text-destructive mb-4" />
|
||||
<h3 className="text-xl font-bold text-white mb-2">
|
||||
Failed to Load API Documentation
|
||||
|
|
|
|||
|
|
@ -101,12 +101,12 @@ export const WebhooksView: React.FC = () => {
|
|||
webhooks.map((hook) => (
|
||||
<Card key={hook.id} variant="glass" className="group overflow-hidden relative border-white/5 hover:border-white/10 transition-all bg-black/40">
|
||||
{/* Status Indicator Bar */}
|
||||
<div className={cn("absolute left-0 top-0 bottom-0 w-1", hook.status === 'active' ? 'bg-lime-500 shadow-status-dot-lime' : 'bg-red-500')} />
|
||||
<div className={cn("absolute left-0 top-0 bottom-0 w-1", hook.status === 'active' ? 'bg-success shadow-status-dot-lime' : 'bg-destructive')} />
|
||||
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between p-6 pl-8 gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<div className={cn("text-xs font-bold px-2 py-0.5 rounded border uppercase tracking-wider", hook.status === 'active' ? 'border-lime-500/30 text-lime-500 bg-lime-500/10' : 'border-destructive/30 text-destructive bg-destructive/10')}>
|
||||
<div className={cn("text-xs font-bold px-2 py-0.5 rounded border uppercase tracking-wider", hook.status === 'active' ? 'border-success/30 text-success bg-success/10' : 'border-destructive/30 text-destructive bg-destructive/10')}>
|
||||
{hook.status}
|
||||
</div>
|
||||
<span className="font-mono text-white text-sm break-all">{hook.url}</span>
|
||||
|
|
|
|||
|
|
@ -93,20 +93,20 @@ export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||
return createPortal(
|
||||
<div className="fixed inset-0 z-[9999] flex items-center justify-center p-4" style={{ zIndex: 9999 }}>
|
||||
<div
|
||||
className="absolute inset-0 bg-kodo-void/90 backdrop-blur-md"
|
||||
className="absolute inset-0 bg-background/90 backdrop-blur-md"
|
||||
onClick={step === 1 ? onClose : undefined}
|
||||
></div>
|
||||
<div className="relative w-full max-w-2xl bg-kodo-graphite border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden glass-hud flex flex-col max-h-layout-modal">
|
||||
<div className="relative w-full max-w-2xl bg-card border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden glass-hud flex flex-col max-h-layout-modal">
|
||||
{/* Header - Fixed */}
|
||||
<div className="p-6 border-b border-border/50 flex justify-between items-center bg-white/5 flex-none z-10">
|
||||
<h3 className="text-xl font-bold text-white flex items-center gap-3 font-display">
|
||||
<div className="p-6 border-b border-border/50 flex justify-between items-center bg-foreground/5 flex-none z-10">
|
||||
<h3 className="text-xl font-bold text-foreground flex items-center gap-3 font-display">
|
||||
<div className="w-8 h-8 rounded-lg bg-warning/20 flex items-center justify-center border border-warning/30">
|
||||
<Key className="w-5 h-5 text-warning" />
|
||||
</div>
|
||||
{step === 1 ? 'Create API Key' : 'API Key Generated'}
|
||||
</h3>
|
||||
<button onClick={onClose} className="p-2 hover:bg-white/10 rounded-lg transition-colors">
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-white" />
|
||||
<button onClick={onClose} className="p-2 hover:bg-foreground/10 rounded-lg transition-colors">
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||
onChange={(e) => setName(e.target.value)}
|
||||
autoFocus
|
||||
disabled={isGenerating}
|
||||
className="bg-kodo-void/50 border-border focus:border-primary h-12 text-lg w-full"
|
||||
className="bg-background/50 border-border focus:border-primary h-12 text-lg w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||
"flex items-center justify-between p-4 rounded-xl border cursor-pointer transition-all duration-[var(--duration-fast)] group relative overflow-hidden",
|
||||
selectedScopes.includes(scope.id)
|
||||
? "bg-primary/10 border-primary/50 shadow-card-glow-cyan"
|
||||
: "bg-kodo-void/30 border-border/50 hover:border-border hover:bg-white/5"
|
||||
: "bg-background/30 border-border/50 hover:border-border hover:bg-foreground/5"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-4 z-10 relative">
|
||||
|
|
@ -154,12 +154,12 @@ export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||
</div>
|
||||
<span className={cn(
|
||||
"text-sm font-medium transition-colors",
|
||||
selectedScopes.includes(scope.id) ? "text-white" : "text-muted-foreground group-hover:text-kodo-text-main"
|
||||
selectedScopes.includes(scope.id) ? "text-foreground" : "text-muted-foreground group-hover:text-foreground"
|
||||
)}>
|
||||
{scope.label}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-xs font-mono text-kodo-steel z-10 hidden sm:block opacity-60 relative">
|
||||
<div className="text-xs font-mono text-muted-foreground z-10 hidden sm:block opacity-60 relative">
|
||||
{scope.id}
|
||||
</div>
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h4 className="text-2xl font-bold text-white font-display">
|
||||
<h4 className="text-2xl font-bold text-foreground font-display">
|
||||
Key Created Successfully
|
||||
</h4>
|
||||
<p className="text-sm text-muted-foreground max-w-xs mx-auto leading-relaxed">
|
||||
|
|
@ -193,7 +193,7 @@ export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-black/40 border border-border/50 rounded-xl p-1 flex items-center gap-2 relative group overflow-hidden">
|
||||
<div className="bg-background/40 border border-border/50 rounded-xl p-1 flex items-center gap-2 relative group overflow-hidden">
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/5 to-transparent skew-x-12 translate-x-[-200%] group-hover:animate-shimmer"></div>
|
||||
<div className="flex-1 px-4 py-3 font-mono text-sm text-warning overflow-x-auto no-scrollbar whitespace-nowrap text-left">
|
||||
{generatedKey}
|
||||
|
|
@ -202,7 +202,7 @@ export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={copyKey}
|
||||
className="h-10 w-10 text-muted-foreground hover:text-white hover:bg-white/10 rounded-lg hover:scale-105 transition-all flex-none"
|
||||
className="h-10 w-10 text-muted-foreground hover:text-foreground hover:bg-foreground/10 rounded-lg hover:scale-105 transition-all flex-none"
|
||||
title="Copy to clipboard"
|
||||
>
|
||||
<Copy className="w-5 h-5" />
|
||||
|
|
@ -213,14 +213,14 @@ export const CreateAPIKeyModal: React.FC<CreateAPIKeyModalProps> = ({
|
|||
</div>
|
||||
|
||||
{/* Footer - Fixed */}
|
||||
<div className="p-6 border-t border-border/50 bg-white/5 flex justify-end gap-3 backdrop-blur-sm flex-none z-10 transition-colors">
|
||||
<div className="p-6 border-t border-border/50 bg-foreground/5 flex justify-end gap-3 backdrop-blur-sm flex-none z-10 transition-colors">
|
||||
{step === 1 ? (
|
||||
<>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={onClose}
|
||||
disabled={isGenerating}
|
||||
className="hover:bg-white/10 text-muted-foreground hover:text-white"
|
||||
className="hover:bg-foreground/10 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -29,25 +29,25 @@ export const CertificateModal: React.FC<CertificateModalProps> = ({
|
|||
return (
|
||||
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
||||
<div
|
||||
className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm"
|
||||
className="absolute inset-0 bg-background/90 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
></div>
|
||||
<div className="relative w-full max-w-3xl bg-kodo-graphite border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden flex flex-col">
|
||||
<div className="p-4 border-b border-border bg-kodo-ink flex justify-between items-center">
|
||||
<h3 className="font-bold text-white flex items-center gap-2">
|
||||
<div className="relative w-full max-w-3xl bg-card border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden flex flex-col">
|
||||
<div className="p-4 border-b border-border bg-card flex justify-between items-center">
|
||||
<h3 className="font-bold text-foreground flex items-center gap-2">
|
||||
<Award className="w-5 h-5 text-warning" /> Completion Certificate
|
||||
</h3>
|
||||
<button onClick={onClose}>
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-white" />
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="p-8 bg-kodo-ink flex justify-center">
|
||||
<div className="p-8 bg-card flex justify-center">
|
||||
{/* Certificate Preview */}
|
||||
<div className="w-full aspect-[1.414] bg-white text-black p-8 relative shadow-2xl max-w-2xl border-8 border-double border-border">
|
||||
<div className="w-full aspect-[1.414] bg-card text-foreground p-8 relative shadow-2xl max-w-2xl border-8 border-double border-border">
|
||||
<div className="h-full border-4 border-warning/20 flex flex-col items-center justify-center text-center p-8 bg-[url('https://www.transparenttextures.com/patterns/cream-paper.png')]">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-4xl font-display font-bold text-kodo-text-main mb-2 uppercase tracking-widest">
|
||||
<h1 className="text-4xl font-display font-bold text-foreground mb-2 uppercase tracking-widest">
|
||||
Certificate
|
||||
</h1>
|
||||
<p className="text-sm font-serif italic text-muted-foreground">
|
||||
|
|
@ -58,26 +58,26 @@ export const CertificateModal: React.FC<CertificateModalProps> = ({
|
|||
<p className="text-sm text-muted-foreground mb-2">
|
||||
This is to certify that
|
||||
</p>
|
||||
<h2 className="text-3xl font-script font-bold text-kodo-steel mb-6 border-b-2 border-border pb-2 px-8">
|
||||
<h2 className="text-3xl font-script font-bold text-muted-foreground mb-6 border-b-2 border-border pb-2 px-8">
|
||||
{studentName}
|
||||
</h2>
|
||||
|
||||
<p className="text-sm text-muted-foreground mb-2">
|
||||
has successfully completed the course
|
||||
</p>
|
||||
<h3 className="text-xl font-bold text-kodo-text-main mb-8 max-w-md leading-tight">
|
||||
<h3 className="text-xl font-bold text-foreground mb-8 max-w-md leading-tight">
|
||||
{courseName}
|
||||
</h3>
|
||||
|
||||
<div className="flex justify-between w-full mt-auto pt-8 border-t border-border">
|
||||
<div className="text-left">
|
||||
<p className="text-xs font-bold text-kodo-text-main">
|
||||
<p className="text-xs font-bold text-foreground">
|
||||
{completionDate}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground uppercase">Date</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="h-8 w-24 bg-kodo-slate mb-1 opacity-50"></div>{' '}
|
||||
<div className="h-8 w-24 bg-muted mb-1 opacity-50"></div>{' '}
|
||||
{/* Signature line */}
|
||||
<p className="text-xs text-muted-foreground uppercase">
|
||||
Veza Academy
|
||||
|
|
@ -92,7 +92,7 @@ export const CertificateModal: React.FC<CertificateModalProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border-t border-border bg-kodo-ink flex justify-end gap-4">
|
||||
<div className="p-4 border-t border-border bg-card flex justify-end gap-4">
|
||||
<Button variant="ghost" onClick={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export const AchievementCard: React.FC<AchievementCardProps> = ({
|
|||
</p>
|
||||
|
||||
{/* Progress */}
|
||||
<div className="w-full bg-kodo-graphite h-1.5 rounded-full overflow-hidden">
|
||||
<div className="w-full bg-card h-1.5 rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full transition-all duration-[var(--duration-slow)] ${isUnlocked ? 'bg-warning' : 'bg-muted'}`}
|
||||
style={{ width: `${percentage}%` }}
|
||||
|
|
@ -64,7 +64,7 @@ export const AchievementCard: React.FC<AchievementCardProps> = ({
|
|||
<span className={isUnlocked ? 'text-warning' : 'text-muted-foreground'}>
|
||||
{achievement.progress} / {achievement.maxProgress}
|
||||
</span>
|
||||
<span className="text-kodo-steel">+{achievement.xpReward} XP</span>
|
||||
<span className="text-muted-foreground">+{achievement.xpReward} XP</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export const AchievementsView: React.FC = () => {
|
|||
if (loading)
|
||||
return (
|
||||
<div className="flex justify-center py-24">
|
||||
<Loader2 className="w-10 h-10 text-kodo-steel animate-spin" />
|
||||
<Loader2 className="w-10 h-10 text-muted-foreground animate-spin" />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
@ -55,23 +55,23 @@ export const AchievementsView: React.FC = () => {
|
|||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-end border-b border-border/50 pb-6 gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-display font-bold text-white mb-2">
|
||||
<h2 className="text-2xl font-display font-bold text-foreground mb-2">
|
||||
ACHIEVEMENTS
|
||||
</h2>
|
||||
<p className="text-muted-foreground font-mono text-sm">
|
||||
Track your milestones and earn rewards.
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-kodo-ink px-4 py-2 rounded-lg border border-border flex items-center gap-4">
|
||||
<div className="bg-card px-4 py-2 rounded-lg border border-border flex items-center gap-4">
|
||||
<Trophy className="w-5 h-5 text-warning" />
|
||||
<span className="text-sm font-bold text-white">
|
||||
<span className="text-sm font-bold text-foreground">
|
||||
{earnedCount} / {achievements.length} Unlocked
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Controls */}
|
||||
<div className="flex flex-col md:flex-row gap-4 items-center bg-kodo-ink/50 p-4 rounded-xl border border-border/50">
|
||||
<div className="flex flex-col md:flex-row gap-4 items-center bg-card/50 p-4 rounded-xl border border-border/50">
|
||||
<div className="flex gap-2 w-full md:w-auto">
|
||||
<Button
|
||||
variant={filter === 'all' ? 'primary' : 'ghost'}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export const LeaderboardView: React.FC = () => {
|
|||
{/* Header */}
|
||||
<div className="flex flex-col md:flex-row justify-between items-end border-b border-border/50 pb-6 gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-display font-bold text-white mb-2">
|
||||
<h2 className="text-2xl font-display font-bold text-foreground mb-2">
|
||||
LEADERBOARD
|
||||
</h2>
|
||||
<p className="text-muted-foreground font-mono text-sm">
|
||||
|
|
@ -42,12 +42,12 @@ export const LeaderboardView: React.FC = () => {
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex bg-kodo-ink p-1 rounded-lg border border-border">
|
||||
<div className="flex bg-card p-1 rounded-lg border border-border">
|
||||
{['weekly', 'monthly', 'all'].map((p) => (
|
||||
<button
|
||||
key={p}
|
||||
onClick={() => setPeriod(p as any)}
|
||||
className={`px-4 py-2 rounded text-xs font-bold uppercase transition-all ${period === p ? 'bg-warning text-black shadow-lg' : 'text-muted-foreground hover:text-white'}`}
|
||||
className={`px-4 py-2 rounded text-xs font-bold uppercase transition-all ${period === p ? 'bg-warning text-foreground shadow-lg' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>
|
||||
{p === 'all' ? 'All Time' : p}
|
||||
</button>
|
||||
|
|
@ -57,7 +57,7 @@ export const LeaderboardView: React.FC = () => {
|
|||
|
||||
{loading ? (
|
||||
<div className="flex justify-center py-24">
|
||||
<Loader2 className="w-10 h-10 text-kodo-steel animate-spin" />
|
||||
<Loader2 className="w-10 h-10 text-muted-foreground animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
|
@ -82,15 +82,15 @@ export const LeaderboardView: React.FC = () => {
|
|||
{i === 1 && (
|
||||
<Crown className="absolute -top-8 left-1/2 -translate-x-1/2 w-10 h-10 text-warning fill-current animate-bounce" />
|
||||
)}
|
||||
<div className="absolute -bottom-3 left-1/2 -translate-x-1/2 bg-black px-2 py-0.5 rounded-full text-xs font-bold border border-white/20">
|
||||
<div className="absolute -bottom-3 left-1/2 -translate-x-1/2 bg-background px-2 py-0.5 rounded-full text-xs font-bold border border-foreground/20">
|
||||
{entry.rank}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="font-bold text-white text-lg">
|
||||
<div className="font-bold text-foreground text-lg">
|
||||
{entry.username}
|
||||
</div>
|
||||
<div className="text-xs text-kodo-steel">
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{entry.xp.toLocaleString()} XP
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -104,7 +104,7 @@ export const LeaderboardView: React.FC = () => {
|
|||
<Card variant="default" className="p-0 overflow-hidden">
|
||||
<table className="w-full text-left">
|
||||
<thead>
|
||||
<tr className="border-b border-border bg-kodo-ink text-xs font-bold text-muted-foreground uppercase tracking-wider">
|
||||
<tr className="border-b border-border bg-card text-xs font-bold text-muted-foreground uppercase tracking-wider">
|
||||
<th className="p-4 w-16 text-center">Rank</th>
|
||||
<th className="p-4">Producer</th>
|
||||
<th className="p-4">Level</th>
|
||||
|
|
@ -116,7 +116,7 @@ export const LeaderboardView: React.FC = () => {
|
|||
{leaderboard.map((entry) => (
|
||||
<tr
|
||||
key={entry.userId}
|
||||
className="hover:bg-white/5 transition-colors group"
|
||||
className="hover:bg-foreground/5 transition-colors group"
|
||||
>
|
||||
<td className="p-4 text-center font-bold font-mono text-muted-foreground">
|
||||
#{entry.rank}
|
||||
|
|
@ -127,17 +127,17 @@ export const LeaderboardView: React.FC = () => {
|
|||
src={entry.avatar}
|
||||
className="w-8 h-8 rounded-full"
|
||||
/>
|
||||
<span className="font-bold text-white group-hover:text-white transition-colors">
|
||||
<span className="font-bold text-foreground group-hover:text-foreground transition-colors">
|
||||
{entry.username}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4">
|
||||
<span className="bg-kodo-slate px-2 py-1 rounded text-xs font-mono text-kodo-text-main">
|
||||
<span className="bg-muted px-2 py-1 rounded text-xs font-mono text-foreground">
|
||||
LVL {entry.level}
|
||||
</span>
|
||||
</td>
|
||||
<td className="p-4 text-right font-mono font-bold text-white">
|
||||
<td className="p-4 text-right font-mono font-bold text-foreground">
|
||||
{entry.xp.toLocaleString()}
|
||||
</td>
|
||||
<td className="p-4 text-center">
|
||||
|
|
|
|||
|
|
@ -45,13 +45,13 @@ export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|||
if (loading)
|
||||
return (
|
||||
<div className="flex justify-center py-24">
|
||||
<Loader2 className="w-10 h-10 text-kodo-steel animate-spin" />
|
||||
<Loader2 className="w-10 h-10 text-muted-foreground animate-spin" />
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="space-y-8 animate-fadeIn pb-20">
|
||||
<h2 className="text-2xl font-display font-bold text-white mb-6">
|
||||
<h2 className="text-2xl font-display font-bold text-foreground mb-6">
|
||||
LEVEL & PROGRESS
|
||||
</h2>
|
||||
|
||||
|
|
@ -63,8 +63,8 @@ export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|||
<div className="relative z-10 flex flex-col md:flex-row items-center gap-8">
|
||||
{/* Level Badge */}
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<div className="w-24 h-24 bg-gradient-to-b from-kodo-gold to-orange-600 rounded-full flex items-center justify-center shadow-gold-glow border-4 border-black">
|
||||
<div className="text-4xl font-black text-black">
|
||||
<div className="w-24 h-24 bg-gradient-to-b from-kodo-gold to-orange-600 rounded-full flex items-center justify-center shadow-gold-glow border-4 border-border">
|
||||
<div className="text-4xl font-black text-foreground">
|
||||
{xpData.level}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -77,7 +77,7 @@ export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|||
<div className="flex-1 w-full space-y-4">
|
||||
<div className="flex justify-between items-end">
|
||||
<div>
|
||||
<h3 className="text-2xl font-bold text-white">{username}</h3>
|
||||
<h3 className="text-2xl font-bold text-foreground">{username}</h3>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Producer • Rank #{xpData.rank}
|
||||
</p>
|
||||
|
|
@ -101,13 +101,13 @@ export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|||
/>
|
||||
|
||||
<div className="flex gap-4 pt-2">
|
||||
<div className="bg-black/30 px-4 py-1 rounded text-xs text-muted-foreground">
|
||||
<span className="text-white font-bold">
|
||||
<div className="bg-background/30 px-4 py-1 rounded text-xs text-muted-foreground">
|
||||
<span className="text-foreground font-bold">
|
||||
{xpData.totalEarned.toLocaleString()}
|
||||
</span>{' '}
|
||||
Total Lifetime XP
|
||||
</div>
|
||||
<div className="bg-black/30 px-4 py-1 rounded text-xs text-muted-foreground">
|
||||
<div className="bg-background/30 px-4 py-1 rounded text-xs text-muted-foreground">
|
||||
<span className="text-success font-bold">+12%</span> vs Last
|
||||
Week
|
||||
</div>
|
||||
|
|
@ -119,36 +119,36 @@ export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|||
{/* Stats Grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<Card variant="default" className="flex items-center gap-4 p-4">
|
||||
<div className="w-12 h-12 bg-kodo-ink rounded-lg flex items-center justify-center text-warning">
|
||||
<div className="w-12 h-12 bg-card rounded-lg flex items-center justify-center text-warning">
|
||||
<Crown className="w-6 h-6" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground uppercase font-bold">
|
||||
Global Rank
|
||||
</div>
|
||||
<div className="text-xl font-bold text-white">#{xpData.rank}</div>
|
||||
<div className="text-xl font-bold text-foreground">#{xpData.rank}</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card variant="default" className="flex items-center gap-4 p-4">
|
||||
<div className="w-12 h-12 bg-kodo-ink rounded-lg flex items-center justify-center text-kodo-steel">
|
||||
<div className="w-12 h-12 bg-card rounded-lg flex items-center justify-center text-muted-foreground">
|
||||
<Zap className="w-6 h-6" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground uppercase font-bold">
|
||||
Daily Streak
|
||||
</div>
|
||||
<div className="text-xl font-bold text-white">12 Days</div>
|
||||
<div className="text-xl font-bold text-foreground">12 Days</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card variant="default" className="flex items-center gap-4 p-4">
|
||||
<div className="w-12 h-12 bg-kodo-ink rounded-lg flex items-center justify-center text-kodo-magenta">
|
||||
<div className="w-12 h-12 bg-card rounded-lg flex items-center justify-center text-kodo-magenta">
|
||||
<Target className="w-6 h-6" />
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs text-muted-foreground uppercase font-bold">
|
||||
Quests Complete
|
||||
</div>
|
||||
<div className="text-xl font-bold text-white">8/10</div>
|
||||
<div className="text-xl font-bold text-foreground">8/10</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
|
@ -156,7 +156,7 @@ export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|||
{/* Recent Achievements */}
|
||||
<div>
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="font-bold text-white">Recent Achievements</h3>
|
||||
<h3 className="font-bold text-foreground">Recent Achievements</h3>
|
||||
<Button variant="ghost" size="sm">
|
||||
View All
|
||||
</Button>
|
||||
|
|
@ -170,8 +170,8 @@ export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|||
|
||||
{/* XP History Graph (Mock) */}
|
||||
<Card variant="default">
|
||||
<h3 className="font-bold text-white mb-6 flex items-center gap-2">
|
||||
<TrendingUp className="w-5 h-5 text-kodo-steel" /> XP History
|
||||
<h3 className="font-bold text-foreground mb-6 flex items-center gap-2">
|
||||
<TrendingUp className="w-5 h-5 text-muted-foreground" /> XP History
|
||||
</h3>
|
||||
<div className="h-48 flex items-end gap-2 px-2">
|
||||
{Array.from({ length: 14 }).map((_, i) => (
|
||||
|
|
@ -183,7 +183,7 @@ export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|||
className="w-full bg-warning rounded-t opacity-50 group-hover:opacity-100 transition-opacity"
|
||||
style={{ height: `${Math.random() * 60 + 10}%` }}
|
||||
></div>
|
||||
<div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap">
|
||||
<div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-background text-foreground text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap">
|
||||
+{Math.floor(Math.random() * 500)} XP
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -40,13 +40,13 @@ export const AutoMetadataDetectionModal: React.FC<
|
|||
return (
|
||||
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
||||
<div
|
||||
className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm"
|
||||
className="absolute inset-0 bg-background/90 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
></div>
|
||||
<div className="relative w-full max-w-md bg-kodo-graphite border border-border/30 rounded-xl shadow-2xl overflow-hidden animate-scaleIn">
|
||||
<div className="p-4 border-b border-border bg-kodo-ink flex justify-between items-center">
|
||||
<div className="relative w-full max-w-md bg-card border border-border/30 rounded-xl shadow-2xl overflow-hidden animate-scaleIn">
|
||||
<div className="p-4 border-b border-border bg-card flex justify-between items-center">
|
||||
<h3 className="font-bold text-white flex items-center gap-2">
|
||||
<Wand2 className="w-4 h-4 text-kodo-steel" /> AI Metadata Detection
|
||||
<Wand2 className="w-4 h-4 text-muted-foreground" /> AI Metadata Detection
|
||||
</h3>
|
||||
<button onClick={onClose}>
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-white" />
|
||||
|
|
@ -59,7 +59,7 @@ export const AutoMetadataDetectionModal: React.FC<
|
|||
<div className="relative">
|
||||
<div className="w-20 h-20 rounded-full border-4 border-border border-t-kodo-steel animate-spin mx-auto"></div>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<Music2 className="w-8 h-8 text-kodo-steel/50" />
|
||||
<Music2 className="w-8 h-8 text-muted-foreground/50" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -68,13 +68,13 @@ export const AutoMetadataDetectionModal: React.FC<
|
|||
</h4>
|
||||
<p className="text-sm text-muted-foreground mt-2">
|
||||
Detecting BPM, Key, and Genre for <br />
|
||||
<span className="text-kodo-steel">{fileName}</span>
|
||||
<span className="text-muted-foreground">{fileName}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full space-y-6 animate-fadeIn">
|
||||
<div className="bg-kodo-ink border border-border/20 rounded-lg p-6 w-full">
|
||||
<div className="bg-card border border-border/20 rounded-lg p-6 w-full">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="text-center p-2">
|
||||
<div className="text-xs text-muted-foreground uppercase font-bold mb-1">
|
||||
|
|
@ -88,7 +88,7 @@ export const AutoMetadataDetectionModal: React.FC<
|
|||
<div className="text-xs text-muted-foreground uppercase font-bold mb-1">
|
||||
Detected Key
|
||||
</div>
|
||||
<div className="text-2xl font-bold text-kodo-steel">
|
||||
<div className="text-2xl font-bold text-muted-foreground">
|
||||
{result?.key}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@ export const CreatePlaylistModal: React.FC<CreatePlaylistModalProps> = ({
|
|||
return (
|
||||
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
||||
<div
|
||||
className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm"
|
||||
className="absolute inset-0 bg-background/90 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
></div>
|
||||
<div className="relative w-full max-w-lg bg-kodo-graphite border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden">
|
||||
<div className="p-4 border-b border-border bg-kodo-ink flex justify-between items-center">
|
||||
<div className="relative w-full max-w-lg bg-card border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden">
|
||||
<div className="p-4 border-b border-border bg-card flex justify-between items-center">
|
||||
<h3 className="font-bold text-white">Create Playlist</h3>
|
||||
<button onClick={onClose}>
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-white" />
|
||||
|
|
@ -43,7 +43,7 @@ export const CreatePlaylistModal: React.FC<CreatePlaylistModalProps> = ({
|
|||
</div>
|
||||
|
||||
<div className="p-6 flex flex-col md:flex-row gap-6">
|
||||
<div className="w-40 h-40 bg-kodo-ink border-2 border-dashed border-border rounded-lg flex flex-col items-center justify-center text-muted-foreground hover:text-white hover:border-border/50 cursor-pointer transition-colors flex-shrink-0">
|
||||
<div className="w-40 h-40 bg-card border-2 border-dashed border-border rounded-lg flex flex-col items-center justify-center text-muted-foreground hover:text-white hover:border-border/50 cursor-pointer transition-colors flex-shrink-0">
|
||||
<ImageIcon className="w-8 h-8 mb-2" />
|
||||
<span className="text-xs font-bold uppercase">Cover</span>
|
||||
</div>
|
||||
|
|
@ -57,7 +57,7 @@ export const CreatePlaylistModal: React.FC<CreatePlaylistModalProps> = ({
|
|||
/>
|
||||
|
||||
<textarea
|
||||
className="w-full bg-kodo-graphite border border-border rounded-lg p-4 text-white focus:border-border outline-none text-sm resize-none h-24"
|
||||
className="w-full bg-card border border-border rounded-lg p-4 text-white focus:border-border outline-none text-sm resize-none h-24"
|
||||
placeholder="Description (Optional)"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
|
|
@ -70,7 +70,7 @@ export const CreatePlaylistModal: React.FC<CreatePlaylistModalProps> = ({
|
|||
>
|
||||
<div className="flex items-center gap-4">
|
||||
{isPublic ? (
|
||||
<Globe className="w-4 h-4 text-kodo-steel" />
|
||||
<Globe className="w-4 h-4 text-muted-foreground" />
|
||||
) : (
|
||||
<Lock className="w-4 h-4 text-warning" />
|
||||
)}
|
||||
|
|
@ -121,7 +121,7 @@ export const CreatePlaylistModal: React.FC<CreatePlaylistModalProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border-t border-border bg-kodo-ink flex justify-end gap-4">
|
||||
<div className="p-4 border-t border-border bg-card flex justify-end gap-4">
|
||||
<Button variant="ghost" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { Playlist, Track } from '../../../types';
|
|||
import { useToast } from '../../../components/feedback/ToastProvider';
|
||||
import { useAudio } from '../../../context/AudioContext';
|
||||
import { EditPlaylistModal } from './EditPlaylistModal';
|
||||
import { OptimizedImage } from '../../ui/optimized-image';
|
||||
|
||||
interface PlaylistDetailViewProps {
|
||||
playlistId: string;
|
||||
|
|
@ -94,10 +95,11 @@ export const PlaylistDetailView: React.FC<PlaylistDetailViewProps> = ({
|
|||
return (
|
||||
<div className="animate-fadeIn pb-20">
|
||||
{/* Header Section */}
|
||||
<div className="flex flex-col md:flex-row gap-8 items-end mb-8 p-8 bg-kodo-ink/40 rounded-2xl border-t border-white/5">
|
||||
<div className="flex flex-col md:flex-row gap-8 items-end mb-8 p-8 bg-card/40 rounded-2xl border-t border-white/5">
|
||||
<div className="w-52 h-52 shadow-2xl shadow-kodo-steel/10 rounded-lg overflow-hidden flex-shrink-0 group relative">
|
||||
<img
|
||||
<OptimizedImage
|
||||
src={playlist.cover_url}
|
||||
alt={playlist.title || 'Playlist cover'}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div
|
||||
|
|
@ -122,7 +124,7 @@ export const PlaylistDetailView: React.FC<PlaylistDetailViewProps> = ({
|
|||
{playlist.description}
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-4 text-sm text-kodo-text-main font-medium mb-6">
|
||||
<div className="flex items-center gap-4 text-sm text-foreground font-medium mb-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-6 h-6 rounded-full bg-muted"></div>
|
||||
<span className="text-foreground hover:underline cursor-pointer">
|
||||
|
|
@ -157,7 +159,7 @@ export const PlaylistDetailView: React.FC<PlaylistDetailViewProps> = ({
|
|||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="border border-white/10 hover:border-white text-kodo-text-main hover:text-foreground"
|
||||
className="border border-white/10 hover:border-white text-foreground hover:text-foreground"
|
||||
onClick={() => addToast('Saved to Library')}
|
||||
aria-label="Ajouter à la bibliothèque"
|
||||
>
|
||||
|
|
@ -166,7 +168,7 @@ export const PlaylistDetailView: React.FC<PlaylistDetailViewProps> = ({
|
|||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="border border-white/10 hover:border-white text-kodo-text-main hover:text-foreground"
|
||||
className="border border-white/10 hover:border-white text-foreground hover:text-foreground"
|
||||
onClick={() => setIsEditing(true)}
|
||||
aria-label="Plus d'options"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ export const PlaylistsView: React.FC<{
|
|||
|
||||
{loading ? (
|
||||
<div className="flex justify-center py-24">
|
||||
<Loader2 className="w-8 h-8 text-kodo-steel animate-spin" />
|
||||
<Loader2 className="w-8 h-8 text-muted-foreground animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-6">
|
||||
|
|
@ -128,7 +128,7 @@ export const PlaylistsView: React.FC<{
|
|||
className="p-0 overflow-hidden group cursor-pointer hover:border-border/50 transition-colors"
|
||||
onClick={() => onNavigate(playlist.id)}
|
||||
>
|
||||
<div className="aspect-square relative bg-kodo-ink">
|
||||
<div className="aspect-square relative bg-card">
|
||||
{playlist.cover_url ? (
|
||||
<img
|
||||
src={playlist.cover_url}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ export const QueueView: React.FC = () => {
|
|||
src={currentTrack.coverUrl}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/40 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<div className="absolute inset-0 bg-background/40 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
{isPlaying ? (
|
||||
<Pause className="w-6 h-6 text-foreground" />
|
||||
) : (
|
||||
|
|
@ -121,7 +121,7 @@ export const QueueView: React.FC = () => {
|
|||
<h2 className="text-xl font-bold text-foreground">
|
||||
{currentTrack.title}
|
||||
</h2>
|
||||
<p className="text-kodo-steel">{currentTrack.artist}</p>
|
||||
<p className="text-muted-foreground">{currentTrack.artist}</p>
|
||||
</div>
|
||||
<div className="text-muted-foreground font-mono text-sm hidden md:block">
|
||||
{currentTrack.duration}
|
||||
|
|
@ -176,7 +176,7 @@ export const QueueView: React.FC = () => {
|
|||
onDragStart={(e) => handleDragStart(e, i)}
|
||||
onDragOver={(e) => handleDragOver(e, i)}
|
||||
onDragEnd={() => setDraggedIndex(null)}
|
||||
className={`flex items-center gap-4 p-4 bg-kodo-ink rounded-lg border border-transparent hover:border-border transition-all group ${draggedIndex === i ? 'opacity-50 border-primary' : ''}`}
|
||||
className={`flex items-center gap-4 p-4 bg-card rounded-lg border border-transparent hover:border-border transition-all group ${draggedIndex === i ? 'opacity-50 border-primary' : ''}`}
|
||||
>
|
||||
<div className="text-muted-foreground cursor-grab active:cursor-grabbing hover:text-foreground p-1">
|
||||
<GripVertical className="w-5 h-5" />
|
||||
|
|
@ -187,7 +187,7 @@ export const QueueView: React.FC = () => {
|
|||
className="w-full h-full object-cover"
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-0 bg-black/50 hidden group-hover:flex items-center justify-center cursor-pointer"
|
||||
className="absolute inset-0 bg-background/50 hidden group-hover:flex items-center justify-center cursor-pointer"
|
||||
onClick={() => playTrack(track)}
|
||||
>
|
||||
<Play className="w-4 h-4 text-foreground fill-current" />
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ export const SaveQueueAsPlaylistModal: React.FC<
|
|||
return (
|
||||
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
||||
<div
|
||||
className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm"
|
||||
className="absolute inset-0 bg-background/90 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
></div>
|
||||
<div className="relative w-full max-w-md bg-kodo-graphite border border-border rounded-xl shadow-2xl animate-scaleIn">
|
||||
<div className="p-4 border-b border-border bg-kodo-ink flex justify-between items-center">
|
||||
<div className="relative w-full max-w-md bg-card border border-border rounded-xl shadow-2xl animate-scaleIn">
|
||||
<div className="p-4 border-b border-border bg-card flex justify-between items-center">
|
||||
<h3 className="font-bold text-white">Save Queue as Playlist</h3>
|
||||
<button onClick={onClose}>
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-white" />
|
||||
|
|
@ -49,12 +49,12 @@ export const SaveQueueAsPlaylistModal: React.FC<
|
|||
/>
|
||||
|
||||
<div
|
||||
className="flex items-center justify-between p-4 bg-kodo-ink rounded border border-border cursor-pointer hover:border-border"
|
||||
className="flex items-center justify-between p-4 bg-card rounded border border-border cursor-pointer hover:border-border"
|
||||
onClick={() => setIsPublic(!isPublic)}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
{isPublic ? (
|
||||
<Globe className="w-5 h-5 text-kodo-steel" />
|
||||
<Globe className="w-5 h-5 text-muted-foreground" />
|
||||
) : (
|
||||
<Lock className="w-5 h-5 text-warning" />
|
||||
)}
|
||||
|
|
@ -77,7 +77,7 @@ export const SaveQueueAsPlaylistModal: React.FC<
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border-t border-border bg-kodo-ink flex justify-end gap-4">
|
||||
<div className="p-4 border-t border-border bg-card flex justify-end gap-4">
|
||||
<Button variant="ghost" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -31,13 +31,13 @@ export const ReviewProductModal: React.FC<ReviewProductModalProps> = ({
|
|||
return (
|
||||
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4">
|
||||
<div
|
||||
className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm"
|
||||
className="absolute inset-0 bg-background/90 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
></div>
|
||||
<div className="relative w-full max-w-md bg-kodo-graphite border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden">
|
||||
<div className="p-4 border-b border-border bg-kodo-ink flex justify-between items-center">
|
||||
<div className="relative w-full max-w-md bg-card border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden">
|
||||
<div className="p-4 border-b border-border bg-card flex justify-between items-center">
|
||||
<h3 className="font-bold text-white flex items-center gap-2">
|
||||
<MessageSquare className="w-4 h-4 text-kodo-steel" /> Write Review
|
||||
<MessageSquare className="w-4 h-4 text-muted-foreground" /> Write Review
|
||||
</h3>
|
||||
<button onClick={onClose}>
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-white" />
|
||||
|
|
@ -77,7 +77,7 @@ export const ReviewProductModal: React.FC<ReviewProductModalProps> = ({
|
|||
Your Review
|
||||
</label>
|
||||
<textarea
|
||||
className="w-full bg-kodo-void border border-border rounded-lg p-4 text-white focus:border-border outline-none text-sm resize-none h-32"
|
||||
className="w-full bg-background border border-border rounded-lg p-4 text-white focus:border-border outline-none text-sm resize-none h-32"
|
||||
placeholder="Share your thoughts on the quality, usability, and value..."
|
||||
value={comment}
|
||||
onChange={(e) => setComment(e.target.value)}
|
||||
|
|
@ -85,7 +85,7 @@ export const ReviewProductModal: React.FC<ReviewProductModalProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border-t border-border bg-kodo-ink flex justify-end gap-4">
|
||||
<div className="p-4 border-t border-border bg-card flex justify-end gap-4">
|
||||
<Button variant="ghost" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -55,10 +55,10 @@ export function useMonitoringDashboard() {
|
|||
}
|
||||
|
||||
export function getFailureRateColor(rate: number): string {
|
||||
if (rate === 0) return 'text-green-600';
|
||||
if (rate < 1) return 'text-yellow-600';
|
||||
if (rate < 5) return 'text-orange-600';
|
||||
return 'text-red-600';
|
||||
if (rate === 0) return 'text-success';
|
||||
if (rate < 1) return 'text-warning';
|
||||
if (rate < 5) return 'text-warning';
|
||||
return 'text-destructive';
|
||||
}
|
||||
|
||||
export function getFailureRateBadge(
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export const AccessibilitySettingsView: React.FC = () => {
|
|||
{/* Visuals */}
|
||||
<Card variant="default">
|
||||
<h3 className="text-lg font-bold text-foreground mb-6 flex items-center gap-2">
|
||||
<Eye className="w-5 h-5 text-kodo-steel" /> Visuals
|
||||
<Eye className="w-5 h-5 text-muted-foreground" /> Visuals
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
<ToggleRow
|
||||
|
|
|
|||
|
|
@ -45,14 +45,14 @@ export const ChangeUsernameModal: React.FC<ChangeUsernameModalProps> = ({
|
|||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||
<div
|
||||
className="absolute inset-0 bg-kodo-void/90 backdrop-blur-sm"
|
||||
className="absolute inset-0 bg-background/90 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
></div>
|
||||
<div className="relative w-full max-w-md bg-kodo-graphite border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden">
|
||||
<div className="p-4 border-b border-border bg-kodo-ink flex justify-between items-center">
|
||||
<h3 className="font-bold text-white">Change Username</h3>
|
||||
<div className="relative w-full max-w-md bg-card border border-border rounded-xl shadow-2xl animate-scaleIn overflow-hidden">
|
||||
<div className="p-4 border-b border-border bg-card flex justify-between items-center">
|
||||
<h3 className="font-bold text-foreground">Change Username</h3>
|
||||
<button onClick={onClose}>
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-white" />
|
||||
<X className="w-5 h-5 text-muted-foreground hover:text-foreground" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -92,19 +92,19 @@ export const ChangeUsernameModal: React.FC<ChangeUsernameModalProps> = ({
|
|||
|
||||
<div className="bg-warning/10 border border-warning/30 p-4 rounded flex gap-4">
|
||||
<AlertCircle className="w-5 h-5 text-warning flex-shrink-0" />
|
||||
<div className="text-xs text-kodo-text-main">
|
||||
<div className="text-xs text-foreground">
|
||||
<span className="font-bold text-warning block mb-1">
|
||||
Warning
|
||||
</span>
|
||||
Changing your username will change your profile URL. Your old
|
||||
username{' '}
|
||||
<span className="font-mono text-white">{currentUsername}</span>{' '}
|
||||
<span className="font-mono text-foreground">{currentUsername}</span>{' '}
|
||||
will become available for anyone else to claim.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border-t border-border bg-kodo-ink flex justify-end gap-4">
|
||||
<div className="p-4 border-t border-border bg-card flex justify-end gap-4">
|
||||
<Button variant="ghost" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export const AppearanceSettingsView: React.FC = () => {
|
|||
{/* Theme Selection */}
|
||||
<Card variant="default">
|
||||
<h3 className="text-lg font-bold text-foreground mb-6 flex items-center gap-2">
|
||||
<Palette className="w-5 h-5 text-kodo-steel" /> Theme
|
||||
<Palette className="w-5 h-5 text-muted-foreground" /> Theme
|
||||
</h3>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
{[
|
||||
|
|
@ -91,11 +91,11 @@ export const AppearanceSettingsView: React.FC = () => {
|
|||
}}
|
||||
className={`
|
||||
cursor-pointer p-6 rounded-xl border-2 transition-all flex flex-col items-center gap-4 relative
|
||||
${theme === opt.id ? 'border-primary bg-primary/5' : 'border-border bg-kodo-ink hover:border-border'}
|
||||
${theme === opt.id ? 'border-primary bg-primary/5' : 'border-border bg-card hover:border-border'}
|
||||
`}
|
||||
>
|
||||
<div
|
||||
className={`p-4 rounded-full ${theme === opt.id ? 'bg-primary text-black' : 'bg-kodo-slate text-muted-foreground'}`}
|
||||
className={`p-4 rounded-full ${theme === opt.id ? 'bg-primary text-black' : 'bg-muted text-muted-foreground'}`}
|
||||
>
|
||||
{opt.icon}
|
||||
</div>
|
||||
|
|
@ -105,7 +105,7 @@ export const AppearanceSettingsView: React.FC = () => {
|
|||
{opt.label}
|
||||
</span>
|
||||
{theme === opt.id && (
|
||||
<div className="absolute top-2 right-2 text-kodo-steel">
|
||||
<div className="absolute top-2 right-2 text-muted-foreground">
|
||||
<Check className="w-4 h-4" />
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -135,7 +135,7 @@ export const AppearanceSettingsView: React.FC = () => {
|
|||
onClick={() => setDensity(opt.id as any)}
|
||||
className={`
|
||||
flex items-center gap-4 p-4 rounded-lg border cursor-pointer transition-all
|
||||
${density === opt.id ? 'bg-kodo-magenta/10 border-kodo-magenta' : 'bg-kodo-ink border-border hover:bg-white/5'}
|
||||
${density === opt.id ? 'bg-kodo-magenta/10 border-kodo-magenta' : 'bg-card border-border hover:bg-white/5'}
|
||||
`}
|
||||
>
|
||||
<div
|
||||
|
|
@ -147,7 +147,7 @@ export const AppearanceSettingsView: React.FC = () => {
|
|||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={`text-sm font-bold ${density === opt.id ? 'text-foreground' : 'text-kodo-text-main'}`}
|
||||
className={`text-sm font-bold ${density === opt.id ? 'text-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{opt.label}
|
||||
</div>
|
||||
|
|
@ -177,7 +177,7 @@ export const AppearanceSettingsView: React.FC = () => {
|
|||
className="w-full h-2 bg-muted rounded-lg appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:bg-warning [&::-webkit-slider-thumb]:rounded-full"
|
||||
/>
|
||||
<div
|
||||
className="mt-4 p-4 bg-kodo-ink rounded border border-border text-kodo-text-main"
|
||||
className="mt-4 p-4 bg-card rounded border border-border text-foreground"
|
||||
style={{ fontSize: `${fontSize}px` }}
|
||||
>
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
|
|
@ -198,7 +198,7 @@ export const AppearanceSettingsView: React.FC = () => {
|
|||
<div
|
||||
key={col.id}
|
||||
onClick={() => setAccentColor(col.id)}
|
||||
className={`w-10 h-10 rounded-full cursor-pointer flex items-center justify-center transition-opacity hover:opacity-80 ring-2 ring-offset-2 ring-offset-kodo-void ${accentColor === col.id ? 'ring-white' : 'ring-transparent'}`}
|
||||
className={`w-10 h-10 rounded-full cursor-pointer flex items-center justify-center transition-opacity hover:opacity-80 ring-2 ring-offset-2 ring-offset-background ${accentColor === col.id ? 'ring-white' : 'ring-transparent'}`}
|
||||
style={{ backgroundColor: col.hex }}
|
||||
>
|
||||
{accentColor === col.id && (
|
||||
|
|
@ -214,7 +214,7 @@ export const AppearanceSettingsView: React.FC = () => {
|
|||
<Layout className="w-5 h-5 text-muted-foreground" /> Layout
|
||||
</h3>
|
||||
<div
|
||||
className="flex items-center justify-between p-4 bg-kodo-ink rounded-lg border border-border cursor-pointer hover:border-border"
|
||||
className="flex items-center justify-between p-4 bg-card rounded-lg border border-border cursor-pointer hover:border-border"
|
||||
onClick={() => setShowSidebar(!showSidebar)}
|
||||
>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export const BackupsView: React.FC = () => {
|
|||
{backups.map((backup) => (
|
||||
<div
|
||||
key={backup.id}
|
||||
className="flex flex-col md:flex-row items-center justify-between p-4 bg-kodo-ink rounded-lg border border-border hover:border-border/50 transition-all"
|
||||
className="flex flex-col md:flex-row items-center justify-between p-4 bg-card rounded-lg border border-border hover:border-border/50 transition-all"
|
||||
>
|
||||
<div className="flex items-center gap-4 mb-2 md:mb-0 w-full md:w-auto">
|
||||
<div
|
||||
|
|
@ -148,7 +148,7 @@ export const BackupsView: React.FC = () => {
|
|||
<div className="space-y-6">
|
||||
<Card variant="glass">
|
||||
<h3 className="font-bold text-foreground mb-4 flex items-center gap-2 text-sm uppercase tracking-wider">
|
||||
<Clock className="w-4 h-4 text-kodo-steel" /> Schedule
|
||||
<Clock className="w-4 h-4 text-muted-foreground" /> Schedule
|
||||
</h3>
|
||||
|
||||
<div className="space-y-4">
|
||||
|
|
@ -177,7 +177,7 @@ export const BackupsView: React.FC = () => {
|
|||
<label className="block text-xs font-bold text-muted-foreground uppercase mb-1">
|
||||
Frequency
|
||||
</label>
|
||||
<select className="w-full bg-kodo-void border border-border rounded p-2 text-foreground text-sm">
|
||||
<select className="w-full bg-background border border-border rounded p-2 text-foreground text-sm">
|
||||
<option>Daily</option>
|
||||
<option>Weekly</option>
|
||||
<option>Monthly</option>
|
||||
|
|
@ -189,7 +189,7 @@ export const BackupsView: React.FC = () => {
|
|||
</label>
|
||||
<input
|
||||
type="time"
|
||||
className="w-full bg-kodo-void border border-border rounded p-2 text-foreground text-sm"
|
||||
className="w-full bg-background border border-border rounded p-2 text-foreground text-sm"
|
||||
defaultValue="04:00"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -197,7 +197,7 @@ export const BackupsView: React.FC = () => {
|
|||
<label className="block text-xs font-bold text-muted-foreground uppercase mb-1">
|
||||
Retention
|
||||
</label>
|
||||
<select className="w-full bg-kodo-void border border-border rounded p-2 text-foreground text-sm">
|
||||
<select className="w-full bg-background border border-border rounded p-2 text-foreground text-sm">
|
||||
<option>Keep last 7 days</option>
|
||||
<option>Keep last 30 days</option>
|
||||
<option>Keep forever</option>
|
||||
|
|
@ -208,13 +208,13 @@ export const BackupsView: React.FC = () => {
|
|||
</div>
|
||||
</Card>
|
||||
|
||||
<div className="bg-kodo-orange/10 border border-kodo-orange/30 p-4 rounded-xl flex gap-4">
|
||||
<AlertTriangle className="w-6 h-6 text-kodo-orange flex-shrink-0" />
|
||||
<div className="bg-warning/10 border border-warning/30 p-4 rounded-xl flex gap-4">
|
||||
<AlertTriangle className="w-6 h-6 text-warning flex-shrink-0" />
|
||||
<div>
|
||||
<h4 className="font-bold text-kodo-orange text-sm mb-1">
|
||||
<h4 className="font-bold text-warning text-sm mb-1">
|
||||
Disaster Recovery
|
||||
</h4>
|
||||
<p className="text-xs text-kodo-text-main">
|
||||
<p className="text-xs text-foreground">
|
||||
Off-site cold storage is available for Enterprise plans.{' '}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
|
|
|
|||
|
|
@ -82,17 +82,17 @@ export const CloudIntegrationView: React.FC = () => {
|
|||
</div>
|
||||
) : (
|
||||
<div className="mt-8 grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="bg-kodo-ink p-4 rounded-lg border border-border text-center">
|
||||
<Server className="w-6 h-6 text-kodo-steel mx-auto mb-2" />
|
||||
<div className="bg-card p-4 rounded-lg border border-border text-center">
|
||||
<Server className="w-6 h-6 text-muted-foreground mx-auto mb-2" />
|
||||
<div className="text-sm font-bold text-foreground">{url}</div>
|
||||
<div className="text-xs text-muted-foreground">Host</div>
|
||||
</div>
|
||||
<div className="bg-kodo-ink p-4 rounded-lg border border-border text-center">
|
||||
<div className="bg-card p-4 rounded-lg border border-border text-center">
|
||||
<RefreshCw className="w-6 h-6 text-warning mx-auto mb-2" />
|
||||
<div className="text-sm font-bold text-foreground">Every 15 mins</div>
|
||||
<div className="text-xs text-muted-foreground">Sync Frequency</div>
|
||||
</div>
|
||||
<div className="bg-kodo-ink p-4 rounded-lg border border-border text-center">
|
||||
<div className="bg-card p-4 rounded-lg border border-border text-center">
|
||||
<Shield className="w-6 h-6 text-success mx-auto mb-2" />
|
||||
<div className="text-sm font-bold text-foreground">Encrypted</div>
|
||||
<div className="text-xs text-muted-foreground">Status</div>
|
||||
|
|
@ -130,7 +130,7 @@ export const CloudIntegrationView: React.FC = () => {
|
|||
<label className="block text-xs font-bold text-muted-foreground uppercase mb-2">
|
||||
Sync Frequency
|
||||
</label>
|
||||
<select className="w-full bg-kodo-ink border border-border rounded p-2 text-foreground outline-none focus:border-border">
|
||||
<select className="w-full bg-card border border-border rounded p-2 text-foreground outline-none focus:border-border">
|
||||
<option>Every 15 minutes</option>
|
||||
<option>Hourly</option>
|
||||
<option>Daily</option>
|
||||
|
|
@ -146,7 +146,7 @@ export const CloudIntegrationView: React.FC = () => {
|
|||
{['Projects', 'Samples', 'Presets'].map((type) => (
|
||||
<span
|
||||
key={type}
|
||||
className="px-4 py-1 bg-kodo-slate rounded text-xs text-foreground border border-border cursor-pointer hover:border-border/50"
|
||||
className="px-4 py-1 bg-muted rounded text-xs text-foreground border border-border cursor-pointer hover:border-border/50"
|
||||
>
|
||||
{type}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export const DataExportView: React.FC = () => {
|
|||
|
||||
<Card variant="default">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="p-4 bg-muted/10 rounded-full text-kodo-steel">
|
||||
<div className="p-4 bg-muted/10 rounded-full text-muted-foreground">
|
||||
<Shield className="w-6 h-6" />
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -65,7 +65,7 @@ export const DataExportView: React.FC = () => {
|
|||
{exports.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className="flex flex-col md:flex-row items-center justify-between p-4 bg-kodo-ink rounded-lg border border-border"
|
||||
className="flex flex-col md:flex-row items-center justify-between p-4 bg-card rounded-lg border border-border"
|
||||
>
|
||||
<div className="flex items-center gap-4 mb-2 md:mb-0 w-full md:w-auto">
|
||||
<FileText className="w-5 h-5 text-muted-foreground" />
|
||||
|
|
@ -90,7 +90,7 @@ export const DataExportView: React.FC = () => {
|
|||
Download
|
||||
</Button>
|
||||
) : (
|
||||
<span className="text-xs text-muted-foreground bg-kodo-graphite px-4 py-1 rounded">
|
||||
<span className="text-xs text-muted-foreground bg-card px-4 py-1 rounded">
|
||||
Expired
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export const FeedView: React.FC = () => {
|
|||
if (loading)
|
||||
return (
|
||||
<div className="flex justify-center py-24">
|
||||
<Loader2 className="w-10 h-10 text-kodo-steel animate-spin" />
|
||||
<Loader2 className="w-10 h-10 text-muted-foreground animate-spin" />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ export const FeedView: React.FC = () => {
|
|||
className="flex-1 cursor-pointer"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
>
|
||||
<div className="w-full bg-kodo-void/50 border border-border rounded-full px-4 py-2.5 text-muted-foreground hover:bg-kodo-void hover:border-border/50 transition-all text-sm">
|
||||
<div className="w-full bg-background/50 border border-border rounded-full px-4 py-2.5 text-muted-foreground hover:bg-background hover:border-border/50 transition-all text-sm">
|
||||
What are you working on today?
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -98,25 +98,25 @@ export const FeedView: React.FC = () => {
|
|||
<div className="flex justify-between items-center mt-3 pl-14">
|
||||
<div className="flex gap-4">
|
||||
<button
|
||||
className="flex items-center gap-1 text-muted-foreground hover:text-white text-xs font-bold cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void rounded"
|
||||
className="flex items-center gap-1 text-muted-foreground hover:text-white text-xs font-bold cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
>
|
||||
<ImageIcon className="w-4 h-4" /> Photo
|
||||
</button>
|
||||
<button
|
||||
className="flex items-center gap-1 text-muted-foreground hover:text-kodo-magenta text-xs font-bold cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void rounded"
|
||||
className="flex items-center gap-1 text-muted-foreground hover:text-kodo-magenta text-xs font-bold cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
>
|
||||
<Video className="w-4 h-4" /> Video
|
||||
</button>
|
||||
<button
|
||||
className="flex items-center gap-1 text-muted-foreground hover:text-success text-xs font-bold cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void rounded"
|
||||
className="flex items-center gap-1 text-muted-foreground hover:text-success text-xs font-bold cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
>
|
||||
<Mic2 className="w-4 h-4" /> Audio
|
||||
</button>
|
||||
<button
|
||||
className="flex items-center gap-1 text-muted-foreground hover:text-warning text-xs font-bold cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-kodo-void rounded"
|
||||
className="flex items-center gap-1 text-muted-foreground hover:text-warning text-xs font-bold cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-kodo-cyan focus-visible:ring-offset-2 focus-visible:ring-offset-background rounded"
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
>
|
||||
<BarChart className="w-4 h-4" /> Poll
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|||
offline: 'bg-muted',
|
||||
away: 'bg-warning',
|
||||
idle: 'bg-warning',
|
||||
busy: 'bg-kodo-red',
|
||||
dnd: 'bg-kodo-red',
|
||||
busy: 'bg-destructive',
|
||||
dnd: 'bg-destructive',
|
||||
};
|
||||
|
||||
const statusSize = {
|
||||
|
|
@ -154,7 +154,7 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|||
>
|
||||
<div
|
||||
className={cn(
|
||||
`${sizeClasses[size]} rounded-full overflow-hidden bg-kodo-graphite border border-border flex items-center justify-center relative`,
|
||||
`${sizeClasses[size]} rounded-full overflow-hidden bg-card border border-border flex items-center justify-center relative`,
|
||||
)}
|
||||
>
|
||||
{src ? (
|
||||
|
|
@ -167,7 +167,7 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|||
{status && (
|
||||
<span
|
||||
className={cn(
|
||||
`absolute bottom-0 right-0 rounded-full border-kodo-void`,
|
||||
`absolute bottom-0 right-0 rounded-full border-background`,
|
||||
statusColors[status],
|
||||
statusSize[size],
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ export const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
|
|||
const actualVariant = variantMap[variant] || variant;
|
||||
|
||||
const styles: Record<string, string> = {
|
||||
cyan: 'bg-muted/10 text-kodo-steel border-border/30',
|
||||
cyan: 'bg-muted/10 text-muted-foreground border-border/30',
|
||||
magenta: 'bg-kodo-magenta/10 text-kodo-magenta border-kodo-magenta/30',
|
||||
lime: 'bg-success/10 text-success border-success/30',
|
||||
gold: 'bg-warning/10 text-warning border-warning/30',
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export const UploadProgressBar: React.FC<UploadProgressBarProps> = ({
|
|||
{isPaused ? (
|
||||
<button
|
||||
onClick={onResume}
|
||||
className="p-1 hover:text-white text-success transition-colors"
|
||||
className="p-1 hover:text-foreground text-success transition-colors"
|
||||
title="Resume"
|
||||
>
|
||||
<Play className="w-3 h-3 fill-current" />
|
||||
|
|
@ -55,7 +55,7 @@ export const UploadProgressBar: React.FC<UploadProgressBarProps> = ({
|
|||
) : (
|
||||
<button
|
||||
onClick={onPause}
|
||||
className="p-1 hover:text-white text-warning transition-colors"
|
||||
className="p-1 hover:text-foreground text-warning transition-colors"
|
||||
title="Pause"
|
||||
>
|
||||
<Pause className="w-3 h-3 fill-current" />
|
||||
|
|
@ -63,7 +63,7 @@ export const UploadProgressBar: React.FC<UploadProgressBarProps> = ({
|
|||
)}
|
||||
<button
|
||||
onClick={onCancel}
|
||||
className="p-1 hover:text-white text-destructive transition-colors"
|
||||
className="p-1 hover:text-foreground text-destructive transition-colors"
|
||||
title="Cancel"
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export const TagSuggestionsModal: React.FC<TagSuggestionsModalProps> = ({
|
|||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2 min-h-[40px]">
|
||||
<div className="flex flex-wrap gap-2 min-h-10">
|
||||
{localTags.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export function AnalyticsViewTopTracks({ tracks, onNavigateTrack }: AnalyticsVie
|
|||
className={cn(
|
||||
'inline-flex items-center gap-1.5 px-2 py-0.5 rounded text-xs font-bold uppercase tracking-wider border',
|
||||
track.change >= 0
|
||||
? 'text-lime-500 border-lime-500/20 bg-lime-500/10'
|
||||
? 'text-success border-success/20 bg-success/10'
|
||||
: 'text-destructive border-destructive/20 bg-destructive/10'
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ export function NotificationsViewItem({
|
|||
notification.type === 'like'
|
||||
? 'bg-destructive/10 text-destructive'
|
||||
: notification.type === 'follow'
|
||||
? 'bg-lime-500/10 text-lime-500'
|
||||
: 'bg-cyan-500/10 text-cyan-500';
|
||||
? 'bg-success/10 text-success'
|
||||
: 'bg-primary/10 text-primary';
|
||||
|
||||
return (
|
||||
<Card
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ export function PasswordStrengthIndicator({
|
|||
>
|
||||
<div>
|
||||
<div
|
||||
className="w-full bg-kodo-slate rounded-full h-2"
|
||||
className="w-full bg-muted rounded-full h-2"
|
||||
role="progressbar"
|
||||
aria-valuenow={level}
|
||||
aria-valuemin={0}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ export const ChatPage: React.FC = () => {
|
|||
<Card variant="glass" className="w-80 shrink-0 flex flex-col overflow-hidden p-0 border-white/5 bg-black/40 backdrop-blur-2xl">
|
||||
<div className="p-4 border-b border-white/5 flex items-center justify-between">
|
||||
<h3 className="font-bold text-sm tracking-widest text-muted-foreground uppercase">Channels</h3>
|
||||
<div className={cn("w-2 h-2 rounded-full", wsStatus === 'connected' ? 'bg-lime-500 shadow-status-dot-lime' : 'bg-red-500')} />
|
||||
<div className={cn("w-2 h-2 rounded-full", wsStatus === 'connected' ? 'bg-success shadow-status-dot-lime' : 'bg-destructive')} />
|
||||
</div>
|
||||
<ChatSidebar />
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ export function getWarrantyStatus(dateStr?: string) {
|
|||
const daysLeft = Math.ceil((expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (daysLeft < 0) return { label: 'Expired', color: 'text-destructive', bg: 'bg-destructive/10' };
|
||||
if (daysLeft < 90) return { label: `Expiring (${daysLeft}d)`, color: 'text-amber-500', bg: 'bg-amber-500/10' };
|
||||
return { label: 'Active', color: 'text-green-600', bg: 'bg-green-600/10' };
|
||||
if (daysLeft < 90) return { label: `Expiring (${daysLeft}d)`, color: 'text-warning', bg: 'bg-warning/10' };
|
||||
return { label: 'Active', color: 'text-success', bg: 'bg-success/10' };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ export const ImportPlaylistButton: React.FC<ImportPlaylistButtonProps> = ({
|
|||
placeholder="Description de la playlist (optionnel)"
|
||||
disabled={isImporting}
|
||||
rows={3}
|
||||
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-4 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="flex min-h-20 w-full rounded-md border border-input bg-background px-4 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ function ErrorFallback({
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-[400px] p-4">
|
||||
<div className="flex items-center justify-center min-h-layout-page-sm p-4">
|
||||
<div className="w-full max-w-md">
|
||||
<ErrorDisplay
|
||||
error={error}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export function AddCollaboratorModalSkeleton({
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg border bg-card p-4 space-y-4 max-w-md',
|
||||
'rounded-xl border bg-card p-4 space-y-4 max-w-md',
|
||||
className,
|
||||
)}
|
||||
role="dialog"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export function CreatePlaylistDialogSkeleton({
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg border bg-card p-4 space-y-4 max-w-md',
|
||||
'rounded-xl border bg-card p-4 space-y-4 max-w-md',
|
||||
className,
|
||||
)}
|
||||
role="dialog"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export function PlaylistAnalyticsStatCard({
|
|||
description,
|
||||
}: PlaylistAnalyticsStatCardProps) {
|
||||
return (
|
||||
<div className="flex flex-col p-4 rounded-lg border bg-card">
|
||||
<div className="flex flex-col p-4 rounded-xl border bg-card">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Icon className="w-5 h-5 text-primary" />
|
||||
<span className="text-sm text-muted-foreground">{label}</span>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export function SharePlaylistModalSkeleton({
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg border bg-card p-4 space-y-4 max-w-md',
|
||||
'rounded-xl border bg-card p-4 space-y-4 max-w-md',
|
||||
className,
|
||||
)}
|
||||
role="dialog"
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ export function PlaylistDetailPageCoverAndInfo({ playlist }: PlaylistDetailPageC
|
|||
className={cn(
|
||||
'px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wider border',
|
||||
playlist.is_public
|
||||
? 'bg-cyan-500/10 text-cyan-500 border-cyan-500/20'
|
||||
: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/20'
|
||||
? 'bg-primary/10 text-primary border-primary/20'
|
||||
: 'bg-warning/10 text-warning border-warning/20'
|
||||
)}
|
||||
>
|
||||
{playlist.is_public ? 'Public Signal' : 'Encrypted'}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ export function RolesPage() {
|
|||
)}
|
||||
</div>
|
||||
<div className="col-span-2 text-center">
|
||||
<div className={cn("inline-flex h-2 w-2 rounded-full", role.is_active ? "bg-lime-500 shadow-status-dot-lime" : "bg-red-500")} />
|
||||
<div className={cn("inline-flex h-2 w-2 rounded-full", role.is_active ? "bg-success shadow-status-dot-lime" : "bg-destructive")} />
|
||||
</div>
|
||||
<div className="col-span-2 flex justify-end gap-2 opacity-60 group-hover:opacity-100 transition-opacity">
|
||||
{role.is_system ? <Lock className="w-4 h-4 text-muted-foreground" /> : (
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export function TrackDetailPageCoverAndActions({
|
|||
<span className="text-xs text-muted-foreground uppercase tracking-wider">Likes</span>
|
||||
</Card>
|
||||
<Card variant="glass" className="p-4 flex flex-col items-center justify-center bg-black/20 text-center hover:bg-white/5 transition-colors">
|
||||
<Play className="w-5 h-5 text-cyan-500 mb-1" />
|
||||
<Play className="w-5 h-5 text-primary mb-1" />
|
||||
<span className="text-xl font-bold text-white">{playCount}</span>
|
||||
<span className="text-xs text-muted-foreground uppercase tracking-wider">Plays</span>
|
||||
</Card>
|
||||
|
|
|
|||
Loading…
Reference in a new issue