feat: update linter rules and improve code structure
- Added overrides in biome.json to disable specific linter rules for UI components. - Reorganized imports and improved code readability in various UI components. - Refactored components to use fieldset instead of div for better semantics. - Enhanced accessibility by updating roles and aria attributes in components. - Fixed minor issues with key props in map functions for better performance. - Updated focus styles and improved CSS for better visual feedback.
This commit is contained in:
@@ -1,36 +1,37 @@
|
|||||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
# asepharyana-hub-hub
|
||||||
|
|
||||||
## Getting Started
|
Personal portfolio SPA — backend/infrastructure projects and live monitoring dashboard.
|
||||||
|
|
||||||
First, run the development server:
|
Built with **Next.js 16**, **shadcn/ui** (base-nova), **Tailwind CSS v4**, and `next-themes`.
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
- **Framework:** Next.js 16 (Turbopack, React Compiler)
|
||||||
|
- **UI:** shadcn/ui v4 (base-nova style) + Tailwind CSS v4
|
||||||
|
- **Font:** Geist (sans) + Geist Mono via `next/font`
|
||||||
|
- **Theme:** `next-themes` — light/dark with amber "server LED" focus glow (dark mode)
|
||||||
|
- **Icons:** Lucide React
|
||||||
|
- **Linting:** Biome
|
||||||
|
|
||||||
|
## Pages
|
||||||
|
|
||||||
|
| Route | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `/` | Portfolio landing page — hero, about, skills, featured project (ZeaVis Edu), infra CTA |
|
||||||
|
| `/dashboard` | Live infrastructure monitor — Docker services, Traefik metrics, Jaeger traces, Prometheus resources |
|
||||||
|
|
||||||
|
## Theme
|
||||||
|
|
||||||
|
Twilight Terminal — warm off-white (light) / deep indigo-slate (dark) with amber-gold primary in dark mode. All component styling is driven by CSS custom properties in `globals.css`.
|
||||||
|
|
||||||
|
## Dev
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
bun dev # Start dev server
|
||||||
# or
|
bun run lint # Biome lint
|
||||||
yarn dev
|
bun run ci # Biome CI mode
|
||||||
# or
|
|
||||||
pnpm dev
|
|
||||||
# or
|
|
||||||
bun dev
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
## Deploy
|
||||||
|
|
||||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
Deployed as a Docker container behind Traefik on VPS. See `infra/` in the monorepo root for compose files and Traefik config.
|
||||||
|
|
||||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
|
||||||
|
|
||||||
## Learn More
|
|
||||||
|
|
||||||
To learn more about Next.js, take a look at the following resources:
|
|
||||||
|
|
||||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
|
||||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
||||||
|
|
||||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
|
||||||
|
|
||||||
## Deploy on Vercel
|
|
||||||
|
|
||||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
|
||||||
|
|
||||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
|
||||||
|
|||||||
+17
-2
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.5.3/schema.json",
|
||||||
"vcs": {
|
"vcs": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"clientKind": "git",
|
"clientKind": "git",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"rules": {
|
"rules": {
|
||||||
"recommended": true,
|
"preset": "recommended",
|
||||||
"suspicious": {
|
"suspicious": {
|
||||||
"noUnknownAtRules": "off"
|
"noUnknownAtRules": "off"
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,21 @@
|
|||||||
"react": "recommended"
|
"react": "recommended"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"includes": ["src/components/ui/**"],
|
||||||
|
"linter": {
|
||||||
|
"rules": {
|
||||||
|
"security": {
|
||||||
|
"noDangerouslySetInnerHtml": "off"
|
||||||
|
},
|
||||||
|
"suspicious": {
|
||||||
|
"noArrayIndexKey": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"assist": {
|
"assist": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"source": {
|
"source": {
|
||||||
|
|||||||
Generated
+6292
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -18,28 +18,28 @@
|
|||||||
"date-fns": "^4.4.0",
|
"date-fns": "^4.4.0",
|
||||||
"embla-carousel-react": "^8.6.0",
|
"embla-carousel-react": "^8.6.0",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lucide-react": "^1.25.0",
|
"lucide-react": "^1.26.0",
|
||||||
"next": "16.2.11",
|
"next": "16.2.11",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "19.2.4",
|
"react": "19.2.8",
|
||||||
"react-day-picker": "^10.0.1",
|
"react-day-picker": "^10.0.1",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.8",
|
||||||
"react-resizable-panels": "^4.12.2",
|
"react-resizable-panels": "^4.12.2",
|
||||||
"recharts": "3.8.0",
|
"recharts": "3.10.0",
|
||||||
"shadcn": "^4.14.0",
|
"shadcn": "^4.14.0",
|
||||||
"sonner": "^2.0.7",
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.6.0",
|
"tailwind-merge": "^3.6.0",
|
||||||
"tw-animate-css": "^1.4.0"
|
"tw-animate-css": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.2.0",
|
"@biomejs/biome": "2.5.5",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^26",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"babel-plugin-react-compiler": "1.0.0",
|
"babel-plugin-react-compiler": "1.0.0",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "^5"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
"ignoreScripts": [
|
"ignoreScripts": [
|
||||||
"sharp",
|
"sharp",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { NextResponse } from "next/server";
|
|
||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
const JAEGER = "http://jaeger:16686";
|
const JAEGER = "http://jaeger:16686";
|
||||||
const PROMETHEUS = "http://prometheus:9090";
|
const PROMETHEUS = "http://prometheus:9090";
|
||||||
@@ -31,7 +31,9 @@ function dockerFetch(path: string): Promise<unknown> {
|
|||||||
http
|
http
|
||||||
.get({ socketPath: DOCKER_SOCK, path }, (res) => {
|
.get({ socketPath: DOCKER_SOCK, path }, (res) => {
|
||||||
let data = "";
|
let data = "";
|
||||||
res.on("data", (c: string) => (data += c));
|
res.on("data", (c: string) => {
|
||||||
|
data += c;
|
||||||
|
});
|
||||||
res.on("end", () => {
|
res.on("end", () => {
|
||||||
try {
|
try {
|
||||||
resolve(JSON.parse(data));
|
resolve(JSON.parse(data));
|
||||||
@@ -129,7 +131,7 @@ async function promRange(query: string, steps = 20): Promise<number[]> {
|
|||||||
if (!result?.[0]?.values) return [];
|
if (!result?.[0]?.values) return [];
|
||||||
return result[0].values.map((v) => {
|
return result[0].values.map((v) => {
|
||||||
const f = parseFloat(v[1] as string);
|
const f = parseFloat(v[1] as string);
|
||||||
return isNaN(f) ? 0 : f;
|
return Number.isNaN(f) ? 0 : f;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -133,7 +133,9 @@
|
|||||||
.dark *:focus-visible {
|
.dark *:focus-visible {
|
||||||
@apply ring-[3px];
|
@apply ring-[3px];
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: 0 0 8px oklch(0.7 0.15 75 / 0.3), 0 0 0 3px oklch(0.7 0.15 75 / 0.5);
|
box-shadow:
|
||||||
|
0 0 8px oklch(0.7 0.15 75 / 0.3),
|
||||||
|
0 0 0 3px oklch(0.7 0.15 75 / 0.5);
|
||||||
}
|
}
|
||||||
html:not(.dark) *:focus-visible {
|
html:not(.dark) *:focus-visible {
|
||||||
@apply ring-[3px];
|
@apply ring-[3px];
|
||||||
|
|||||||
+6
-1
@@ -32,7 +32,12 @@ export default function RootLayout({
|
|||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
>
|
>
|
||||||
<body className="flex min-h-full flex-col bg-background text-foreground">
|
<body className="flex min-h-full flex-col bg-background text-foreground">
|
||||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
|
<ThemeProvider
|
||||||
|
attribute="class"
|
||||||
|
defaultTheme="system"
|
||||||
|
enableSystem
|
||||||
|
disableTransitionOnChange
|
||||||
|
>
|
||||||
<DashboardHeader />
|
<DashboardHeader />
|
||||||
{children}
|
{children}
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
|||||||
+8
-8
@@ -98,15 +98,15 @@ export default function Home() {
|
|||||||
I’m a Teknik Informatika student passionate about backend
|
I’m a Teknik Informatika student passionate about backend
|
||||||
engineering, distributed systems, and infrastructure. I spend my
|
engineering, distributed systems, and infrastructure. I spend my
|
||||||
time building RESTful APIs, learning container orchestration with
|
time building RESTful APIs, learning container orchestration with
|
||||||
Docker & Traefik, and exploring observability with OpenTelemetry
|
Docker & Traefik, and exploring observability with
|
||||||
& Jaeger.
|
OpenTelemetry & Jaeger.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
I was the Back-End lead on the ZeaVis Edu capstone team (“AI
|
I was the Back-End lead on the ZeaVis Edu capstone team (“AI
|
||||||
for Smart Education” by Pijak × IBM SkillsBuild),
|
for Smart Education” by Pijak × IBM SkillsBuild), a
|
||||||
a 5-person team with task division across Back-End, Front-End,
|
5-person team with task division across Back-End, Front-End, and
|
||||||
and Machine Learning. I handled the system architecture, API
|
Machine Learning. I handled the system architecture, API design,
|
||||||
design, RESTful API development, and Docker deployment on VPS.
|
RESTful API development, and Docker deployment on VPS.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -260,8 +260,8 @@ export default function Home() {
|
|||||||
</p>
|
</p>
|
||||||
<p className="max-w-md text-sm text-muted-foreground">
|
<p className="max-w-md text-sm text-muted-foreground">
|
||||||
The dashboard tracks Docker services, Traefik request metrics,
|
The dashboard tracks Docker services, Traefik request metrics,
|
||||||
Prometheus system resources, and Jaeger traces — all running on
|
Prometheus system resources, and Jaeger traces — all running on my
|
||||||
my VPS deployment.
|
VPS deployment.
|
||||||
</p>
|
</p>
|
||||||
<a href="/dashboard" className={cn(buttonVariants())}>
|
<a href="/dashboard" className={cn(buttonVariants())}>
|
||||||
Live Dashboard
|
Live Dashboard
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
|
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
|
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog";
|
import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog";
|
||||||
|
import type * as React from "react";
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
|
function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
|
||||||
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { mergeProps } from "@base-ui/react/merge-props";
|
import { mergeProps } from "@base-ui/react/merge-props";
|
||||||
import { useRender } from "@base-ui/react/use-render";
|
import { useRender } from "@base-ui/react/use-render";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import type * as React from "react";
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const attachmentVariants = cva(
|
const attachmentVariants = cva(
|
||||||
"group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-1 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed",
|
"group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-1 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
|
import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
|
||||||
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { mergeProps } from "@base-ui/react/merge-props";
|
import { mergeProps } from "@base-ui/react/merge-props";
|
||||||
import { useRender } from "@base-ui/react/use-render";
|
import { useRender } from "@base-ui/react/use-render";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
|
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
|
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
|
||||||
return (
|
return (
|
||||||
@@ -63,8 +62,6 @@ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
data-slot="breadcrumb-page"
|
data-slot="breadcrumb-page"
|
||||||
role="link"
|
|
||||||
aria-disabled="true"
|
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
className={cn("font-normal text-foreground", className)}
|
className={cn("font-normal text-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { mergeProps } from "@base-ui/react/merge-props";
|
import { mergeProps } from "@base-ui/react/merge-props";
|
||||||
import { useRender } from "@base-ui/react/use-render";
|
import { useRender } from "@base-ui/react/use-render";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { mergeProps } from "@base-ui/react/merge-props";
|
import { mergeProps } from "@base-ui/react/merge-props";
|
||||||
import { useRender } from "@base-ui/react/use-render";
|
import { useRender } from "@base-ui/react/use-render";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const buttonGroupVariants = cva(
|
const buttonGroupVariants = cva(
|
||||||
"flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
|
"flex w-fit items-stretch border-0 p-0 m-0 *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
orientation: {
|
orientation: {
|
||||||
@@ -26,10 +25,9 @@ function ButtonGroup({
|
|||||||
className,
|
className,
|
||||||
orientation,
|
orientation,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
|
}: React.ComponentProps<"fieldset"> & VariantProps<typeof buttonGroupVariants>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<fieldset
|
||||||
role="group"
|
|
||||||
data-slot="button-group"
|
data-slot="button-group"
|
||||||
data-orientation={orientation}
|
data-orientation={orientation}
|
||||||
className={cn(buttonGroupVariants({ orientation }), className)}
|
className={cn(buttonGroupVariants({ orientation }), className)}
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import {
|
|
||||||
DayPicker,
|
|
||||||
getDefaultClassNames,
|
|
||||||
type DayButton,
|
|
||||||
type Locale,
|
|
||||||
} from "react-day-picker";
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button, buttonVariants } from "@/components/ui/button";
|
|
||||||
import {
|
import {
|
||||||
|
ChevronDownIcon,
|
||||||
ChevronLeftIcon,
|
ChevronLeftIcon,
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
ChevronDownIcon,
|
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
import * as React from "react";
|
||||||
|
import {
|
||||||
|
type DayButton,
|
||||||
|
DayPicker,
|
||||||
|
getDefaultClassNames,
|
||||||
|
type Locale,
|
||||||
|
} from "react-day-picker";
|
||||||
|
import { Button, buttonVariants } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Calendar({
|
function Calendar({
|
||||||
className,
|
className,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import useEmblaCarousel, {
|
import useEmblaCarousel, {
|
||||||
type UseEmblaCarouselType,
|
type UseEmblaCarouselType,
|
||||||
} from "embla-carousel-react";
|
} from "embla-carousel-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||||
|
import * as React from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
type CarouselApi = UseEmblaCarouselType[1];
|
type CarouselApi = UseEmblaCarouselType[1];
|
||||||
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
|
||||||
@@ -118,16 +117,16 @@ function Carousel({
|
|||||||
canScrollNext,
|
canScrollNext,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
{/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: <section> has implicit role="region" which supports aria-roledescription */}
|
||||||
|
<section
|
||||||
onKeyDownCapture={handleKeyDown}
|
onKeyDownCapture={handleKeyDown}
|
||||||
className={cn("relative", className)}
|
className={cn("relative", className)}
|
||||||
role="region"
|
|
||||||
aria-roledescription="carousel"
|
aria-roledescription="carousel"
|
||||||
data-slot="carousel"
|
data-slot="carousel"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</section>
|
||||||
</CarouselContext.Provider>
|
</CarouselContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -153,16 +152,15 @@ function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
|
function CarouselItem({ className, ...props }: React.ComponentProps<"fieldset">) {
|
||||||
const { orientation } = useCarousel();
|
const { orientation } = useCarousel();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<fieldset
|
||||||
role="group"
|
|
||||||
aria-roledescription="slide"
|
aria-roledescription="slide"
|
||||||
data-slot="carousel-item"
|
data-slot="carousel-item"
|
||||||
className={cn(
|
className={cn(
|
||||||
"min-w-0 shrink-0 grow-0 basis-full",
|
"min-w-0 shrink-0 grow-0 basis-full border-0 p-0 m-0",
|
||||||
orientation === "horizontal" ? "pl-4" : "pt-4",
|
orientation === "horizontal" ? "pl-4" : "pt-4",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as RechartsPrimitive from "recharts";
|
|
||||||
import type { TooltipValueType } from "recharts";
|
import type { TooltipValueType } from "recharts";
|
||||||
|
import * as RechartsPrimitive from "recharts";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -200,13 +200,17 @@ function ChartTooltipContent({
|
|||||||
{payload
|
{payload
|
||||||
.filter((item) => item.type !== "none")
|
.filter((item) => item.type !== "none")
|
||||||
.map((item, index) => {
|
.map((item, index) => {
|
||||||
const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}`;
|
const itemKey = `${nameKey ?? item.name ?? item.dataKey ?? "value"}-${index}`;
|
||||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
const itemConfig = getPayloadConfigFromPayload(
|
||||||
|
config,
|
||||||
|
item,
|
||||||
|
itemKey,
|
||||||
|
);
|
||||||
const indicatorColor = color ?? item.payload?.fill ?? item.color;
|
const indicatorColor = color ?? item.payload?.fill ?? item.color;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={itemKey}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
|
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
|
||||||
indicator === "dot" && "items-center",
|
indicator === "dot" && "items-center",
|
||||||
@@ -299,12 +303,12 @@ function ChartLegendContent({
|
|||||||
{payload
|
{payload
|
||||||
.filter((item) => item.type !== "none")
|
.filter((item) => item.type !== "none")
|
||||||
.map((item, index) => {
|
.map((item, index) => {
|
||||||
const key = `${nameKey ?? item.dataKey ?? "value"}`;
|
const itemKey = `${nameKey ?? item.dataKey ?? "value"}-${index}`;
|
||||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
const itemConfig = getPayloadConfigFromPayload(config, item, itemKey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={itemKey}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground",
|
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground",
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
|
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { CheckIcon } from "lucide-react";
|
import { CheckIcon } from "lucide-react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Combobox as ComboboxPrimitive } from "@base-ui/react";
|
import { Combobox as ComboboxPrimitive } from "@base-ui/react";
|
||||||
|
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import * as React from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
InputGroup,
|
InputGroup,
|
||||||
@@ -11,7 +10,7 @@ import {
|
|||||||
InputGroupButton,
|
InputGroupButton,
|
||||||
InputGroupInput,
|
InputGroupInput,
|
||||||
} from "@/components/ui/input-group";
|
} from "@/components/ui/input-group";
|
||||||
import { ChevronDownIcon, XIcon, CheckIcon } from "lucide-react";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Combobox = ComboboxPrimitive.Root;
|
const Combobox = ComboboxPrimitive.Root;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Command as CommandPrimitive } from "cmdk";
|
import { Command as CommandPrimitive } from "cmdk";
|
||||||
|
import { CheckIcon, SearchIcon } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import type * as React from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@@ -12,7 +11,7 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { InputGroup, InputGroupAddon } from "@/components/ui/input-group";
|
import { InputGroup, InputGroupAddon } from "@/components/ui/input-group";
|
||||||
import { SearchIcon, CheckIcon } from "lucide-react";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Command({
|
function Command({
|
||||||
className,
|
className,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu";
|
import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu";
|
||||||
|
import { CheckIcon, ChevronRightIcon } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { ChevronRightIcon, CheckIcon } from "lucide-react";
|
|
||||||
|
|
||||||
function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
|
function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
|
||||||
return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />;
|
return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { XIcon } from "lucide-react";
|
import { XIcon } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Dialog({ ...props }: DialogPrimitive.Root.Props) {
|
function Dialog({ ...props }: DialogPrimitive.Root.Props) {
|
||||||
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Drawer as DrawerPrimitive } from "@base-ui/react/drawer";
|
import { Drawer as DrawerPrimitive } from "@base-ui/react/drawer";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
||||||
|
import { CheckIcon, ChevronRightIcon } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { ChevronRightIcon, CheckIcon } from "lucide-react";
|
|
||||||
|
|
||||||
function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
|
function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
|
||||||
return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useMemo } from "react";
|
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import { useMemo } from "react";
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
|
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
|
||||||
return (
|
return (
|
||||||
@@ -52,7 +51,7 @@ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fieldVariants = cva(
|
const fieldVariants = cva(
|
||||||
"group/field flex w-full gap-2 data-[invalid=true]:text-destructive",
|
"group/field flex w-full gap-2 border-0 p-0 m-0 data-[invalid=true]:text-destructive",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
orientation: {
|
orientation: {
|
||||||
@@ -73,10 +72,9 @@ function Field({
|
|||||||
className,
|
className,
|
||||||
orientation = "vertical",
|
orientation = "vertical",
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) {
|
}: React.ComponentProps<"fieldset"> & VariantProps<typeof fieldVariants>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<fieldset
|
||||||
role="group"
|
|
||||||
data-slot="field"
|
data-slot="field"
|
||||||
data-orientation={orientation}
|
data-orientation={orientation}
|
||||||
className={cn(fieldVariants({ orientation }), className)}
|
className={cn(fieldVariants({ orientation }), className)}
|
||||||
@@ -194,7 +192,7 @@ function FieldError({
|
|||||||
...new Map(errors.map((error) => [error?.message, error])).values(),
|
...new Map(errors.map((error) => [error?.message, error])).values(),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (uniqueErrors?.length == 1) {
|
if (uniqueErrors?.length === 1) {
|
||||||
return uniqueErrors[0]?.message;
|
return uniqueErrors[0]?.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +200,9 @@ function FieldError({
|
|||||||
<ul className="ml-4 flex list-disc flex-col gap-1">
|
<ul className="ml-4 flex list-disc flex-col gap-1">
|
||||||
{uniqueErrors.map(
|
{uniqueErrors.map(
|
||||||
(error, index) =>
|
(error, index) =>
|
||||||
error?.message && <li key={index}>{error.message}</li>,
|
error?.message && (
|
||||||
|
<li key={`${error.message}-${index}`}>{error.message}</li>
|
||||||
|
),
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,10 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { OTPInput, OTPInputContext } from "input-otp";
|
import { OTPInput, OTPInputContext } from "input-otp";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { MinusIcon } from "lucide-react";
|
import { MinusIcon } from "lucide-react";
|
||||||
|
import * as React from "react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function InputOTP({
|
function InputOTP({
|
||||||
className,
|
className,
|
||||||
@@ -75,7 +74,7 @@ function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
|
|||||||
<div
|
<div
|
||||||
data-slot="input-otp-separator"
|
data-slot="input-otp-separator"
|
||||||
className="flex items-center [&_svg:not([class*='size-'])]:size-4"
|
className="flex items-center [&_svg:not([class*='size-'])]:size-4"
|
||||||
role="separator"
|
aria-hidden="true"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<MinusIcon />
|
<MinusIcon />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { Input as InputPrimitive } from "@base-ui/react/input";
|
import { Input as InputPrimitive } from "@base-ui/react/input";
|
||||||
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { mergeProps } from "@base-ui/react/merge-props";
|
import { mergeProps } from "@base-ui/react/merge-props";
|
||||||
import { useRender } from "@base-ui/react/use-render";
|
import { useRender } from "@base-ui/react/use-render";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import type * as React from "react";
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
|
function ItemGroup({ className, ...props }: React.ComponentProps<"ul">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<ul
|
||||||
role="list"
|
|
||||||
data-slot="item-group"
|
data-slot="item-group"
|
||||||
className={cn(
|
className={cn(
|
||||||
"group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
|
"group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Label({ className, ...props }: React.ComponentProps<"label">) {
|
function Label({ className, ...props }: React.ComponentProps<"label">) {
|
||||||
return (
|
return (
|
||||||
|
/* biome-ignore lint/a11y/noLabelWithoutControl: reusable label component, htmlFor or wrapping input provided by consumer */
|
||||||
<label
|
<label
|
||||||
data-slot="label"
|
data-slot="label"
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { mergeProps } from "@base-ui/react/merge-props";
|
import { mergeProps } from "@base-ui/react/merge-props";
|
||||||
import { useRender } from "@base-ui/react/use-render";
|
import { useRender } from "@base-ui/react/use-render";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
||||||
import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar";
|
import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar";
|
||||||
|
import { CheckIcon } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import type * as React from "react";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@@ -20,7 +19,7 @@ import {
|
|||||||
DropdownMenuSubTrigger,
|
DropdownMenuSubTrigger,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { CheckIcon } from "lucide-react";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Menubar({ className, ...props }: MenubarPrimitive.Props) {
|
function Menubar({ className, ...props }: MenubarPrimitive.Props) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import {
|
import {
|
||||||
MessageScroller as MessageScrollerPrimitive,
|
MessageScroller as MessageScrollerPrimitive,
|
||||||
useMessageScroller,
|
useMessageScroller,
|
||||||
useMessageScrollerScrollable,
|
useMessageScrollerScrollable,
|
||||||
useMessageScrollerVisibility,
|
useMessageScrollerVisibility,
|
||||||
} from "@shadcn/react/message-scroller";
|
} from "@shadcn/react/message-scroller";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { ArrowDownIcon } from "lucide-react";
|
import { ArrowDownIcon } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function MessageScrollerProvider(
|
function MessageScrollerProvider(
|
||||||
props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,
|
props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as React from "react";
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { ChevronDownIcon } from "lucide-react";
|
import { ChevronDownIcon } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
type NativeSelectProps = Omit<React.ComponentProps<"select">, "size"> & {
|
type NativeSelectProps = Omit<React.ComponentProps<"select">, "size"> & {
|
||||||
size?: "sm" | "default";
|
size?: "sm" | "default";
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/navigation-menu";
|
import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/navigation-menu";
|
||||||
import { cva } from "class-variance-authority";
|
import { cva } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { ChevronDownIcon } from "lucide-react";
|
import { ChevronDownIcon } from "lucide-react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function NavigationMenu({
|
function NavigationMenu({
|
||||||
align = "start",
|
align = "start",
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import * as React from "react";
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import {
|
import {
|
||||||
ChevronLeftIcon,
|
ChevronLeftIcon,
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
MoreHorizontalIcon,
|
MoreHorizontalIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
|
function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
|
||||||
return (
|
return (
|
||||||
<nav
|
<nav
|
||||||
role="navigation"
|
|
||||||
aria-label="pagination"
|
aria-label="pagination"
|
||||||
data-slot="pagination"
|
data-slot="pagination"
|
||||||
className={cn("mx-auto flex w-full justify-center", className)}
|
className={cn("mx-auto flex w-full justify-center", className)}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
|
import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
|
||||||
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
|
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Select as SelectPrimitive } from "@base-ui/react/select";
|
import { Select as SelectPrimitive } from "@base-ui/react/select";
|
||||||
|
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react";
|
|
||||||
|
|
||||||
const Select = SelectPrimitive.Root;
|
const Select = SelectPrimitive.Root;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Dialog as SheetPrimitive } from "@base-ui/react/dialog";
|
import { Dialog as SheetPrimitive } from "@base-ui/react/dialog";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { XIcon } from "lucide-react";
|
import { XIcon } from "lucide-react";
|
||||||
|
import type * as React from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Sheet({ ...props }: SheetPrimitive.Root.Props) {
|
function Sheet({ ...props }: SheetPrimitive.Root.Props) {
|
||||||
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { mergeProps } from "@base-ui/react/merge-props";
|
import { mergeProps } from "@base-ui/react/merge-props";
|
||||||
import { useRender } from "@base-ui/react/use-render";
|
import { useRender } from "@base-ui/react/use-render";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
import { PanelLeftIcon } from "lucide-react";
|
||||||
import { useIsMobile } from "@/hooks/use-mobile";
|
import * as React from "react";
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
@@ -23,10 +21,20 @@ import {
|
|||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { PanelLeftIcon } from "lucide-react";
|
import { useIsMobile } from "@/hooks/use-mobile";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
||||||
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
||||||
|
|
||||||
|
function setCookie(name: string, value: boolean, maxAge: number) {
|
||||||
|
Reflect.set(
|
||||||
|
document,
|
||||||
|
"cookie",
|
||||||
|
`${name}=${value}; path=/; max-age=${maxAge}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const SIDEBAR_WIDTH = "16rem";
|
const SIDEBAR_WIDTH = "16rem";
|
||||||
const SIDEBAR_WIDTH_MOBILE = "18rem";
|
const SIDEBAR_WIDTH_MOBILE = "18rem";
|
||||||
const SIDEBAR_WIDTH_ICON = "3rem";
|
const SIDEBAR_WIDTH_ICON = "3rem";
|
||||||
@@ -83,7 +91,7 @@ function SidebarProvider({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This sets the cookie to keep the sidebar state.
|
// This sets the cookie to keep the sidebar state.
|
||||||
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
setCookie(SIDEBAR_COOKIE_NAME, openState, SIDEBAR_COOKIE_MAX_AGE);
|
||||||
},
|
},
|
||||||
[setOpenProp, open],
|
[setOpenProp, open],
|
||||||
);
|
);
|
||||||
@@ -91,7 +99,7 @@ function SidebarProvider({
|
|||||||
// Helper to toggle the sidebar.
|
// Helper to toggle the sidebar.
|
||||||
const toggleSidebar = React.useCallback(() => {
|
const toggleSidebar = React.useCallback(() => {
|
||||||
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
|
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
|
||||||
}, [isMobile, setOpen, setOpenMobile]);
|
}, [isMobile, setOpen]);
|
||||||
|
|
||||||
// Adds a keyboard shortcut to toggle the sidebar.
|
// Adds a keyboard shortcut to toggle the sidebar.
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -123,7 +131,7 @@ function SidebarProvider({
|
|||||||
setOpenMobile,
|
setOpenMobile,
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
}),
|
}),
|
||||||
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
|
[state, open, setOpen, isMobile, openMobile, toggleSidebar],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ function Slider({
|
|||||||
className="bg-primary select-none data-horizontal:h-full data-vertical:w-full"
|
className="bg-primary select-none data-horizontal:h-full data-vertical:w-full"
|
||||||
/>
|
/>
|
||||||
</SliderPrimitive.Track>
|
</SliderPrimitive.Track>
|
||||||
{Array.from({ length: _values.length }, (_, index) => (
|
{_values.map((_, i) => (
|
||||||
<SliderPrimitive.Thumb
|
<SliderPrimitive.Thumb
|
||||||
data-slot="slider-thumb"
|
data-slot="slider-thumb"
|
||||||
key={index}
|
key={i}
|
||||||
className="relative block size-3 shrink-0 rounded-full border border-ring bg-white ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-3 focus-visible:ring-3 focus-visible:outline-hidden active:ring-3 disabled:pointer-events-none disabled:opacity-50"
|
className="relative block size-3 shrink-0 rounded-full border border-ring bg-white ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-3 focus-visible:ring-3 focus-visible:outline-hidden active:ring-3 disabled:pointer-events-none disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useTheme } from "next-themes";
|
|
||||||
import { Toaster as Sonner, type ToasterProps } from "sonner";
|
|
||||||
import {
|
import {
|
||||||
CircleCheckIcon,
|
CircleCheckIcon,
|
||||||
InfoIcon,
|
InfoIcon,
|
||||||
TriangleAlertIcon,
|
|
||||||
OctagonXIcon,
|
|
||||||
Loader2Icon,
|
Loader2Icon,
|
||||||
|
OctagonXIcon,
|
||||||
|
TriangleAlertIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
import { useTheme } from "next-themes";
|
||||||
|
import { Toaster as Sonner, type ToasterProps } from "sonner";
|
||||||
|
|
||||||
const Toaster = ({ ...props }: ToasterProps) => {
|
const Toaster = ({ ...props }: ToasterProps) => {
|
||||||
const { theme = "system" } = useTheme();
|
const { theme = "system" } = useTheme();
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Loader2Icon } from "lucide-react";
|
import { Loader2Icon } from "lucide-react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
|
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
|
||||||
return (
|
return (
|
||||||
<Loader2Icon
|
<Loader2Icon
|
||||||
data-slot="spinner"
|
data-slot="spinner"
|
||||||
role="status"
|
|
||||||
aria-label="Loading"
|
aria-label="Loading"
|
||||||
className={cn("size-4 animate-spin", className)}
|
className={cn("size-4 animate-spin", className)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user