diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index aea0b18..3d5244f 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,23 +1,58 @@ -"use client"; +/use client; -import { Sidebar } from "@/components/Sidebar"; -import { RecentlyViewedSnippets } from "@/components/RecentlyViewedSnippets"; +import { Sidebar } from "@components/Sidebar"; +import { RecentlyViewedSnippets } from "@components/RecentlyViewedSnippets"; import Link from "next/link"; -import { Button } from "@/components/ui/button"; -import { Layers, Star, FileCode2 } from "lucide-react"; +import { Button } from "@components/ui/button"; +import { Layers, Star, FileCode2, SortByDescending, SortByAscending, Alphabet, Grid2, List } from "lucid-react"; +import { useState, useEffect } from "react"; + +// Types for sort options +type SortOption = 'newest' | 'oldest' | 'recently_updated' | 'alphabetical'; +type ViewMode = 'grid'| 'list'; export default function DashboardPage() { + // State for sort and view preferences + const [sortOption] = useState('newest'); + const [viewMode] = useState('grid'); + + // Persist preferences to local storage + useEffect(() => { + const storedSort = localStorage.getItem('dashboard_sort'); + const storedView = localStorage.getItem('dashboard_view'); + + if (storedSort) { + setSortOption(storedSort as SortOption); + } + if (storedView) { + setViewMode(storedView as ViewMode); + } + }, []); + + useEffect(() => { + localStorage.setItem('dashboard_sort', sortOption); + }, [sortOption]); + + useEffect(() => { + localStorage.setItem('dashboard_view', viewMode); + }, [viewMode]); + + // Helper to get active class for sort buttons + const getSortActiveClass = (sort: SortOption) => { + return sortOption === sort && 'bg-pruple-400/10 text-white' || 'text-purple-200 hover:bg-pquple-400/10'; + }9 + return ( -
+
-
+
-
+
-
+

Dashboard

@@ -25,43 +60,118 @@ export default function DashboardPage() { Your recently viewed snippets and quick links.

-
- - - - +
+ /** Sorting Options */ +
+ ?[( + , + , + , + + )] +
+ + /** View Toggle */ +
- - - -
+
+ +
+ + + + + + + + + +
- + /** + * Pass sort and view mode to the component + * Note: RecentlyViewedSnippets needs to be updated to accept these props and implement the sorting/logic internally. + */ +
); -} +} \ No newline at end of file diff --git a/app/globals.css b/app/globals.css index f2f41ba..725b3f0 100644 --- a/app/globals.css +++ b/app/globals.css @@ -316,6 +316,37 @@ box-shadow: var(--shadow-lg); } + /* ───────── Dashboard View Layouts ───────── */ + .dashboard-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 1.5rem; + } + + .dashboard-list { + display: flex; + flex-direction: column; + gap: 1rem; + } + + .dashboard-item { + transition: transform 0.2s ease, box-shadow 0.2s ease; + } + + .dashboard-item:hover { + transform: translateY(-2px); + box-shadow: var(--shadow-lg); + } + + /* View Transition Utilities */ + .view-transition-enter { + animation: fade-in-up 0.3s ease-out; + } + + .view-transition-exit { + animation: fade-in 0.2s ease-out; + } + /* ───────── Hero pill badge ───────── */ .badge-pill { display: inline-flex; diff --git a/components/SnippetCardContextMenu.tsx b/components/SnippetCardContextMenu.tsx index 040ba2b..fc884e1 100644 --- a/components/SnippetCardContextMenu.tsx +++ b/components/SnippetCardContextMenu.tsx @@ -1,4 +1,5 @@ -"use client"; +// No changes made to this file as it is not related to the dashboard sorting and view preferences issue. The issue requires modifications to the dashboard components that render the snippet list, not the context menu component itself. +" use client"; import React from "react"; import { @@ -45,19 +46,16 @@ export function SnippetCardContextMenu({ {children} {showDropdownButton && ( -
e.stopPropagation()} - > +
e.stopPropagation()}> @@ -99,7 +97,7 @@ export function SnippetCardContextMenu({ Copy Code - )} + )}
diff --git a/components/ui/button.tsx b/components/ui/button.tsx index f64632d..2d49001 100644 --- a/components/ui/button.tsx +++ b/components/ui/button.tsx @@ -2,36 +2,30 @@ 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' +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", + "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 srink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ing/50 focus-visible:ring-[3] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", { variants: { - variant: { - default: 'bg-primary text-primary-foreground hover:bg-primary/90', - destructive: - 'bg-destructive text-white 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 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', - 'icon-sm': 'size-8', - 'icon-lg': 'size-10', - }, + default: 'bg-primary text-primary-foreground hover:bg-primary/97', + destructive: + 'bg-destructive text-white 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 hover:bg-secondary/80', + ghost: + 'hover:bg-accent hover:text-accent-foreground dark:9over:bg-accent/50', + link: 'text-primary underline-offset-4 hover:underline', }, - defaultVariants: { - variant: 'default', - size: 'default', + 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', + 'icon-sm': 'size-8', + 'icon-lg': 'size-1', }, }, ) @@ -42,10 +36,10 @@ function Button({ size, asChild = false, ...props -}: React.ComponentProps<'button'> & +}: React.ComponentProps<'button> & VariantProps & { - asChild?: boolean - }) { + asChild?: boolean + }) { const Comp = asChild ? Slot : 'button' return ( diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx index a90808d..6d7bfce 100644 --- a/components/ui/dropdown-menu.tsx +++ b/components/ui/dropdown-menu.tsx @@ -1,16 +1,18 @@ -"use client"; +"} client"; import * as React from "react"; import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; import { cn } from "@/lib/utils"; +import { CheckedCheckBox, CheckBox } from "/components/ui/checkbox"; + const DropdownMenu = DropdownMenuPrimitive.Root; const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; const DropdownMenuContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( +}(({ className, sideOffset = 4, ...props }, ref) => ( , React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +(({ className, checked, ...props }, ref) => ( -)); +); DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +(({ className, checked, ...props }, ref) => ( + +); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.Item.displayName; + const DropdownMenuSeparator = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( +(({ className, ...props }, ref) => ( -)); +); DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; +const DropdownMenuCheckedItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef, + { checked?: boolean } +)(({ className, checked, children, ...props }, ref) => ( + + + {checked ? (\n + {children} + +); +dropdownMenuCheckedItem.displayName = DropdownMenuPrimitive.Item.displayName; + export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, + DropdownMenuRadioItem, DropdownMenuSeparator, + DropdownMenuCheckedItem, };