2026-01-07 09:31:02 +00:00
|
|
|
import React from 'react';
|
|
|
|
|
import { X, Play, Upload, Layers } from 'lucide-react';
|
|
|
|
|
import { Button } from '../ui/button';
|
|
|
|
|
import { FilePreviewCard, UploadFile } from './FilePreviewCard';
|
|
|
|
|
|
|
|
|
|
interface BulkUploadModalProps {
|
|
|
|
|
files: UploadFile[];
|
|
|
|
|
onClose: () => void;
|
|
|
|
|
onStartUpload: () => void;
|
|
|
|
|
onCancelFile: (id: string) => void;
|
|
|
|
|
onPauseFile: (id: string) => void;
|
|
|
|
|
onResumeFile: (id: string) => void;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
export const BulkUploadModal: React.FC<BulkUploadModalProps> = ({
|
|
|
|
|
files,
|
|
|
|
|
onClose,
|
2026-01-07 09:31:02 +00:00
|
|
|
onStartUpload,
|
|
|
|
|
onCancelFile,
|
|
|
|
|
onPauseFile,
|
2026-01-13 18:47:57 +00:00
|
|
|
onResumeFile,
|
2026-01-07 09:31:02 +00:00
|
|
|
}) => {
|
2026-01-13 18:47:57 +00:00
|
|
|
const totalProgress =
|
|
|
|
|
files.reduce((acc, f) => acc + f.progress, 0) / (files.length || 1);
|
|
|
|
|
const uploadingCount = files.filter((f) => f.status === 'uploading').length;
|
|
|
|
|
const completedCount = files.filter((f) => f.status === 'completed').length;
|
2026-01-07 09:31:02 +00:00
|
|
|
|
|
|
|
|
return (
|
2026-02-12 00:54:47 +00:00
|
|
|
<div className="fixed inset-0 z-[400] flex items-center justify-center p-4">
|
2026-01-13 18:47:57 +00:00
|
|
|
<div
|
2026-02-07 15:07:09 +00:00
|
|
|
className="absolute inset-0 bg-background/90 backdrop-blur-sm"
|
2026-01-13 18:47:57 +00:00
|
|
|
onClick={onClose}
|
|
|
|
|
></div>
|
2026-02-08 21:47:41 +00:00
|
|
|
<div className="relative w-full max-w-3xl bg-card border border-border rounded-2xl shadow-2xl overflow-hidden flex flex-col max-h-layout-modal-sm animate-scaleIn">
|
2026-01-07 09:31:02 +00:00
|
|
|
{/* Header */}
|
2026-02-07 15:07:09 +00:00
|
|
|
<div className="p-8 border-b border-border bg-muted flex justify-between items-center">
|
2026-01-07 09:31:02 +00:00
|
|
|
<div>
|
2026-02-12 00:49:07 +00:00
|
|
|
<h3 className="font-heading font-bold text-xl text-white flex items-center gap-2">
|
refactor: Phase 3a — Global color class migration to SUMI semantics
- Replace all kodo-* color classes across ~100 TSX files:
kodo-void → background, kodo-ink → card, kodo-graphite → muted,
kodo-steel → muted-foreground, kodo-cyan → primary, kodo-magenta → destructive,
kodo-lime → success, kodo-red → destructive, kodo-gold → warning
- Replace cyan-500, magenta-500, lime-500 default Tailwind colors with
semantic equivalents (primary, destructive, success)
- Fix WaveformVisualizer hardcoded hex colors to SUMI values
- Delete global-effects.css (conflicting, redundant with index.css)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 00:51:49 +00:00
|
|
|
<Layers className="w-5 h-5 text-muted-foreground" /> Bulk Upload Manager
|
2026-01-13 18:47:57 +00:00
|
|
|
</h3>
|
2026-02-07 15:07:09 +00:00
|
|
|
<p className="text-xs text-muted-foreground mt-1">
|
2026-01-13 18:47:57 +00:00
|
|
|
{completedCount} / {files.length} files uploaded •{' '}
|
|
|
|
|
{files.length - completedCount} remaining
|
|
|
|
|
</p>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
consistency: replace custom buttons with Button component (partial)
- Replaced custom button implementations with Button component in 14 files
- Files updated: LiveStreamDetailView, DashboardPage, CommentItem, PostCard, SocialPage, SocialView, AdminUsersView, UserTableRow, ProjectsManager, CloudFileBrowser, FileManagerView, CreatorModal, ImageCropper, BulkUploadModal
- ~31 buttons replaced across high-priority files
- Used appropriate Button variants: ghost, outline, default, secondary, link
- Preserved visual appearance with className overrides where needed
- Action 9.2.1.2 in progress (partial completion)
2026-01-16 01:06:14 +00:00
|
|
|
<Button variant="ghost" size="icon" onClick={onClose}>
|
2026-01-13 18:47:57 +00:00
|
|
|
<X className="w-5 h-5" />
|
consistency: replace custom buttons with Button component (partial)
- Replaced custom button implementations with Button component in 14 files
- Files updated: LiveStreamDetailView, DashboardPage, CommentItem, PostCard, SocialPage, SocialView, AdminUsersView, UserTableRow, ProjectsManager, CloudFileBrowser, FileManagerView, CreatorModal, ImageCropper, BulkUploadModal
- ~31 buttons replaced across high-priority files
- Used appropriate Button variants: ghost, outline, default, secondary, link
- Preserved visual appearance with className overrides where needed
- Action 9.2.1.2 in progress (partial completion)
2026-01-16 01:06:14 +00:00
|
|
|
</Button>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Global Progress */}
|
refactor: Phase 3a — Global color class migration to SUMI semantics
- Replace all kodo-* color classes across ~100 TSX files:
kodo-void → background, kodo-ink → card, kodo-graphite → muted,
kodo-steel → muted-foreground, kodo-cyan → primary, kodo-magenta → destructive,
kodo-lime → success, kodo-red → destructive, kodo-gold → warning
- Replace cyan-500, magenta-500, lime-500 default Tailwind colors with
semantic equivalents (primary, destructive, success)
- Fix WaveformVisualizer hardcoded hex colors to SUMI values
- Delete global-effects.css (conflicting, redundant with index.css)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 00:51:49 +00:00
|
|
|
<div className="px-6 py-2 bg-muted/30 border-b border-border">
|
feat(web): UI premium Discord/Spotify-like — tokens, shadows, focus, layout
Plan UI premium 6–8 semaines (design system, shell, Storybook, a11y):
- Design system: DESIGN_TOKENS.md, APP_SHELL.md, FULL_LAYOUT_PAGE.md. Single source
for layout/shell (index.css), shadows (design-system.css), durations/easing.
- Tokens: shadow-cover-depth, shadow-gold-glow, shadow-fab-glow; layout max-height
(max-h-layout-drawer, max-h-layout-panel, max-h-layout-list). All duration-200/300/500
replaced by --duration-fast/normal/slow. Arbitrary shadows replaced by token classes.
- Shell & player: Sidebar, Header, GlobalPlayer, MiniPlayer, PlayerQueue, PlayerControls,
AudioPlayer use tokens; focus-visible on Sidebar, PlayerQueue, DropdownMenuTrigger/Item,
TabsTrigger. Typography: text-[10px]/[9px] → text-xs where applicable.
- ESLint: no-restricted-syntax (warn) for w-/h-/rounded-/shadow-/text-/spacing arbitrary.
- Scripts: report-arbitrary-values.mjs, capture/compare/generate visual; visual-complete.spec.ts.
- Stories full layout: Dashboard, Playlists, Library, Settings, Profile in DashboardLayout.stories.
- .cursorrules + README: DESIGN_TOKENS, APP_SHELL, visual commands, no arbitrary without justification.
- apps/web/.gitignore: e2e test artifacts (test-results-visual, playwright-report-visual).
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 16:15:58 +00:00
|
|
|
<div className="flex justify-between text-xs font-bold text-muted-foreground uppercase mb-1">
|
2026-01-13 18:47:57 +00:00
|
|
|
<span>Overall Progress</span>
|
|
|
|
|
<span>{Math.round(totalProgress)}%</span>
|
|
|
|
|
</div>
|
2026-02-07 15:07:09 +00:00
|
|
|
<div className="h-1 bg-muted rounded-full overflow-hidden">
|
2026-01-13 18:47:57 +00:00
|
|
|
<div
|
ui(tokens): migrate kodo-cyan to primary (51 files, 88 instances)
Replace legacy text-kodo-cyan/border-kodo-cyan/bg-kodo-cyan with semantic
text-primary/border-primary/bg-primary across 51 components.
The brand primary color now uses the design system token, enabling proper
theme adaptation. Covers UI primitives, search, dashboard, chat, playlists,
settings, social, marketplace, and auth components.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 23:19:12 +00:00
|
|
|
className="h-full bg-primary transition-all duration-[var(--duration-normal)]"
|
2026-01-13 18:47:57 +00:00
|
|
|
style={{ width: `${totalProgress}%` }}
|
|
|
|
|
></div>
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* File List */}
|
2026-02-07 15:07:09 +00:00
|
|
|
<div className="flex-1 overflow-y-auto p-8 space-y-4 bg-muted/50">
|
2026-01-13 18:47:57 +00:00
|
|
|
{files.map((file) => (
|
|
|
|
|
<FilePreviewCard
|
|
|
|
|
key={file.id}
|
|
|
|
|
fileData={file}
|
|
|
|
|
onCancel={() => onCancelFile(file.id)}
|
|
|
|
|
onPause={() => onPauseFile(file.id)}
|
|
|
|
|
onResume={() => onResumeFile(file.id)}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Footer Actions */}
|
2026-02-07 15:07:09 +00:00
|
|
|
<div className="p-8 border-t border-border bg-muted flex justify-between items-center">
|
2026-01-13 18:47:57 +00:00
|
|
|
<div className="flex gap-2">
|
|
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="sm"
|
2026-02-07 15:07:09 +00:00
|
|
|
className="text-muted-foreground hover:text-foreground"
|
2026-01-13 18:47:57 +00:00
|
|
|
onClick={onClose}
|
|
|
|
|
>
|
|
|
|
|
Cancel All
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
aesthetic-improvements: align spacing to 8px grid (Action 11.2.1.3)
- Created automated script (scripts/align-8px-grid.py) to align all spacing to 8px grid
- Replaced non-8px-aligned spacing: gap-3/p-3/m-3 (12px) → gap-4/p-4/m-4 (16px), gap-5/p-5/m-5 (20px) → gap-6/p-6/m-6 (24px), gap-10/p-10/m-10 (40px) → gap-12/p-12/m-12 (48px), gap-20/p-20/m-20 (80px) → gap-24/p-24/m-24 (96px)
- Preserved: 4px values (gap-1, p-1, m-1) as they may be intentional fine-tuning, responsive breakpoints (sm:, md:, lg:), test files, documentation
- Modified files across all components to ensure consistent 8px grid alignment
- Action 11.2.1.3: Align all elements to 8px grid - COMPLETE
2026-01-16 10:50:46 +00:00
|
|
|
<div className="flex gap-4">
|
2026-01-13 18:47:57 +00:00
|
|
|
<Button
|
|
|
|
|
variant="secondary"
|
|
|
|
|
size="sm"
|
|
|
|
|
icon={<Upload className="w-4 h-4" />}
|
|
|
|
|
>
|
|
|
|
|
Apply Metadata to All
|
|
|
|
|
</Button>
|
|
|
|
|
{uploadingCount === 0 && completedCount < files.length && (
|
|
|
|
|
<Button
|
|
|
|
|
variant="primary"
|
|
|
|
|
size="sm"
|
|
|
|
|
icon={<Play className="w-4 h-4" />}
|
|
|
|
|
onClick={onStartUpload}
|
|
|
|
|
>
|
|
|
|
|
Start Upload
|
2026-01-07 09:31:02 +00:00
|
|
|
</Button>
|
2026-01-13 18:47:57 +00:00
|
|
|
)}
|
|
|
|
|
{completedCount === files.length && (
|
|
|
|
|
<Button variant="primary" size="sm" onClick={onClose}>
|
|
|
|
|
Done
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2026-01-13 18:47:57 +00:00
|
|
|
};
|