diff --git a/app/globals.css b/app/globals.css
index 6178ebe..60318f1 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,151 +1,66 @@
@import "tailwindcss";
-@import "tw-animate-css";
-@custom-variant dark (&:is(.dark *));
+@theme inline {
+ /* Updated to use the CSS variable generated by Next.js */
+ --font-mono: var(--font-vt323), monospace;
+ --font-sans: var(--font-vt323), monospace;
+ --radius: 0rem;
+}
:root {
- --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);
- --destructive-foreground: 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);
- --radius: 0.625rem;
- --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);
+ /* Pure Black & Green Terminal Theme */
+ --background: #000000;
+ /* Brightened the green to a classic phosphor green */
+ --foreground: #33ff00;
+
+ --card: #050505;
+ --card-foreground: #33ff00;
+
+ --popover: #000000;
+ --popover-foreground: #33ff00;
+
+ --primary: #33ff00;
+ --primary-foreground: #000000;
+
+ --secondary: #002200;
+ --secondary-foreground: #33ff00;
+
+ --muted: #001100;
+ --muted-foreground: #008800;
+
+ --accent: #003300;
+ --accent-foreground: #33ff00;
+
+ --destructive: #cc0000;
+ --destructive-foreground: #000000;
+
+ --border: #004400;
+ --input: #004400;
+ --ring: #33ff00;
+
+ --radius: 0rem;
}
.dark {
- --background: oklch(0.145 0 0);
- --foreground: oklch(0.985 0 0);
- --card: oklch(0.145 0 0);
- --card-foreground: oklch(0.985 0 0);
- --popover: oklch(0.145 0 0);
- --popover-foreground: oklch(0.985 0 0);
- --primary: oklch(0.985 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.396 0.141 25.723);
- --destructive-foreground: oklch(0.637 0.237 25.331);
- --border: oklch(0.269 0 0);
- --input: oklch(0.269 0 0);
- --ring: oklch(0.439 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(0.269 0 0);
- --sidebar-ring: oklch(0.439 0 0);
-}
-
-@theme inline {
- /* optional: --font-sans, --font-serif, --font-mono if they are applied in the layout.tsx */
- --font-mono: "JetBrains Mono", "Fira Code", "Courier New", monospace;
- --font-sans: "JetBrains Mono", "Fira Code", "Courier New", monospace;
-
- --color-background: #0a0a0a;
- --color-foreground: #00ff00; /* Terminal Green */
-
- --color-card: #111111;
- --color-card-foreground: #e5e5e5;
-
- --color-popover: #111111;
- --color-popover-foreground: #e5e5e5;
-
- --color-primary: #00ff00;
- --color-primary-foreground: #000000;
-
- --color-secondary: #333333;
- --color-secondary-foreground: #ffffff;
-
- --color-muted: #222222;
- --color-muted-foreground: #888888;
-
- --color-accent: #00ff00;
- --color-accent-foreground: #000000;
-
- --color-destructive: #ff0000;
- --color-destructive-foreground: #ffffff;
-
- --color-border: #333333;
- --color-input: #222222;
- --color-ring: #00ff00;
-
- --radius-sm: 0px;
- --radius-md: 0px;
- --radius-lg: 0px;
- --color-background: var(--background);
- --color-foreground: var(--foreground);
- --color-card: var(--card);
- --color-card-foreground: var(--card-foreground);
- --color-popover: var(--popover);
- --color-popover-foreground: var(--popover-foreground);
- --color-primary: var(--primary);
- --color-primary-foreground: var(--primary-foreground);
- --color-secondary: var(--secondary);
- --color-secondary-foreground: var(--secondary-foreground);
- --color-muted: var(--muted);
- --color-muted-foreground: var(--muted-foreground);
- --color-accent: var(--accent);
- --color-accent-foreground: var(--accent-foreground);
- --color-destructive: var(--destructive);
- --color-destructive-foreground: var(--destructive-foreground);
- --color-border: var(--border);
- --color-input: var(--input);
- --color-ring: var(--ring);
- --color-chart-1: var(--chart-1);
- --color-chart-2: var(--chart-2);
- --color-chart-3: var(--chart-3);
- --color-chart-4: var(--chart-4);
- --color-chart-5: var(--chart-5);
- --radius-sm: calc(var(--radius) - 4px);
- --radius-md: calc(var(--radius) - 2px);
- --radius-lg: var(--radius);
- --radius-xl: calc(var(--radius) + 4px);
- --color-sidebar: var(--sidebar);
- --color-sidebar-foreground: var(--sidebar-foreground);
- --color-sidebar-primary: var(--sidebar-primary);
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
- --color-sidebar-accent: var(--sidebar-accent);
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
- --color-sidebar-border: var(--sidebar-border);
- --color-sidebar-ring: var(--sidebar-ring);
+ --background: #000000;
+ --foreground: #33ff00;
+ --card: #050505;
+ --card-foreground: #33ff00;
+ --popover: #000000;
+ --popover-foreground: #33ff00;
+ --primary: #33ff00;
+ --primary-foreground: #000000;
+ --secondary: #002200;
+ --secondary-foreground: #33ff00;
+ --muted: #001100;
+ --muted-foreground: #008800;
+ --accent: #003300;
+ --accent-foreground: #33ff00;
+ --destructive: #cc0000;
+ --destructive-foreground: #000000;
+ --border: #004400;
+ --input: #004400;
+ --ring: #33ff00;
}
@layer base {
@@ -156,24 +71,26 @@
@apply bg-background text-foreground font-mono antialiased selection:bg-primary selection:text-primary-foreground;
}
- /* Custom Scrollbar for that retro feel */
+ /* Retro Terminal Scrollbar */
::-webkit-scrollbar {
- width: 10px;
- height: 10px;
+ width: 14px;
}
::-webkit-scrollbar-track {
- background: #0a0a0a;
- border-left: 1px solid #333;
+ background: #000000;
+ border-left: 1px solid #003300;
}
::-webkit-scrollbar-thumb {
- background: #333;
- border: 1px solid #0a0a0a;
+ background: #003300;
+ border: 1px solid #33ff00;
+ box-shadow: inset 0 0 4px rgba(51, 255, 0, 0.5);
}
::-webkit-scrollbar-thumb:hover {
- background: #00ff00;
+ background: #33ff00;
+ box-shadow: 0 0 10px #33ff00;
}
}
+/* CRT Scanline Effect */
.scanline {
background: linear-gradient(
to bottom,
@@ -190,9 +107,10 @@
bottom: 0;
left: 0;
z-index: 9999;
- opacity: 0.15;
+ opacity: 0.3;
}
+/* Text Glow */
.glow-text {
- text-shadow: 0 0 5px rgba(0, 255, 0, 0.5);
+ text-shadow: 0 0 5px rgba(51, 255, 0, 0.7);
}
diff --git a/app/layout.tsx b/app/layout.tsx
index f018b95..6a9c787 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,10 +1,10 @@
import type React from "react"
import type { Metadata } from "next"
-import { JetBrains_Mono } from "next/font/google"
+import { VT323 } from "next/font/google"
import "./globals.css"
import Link from "next/link"
-const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"] })
+const vt323 = VT323({ weight: "400", subsets: ["latin"], variable: "--font-vt323" })
export const metadata: Metadata = {
title: "mytmux.life - Terminal Multiplexer Configurator",
@@ -19,7 +19,7 @@ export default function RootLayout({
}>) {
return (
-
+
diff --git a/components/terminal-visualizer.tsx b/components/terminal-visualizer.tsx
index a240874..693d181 100644
--- a/components/terminal-visualizer.tsx
+++ b/components/terminal-visualizer.tsx
@@ -1,5 +1,7 @@
"use client"
+import type React from "react"
+
import { useEffect, useRef, useState } from "react"
import type { LayoutNode } from "@/app/page"
@@ -8,6 +10,15 @@ interface TerminalVisualizerProps {
activePaneId: number
}
+interface MatrixStream {
+ x: number
+ y: number
+ speed: number
+ chars: string[]
+ length: number
+ firstChar: string
+}
+
export default function TerminalVisualizer({ layout, activePaneId }: TerminalVisualizerProps) {
const canvasRef = useRef(null)
const [containerSize, setContainerSize] = useState({ width: 0, height: 0 })
@@ -15,15 +26,26 @@ export default function TerminalVisualizer({ layout, activePaneId }: TerminalVis
const lastTimeRef = useRef(0)
const cursorBlinkRef = useRef(true)
+ // Matrix Rain Refs
+ const streamsRef = useRef([])
+ const mouseRef = useRef({ x: 0, y: 0 })
+ const lastSpawnTimeRef = useRef(0)
+
// Colors
- const BG_COLOR = "#0a0a0a"
- const BORDER_COLOR = "#333333"
- const ACTIVE_BORDER_COLOR = "#00ff00"
- const TEXT_COLOR = "#00ff00"
- const MUTED_TEXT = "#444444"
+ const BG_COLOR = "#000000" // Pure black for hacker vibe
+ const BORDER_COLOR = "#004400" // Dark green border
+ const ACTIVE_BORDER_COLOR = "#33ff00"
+ const TEXT_COLOR = "#33ff00"
+ const MUTED_TEXT = "#006600" // More visible muted green
+ const MATRIX_CHARS = "0123456789ABCDEF"
+
+ const fontFamilyRef = useRef("monospace")
// Handle resize
useEffect(() => {
+ const computedStyle = window.getComputedStyle(document.body)
+ fontFamilyRef.current = computedStyle.fontFamily || "monospace"
+
const handleResize = () => {
if (canvasRef.current && canvasRef.current.parentElement) {
const parent = canvasRef.current.parentElement
@@ -43,6 +65,25 @@ export default function TerminalVisualizer({ layout, activePaneId }: TerminalVis
return () => window.removeEventListener("resize", handleResize)
}, [])
+ const handleMouseMove = (e: React.MouseEvent) => {
+ const rect = e.currentTarget.getBoundingClientRect()
+ mouseRef.current = {
+ x: e.clientX - rect.left,
+ y: e.clientY - rect.top,
+ }
+ }
+
+ const handleTouchMove = (e: React.TouchEvent) => {
+ const rect = e.currentTarget.getBoundingClientRect()
+ const touch = e.touches[0]
+ if (touch) {
+ mouseRef.current = {
+ x: touch.clientX - rect.left,
+ y: touch.clientY - rect.top,
+ }
+ }
+ }
+
// Animation Loop
useEffect(() => {
const animate = (time: number) => {
@@ -51,6 +92,32 @@ export default function TerminalVisualizer({ layout, activePaneId }: TerminalVis
lastTimeRef.current = time
}
+ // Spawn matrix streams from cursor
+ if (time - lastSpawnTimeRef.current > 50) {
+ // Spawn every 50ms
+ const x = mouseRef.current.x
+ const y = mouseRef.current.y
+
+ // Snap to grid columns roughly
+ const colWidth = 14
+ const snappedX = Math.floor(x / colWidth) * colWidth
+
+ // Only spawn if we moved or randomly
+ if (Math.random() > 0.7) {
+ streamsRef.current.push({
+ x: snappedX,
+ y: y,
+ speed: 2 + Math.random() * 3,
+ chars: Array(20)
+ .fill(0)
+ .map(() => MATRIX_CHARS[Math.floor(Math.random() * MATRIX_CHARS.length)]),
+ length: 5 + Math.floor(Math.random() * 8),
+ firstChar: MATRIX_CHARS[Math.floor(Math.random() * MATRIX_CHARS.length)],
+ })
+ lastSpawnTimeRef.current = time
+ }
+ }
+
// Trigger a redraw
draw()
@@ -60,11 +127,7 @@ export default function TerminalVisualizer({ layout, activePaneId }: TerminalVis
animationRef.current = requestAnimationFrame(animate)
return () => cancelAnimationFrame(animationRef.current)
- }) // No dependency array to ensure it always has access to latest props via closure if needed,
- // but actually we should probably use refs for props if we want to avoid re-binding the loop.
- // However, since we call draw() which uses the props, we need to make sure draw() sees the latest props.
- // The best way in React for a canvas loop is often to use refs for the mutable state or just let the effect re-run.
- // Let's optimize:
+ })
// Drawing Logic
const draw = () => {
@@ -87,10 +150,53 @@ export default function TerminalVisualizer({ layout, activePaneId }: TerminalVis
// Draw Layout
drawNode(ctx, layout, 0, 0, width, height)
+
+ // Draw Matrix Rain
+ drawMatrixRain(ctx, width, height)
+ }
+
+ const drawMatrixRain = (ctx: CanvasRenderingContext2D, w: number, h: number) => {
+ ctx.font = `20px ${fontFamilyRef.current}`
+
+ // Update and draw streams
+ for (let i = streamsRef.current.length - 1; i >= 0; i--) {
+ const stream = streamsRef.current[i]
+ stream.y += stream.speed
+
+ // Randomly change characters
+ if (Math.random() > 0.9) {
+ stream.firstChar = MATRIX_CHARS[Math.floor(Math.random() * MATRIX_CHARS.length)]
+ }
+
+ // Draw the stream
+ for (let j = 0; j < stream.length; j++) {
+ const charY = stream.y - j * 20 // Adjusted spacing for larger font
+
+ // Don't draw if off screen (above or below)
+ if (charY > h + 20) continue
+
+ // Opacity fade based on position in tail
+ const opacity = (1 - j / stream.length) * 0.8
+
+ if (j === 0) {
+ // Head of the stream (bright white/green)
+ ctx.fillStyle = `rgba(200, 255, 200, ${opacity})`
+ ctx.fillText(stream.firstChar, stream.x, charY)
+ } else {
+ // Tail (green)
+ ctx.fillStyle = `rgba(51, 255, 0, ${opacity * 0.5})`
+ ctx.fillText(stream.chars[j % stream.chars.length], stream.x, charY)
+ }
+ }
+
+ // Remove if off screen or fully faded
+ if (stream.y - stream.length * 20 > h || stream.y > h + 100) {
+ streamsRef.current.splice(i, 1)
+ }
+ }
}
function drawNode(ctx: CanvasRenderingContext2D, node: LayoutNode, x: number, y: number, w: number, h: number) {
- // Add a small gap for the border
const gap = 2
if (node.type === "pane") {
@@ -114,7 +220,7 @@ export default function TerminalVisualizer({ layout, activePaneId }: TerminalVis
ctx.shadowBlur = 0 // Reset
// Draw Pane ID/Status
- ctx.font = '12px "JetBrains Mono", monospace'
+ ctx.font = `18px ${fontFamilyRef.current}`
ctx.fillStyle = node.id === activePaneId ? TEXT_COLOR : MUTED_TEXT
ctx.fillText(`[${node.id}] zsh`, x + 15, y + 25)
@@ -153,7 +259,13 @@ export default function TerminalVisualizer({ layout, activePaneId }: TerminalVis
return (
-
+
{/* Scanline overlay for the canvas specifically */}
diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx
deleted file mode 100644
index e538a33..0000000
--- a/components/ui/accordion.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-'use client'
-
-import * as React from 'react'
-import * as AccordionPrimitive from '@radix-ui/react-accordion'
-import { ChevronDownIcon } from 'lucide-react'
-
-import { cn } from '@/lib/utils'
-
-function Accordion({
- ...props
-}: React.ComponentProps
) {
- return
-}
-
-function AccordionItem({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AccordionTrigger({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
- svg]:rotate-180',
- className,
- )}
- {...props}
- >
- {children}
-
-
-
- )
-}
-
-function AccordionContent({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
- {children}
-
- )
-}
-
-export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx
deleted file mode 100644
index 9704452..0000000
--- a/components/ui/alert-dialog.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-'use client'
-
-import * as React from 'react'
-import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'
-
-import { cn } from '@/lib/utils'
-import { buttonVariants } from '@/components/ui/button'
-
-function AlertDialog({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-function AlertDialogTrigger({
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AlertDialogPortal({
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AlertDialogOverlay({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AlertDialogContent({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
- )
-}
-
-function AlertDialogHeader({
- className,
- ...props
-}: React.ComponentProps<'div'>) {
- return (
-
- )
-}
-
-function AlertDialogFooter({
- className,
- ...props
-}: React.ComponentProps<'div'>) {
- return (
-
- )
-}
-
-function AlertDialogTitle({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AlertDialogDescription({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AlertDialogAction({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AlertDialogCancel({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export {
- AlertDialog,
- AlertDialogPortal,
- AlertDialogOverlay,
- AlertDialogTrigger,
- AlertDialogContent,
- AlertDialogHeader,
- AlertDialogFooter,
- AlertDialogTitle,
- AlertDialogDescription,
- AlertDialogAction,
- AlertDialogCancel,
-}
diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx
deleted file mode 100644
index e6751ab..0000000
--- a/components/ui/alert.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import * as React from 'react'
-import { cva, type VariantProps } from 'class-variance-authority'
-
-import { cn } from '@/lib/utils'
-
-const alertVariants = cva(
- 'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
- {
- variants: {
- variant: {
- default: 'bg-card text-card-foreground',
- destructive:
- 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90',
- },
- },
- defaultVariants: {
- variant: 'default',
- },
- },
-)
-
-function Alert({
- className,
- variant,
- ...props
-}: React.ComponentProps<'div'> & VariantProps) {
- return (
-
- )
-}
-
-function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
- return (
-
- )
-}
-
-function AlertDescription({
- className,
- ...props
-}: React.ComponentProps<'div'>) {
- return (
-
- )
-}
-
-export { Alert, AlertTitle, AlertDescription }
diff --git a/components/ui/aspect-ratio.tsx b/components/ui/aspect-ratio.tsx
deleted file mode 100644
index 40bb120..0000000
--- a/components/ui/aspect-ratio.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-'use client'
-
-import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio'
-
-function AspectRatio({
- ...props
-}: React.ComponentProps) {
- return
-}
-
-export { AspectRatio }
diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx
deleted file mode 100644
index aa98465..0000000
--- a/components/ui/avatar.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-'use client'
-
-import * as React from 'react'
-import * as AvatarPrimitive from '@radix-ui/react-avatar'
-
-import { cn } from '@/lib/utils'
-
-function Avatar({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AvatarImage({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-function AvatarFallback({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export { Avatar, AvatarImage, AvatarFallback }
diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx
deleted file mode 100644
index fc4126b..0000000
--- a/components/ui/badge.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-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 badgeVariants = cva(
- 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-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 transition-[color,box-shadow] overflow-hidden',
- {
- variants: {
- variant: {
- default:
- 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
- secondary:
- 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
- destructive:
- 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
- outline:
- 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
- },
- },
- defaultVariants: {
- variant: 'default',
- },
- },
-)
-
-function Badge({
- className,
- variant,
- asChild = false,
- ...props
-}: React.ComponentProps<'span'> &
- VariantProps & { asChild?: boolean }) {
- const Comp = asChild ? Slot : 'span'
-
- return (
-
- )
-}
-
-export { Badge, badgeVariants }
diff --git a/components/ui/breadcrumb.tsx b/components/ui/breadcrumb.tsx
deleted file mode 100644
index 1750ff2..0000000
--- a/components/ui/breadcrumb.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import * as React from 'react'
-import { Slot } from '@radix-ui/react-slot'
-import { ChevronRight, MoreHorizontal } from 'lucide-react'
-
-import { cn } from '@/lib/utils'
-
-function Breadcrumb({ ...props }: React.ComponentProps<'nav'>) {
- return
-}
-
-function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
- return (
-
- )
-}
-
-function BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {
- return (
-
- )
-}
-
-function BreadcrumbLink({
- asChild,
- className,
- ...props
-}: React.ComponentProps<'a'> & {
- asChild?: boolean
-}) {
- const Comp = asChild ? Slot : 'a'
-
- return (
-
- )
-}
-
-function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
- return (
-
- )
-}
-
-function BreadcrumbSeparator({
- children,
- className,
- ...props
-}: React.ComponentProps<'li'>) {
- return (
- svg]:size-3.5', className)}
- {...props}
- >
- {children ?? }
-
- )
-}
-
-function BreadcrumbEllipsis({
- className,
- ...props
-}: React.ComponentProps<'span'>) {
- return (
-
-
- More
-
- )
-}
-
-export {
- Breadcrumb,
- BreadcrumbList,
- BreadcrumbItem,
- BreadcrumbLink,
- BreadcrumbPage,
- BreadcrumbSeparator,
- BreadcrumbEllipsis,
-}
diff --git a/components/ui/button-group.tsx b/components/ui/button-group.tsx
deleted file mode 100644
index 09d4430..0000000
--- a/components/ui/button-group.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import { Slot } from '@radix-ui/react-slot'
-import { cva, type VariantProps } from 'class-variance-authority'
-
-import { cn } from '@/lib/utils'
-import { Separator } from '@/components/ui/separator'
-
-const buttonGroupVariants = cva(
- "flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2",
- {
- variants: {
- orientation: {
- horizontal:
- '[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none',
- vertical:
- 'flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none',
- },
- },
- defaultVariants: {
- orientation: 'horizontal',
- },
- },
-)
-
-function ButtonGroup({
- className,
- orientation,
- ...props
-}: React.ComponentProps<'div'> & VariantProps) {
- return (
-
- )
-}
-
-function ButtonGroupText({
- className,
- asChild = false,
- ...props
-}: React.ComponentProps<'div'> & {
- asChild?: boolean
-}) {
- const Comp = asChild ? Slot : 'div'
-
- return (
-
- )
-}
-
-function ButtonGroupSeparator({
- className,
- orientation = 'vertical',
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
-
-export {
- ButtonGroup,
- ButtonGroupSeparator,
- ButtonGroupText,
- buttonGroupVariants,
-}
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
deleted file mode 100644
index f64632d..0000000
--- a/components/ui/button.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-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 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',
- },
- },
- defaultVariants: {
- variant: 'default',
- size: 'default',
- },
- },
-)
-
-function Button({
- className,
- variant,
- size,
- asChild = false,
- ...props
-}: React.ComponentProps<'button'> &
- VariantProps & {
- asChild?: boolean
- }) {
- const Comp = asChild ? Slot : 'button'
-
- return (
-
- )
-}
-
-export { Button, buttonVariants }
diff --git a/components/ui/calendar.tsx b/components/ui/calendar.tsx
deleted file mode 100644
index eaa373e..0000000
--- a/components/ui/calendar.tsx
+++ /dev/null
@@ -1,213 +0,0 @@
-'use client'
-
-import * as React from 'react'
-import {
- ChevronDownIcon,
- ChevronLeftIcon,
- ChevronRightIcon,
-} from 'lucide-react'
-import { DayButton, DayPicker, getDefaultClassNames } from 'react-day-picker'
-
-import { cn } from '@/lib/utils'
-import { Button, buttonVariants } from '@/components/ui/button'
-
-function Calendar({
- className,
- classNames,
- showOutsideDays = true,
- captionLayout = 'label',
- buttonVariant = 'ghost',
- formatters,
- components,
- ...props
-}: React.ComponentProps & {
- buttonVariant?: React.ComponentProps['variant']
-}) {
- const defaultClassNames = getDefaultClassNames()
-
- return (
- svg]:rotate-180`,
- String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
- className,
- )}
- captionLayout={captionLayout}
- formatters={{
- formatMonthDropdown: (date) =>
- date.toLocaleString('default', { month: 'short' }),
- ...formatters,
- }}
- classNames={{
- root: cn('w-fit', defaultClassNames.root),
- months: cn(
- 'flex gap-4 flex-col md:flex-row relative',
- defaultClassNames.months,
- ),
- month: cn('flex flex-col w-full gap-4', defaultClassNames.month),
- nav: cn(
- 'flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between',
- defaultClassNames.nav,
- ),
- button_previous: cn(
- buttonVariants({ variant: buttonVariant }),
- 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
- defaultClassNames.button_previous,
- ),
- button_next: cn(
- buttonVariants({ variant: buttonVariant }),
- 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
- defaultClassNames.button_next,
- ),
- month_caption: cn(
- 'flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)',
- defaultClassNames.month_caption,
- ),
- dropdowns: cn(
- 'w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5',
- defaultClassNames.dropdowns,
- ),
- dropdown_root: cn(
- 'relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md',
- defaultClassNames.dropdown_root,
- ),
- dropdown: cn(
- 'absolute bg-popover inset-0 opacity-0',
- defaultClassNames.dropdown,
- ),
- caption_label: cn(
- 'select-none font-medium',
- captionLayout === 'label'
- ? 'text-sm'
- : 'rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5',
- defaultClassNames.caption_label,
- ),
- table: 'w-full border-collapse',
- weekdays: cn('flex', defaultClassNames.weekdays),
- weekday: cn(
- 'text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none',
- defaultClassNames.weekday,
- ),
- week: cn('flex w-full mt-2', defaultClassNames.week),
- week_number_header: cn(
- 'select-none w-(--cell-size)',
- defaultClassNames.week_number_header,
- ),
- week_number: cn(
- 'text-[0.8rem] select-none text-muted-foreground',
- defaultClassNames.week_number,
- ),
- day: cn(
- 'relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none',
- defaultClassNames.day,
- ),
- range_start: cn(
- 'rounded-l-md bg-accent',
- defaultClassNames.range_start,
- ),
- range_middle: cn('rounded-none', defaultClassNames.range_middle),
- range_end: cn('rounded-r-md bg-accent', defaultClassNames.range_end),
- today: cn(
- 'bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none',
- defaultClassNames.today,
- ),
- outside: cn(
- 'text-muted-foreground aria-selected:text-muted-foreground',
- defaultClassNames.outside,
- ),
- disabled: cn(
- 'text-muted-foreground opacity-50',
- defaultClassNames.disabled,
- ),
- hidden: cn('invisible', defaultClassNames.hidden),
- ...classNames,
- }}
- components={{
- Root: ({ className, rootRef, ...props }) => {
- return (
-
- )
- },
- Chevron: ({ className, orientation, ...props }) => {
- if (orientation === 'left') {
- return (
-
- )
- }
-
- if (orientation === 'right') {
- return (
-
- )
- }
-
- return (
-
- )
- },
- DayButton: CalendarDayButton,
- WeekNumber: ({ children, ...props }) => {
- return (
-
-
- {children}
-
- |
- )
- },
- ...components,
- }}
- {...props}
- />
- )
-}
-
-function CalendarDayButton({
- className,
- day,
- modifiers,
- ...props
-}: React.ComponentProps) {
- const defaultClassNames = getDefaultClassNames()
-
- const ref = React.useRef(null)
- React.useEffect(() => {
- if (modifiers.focused) ref.current?.focus()
- }, [modifiers.focused])
-
- return (
-