This commit is contained in:
Felix Schulze 2025-04-29 18:33:19 +02:00
parent 97fa489d6c
commit 6018239c43
5 changed files with 619 additions and 4 deletions

218
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@hookform/resolvers": "^5.0.1",
"@radix-ui/react-accordion": "^1.2.8",
"@radix-ui/react-label": "^2.1.4",
"@radix-ui/react-slot": "^1.2.0",
"@t3-oss/env-nextjs": "^0.12.0",
@ -883,6 +884,99 @@
"node": ">=12.4.0"
}
},
"node_modules/@radix-ui/primitive": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
"integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==",
"license": "MIT"
},
"node_modules/@radix-ui/react-accordion": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.8.tgz",
"integrity": "sha512-c7OKBvO36PfQIUGIjj1Wko0hH937pYFU2tR5zbIJDUsmTzHoZVHHt4bmb7OOJbzTaWJtVELKWojBHa7OcnUHmQ==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.2",
"@radix-ui/react-collapsible": "1.1.8",
"@radix-ui/react-collection": "1.1.4",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-direction": "1.1.1",
"@radix-ui/react-id": "1.1.1",
"@radix-ui/react-primitive": "2.1.0",
"@radix-ui/react-use-controllable-state": "1.2.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.8.tgz",
"integrity": "sha512-hxEsLvK9WxIAPyxdDRULL4hcaSjMZCfP7fHB0Z1uUnDoDBat1Zh46hwYfa69DeZAbJrPckjf0AGAtEZyvDyJbw==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.2",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-id": "1.1.1",
"@radix-ui/react-presence": "1.1.4",
"@radix-ui/react-primitive": "2.1.0",
"@radix-ui/react-use-controllable-state": "1.2.2",
"@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collection": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.4.tgz",
"integrity": "sha512-cv4vSf7HttqXilDnAnvINd53OTl1/bjUYVZrkFnA7nwmY9Ob2POUy0WY0sfqBAe1s5FyKsyceQlqiEGPYNTadg==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-primitive": "2.1.0",
"@radix-ui/react-slot": "1.2.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
@ -898,6 +992,54 @@
}
}
},
"node_modules/@radix-ui/react-context": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-direction": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-id": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-label": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.4.tgz",
@ -921,6 +1063,30 @@
}
}
},
"node_modules/@radix-ui/react-presence": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
"integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-primitive": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.0.tgz",
@ -962,6 +1128,58 @@
}
}
},
"node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-use-effect-event": "0.0.2",
"@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-effect-event": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
"integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",

View File

@ -17,6 +17,7 @@
},
"dependencies": {
"@hookform/resolvers": "^5.0.1",
"@radix-ui/react-accordion": "^1.2.8",
"@radix-ui/react-label": "^2.1.4",
"@radix-ui/react-slot": "^1.2.0",
"@t3-oss/env-nextjs": "^0.12.0",

View File

@ -4,8 +4,10 @@ import { type Metadata } from "next";
import { Geist } from "next/font/google";
export const metadata: Metadata = {
title: "Create T3 App",
description: "Generated by create-t3-app",
title:
"FIRE Calculator - Plan Your Financial Independence & Early Retirement",
description:
"Calculate your FIRE number, estimate your retirement age, and plan your path to financial independence with this comprehensive FIRE calculator.",
icons: [{ rel: "icon", url: "/favicon.ico" }],
};
@ -18,7 +20,7 @@ export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en" className={`${geist.variable}`}>
<html lang="en" className={geist.variable}>
<body>{children}</body>
</html>
);

View File

@ -1,14 +1,348 @@
import FireCalculatorForm from "./components/FireCalculatorForm";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
export default function HomePage() {
return (
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[oklch(0.49_0.1326_259.29)] to-[oklch(0.33_0.1316_336.24)] p-4 text-[oklch(0.97_0.0228_95.96)]">
<main className="text-primary-foreground to-destructive from-secondary flex min-h-screen flex-col items-center bg-gradient-to-b p-4">
<div className="container mx-auto flex flex-col items-center justify-center gap-12 px-4 py-16">
<h1 className="text-primary-foreground text-5xl font-extrabold tracking-tight sm:text-[5rem]">
FIRE Calculator
</h1>
<FireCalculatorForm />
</div>
{/* Added SEO Content Sections */}
<div className="container mx-auto max-w-4xl px-4 py-8 text-left">
<section className="mb-12">
<h2 className="mb-4 text-3xl font-bold">What is FIRE?</h2>
<p className="mb-4 text-lg leading-relaxed">
FIRE stands for &quot;Financial Independence, Retire Early.&quot;
It&apos;s a movement focused on aggressive saving and investing to
build a large enough portfolio that the returns can cover living
expenses indefinitely. Achieving FIRE means you are no longer
dependent on traditional employment to fund your lifestyle, giving
you the freedom to pursue passions, travel, or simply enjoy life
without the need for a regular paycheck.
</p>
<p className="text-lg leading-relaxed">
The core principle often involves saving a high percentage of income
(sometimes 50% or more) and investing it wisely, typically in
low-cost index funds. The target amount, often called the &quot;FIRE
number,&quot; is usually calculated as 25 times your desired annual
spending, based on the 4% safe withdrawal rate rule.
</p>
</section>
<section className="mb-12">
<h2 className="mb-4 text-3xl font-bold">How This Calculator Works</h2>
<p className="mb-4 text-lg leading-relaxed">
This calculator helps you estimate your path to FIRE based on your
current financial situation and future projections. Here&apos;s a
breakdown of the inputs:
</p>
<ul className="mb-4 ml-6 list-disc space-y-2 text-lg">
<li>
<strong>Starting Capital:</strong> The total amount you currently
have invested.
</li>
<li>
<strong>Monthly Savings:</strong> The amount you consistently save
and invest each month.
</li>
<li>
<strong>Current Age:</strong> Your current age in years.
</li>
<li>
<strong>Expected Annual Growth Rate (%):</strong> The average
annual return you expect from your investments (after fees, before
inflation).
</li>
<li>
<strong>Desired Monthly Allowance (Today&apos;s Value):</strong>{" "}
How much you want to be able to spend each month in retirement, in
today&apos;s money value.
</li>
<li>
<strong>Annual Inflation Rate (%):</strong> The expected average
rate at which the cost of living will increase.
</li>
<li>
<strong>Life Expectancy (Age):</strong> The age until which you
want your funds to last.
</li>
</ul>
<p className="text-lg leading-relaxed">
The calculator simulates your investment growth year by year,
factoring in monthly contributions, compound growth, and
inflation&apos;s effect on your target allowance. It then determines
the age at which your accumulated capital is sufficient to sustain
your desired, inflation-adjusted monthly allowance throughout your
expected retirement years until your specified life expectancy. It
estimates your &quot;FIRE Number&quot; (the capital needed at
retirement) and the age you might reach it.
</p>
</section>
<section className="mb-12">
<h2 className="mb-4 text-3xl font-bold">
Frequently Asked Questions (FAQ)
</h2>
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="item-1">
<AccordionTrigger className="text-xl font-semibold">
What is the 4% rule?
</AccordionTrigger>
<AccordionContent className="text-lg leading-relaxed">
The 4% rule is a guideline suggesting that you can safely
withdraw 4% of your investment portfolio&apos;s value in your
first year of retirement, and then adjust that amount for
inflation each subsequent year, with a high probability of your
money lasting for at least 30 years. This calculator uses a more
dynamic simulation based on your life expectancy but is related
to this concept.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger className="text-xl font-semibold">
Is the Expected Growth Rate realistic?
</AccordionTrigger>
<AccordionContent className="text-lg leading-relaxed">
Historically, diversified stock market investments have returned
around 7-10% annually over the long term, before inflation. A
rate of 7% (after fees) is often used as a reasonable estimate,
but past performance doesn&apos;t guarantee future results.
It&apos;s crucial to choose a rate you feel comfortable with and
understand the associated risks.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3">
<AccordionTrigger className="text-xl font-semibold">
How does inflation impact my FIRE number?
</AccordionTrigger>
<AccordionContent className="text-lg leading-relaxed">
Inflation erodes the purchasing power of money over time. Your
desired monthly allowance needs to increase each year just to
maintain the same standard of living. This calculator accounts
for this by adjusting your target allowance upwards based on the
inflation rate you provide, ensuring the calculated FIRE number
supports your desired lifestyle in future dollars.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-4">
<AccordionTrigger className="text-xl font-semibold">
Can I really retire early?
</AccordionTrigger>
<AccordionContent className="text-lg leading-relaxed">
Retiring significantly earlier than traditional retirement age
is possible but requires discipline, a high savings rate, and
consistent investment growth. The feasibility depends heavily on
your income, expenses, savings habits, and investment returns.
Use this calculator as a tool for planning and motivation, but
remember it provides estimates based on your inputs.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-5">
<AccordionTrigger className="text-xl font-semibold">
What does FIRE stand for?
</AccordionTrigger>
<AccordionContent className="text-lg leading-relaxed">
FIRE stands for Financial Independence, Retire Early. It
represents a lifestyle movement aimed at maximizing your savings
rate through increased income and/or decreased expenses to
achieve financial independence and retire much earlier than
traditional retirement age.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-6">
<AccordionTrigger className="text-xl font-semibold">
How much should I save each month?
</AccordionTrigger>
<AccordionContent className="text-lg leading-relaxed">
FIRE enthusiasts typically aim to save 50-70% of their income.
The more you can save, the faster you&apos;ll reach your FIRE
goal. However, the right amount depends on your income,
lifestyle, and target retirement age. Use the calculator to
experiment with different monthly savings amounts to see their
impact on your retirement timeline.
</AccordionContent>
</AccordionItem>
</Accordion>
</section>
{/* Optional: Add a section for relevant resources/links here */}
<section className="mb-12">
<h2 className="mb-4 text-3xl font-bold">
Further Reading & Resources
</h2>
<p className="mb-6 text-lg leading-relaxed">
Want to learn more about FIRE and continue your journey to financial
independence? Here are some valuable resources to explore:
</p>
<div className="bg-secondary/20 my-8 rounded-md p-4 text-lg">
<p className="font-semibold">Getting Started with FIRE:</p>
<ol className="ml-6 list-decimal space-y-1">
<li>
Read foundational content like Mr. Money Mustache&apos;s simple
math article
</li>
<li>
Calculate your personal numbers using this and other FIRE
calculators
</li>
<li>
Join communities like r/Fire to ask questions and find support
</li>
<li>Explore books and podcasts to deepen your understanding</li>
</ol>
</div>
<div className="grid gap-8 md:grid-cols-2">
<div>
<h3 className="mb-3 text-xl font-semibold">Blogs & Websites</h3>
<ul className="ml-6 list-disc space-y-2 text-lg">
<li>
<a
href="https://www.mrmoneymustache.com/2012/01/13/the-shockingly-simple-math-behind-early-retirement/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Mr. Money Mustache - The Shockingly Simple Math Behind Early
Retirement
</a>
</li>
<li>
<a
href="https://www.playingwithfire.co/resources"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Playing With FIRE - Comprehensive Resources
</a>
</li>
<li>
<a
href="https://www.reddit.com/r/Fire/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
r/Fire Reddit Community
</a>
</li>
</ul>
</div>
<div>
<h3 className="mb-3 text-xl font-semibold">Books & Learning</h3>
<ul className="ml-6 list-disc space-y-2 text-lg">
<li>
<a
href="https://www.amazon.com/Your-Money-Life-Transforming-Relationship/dp/0143115766"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Your Money or Your Life - Vicki Robin & Joe Dominguez
</a>
</li>
<li>
<a
href="https://www.playingwithfire.co/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Playing With FIRE Documentary
</a>
</li>
<li>
<a
href="https://podcasts.apple.com/us/podcast/can-you-retire-now-this-fire-calculator-will-tell-you/id1330225136?i=1000683436292"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
BiggerPockets Money Podcast - FIRE Calculators
</a>
</li>
</ul>
</div>
<div>
<h3 className="mb-3 text-xl font-semibold">
Additional Calculators & Tools
</h3>
<ul className="ml-6 list-disc space-y-2 text-lg">
<li>
<a
href="https://walletburst.com/tools/coast-fire-calculator/"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Coast FIRE Calculator - For those considering a partial
early retirement
</a>
</li>
<li>
<a
href="https://www.empower.com/retirement-calculator"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Empower Retirement Planner - Free portfolio analysis and net
worth tracking
</a>
</li>
</ul>
</div>
<div>
<h3 className="mb-3 text-xl font-semibold">
Recent Articles & Trends
</h3>
<ul className="ml-6 list-disc space-y-2 text-lg">
<li>
<a
href="https://www.businessinsider.com/retiring-tech-early-coast-fire-make-me-millionaire-2025-4"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Coast FIRE: Retiring in your 30s while becoming a
millionaire by 60
</a>
</li>
<li>
<a
href="https://www.businessinsider.com/financial-independence-retire-early-saving-loneliness-retreat-bali-making-friends-2025-2"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
The Social Side of FIRE: Finding Community in Financial
Independence
</a>
</li>
</ul>
</div>
</div>
</section>
</div>
</main>
);
}

View File

@ -0,0 +1,60 @@
"use client";
import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
const Accordion = AccordionPrimitive.Root;
const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item
ref={ref}
className={cn("border-primary-foreground/20 border-b", className)}
{...props}
/>
));
AccordionItem.displayName = "AccordionItem";
const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className,
)}
{...props}
>
{children}
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));
AccordionTrigger.displayName = "AccordionTrigger";
const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className={cn(
"data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm transition-all",
className,
)}
{...props}
>
<div className="pt-0 pb-4">{children}</div>
</AccordionPrimitive.Content>
));
AccordionContent.displayName = "AccordionContent";
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };