Recreate Next.js source — shadcn components, chart, types, hooks
Source files were untracked and lost during reset. Recreated: - page.tsx (full 3-tab dashboard), layout.tsx, globals.css (shadcn theme) - types.ts, api.ts, utils.ts - strategy-card.tsx, equity-chart.tsx, positions-panel.tsx - ui/ (7 shadcn wrappers: card, badge, button, table, tabs, sheet, collapsible, select) - Config files: next.config.ts, tsconfig.json, postcss.config.mjs, components.json
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const badgeVariants = {
|
||||
default: "border-transparent bg-primary text-primary-foreground",
|
||||
secondary: "border-transparent bg-secondary text-secondary-foreground",
|
||||
destructive: "border-transparent bg-destructive text-destructive-foreground",
|
||||
outline: "text-foreground",
|
||||
};
|
||||
|
||||
function Badge({
|
||||
className,
|
||||
variant = "default",
|
||||
...props
|
||||
}: React.ComponentProps<"div"> & { variant?: keyof typeof badgeVariants }) {
|
||||
return (
|
||||
<div
|
||||
data-slot="badge"
|
||||
className={cn(
|
||||
"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",
|
||||
badgeVariants[variant],
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Badge };
|
||||
@@ -0,0 +1,37 @@
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function Button({
|
||||
className,
|
||||
variant = "default",
|
||||
size = "default",
|
||||
...props
|
||||
}: React.ComponentProps<"button"> & {
|
||||
variant?: "default" | "ghost" | "outline";
|
||||
size?: "default" | "sm" | "icon";
|
||||
}) {
|
||||
const variants: Record<string, string> = {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
};
|
||||
const sizes: Record<string, string> = {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
icon: "h-9 w-9",
|
||||
};
|
||||
return (
|
||||
<button
|
||||
data-slot="button"
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
variants[variant],
|
||||
sizes[size],
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Button };
|
||||
@@ -0,0 +1,37 @@
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card"
|
||||
className={cn(
|
||||
"group/card flex flex-col gap-[--card-spacing] overflow-hidden rounded-xl bg-card text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return <div data-slot="card-header" className={cn("flex flex-col gap-1.5 px-[--card-spacing] pt-[--card-spacing]", className)} {...props} />;
|
||||
}
|
||||
|
||||
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return <div data-slot="card-title" className={cn("font-semibold leading-none tracking-tight", className)} {...props} />;
|
||||
}
|
||||
|
||||
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return <div data-slot="card-description" className={cn("text-muted-foreground text-sm", className)} {...props} />;
|
||||
}
|
||||
|
||||
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return <div data-slot="card-content" className={cn("px-[--card-spacing]", className)} {...props} />;
|
||||
}
|
||||
|
||||
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return <div data-slot="card-footer" className={cn("flex items-center px-[--card-spacing] pb-[--card-spacing]", className)} {...props} />;
|
||||
}
|
||||
|
||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
||||
@@ -0,0 +1,47 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface CollapsibleContextType {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}
|
||||
const CollapsibleContext = React.createContext<CollapsibleContextType | null>(null);
|
||||
|
||||
function Collapsible({ open, onOpenChange, className, children, ...props }: React.ComponentProps<"div"> & CollapsibleContextType) {
|
||||
return (
|
||||
<CollapsibleContext.Provider value={{ open, onOpenChange }}>
|
||||
<div data-slot="collapsible" className={cn("flex flex-col gap-2", className)} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
</CollapsibleContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function CollapsibleTrigger({ className, children, ...props }: React.ComponentProps<"button">) {
|
||||
const ctx = React.useContext(CollapsibleContext);
|
||||
return (
|
||||
<button
|
||||
data-slot="collapsible-trigger"
|
||||
className={cn("flex items-center gap-2 text-sm font-medium [&[data-state=open]>svg]:rotate-180", className)}
|
||||
onClick={() => ctx?.onOpenChange(!ctx?.open)}
|
||||
data-state={ctx?.open ? "open" : "closed"}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function CollapsibleContent({ className, children, ...props }: React.ComponentProps<"div">) {
|
||||
const ctx = React.useContext(CollapsibleContext);
|
||||
if (!ctx?.open) return null;
|
||||
return (
|
||||
<div data-slot="collapsible-content" className={cn("overflow-hidden data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down", className)} data-state={ctx.open ? "open" : "closed"} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
||||
@@ -0,0 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
|
||||
function Select({ value, onChange, className, children, ...props }: React.ComponentProps<"select"> & { onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void }) {
|
||||
return (
|
||||
<select
|
||||
data-slot="select"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
className={cn(
|
||||
"border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full 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 focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
||||
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
||||
export { Select };
|
||||
@@ -0,0 +1,42 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
function Sheet({ open, onOpenChange, children }: { open: boolean; onOpenChange: (open: boolean) => void; children: React.ReactNode }) {
|
||||
if (!open) return null;
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm" onClick={() => onOpenChange(false)}>
|
||||
<div className="fixed inset-y-0 right-0 z-50 flex" onClick={(e) => e.stopPropagation()}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SheetContent({ side = "right", className, children, ...props }: React.ComponentProps<"div"> & { side?: "right" | "left" }) {
|
||||
return (
|
||||
<div
|
||||
data-slot="sheet-content"
|
||||
className={cn(
|
||||
"bg-background flex h-full flex-col shadow-lg",
|
||||
side === "right" ? "ml-auto" : "mr-auto",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return <div data-slot="sheet-header" className={cn("flex flex-col gap-1.5 p-4", className)} {...props} />;
|
||||
}
|
||||
|
||||
function SheetTitle({ className, ...props }: React.ComponentProps<"h2">) {
|
||||
return <h2 data-slot="sheet-title" className={cn("text-lg font-semibold", className)} {...props} />;
|
||||
}
|
||||
|
||||
export { Sheet, SheetContent, SheetHeader, SheetTitle };
|
||||
@@ -0,0 +1,28 @@
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function Table({ className, ...props }: React.ComponentProps<"table">) {
|
||||
return <table data-slot="table" className={cn("w-full caption-bottom text-sm", className)} {...props} />;
|
||||
}
|
||||
|
||||
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
|
||||
return <thead data-slot="table-header" className={cn("[&_tr]:border-b", className)} {...props} />;
|
||||
}
|
||||
|
||||
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
|
||||
return <tbody data-slot="table-body" className={cn("[&_tr:last-child]:border-0", className)} {...props} />;
|
||||
}
|
||||
|
||||
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
||||
return <tr data-slot="table-row" className={cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className)} {...props} />;
|
||||
}
|
||||
|
||||
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
||||
return <th data-slot="table-head" className={cn("h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0", className)} {...props} />;
|
||||
}
|
||||
|
||||
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
||||
return <td data-slot="table-cell" className={cn("p-2 align-middle [&:has([role=checkbox])]:pr-0", className)} {...props} />;
|
||||
}
|
||||
|
||||
export { Table, TableHeader, TableBody, TableRow, TableHead, TableCell };
|
||||
@@ -0,0 +1,51 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const TabsContext = React.createContext<{ value: string; onValueChange: (v: string) => void } | null>(null);
|
||||
|
||||
function Tabs({ value, onValueChange, className, children, ...props }: React.ComponentProps<"div"> & { value: string; onValueChange: (v: string) => void }) {
|
||||
return (
|
||||
<TabsContext.Provider value={{ value, onValueChange }}>
|
||||
<div data-slot="tabs" className={cn("flex flex-col", className)} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
</TabsContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function TabsList({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return <div data-slot="tabs-list" className={cn("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", className)} {...props} />;
|
||||
}
|
||||
|
||||
function TabsTrigger({ value, className, children, ...props }: React.ComponentProps<"button"> & { value: string }) {
|
||||
const ctx = React.useContext(TabsContext);
|
||||
const active = ctx?.value === value;
|
||||
return (
|
||||
<button
|
||||
data-slot="tabs-trigger"
|
||||
data-state={active ? "active" : "inactive"}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||
className,
|
||||
)}
|
||||
onClick={() => ctx?.onValueChange(value)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function TabsContent({ value, className, children, ...props }: React.ComponentProps<"div"> & { value: string }) {
|
||||
const ctx = React.useContext(TabsContext);
|
||||
if (ctx?.value !== value) return null;
|
||||
return (
|
||||
<div data-slot="tabs-content" className={cn("flex-1 outline-none", className)} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
||||
Reference in New Issue
Block a user