mirror of
https://github.com/ClipFusion-org/clipfusion.git
synced 2025-08-03 14:45:09 +00:00
ui: home page basic layout implemented
This commit is contained in:
parent
a96b74eeb4
commit
07bfee1b64
@ -1,4 +1,14 @@
|
||||
services:
|
||||
web-development:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./src/Dockerfile
|
||||
target: development
|
||||
ports:
|
||||
- "3001:3000"
|
||||
volumes:
|
||||
- "./src:/app/src:ro"
|
||||
- "./public:/app/public:ro"
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
|
24
package-lock.json
generated
24
package-lock.json
generated
@ -9,6 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.1.1",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
||||
"@radix-ui/react-dialog": "^1.1.14",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
@ -1063,6 +1064,29 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-aspect-ratio": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz",
|
||||
"integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
|
@ -10,6 +10,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.1.1",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.7",
|
||||
"@radix-ui/react-dialog": "^1.1.14",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
|
@ -12,6 +12,22 @@ RUN \
|
||||
else echo "Lockfile not found." && exit 1; \
|
||||
fi
|
||||
|
||||
FROM base AS development
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
CMD ["/bin/sh", "-c", "\
|
||||
if [ -f yarn.lock ]; then yarn run dev; \
|
||||
elif [ -f package-lock.json ]; then npm run dev; \
|
||||
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run dev; \
|
||||
else echo \"Lockfile not found.\" && exit 1; \
|
||||
fi \
|
||||
"]
|
||||
|
||||
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
|
@ -34,7 +34,7 @@ export default function RootLayout({
|
||||
<ThemeProvider>
|
||||
<SidebarProvider>
|
||||
<Dashboard/>
|
||||
<main>
|
||||
<main className="w-full">
|
||||
{children}
|
||||
</main>
|
||||
</SidebarProvider>
|
||||
|
@ -4,19 +4,60 @@ import { ReactNode } from "react";
|
||||
import { useLiveQuery } from "dexie-react-hooks";
|
||||
import { db } from "@/lib/db";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ListIcon, PlusIcon } from "lucide-react";
|
||||
import { Toggle } from "@/components/ui/toggle";
|
||||
import Search from "@/components/search";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { AspectRatio } from "@/components/ui/aspect-ratio";
|
||||
import { Card } from "@/components/ui/card";
|
||||
|
||||
const Project = (): ReactNode => {
|
||||
return (
|
||||
<AspectRatio ratio={16 / 9}>
|
||||
<Card className=" rounded-lg shadow-md p-4 w-full h-full">
|
||||
<h3 className="text-lg font-semibold">Project Title</h3>
|
||||
<p className="text-sm text-gray-600">Project description goes here.</p>
|
||||
</Card>
|
||||
</AspectRatio>
|
||||
)
|
||||
};
|
||||
|
||||
export default function Home(): ReactNode {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const projectsCount = useLiveQuery(() => {
|
||||
return db.projects.count();
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-5">
|
||||
<div className="p-5 w-full">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<SidebarTrigger size="lg"/>
|
||||
<h2 className="font-bold text-4xl">Project Library</h2>
|
||||
<h2 className="font-bold break-keep text-xl sm:text-2xl md:text-3xl lg:text-4xl leading-none">Project Library</h2>
|
||||
<Label className="text-muted-foreground text-sm">(Found {projectsCount != undefined ? projectsCount : '-'} projects)</Label>
|
||||
</div>
|
||||
<div className="flex flex-row items-center justify-between sticky top-0 bg-background gap-2 mt-3 pb-2 pt-2 w-full overscroll-none z-50">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<Button>
|
||||
<PlusIcon/> {!isMobile && "New Project"}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<Toggle variant="outline">
|
||||
<ListIcon/> {!isMobile && "Select Projects"}
|
||||
</Toggle>
|
||||
<Search placeholder="Search Projects"/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 mt-5">
|
||||
<Project/>
|
||||
<Project/>
|
||||
<Project/>
|
||||
<Project/>
|
||||
<Project/>
|
||||
<Project/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ export default function Settings(): ReactNode {
|
||||
<div className="p-5">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<SidebarTrigger/>
|
||||
<h1 className="text-4xl font-bold">Settings</h1>
|
||||
<h2 className="font-bold break-keep text-xl sm:text-2xl md:text-3xl lg:text-4xl leading-none">Settings</h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -30,7 +30,7 @@ const items: DashboardItem[] = [
|
||||
export const Dashboard = (): ReactNode => {
|
||||
return (
|
||||
<Sidebar>
|
||||
<SidebarHeader className="flex justify-center items-center">
|
||||
<SidebarHeader className="flex justify-center items-center mt-2">
|
||||
<ClipFusionLogo width="30" height="30">
|
||||
<p className="font-bold text-xl select-none">Community</p>
|
||||
</ClipFusionLogo>
|
||||
|
11
src/components/ui/aspect-ratio.tsx
Normal file
11
src/components/ui/aspect-ratio.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
"use client"
|
||||
|
||||
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
|
||||
|
||||
function AspectRatio({
|
||||
...props
|
||||
}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
|
||||
return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />
|
||||
}
|
||||
|
||||
export { AspectRatio }
|
92
src/components/ui/card.tsx
Normal file
92
src/components/ui/card.tsx
Normal file
@ -0,0 +1,92 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card"
|
||||
className={cn(
|
||||
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-header"
|
||||
className={cn(
|
||||
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-title"
|
||||
className={cn("leading-none font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-description"
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-action"
|
||||
className={cn(
|
||||
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-content"
|
||||
className={cn("px-6", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-footer"
|
||||
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardAction,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
}
|
Loading…
Reference in New Issue
Block a user