Compare commits

..

20 Commits

Author SHA1 Message Date
464872e973 Merge branch 'staging' of http://35.207.46.142/Wodey/wodey-prototype into feature/home_page 2025-04-27 11:06:35 +00:00
5717a1058a Merge pull request 'feature/sidebar' (#3) from feature/sidebar into staging
Reviewed-on: http://35.207.46.142/Wodey/wodey-prototype/pulls/3
2025-04-27 10:01:29 +00:00
iamkiddy
82856a6779 feat: add PlayGroundPage component to render PlayGround 2025-04-27 02:42:55 +00:00
iamkiddy
7d7412bbc8 Refactor code structure for improved readability and maintainability 2025-04-27 01:51:24 +00:00
iamkiddy
e89568fece Merge branch 'feature/sidebar' of http://35.207.46.142/Wodey/wodey-prototype into feature/sidebar 2025-04-27 00:45:44 +00:00
iamkiddy
ba1df8a261 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.
2025-04-27 00:39:20 +00:00
iamkiddy
e61e5e7ce5 fix: correct translation direction for link label animation in Sidebar component 2025-04-26 23:44:55 +00:00
iamkiddy
4ac05d5079 feat: enhance Sidebar component with menu toggle functionality and improved link interactions 2025-04-26 23:44:55 +00:00
iamkiddy
24d95e4ac4 feat: implement RecentDesign and SideNav components with sidebar navigation 2025-04-26 23:44:55 +00:00
iamkiddy
039c34ffdb refactor: remove unnecessary return type annotation from Sidebar component 2025-04-26 23:44:55 +00:00
iamkiddy
3de81bd07a feat: update dependencies and add new icons
- Added `lucide-react` dependency.
- Updated `next` version to 15.3.1.
- Added new icons: design-icon.png, home-icon.png, logo.png, menu-icon.png.
- Added recent images: recent-image-1.png, recent-image-2.png, recent-image-3.png, recent-image-4.png, recent-image-5.png.
- Updated devDependencies: added `@eslint/eslintrc`, `@tailwindcss/postcss`, and ensured `typescript` is included.
2025-04-26 23:44:55 +00:00
iamkiddy
b74bb4e0eb fix: correct translation direction for link label animation in Sidebar component 2025-04-26 23:15:44 +00:00
iamkiddy
7a63c50eff feat: enhance Sidebar component with menu toggle functionality and improved link interactions 2025-04-26 23:10:45 +00:00
iamkiddy
3225ed2394 feat: implement RecentDesign and SideNav components with sidebar navigation 2025-04-26 22:48:39 +00:00
4169e0973c Merge pull request 'Feature: Added Trash page with sub tabs for' (#2) from feature/trash-page into staging
Reviewed-on: http://35.207.46.142/Wodey/wodey-prototype/pulls/2
2025-04-26 22:08:40 +00:00
pious2847
26b9b3ca55 Style: Enhance Tabs appearance on Trash page 2025-04-26 21:40:41 +00:00
pious2847
0412ef3f92 updated page background 2025-04-26 21:13:23 +00:00
pious2847
9dca6a71fc Feature: Added Trash page with sub tabs for
-Ebooks
-Images
-Videos
-Audios
2025-04-26 20:50:07 +00:00
iamkiddy
b7200cc1fd refactor: remove unnecessary return type annotation from Sidebar component 2025-04-26 20:26:25 +00:00
iamkiddy
a5364ba345 feat: update dependencies and add new icons
- Added `lucide-react` dependency.
- Updated `next` version to 15.3.1.
- Added new icons: design-icon.png, home-icon.png, logo.png, menu-icon.png.
- Added recent images: recent-image-1.png, recent-image-2.png, recent-image-3.png, recent-image-4.png, recent-image-5.png.
- Updated devDependencies: added `@eslint/eslintrc`, `@tailwindcss/postcss`, and ensured `typescript` is included.
2025-04-26 20:18:30 +00:00
39 changed files with 7022 additions and 12 deletions

View File

@ -0,0 +1,28 @@
import Image from "next/image";
export interface Trash {
file: string,
description: string,
filetype: string,
filesize: string,
}
const TrashCards = ({ file, description, filetype, filesize }: Trash) => {
return (
<div className="w-[191px] h-[195px] flex flex-col overflow-hidden rounded-sm bg-white shadow-sm hover:transform hover:scale-105 transition-transform duration-300 ease-in-out">
<Image src={file} alt={description} width={191} height={150} className="w-[191px] h-[150px] rounded-sm object-cover min-h-[140px]" />
<div className="flex flex-col gap-1 p-2">
<p className="text-sm font-medium truncate">{description}</p>
<div className="flex gap-1 items-center align-middle p-0">
<p className="text-xs text-gray-500 ">{filetype}</p>{" "}
.{" "}
<p className="text-xs text-gray-500">{filesize}</p>
</div>
</div>
</div>
);
}
export default TrashCards;

View File

@ -0,0 +1,20 @@
import Image from 'next/image'
import React from 'react'
export interface EmptyRecordsProps {
image: string,
shortDescription: string,
longDescription: string,
}
export default function EmptyRecords({ image, shortDescription, longDescription }: EmptyRecordsProps) {
return (
<div className='h-[100%] p-10 w-full flex flex-col justify-center items-center gap-[10px]'>
<Image src={image} alt={shortDescription} width={240} height={240} />
<h5 className='text-2xl font-bold '>{shortDescription}</h5>
<p className='text-gray-500 md:w-[550px] text-center w-fit'>
{longDescription}
</p>
</div>
)
}

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

@ -0,0 +1,24 @@
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 min-h-screen">
<div className="fixed left-0 top-0 h-screen">
<SideNav />
</div>
<div className="flex flex-col w-full ml-[380px]">
<div className="fixed top-0 right-0 left-[380px] z-10">
<Navbar />
</div>
<main className="flex-1 p-6 bg-[#F3F3F3] mt-[75px]">{children}</main>
</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

@ -0,0 +1,7 @@
import PlayGround from "@/components/custom/Play_Ground";
export default function PlayGroundPage() {
return (
<PlayGround />
);
}

View File

@ -0,0 +1,77 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import TrashCards, { Trash } from "@/app/components/cards/TrashCards";
import EmptyRecords from "@/app/components/common/EmptyRecords";
const TrashPage = () => {
const trashData: Trash[] = [
{
file: "/images/image1.png",
description: "Elephants drinking water",
filetype: "image",
filesize: "74MB"
},
{
file: "/images/image2.png",
description: "wonderful sunrise in an aug...",
filetype: "image",
filesize: "7MB"
},
{
file: "/images/image3.png",
description: "Beautiful selective focus sh...",
filetype: "image",
filesize: "23MB"
},
{
file: "/images/image4.png",
description: "Urban double exposure port...",
filetype: "image",
filesize: "18MB"
},
{
file: "/images/image5.png",
description: "Closeup shot of a beautiful...",
filetype: "image",
filesize: "56KB"
}
]
return (
<div className="w-full h-screen flex flex-col p-10 bg-[#F3F3F3]">
<Tabs defaultValue="ebooks" className="w-full">
<TabsList className="w-full md:w-fit bg-transparent">
<TabsTrigger value="ebooks" className="border-b-2 border-transparent data-[state=active]:border-b-primary rounded-none data-[state=active]:shadow-none data-[state=active]:bg-transparent">Ebooks</TabsTrigger>
<TabsTrigger value="images" className="border-b-2 border-transparent data-[state=active]:border-b-primary rounded-none data-[state=active]:shadow-none data-[state=active]:bg-transparent">Images</TabsTrigger>
<TabsTrigger value="videos" className="border-b-2 border-transparent data-[state=active]:border-b-primary rounded-none data-[state=active]:shadow-none data-[state=active]:bg-transparent">Videos</TabsTrigger>
<TabsTrigger value="audios" className="border-b-2 border-transparent data-[state=active]:border-b-primary rounded-none data-[state=active]:shadow-none data-[state=active]:bg-transparent">Audios</TabsTrigger>
</TabsList>
<TabsContent value="ebooks">
<EmptyRecords image="/images/noEbook.png" longDescription="Any ebooks you trashed will end up here. Youll have 30 days to restore them before theyre automatically deleted from your Trash." shortDescription="Theres nothing in your Trash" />
</TabsContent>
<TabsContent value="images">
<div className="flex-col flex gap-4 mt-4">
<div className="flex items-center bg-gray-200/20 p-2 rounded-md ">
<p className="text-sm font-medium">Any images youve trashed can be found here. Please note that the images deleted from the Trash wont be removed from the existing ebooks. The images will only be deleted if those ebooks are deleted.</p>
</div>
<div className="flex flex-wrap md:flex-nowrap gap-4 justify-center md:justify-start">
{trashData.map((data, index) => (
<TrashCards key={index} {...data} />
))}
</div>
</div>
</TabsContent>
<TabsContent value="videos">
<EmptyRecords image="/images/noVideo.png" longDescription="Any videos you trashed will end up here. Youll have 30 days to restore them before theyre automatically deleted from your Trash." shortDescription="Theres nothing in your Trash" />
</TabsContent>
<TabsContent value="audios">
<EmptyRecords image="/images/noAudio.png" longDescription="Any audios you trashed will end up here. Youll have 30 days to restore them before theyre automatically deleted from your Trash." shortDescription="Theres nothing in your Trash" />
</TabsContent>
</Tabs>
</div>
);
}
export default TrashPage;

View File

@ -1,27 +1,166 @@
@import "tailwindcss";
@import "tw-animate-css";
:root {
--background: #ffffff;
--foreground: #171717;
}
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-sideNavColor:#010313;
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}
body {
background: var(--background);
color: var(--foreground);
.hero_img {
background-color: #010313D9;
background-image: url("/assets/89f1cacd4041e59eb162ffcb0f8080dc179fe415.png");
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
background-blend-mode: multiply;
height: 170px;
width: 1045px;
border-radius: 10px;
padding: 8px;
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 40px;
padding-right: 40px;
}
.hero_text {
display: flex;
flex-direction: column;
gap: 10px;
color: #ffffff;
width: 476px;
text-align: left;
}
.hero_text h3 {
font-size: 20px;
font-weight: 700;
line-height: 30px;
font-family: sans-serif;
margin: 0;
}
.hero_text p {
font-size: 14px;
font-weight: 400;
line-height: 21px;
font-family: Arial, Helvetica, sans-serif;
}

21
components.json Normal file
View File

@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}

View File

@ -0,0 +1,92 @@
'use client'
import Image from 'next/image';
import { CopyPlus, Trash2, Plus, X } from 'lucide-react';
import { useState } from 'react';
interface Card {
id: number;
isEditing: boolean;
}
export default function Frame() {
const [cards, setCards] = useState<Card[]>([]);
const [nextId, setNextId] = useState(1);
const handleAddCard = () => {
setCards([...cards, { id: nextId, isEditing: true }]);
setNextId(nextId + 1);
};
const handleDeleteCard = (id: number) => {
setCards(cards.filter(card => card.id !== id));
};
const totalPages = cards.length + 1;
return (
<div className="min-h-screen flex flex-col items-center justify-center">
<div className="w-[450px] flex items-center justify-between px-4 py-2 mb-2" style={{ minHeight: 40 }}>
<span className="text-[#2633B9] text-[14px] font-[#1A237E400]">Page 1/{totalPages}</span>
<div className="flex gap-2">
<CopyPlus
size={18}
className="cursor-pointer text-[#1A237E] hover:text-blue-600"
onClick={handleAddCard}
/>
<Trash2
size={18}
className="cursor-pointer text-[#1A237E] hover:text-red-600"
onClick={() => handleDeleteCard(0)}
/>
</div>
</div>
<div className="flex flex-col items-center gap-8">
<div className="w-[450px] flex flex-col items-center">
<div className="w-[410px] h-[510px] flex items-center justify-center">
<Image src="/pdf-image.png" alt="Excerpt Card" width={410} height={510} style={{ objectFit: 'contain' }} />
</div>
</div>
{cards.map((card, index) => (
<div key={card.id} className="w-[450px] flex flex-col items-center">
<div className="w-full flex items-center justify-between px-4 py-2 mb-2" style={{ minHeight: 40 }}>
<span className="text-[#2633B9] text-[14px] font-[#1A237E400]">Page {index + 2}/{totalPages}</span>
<div className="flex gap-2">
<CopyPlus
size={18}
className="cursor-pointer text-[#1A237E] hover:text-blue-600"
onClick={handleAddCard}
/>
<Trash2
size={18}
className="cursor-pointer text-[#1A237E] hover:text-red-600"
onClick={() => handleDeleteCard(card.id)}
/>
</div>
</div>
<div className="w-[410px] h-[510px] bg-white rounded-lg shadow-md">
</div>
</div>
))}
<div className="w-[450px] flex justify-center">
<button
onClick={handleAddCard}
className="flex justify-center items-center gap-2 py-2 border-2 rounded-xs text-[#1A237E] font-medium bg-white hover:bg-blue-50 transition-colors shadow-sm"
style={{ borderColor: '#D9D7D7', width: 410 }}
>
<Plus size={20} className="text-[#1A237E]" />
<span className="text-center text-[16px] font-[400]">Add new page</span>
</button>
</div>
</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

@ -0,0 +1,9 @@
import Frame from "./Frame";
export default function PlayGround() {
return (
<div className="w-full">
<Frame />
</div>
);
}

View File

@ -0,0 +1,102 @@
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 = [
{
icon: "/recent-image-1.png",
title: "Good morning Gabe ...",
},
{
icon: "/recent-image-2.png",
title: "Daphne's first eBook...",
},
{
icon: "/recent-image-3.png",
title: "Story of my life (Story...",
},
{
icon: "/recent-image-4.png",
title: "Good morning Gabe ...",
},
{
icon: "/recent-image-5.png",
title: "A fantastic saga, the...",
},
];
/**
* RecentDesign Component
* Displays a sidebar with recent designs and a trash section
*/
export default function RecentDesign() {
return (
<div className="bg-white border-t md:border-t-0 md:border-r border-[#D9D7D7] w-full md:w-[300px] flex flex-col h-auto md:h-screen justify-between p-4 md:px-4 md:pt-6 md:pb-4">
{/* Logo and Title Section */}
<div>
<div className="flex flex-col items-center mb-6 md:mb-12">
<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 */}
<div className="text-[#27275A] text-[12px] font-[400] mb-2 pl-1">Recent designs</div>
<div className="grid grid-cols-2 md:flex md:flex-col gap-2">
{recentDesigns.map((design, idx) => (
<div
key={idx}
className="flex items-center bg-white rounded-lg py-2 px-2 hover:bg-[#F5F6FA] group transition cursor-pointer"
>
<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={28}
height={28}
className="w-5 h-5 md:w-7 md:h-7"
/>
</div>
{/* Design Title */}
<span className="flex-1 text-[10px] text-[#27275A] truncate max-w-[100px] md:max-w-[120px] font-[400]">
{design.title}
</span>
{/* Action Buttons */}
<div className="ml-auto">
<Button variant="ghost" size="icon" className="h-10 w-10 p-1">
<div className="flex items-center gap-0.5 md:gap-1 pr-5">
<Button variant="ghost" size="icon" className="h-7 w-7 md:h-8 md:w-8 p-0 hover:bg-[#e6e6e8]">
<ExternalLink className="text-[#27275A] bg-[#f2f2f3] border border-gray-200 rounded-[4px] p-1 w-7 h-7 md:w-8 md:h-8" />
</Button>
<Button variant="ghost" size="icon" className="h-7 w-7 md:h-8 md:w-8 p-0 hover:bg-[#e6e6e8]">
<Ellipsis className="text-[#27275A] bg-[#f2f2f3] border border-gray-200 rounded-[4px] p-1 w-7 h-7 md:w-8 md:h-8" />
</Button>
</div>
</Button>
</div>
</div>
))}
</div>
</div>
{/* Trash Section */}
<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

@ -0,0 +1,15 @@
import Sidebar from "./Side_bar";
import RecentDesign from "./Recent_Design";
export default function SideNav() {
return (
<div className="flex h-screen">
<div className="h-full">
<Sidebar />
</div>
<div className="h-full">
<RecentDesign />
</div>
</div>
);
}

View File

@ -0,0 +1,77 @@
"use client";
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";
const links = [
{
icon: "/home-icon.png",
label: "Home",
path: "/"
},
{
icon: "/design-icon.png",
label: "Design St.",
path: "/design"
}
];
export default function Sidebar() {
const pathname = usePathname();
const [isMenuOpen, setIsMenuOpen] = useState(false);
return (
<div className={`bg-[#050616] w-full md:w-[80px] h-auto md:h-screen transition-all duration-300 ease-in-out ${isMenuOpen ? 'md:w-[200px]' : ''}`}>
<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">
<Button
variant="ghost"
size="icon"
className="mb-5 hover:bg-[#1a1c2b]/50"
onClick={() => setIsMenuOpen(!isMenuOpen)}
>
<Menu className="h-6 w-6 text-white" />
</Button>
{/* Navigation Links */}
{links.map((link) => (
<div
key={link.path}
className={`flex flex-col items-center cursor-pointer group`}
>
<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"
priority={link.path === "/"} // Prioritize loading home icon
/>
</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`}>
{link.label}
</p>
</div>
))}
</div>
</div>
</div>
);
}

59
components/ui/button.tsx Normal file
View File

@ -0,0 +1,59 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
destructive:
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
icon: "size-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot : "button"
return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
}
export { Button, buttonVariants }

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 }

66
components/ui/tabs.tsx Normal file
View File

@ -0,0 +1,66 @@
"use client"
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import { cn } from "@/lib/utils"
function Tabs({
className,
...props
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
return (
<TabsPrimitive.Root
data-slot="tabs"
className={cn("flex flex-col gap-2", className)}
{...props}
/>
)
}
function TabsList({
className,
...props
}: React.ComponentProps<typeof TabsPrimitive.List>) {
return (
<TabsPrimitive.List
data-slot="tabs-list"
className={cn(
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
className
)}
{...props}
/>
)
}
function TabsTrigger({
className,
...props
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
return (
<TabsPrimitive.Trigger
data-slot="tabs-trigger"
className={cn(
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
/>
)
}
function TabsContent({
className,
...props
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
return (
<TabsPrimitive.Content
data-slot="tabs-content"
className={cn("flex-1 outline-none", className)}
{...props}
/>
)
}
export { Tabs, TabsList, TabsTrigger, TabsContent }

6
lib/utils.ts Normal file
View File

@ -0,0 +1,6 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

5865
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9,9 +9,15 @@
"lint": "next lint"
},
"dependencies": {
"lucide-react": "^0.503.0",
"next": "15.3.1",
"@radix-ui/react-slot": "^1.2.0",
"@radix-ui/react-tabs": "^1.1.9",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^3.2.0"
"react-icons": "^5.5.0"
},
"devDependencies": {
@ -23,6 +29,14 @@
"eslint": "^9",
"eslint-config-next": "15.3.1",
"tailwindcss": "^4",
"tw-animate-css": "^1.2.8",
"typescript": "^5"
}
},
"pnpm": {
"onlyBuiltDependencies": [
"sharp",
"unrs-resolver"
]
},
"packageManager": "pnpm@10.9.0+sha512.0486e394640d3c1fb3c9d43d49cf92879ff74f8516959c235308f5a8f62e2e19528a65cdc2a3058f587cde71eba3d5b56327c8c33a97e4c4051ca48a10ca2d5f"
}

View File

@ -8,6 +8,21 @@ importers:
.:
dependencies:
'@radix-ui/react-slot':
specifier: ^1.2.0
version: 1.2.0(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-tabs':
specifier: ^1.1.9
version: 1.1.9(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
clsx:
specifier: ^2.1.1
version: 2.1.1
lucide-react:
specifier: ^0.503.0
version: 0.503.0(react@19.1.0)
next:
specifier: 15.3.1
version: 15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@ -17,6 +32,9 @@ importers:
react-dom:
specifier: ^19.0.0
version: 19.1.0(react@19.1.0)
tailwind-merge:
specifier: ^3.2.0
version: 3.2.0
react-icons:
specifier: ^5.5.0
version: 5.5.0(react@19.1.0)
@ -45,6 +63,9 @@ importers:
tailwindcss:
specifier: ^4
version: 4.1.4
tw-animate-css:
specifier: ^1.2.8
version: 1.2.8
typescript:
specifier: ^5
version: 5.8.3
@ -305,6 +326,155 @@ packages:
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
engines: {node: '>=12.4.0'}
'@radix-ui/primitive@1.1.2':
resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==}
'@radix-ui/react-collection@1.1.4':
resolution: {integrity: sha512-cv4vSf7HttqXilDnAnvINd53OTl1/bjUYVZrkFnA7nwmY9Ob2POUy0WY0sfqBAe1s5FyKsyceQlqiEGPYNTadg==}
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
'@radix-ui/react-compose-refs@1.1.2':
resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-context@1.1.2':
resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-direction@1.1.1':
resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-id@1.1.1':
resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-presence@1.1.4':
resolution: {integrity: sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==}
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
'@radix-ui/react-primitive@2.1.0':
resolution: {integrity: sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==}
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
'@radix-ui/react-roving-focus@1.1.7':
resolution: {integrity: sha512-C6oAg451/fQT3EGbWHbCQjYTtbyjNO1uzQgMzwyivcHT3GKNEmu1q3UuREhN+HzHAVtv3ivMVK08QlC+PkYw9Q==}
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
'@radix-ui/react-slot@1.2.0':
resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-tabs@1.1.9':
resolution: {integrity: sha512-KIjtwciYvquiW/wAFkELZCVnaNLBsYNhTNcvl+zfMAbMhRkcvNuCLXDDd22L0j7tagpzVh/QwbFpwAATg7ILPw==}
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
'@radix-ui/react-use-callback-ref@1.1.1':
resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-use-controllable-state@1.2.2':
resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-use-effect-event@0.0.2':
resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-use-layout-effect@1.1.1':
resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
@ -675,9 +845,16 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
class-variance-authority@0.7.1:
resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@ -1290,6 +1467,11 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
lucide-react@0.503.0:
resolution: {integrity: sha512-HGGkdlPWQ0vTF8jJ5TdIqhQXZi6uh3LnNgfZ8MHiuxFfX3RZeA79r2MW2tHAZKlAVfoNE8esm3p+O6VkIvpj6w==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@ -1627,6 +1809,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
tailwind-merge@3.2.0:
resolution: {integrity: sha512-FQT/OVqCD+7edmmJpsgCsY820RTD5AkBryuG5IUqR5YQZSdj5xlH5nLgH7YPths7WsLPSpSBNneJdM8aS8aeFA==}
tailwindcss@4.1.4:
resolution: {integrity: sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==}
@ -1654,6 +1839,9 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tw-animate-css@1.2.8:
resolution: {integrity: sha512-AxSnYRvyFnAiZCUndS3zQZhNfV/B77ZhJ+O7d3K6wfg/jKJY+yv6ahuyXwnyaYA9UdLqnpCwhTRv9pPTBnPR2g==}
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@ -1927,6 +2115,131 @@ snapshots:
'@nolyfill/is-core-module@1.0.39': {}
'@radix-ui/primitive@1.1.2': {}
'@radix-ui/react-collection@1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-context': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-slot': 1.2.0(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-context@1.1.2(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-direction@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-id@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-primitive@2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/react-slot': 1.2.0(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-roving-focus@1.1.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
'@radix-ui/react-collection': 1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-context': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-direction': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-id': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-slot@1.2.0(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-tabs@1.1.9(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
'@radix-ui/react-context': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-direction': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-id': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-roving-focus': 1.1.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@rtsao/scc@1.1.0': {}
'@rushstack/eslint-patch@1.11.0': {}
@ -2299,8 +2612,14 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
class-variance-authority@0.7.1:
dependencies:
clsx: 2.1.1
client-only@0.0.1: {}
clsx@2.1.1: {}
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@ -3060,6 +3379,10 @@ snapshots:
dependencies:
js-tokens: 4.0.0
lucide-react@0.503.0(react@19.1.0):
dependencies:
react: 19.1.0
math-intrinsics@1.1.0: {}
merge2@1.4.1: {}
@ -3459,6 +3782,8 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
tailwind-merge@3.2.0: {}
tailwindcss@4.1.4: {}
tapable@2.2.1: {}
@ -3485,6 +3810,8 @@ snapshots:
tslib@2.8.1: {}
tw-animate-css@1.2.8: {}
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1

BIN
public/design-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

BIN
public/home-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

BIN
public/images/image1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

BIN
public/images/image2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

BIN
public/images/image3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

BIN
public/images/image4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
public/images/image5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

BIN
public/images/noAudio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
public/images/noEbook.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
public/images/noVideo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
public/menu-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

BIN
public/pdf-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
public/recent-image-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
public/recent-image-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
public/recent-image-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
public/recent-image-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
public/recent-image-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB