feat: Implement Creator Layout and Pages

- Added CreatorLayout component for consistent layout structure.
- Created CreatorPage with a simple header.
- Introduced TrashPage with tabs for managing trashed items, including images and empty states.
- Developed Navbar component for navigation with search functionality and notifications.
- Added RecentDesign component to display recent designs with action buttons.
- Implemented SideNav component to house Sidebar and RecentDesign.
- Created Sidebar component for navigation links with responsive design.
- Added Input component for consistent styling across forms.
- Updated package.json to include new dependencies and set package manager.
This commit is contained in:
iamkiddy 2025-04-27 00:39:20 +00:00
parent e61e5e7ce5
commit ba1df8a261
11 changed files with 134 additions and 5897 deletions

20
app/creator/layout.tsx Normal file
View File

@ -0,0 +1,20 @@
import SideNav from "@/components/custom/Side_Nav";
import Navbar from "@/components/custom/Nav_bar";
export default function CreatorLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<div className="flex">
<SideNav />
<div className="flex flex-col w-full">
<Navbar />
<body className="antialiased bg-[#F3F3F3]">{children}</body>
</div>
</div>
</html>
);
}

7
app/creator/page.tsx Normal file
View File

@ -0,0 +1,7 @@
export default function CreatorPage() {
return (
<div className="text-black">
<h1>Creator</h1>
</div>
)
}

View File

@ -1,7 +1,7 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import TrashCards, { Trash } from "../components/cards/TrashCards";
import EmptyRecords from "../components/common/EmptyRecords";
import TrashCards, { Trash } from "@/app/components/cards/TrashCards";
import EmptyRecords from "@/app/components/common/EmptyRecords";
const TrashPage = () => {
const trashData: Trash[] = [

View File

@ -1,8 +1,8 @@
import SideNav from "@/components/Side_Nav";
export default function Home() {
return (
<div>
<SideNav />
<div className="flex">
<div>Home</div>
</div>
);
}

View File

@ -0,0 +1,34 @@
import { Bell } from 'lucide-react';
import { Search } from 'lucide-react';
import { Input } from '@/components/ui/input';
export default function Navbar() {
return (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end', padding: '24px 40px', background: 'white', width: '100%', height: '75px' }}>
<div style={{ flex: 1, display: 'flex', justifyContent: 'flex-end', marginRight: 120 }}>
<div style={{ display: 'flex', alignItems: 'center', background: '#F2F4F8', borderRadius: '10px', padding: '8px 16px', minWidth: 350 }}>
<Search size={20} style={{ color: '#6B7280', marginRight: 8 }} />
<Input
type="text"
placeholder="Search ebooks, folders, and uploads"
className="bg-transparent text-[#6B7280] text-base w-[250px] focus-visible:ring-0 focus-visible:ring-offset-0 border-0 focus:border-0"
/>
</div>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 24 }}>
<div style={{ position: 'relative', cursor: 'pointer' }}>
<Bell size={22} style={{ color: '#222' }} />
<span style={{ position: 'absolute', top: -2, right: 0, width: 9, height: 9, background: '#FF3B30', borderRadius: '50%', border: '1.5px solid white' }} />
</div>
<div style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}>
<div style={{ width: 32, height: 32, borderRadius: '50%', background: '#FFD600', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 600, color: '#222', fontSize: 14, position: 'relative', zIndex: 1 }}>
D
</div>
<div style={{ width: 32, height: 32, borderRadius: '50%', background: 'white', border: '1px solid #E5E7EB', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 20, color: '#222', cursor: 'pointer', marginLeft: -8, position: 'relative', zIndex: 0 }}>
+
</div>
</div>
</div>
</div>
);
}

View File

