├── .env.example ├── .eslintrc.json ├── .github └── FUNDING.yml ├── .gitignore ├── .npmrc ├── .vscode └── settings.json ├── LICENSE.md ├── README.md ├── app ├── (hand-crafted) │ ├── buttons │ │ └── page.tsx │ ├── cards │ │ └── page.tsx │ ├── carousel │ │ └── page.tsx │ ├── cta │ │ └── page.tsx │ ├── forms │ │ └── page.tsx │ ├── hero │ │ └── page.tsx │ ├── icons │ │ └── animated-arrow.tsx │ ├── inputs │ │ └── page.tsx │ ├── navbars │ │ └── page.tsx │ ├── scroll │ │ └── page.tsx │ └── text │ │ └── page.tsx ├── (marketting) │ ├── _components │ │ ├── call-to-action.tsx │ │ ├── features-grid.tsx │ │ ├── hero.tsx │ │ ├── index.ts │ │ ├── stack.tsx │ │ └── testimonials.tsx │ ├── layout.tsx │ └── page.tsx ├── (templates) │ └── templates │ │ └── page.tsx ├── docs │ ├── [[...slug]] │ │ └── page.tsx │ └── layout.tsx └── layout.tsx ├── comments.tsx ├── components.json ├── components ├── all-components.tsx ├── announcement.tsx ├── buttons │ ├── checkout.tsx │ ├── create-new.tsx │ ├── delete.tsx │ ├── get-started.tsx │ ├── github.tsx │ ├── one.tsx │ └── two.tsx ├── callout.tsx ├── cards │ ├── add.tsx │ ├── birthday.tsx │ ├── booking.tsx │ ├── calendar-subcriptions.tsx │ ├── calendar.tsx │ ├── call.tsx │ ├── card-one.tsx │ ├── check-card.tsx │ ├── credit-card.tsx │ ├── drop.tsx │ ├── experience.tsx │ ├── gallery-two.tsx │ ├── gallery.tsx │ ├── heightlights.tsx │ ├── linear.tsx │ ├── loader.tsx │ ├── loading.tsx │ ├── menu.tsx │ ├── nother.tsx │ ├── nothing.tsx │ ├── option.tsx │ ├── overview-stacked.tsx │ ├── overview.tsx │ ├── piano.tsx │ ├── pill.tsx │ ├── sm-navbar.tsx │ ├── vercel.tsx │ ├── wheel.tsx │ └── words.tsx ├── carousel │ ├── another.tsx │ ├── mouse-move.tsx │ ├── spinner.tsx │ ├── swipe-two.tsx │ ├── swipe.tsx │ └── tilt.tsx ├── code-block-wrapper.tsx ├── component-card.tsx ├── component-example.tsx ├── component-list-item.tsx ├── component-preview.tsx ├── component-source.tsx ├── copy-button.tsx ├── drawer.tsx ├── form │ └── google.tsx ├── framework-docs.tsx ├── grid │ └── beam.tsx ├── hand-crafted │ ├── check-box.tsx │ ├── loading.tsx │ └── trans.tsx ├── header-dock-item.tsx ├── icons.tsx ├── inputs │ ├── apple.tsx │ ├── google.tsx │ ├── password-strength.tsx │ ├── validity.tsx │ ├── verifier-with-zod.tsx │ └── verifier.tsx ├── main-nav.tsx ├── mdx-base-components.tsx ├── mdx-components.tsx ├── mobile-nav.tsx ├── mode-toggle.tsx ├── navbar │ ├── Navbar.tsx │ ├── chevron.tsx │ ├── dimension.tsx │ ├── liquid-morph.tsx │ ├── notch-bar.tsx │ ├── scroll-reveal.tsx │ ├── sticky-top.tsx │ ├── toolbar.tsx │ └── vercel.tsx ├── others │ └── cursor.tsx ├── page-header.tsx ├── pager.tsx ├── preview-container.tsx ├── providers.tsx ├── reload-button.tsx ├── remount-on-mouse-in.tsx ├── scroll │ ├── air-pods.tsx │ ├── horizontal.tsx │ └── scroller.tsx ├── shared │ ├── animate-enter.tsx │ ├── arrow.tsx │ ├── breadcrumb.tsx │ ├── doc-header.tsx │ ├── docs-actions.tsx │ ├── docs-navbar.tsx │ ├── docs-sidebar.tsx │ ├── feeback.tsx │ ├── footer.tsx │ ├── icons.tsx │ ├── loading.tsx │ ├── logo.tsx │ ├── navbar.tsx │ └── theme-switcher.tsx ├── tailwind-indicator.tsx ├── text │ └── first.tsx ├── toc.tsx └── ui │ ├── accordion.tsx │ ├── alert.tsx │ ├── aspect-ratio.tsx │ ├── badge.tsx │ ├── breadcrumb.tsx │ ├── button.tsx │ ├── collapsible.tsx │ ├── command-dialog.tsx │ ├── command-menu-components.tsx │ ├── command-menu.tsx │ ├── command.tsx │ ├── dialog.tsx │ ├── dropdown-menu.tsx │ ├── form.tsx │ ├── hover-card.tsx │ ├── input.tsx │ ├── label.tsx │ ├── lamp.tsx │ ├── scroll-area.tsx │ ├── separator.tsx │ ├── sheet.tsx │ ├── tabs.tsx │ ├── textarea.tsx │ └── tooltip.tsx ├── config ├── docs.ts ├── index.tsx └── site.ts ├── constants └── index.ts ├── content └── docs │ ├── changelog.mdx │ ├── components │ ├── button │ │ ├── checkout.mdx │ │ ├── create-new.mdx │ │ ├── delete.mdx │ │ ├── github.mdx │ │ ├── index.mdx │ │ ├── second-brain.mdx │ │ └── sparkles.mdx │ ├── cards │ │ ├── birthday.mdx │ │ ├── booking.mdx │ │ ├── calendar.mdx │ │ ├── call.mdx │ │ ├── counter.mdx │ │ ├── experience.mdx │ │ ├── frequency.mdx │ │ ├── hello-world.mdx │ │ ├── index.mdx │ │ ├── linear.mdx │ │ ├── notch-two.mdx │ │ ├── notch.mdx │ │ ├── overview-stacked.mdx │ │ ├── overview.mdx │ │ ├── piano.mdx │ │ ├── pill.mdx │ │ └── strike.mdx │ ├── carousel │ │ ├── index.mdx │ │ ├── one.mdx │ │ ├── perspective.mdx │ │ └── swipe.mdx │ ├── gallery │ │ ├── hover.mdx │ │ ├── index.mdx │ │ ├── one.mdx │ │ ├── radial.mdx │ │ └── two.mdx │ ├── index.mdx │ ├── inputs │ │ ├── google.mdx │ │ ├── iMessage.mdx │ │ ├── index.mdx │ │ ├── password-strength.mdx │ │ ├── validity.mdx │ │ └── verifier.mdx │ ├── layouts │ │ ├── grid-to-flex.mdx │ │ ├── index.mdx │ │ └── scroll-count.mdx │ ├── menu │ │ ├── circular.mdx │ │ ├── hamburger.mdx │ │ ├── index.mdx │ │ └── mode-toggle.mdx │ └── navbars │ │ ├── liquid.mdx │ │ ├── reveal.mdx │ │ └── vercel.mdx │ ├── contributing │ ├── best-practices.mdx │ ├── components.mdx │ ├── folder-structure.mdx │ ├── guidelines.mdx │ ├── index.mdx │ └── running-locally.mdx │ ├── index.mdx │ ├── setup.mdx │ └── without-framer-motion │ └── marquee.mdx ├── contentlayer.config.ts ├── context └── command-menu.tsx ├── fg ├── button │ ├── checkout.tsx │ ├── create-new.tsx │ ├── delete.tsx │ ├── github.tsx │ ├── second-brain.tsx │ ├── sparkles.tsx │ └── status-button.tsx ├── cards │ ├── birthday.tsx │ ├── booking.tsx │ ├── calendar.tsx │ ├── call.tsx │ ├── cashflow-heatmap.tsx │ ├── counter.tsx │ ├── experience.tsx │ ├── frequency.tsx │ ├── hello-world.tsx │ ├── linear.tsx │ ├── notch-two.tsx │ ├── notch.tsx │ ├── overview-stacked.tsx │ ├── overview.tsx │ ├── piano.tsx │ ├── pill.tsx │ └── strike.tsx ├── carousel │ ├── one.tsx │ ├── perspective.tsx │ └── swipe.tsx ├── gallery │ ├── hover.tsx │ ├── one.tsx │ ├── radial.tsx │ └── two.tsx ├── inputs │ ├── google.tsx │ ├── iMessage.tsx │ ├── password-strength-zod.tsx │ ├── password-strength.tsx │ ├── validity.tsx │ ├── verifier-with-zod.tsx │ └── verifier.tsx ├── layouts │ ├── grid-to-flex.tsx │ └── scroll-count.tsx ├── menu │ ├── circular.tsx │ ├── hamburger.tsx │ └── mode-toggle.tsx ├── navbar │ ├── liquid.tsx │ ├── reveal.tsx │ ├── vercel-vertical.tsx │ └── vercel.tsx ├── overlay │ └── modal.tsx ├── text │ └── animated-gradient-text.tsx └── without-framer-motion │ ├── marquee-demo.tsx │ ├── marquee.tsx │ └── vertical-marquee.tsx ├── fonts ├── Satoshi-Black.otf ├── Satoshi-BlackItalic.otf ├── Satoshi-Bold.otf ├── Satoshi-BoldItalic.otf ├── Satoshi-Italic.otf ├── Satoshi-Light.otf ├── Satoshi-LightItalic.otf ├── Satoshi-Medium.otf ├── Satoshi-MediumItalic.otf └── Satoshi-Regular.otf ├── hooks ├── click-outsite.ts ├── use-lock-body.ts ├── use-media-query.ts ├── use-mounted.ts ├── use-mouse-position.ts ├── use-mutation-observer.ts └── use-newsletter-subscription.ts ├── lib ├── events.ts ├── moonlight.json ├── toc.ts └── utils.ts ├── next.config.mjs ├── package.json ├── pnpm-lock.yaml ├── postcss.config.mjs ├── providers ├── cash-flow.tsx ├── global.tsx └── theme.tsx ├── public ├── airpods │ ├── 1.webp │ ├── 10.webp │ ├── 11.webp │ ├── 12.webp │ ├── 13.webp │ ├── 14.webp │ ├── 15.webp │ ├── 16.webp │ ├── 17.webp │ ├── 18.webp │ ├── 19.webp │ ├── 2.webp │ ├── 20.webp │ ├── 21.webp │ ├── 22.webp │ ├── 23.webp │ ├── 24.webp │ ├── 25.webp │ ├── 26.webp │ ├── 27.webp │ ├── 28.webp │ ├── 29.webp │ ├── 3.webp │ ├── 30.webp │ ├── 31.webp │ ├── 32.webp │ ├── 33.webp │ ├── 34.webp │ ├── 35.webp │ ├── 36.webp │ ├── 37.webp │ ├── 38.webp │ ├── 39.webp │ ├── 4.webp │ ├── 40.webp │ ├── 41.webp │ ├── 42.webp │ ├── 43.webp │ ├── 44.webp │ ├── 45.webp │ ├── 46.webp │ ├── 47.webp │ ├── 48.webp │ ├── 49.webp │ ├── 5.webp │ ├── 50.webp │ ├── 51.webp │ ├── 52.webp │ ├── 53.webp │ ├── 54.webp │ ├── 55.webp │ ├── 56.webp │ ├── 57.webp │ ├── 58.webp │ ├── 59.webp │ ├── 6.webp │ ├── 60.webp │ ├── 61.webp │ ├── 62.webp │ ├── 63.webp │ ├── 64.webp │ ├── 65.webp │ ├── 66.webp │ ├── 67.webp │ ├── 68.webp │ ├── 69.webp │ ├── 7.webp │ ├── 70.webp │ ├── 71.webp │ ├── 72.webp │ ├── 73.webp │ ├── 74.webp │ ├── 75.webp │ ├── 76.webp │ ├── 77.webp │ ├── 78.webp │ ├── 79.webp │ ├── 8.webp │ ├── 80.webp │ ├── 81.webp │ ├── 82.webp │ ├── 83.webp │ ├── 84.webp │ ├── 85.webp │ ├── 86.webp │ ├── 9.webp │ └── video.mp4 ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── her │ ├── image1.jpeg │ ├── image2.jpeg │ ├── image3.jpeg │ ├── image4.jpeg │ ├── image5.jpeg │ ├── image6.jpeg │ └── image7.jpeg ├── image1.jpg ├── image2.jpg ├── image3.jpg ├── image4.jpg ├── image5.jpeg ├── image6.jpg ├── image7.jpg ├── image8.jpg ├── logo-dark.svg ├── logo.svg ├── mought.svg ├── music │ ├── audio.mp3 │ └── audio2.mp3 ├── next.svg ├── nothing-1.png ├── nothing.png ├── nothing.svg ├── og.png ├── others │ ├── photo-1.jpg │ ├── photo-2.jpg │ ├── photo-3.jpg │ ├── photo-4.jpg │ ├── photo-5.jpg │ ├── photo-6.jpg │ └── photo-7.jpg ├── site.site.webmanifest ├── templates │ ├── bossadizenith.png │ └── index.ts ├── tes_gen_blog_post_071921_1233182206-1-800x412.jpg ├── think.jpg ├── vercel.svg └── zenith.jpeg ├── scripts └── create-new.js ├── styles ├── globals.css └── mdx.css ├── tailwind.config.ts ├── tsconfig.json └── types ├── index.ts └── unist.ts /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_APP_URL=https://ground.bossadizenith.me 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: code-enn 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env 30 | 31 | # vercel 32 | .vercel 33 | .contentlayer 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true 2 | save-workspace-protocol=false 3 | save-prefix='' 4 | package-import-method=clone-or-copy 5 | package-manager=false 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Framer Ground 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![ground](https://github.com/user-attachments/assets/b2c19564-825b-4656-8937-b6f7a333d1bf) 2 | 3 | # Framer ground 4 | 5 | Elevate your web projects with fine, small animated components. 6 | 7 | 8 | See the website 9 | 10 | 11 | ### How to use? 12 | 13 | Simply click on a component, copy the code and paste it into your project. 14 | 15 | ### Inspiration 16 | 17 | My biggest inspiration for creating components comes from looking at [shadcnui](https://ui.shadnc.me) and websites, such as [Vercel](https://vercel.com), which is fascinating when it comes to user experience. 18 | 19 | I would like to thank [Lndev](https://ui.lndev.me), who was a fundamental inspiration for the creation of this project. 20 | 21 | ### Future plans 22 | 23 | I was very excited to develop this project, it's a great pleasure for me to be working on this, I intend to continue and add more and more components and for other like me back then to add micro animations to their website. 24 | 25 | ### For contributions 26 | 27 | Visit our [contributing guide](https://ground.bossadizenith.me/docs/contributing) to learn how to contribute. _So easy_ that you just run a command to get started. 28 | -------------------------------------------------------------------------------- /app/(hand-crafted)/buttons/page.tsx: -------------------------------------------------------------------------------- 1 | import Checkout from "@/components/buttons/checkout"; 2 | import CreateNew from "@/components/buttons/create-new"; 3 | import Delete from "@/components/buttons/delete"; 4 | import GetStarted from "@/components/buttons/get-started"; 5 | import Github from "@/components/buttons/github"; 6 | import Two from "@/components/buttons/two"; 7 | import React from "react"; 8 | 9 | const Buttons = () => { 10 | return ( 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | ); 20 | }; 21 | 22 | export default Buttons; 23 | -------------------------------------------------------------------------------- /app/(hand-crafted)/carousel/page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import Nothing from "@/components/carousel/another"; 4 | import MouseMove from "@/components/carousel/mouse-move"; 5 | import Spinner from "@/components/carousel/spinner"; 6 | import Swipe from "@/components/carousel/swipe"; 7 | import SwipeTwo from "@/components/carousel/swipe-two"; 8 | import Tilt from "@/components/carousel/tilt"; 9 | 10 | const Carousel = () => { 11 | return ( 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | ); 21 | }; 22 | 23 | export default Carousel; 24 | -------------------------------------------------------------------------------- /app/(hand-crafted)/cta/page.tsx: -------------------------------------------------------------------------------- 1 | import Button from "@/components/buttons/one"; 2 | 3 | const Buttons = () => { 4 | return ( 5 |
6 |
8 | ); 9 | }; 10 | 11 | export default Buttons; 12 | -------------------------------------------------------------------------------- /app/(hand-crafted)/forms/page.tsx: -------------------------------------------------------------------------------- 1 | import Google from "@/components/form/google"; 2 | import React from "react"; 3 | 4 | const Forms = () => { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | }; 11 | 12 | export default Forms; 13 | -------------------------------------------------------------------------------- /app/(hand-crafted)/hero/page.tsx: -------------------------------------------------------------------------------- 1 | import Experience from "@/components/cards/experience"; 2 | import React from "react"; 3 | 4 | const HeroPages = () => { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | }; 11 | 12 | export default HeroPages; 13 | -------------------------------------------------------------------------------- /app/(hand-crafted)/icons/animated-arrow.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { motion } from "framer-motion"; 3 | 4 | interface AnimatedArrowProps { 5 | isHovered: boolean; 6 | } 7 | 8 | const AnimatedArrow = ({ isHovered }: AnimatedArrowProps) => { 9 | return ( 10 | 17 | 31 | 41 | 42 | ); 43 | }; 44 | 45 | export default AnimatedArrow; 46 | -------------------------------------------------------------------------------- /app/(hand-crafted)/inputs/page.tsx: -------------------------------------------------------------------------------- 1 | import Apple from "@/components/inputs/apple"; 2 | import GoogleInput from "@/components/inputs/google"; 3 | import PasswordStrength from "@/components/inputs/password-strength"; 4 | import InputVerification from "@/components/inputs/validity"; 5 | import Verifier from "@/components/inputs/verifier"; 6 | import VerifierWithZod from "@/components/inputs/verifier-with-zod"; 7 | import { Metadata } from "next"; 8 | 9 | export const metadata: Metadata = { 10 | title: "Inputs", 11 | description: "This page showcases the different types of input animation", 12 | }; 13 | 14 | const Inputs = () => { 15 | return ( 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | ); 25 | }; 26 | 27 | export default Inputs; 28 | -------------------------------------------------------------------------------- /app/(hand-crafted)/navbars/page.tsx: -------------------------------------------------------------------------------- 1 | import Toolbar from "@/components/navbar/toolbar"; 2 | import React from "react"; 3 | 4 | const Page = () => { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | }; 11 | 12 | export default Page; 13 | -------------------------------------------------------------------------------- /app/(hand-crafted)/scroll/page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Horizontal from "@/components/scroll/horizontal"; 3 | import Scroller from "@/components/scroll/scroller"; 4 | import { Metadata } from "next"; 5 | 6 | export const metadata: Metadata = { 7 | title: "Scroll Animation", 8 | }; 9 | 10 | const Scroll = () => { 11 | return ( 12 |
13 | {/*
14 | 15 |
*/} 16 | 17 |
18 | ); 19 | }; 20 | 21 | export default Scroll; 22 | -------------------------------------------------------------------------------- /app/(hand-crafted)/text/page.tsx: -------------------------------------------------------------------------------- 1 | import FirstTextNimation from "@/components/text/first"; 2 | import React from "react"; 3 | 4 | const Texts = () => { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | }; 11 | 12 | export default Texts; 13 | -------------------------------------------------------------------------------- /app/(marketting)/_components/index.ts: -------------------------------------------------------------------------------- 1 | import Hero from "./hero"; 2 | import MarkettingNavbar from "../../../components/shared/navbar"; 3 | import CallToAction from "./call-to-action"; 4 | import Stack from "./stack"; 5 | 6 | export { Hero, MarkettingNavbar, CallToAction, Stack }; 7 | -------------------------------------------------------------------------------- /app/(marketting)/_components/stack.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { motion } from "framer-motion"; 5 | import { stacks } from "@/constants"; 6 | 7 | const Stack = () => { 8 | return ( 9 |
10 |
11 | 19 | Powered by your existing stack 20 | 21 |
22 | {stacks.map((stack, index) => ( 23 | 24 | 25 | 26 | ))} 27 |
28 |
29 |
30 | ); 31 | }; 32 | 33 | export default Stack; 34 | -------------------------------------------------------------------------------- /app/(marketting)/layout.tsx: -------------------------------------------------------------------------------- 1 | import Footer from "@/components/shared/footer"; 2 | import Navbar from "@/components/shared/navbar"; 3 | import Link from "next/link"; 4 | import React, { ReactNode } from "react"; 5 | 6 | const MarkettingLayout = ({ children }: { children: ReactNode }) => { 7 | return ( 8 |
9 | 15 |
16 | 🎉 Exciting News! 🎉. Ground v1 is now available. Animations build for 17 | performance. 18 |
19 | 20 | 21 | {children} 22 | 23 |
24 |
25 | ); 26 | }; 27 | 28 | export default MarkettingLayout; 29 | -------------------------------------------------------------------------------- /app/(marketting)/page.tsx: -------------------------------------------------------------------------------- 1 | import { CallToAction, Hero } from "./_components"; 2 | import Testimonials from "./_components/testimonials"; 3 | 4 | async function getGitHubStars(): Promise { 5 | try { 6 | const response = await fetch( 7 | "https://api.github.com/repos/code-env/framer-ground/collaborators", 8 | { 9 | headers: { 10 | Accept: "application/vnd.github+json", 11 | Authorization: `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`, 12 | }, 13 | next: { 14 | revalidate: 60, 15 | }, 16 | } 17 | ); 18 | 19 | if (!response?.ok) { 20 | return null; 21 | } 22 | 23 | const data = await response.json(); 24 | 25 | return data; 26 | } catch (error) { 27 | return null; 28 | } 29 | } 30 | 31 | const LandingPage = async () => { 32 | const data = await getGitHubStars(); 33 | 34 | console.log(data); 35 | 36 | return ( 37 |
38 | 39 | 40 | {/* */} 41 | 42 |
43 | ); 44 | }; 45 | 46 | export default LandingPage; 47 | -------------------------------------------------------------------------------- /app/(templates)/templates/page.tsx: -------------------------------------------------------------------------------- 1 | import { buttonVariants } from "@/components/ui/button"; 2 | import { siteConfig } from "@/config/site"; 3 | import { DiscordLogoIcon } from "@radix-ui/react-icons"; 4 | import Link from "next/link"; 5 | 6 | const Templates = () => { 7 | return ( 8 |
9 |
10 |

11 | Ground. Templates. 12 |

13 |

14 | These templates are designed to help you get started with your next 15 | project. They are fully customizable and built with React, NextJS, 16 | TailwindCSS, Framer Motion and Typescript. 17 |

18 |
19 |
20 |
21 |

22 | New templates are coming be the first to know. Join our discord 23 |

24 | 31 | 32 | Discord 33 | 34 |
35 |
36 |
37 | ); 38 | }; 39 | export default Templates; 40 | -------------------------------------------------------------------------------- /app/docs/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | 3 | import DocsSidebar from "@/components/shared/docs-sidebar"; 4 | import { ScrollArea } from "@/components/ui/scroll-area"; 5 | import { docsConfig } from "@/config/docs"; 6 | import ThemeSwitcher from "@/components/shared/theme-switcher"; 7 | import DocsHeader from "@/components/shared/doc-header"; 8 | import DocsActions from "@/components/shared/docs-actions"; 9 | 10 | const DocsLayout = ({ children }: { children: ReactNode }) => { 11 | return ( 12 |
13 | 20 |
21 | 22 |
{children}
23 |
24 |
25 | ); 26 | }; 27 | 28 | export default DocsLayout; 29 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /components/announcement.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | import { ArrowRight, Combine } from "lucide-react"; 3 | 4 | import AnimatedGradientText from "@/fg/text/animated-gradient-text"; 5 | import { Separator } from "@/components/ui/separator"; 6 | 7 | export function Announcement() { 8 | return ( 9 |
10 | 11 | 12 | {" "} 13 | {" "} 14 | Framer ground is live 15 | {" "} 16 | 17 | 18 |
19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /components/buttons/get-started.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion } from "framer-motion"; 4 | import { Sparkles } from "lucide-react"; 5 | 6 | import { cn } from "@/lib/utils"; 7 | import { useState } from "react"; 8 | 9 | const GetStarted = () => { 10 | const [hovering, setHovering] = useState(false); 11 | return ( 12 |
13 | setHovering(true)} 18 | onMouseLeave={() => setHovering(false)} 19 | className="bg-indigo-500 text-white z-0 relative outline-none border-none text-primary-foreground px-10 py-3 font-medium rounded-xl overflow-hidden hover:shadow-[0_0_10px] hover:shadow-indigo-400" 20 | > 21 | 22 | 23 | 24 | 25 | Get Second Brain 26 | 27 | 28 | 29 | 30 | 36 | 37 |
38 | ); 39 | }; 40 | 41 | export default GetStarted; 42 | -------------------------------------------------------------------------------- /components/buttons/github.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState } from "react"; 4 | import { motion } from "framer-motion"; 5 | 6 | const Github = () => { 7 | const [isHovered, setIsHovered] = useState(false); 8 | 9 | return ( 10 |
11 | 46 |
47 | ); 48 | }; 49 | 50 | export default Github; 51 | -------------------------------------------------------------------------------- /components/buttons/two.tsx: -------------------------------------------------------------------------------- 1 | import { ArrowRight } from "lucide-react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | interface TwoProps { 6 | text: string; 7 | className?: string; 8 | } 9 | 10 | const Two = ({ text = "Get started", className }: TwoProps) => { 11 | return ( 12 |
13 |
14 | 49 |
50 |
51 | ); 52 | }; 53 | 54 | export default Two; 55 | -------------------------------------------------------------------------------- /components/callout.tsx: -------------------------------------------------------------------------------- 1 | import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; 2 | import { cn } from "@/lib/utils"; 3 | 4 | interface CalloutProps { 5 | icon?: string; 6 | title?: string; 7 | className?: string; 8 | children?: React.ReactNode; 9 | } 10 | 11 | export function Callout({ 12 | title, 13 | children, 14 | icon, 15 | className, 16 | ...props 17 | }: CalloutProps) { 18 | return ( 19 | 20 | {icon && {icon}} 21 | {title && {title}} 22 | {children} 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /components/cards/check-card.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState } from "react"; 4 | import { AnimatePresence, motion } from "framer-motion"; 5 | import Checkbox from "../hand-crafted/check-box"; 6 | 7 | const CheckCard = () => { 8 | const [checked, setCheced] = useState(false); 9 | 10 | const variants = { 11 | initial: { 12 | width: 0, 13 | height: 2, 14 | x: -100, 15 | transition: { 16 | duration: 0.5, 17 | }, 18 | }, 19 | animate: { 20 | width: "100%", 21 | height: 2, 22 | x: 0, 23 | transition: { 24 | duration: 0.5, 25 | }, 26 | }, 27 | exit: { 28 | width: 0, 29 | height: 0, 30 | x: -100, 31 | transition: { 32 | duration: 0.5, 33 | }, 34 | }, 35 | }; 36 | 37 | return ( 38 |
39 | 40 | 41 |
42 |
43 | Post on Linkedin 44 | 45 | {checked && ( 46 | 54 | )} 55 | 56 |
57 |
58 |
59 |
60 | ); 61 | }; 62 | 63 | export default CheckCard; 64 | -------------------------------------------------------------------------------- /components/cards/loading.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | 5 | const Loading = () => { 6 | return
Loading
; 7 | }; 8 | 9 | export default Loading; 10 | -------------------------------------------------------------------------------- /components/cards/wheel.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion, useMotionValue, useTransform } from "framer-motion"; 4 | import { useState } from "react"; 5 | 6 | const items = Array.from({ length: 12 }, (_, i) => `Item ${i + 1}`); 7 | 8 | const Wheel: React.FC = () => { 9 | const [isDragging, setIsDragging] = useState(false); 10 | const rotation = useMotionValue(0); 11 | 12 | // Map rotation value to smooth spinning 13 | const rotate = useTransform(rotation, (value) => `rotate(${value}deg)`); 14 | 15 | const startDrag = () => setIsDragging(true); 16 | const endDrag = () => setIsDragging(false); 17 | 18 | const handleDrag = (_: any, info: any) => { 19 | const speedFactor = 0.5; // Adjust to control spin speed 20 | rotation.set(rotation.get() + info.delta.x * speedFactor); 21 | }; 22 | 23 | return ( 24 |
25 | 36 | {items.map((item, index) => ( 37 | 46 | {item} 47 | 48 | ))} 49 | 50 |
51 | ); 52 | }; 53 | 54 | export default Wheel; 55 | -------------------------------------------------------------------------------- /components/cards/words.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState } from "react"; 4 | import { motion, AnimatePresence } from "framer-motion"; 5 | 6 | const words = ["Creative", "Create", "Continue", "Confirm"]; 7 | 8 | const Words = () => { 9 | const [activeWord, setActiveWord] = useState("Creative"); 10 | 11 | const animateWord = (word: string) => { 12 | return ( 13 |
14 | {word.split("").map((char, index) => ( 15 | 22 | {char} 23 | 24 | ))} 25 |
26 | ); 27 | }; 28 | 29 | return ( 30 |
31 |
32 |
33 | 34 | 40 | {animateWord(activeWord)} 41 | 42 | 43 |
44 |
45 | {words.map((word) => ( 46 | 55 | ))} 56 |
57 |
58 |
59 | ); 60 | }; 61 | 62 | export default Words; 63 | -------------------------------------------------------------------------------- /components/carousel/another.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion, useMotionValue, useTransform } from "framer-motion"; 4 | import { Dispatch, SetStateAction, useState } from "react"; 5 | 6 | type Card = { 7 | id: number; 8 | image: string; 9 | }; 10 | 11 | const cardsData: Card[] = [ 12 | { 13 | id: 1, 14 | image: "/others/photo-1.jpg", 15 | }, 16 | { 17 | id: 2, 18 | image: "/others/photo-2.jpg", 19 | }, 20 | { 21 | id: 3, 22 | image: "/others/photo-3.jpg", 23 | }, 24 | { 25 | id: 4, 26 | image: "/others/photo-4.jpg", 27 | }, 28 | { 29 | id: 5, 30 | image: "/others/photo-5.jpg", 31 | }, 32 | ]; 33 | 34 | const Swipe = () => { 35 | const [cards, setCards] = useState(cardsData); 36 | return ( 37 |
38 | {cards 39 | .slice() 40 | .reverse() 41 | .map((card, index) => ( 42 | 49 | ))} 50 |
51 | ); 52 | }; 53 | 54 | interface CardProps { 55 | cards: Card[]; 56 | item: Card; 57 | setCards: Dispatch>; 58 | index: number; 59 | } 60 | 61 | function Card({ item, cards, setCards, index }: CardProps) { 62 | const x = useMotionValue(0); 63 | const frontCard = index === 0; 64 | 65 | const cardsRotation = useTransform(x, [-160, 160], [-20, 20]); 66 | 67 | const rotate = useTransform(() => { 68 | const newOffset = frontCard ? 0 : index % 2 ? 10 : -10; 69 | 70 | return `${cardsRotation.get() + newOffset}deg`; 71 | }); 72 | 73 | return ( 74 | 85 | ); 86 | } 87 | 88 | export default Swipe; 89 | -------------------------------------------------------------------------------- /components/code-block-wrapper.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | 5 | import { Button } from "@/components/ui/button" 6 | import { 7 | Collapsible, 8 | CollapsibleContent, 9 | CollapsibleTrigger, 10 | } from "@/components/ui/collapsible" 11 | import { cn } from "@/lib/utils" 12 | 13 | interface CodeBlockProps extends React.HTMLAttributes { 14 | expandButtonTitle?: string 15 | } 16 | 17 | export function CodeBlockWrapper({ 18 | expandButtonTitle = "View Code", 19 | className, 20 | children, 21 | ...props 22 | }: CodeBlockProps) { 23 | const [isOpened, setIsOpened] = React.useState(false) 24 | 25 | return ( 26 | 27 |
28 | 32 |
38 | {children} 39 |
40 |
41 |
47 | 48 | 51 | 52 |
53 |
54 |
55 | ) 56 | } 57 | -------------------------------------------------------------------------------- /components/component-card.tsx: -------------------------------------------------------------------------------- 1 | import { HTMLAttributes, useState } from "react"; 2 | import Link from "next/link"; 3 | import { ArrowRight, CircleDashed } from "lucide-react"; 4 | 5 | import { cn } from "@/lib/utils"; 6 | 7 | export function ComponentCard({ 8 | name, 9 | href, 10 | className, 11 | rounded = true, 12 | ...props 13 | }: HTMLAttributes & { 14 | href: string; 15 | name: string; 16 | rounded?: boolean; 17 | }) { 18 | const [clicked, setClicked] = useState(false); 19 | return ( 20 |
29 |
38 |

42 | {name} 43 |

44 | setClicked(true)} 47 | className="ml-auto flex items-center gap-1 text-xs font-semibold leading-none text-blue-500 hover:underline" 48 | > 49 | View{" "} 50 | {clicked ? ( 51 | 52 | ) : ( 53 | 54 | )} 55 | 56 |
57 |
58 |
59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /components/component-list-item.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, Suspense, useState } from "react"; 2 | 3 | import { CopyButton } from "@/components/copy-button"; 4 | import { ReloadButton } from "@/components/reload-button"; 5 | import { cn } from "@/lib/utils"; 6 | 7 | function Actions({ 8 | copyId, 9 | onRefresh, 10 | }: { 11 | copyId: string; 12 | onRefresh: () => void; 13 | }) { 14 | return ( 15 |
16 | 21 | 25 |
26 | ); 27 | } 28 | 29 | const lazyList: Record JSX.Element>> = { 30 | "status-button": lazy(() => import("@/fg/button/status-button")), 31 | }; 32 | 33 | export default function ComponentListItem({ 34 | children, 35 | className, 36 | copyId, 37 | lazy, 38 | ...props 39 | }: { 40 | copyId: string; 41 | className?: string; 42 | children: React.ReactNode; 43 | lazy?: boolean; 44 | }) { 45 | const [forceUpdate, setForceUpdate] = useState(0); 46 | const Component = 47 | lazy && Reflect.has(lazyList, copyId) ? lazyList[copyId] : null; 48 | return ( 49 |
53 | setForceUpdate((prev) => prev + 1)} 56 | /> 57 |
61 | {children} 62 | {Component && ( 63 | }> 64 | 65 | 66 | )} 67 |
68 |
69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /components/component-source.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | 5 | import { CodeBlockWrapper } from "@/components/code-block-wrapper"; 6 | import { cn } from "@/lib/utils"; 7 | 8 | interface ComponentSourceProps extends React.HTMLAttributes { 9 | src: string; 10 | } 11 | 12 | export function ComponentSource({ children, className }: ComponentSourceProps) { 13 | return ( 14 | 18 | {children} 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /components/drawer.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { forwardRef } from "react"; 4 | import { Drawer as DrawerPrimitive } from "vaul"; 5 | 6 | import { cn } from "@/lib/utils"; 7 | 8 | const DrawerTrigger = DrawerPrimitive.Trigger; 9 | 10 | const DrawerContent = forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, children, ...props }, ref) => ( 14 | 15 | 16 | 24 |
25 | {children} 26 | 27 | 28 | )); 29 | DrawerContent.displayName = "DrawerContent"; 30 | 31 | export { DrawerContent, DrawerTrigger }; 32 | -------------------------------------------------------------------------------- /components/framework-docs.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { allDocs } from "contentlayer/generated" 5 | 6 | import { Mdx } from "./mdx-components" 7 | 8 | interface FrameworkDocsProps extends React.HTMLAttributes { 9 | data: string 10 | } 11 | 12 | export function FrameworkDocs({ ...props }: FrameworkDocsProps) { 13 | const frameworkDoc = allDocs.find( 14 | (doc) => doc.slug === `/docs/installation/${props.data}` 15 | ) 16 | 17 | if (!frameworkDoc) { 18 | return null 19 | } 20 | 21 | return 22 | } 23 | -------------------------------------------------------------------------------- /components/grid/beam.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { motion } from "framer-motion"; 5 | import { cn } from "@/lib/utils"; 6 | 7 | export const GridBeam: React.FC<{ 8 | children: React.ReactNode; 9 | className?: string; 10 | }> = ({ children, className }) => ( 11 |
12 | 13 | {children} 14 |
15 | ); 16 | 17 | export const Beam = () => { 18 | return ( 19 | 27 | 32 | 33 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | ); 67 | }; 68 | -------------------------------------------------------------------------------- /components/hand-crafted/check-box.tsx: -------------------------------------------------------------------------------- 1 | import React, { Dispatch, SetStateAction, useState } from "react"; 2 | import { motion } from "framer-motion"; 3 | 4 | interface CheckboxProps { 5 | isChecked: boolean; 6 | setIsChecked: Dispatch>; 7 | } 8 | 9 | const Checkbox: React.FC = ({ isChecked, setIsChecked }) => { 10 | const checkboxVariants = { 11 | checked: { 12 | backgroundColor: "black", 13 | borderColor: "black", 14 | transition: { 15 | duration: 0.5, 16 | }, 17 | }, 18 | unchecked: { 19 | backgroundColor: "#ccc", 20 | borderColor: "#ccc", 21 | transition: { 22 | duration: 0.5, 23 | }, 24 | }, 25 | }; 26 | 27 | const checkmarkVariants = { 28 | checked: { 29 | pathLength: 1, 30 | opacity: 1, 31 | transition: { 32 | duration: 0.5, 33 | }, 34 | }, 35 | unchecked: { 36 | pathLength: 0, 37 | opacity: 0, 38 | transition: { 39 | duration: 0.5, 40 | }, 41 | }, 42 | }; 43 | 44 | const spring = {}; 45 | 46 | return ( 47 | setIsChecked(!isChecked)} 52 | whileTap={{ 53 | scale: 0.8, 54 | }} 55 | > 56 | 57 | 67 | 68 | 69 | ); 70 | }; 71 | 72 | export default Checkbox; 73 | -------------------------------------------------------------------------------- /components/hand-crafted/loading.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion } from "framer-motion"; 4 | 5 | import React from "react"; 6 | 7 | const Loading = () => { 8 | return ( 9 |
10 | {["Nothing", "Nothing", "Nothing"].map((item, index) => ( 11 | 24 | {item} 25 | 26 | ))} 27 |
28 | ); 29 | }; 30 | 31 | export default Loading; 32 | -------------------------------------------------------------------------------- /components/header-dock-item.tsx: -------------------------------------------------------------------------------- 1 | import { motion, TargetAndTransition, VariantLabels } from "framer-motion"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | export default function HeaderDockItem({ 6 | children, 7 | className, 8 | ...props 9 | }: { 10 | children: React.ReactNode; 11 | className?: string; 12 | whileTap?: VariantLabels | TargetAndTransition; 13 | }) { 14 | return ( 15 | 24 | {children} 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /components/inputs/google.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState, ChangeEvent } from "react"; 4 | import { motion, Variants } from "framer-motion"; 5 | 6 | import { Input } from "@/components/ui/input"; 7 | import { Label } from "@/components/ui/label"; 8 | 9 | interface GoogleInputProps { 10 | id?: string; 11 | label: string; 12 | type?: string; 13 | } 14 | 15 | const GoogleInput: React.FC = ({ 16 | id = "googleInput", 17 | label, 18 | type = "text", 19 | }) => { 20 | const [isFocused, setIsFocused] = useState(false); 21 | const [inputValue, setInputValue] = useState(""); 22 | 23 | const labelVariants: Variants = { 24 | default: { top: "12px", fontSize: "16px", color: "#999" }, 25 | active: { top: "-10px", fontSize: "12px", color: "#4285f4" }, 26 | }; 27 | 28 | const handleInputChange = (e: ChangeEvent) => { 29 | setInputValue(e.target.value); 30 | }; 31 | 32 | return ( 33 |
34 |
35 | setIsFocused(true)} 42 | onBlur={() => setIsFocused(false)} 43 | /> 44 | 56 |
57 |
58 | ); 59 | }; 60 | 61 | export default GoogleInput; 62 | -------------------------------------------------------------------------------- /components/main-nav.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import Link from "next/link"; 4 | 5 | import { Icons } from "@/components/icons"; 6 | 7 | export function MainNav() { 8 | return ( 9 |
10 | 11 | 12 | 13 | 14 | 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /components/mode-toggle.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { Moon, Sun } from "lucide-react"; 5 | import { useTheme } from "next-themes"; 6 | 7 | import { Button } from "@/components/ui/button"; 8 | import { 9 | DropdownMenu, 10 | DropdownMenuContent, 11 | DropdownMenuItem, 12 | DropdownMenuTrigger, 13 | } from "@/components/ui/dropdown-menu"; 14 | import { cn } from "@/lib/utils"; 15 | 16 | interface ModeToggleProps { 17 | showBorder?: boolean; 18 | } 19 | 20 | const ModeToggle = ({ showBorder }: ModeToggleProps) => { 21 | const { setTheme } = useTheme(); 22 | 23 | return ( 24 | 25 | 26 | 37 | 38 | 39 | setTheme("light")}> 40 | Light 41 | 42 | setTheme("dark")}> 43 | Dark 44 | 45 | setTheme("system")}> 46 | System 47 | 48 | 49 | 50 | ); 51 | }; 52 | 53 | export default ModeToggle; 54 | -------------------------------------------------------------------------------- /components/navbar/chevron.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React, { useState } from "react"; 4 | import { motion, AnimatePresence } from "framer-motion"; 5 | 6 | const navbarRoutes = [ 7 | { 8 | id: 1, 9 | name: "Home", 10 | component: () => { 11 | return
something
; 12 | }, 13 | }, 14 | { 15 | id: 2, 16 | name: "About", 17 | component: () => { 18 | return
something
; 19 | }, 20 | }, 21 | { 22 | id: 3, 23 | name: "others", 24 | component: () => { 25 | return
something
; 26 | }, 27 | }, 28 | ]; 29 | const Chevron = () => { 30 | return
Chevron
; 31 | }; 32 | 33 | const Routes = () => { 34 | const [active, setActive] = useState(null); 35 | const [direction, setDirection] = useState(null); 36 | 37 | const changeSelected = (value: number | null) => { 38 | if (typeof active === "number" && typeof value === "number") { 39 | setDirection(active > value ? "right" : "left"); 40 | } else if (value === null) { 41 | setDirection(null); 42 | } 43 | 44 | setActive(value); 45 | }; 46 | return
; 47 | }; 48 | 49 | export default Chevron; 50 | -------------------------------------------------------------------------------- /components/navbar/liquid-morph.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | import { motion } from "framer-motion"; 5 | import { useState } from "react"; 6 | 7 | const LiquidMorph = () => { 8 | const links = ["home", "changelog", "career", "about"]; 9 | const [currentLink, setCurrentLink] = useState(0); 10 | return ( 11 |
12 | 17 | 18 | 19 | 24 | 30 | 31 | 32 | 33 | 34 | 41 | {links.map((link, index) => ( 42 | setCurrentLink(index)} 45 | animate={{ 46 | x: [20, -20], 47 | }} 48 | className={cn( 49 | "bg-black text-white px-7 h-full items-center mx-0 transition-all duration-500 cursor-pointer justify-center flex capitalize font-bold", 50 | currentLink === index && "bg-blue-500 mx-6" 51 | )} 52 | > 53 | {link} 54 | 55 | ))} 56 | 57 |
58 | ); 59 | }; 60 | 61 | export default LiquidMorph; 62 | -------------------------------------------------------------------------------- /components/page-header.tsx: -------------------------------------------------------------------------------- 1 | import Balance from "react-wrap-balancer"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | function PageHeader({ className, children, ...props }: React.HTMLAttributes) { 6 | return ( 7 |
14 | {children} 15 |
16 | ); 17 | } 18 | 19 | function PageHeaderHeading({ className, ...props }: React.HTMLAttributes) { 20 | return ( 21 |

28 | ); 29 | } 30 | 31 | function PageHeaderDescription({ 32 | className, 33 | ...props 34 | }: React.HTMLAttributes) { 35 | return ( 36 | 40 | ); 41 | } 42 | 43 | function PageActions({ className, ...props }: React.HTMLAttributes) { 44 | return ( 45 |
49 | ); 50 | } 51 | 52 | export { PageActions, PageHeader, PageHeaderDescription, PageHeaderHeading }; 53 | -------------------------------------------------------------------------------- /components/preview-container.tsx: -------------------------------------------------------------------------------- 1 | export default function PreviewContainer({ children }: { children: React.ReactNode }) { 2 | return ( 3 |
4 | {children} 5 |
6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /components/providers.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { ThemeProvider as NextThemesProvider } from "next-themes" 4 | import { ThemeProviderProps } from "next-themes/dist/types" 5 | 6 | import { TooltipProvider } from "@/components/ui/tooltip" 7 | 8 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 9 | return ( 10 | <> 11 | 12 | {children} 13 | 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /components/reload-button.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { RotateCwIcon } from "lucide-react"; 4 | 5 | import { Button, ButtonProps } from "@/components/ui/button"; 6 | import { cn } from "@/lib/utils"; 7 | 8 | export function ReloadButton({ 9 | className, 10 | variant = "secondary", 11 | ...props 12 | }: ButtonProps) { 13 | return ( 14 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /components/remount-on-mouse-in.tsx: -------------------------------------------------------------------------------- 1 | import { Fragment, ReactNode, useRef, useState } from "react"; 2 | 3 | export default function RemountOnMouseIn({ 4 | children, 5 | className, 6 | duration, 7 | }: { 8 | children: ReactNode; 9 | className?: string; 10 | /** 11 | * Duration in milliseconds to wait before allowing a remount 12 | */ 13 | duration?: number; 14 | }) { 15 | const [key, setKey] = useState(0); 16 | const lastUpdate = useRef(Date.now()); 17 | 18 | const update = () => { 19 | if (Date.now() - lastUpdate.current > (duration ?? 1000)) { 20 | setKey((prev) => prev + 1); 21 | lastUpdate.current = Date.now(); 22 | } 23 | }; 24 | 25 | return ( 26 |
27 | {children} 28 |
29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /components/scroll/air-pods.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useMotionValueEvent, useScroll, useTransform } from "framer-motion"; 4 | import { useCallback, useEffect, useMemo, useRef } from "react"; 5 | 6 | function Airpods() { 7 | const ref = useRef(null); 8 | 9 | const { scrollYProgress } = useScroll({ 10 | target: ref, 11 | offset: ["center end", "start start"], 12 | }); 13 | 14 | const images = useMemo(() => { 15 | const loadedImages: HTMLImageElement[] = []; 16 | 17 | for (let i = 1; i <= 86; i++) { 18 | const img = new Image(); 19 | img.src = `/airpods/${i}.webp`; 20 | loadedImages.push(img); 21 | } 22 | 23 | return loadedImages; 24 | }, []); 25 | 26 | const render = useCallback( 27 | (index: number) => { 28 | if (images[index - 1]) { 29 | ref.current?.getContext("2d")?.drawImage(images[index - 1], 0, 0); 30 | } 31 | }, 32 | [images] 33 | ); 34 | 35 | const currentIndex = useTransform(scrollYProgress, [0, 1], [1, 86]); 36 | 37 | useMotionValueEvent(currentIndex, "change", (latest) => { 38 | render(Number(latest.toFixed())); 39 | }); 40 | 41 | useEffect(() => { 42 | render(1); 43 | }, [render]); 44 | 45 | return ( 46 |
47 | 48 |
49 | ); 50 | } 51 | 52 | export default Airpods; 53 | -------------------------------------------------------------------------------- /components/scroll/horizontal.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { motion, useScroll, useTransform } from "framer-motion"; 3 | 4 | import React, { useRef } from "react"; 5 | 6 | const Horizontal = () => { 7 | const ref = useRef(null); 8 | const { scrollYProgress } = useScroll({ 9 | target: ref, 10 | offset: ["center start", "end end"], 11 | }); 12 | 13 | const x = useTransform(scrollYProgress, [0, 1], ["1%", "-95%"]); 14 | return ( 15 |
16 |
17 | 18 | {Array.from({ length: 10 }).map((_, index) => ( 19 |
23 | {" "} 24 | {index + 1} 25 |
26 | ))} 27 |
28 |
29 |
30 | ); 31 | }; 32 | 33 | export default Horizontal; 34 | -------------------------------------------------------------------------------- /components/scroll/scroller.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | import { 5 | AnimatePresence, 6 | motion, 7 | useMotionValueEvent, 8 | useScroll, 9 | } from "framer-motion"; 10 | import { MessageCircle } from "lucide-react"; 11 | import { useState } from "react"; 12 | 13 | const Scroller = () => { 14 | const [isHidden, setIsHidden] = useState(false); 15 | const { scrollY } = useScroll(); 16 | 17 | useMotionValueEvent(scrollY, "change", (y) => { 18 | if (y > 50) { 19 | setIsHidden(true); 20 | } else { 21 | setIsHidden(false); 22 | } 23 | }); 24 | 25 | return ( 26 |
27 |
28 | 35 | Nothing 36 | 37 |
38 |
39 | 40 |
41 | ); 42 | }; 43 | 44 | const ChatButton = ({ isHidden }: { isHidden: boolean }) => { 45 | return ( 46 | 47 | {isHidden && ( 48 | 57 | 58 | 59 | )} 60 | 61 | ); 62 | }; 63 | 64 | export default Scroller; 65 | -------------------------------------------------------------------------------- /components/shared/animate-enter.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion } from "framer-motion"; 4 | 5 | import { cn } from "@/lib/utils"; 6 | 7 | type AnimateEnterProps = { 8 | className?: string; 9 | delay?: number; 10 | children: React.ReactNode; 11 | duration?: number; 12 | }; 13 | 14 | export function AnimateEnter({ 15 | className, 16 | delay, 17 | children, 18 | duration = 0.5, 19 | }: AnimateEnterProps) { 20 | return ( 21 | 28 | {children} 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /components/shared/arrow.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { motion } from "framer-motion"; 4 | 5 | interface ArrowProps { 6 | isHovered: boolean; 7 | angle?: number; 8 | } 9 | 10 | const Arrow = ({ isHovered, angle }: ArrowProps) => { 11 | return ( 12 | 13 | 20 | 30 | 40 | 41 | 42 | ); 43 | }; 44 | 45 | export default Arrow; 46 | -------------------------------------------------------------------------------- /components/shared/breadcrumb.tsx: -------------------------------------------------------------------------------- 1 | import { Fragment } from "react"; 2 | 3 | import { 4 | Breadcrumb, 5 | BreadcrumbItem, 6 | BreadcrumbLink, 7 | BreadcrumbList, 8 | BreadcrumbPage, 9 | BreadcrumbSeparator, 10 | } from "@/components/ui/breadcrumb"; 11 | import Link from "next/link"; 12 | 13 | const BreadcrumbComponent = ({ url }: { url: string }) => { 14 | const pathNames = url.split("/").filter((path) => path); 15 | pathNames.shift(); 16 | 17 | return ( 18 | 19 | 20 | 21 | 22 | Docs 23 | 24 | 25 | 26 | {pathNames.length > 0 && } 27 | 28 | {pathNames.map((path, index) => { 29 | const href = `/${pathNames.slice(0, index + 1).join("/")}`; 30 | let linkName = `${ 31 | path[0].toUpperCase() + path.slice(1, path.length) 32 | }`; 33 | 34 | const isLastPath = pathNames.length === index + 1; 35 | if (linkName === "Dashboard") return (linkName = "Home"); 36 | 37 | return ( 38 | 39 | 40 | {!isLastPath ? ( 41 | 42 | {linkName} 43 | 44 | ) : ( 45 | {linkName} 46 | )} 47 | 48 | {pathNames.length !== index + 1 && } 49 | 50 | ); 51 | })} 52 | 53 | 54 | ); 55 | }; 56 | 57 | export default BreadcrumbComponent; 58 | -------------------------------------------------------------------------------- /components/shared/doc-header.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useProvider } from "@/context/command-menu"; 4 | import { Search } from "lucide-react"; 5 | import Logo from "./logo"; 6 | 7 | const routes = [ 8 | { name: "Blog", path: "/blog" }, 9 | { name: "Changelog", path: "/docs/changelog" }, 10 | ]; 11 | 12 | const DocsHeader = () => { 13 | const { setShowCommandMenu } = useProvider(); 14 | 15 | return ( 16 |
17 |
18 | 19 |
20 |
setShowCommandMenu((prev) => !prev)} 23 | > 24 |

25 | 26 | Find something... 27 |

28 | cmd+k 29 |
30 |
31 | ); 32 | }; 33 | 34 | export default DocsHeader; 35 | -------------------------------------------------------------------------------- /components/shared/docs-navbar.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Logo from "./logo"; 3 | import ModeToggle from "../mode-toggle"; 4 | 5 | const DocsNavbar = () => { 6 | return ( 7 |
8 | 12 |
13 | ); 14 | }; 15 | 16 | export default DocsNavbar; 17 | -------------------------------------------------------------------------------- /components/shared/loading.tsx: -------------------------------------------------------------------------------- 1 | import React, { type SVGProps } from "react"; 2 | 3 | export function Loading({ 4 | width = 24, 5 | height = 24, 6 | dur = "0.75s", 7 | }: SVGProps): JSX.Element { 8 | return ( 9 | 16 | 17 | 24 | 25 | 26 | 32 | 33 | 34 | 41 | 42 | 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /components/shared/logo.tsx: -------------------------------------------------------------------------------- 1 | import { siteConfig } from "@/config/site"; 2 | import { cn } from "@/lib/utils"; 3 | import Image from "next/image"; 4 | import Link from "next/link"; 5 | import React from "react"; 6 | import { Icons } from "@/components/icons"; 7 | 8 | interface LogoProps { 9 | className?: string; 10 | link?: string; 11 | withText?: boolean; 12 | } 13 | 14 | const Logo = ({ link, withText, className }: LogoProps) => { 15 | return ( 16 | 20 | {" "} 21 | {withText && {siteConfig.name}} 22 | 23 | ); 24 | }; 25 | 26 | export default Logo; 27 | -------------------------------------------------------------------------------- /components/shared/theme-switcher.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useTheme } from "next-themes"; 4 | import { Laptop, Sun, Moon } from "lucide-react"; 5 | import { motion } from "framer-motion" 6 | 7 | import { useMounted } from "@/hooks/use-mounted"; 8 | import { cn } from "@/lib/utils"; 9 | 10 | 11 | const themes = [ 12 | { 13 | name: "light", 14 | icon: Sun, 15 | }, 16 | { 17 | name: "dark", 18 | icon: Moon, 19 | }, 20 | { 21 | name: "system", 22 | icon: Laptop, 23 | }, 24 | ]; 25 | 26 | const ThemeSwitcher = () => { 27 | const { setTheme, theme: justTheme } = useTheme(); 28 | const mouted = useMounted() 29 | 30 | if (!mouted) return 31 | 32 | 33 | return ( 34 |
35 | {themes.map((theme, index) => { 36 | // something 37 | return ( 38 | 47 | ); 48 | })} 49 |
50 | ); 51 | }; 52 | 53 | export default ThemeSwitcher 54 | -------------------------------------------------------------------------------- /components/tailwind-indicator.tsx: -------------------------------------------------------------------------------- 1 | export function TailwindIndicator() { 2 | if (process.env.NODE_ENV === "production") return null 3 | 4 | return ( 5 |
6 |
xs
7 |
sm
8 |
md
9 |
lg
10 |
xl
11 |
2xl
12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /components/text/first.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { motion } from "framer-motion"; 5 | 6 | const FirstTextNimation = () => { 7 | return ( 8 |
9 |
10 | 11 | 12 | 13 |
14 |
15 | ); 16 | }; 17 | 18 | const Text = ({ text }: { text: string }) => { 19 | return ( 20 | 25 |
26 | {text.split("").map((letter, index) => ( 27 | 40 | {letter} 41 | 42 | ))} 43 |
44 |
45 | {text.split("").map((letter, index) => ( 46 | 59 | {letter} 60 | 61 | ))} 62 |
63 |
64 | ); 65 | }; 66 | 67 | export default FirstTextNimation; 68 | -------------------------------------------------------------------------------- /components/ui/alert.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva, type VariantProps } from "class-variance-authority" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const alertVariants = cva( 7 | "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", 8 | { 9 | variants: { 10 | variant: { 11 | default: "bg-background text-foreground", 12 | destructive: 13 | "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", 14 | }, 15 | }, 16 | defaultVariants: { 17 | variant: "default", 18 | }, 19 | } 20 | ) 21 | 22 | const Alert = React.forwardRef< 23 | HTMLDivElement, 24 | React.HTMLAttributes & VariantProps 25 | >(({ className, variant, ...props }, ref) => ( 26 |
32 | )) 33 | Alert.displayName = "Alert" 34 | 35 | const AlertTitle = React.forwardRef< 36 | HTMLParagraphElement, 37 | React.HTMLAttributes 38 | >(({ className, ...props }, ref) => ( 39 |
44 | )) 45 | AlertTitle.displayName = "AlertTitle" 46 | 47 | const AlertDescription = React.forwardRef< 48 | HTMLParagraphElement, 49 | React.HTMLAttributes 50 | >(({ className, ...props }, ref) => ( 51 |
56 | )) 57 | AlertDescription.displayName = "AlertDescription" 58 | 59 | export { Alert, AlertTitle, AlertDescription } 60 | -------------------------------------------------------------------------------- /components/ui/aspect-ratio.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" 4 | 5 | const AspectRatio = AspectRatioPrimitive.Root 6 | 7 | export { AspectRatio } 8 | -------------------------------------------------------------------------------- /components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { cva, type VariantProps } from "class-variance-authority" 3 | 4 | import { cn } from "@/lib/utils" 5 | 6 | const badgeVariants = cva( 7 | "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 8 | { 9 | variants: { 10 | variant: { 11 | default: 12 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", 13 | secondary: 14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", 15 | destructive: 16 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", 17 | outline: "text-foreground", 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: "default", 22 | }, 23 | } 24 | ) 25 | 26 | export interface BadgeProps 27 | extends React.HTMLAttributes, 28 | VariantProps {} 29 | 30 | function Badge({ className, variant, ...props }: BadgeProps) { 31 | return ( 32 |
33 | ) 34 | } 35 | 36 | export { Badge, badgeVariants } 37 | -------------------------------------------------------------------------------- /components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Slot } from "@radix-ui/react-slot"; 3 | import { cva, type VariantProps } from "class-variance-authority"; 4 | 5 | import { cn } from "@/lib/utils"; 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", 9 | { 10 | variants: { 11 | variant: { 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 13 | destructive: 14 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 15 | outline: 16 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground", 17 | secondary: 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 19 | ghost: "hover:bg-accent hover:text-accent-foreground", 20 | link: "text-primary underline-offset-4 hover:underline", 21 | }, 22 | size: { 23 | default: "h-10 px-4 py-2", 24 | sm: "h-9 rounded-md px-3", 25 | lg: "h-11 rounded-md px-8", 26 | icon: "h-10 w-10", 27 | }, 28 | }, 29 | defaultVariants: { 30 | variant: "default", 31 | size: "default", 32 | }, 33 | } 34 | ); 35 | 36 | export interface ButtonProps 37 | extends React.ButtonHTMLAttributes, 38 | VariantProps { 39 | asChild?: boolean; 40 | } 41 | 42 | const Button = React.forwardRef( 43 | ({ className, variant, size, asChild = false, ...props }, ref) => { 44 | const Comp = asChild ? Slot : "button"; 45 | return ( 46 | 51 | ); 52 | } 53 | ); 54 | Button.displayName = "Button"; 55 | 56 | export { Button, buttonVariants }; 57 | -------------------------------------------------------------------------------- /components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 4 | 5 | const Collapsible = CollapsiblePrimitive.Root 6 | 7 | const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger 8 | 9 | const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent 10 | 11 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 12 | -------------------------------------------------------------------------------- /components/ui/hover-card.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as HoverCardPrimitive from "@radix-ui/react-hover-card" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const HoverCard = HoverCardPrimitive.Root 9 | 10 | const HoverCardTrigger = HoverCardPrimitive.Trigger 11 | 12 | const HoverCardContent = React.forwardRef< 13 | React.ElementRef, 14 | React.ComponentPropsWithoutRef 15 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 16 | 26 | )) 27 | HoverCardContent.displayName = HoverCardPrimitive.Content.displayName 28 | 29 | export { HoverCard, HoverCardTrigger, HoverCardContent } 30 | -------------------------------------------------------------------------------- /components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ); 21 | } 22 | ); 23 | Input.displayName = "Input"; 24 | 25 | export { Input }; 26 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /components/ui/scroll-area.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; 5 | 6 | import { cn } from "@/lib/utils"; 7 | 8 | const ScrollArea = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >(({ className, children, ...props }, ref) => ( 12 | 17 | 18 | {children} 19 | 20 | 21 | 22 | 23 | )); 24 | ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; 25 | 26 | const ScrollBar = React.forwardRef< 27 | React.ElementRef, 28 | React.ComponentPropsWithoutRef 29 | >(({ className, orientation = "vertical", ...props }, ref) => ( 30 | 43 | 44 | 45 | )); 46 | ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; 47 | 48 | export { ScrollArea, ScrollBar }; 49 | -------------------------------------------------------------------------------- /components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as SeparatorPrimitive from "@radix-ui/react-separator" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Separator = React.forwardRef< 9 | React.ElementRef, 10 | React.ComponentPropsWithoutRef 11 | >( 12 | ( 13 | { className, orientation = "horizontal", decorative = true, ...props }, 14 | ref 15 | ) => ( 16 | 27 | ) 28 | ) 29 | Separator.displayName = SeparatorPrimitive.Root.displayName 30 | 31 | export { Separator } 32 | -------------------------------------------------------------------------------- /components/ui/tabs.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as TabsPrimitive from "@radix-ui/react-tabs" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Tabs = TabsPrimitive.Root 9 | 10 | const TabsList = React.forwardRef< 11 | React.ElementRef, 12 | React.ComponentPropsWithoutRef 13 | >(({ className, ...props }, ref) => ( 14 | 22 | )) 23 | TabsList.displayName = TabsPrimitive.List.displayName 24 | 25 | const TabsTrigger = React.forwardRef< 26 | React.ElementRef, 27 | React.ComponentPropsWithoutRef 28 | >(({ className, ...props }, ref) => ( 29 | 37 | )) 38 | TabsTrigger.displayName = TabsPrimitive.Trigger.displayName 39 | 40 | const TabsContent = React.forwardRef< 41 | React.ElementRef, 42 | React.ComponentPropsWithoutRef 43 | >(({ className, ...props }, ref) => ( 44 | 52 | )) 53 | TabsContent.displayName = TabsPrimitive.Content.displayName 54 | 55 | export { Tabs, TabsList, TabsTrigger, TabsContent } 56 | -------------------------------------------------------------------------------- /components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |