18 Commits

Author SHA1 Message Date
a2c1220c7d fix(deps): update dependency recharts to v3
Some checks failed
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Failing after 35s
Lint / Lint and Typecheck (pull_request) Failing after 28s
2025-11-22 04:01:48 +00:00
3dfd35d8ba chore(deps): update dependency typescript-eslint to v8.47.0
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 37s
2025-11-22 03:02:27 +00:00
eebdc619f2 chore(deps): update dependency react-hook-form to v7.66.1
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 35s
2025-11-22 02:02:40 +00:00
188aa4fc74 chore(deps): update dependency @types/react to v19.2.6
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 39s
2025-11-22 01:02:44 +00:00
2d73cb5def chore(deps): update actions/checkout digest to 93cb6ef
All checks were successful
Lint / Lint and Typecheck (push) Successful in 34s
2025-11-22 00:01:59 +00:00
431e654154 linter issues
All checks were successful
Lint / Lint and Typecheck (push) Successful in 41s
2025-11-15 18:18:15 +01:00
6b7e254014 remove eslint react hooks
Some checks failed
Lint / Lint and Typecheck (push) Failing after 24s
2025-11-15 17:05:52 +01:00
8006a65e88 linter issues
Some checks failed
Lint / Lint and Typecheck (push) Failing after 27s
2025-11-15 16:43:44 +01:00
fe4783ae97 fix eslint 2025-11-15 16:43:16 +01:00
d880b3fc26 tailwind 4 2025-11-15 16:40:44 +01:00
299de302d4 prettier file 2025-11-15 16:40:29 +01:00
96a3c13cc7 next16 2025-11-15 16:12:28 +01:00
782ba7b911 chore(deps): update pnpm to v10.22.0
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 30s
2025-11-15 14:02:23 +00:00
201f133863 chore(deps): update pnpm to v10.21.0
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 27s
2025-11-15 07:02:47 +00:00
d46fea9ea3 chore(deps): update dependency @types/react-dom to v19.2.3
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 28s
2025-11-15 06:03:37 +00:00
7811949cc4 chore(deps): update dependency tailwind-merge to v3.4.0
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 27s
2025-11-15 04:02:50 +00:00
9cdedf2bf9 chore(deps): update dependency typescript-eslint to v8.46.4
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 25s
2025-11-15 03:03:24 +00:00
5720571416 chore(deps): update dependency next-plausible to v3.12.5
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Lint / Lint and Typecheck (push) Successful in 25s
2025-11-15 02:03:20 +00:00
18 changed files with 993 additions and 754 deletions

View File

@@ -13,7 +13,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
- name: Install pnpm
uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4
@@ -27,5 +27,5 @@ jobs:
- name: Install dependencies
run: pnpm install
- name: Run check
run: pnpm run check
- name: Run lint
run: pnpm run lint

6
.prettierrc Normal file
View File

@@ -0,0 +1,6 @@
{
"tabWidth": 2,
"singleQuote": true,
"printWidth": 105,
"plugins": ["prettier-plugin-tailwindcss"]
}

View File

@@ -1,48 +0,0 @@
import { FlatCompat } from "@eslint/eslintrc";
import tseslint from "typescript-eslint";
const compat = new FlatCompat({
baseDirectory: import.meta.dirname,
});
export default tseslint.config(
{
ignores: [".next"],
},
...compat.extends("next/core-web-vitals"),
{
files: ["**/*.ts", "**/*.tsx"],
extends: [
...tseslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
],
rules: {
"@typescript-eslint/array-type": "off",
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/consistent-type-imports": [
"warn",
{ prefer: "type-imports", fixStyle: "inline-type-imports" },
],
"@typescript-eslint/no-unused-vars": [
"warn",
{ argsIgnorePattern: "^_" },
],
"@typescript-eslint/require-await": "off",
"@typescript-eslint/no-misused-promises": [
"error",
{ checksVoidReturn: { attributes: false } },
],
},
},
{
linterOptions: {
reportUnusedDisableDirectives: true,
},
languageOptions: {
parserOptions: {
projectService: true,
},
},
},
);

37
eslint.config.mjs Normal file
View File

@@ -0,0 +1,37 @@
// @ts-check
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
import tseslint from "typescript-eslint";
const eslintConfig = defineConfig([
// Next.js core-web-vitals and TypeScript configs
...nextVitals,
...nextTs,
// Add strict TypeScript rules on top
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
// Configure TypeScript parser options
{
files: ["**/*.{ts,tsx}"],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
// Override default ignores of eslint-config-next
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
// Additional ignores:
"*.mjs",
"tailwind.config.ts",
]),
]);
export default eslintConfig;

