Commit 4918e579 authored by Administrator's avatar Administrator

Update 13 files via Son of Anton

parent b02ad490
{
"name": "son-of-anton-frontend",
"version": "1.0.0",
"version": "2.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"lucide-react": "^0.469.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-markdown": "^9.0.1",
"react-router-dom": "^7.1.1",
"react-markdown": "^9.0.1",
"react-syntax-highlighter": "^15.6.1",
"remark-gfm": "^4.0.0"
"remark-gfm": "^4.0.0",
"lucide-react": "^0.469.0",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-popover": "^1.1.4",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-slider": "^1.2.2",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.6",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-avatar": "^1.1.2",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-context-menu": "^2.2.4",
"@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-toggle": "^1.1.1",
"@radix-ui/react-toggle-group": "^1.1.1",
"@radix-ui/react-progress": "^1.1.1",
"@radix-ui/react-alert-dialog": "^1.1.4",
"framer-motion": "^11.18.0",
"sonner": "^1.7.1",
"cmdk": "^1.0.4",
"vaul": "^1.1.2",
"recharts": "^2.15.0",
"react-hot-toast": "^2.5.2",
"input-otp": "^1.4.2",
"react-resizable-panels": "^2.1.7",
"embla-carousel-react": "^8.5.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"tailwind-merge": "^2.6.0",
"date-fns": "^4.1.0",
"react-day-picker": "^9.5.0",
"zustand": "^5.0.3",
"usehooks-ts": "^3.1.0"
},
"devDependencies": {
"@types/react": "^18.3.18",
......@@ -23,6 +58,10 @@
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.17",
"vite": "^6.0.7"
"vite": "^6.0.7",
"@tailwindcss/typography": "^0.5.16",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/container-queries": "^0.1.1",
"tailwindcss-animate": "^1.0.7"
}
}
\ No newline at end of file
import React from "react";
import { cva } from "class-variance-authority";
import { cn } from "../../lib/utils";
const badgeVariants = cva(
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
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",
success: "border-transparent bg-green-500/15 text-green-400 border-green-500/20",
warning: "border-transparent bg-yellow-500/15 text-yellow-400 border-yellow-500/20",
info: "border-transparent bg-blue-500/15 text-blue-400 border-blue-500/20",
accent: "border-transparent bg-primary/15 text-primary border-primary/20",
},
},
defaultVariants: {
variant: "default",
},
}
);
function Badge({ className, variant, ...props }) {
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}
export { Badge, badgeVariants };
\ No newline at end of file
import React from "react";
import { cva } from "class-variance-authority";
import { cn } from "../../lib/utils";
import { Loader2 } from "lucide-react";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 active:scale-[0.98]",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm",
outline: "border border-border bg-transparent hover:bg-white/5 hover:text-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-white/5 hover:text-foreground",
link: "text-primary underline-offset-4 hover:underline",
glow: "bg-primary text-primary-foreground hover:bg-primary/90 shadow-glow hover:shadow-glow-lg",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-11 rounded-lg px-8 text-base",
xl: "h-12 rounded-xl px-10 text-base",
icon: "h-9 w-9",
"icon-sm": "h-8 w-8",
"icon-lg": "h-11 w-11",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
const Button = React.forwardRef(
({ className, variant, size, loading, children, disabled, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
disabled={disabled || loading}
{...props}
>
{loading && <Loader2 className="animate-spin" />}
{children}
</button>
);
}
);
Button.displayName = "Button";
export { Button, buttonVariants };
\ No newline at end of file
import React from "react";
import { cn } from "../../lib/utils";
const Card = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-xl border border-border bg-card text-card-foreground shadow-sm transition-shadow hover:shadow-card-hover",
className
)}
{...props}
/>
));
Card.displayName = "Card";
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
));
CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
<h3 ref={ref} className={cn("font-semibold leading-none tracking-tight text-white", className)} {...props} />
));
CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
<p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
));
CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
));
CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />
));
CardFooter.displayName = "CardFooter";
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
\ No newline at end of file
import React from "react";
import { cn } from "../../lib/utils";
const Input = React.forwardRef(({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-lg border border-border bg-transparent px-3 py-1 text-sm shadow-sm transition-colors",
"file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground",
"placeholder:text-muted-foreground",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
"disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
});
Input.displayName = "Input";
export { Input };
\ No newline at end of file
import { motion, AnimatePresence } from "framer-motion";
/**
* Pre-configured motion variants for common animations.
* Use these instead of raw CSS animations for buttery-smooth UX.
*/
export const fadeIn = {
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
transition: { duration: 0.2 },
};
export const fadeInUp = {
initial: { opacity: 0, y: 12 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: 12 },
transition: { duration: 0.25, ease: "easeOut" },
};
export const fadeInDown = {
initial: { opacity: 0, y: -12 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -12 },
transition: { duration: 0.25, ease: "easeOut" },
};
export const scaleIn = {
initial: { opacity: 0, scale: 0.95 },
animate: { opacity: 1, scale: 1 },
exit: { opacity: 0, scale: 0.95 },
transition: { duration: 0.2, ease: "easeOut" },
};
export const slideInRight = {
initial: { opacity: 0, x: 20 },
animate: { opacity: 1, x: 0 },
exit: { opacity: 0, x: 20 },
transition: { duration: 0.25, ease: "easeOut" },
};
export const slideInLeft = {
initial: { opacity: 0, x: -20 },
animate: { opacity: 1, x: 0 },
exit: { opacity: 0, x: -20 },
transition: { duration: 0.25, ease: "easeOut" },
};
export const staggerContainer = {
animate: {
transition: {
staggerChildren: 0.05,
delayChildren: 0.1,
},
},
};
export const staggerItem = {
initial: { opacity: 0, y: 10 },
animate: { opacity: 1, y: 0 },
transition: { duration: 0.2 },
};
/**
* MotionDiv — a pre-configured motion.div with fadeInUp by default.
* Pass any variant prop to override.
*/
export function MotionDiv({ children, className, variants = fadeInUp, ...props }) {
return (
<motion.div className={className} {...variants} {...props}>
{children}
</motion.div>
);
}
/**
* MotionList — staggered list animation
*/
export function MotionList({ children, className, ...props }) {
return (
<motion.div
className={className}
variants={staggerContainer}
initial="initial"
animate="animate"
{...props}
>
{children}
</motion.div>
);
}
export function MotionItem({ children, className, ...props }) {
return (
<motion.div className={className} variants={staggerItem} {...props}>
{children}
</motion.div>
);
}
export { motion, AnimatePresence };
\ No newline at end of file
import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import { cn } from "../../lib/utils";
const Separator = React.forwardRef(
({ className, orientation = "horizontal", decorative = true, ...props }, ref) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className
)}
{...props}
/>
)
);
Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator };
\ No newline at end of file
import { cn } from "../../lib/utils";
function Skeleton({ className, ...props }) {
return (
<div
className={cn(
"animate-pulse rounded-md bg-white/[0.06]",
className
)}
{...props}
/>
);
}
export { Skeleton };
\ No newline at end of file
import { Toaster as SonnerToaster } from "sonner";
/**
* Drop this into App.jsx: <Toaster />
* Then use: toast("Hello"), toast.success("Done"), toast.error("Shit")
*/
export function Toaster() {
return (
<SonnerToaster
position="bottom-right"
toastOptions={{
style: {
background: "hsl(230, 18%, 8%)",
border: "1px solid hsl(230, 14%, 16%)",
color: "hsl(220, 15%, 85%)",
fontSize: "13px",
},
classNames: {
success: "!border-green-500/30",
error: "!border-red-500/30",
warning: "!border-yellow-500/30",
info: "!border-blue-500/30",
},
}}
theme="dark"
richColors
closeButton
/>
);
}
\ No newline at end of file
import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { cn } from "../../lib/utils";
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef(
({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-popover border border-border px-3 py-1.5 text-xs text-popover-foreground shadow-md",
"animate-in fade-in-0 zoom-in-95",
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
)
);
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
\ No newline at end of file
This diff is collapsed.
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
/**
* Merge Tailwind classes intelligently — the foundation of
* every good component library. Handles conflicts like a boss.
*
* Usage: cn("px-4 py-2", isActive && "bg-primary", className)
*/
export function cn(...inputs) {
return twMerge(clsx(inputs));
}
/**
* Format a number with locale-aware separators
*/
export function formatNumber(n) {
if (n == null) return "0";
return Number(n).toLocaleString();
}
/**
* Truncate text with ellipsis
*/
export function truncate(str, maxLength = 50) {
if (!str || str.length <= maxLength) return str || "";
return str.slice(0, maxLength) + "…";
}
/**
* Generate initials from a name
*/
export function getInitials(name, maxChars = 2) {
if (!name) return "?";
return name
.split(/[\s_-]+/)
.map((w) => w[0])
.filter(Boolean)
.slice(0, maxChars)
.join("")
.toUpperCase();
}
\ No newline at end of file
/** @type {import('tailwindcss').Config} */
export default {
darkMode: "class",
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
container: {
center: true,
padding: "2rem",
screens: { "2xl": "1400px" },
},
extend: {
colors: {
"anton-bg": "#09090f",
"anton-surface": "#0f0f1a",
"anton-card": "#16162a",
"anton-border": "#1e1e3a",
"anton-text": "#e2e2ea",
"anton-muted": "#6b6b8a",
"anton-accent": "#e53e3e",
"anton-success": "#48bb78",
"anton-danger": "#e53e3e",
// ── Core brand ──
anton: {
bg: "hsl(var(--anton-bg) / <alpha-value>)",
surface: "hsl(var(--anton-surface) / <alpha-value>)",
card: "hsl(var(--anton-card) / <alpha-value>)",
border: "hsl(var(--anton-border) / <alpha-value>)",
text: "hsl(var(--anton-text) / <alpha-value>)",
muted: "hsl(var(--anton-muted) / <alpha-value>)",
accent: "hsl(var(--anton-accent) / <alpha-value>)",
success: "hsl(var(--anton-success) / <alpha-value>)",
danger: "hsl(var(--anton-danger) / <alpha-value>)",
warning: "hsl(var(--anton-warning) / <alpha-value>)",
info: "hsl(var(--anton-info) / <alpha-value>)",
},
// ── shadcn-compatible semantic tokens ──
border: "hsl(var(--border) / <alpha-value>)",
input: "hsl(var(--input) / <alpha-value>)",
ring: "hsl(var(--ring) / <alpha-value>)",
background: "hsl(var(--background) / <alpha-value>)",
foreground: "hsl(var(--foreground) / <alpha-value>)",
primary: {
DEFAULT: "hsl(var(--primary) / <alpha-value>)",
foreground: "hsl(var(--primary-foreground) / <alpha-value>)",
},
secondary: {
DEFAULT: "hsl(var(--secondary) / <alpha-value>)",
foreground: "hsl(var(--secondary-foreground) / <alpha-value>)",
},
destructive: {
DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
foreground: "hsl(var(--destructive-foreground) / <alpha-value>)",
},
muted: {
DEFAULT: "hsl(var(--muted) / <alpha-value>)",
foreground: "hsl(var(--muted-foreground) / <alpha-value>)",
},
accent: {
DEFAULT: "hsl(var(--accent) / <alpha-value>)",
foreground: "hsl(var(--accent-foreground) / <alpha-value>)",
},
popover: {
DEFAULT: "hsl(var(--popover) / <alpha-value>)",
foreground: "hsl(var(--popover-foreground) / <alpha-value>)",
},
card: {
DEFAULT: "hsl(var(--card) / <alpha-value>)",
foreground: "hsl(var(--card-foreground) / <alpha-value>)",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
fontFamily: {
sans: ["Inter", "system-ui", "-apple-system", "sans-serif"],
mono: ["JetBrains Mono", "Fira Code", "monospace"],
display: ["Inter", "system-ui", "sans-serif"],
},
fontSize: {
"2xs": ["0.625rem", { lineHeight: "0.875rem" }],
},
spacing: {
"4.5": "1.125rem",
"5.5": "1.375rem",
"13": "3.25rem",
"15": "3.75rem",
"17": "4.25rem",
"18": "4.5rem",
"112": "28rem",
"128": "32rem",
"144": "36rem",
},
backdropBlur: {
xs: "2px",
},
boxShadow: {
glow: "0 0 20px rgba(229, 62, 62, 0.15)",
"glow-lg": "0 0 40px rgba(229, 62, 62, 0.2)",
"inner-glow": "inset 0 0 20px rgba(229, 62, 62, 0.05)",
"card-hover": "0 8px 30px rgba(0, 0, 0, 0.3), 0 0 1px rgba(255, 255, 255, 0.05)",
"elevated": "0 20px 60px rgba(0, 0, 0, 0.4)",
},
keyframes: {
"fade-in": {
from: { opacity: "0", transform: "translateY(8px)" },
to: { opacity: "1", transform: "translateY(0)" },
},
"fade-out": {
from: { opacity: "1", transform: "translateY(0)" },
to: { opacity: "0", transform: "translateY(8px)" },
},
"slide-in-from-right": {
from: { transform: "translateX(100%)" },
to: { transform: "translateX(0)" },
},
"slide-in-from-left": {
from: { transform: "translateX(-100%)" },
to: { transform: "translateX(0)" },
},
"slide-in-from-top": {
from: { transform: "translateY(-100%)" },
to: { transform: "translateY(0)" },
},
"slide-in-from-bottom": {
from: { transform: "translateY(100%)" },
to: { transform: "translateY(0)" },
},
"scale-in": {
from: { opacity: "0", transform: "scale(0.95)" },
to: { opacity: "1", transform: "scale(1)" },
},
"spin-slow": {
from: { transform: "rotate(0deg)" },
to: { transform: "rotate(360deg)" },
},
shimmer: {
"0%": { backgroundPosition: "-200% 0" },
"100%": { backgroundPosition: "200% 0" },
},
"pulse-glow": {
"0%, 100%": { boxShadow: "0 0 5px rgba(229, 62, 62, 0.2)" },
"50%": { boxShadow: "0 0 20px rgba(229, 62, 62, 0.4)" },
},
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
float: {
"0%, 100%": { transform: "translateY(0px)" },
"50%": { transform: "translateY(-6px)" },
},
"border-beam": {
"100%": { offsetDistance: "100%" },
},
},
animation: {
"fade-in": "fade-in 0.3s ease-out",
"fade-out": "fade-out 0.3s ease-out",
"slide-in-right": "slide-in-from-right 0.3s ease-out",
"slide-in-left": "slide-in-from-left 0.3s ease-out",
"slide-in-top": "slide-in-from-top 0.3s ease-out",
"slide-in-bottom": "slide-in-from-bottom 0.3s ease-out",
"scale-in": "scale-in 0.2s ease-out",
"spin-slow": "spin-slow 3s linear infinite",
shimmer: "shimmer 2s linear infinite",
"pulse-glow": "pulse-glow 2s ease-in-out infinite",
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
float: "float 3s ease-in-out infinite",
"border-beam": "border-beam calc(var(--duration)*1s) infinite linear",
},
screens: {
"xs": "400px",
typography: {
anton: {
css: {
"--tw-prose-body": "hsl(var(--anton-text))",
"--tw-prose-headings": "#ffffff",
"--tw-prose-links": "hsl(var(--anton-accent))",
"--tw-prose-bold": "#ffffff",
"--tw-prose-code": "hsl(var(--anton-accent))",
"--tw-prose-pre-bg": "hsl(var(--anton-card))",
"--tw-prose-pre-code": "hsl(var(--anton-text))",
"--tw-prose-quotes": "hsl(var(--anton-muted))",
"--tw-prose-quote-borders": "hsl(var(--anton-accent))",
"--tw-prose-hr": "hsl(var(--anton-border))",
"--tw-prose-th-borders": "hsl(var(--anton-border))",
"--tw-prose-td-borders": "hsl(var(--anton-border))",
maxWidth: "none",
a: { textDecoration: "none", fontWeight: "500" },
"a:hover": { color: "hsl(var(--anton-accent))" },
code: {
backgroundColor: "rgba(255,255,255,0.06)",
padding: "0.15em 0.35em",
borderRadius: "0.25em",
fontWeight: "400",
},
"code::before": { content: '""' },
"code::after": { content: '""' },
pre: {
backgroundColor: "hsl(var(--anton-card))",
border: "1px solid hsl(var(--anton-border))",
borderRadius: "0.75rem",
},
table: { fontSize: "0.875rem" },
th: { fontWeight: "600", color: "#ffffff" },
img: { borderRadius: "0.75rem" },
hr: { borderColor: "hsl(var(--anton-border))" },
blockquote: {
borderLeftColor: "hsl(var(--anton-accent))",
fontStyle: "normal",
},
},
},
},
},
},
plugins: [],
plugins: [
require("@tailwindcss/typography"),
require("@tailwindcss/forms")({ strategy: "class" }),
require("@tailwindcss/container-queries"),
require("tailwindcss-animate"),
],
};
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment