ui: home page basic layout implemented

This commit is contained in:
corgifist 2025-07-22 03:02:02 +03:00
parent a96b74eeb4
commit 07bfee1b64
10 changed files with 210 additions and 15 deletions

View File

@ -1,4 +1,14 @@
services: services:
web-development:
build:
context: .
dockerfile: ./src/Dockerfile
target: development
ports:
- "3001:3000"
volumes:
- "./src:/app/src:ro"
- "./public:/app/public:ro"
web: web:
build: build:
context: . context: .

24
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@hookform/resolvers": "^5.1.1", "@hookform/resolvers": "^5.1.1",
"@radix-ui/react-aspect-ratio": "^1.1.7",
"@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-label": "^2.1.7", "@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-separator": "^1.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": { "node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",

View File

@ -10,6 +10,7 @@
}, },
"dependencies": { "dependencies": {
"@hookform/resolvers": "^5.1.1", "@hookform/resolvers": "^5.1.1",
"@radix-ui/react-aspect-ratio": "^1.1.7",
"@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-label": "^2.1.7", "@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-separator": "^1.1.7",

View File

@ -12,6 +12,22 @@ RUN \
else echo "Lockfile not found." && exit 1; \ else echo "Lockfile not found." && exit 1; \
fi 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 FROM base AS builder
WORKDIR /app WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules

View File

@ -34,7 +34,7 @@ export default function RootLayout({
<ThemeProvider> <ThemeProvider>
<SidebarProvider> <SidebarProvider>
<Dashboard/> <Dashboard/>
<main> <main className="w-full">
{children} {children}
</main> </main>
</SidebarProvider> </SidebarProvider>

View File

@ -4,19 +4,60 @@ import { ReactNode } from "react";
import { useLiveQuery } from "dexie-react-hooks"; import { useLiveQuery } from "dexie-react-hooks";
import { db } from "@/lib/db"; import { db } from "@/lib/db";
import { Label } from "@/components/ui/label"; 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 { export default function Home(): ReactNode {
const isMobile = useIsMobile();
const projectsCount = useLiveQuery(() => { const projectsCount = useLiveQuery(() => {
return db.projects.count(); return db.projects.count();
}); });
return ( return (
<div className="p-5"> <div className="p-5 w-full">
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
<SidebarTrigger size="lg"/> <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> <Label className="text-muted-foreground text-sm">(Found {projectsCount != undefined ? projectsCount : '-'} projects)</Label>
</div> </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> </div>
); );
}; };

View File

@ -6,7 +6,7 @@ export default function Settings(): ReactNode {
<div className="p-5"> <div className="p-5">
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
<SidebarTrigger/> <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>
</div> </div>
); );

View File

@ -30,7 +30,7 @@ const items: DashboardItem[] = [
export const Dashboard = (): ReactNode => { export const Dashboard = (): ReactNode => {
return ( return (
<Sidebar> <Sidebar>
<SidebarHeader className="flex justify-center items-center"> <SidebarHeader className="flex justify-center items-center mt-2">
<ClipFusionLogo width="30" height="30"> <ClipFusionLogo width="30" height="30">
<p className="font-bold text-xl select-none">Community</p> <p className="font-bold text-xl select-none">Community</p>
</ClipFusionLogo> </ClipFusionLogo>

View 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 }

View 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,
}