View File

@@ -2,7 +2,7 @@
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
import "./src/env.js";
import './src/env.ts';
/** @type {import("next").NextConfig} */
const config = {};

View File

@@ -9,7 +9,7 @@
"dev": "next dev --turbopack",
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,mdx}\" --cache",
"format:write": "prettier --write \"**/*.{ts,tsx,js,jsx,mdx}\" --cache",
"lint:fix": "next lint --fix",
"lint": "next typegen && eslint . && npx tsc --noEmit",
"preview": "next build && next start",
"start": "next start"
},
@@ -24,34 +24,39 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.553.0",
"next": "^15.4.1",
"next": "16.0.3",
"next-plausible": "^3.12.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react": "19.2.0",
"react-dom": "19.2.0",
"react-hook-form": "^7.56.1",
"recharts": "^3.0.0",
"tailwind-merge": "^3.2.0",
"zod": "^4.0.0"
},
"devDependencies": {
"@eslint/eslintrc": "3.3.1",
"@tailwindcss/postcss": "4.1.17",
"@types/node": "24.10.1",
"@types/react": "19.2.3",
"@types/react-dom": "19.2.2",
"@types/react": "19.2.6",
"@types/react-dom": "19.2.3",
"eslint": "9.39.1",
"eslint-config-next": "15.5.6",
"eslint-plugin-react-hooks": "5.2.0",
"eslint-config-next": "16.0.3",
"eslint-config-prettier": "^10.1.8",
"postcss": "8.5.6",
"prettier": "3.6.2",
"prettier-plugin-tailwindcss": "0.7.1",
"tailwindcss": "4.1.17",
"tw-animate-css": "1.4.0",
"typescript": "5.9.3",
"typescript-eslint": "8.46.3"
"typescript-eslint": "8.47.0"
},
"ct3aMetadata": {
"initVersion": "7.39.3"
},
"packageManager": "pnpm@10.20.0"
"packageManager": "pnpm@10.22.0",
"pnpm": {
"overrides": {
"@types/react": "19.2.6",
"@types/react-dom": "19.2.3"
}
}
}

1454
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +0,0 @@
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
export default {
plugins: ["prettier-plugin-tailwindcss"],
};

View File

