feat: add AdjustAIButton, EditPlanButton, and AsignaturaPreviewCard components
- Implemented AdjustAIButton for AI-driven plan adjustments with a confetti effect on success. - Created EditPlanButton to allow editing of plan details with form validation and optimistic updates. - Added AsignaturaPreviewCard to display course previews with relevant statistics and details. - Introduced Field component for consistent form field labeling. - Developed GradientMesh for dynamic background effects based on color input. - Added Pulse component for skeleton loading states. - Created SmallStat and StatCard components for displaying statistical information in a card format. - Implemented utility functions in planHelpers for color manipulation and formatting. - Established planQueries for fetching plan and course data from the database. - Updated the plan detail route to utilize new components and queries for improved user experience.
This commit is contained in:
33
src/components/planes/StatCard.tsx
Normal file
33
src/components/planes/StatCard.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as Icons from "lucide-react"
|
||||
import { hexToRgbA } from "./planHelpers"
|
||||
|
||||
export function StatCard({ label, value = "—", Icon = Icons.Info, accent, className = "", title }: {
|
||||
label: string
|
||||
value?: React.ReactNode
|
||||
Icon?: React.ComponentType<React.SVGProps<SVGSVGElement>>
|
||||
accent?: string | null
|
||||
className?: string
|
||||
title?: string
|
||||
}) {
|
||||
const border = hexToRgbA(accent, .28)
|
||||
const chipBg = hexToRgbA(accent, .08)
|
||||
const glow = hexToRgbA(accent, .14)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`group relative overflow-hidden rounded-2xl border p-4 sm:p-5 bg-white/70 dark:bg-neutral-900/60 backdrop-blur shadow-sm hover:shadow-md transition-all ${className}`}
|
||||
style={{ borderColor: border }}
|
||||
title={title ?? (typeof value === "string" ? value : undefined)}
|
||||
aria-label={`${label}: ${typeof value === "string" ? value : ""}`}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="text-xs text-neutral-500">{label}</div>
|
||||
<span className="inline-flex items-center justify-center rounded-xl px-2.5 py-2 border" style={{ borderColor: border, background: chipBg }}>
|
||||
<Icon className="h-4 w-4 opacity-80" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-1 text-2xl font-semibold tabular-nums tracking-tight truncate">{value}</div>
|
||||
<div className="pointer-events-none absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity" style={{ background: `radial-gradient(600px 120px at 20% -10%, ${glow}, transparent 60%)` }} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user