diff --git a/src/app/chart-demo/page.tsx b/src/app/chart-demo/page.tsx
new file mode 100644
index 0000000..a8ed9e5
--- /dev/null
+++ b/src/app/chart-demo/page.tsx
@@ -0,0 +1,114 @@
+"use client"
+
+import React, { useState } from "react"
+import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"
+import { WireframeAnimatedChart } from "@/components/ui/wireframe-animated-chart"
+import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
+import { Button } from "@/components/ui/button"
+
+export default function ChartDemo() {
+ const [loading, setLoading] = useState(false)
+ const [animated, setAnimated] = useState(true)
+
+ const handleToggleLoading = () => {
+ setLoading(prev => !prev)
+ }
+
+ const handleReplayAnimation = () => {
+ setAnimated(false)
+ setTimeout(() => setAnimated(true), 50)
+ }
+
+ return (
+
+
Wireframe Chart Demo
+
+
+
+
+
+
+
+
+
+ Animated Placeholder Chart
+ Cartoonish wireframe chart with animation
+
+
+
+
+ Bar Chart
+ Line Chart
+ Area Chart
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Usage Information
+
+
+
+
This demo showcases the WireframeAnimatedChart component with the following features:
+
+ - Animated data visualization that grows from 0 to target values
+ - Support for bar, line, and area chart types
+ - Loading state with randomized data animation
+ - Cartoonish wireframe styling that matches the project design
+ - Interactive tooltips showing data values
+
+
+ {``}
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/chart-placeholder/page.tsx b/src/app/chart-placeholder/page.tsx
new file mode 100644
index 0000000..cd9deb4
--- /dev/null
+++ b/src/app/chart-placeholder/page.tsx
@@ -0,0 +1,54 @@
+"use client"
+
+import React from "react"
+import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"
+import { WireframeAnimatedChart } from "@/components/ui/wireframe-animated-chart"
+import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
+
+export default function ChartPlaceholder() {
+ return (
+
+
Chart Placeholder Example
+
+
+
+ Wireframe Chart Placeholder
+ Simple cartoonish chart placeholder for prototype designs
+
+
+
+
+ Bar Chart
+ Line Chart
+ Area Chart
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx
new file mode 100644
index 0000000..d6dbd5d
--- /dev/null
+++ b/src/app/dashboard/page.tsx
@@ -0,0 +1,273 @@
+"use client"
+
+import React from "react"
+import * as RechartsPrimitive from "recharts"
+import {
+ Card,
+ CardHeader,
+ CardTitle,
+ CardDescription,
+ CardContent
+} from "@/components/ui/card"
+import {
+ ChartContainer,
+ ChartTooltip,
+ ChartTooltipContent
+} from "@/components/ui/chart"
+import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
+
+// Dummy data for demonstration purposes
+const revenueData = [
+ { month: "Jan", revenue: 4000, expenses: 2400 },
+ { month: "Feb", revenue: 3000, expenses: 1398 },
+ { month: "Mar", revenue: 2000, expenses: 9800 },
+ { month: "Apr", revenue: 2780, expenses: 3908 },
+ { month: "May", revenue: 1890, expenses: 4800 },
+ { month: "Jun", revenue: 2390, expenses: 3800 },
+ { month: "Jul", revenue: 3490, expenses: 4300 },
+]
+
+const expenseCategories = [
+ { name: "Marketing", value: 400 },
+ { name: "Operations", value: 300 },
+ { name: "Sales", value: 300 },
+ { name: "Development", value: 200 },
+ { name: "Admin", value: 100 },
+]
+
+const balanceHistory = [
+ { date: "Jan 1", balance: 10000 },
+ { date: "Feb 1", balance: 12000 },
+ { date: "Mar 1", balance: 9800 },
+ { date: "Apr 1", balance: 11200 },
+ { date: "May 1", balance: 14500 },
+ { date: "Jun 1", balance: 18000 },
+]
+
+export default function Dashboard() {
+ return (
+
+
Financial Dashboard
+
+ {/* Summary Cards */}
+
+
+
+ Total Revenue
+ Current Month
+
+
+ $24,350
+
+
+ +5.2% from last month
+
+
+
+
+
+
+ Total Expenses
+ Current Month
+
+
+ $12,760
+
+
+ +2.4% from last month
+
+
+
+
+
+
+ Net Profit
+ Current Month
+
+
+ $11,590
+
+
+ +8.1% from last month
+
+
+
+
+
+ {/* Revenue vs Expenses Chart */}
+
+
+ Revenue vs Expenses
+ Monthly comparison for the current year
+
+
+
+
+ Bar Chart
+ Line Chart
+
+
+
+ {(props) => (
+
+
+
+
+ (
+
+ )}
+ />
+
+
+
+ )}
+
+
+
+
+ {(props) => (
+
+
+
+
+ (
+
+ )}
+ />
+
+
+
+ )}
+
+
+
+
+
+
+ {/* Expense Breakdown and Balance History */}
+
+ {/* Expense Breakdown */}
+
+
+ Expense Breakdown
+ Current Month
+
+
+
+ {(props) => (
+
+
+ {expenseCategories.map((entry, index) => (
+
+ ))}
+
+ (
+
+ )}
+ />
+
+ )}
+
+
+
+
+ {/* Balance History */}
+
+
+ Account Balance
+ Last 6 months
+
+
+
+ {(props) => (
+
+
+
+
+ (
+
+ )}
+ />
+
+
+ )}
+
+
+
+
+
+ )
+}
diff --git a/src/app/globals.css b/src/app/globals.css
index 6e330db..ac06876 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1,5 +1,6 @@
@import "tailwindcss";
@import "tw-animate-css";
+@import "./wireframe.css";
@custom-variant dark (&:is(.dark *));
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index f7fa87e..5f641c5 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
+import { MainNavigation } from "@/components/main-navigation";
const geistSans = Geist({
variable: "--font-geist-sans",
@@ -25,9 +26,9 @@ export default function RootLayout({
return (
- {children}
+ {children}
);
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 07a01d9..2f538a2 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,3 +1,37 @@
+import Link from 'next/link'
+
export default function Home() {
- return ();
+ return (
+
+
+
Welcome to Financial App
+
+
Access your financial dashboard
+
+ {/* Hand-drawn arrow pointing to button */}
+
+
+
+ View Dashboard
+
+
+ {/* Hand-drawn decorations */}
+
+
+
+ );
}
diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx
new file mode 100644
index 0000000..aff892a
--- /dev/null
+++ b/src/app/settings/page.tsx
@@ -0,0 +1,130 @@
+"use client"
+
+import React from "react"
+import {
+ Card,
+ CardHeader,
+ CardTitle,
+ CardDescription,
+ CardContent,
+ CardFooter
+} from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Label } from "@/components/ui/label"
+import { Switch } from "@/components/ui/switch"
+import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
+
+export default function Settings() {
+ return (
+
+
Settings
+
+
+
+ Account
+ Notifications
+ Appearance
+
+
+
+
+
+ Account Settings
+ Manage your account information
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notification Settings
+ Manage how you receive notifications
+
+
+
+
+
Email Notifications
+
Receive notifications via email
+
+
+
+
+
+
Push Notifications
+
Receive notifications on your device
+
+
+
+
+
+
Marketing Emails
+
Receive marketing and promotional emails
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Appearance Settings
+ Customize how the application looks
+
+
+
+
+
Dark Mode
+
Switch between light and dark mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/app/wireframe.css b/src/app/wireframe.css
new file mode 100644
index 0000000..e0b79cd
--- /dev/null
+++ b/src/app/wireframe.css
@@ -0,0 +1,172 @@
+/* Wireframe Cartoonish Styles */
+/* Custom font for hand-drawn look */
+@import url('https://fonts.googleapis.com/css2?family=Comic+Neue:wght@400;700&display=swap');
+
+/* Global Wireframe Styles */
+.wireframe-mode * {
+ font-family: 'Comic Neue', sans-serif !important;
+ transition: all 0.2s ease;
+}
+
+/* Cartoonish Border Style */
+.wireframe-mode .wireframe-border {
+ border: 2px solid #000 !important;
+ border-radius: 8px !important;
+ box-shadow: 3px 3px 0 #000 !important;
+}
+
+/* Cards */
+.wireframe-mode [data-slot="card"] {
+ background-color: #fff !important;
+ border: 2px solid #000 !important;
+ border-radius: 12px !important;
+ box-shadow: 4px 4px 0 #000 !important;
+ position: relative;
+ overflow: hidden;
+}
+
+/* Buttons */
+.wireframe-mode [data-slot="button"] {
+ background-color: #fff !important;
+ border: 2px solid #000 !important;
+ border-radius: 8px !important;
+ box-shadow: 3px 3px 0 #000 !important;
+ color: #000 !important;
+ font-weight: bold !important;
+ transition: all 0.2s;
+}
+
+.wireframe-mode [data-slot="button"]:hover {
+ transform: translate(-2px, -2px);
+ box-shadow: 5px 5px 0 #000 !important;
+}
+
+.wireframe-mode [data-slot="button"]:active {
+ transform: translate(1px, 1px);
+ box-shadow: 2px 2px 0 #000 !important;
+}
+
+/* Headings and Text */
+.wireframe-mode h1, .wireframe-mode h2, .wireframe-mode h3,
+.wireframe-mode [data-slot="card-title"] {
+ color: #000 !important;
+ font-weight: bold !important;
+ text-decoration: none !important;
+}
+
+/* Tables */
+.wireframe-mode table {
+ border: 2px solid #000 !important;
+}
+
+.wireframe-mode th, .wireframe-mode td {
+ border: 1px solid #000 !important;
+}
+
+/* Inputs */
+.wireframe-mode input, .wireframe-mode textarea, .wireframe-mode select {
+ background-color: #fff !important;
+ border: 2px solid #000 !important;
+ border-radius: 8px !important;
+}
+
+/* Charts */
+.wireframe-mode .recharts-wrapper {
+ border: 2px dashed #000 !important;
+ border-radius: 8px !important;
+ padding: 10px !important;
+}
+
+.wireframe-mode .recharts-cartesian-grid line {
+ stroke: #000 !important;
+ stroke-width: 1px !important;
+ stroke-dasharray: 3 3 !important;
+}
+
+.wireframe-mode .recharts-layer.recharts-bar-rectangle path,
+.wireframe-mode .recharts-layer.recharts-area-area path,
+.wireframe-mode .recharts-layer.recharts-line path {
+ stroke: #000 !important;
+ stroke-width: 2px !important;
+}
+
+/* Chart colors */
+.wireframe-mode .recharts-layer.recharts-bar-rectangle[name="revenue"] path {
+ fill: #a9e3ff !important;
+}
+
+.wireframe-mode .recharts-layer.recharts-bar-rectangle[name="expenses"] path {
+ fill: #ffb5b5 !important;
+}
+
+.wireframe-mode .recharts-layer.recharts-area-area path {
+ fill: #d4d4ff !important;
+}
+
+.wireframe-mode .recharts-sector {
+ stroke: #000 !important;
+ stroke-width: 2px !important;
+}
+
+/* Cartoonish Hand-drawn Elements */
+.wireframe-mode .hand-drawn-circle {
+ border-radius: 50%;
+ border: 2px solid #000;
+ background: white;
+}
+
+.wireframe-mode .hand-drawn-line {
+ height: 2px;
+ background-color: #000;
+ margin: 10px 0;
+}
+
+/* Tooltips */
+.wireframe-mode [data-slot="tooltip-content"] {
+ background-color: #fff !important;
+ border: 2px solid #000 !important;
+ border-radius: 8px !important;
+ box-shadow: 3px 3px 0 #000 !important;
+}
+
+/* Scribble Effects for Headers */
+.wireframe-mode h1::after {
+ content: "";
+ display: block;
+ height: 4px;
+ background-image: url("data:image/svg+xml,%3Csvg width='100' height='4' viewBox='0 0 100 4' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0,1 C5,0 10,3 15,2 C20,1 25,0 30,1 C35,2 40,3 45,2 C50,1 55,0 60,1 C65,2 70,3 75,2 C80,1 85,0 90,1 C95,2 100,3 105,2' stroke='black' fill='none' stroke-width='1'/%3E%3C/svg%3E");
+ background-repeat: repeat-x;
+ margin-top: 4px;
+}
+
+/* Added Paper Texture Background */
+.wireframe-mode [data-slot="card"] {
+ background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23000000' fill-opacity='0.03'%3E%3Cpath d='M0,0 L10,0 L10,10 L0,10 L0,0 Z M20,0 L30,0 L30,10 L20,10 L20,0 Z M40,0 L50,0 L50,10 L40,10 L40,0 Z M60,0 L70,0 L70,10 L60,10 L60,0 Z M80,0 L90,0 L90,10 L80,10 L80,0 Z'/%3E%3C/g%3E%3C/svg%3E") !important;
+}
+
+/* Arrow Notes */
+.wireframe-mode .note {
+ position: relative;
+ background: #fffed1;
+ padding: 15px;
+ border: 1px solid #000;
+ border-radius: 5px;
+ transform: rotate(-1deg);
+ font-family: 'Comic Neue', cursive;
+ font-style: italic;
+ box-shadow: 2px 2px 0 #000;
+}
+
+/* Scribbled Outlines for Elements */
+.wireframe-mode [data-slot="card"]::before {
+ content: "";
+ position: absolute;
+ top: -3px;
+ left: -3px;
+ right: -3px;
+ bottom: -3px;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ border-radius: 14px;
+ pointer-events: none;
+ z-index: -1;
+}
diff --git a/src/components/main-navigation.tsx b/src/components/main-navigation.tsx
new file mode 100644
index 0000000..b4ed831
--- /dev/null
+++ b/src/components/main-navigation.tsx
@@ -0,0 +1,122 @@
+"use client"
+
+import * as React from "react"
+import Link from "next/link"
+import { usePathname } from "next/navigation"
+import { ChevronDown, Home, LayoutDashboard, Settings, User } from "lucide-react"
+
+import {
+ Sidebar,
+ SidebarContent,
+ SidebarFooter,
+ SidebarHeader,
+ SidebarMenu,
+ SidebarMenuItem,
+ SidebarMenuButton,
+ SidebarProvider,
+ SidebarTrigger,
+} from "@/components/ui/sidebar"
+import { Button } from "@/components/ui/button"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger
+} from "@/components/ui/dropdown-menu"
+import { Avatar, AvatarFallback } from "@/components/ui/avatar"
+
+export function MainNavigation({ children }: { children: React.ReactNode }) {
+ const pathname = usePathname()
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ Personal Workspace
+ Team Workspace
+ Project Workspace
+
+
+
+
+
+
+
+
+
+
+ Home
+
+
+
+
+
+
+
+ Dashboard
+
+
+
+
+
+
+
+ Settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{pathname === "/dashboard" ? "Dashboard" : pathname === "/settings" ? "Settings" : "Home"}
+
+
{children}
+
+
+
+ )
+}
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index a2df8dc..f8dd2ad 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -10,13 +10,13 @@ const buttonVariants = cva(
variants: {
variant: {
default:
- "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 wireframe-border",
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",
+ "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 wireframe-border",
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",
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 wireframe-border",
secondary:
- "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80 wireframe-border",
ghost:
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
diff --git a/src/components/ui/sidebar.tsx b/src/components/ui/sidebar.tsx
index 7ffbc07..c689407 100644
--- a/src/components/ui/sidebar.tsx
+++ b/src/components/ui/sidebar.tsx
@@ -374,7 +374,7 @@ function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
data-slot="sidebar-content"
data-sidebar="content"
className={cn(
- "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
+ "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden px-[8px]",
className
)}
{...props}
diff --git a/src/components/ui/wireframe-animated-chart.tsx b/src/components/ui/wireframe-animated-chart.tsx
new file mode 100644
index 0000000..3fc8221
--- /dev/null
+++ b/src/components/ui/wireframe-animated-chart.tsx
@@ -0,0 +1,213 @@
+"use client"
+
+import React, { useState, useEffect } from "react"
+import * as RechartsPrimitive from "recharts"
+import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"
+
+interface WireframeAnimatedChartProps {
+ chartType?: "bar" | "line" | "area"
+ height?: number
+ animated?: boolean
+ loading?: boolean
+}
+
+export function WireframeAnimatedChart({
+ chartType = "bar",
+ height = 300,
+ animated = true,
+ loading = false
+}: WireframeAnimatedChartProps) {
+ // Placeholder data that will be animated
+ const [data, setData] = useState([
+ { month: "Jan", value: 0 },
+ { month: "Feb", value: 0 },
+ { month: "Mar", value: 0 },
+ { month: "Apr", value: 0 },
+ { month: "May", value: 0 },
+ { month: "Jun", value: 0 },
+ ])
+
+ // Target values for final animation state
+ const targetData = [
+ { month: "Jan", value: 400 },
+ { month: "Feb", value: 300 },
+ { month: "Mar", value: 600 },
+ { month: "Apr", value: 200 },
+ { month: "May", value: 500 },
+ { month: "Jun", value: 350 },
+ ]
+
+ // Animation effect
+ useEffect(() => {
+ if (!animated) {
+ setData(targetData)
+ return
+ }
+
+ // If loading is true, use a pulsing animation
+ if (loading) {
+ let direction = 1
+ const interval = setInterval(() => {
+ setData(prev =>
+ prev.map(item => {
+ const randomValue = Math.floor(Math.random() * 300) + 100
+ return { ...item, value: randomValue }
+ })
+ )
+ direction *= -1
+ }, 1500)
+
+ return () => clearInterval(interval)
+ }
+
+ // Animate from 0 to target values
+ let animationFrame: number
+ let startTime: number | null = null
+ const duration = 1500 // milliseconds
+
+ const animateValues = (timestamp: number) => {
+ if (!startTime) startTime = timestamp
+ const elapsed = timestamp - startTime
+ const progress = Math.min(elapsed / duration, 1)
+
+ // Ease-out function for smoother animation
+ const easeOutProgress = 1 - Math.pow(1 - progress, 3)
+
+ const newData = data.map((item, i) => ({
+ ...item,
+ value: Math.floor(targetData[i].value * easeOutProgress)
+ }))
+
+ setData(newData)
+
+ if (progress < 1) {
+ animationFrame = requestAnimationFrame(animateValues)
+ }
+ }
+
+ animationFrame = requestAnimationFrame(animateValues)
+
+ return () => {
+ if (animationFrame) {
+ cancelAnimationFrame(animationFrame)
+ }
+ }
+ }, [animated, loading])
+
+ const chartConfig = {
+ value: { label: "Value", color: "#a9e3ff" }
+ }
+
+ // Render the appropriate chart type
+ const renderChart = (props: any) => {
+ switch (chartType) {
+ case "bar":
+ return (
+
+
+
+
+ (
+
+ )}
+ />
+
+
+ )
+
+ case "line":
+ return (
+
+
+
+
+ (
+
+ )}
+ />
+
+
+ )
+
+ case "area":
+ return (
+
+
+
+
+ (
+
+ )}
+ />
+
+
+ )
+
+ default:
+ return null
+ }
+ }
+
+ return (
+
+
+ {(props) => (
+
+ {renderChart(props)}
+ {loading && (
+
+ )}
+
+ )}
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/ui/wireframe-chart.tsx b/src/components/ui/wireframe-chart.tsx
new file mode 100644
index 0000000..c5cb820
--- /dev/null
+++ b/src/components/ui/wireframe-chart.tsx
@@ -0,0 +1,167 @@
+"use client"
+
+import React from "react"
+import * as RechartsPrimitive from "recharts"
+import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"
+
+interface WireframeChartProps {
+ data: any[]
+ dataKeys: string[]
+ xAxisKey: string
+ chartType: "bar" | "line" | "area" | "pie"
+ height?: number
+ colors?: Record
+}
+
+export function WireframeChart({
+ data,
+ dataKeys,
+ xAxisKey,
+ chartType,
+ height = 300,
+ colors = {}
+}: WireframeChartProps) {
+ // Default wireframe colors
+ const defaultColors = {
+ item1: "#a9e3ff",
+ item2: "#ffb5b5",
+ item3: "#d4d4ff",
+ item4: "#c1f0c1",
+ item5: "#ffecb5"
+ }
+
+ // Merge with provided colors
+ const chartColors = { ...defaultColors, ...colors }
+
+ // Generate config based on dataKeys
+ const config = dataKeys.reduce((acc, key, index) => {
+ const colorKey = `item${index + 1}` as keyof typeof defaultColors
+ acc[key] = {
+ label: key.charAt(0).toUpperCase() + key.slice(1),
+ color: chartColors[colorKey] || "#888888"
+ }
+ return acc
+ }, {} as Record)
+
+ const renderChart = (props: any) => {
+ switch (chartType) {
+ case "bar":
+ return (
+
+
+
+
+ (
+
+ )}
+ />
+ {dataKeys.map((key, index) => (
+
+ ))}
+
+ )
+
+ case "line":
+ return (
+
+
+
+
+ (
+
+ )}
+ />
+ {dataKeys.map((key, index) => (
+
+ ))}
+
+ )
+
+ case "area":
+ return (
+
+
+
+
+ (
+
+ )}
+ />
+ {dataKeys.map((key, index) => (
+
+ ))}
+
+ )
+
+ case "pie":
+ return (
+
+
+ {data.map((entry, index) => (
+
+ ))}
+
+ (
+
+ )}
+ />
+
+ )
+
+ default:
+ return null
+ }
+ }
+
+ return (
+
+
+ {(props) => (
+
+ {renderChart(props)}
+
+ )}
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/ui/wireframe-demo.tsx b/src/components/ui/wireframe-demo.tsx
new file mode 100644
index 0000000..ee46092
--- /dev/null
+++ b/src/components/ui/wireframe-demo.tsx
@@ -0,0 +1,75 @@
+"use client"
+
+import React from "react"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+
+export function WireframeDemo() {
+ return (
+
+
Wireframe Components
+
+
+
+
+
+ Hand-drawn Elements
+
+
+
+
+ Circle
+
+
+ Square
+
+
+ Rotated
+
+
+ Sticky Note
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/ui/wireframe-toggle.tsx b/src/components/ui/wireframe-toggle.tsx
new file mode 100644
index 0000000..daa2e64
--- /dev/null
+++ b/src/components/ui/wireframe-toggle.tsx
@@ -0,0 +1,25 @@
+"use client"
+
+import React, { useState, useEffect } from "react"
+import { Switch } from "@/components/ui/switch"
+import { Label } from "@/components/ui/label"
+
+export function WireframeToggle() {
+ const [enabled, setEnabled] = useState(true)
+
+ useEffect(() => {
+ const body = document.body
+ if (enabled) {
+ body.classList.add('wireframe-mode')
+ } else {
+ body.classList.remove('wireframe-mode')
+ }
+ }, [enabled])
+
+ return (
+
+
+
+
+ )
+}
\ No newline at end of file