@ -1,5 +1,7 @@
import Image from "next/image";
import { ExternalLink, Ellipsis, Trash2 } from 'lucide-react';
import Link from "next/link";
import { Button } from "@/components/ui/button";
// Sample data for recent designs
const recentDesigns = [
@ -35,7 +37,13 @@ export default function RecentDesign() {
{/* Logo and Title Section */}
<div>
<div className="flex flex-col items-center mb-6 md:mb-12">
<img src="/logo.png" alt="Wodey logo" className="w-[120px] md:w-[157px] h-auto md:h-[53px]" />
<Image
src="/logo.png"
alt="Wodey logo"
width={157}
height={53}
className="w-[120px] md:w-[157px] h-auto md:h-[53px]"
/>
</div>
{/* Recent Designs Header */}
@ -50,7 +58,13 @@ export default function RecentDesign() {
>
{/* Design Icon */}
<div className="w-6 h-6 md:w-8 md:h-8 flex items-center justify-center mr-2">
<Image src={design.icon} alt="icon" width={24} height={24} className="w-5 h-5 md:w-7 md:h-7" />
<Image
src={design.icon}
alt="icon"
width={28}
height={28}
className="w-5 h-5 md:w-7 md:h-7"
/>
</div>
{/* Design Title */}
@ -59,22 +73,24 @@ export default function RecentDesign() {
</span>
{/* Action Buttons */}
<button className="p-1 rounded hover:bg-gray-100 transition">
<Button variant="ghost" size="icon" className="h-8 w-8 p-1">
<div className="flex items-center gap-1 md:gap-2">
<ExternalLink className="text-[#27275A] bg-[#f2f2f3] border border-gray-200 rounded-[8px] p-1 w-4 h-4 md:w-5 md:h-5" />
<Ellipsis className="text-[#27275A] bg-[#f2f2f3] border border-gray-200 rounded-[8px] p-1 w-4 h-4 md:w-5 md:h-5" />
</div>
</button>
</Button>
</div>
))}
</div>
</div>
{/* Trash Section */}
<div className="flex items-center gap-2 pl-1 cursor-pointer hover:bg-[#F5F6FA] rounded-lg p-2 mt-4 md:mt-0">
<Trash2 className="text-[#27275A] w-[16px] md:w-[20px]" />
<span className="text-[#27275A] text-[12px] md:text-[14px] font-[400]">Trash</span>
</div>
<Button variant="ghost" className="flex items-center gap-2 p-2 hover:bg-[#F5F6FA] rounded-lg mt-4 md:mt-0 w-full justify-start">
<Link href="/trash" className="flex items-center gap-2">
<Trash2 className="text-[#27275A] w-[16px] md:w-[20px]" />
<span className="text-[#27275A] text-[12px] md:text-[14px] font-[400]">Trash</span>
</Link>
</Button>
</div>
);
}

View File

@ -3,6 +3,8 @@
import Image from "next/image";
import { usePathname } from "next/navigation";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Menu } from "lucide-react";
// Navigation links configuration
const links = [
@ -31,17 +33,14 @@ export default function Sidebar() {
<div className="flex md:flex-col items-center justify-center gap-4 p-4 md:pt-10">
{/* Menu Icon */}
<div className="flex md:flex-col items-center gap-4 md:gap-6">
<div
className="cursor-pointer hover:opacity-80 transition-opacity duration-200 mb-5"
<Button
variant="ghost"
size="icon"
className="mb-5 hover:bg-[#1a1c2b]/50"
onClick={() => setIsMenuOpen(!isMenuOpen)}
>
<Image
src="/menu-icon.png"
alt="logo"
width={24}
height={24}
/>
</div>
<Menu className="h-6 w-6 text-white" />
</Button>
{/* Navigation Links */}
{links.map((link) => (
@ -49,19 +48,27 @@ export default function Sidebar() {
key={link.path}
className={`flex flex-col items-center cursor-pointer group`}
>
{/* Link Icon Container */}
<div className={`p-2 rounded-lg transition-colors duration-200 ${pathname === link.path ? 'bg-[#1a1c2b]' : 'group-hover:bg-[#1a1c2b]/50'}`}>
<Button
variant="ghost"
size="icon"
className={`p-2 rounded-lg transition-colors duration-200 ${
pathname === link.path ? 'bg-[#1a1c2b]' : 'group-hover:bg-[#1a1c2b]/50'
}`}
>
<Image
src={link.icon}
alt={link.label}
width={24}
height={24}
className="group-hover:opacity-80 transition-opacity duration-200"
className="group-hover:opacity-80 transition-opacity duration-200"
priority={link.path === "/"} // Prioritize loading home icon
/>
</div>
</Button>
{/* Link Label */}
<p className={`text-white text-xs mt-1 transition-all duration-300 ease-in-out ${isMenuOpen ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-4'} group-hover:opacity-80`}>
<p className={`text-white text-xs mt-1 transition-all duration-300 ease-in-out ${
isMenuOpen ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-4'
} group-hover:opacity-80`}>
{link.label}
</p>
</div>

21
components/ui/input.tsx Normal file
View File

@ -0,0 +1,21 @@
import * as React from "react"
import { cn } from "@/lib/utils"
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
<input
type={type}
data-slot="input"
className={cn(
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className
)}
{...props}
/>
)
}
export { Input }

5865
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,15 +15,11 @@
"@radix-ui/react-tabs": "^1.1.9",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.503.0",
"next": "15.3.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^3.2.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
@ -40,5 +36,6 @@
"sharp",
"unrs-resolver"
]
}
},
"packageManager": "pnpm@10.9.0+sha512.0486e394640d3c1fb3c9d43d49cf92879ff74f8516959c235308f5a8f62e2e19528a65cdc2a3058f587cde71eba3d5b56327c8c33a97e4c4051ca48a10ca2d5f"
}