@@ -1,5 +1,6 @@
"use client";
import { useState, useEffect } from "react";
import type React from "react";
import {
type LucideIcon,
HandCoins,
@@ -112,46 +113,49 @@ export default function MultiIconPattern({ opacity = 0.2, spacing = 160 }) {
Target,
];
const renderIcons = ({
rows,
columns,
}: {
rows: number;
columns: number;
}) => {
const icons = [];
const [icons, setIcons] = useState<React.ReactElement[]>([]);
useEffect(() => {
if (rows === 0 || columns === 0) {
setIcons([]);
return;
}
const iconElements: React.ReactElement[] = [];
for (let y = 0; y < rows; y++) {
for (let x = 0; x < columns; x++) {
// Pick a random icon component from the array
const randomIndex = Math.floor(Math.random() * iconComponents.length);
const IconComponent = iconComponents[randomIndex]!;
const IconComponent = iconComponents[randomIndex];
// Slightly randomize size and position for more organic feel
const size = 28 + Math.floor(Math.random() * 8);
const xOffset = Math.floor(Math.random() * (spacing / 1.618));
const yOffset = Math.floor(Math.random() * (spacing / 1.618));
const rotation = Math.round((Math.random() - 0.5) * 30);
icons.push(
iconElements.push(
<IconComponent
key={`icon-${x}-${y}`}
key={`icon-${String(x)}-${String(y)}`}
size={size}
className="text-primary fixed"
style={{
left: `${x * spacing + xOffset}px`,
top: `${y * spacing + yOffset}px`,
left: `${String(x * spacing + xOffset)}px`,
top: `${String(y * spacing + yOffset)}px`,
opacity: opacity,
transform: `rotate(${Math.round((Math.random() - 0.5) * 30)}deg)`,
transform: `rotate(${String(rotation)}deg)`,
}}
/>,
);
}
}
return icons;
};
setIcons(iconElements);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [rows, columns, spacing, opacity]);
return (
<div className="absolute h-full w-full">
{width > 0 && renderIcons({ rows, columns })}
{width > 0 && icons}
</div>
);
}

View File

@@ -216,7 +216,7 @@ export default function FireCalculatorForm() {
return [0, 0];
})();
if (retirementIndex === -1 || !retirementData) {
if (retirementIndex === -1) {
setResult({
fireNumber: null,
fireNumber4percent: null,
@@ -246,7 +246,13 @@ export default function FireCalculatorForm() {
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<form
onSubmit={(e) => {
e.preventDefault();
void form.handleSubmit(onSubmit)(e);
}}
className="space-y-8"
>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
<FormField
control={form.control}
@@ -265,7 +271,8 @@ export default function FireCalculatorForm() {
? undefined
: Number(e.target.value),
);
void form.handleSubmit(onSubmit)();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
form.handleSubmit(onSubmit)();
}}
onBlur={field.onBlur}
name={field.name}
@@ -293,7 +300,8 @@ export default function FireCalculatorForm() {
? undefined
: Number(e.target.value),
);
void form.handleSubmit(onSubmit)();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
form.handleSubmit(onSubmit)();
}}
onBlur={field.onBlur}
name={field.name}
@@ -321,7 +329,8 @@ export default function FireCalculatorForm() {
? undefined
: Number(e.target.value),
);
void form.handleSubmit(onSubmit)();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
form.handleSubmit(onSubmit)();
}}
onBlur={field.onBlur}
name={field.name}
@@ -349,7 +358,8 @@ export default function FireCalculatorForm() {
? undefined
: Number(e.target.value),
);
void form.handleSubmit(onSubmit)();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
form.handleSubmit(onSubmit)();
}}
onBlur={field.onBlur}
name={field.name}
@@ -378,7 +388,8 @@ export default function FireCalculatorForm() {
? undefined
: Number(e.target.value),
);
void form.handleSubmit(onSubmit)();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
form.handleSubmit(onSubmit)();
}}
onBlur={field.onBlur}
name={field.name}
@@ -407,7 +418,8 @@ export default function FireCalculatorForm() {
? undefined
: Number(e.target.value),
);
void form.handleSubmit(onSubmit)();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
form.handleSubmit(onSubmit)();
}}
onBlur={field.onBlur}
name={field.name}
@@ -437,7 +449,8 @@ export default function FireCalculatorForm() {
? undefined
: Number(e.target.value),
);
void form.handleSubmit(onSubmit)();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
form.handleSubmit(onSubmit)();
}}
onBlur={field.onBlur}
name={field.name}
@@ -467,7 +480,8 @@ export default function FireCalculatorForm() {
step={1}
onValueChange={(value: number[]) => {
field.onChange(value[0]);
void form.handleSubmit(onSubmit)();
// eslint-disable-next-line @typescript-eslint/no-floating-promises
form.handleSubmit(onSubmit)();
}}
className="py-4"
/>
@@ -648,7 +662,7 @@ export default function FireCalculatorForm() {
)}
{result && (
<Button
onClick={() => setShowing4percent(!showing4percent)}
onClick={() => { setShowing4percent(!showing4percent); }}
variant={showing4percent ? "secondary" : "default"}
size={"sm"}
>

View File

@@ -66,7 +66,7 @@ export default function HomePage() {
};
return (
<main className="text-primary-foreground to-destructive from-secondary flex min-h-screen flex-col items-center bg-gradient-to-b p-2">
<main className="text-primary-foreground to-destructive from-secondary flex min-h-screen flex-col items-center bg-linear-to-b p-2">
<BackgroundPattern />
<div className="z-10 mx-auto flex flex-col items-center justify-center gap-4 text-center">
<div className="mt-8 flex flex-row flex-wrap items-center justify-center gap-4 align-middle">
@@ -78,7 +78,7 @@ export default function HomePage() {
width={100}
height={100}
/>
<h1 className="from-primary via-primary-foreground to-primary bg-gradient-to-r bg-clip-text text-5xl font-extrabold tracking-tight text-transparent drop-shadow-md sm:text-[5rem]">
<h1 className="from-primary via-primary-foreground to-primary bg-linear-to-r bg-clip-text text-5xl font-extrabold tracking-tight text-transparent drop-shadow-md sm:text-[5rem]">
InvestingFIRE
</h1>
</div>

View File

@@ -20,9 +20,9 @@ export type ChartConfig = Record<
)
>;
type ChartContextProps = {
interface ChartContextProps {
config: ChartConfig;
};
}
const ChartContext = React.createContext<ChartContextProps | null>(null);
@@ -135,12 +135,12 @@ function ChartTooltipContent({
return null;
}
const [item] = payload;
const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`;
const item = payload[0];
const key = labelKey ?? String(item.dataKey ?? item.name ?? "value");
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const value =
!labelKey && typeof label === "string"
? (config[label]?.label ?? label)
? (label in config && config[label].label ? config[label].label : undefined) ?? label
: itemConfig?.label;
if (labelFormatter) {
@@ -175,14 +175,14 @@ function ChartTooltipContent({
return (
<div
className={cn(
"border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
"border-border/50 bg-background grid min-w-32 items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
className,
)}
>
{!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5">
{payload.map((item, index) => {
const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}`;
const key = nameKey ?? String(item.name ?? item.dataKey ?? "value");
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const indicatorColor: string | undefined =
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
@@ -196,7 +196,7 @@ function ChartTooltipContent({
indicator === "dot" && "items-center",
)}
>
{formatter && item?.value !== undefined && item.name ? (
{formatter && item.value !== undefined && item.name ? (
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
formatter(item.value, item.name, item, index, item.payload)
) : (
@@ -207,7 +207,7 @@ function ChartTooltipContent({
!hideIndicator && (
<div
className={cn(
"shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
"shrink-0 rounded-[2px] border-border bg-(--color-bg)",
{
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",

View File

@@ -18,12 +18,12 @@ import { Label } from "@/components/ui/label";
const Form = FormProvider;
type FormFieldContextValue<
interface FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = {
> {
name: TName;
};
}
const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue,
@@ -61,9 +61,9 @@ const useFormField = () => {
};
};
type FormItemContextValue = {
interface FormItemContextValue {
id: string;
};
}
const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue,
@@ -110,7 +110,7 @@ function FormControl({ ...props }: React.ComponentProps<typeof Slot>) {
id={formItemId}
aria-describedby={
!error
? `${formDescriptionId}`
? formDescriptionId
: `${formDescriptionId} ${formMessageId}`
}
aria-invalid={!!error}
@@ -134,7 +134,7 @@ function FormDescription({ className, ...props }: React.ComponentProps<"p">) {
function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
const { error, formMessageId } = useFormField();
const body = error ? String(error?.message ?? "") : props.children;
const body = error ? (error.message ?? "") : props.children;
if (!body) {
return null;

View File

@@ -37,7 +37,7 @@ function SelectTrigger({
data-slot="select-trigger"
data-size={size}
className={cn(
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"border-input data-placeholder:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}
@@ -61,7 +61,7 @@ function SelectContent({
<SelectPrimitive.Content
data-slot="select-content"
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 relative z-50 max-h-(--radix-select-content-available-height) min-w-32 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className,
@@ -74,7 +74,7 @@ function SelectContent({
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1",
"h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width) scroll-my-1",
)}
>
{children}
@@ -107,7 +107,7 @@ function SelectItem({
<SelectPrimitive.Item
data-slot="select-item"
className={cn(
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
className,
)}
{...props}

View File

@@ -31,7 +31,7 @@ function Slider({
min={min}
max={max}
className={cn(
"relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
"relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
className,
)}
{...props}

View File

@@ -1,42 +1,35 @@
{
"compilerOptions": {
/* Base Options: */
"esModuleInterop": true,
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": false,
"skipLibCheck": true,
"target": "es2022",
"allowJs": true,
"resolveJsonModule": true,
"moduleDetection": "force",
"isolatedModules": true,
"verbatimModuleSyntax": true,
/* Strictness */
"strict": true,
"noUncheckedIndexedAccess": true,
"checkJs": true,
/* Bundled projects */
"lib": ["dom", "dom.iterable", "ES2022"],
"noEmit": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "preserve",
"plugins": [{ "name": "next" }],
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
/* Path Aliases */
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"target": "ES2022",
"forceConsistentCasingInFileNames": true,
"verbatimModuleSyntax": true,
"noUncheckedIndexedAccess": false,
"exactOptionalPropertyTypes": false,
"noImplicitReturns": false,
"plugins": [{ "name": "next" }]
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"**/*.cjs",
"**/*.js",
".next/types/**/*.ts"
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": ["node_modules"]
}