Initialize the repository with the core Go backend architecture and a frontend mockup for warpbox.dev, a self-hosted file-sharing application. - Set up Go backend modules for configuration, HTTP server, middleware, handlers, and templates. - Add local development scripts, environment templates, and basic project configuration. - Include a React-based frontend mockup under the docs directory.
113 lines
5.3 KiB
TypeScript
113 lines
5.3 KiB
TypeScript
import { createFileRoute } from "@tanstack/react-router";
|
|
import { AppShell } from "@/components/layout/AppShell";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import {
|
|
Table, TableBody, TableCell, TableHead, TableHeader, TableRow,
|
|
} from "@/components/ui/table";
|
|
import {
|
|
Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator,
|
|
} from "@/components/ui/breadcrumb";
|
|
import {
|
|
ChevronRight, Folder, FolderPlus, Search, Share2, Upload, MoreHorizontal,
|
|
} from "lucide-react";
|
|
import { mockFiles, mockFolders } from "@/lib/mock-data";
|
|
|
|
export const Route = createFileRoute("/app/files")({
|
|
head: () => ({ meta: [{ title: "My files — warpbox.dev" }] }),
|
|
component: Files,
|
|
});
|
|
|
|
function Files() {
|
|
return (
|
|
<AppShell variant="user" title="My files">
|
|
<div className="grid gap-4 md:grid-cols-[240px_1fr]">
|
|
<Card className="h-fit">
|
|
<CardContent className="p-3">
|
|
<div className="mb-2 px-2 text-xs font-medium uppercase text-muted-foreground">Folders</div>
|
|
<div className="space-y-0.5 text-sm">
|
|
<div className="flex items-center gap-1 rounded px-2 py-1.5 font-medium hover:bg-muted">
|
|
<ChevronRight className="h-3.5 w-3.5" /> <Folder className="h-3.5 w-3.5" /> My files
|
|
</div>
|
|
{mockFolders.map((f) => (
|
|
<div key={f.name}>
|
|
<div className="flex items-center gap-1 rounded px-2 py-1.5 pl-5 hover:bg-muted">
|
|
<ChevronRight className="h-3.5 w-3.5" /> <Folder className="h-3.5 w-3.5" /> {f.name}
|
|
</div>
|
|
{f.children.map((c) => (
|
|
<div key={c.name} className="flex items-center gap-1 rounded px-2 py-1.5 pl-10 text-muted-foreground hover:bg-muted">
|
|
<Folder className="h-3.5 w-3.5" /> {c.name}
|
|
</div>
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="space-y-4">
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<Breadcrumb>
|
|
<BreadcrumbList>
|
|
<BreadcrumbItem><BreadcrumbLink>My files</BreadcrumbLink></BreadcrumbItem>
|
|
<BreadcrumbSeparator />
|
|
<BreadcrumbItem><BreadcrumbLink>Projects</BreadcrumbLink></BreadcrumbItem>
|
|
</BreadcrumbList>
|
|
</Breadcrumb>
|
|
<div className="ml-auto flex items-center gap-2">
|
|
<div className="relative">
|
|
<Search className="absolute left-2 top-2.5 h-3.5 w-3.5 text-muted-foreground" />
|
|
<Input placeholder="Search files…" className="h-8 w-56 pl-7" />
|
|
</div>
|
|
<Button size="sm" variant="outline" className="gap-1.5"><FolderPlus className="h-3.5 w-3.5" /> New folder</Button>
|
|
<Button size="sm" variant="outline" className="gap-1.5"><Share2 className="h-3.5 w-3.5" /> Share</Button>
|
|
<Button size="sm" className="gap-1.5"><Upload className="h-3.5 w-3.5" /> Upload</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardContent className="p-0">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Name</TableHead>
|
|
<TableHead>Size</TableHead>
|
|
<TableHead>Modified</TableHead>
|
|
<TableHead>Visibility</TableHead>
|
|
<TableHead className="w-10"></TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{mockFolders.slice(0, 2).map((f) => (
|
|
<TableRow key={f.name}>
|
|
<TableCell className="font-medium"><span className="inline-flex items-center gap-2"><Folder className="h-4 w-4 text-muted-foreground" />{f.name}</span></TableCell>
|
|
<TableCell className="text-muted-foreground">—</TableCell>
|
|
<TableCell className="text-muted-foreground">2d ago</TableCell>
|
|
<TableCell><Badge variant="outline">Private</Badge></TableCell>
|
|
<TableCell><Button variant="ghost" size="icon" className="h-7 w-7"><MoreHorizontal className="h-4 w-4" /></Button></TableCell>
|
|
</TableRow>
|
|
))}
|
|
{mockFiles.map((f) => (
|
|
<TableRow key={f.id}>
|
|
<TableCell className="font-medium">{f.name}</TableCell>
|
|
<TableCell>{f.size}</TableCell>
|
|
<TableCell className="text-muted-foreground">{f.uploaded}</TableCell>
|
|
<TableCell>
|
|
<Badge variant={f.status === "Active" ? "secondary" : "outline"}>
|
|
{f.status === "Active" ? "Link" : f.status}
|
|
</Badge>
|
|
</TableCell>
|
|
<TableCell><Button variant="ghost" size="icon" className="h-7 w-7"><MoreHorizontal className="h-4 w-4" /></Button></TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</AppShell>
|
|
);
|
|
} |