├── .env.example ├── .eslintrc.json ├── .gitignore ├── .prettierrc.js ├── README.md ├── app ├── changelog │ ├── logs.ts │ └── page.tsx ├── components │ ├── (component-docs) │ │ ├── accordion │ │ │ └── page.mdx │ │ ├── button │ │ │ └── page.mdx │ │ ├── callout │ │ │ └── page.mdx │ │ ├── card │ │ │ └── page.mdx │ │ ├── icon-button │ │ │ └── page.mdx │ │ ├── input │ │ │ └── page.mdx │ │ ├── layout.tsx │ │ ├── pillar │ │ │ └── page.mdx │ │ ├── responsive-control │ │ │ └── page.mdx │ │ ├── sidebar-menu │ │ │ └── page.mdx │ │ ├── stepper │ │ │ └── page.mdx │ │ ├── switch │ │ │ └── page.mdx │ │ ├── tab-menu │ │ │ └── page.mdx │ │ ├── timeline │ │ │ └── page.mdx │ │ └── toast │ │ │ └── page.mdx │ ├── common │ │ ├── components-list.tsx │ │ └── examples │ │ │ ├── accordion-examples.tsx │ │ │ ├── button-examples.tsx │ │ │ ├── callout-examples.tsx │ │ │ ├── card-examples.tsx │ │ │ ├── icon-button-examples.tsx │ │ │ ├── input-examples.tsx │ │ │ ├── pillar-examples.tsx │ │ │ ├── sidebar-menu-examples.tsx │ │ │ ├── stepper-examples.tsx │ │ │ ├── switch-examples.tsx │ │ │ ├── tab-menu-examples.tsx │ │ │ ├── timeline-examples.tsx │ │ │ └── toast-examples.tsx │ └── page.tsx ├── cookies │ ├── (cookies-docs) │ │ ├── authentication-form │ │ │ └── page.mdx │ │ ├── empty-state │ │ │ └── page.mdx │ │ ├── hero-section │ │ │ └── page.mdx │ │ ├── image-card │ │ │ └── page.mdx │ │ ├── layout.tsx │ │ └── toggle-list │ │ │ └── page.mdx │ ├── common │ │ ├── cookies-list.tsx │ │ └── examples │ │ │ ├── authentication-form-examples.tsx │ │ │ ├── empty-state-examples.tsx │ │ │ ├── hero-section-examples.tsx │ │ │ ├── image-card-examples.tsx │ │ │ └── toggle-list-examples.tsx │ └── page.tsx ├── favicon.ico ├── getting-started │ └── page.tsx ├── globals.css ├── layout.tsx └── page.tsx ├── common ├── content.ts └── env.ts ├── components ├── configs │ └── animation-config.ts ├── cookies │ ├── authentication-form.tsx │ ├── empty-state.tsx │ ├── hero-section.tsx │ ├── image-card.tsx │ └── toggle-list.tsx ├── dev │ └── tailwind-breakpoint-indicator.tsx ├── layouts │ ├── full-page-grid-design.tsx │ ├── page-header.tsx │ └── responsive-control.tsx ├── sections │ ├── component-manual-setup.tsx │ ├── landing-hero-section.tsx │ ├── setup-section.tsx │ └── website-navigation.tsx ├── ui │ ├── accordion.tsx │ ├── button.tsx │ ├── callout.tsx │ ├── card.tsx │ ├── contact-input.tsx │ ├── icon-button.tsx │ ├── input.tsx │ ├── pillar.tsx │ ├── sidebar-menu.tsx │ ├── stepper.tsx │ ├── switch.tsx │ ├── tab-menu.tsx │ ├── timeline.tsx │ └── toast.tsx └── website │ ├── code-block.tsx │ ├── component-block.tsx │ ├── component-docs-header.tsx │ ├── component-preview.tsx │ ├── cookie-block.tsx │ ├── cookie-preview.tsx │ ├── cookies-docs-header.tsx │ ├── docs-page-outline.tsx │ └── navbar-logo.tsx ├── generators ├── README.md ├── update-cookie-code.ts └── update-setup-code.ts ├── helpers ├── copy-to-clipboard.ts ├── dev.ts └── utils.ts ├── mdx-components.tsx ├── next.config.mjs ├── package.json ├── package └── registry │ ├── README.md │ ├── cookies-setup-code.tsx │ └── setup-code.tsx ├── postcss.config.js ├── public ├── data │ └── country-input-config.json ├── logos │ ├── cookies-logo.png │ ├── next.svg │ └── vercel.svg └── media │ └── images │ ├── portrait-test-image.jpg │ ├── responsive-control-banner.png │ └── responsive-control-banner.svg ├── services └── posthog │ └── provider.tsx ├── tailwind.config.ts ├── tsconfig.json └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_POSTHOG_KEY=******** 2 | NEXT_PUBLIC_POSTHOG_HOST=******* 3 | NEXT_PUBLIC_ENVIRONMENT=development/production -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.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*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # pages 39 | /app/test -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | singleQuote: true, 4 | trailingComma: 'all', 5 | bracketSameLine: true, 6 | tabWidth: 2, 7 | useTabs: false, 8 | arrowParens: 'always', 9 | }; 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /app/changelog/logs.ts: -------------------------------------------------------------------------------- 1 | export type ChangelogContentType = { 2 | version: string; 3 | features: string[]; 4 | }; 5 | 6 | export const ChangelogContent: ChangelogContentType[] = [ 7 | { 8 | version: '0.1', 9 | features: [ 10 | 'Adding design and setup for the landing page', 11 | 'Generator code for updating package/registry', 12 | 'Adding docs for getting started and all components', 13 | ], 14 | }, 15 | { 16 | version: '0.2', 17 | features: [ 18 | 'Added docs and MDX support', 19 | 'Added button components', 20 | 'Has generators in-place to update setup-code to package/registry', 21 | 'Add support for project setup and required dependencies', 22 | 'Configured Posthog for user analysis', 23 | ], 24 | }, 25 | { 26 | version: '0.3', 27 | features: [ 28 | 'Fixing styles and changes in button and docs', 29 | 'Adding IconButton to components', 30 | 'Fix button example with icon in docs', 31 | '🍪 Adding Input component to package/registry', 32 | '💄 Add card component to collection <> Docs update', 33 | '💄 Create switch components for collection', 34 | ], 35 | }, 36 | { 37 | version: '0.4', 38 | features: [ 39 | '🍪 Add accordion to components collection', 40 | 'Adding Posthog events', 41 | 'Update authentication-form cookie docs', 42 | '🍪 Callout component to cookies', 43 | '✨ Redesign cookie card', 44 | '✨ Fix switch loader', 45 | '🍪 Add hero-section to cookies', 46 | ], 47 | }, 48 | { 49 | version: '0.5', 50 | features: [ 51 | '🍪 Add empty-state to cookies <> Docs support', 52 | '🍪 Add timeline component to collection', 53 | '🍪 Add tab-menu to component collection', 54 | '🍪 Add sidebar menu to component collection', 55 | '🍪 Add image-card to cookies collection', 56 | ], 57 | }, 58 | { 59 | version: '1.0', 60 | features: [ 61 | '🍪 Add toggle-list to cookies collection', 62 | '🍪 Add pillar to component collection', 63 | '🍪 Add responsive control to component collection', 64 | ], 65 | }, 66 | ]; 67 | -------------------------------------------------------------------------------- /app/changelog/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { PageHeader } from '@/components/layouts/page-header'; 3 | import { ChangelogContent, ChangelogContentType } from './logs'; 4 | import { ResponsiveControl } from '@/components/layouts/responsive-control'; 5 | import Image from 'next/image'; 6 | import { useEffect, useState } from 'react'; 7 | import { motion } from 'framer-motion'; 8 | import posthog from 'posthog-js'; 9 | 10 | export default function Changelog() { 11 | const [changelogData, setChangelog] = useState([]); 12 | 13 | useEffect(() => { 14 | posthog.capture('changelog'); 15 | }, []); 16 | 17 | useEffect(() => { 18 | const data: ChangelogContentType[] = ChangelogContent.slice().reverse(); 19 | setChangelog(data as ChangelogContentType[]); 20 | }, []); 21 | 22 | return ( 23 |
24 | 25 | 26 |

{'Changelog'}

27 |
28 |
29 |
30 | 31 | {changelogData.map( 32 | (changelog: ChangelogContentType, index: number) => { 33 | return ( 34 | 44 | 45 | 46 | ); 47 | }, 48 | )} 49 | 50 |
51 |
52 | ); 53 | } 54 | 55 | function ChangelogUpdate(changelog: ChangelogContentType) { 56 | return ( 57 |
58 | 59 |
60 |

{`Release v${changelog.version}`}

61 |
62 |
    63 | {changelog.features.map((feature: string, index: number) => { 64 | return ( 65 |
  • 66 | {feature} 67 |
  • 68 | ); 69 | })} 70 |
71 |
72 |
73 |
74 | ); 75 | } 76 | 77 | function ChangelogBannerTemplate({ version }: { version: string }) { 78 | return ( 79 |
80 | 81 | cookies-logo{' '} 88 | Cookies 89 | 90 | {`Release v${version}`} 91 |
92 | ); 93 | } 94 | -------------------------------------------------------------------------------- /app/components/(component-docs)/accordion/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { 6 | Accordion, 7 | AccordionItem, 8 | AccordionTrigger, 9 | AccordionContent, 10 | } from '@/components/ui/accordion.tsx'; 11 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 12 | import { AccordionWithAnimationInContent } from '@/app/components/common/examples/accordion-examples.tsx'; 13 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 14 | 15 | 16 | 17 | 18 | 19 | 20 | {`# using npm\nnpm install @radix-ui/react-accordion\n\n# using yarn\nyarn add @radix-ui/react-accordion`} 21 |
22 | 23 | {SETUP_CODE['accordion'].code} 24 | 25 | 26 | 27 |
28 | 29 | 31 | 32 | Demo Accordion 33 | This is a demo accordion content 34 | 35 | `} 36 | headline="Accordion Example"> 37 | 38 | 39 | Demo Accordion 40 | This is a demo accordion content 41 | 42 | 43 | 44 | 45 |
46 | 47 | 49 | 50 | Demo Accordion 01 51 | This is a demo accordion content 52 | 53 | 54 | Demo Accordion 02 55 | This is a demo accordion content 56 | 57 | 58 | Demo Accordion 03 59 | This is a demo accordion content 60 | 61 | `} 62 | headline="Accordion with multiple items (single item at a time)"> 63 | 64 | 65 | Demo Accordion 01 66 | This is a demo accordion content 67 | 68 | 69 | Demo Accordion 02 70 | This is a demo accordion content 71 | 72 | 73 | Demo Accordion 03 74 | This is a demo accordion content 75 | 76 | 77 | 78 | 79 |
80 | 81 | 83 | 84 | Demo Accordion 01 85 | This is a demo accordion content 86 | 87 | 88 | Demo Accordion 02 89 | This is a demo accordion content 90 | 91 | 92 | Demo Accordion 03 93 | This is a demo accordion content 94 | 95 | `} 96 | headline="Accordion with multiple items (multiple item at a time)"> 97 | 98 | 99 | Demo Accordion 01 100 | This is a demo accordion content 101 | 102 | 103 | Demo Accordion 02 104 | This is a demo accordion content 105 | 106 | 107 | Demo Accordion 03 108 | This is a demo accordion content 109 | 110 | 111 | 112 | 113 |
114 | 115 | 117 | 118 | 119 | Accessible 120 | 121 | 122 | Fully accessible using keyboard 123 | 124 | 125 | 126 | 127 | Clean Design 128 | 129 | 130 | Has a clean design with option to open 131 | single/multiple content at a time. 132 | 133 | 134 | `} 135 | headline="Accordion with animation example"> 136 | 137 | 138 | -------------------------------------------------------------------------------- /app/components/(component-docs)/button/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 6 | import { Button } from '@/components/ui/button.tsx'; 7 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {SETUP_CODE['button'].code} 16 | 17 | 18 | 19 |
20 | 21 | Primary Button`} 23 | headline="Primary Button" 24 | description="This is the default/primary button design, with subtle blue gradient effect"> 25 | 26 | 27 | 28 |
29 | 30 | Secondary Button`} 32 | headline="Secondary Button" 33 | description="This is the secondary button, with subtle background"> 34 | 35 | 36 | 37 |
38 | 39 | Ghost Button`} 41 | headline="Ghost Button" 42 | description="This is the ghost button, with trasnparent background and subtle white themed background on interaction"> 43 | 44 | 45 | 46 |
47 | 48 | Loading Button`} 50 | headline="Loading Button" 51 | description="Has support for loading states, by setting isLoading as true"> 52 | 53 | 54 | 55 |
56 | 57 | Disabled Button`} 59 | headline="Disabled Button" 60 | description="Button with disabled state. Not accessible if disabled is set as true"> 61 | 62 | 63 | 64 |
65 | 66 | Button With Arrow`} 68 | headline="Button with arrow" 69 | description="Button component with leading arrow icon"> 70 | 71 | 72 | 73 |
74 | 75 | 🍪} iconDirection="left"> 77 | Button With Icon Left 78 | 79 | 80 | `} 83 | headline="Button with icon" 84 | description="Button component with leading icon. With iconDirection you can manage the icon placement" 85 | className="flex flex-row items-center justify-center gap-4"> 86 | 89 | 92 | 93 | 94 |
95 | 96 | Small Primary Button`} 98 | headline="Small Primary Button" 99 | description="Primary Button with small size"> 100 | 103 | 104 | 105 |
106 | 107 | Small Secondary Button`} 109 | headline="Small Secondary Button" 110 | description="Secondary button with small size"> 111 | 114 | 115 | 116 |
117 | 118 | Small Ghost Button`} 120 | headline="Small Ghost Button" 121 | description="Ghost Button with small size"> 122 | 125 | 126 | 127 |
128 | 129 | Large Primary Button`} 131 | headline="Large Primary Button" 132 | description="Primary Button with large size"> 133 | 136 | 137 | 138 |
139 | 140 | Large Secondary Button`} 142 | headline="Large Secondary Button" 143 | description="Secondary button with large size"> 144 | 147 | 148 | 149 |
150 | 151 | Large Ghost Button`} 153 | headline="Large Ghost Button" 154 | description="Ghost Button with large size"> 155 | 158 | 159 | -------------------------------------------------------------------------------- /app/components/(component-docs)/callout/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { Callout } from '@/components/ui/callout.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {SETUP_CODE['callout'].code} 16 | 17 | 18 | 19 |
20 | 21 | This is an info callout`} 23 | headline="Callout Info" 24 | description="This is the callout component with info variant"> 25 | This is an info callout 26 | 27 | 28 |
29 | 30 | This is an warning callout`} 32 | headline="Callout Warning" 33 | description="This is the callout component with warning variant"> 34 | This is an warning callout 35 | 36 | 37 |
38 | 39 | This is an error callout`} 41 | headline="Callout Error" 42 | description="This is the callout component with error variant"> 43 | This is an error callout 44 | 45 | 46 |
47 | 48 | This is an success callout`} 50 | headline="Callout Success" 51 | description="This is the callout component with success variant"> 52 | This is an success callout 53 | 54 | 55 |
56 | 57 | This is an subtle callout`} 59 | headline="Callout Subtle" 60 | description="This is the callout component with subtle variant"> 61 | This is an subtle callout 62 | 63 | -------------------------------------------------------------------------------- /app/components/(component-docs)/card/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { 6 | Card, 7 | CardContent, 8 | CardHeader, 9 | CardFooter, 10 | CardHeaderTitle, 11 | CardHeaderDescription, 12 | } from '@/components/ui/card.tsx'; 13 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 14 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {SETUP_CODE['card'].code} 23 | 24 | 25 | 26 |
27 | 28 | 30 | 31 | Card Header Title 32 | Card Header Description 33 | 34 | Card Content 35 | Card Footer Content 36 | `} 37 | headline="Card Component Structure" 38 | description="Outline of the card component"> 39 | 40 | 41 | Card Header Title 42 | Card Header Description 43 | 44 | Card Content 45 | Card Footer Content 46 | 47 | 48 | 49 |
50 | 51 | 53 | 54 | Welcome to cookies -- It is a collection of boilerplate components and UI 55 | examples. 56 | 57 | `} 58 | headline="Simple Card as a wrapper" 59 | description="Using card as a simple and clean wrapper to wrap content"> 60 | 61 | 62 | Welcome to cookies -- It is a collection of boilerplate components and UI 63 | examples. 64 | 65 | 66 | 67 | 68 |
69 | 70 | 72 | 73 | Posted in #frontend 74 | 75 | 76 | Lorem ipsum, dolor sit amet consectetur adipisicing elit. Doloribus, 77 | nostrum iste doloremque eaque vel odio vitae inventore 78 | 79 | {'Posted by @yashsehgal'} 80 | `} 81 | headline="Card with header and footer content" 82 | description="Using card with header and footer content, making everything look easy to understand"> 83 | 84 | 85 | Posted in #frontend 86 | 87 | 88 | Lorem ipsum, dolor sit amet consectetur adipisicing elit. Doloribus, 89 | nostrum iste doloremque eaque vel odio vitae inventore 90 | 91 | {'Posted by @yashsehgal'} 92 | 93 | 94 | -------------------------------------------------------------------------------- /app/components/(component-docs)/icon-button/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 6 | import { 7 | IconButtonDefaultExample, 8 | IconButtonPrimaryExample, 9 | IconButtonPrimarySmallExample, 10 | IconButtonPrimaryLargeExample, 11 | IconButtonSecondaryExample, 12 | IconButtonSecondarySmallExample, 13 | IconButtonSecondaryLargeExample, 14 | IconButtonGhostExample, 15 | IconButtonGhostSmallExample, 16 | IconButtonGhostLargeExample, 17 | IconButtonLoadingExample, 18 | IconButtonDisabledExample, 19 | } from '@/app/components/common/examples/icon-button-examples.tsx'; 20 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {SETUP_CODE['icon-button'].code} 29 | 30 | 31 | 32 |
33 | 34 | 36 | 37 | `} 38 | headline="Primary Icon Button" 39 | description="This is the default/primary icon button design, with subtle blue gradient effect"> 40 | 41 | 42 | 43 |
44 | 45 | 47 | 48 | `} 49 | headline="Secondary Icon Button" 50 | description="This is the secondary icon button, with subtle background"> 51 | 52 | 53 | 54 |
55 | 56 | 58 | 59 | `} 60 | headline="Ghost Icon Button" 61 | description="This is the ghost icon button, with trasnparent background and subtle white themed background on interaction"> 62 | 63 | 64 | 65 |
66 | 67 | 69 | 70 | `} 71 | headline="Loading Icon Button" 72 | description="Icon button has support to loading state"> 73 | 74 | 75 | 76 |
77 | 78 | 80 | 81 | `} 82 | headline="Disabled Icon Button" 83 | description="Icon button has support to disabled state"> 84 | 85 | 86 | 87 |
88 | 89 | 91 | 92 | `} 93 | headline="Primary Icon Button Small" 94 | description="Primary icon button with small size"> 95 | 96 | 97 | 98 |
99 | 100 | 102 | 103 | `} 104 | headline="Secondary Icon Button Small" 105 | description="Secondary icon button with small size"> 106 | 107 | 108 | 109 |
110 | 111 | 113 | 114 | `} 115 | headline="Ghost Icon Button Small" 116 | description="Ghost icon button with small size"> 117 | 118 | 119 | 120 |
121 | 122 | 124 | 125 | `} 126 | headline="Primary Icon Button Large" 127 | description="Primary icon button with Large size"> 128 | 129 | 130 | 131 |
132 | 133 | 135 | 136 | `} 137 | headline="Secondary Icon Button Large" 138 | description="Secondary icon button with Large size"> 139 | 140 | 141 | 142 |
143 | 144 | 146 | 147 | `} 148 | headline="Ghost Icon Button Large" 149 | description="Ghost icon button with Large size"> 150 | 151 | 152 | -------------------------------------------------------------------------------- /app/components/(component-docs)/input/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { Input } from '@/components/ui/input.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {SETUP_CODE['input'].code} 16 | 17 | 18 | 19 |
20 | 21 | `} 23 | headline="Default Text Input" 24 | description="This is the default input component with 'text' as type"> 25 | 26 | 27 | 28 |
29 | 30 | `} 36 | headline="Text Input with Label (horizontal by-default)" 37 | description="Input element with supporting label text, aligned horizontally by-default"> 38 | 43 | 44 | 45 |
46 | 47 | `} 54 | headline="Text Input with Label (vertical)" 55 | description="Input element with supporting label text, aligned vertically"> 56 | 62 | 63 | 64 |
65 | 66 | `} 72 | headline="Disabled Input" 73 | description="This is the default input component with 'text' as type"> 74 | 79 | 80 | 81 |
82 | 83 | `} 89 | headline="Number Input" 90 | description="This is the number input"> 91 | 96 | 97 | -------------------------------------------------------------------------------- /app/components/(component-docs)/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ResponsiveControl } from '@/components/layouts/responsive-control'; 2 | import { ReactNode } from 'react'; 3 | 4 | export default function ComponentDocsLayout({ 5 | children, 6 | }: { 7 | children: ReactNode; 8 | }) { 9 | return ( 10 |
11 | 12 |
{children}
13 |
14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /app/components/(component-docs)/pillar/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { 6 | Pillar, 7 | PillarIcon, 8 | PillarHeadline, 9 | PillarDescription, 10 | } from '@/components/ui/pillar.tsx'; 11 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 12 | import { PillarExample } from '@/app/components/common/examples/pillar-examples.tsx'; 13 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {SETUP_CODE['pillar'].code} 22 | 23 | 24 | 25 |
26 | 27 | 29 | 30 | 31 | 32 | 33 | Design & Accessibility 34 | 35 | 36 | Cookies has a collection of components with fresh design and accessibility. 37 | 38 | `} 39 | headline="Pillar Example Use-case"> 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/components/(component-docs)/responsive-control/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 6 | 7 | 8 | 9 | 10 | 11 | {SETUP_CODE['responsive-control'].code} 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/components/(component-docs)/stepper/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { 6 | Stepper, 7 | StepperItem, 8 | StepperStatusIcon, 9 | StepperTitle, 10 | } from '@/components/ui/stepper.tsx'; 11 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 12 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {SETUP_CODE['stepper'].code} 21 | 22 | 23 | 24 |
25 | 26 | 28 | 29 | 30 | Create Project 31 | 32 | 33 | 34 | Select Tooling 35 | 36 | 37 | 38 | Connect Account 39 | 40 | `} 41 | headline="Stepper Flow"> 42 | 43 | 44 | 45 | Create Project 46 | 47 | 48 | 49 | Select Tooling 50 | 51 | 52 | 53 | Connect Account 54 | 55 | 56 | 57 | 58 |
59 | 60 | 62 | 63 | 64 | Inactive Stepper Item 65 | 66 | `} 67 | headline="Stepper Item (status inactive)"> 68 | 69 | 70 | 71 | Inactive Stepper Item 72 | 73 | 74 | 75 | 76 |
77 | 78 | 80 | 81 | 82 | Success Stepper Item 83 | 84 | `} 85 | headline="Stepper Item (status success)"> 86 | 87 | 88 | 89 | Success Stepper Item 90 | 91 | 92 | 93 | 94 |
95 | 96 | 98 | 99 | 100 | Failed Stepper Item 101 | 102 | `} 103 | headline="Stepper Item (status failed)"> 104 | 105 | 106 | 107 | Failed Stepper Item 108 | 109 | 110 | 111 | 112 |
113 | 114 | 116 | 117 | 118 | Warning Stepper Item 119 | 120 | `} 121 | headline="Stepper Item (status warning)"> 122 | 123 | 124 | 125 | Warning Stepper Item 126 | 127 | 128 | 129 | 130 |
131 | 132 | 134 | 135 | 136 | Loading Stepper Item 137 | 138 | `} 139 | headline="Stepper Item (status loading)"> 140 | 141 | 142 | 143 | Loading Stepper Item 144 | 145 | 146 | 147 | 148 |
149 | 150 | 152 | 153 | 154 | Create Project 155 | 156 | 157 | 158 | Select Tooling 159 | 160 | 161 | 162 | Connect Account 163 | 164 | `} 165 | headline="Stepper {activeStep}" 166 | description="activeStep attribute receives a number, identifying the current active tab/step (starts from 0)"> 167 | 168 | 169 | 170 | Create Project 171 | 172 | 173 | 174 | Select Tooling 175 | 176 | 177 | 178 | Connect Account 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /app/components/(component-docs)/switch/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { Switch } from '@/components/ui/switch.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {SETUP_CODE['switch'].code} 16 | 17 | 18 | 19 |
20 | 21 | `} headline="Switch"> 22 | 23 | 24 | 25 |
26 | 27 | `} 29 | headline="Switch with label (horizontal-left)"> 30 | 31 | 32 | 33 |
34 | 35 | `} 37 | headline="Switch with label (horizontal-right)"> 38 | 39 | 40 | 41 |
42 | 43 | `} 45 | headline="Switch with label (vertical)"> 46 | 47 | 48 | 49 |
50 | 51 | `} 53 | headline="Disabled Switch (un-checked)"> 54 | 55 | 56 | 57 |
58 | 59 | `} 61 | headline="Disabled Switch (checked)"> 62 | 63 | 64 | 65 |
66 | 67 | `} headline="Switch with loading"> 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/components/(component-docs)/tab-menu/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { TabMenu, TabMenuOption } from '@/components/ui/tab-menu.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {SETUP_CODE['tab-menu'].code} 16 | 17 | 18 | 19 |
20 | 21 | 23 | Home 24 | Explore 25 | Profile 26 | Settings 27 | Changelog 28 | `} 29 | headline="Tab Menu Example" 30 | description="This is a simple example of a tab menu"> 31 | 32 | Home 33 | Explore 34 | Profile 35 | Settings 36 | Changelog 37 | 38 | 39 | 40 |
41 | 42 | 44 | Home 45 | Explore 46 | Profile 47 | Settings 48 | Changelog 49 | `} 50 | headline="Locked Tab Menu Options" 51 | description="Tab menu with locked options"> 52 | 53 | Home 54 | Explore 55 | Profile 56 | Settings 57 | Changelog 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/components/(component-docs)/timeline/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { CookiePreview } from '@/components/website/cookie-preview.tsx'; 6 | import { 7 | Timeline, 8 | TimelineItem, 9 | TimelineItemIcon, 10 | TimelineItemHeadline, 11 | TimelineItemDescription, 12 | TimelineItemActionContainer, 13 | TimelineItemPrimaryAction, 14 | TimelineItemSecondaryAction, 15 | } from '@/components/ui/timeline.tsx'; 16 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 17 | import { TimelineWithCustomIconExample } from '@/app/components/common/examples/timeline-examples.tsx'; 18 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {SETUP_CODE['timeline'].code} 27 | 28 | 29 | 30 |
31 | 32 | 34 | 35 | 36 | Headline 37 | 38 | This is a description text. 39 | 40 | 41 | `} 42 | headline={'Timeline Item'}> 43 | 44 | 45 | 46 | Headline 47 | 48 | This is a description text. 49 | 50 | 51 | 52 | 53 | 54 |
55 | 56 | 58 | 59 | 60 | Headline 61 | 62 | This is a description text. 63 | 64 | 65 | `} 66 | headline={'Timeline Item with icon="info"'}> 67 | 68 | 69 | 70 | Headline 71 | 72 | This is a description text. 73 | 74 | 75 | 76 | 77 | 78 |
79 | 80 | 82 | 83 | 84 | Headline 85 | 86 | This is a description text. 87 | 88 | 89 | `} 90 | headline={'Timeline Item with icon="error"'}> 91 | 92 | 93 | 94 | Headline 95 | 96 | This is a description text. 97 | 98 | 99 | 100 | 101 | 102 |
103 | 104 | 106 | 107 | 108 | Headline 109 | 110 | This is a description text. 111 | 112 | 113 | `} 114 | headline={'Timeline Item with icon="success"'}> 115 | 116 | 117 | 118 | Headline 119 | 120 | This is a description text. 121 | 122 | 123 | 124 | 125 | 126 |
127 | 128 | 130 | 131 | 132 | Headline 133 | 134 | This is a description text. 135 | 136 | 137 | `} 138 | headline={'Timeline Item with icon="warning"'}> 139 | 140 | 141 | 142 | Headline 143 | 144 | This is a description text. 145 | 146 | 147 | 148 | 149 | 150 |
151 | 152 | 154 | 155 | 156 | 157 | 158 | Headline 159 | 160 | This is a description text. 161 | 162 | 163 | `} 164 | headline={'Timeline Item with custom icon'}> 165 | 166 | 167 | 168 |
169 | 170 | 172 | 173 | 174 | Headline 175 | 176 | This is a description text. 177 | 178 | 179 | 180 | 181 | Headline 182 | 183 | This is a description text. 184 | 185 | 186 | `} 187 | headline={'Timeline with multiple timeline item'}> 188 | 189 | 190 | 191 | Headline 192 | 193 | This is a description text. 194 | 195 | 196 | 197 | 198 | Headline 199 | 200 | This is a description text. 201 | 202 | 203 | 204 | 205 | 206 |
207 | 208 | 210 | 211 | 212 | Headline 213 | 214 | This is a description text. 215 | 216 | 217 | Get Started 218 | Learn more 219 | 220 | 221 | `} 222 | headline={'Timeline Item with actions'}> 223 | 224 | 225 | 226 | Headline 227 | 228 | This is a description text. 229 | 230 | 231 | Get Started 232 | Learn more 233 | 234 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /app/components/(component-docs)/toast/page.mdx: -------------------------------------------------------------------------------- 1 | import ComponentDocsHeader from '@/components/website/component-docs-header'; 2 | import { SETUP_CODE } from '@/package/registry/setup-code.tsx'; 3 | import { CodeBlock } from '@/components/website/code-block.tsx'; 4 | import { ComponentPreview } from '@/components/website/component-preview.tsx'; 5 | import { 6 | ToastProvider, 7 | Toast, 8 | ToastTitle, 9 | ToastDescription, 10 | ToastAction, 11 | } from '@/components/ui/toast.tsx'; 12 | import { 13 | ToastExampleDefault, 14 | ToastExampleTopRight, 15 | ToastExampleTopLeft, 16 | ToastExampleBottomLeft, 17 | ToastExampleBottomRight, 18 | } from '@/app/components/common/examples/toast-examples.tsx'; 19 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 20 | import DocsPageOutline from '@/components/website/docs-page-outline.tsx'; 21 | 22 | 23 | 24 | 25 | 26 | 27 | {`# using npm\nnpm install @radix-ui/react-toast\n\n# using yarn\nyarn add @radix-ui/react-toast`} 28 |
29 | 30 | {SETUP_CODE['toast'].code} 31 | 32 | 33 | 34 |
35 | 36 | { 38 | const [open, setOpen] = React.useState(false); 39 | const timerRef = React.useRef(0); 40 | return 41 | 51 | 52 | Testing toast 53 | 54 | Description text for the testing toast 55 | 56 | Got it 57 | 58 | 59 | }`} 60 | headline="Toast default example"> 61 | 62 | 63 | 64 |
65 | 66 | 68 | 78 | 79 | Top-right toast 80 | 81 | Using position="top-right" 82 | 83 | Got it 84 | 85 | `} 86 | headline="Toast with position top-right"> 87 | 88 | 89 | 90 |
91 | 92 | 94 | 104 | 105 | Top-left toast 106 | 107 | Using position="top-left" 108 | 109 | Got it 110 | 111 | `} 112 | headline="Toast with position top-left"> 113 | 114 | 115 | 116 |
117 | 118 | 120 | 130 | 131 | Bottom-left toast 132 | 133 | Using position="bottom-left" 134 | 135 | Got it 136 | 137 | `} 138 | headline="Toast with position bottom-left"> 139 | 140 | 141 | 142 |
143 | 144 | 146 | 156 | 157 | Bottom-right toast 158 | 159 | Using position="bottom-right" 160 | 161 | Got it 162 | 163 | `} 164 | headline="Toast with position bottom-right"> 165 | 166 | 167 | -------------------------------------------------------------------------------- /app/components/common/components-list.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { ButtonDefaultExample } from './examples/button-examples'; 3 | import { IconButtonDefaultExample } from './examples/icon-button-examples'; 4 | import { InputDefaultExample } from './examples/input-examples'; 5 | import { CardExample } from './examples/card-examples'; 6 | import { SwitchDefaultExample } from './examples/switch-examples'; 7 | import { AccordionDefaultExample } from './examples/accordion-examples'; 8 | import { CalloutExample } from './examples/callout-examples'; 9 | import { TimelineExample } from './examples/timeline-examples'; 10 | import { TabMenuExample } from './examples/tab-menu-examples'; 11 | import { SidebarMenuExample } from './examples/sidebar-menu-examples'; 12 | import { PillarExample } from './examples/pillar-examples'; 13 | import Image from 'next/image'; 14 | import { StepperExample } from './examples/stepper-examples'; 15 | import { ToastComponentDemo } from './examples/toast-examples'; 16 | 17 | export type ComponentListItemType = { 18 | name: string; 19 | description: string; 20 | path: string; 21 | render: ReactNode; 22 | }; 23 | 24 | export const ComponentsList: ComponentListItemType[] = [ 25 | { 26 | name: 'Responsive Control', 27 | description: 28 | 'A layout component to centre screen content for multiple devices, based on tailwind classes.', 29 | path: '/components/responsive-control', 30 | render: ( 31 |
32 | responsive-control-banner 39 |
40 | ), 41 | }, 42 | { 43 | name: 'Button', 44 | description: 45 | 'A framer-motion supported button with size and design variants.', 46 | path: '/components/button', 47 | render: , 48 | }, 49 | { 50 | name: 'Icon Button', 51 | description: 52 | "Similar to button component and it's properties, but for icon-based actions.", 53 | path: '/components/icon-button', 54 | render: , 55 | }, 56 | { 57 | name: 'Input', 58 | description: 59 | 'A subtle and clean input component, with all the native properties.', 60 | path: '/components/input', 61 | render: , 62 | }, 63 | { 64 | name: 'Card', 65 | description: 66 | 'A sleek looking card container with added header and footer layout', 67 | path: '/components/card', 68 | render: , 69 | }, 70 | { 71 | name: 'Switch', 72 | description: 'A native working switch component', 73 | path: '/components/switch', 74 | render: , 75 | }, 76 | { 77 | name: 'Accordion', 78 | description: 79 | 'Fully functional, accessible and responsive accordion component.', 80 | path: '/components/accordion', 81 | render: , 82 | }, 83 | { 84 | name: 'Callout', 85 | description: 86 | 'Callout component with multiple variants covering various use cases.', 87 | path: '/components/callout', 88 | render: , 89 | }, 90 | { 91 | name: 'Tab Menu', 92 | description: 'A auto-adjustable tab menu component', 93 | path: '/components/tab-menu', 94 | render: ( 95 |
96 | 97 |
98 | ), 99 | }, 100 | { 101 | name: 'Timeline', 102 | description: 103 | 'A thoughtful timeline component for your web-apps & landing pages', 104 | path: '/components/timeline', 105 | render: ( 106 |
107 | 108 |
109 | ), 110 | }, 111 | { 112 | name: 'Sidebar Menu', 113 | description: 114 | 'An auto-adjustable sidebar menu component for side navigations.', 115 | path: '/components/sidebar-menu', 116 | render: ( 117 |
118 | 119 |
120 | ), 121 | }, 122 | { 123 | name: 'Pillar', 124 | description: 125 | 'Pillar component can be used for listing features, options for landing pages/websites.', 126 | path: '/components/pillar', 127 | render: ( 128 |
129 | 130 |
131 | ), 132 | }, 133 | { 134 | name: 'Stepper', 135 | description: 136 | 'A stepper component with features to show status and active tab', 137 | path: '/components/stepper', 138 | render: ( 139 |
140 | 141 |
142 | ), 143 | }, 144 | { 145 | name: 'Toast', 146 | description: 'A simple and customizable toast component using Radix', 147 | path: '/components/toast', 148 | render: ( 149 |
150 | 151 |
152 | ), 153 | }, 154 | ]; 155 | -------------------------------------------------------------------------------- /app/components/common/examples/accordion-examples.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { ComponentAnimationType } from '@/components/configs/animation-config'; 3 | import { 4 | Accordion, 5 | AccordionContent, 6 | AccordionItem, 7 | AccordionTrigger, 8 | } from '@/components/ui/accordion'; 9 | import { cn } from '@/helpers/utils'; 10 | import { useState } from 'react'; 11 | 12 | export const AccordionDefaultExample = () => ( 13 |
14 | 15 | 16 | Accessible 17 | Fully accessible using keyboard 18 | 19 | 20 | Clean Design 21 | 22 | Has a clean design with option to open single/multiple content at a 23 | time. 24 | 25 | 26 | 27 |
28 | ); 29 | 30 | export const AccordionWithAnimationInContent = () => { 31 | const [animation, setAnimation] = 32 | useState('from-bottom'); 33 | return ( 34 |
35 |
36 | {['from-bottom', 'from-top', 'from-right', 'from-left'].map( 37 | (anim, index) => ( 38 | 47 | ), 48 | )} 49 |
50 | 51 | 52 | Accessible 53 | 54 | Fully accessible using keyboard 55 | 56 | 57 | 58 | Clean Design 59 | 60 | Has a clean design with option to open single/multiple content at a 61 | time. 62 | 63 | 64 | 65 |
66 | ); 67 | }; 68 | -------------------------------------------------------------------------------- /app/components/common/examples/button-examples.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@/components/ui/button'; 2 | 3 | export const ButtonDefaultExample = () => ; 4 | -------------------------------------------------------------------------------- /app/components/common/examples/callout-examples.tsx: -------------------------------------------------------------------------------- 1 | import { Callout } from '@/components/ui/callout'; 2 | 3 | export const CalloutExample = () => This is an info callout; 4 | -------------------------------------------------------------------------------- /app/components/common/examples/card-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Card, 3 | CardContent, 4 | CardFooter, 5 | CardHeader, 6 | CardHeaderTitle, 7 | } from '@/components/ui/card'; 8 | 9 | export const CardExample = () => ( 10 | 11 | 12 | Posted in #frontend 13 | 14 | 15 | { 16 | 'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Doloribus, nostrum iste doloremque eaque vel odio vitae inventore' 17 | } 18 | 19 | {'Posted by Author'} 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /app/components/common/examples/icon-button-examples.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { IconButton } from '@/components/ui/icon-button'; 3 | import { Text, User } from 'lucide-react'; 4 | 5 | export const IconButtonDefaultExample = () => ( 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | ); 15 | 16 | export const IconButtonPrimaryExample = () => ( 17 | 18 | 19 | 20 | ); 21 | 22 | export const IconButtonPrimarySmallExample = () => ( 23 | 24 | 25 | 26 | ); 27 | 28 | export const IconButtonPrimaryLargeExample = () => ( 29 | 30 | 31 | 32 | ); 33 | 34 | export const IconButtonSecondaryExample = () => ( 35 | 36 | 37 | 38 | ); 39 | 40 | export const IconButtonSecondarySmallExample = () => ( 41 | 42 | 43 | 44 | ); 45 | 46 | export const IconButtonSecondaryLargeExample = () => ( 47 | 48 | 49 | 50 | ); 51 | 52 | export const IconButtonGhostExample = () => ( 53 | 54 | 55 | 56 | ); 57 | 58 | export const IconButtonGhostSmallExample = () => ( 59 | 60 | 61 | 62 | ); 63 | 64 | export const IconButtonGhostLargeExample = () => ( 65 | 66 | 67 | 68 | ); 69 | 70 | export const IconButtonLoadingExample = () => ( 71 | 72 | 73 | 74 | ); 75 | 76 | export const IconButtonDisabledExample = () => ( 77 | 78 | 79 | 80 | ); 81 | -------------------------------------------------------------------------------- /app/components/common/examples/input-examples.tsx: -------------------------------------------------------------------------------- 1 | import { Input } from '@/components/ui/input'; 2 | 3 | export const InputDefaultExample = () => ( 4 | 5 | ); 6 | -------------------------------------------------------------------------------- /app/components/common/examples/pillar-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Pillar, 3 | PillarDescription, 4 | PillarHeadline, 5 | PillarIcon, 6 | } from '@/components/ui/pillar'; 7 | import { Paintbrush } from 'lucide-react'; 8 | 9 | export const PillarExample = () => ( 10 | 11 | 12 | 13 | 14 | Design & Accessibility 15 | 16 | Cookies has a collection of components with fresh design and 17 | accessibility. 18 | 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /app/components/common/examples/sidebar-menu-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | SidebarMenu, 3 | SidebarMenuContainer, 4 | SidebarMenuContent, 5 | SidebarMenuItem, 6 | SidebarSubMenu, 7 | SidebarSubMenuContent, 8 | SidebarSubMenuItem, 9 | } from '@/components/ui/sidebar-menu'; 10 | import { 11 | CircleUserRound, 12 | MessageCircleDashed, 13 | Settings, 14 | ShieldCheck, 15 | } from 'lucide-react'; 16 | 17 | export const SidebarMenuExample = () => ( 18 | 19 | }> 22 | 23 | Change username 24 | Manage subscriptions 25 | Manage profile visibility 26 | }> 29 | 30 | Hide posts from members 31 | 32 | Hide initiatives from members 33 | 34 | 35 | 36 | 37 | 38 | }> 41 | 42 | Change commnuity logo 43 | Create new community 44 | 45 | 46 | 47 | ); 48 | -------------------------------------------------------------------------------- /app/components/common/examples/stepper-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Stepper, 3 | StepperItem, 4 | StepperStatusIcon, 5 | StepperTitle, 6 | } from '@/components/ui/stepper'; 7 | 8 | export const StepperExample = () => ( 9 | 10 | 11 | 12 | Create Project 13 | 14 | 15 | 16 | Select Tooling 17 | 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /app/components/common/examples/switch-examples.tsx: -------------------------------------------------------------------------------- 1 | import { Switch } from '@/components/ui/switch'; 2 | 3 | export const SwitchDefaultExample = () => ; 4 | -------------------------------------------------------------------------------- /app/components/common/examples/tab-menu-examples.tsx: -------------------------------------------------------------------------------- 1 | import { TabMenu, TabMenuOption } from '@/components/ui/tab-menu'; 2 | 3 | export const TabMenuExample = () => ( 4 | 5 | Home 6 | Explore 7 | Profile 8 | Settings 9 | Changelog 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /app/components/common/examples/timeline-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Timeline, 3 | TimelineItem, 4 | TimelineItemActionContainer, 5 | TimelineItemDescription, 6 | TimelineItemHeadline, 7 | TimelineItemIcon, 8 | TimelineItemPrimaryAction, 9 | TimelineItemSecondaryAction, 10 | } from '@/components/ui/timeline'; 11 | import { Rocket } from 'lucide-react'; 12 | 13 | export const TimelineExample = () => ( 14 | 15 | 16 | 17 | This is a timeline item 18 | 19 | This is a timeline item description. 20 | 21 | 22 | Get started 23 | Learn more 24 | 25 | 26 | 27 | 28 | Your changes are merged 29 | 30 | 31 | Go to home 32 | 33 | 34 | 35 | 36 | 37 | Merge Failed 38 | 39 | Merge failed due to conflicts 40 | 41 | 42 | 43 | Rollback to main branch 44 | 45 | 46 | 47 | 48 | ); 49 | 50 | export const TimelineWithCustomIconExample = () => ( 51 | 52 | 53 | 54 | 55 | 56 | Headline 57 | 58 | This is a description text. 59 | 60 | 61 | 62 | ); 63 | -------------------------------------------------------------------------------- /app/components/common/examples/toast-examples.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { Button } from '@/components/ui/button'; 3 | import { 4 | Toast, 5 | ToastAction, 6 | ToastDescription, 7 | ToastProvider, 8 | ToastTitle, 9 | } from '@/components/ui/toast'; 10 | import React from 'react'; 11 | 12 | export const ToastComponentDemo = () => { 13 | return ( 14 |
15 | Toast Title 16 | Description text for toast component 17 | Explore 18 |
19 | ); 20 | }; 21 | 22 | export const ToastExampleDefault = () => { 23 | const [open, setOpen] = React.useState(false); 24 | const timerRef = React.useRef(0); 25 | return ( 26 | 27 | 37 | 38 | Testing toast 39 | 40 | Description text for the testing toast 41 | 42 | Got it 43 | 44 | 45 | ); 46 | }; 47 | 48 | export const ToastExampleTopRight = () => { 49 | const [open, setOpen] = React.useState(false); 50 | const timerRef = React.useRef(0); 51 | return ( 52 | 53 | 63 | 64 | Top-right toast 65 | {`Using position="top-right"`} 66 | Got it 67 | 68 | 69 | ); 70 | }; 71 | 72 | export const ToastExampleTopLeft = () => { 73 | const [open, setOpen] = React.useState(false); 74 | const timerRef = React.useRef(0); 75 | return ( 76 | 77 | 87 | 88 | Top-left toast 89 | {`Using position="top-left"`} 90 | Got it 91 | 92 | 93 | ); 94 | }; 95 | 96 | export const ToastExampleBottomLeft = () => { 97 | const [open, setOpen] = React.useState(false); 98 | const timerRef = React.useRef(0); 99 | return ( 100 | 101 | 111 | 112 | Bottom-left toast 113 | {`Using position="bottom-left"`} 114 | Got it 115 | 116 | 117 | ); 118 | }; 119 | 120 | export const ToastExampleBottomRight = () => { 121 | const [open, setOpen] = React.useState(false); 122 | const timerRef = React.useRef(0); 123 | return ( 124 | 125 | 135 | 136 | Bottom-right toast 137 | {`Using position="bottom-right"`} 138 | Got it 139 | 140 | 141 | ); 142 | }; 143 | -------------------------------------------------------------------------------- /app/components/page.tsx: -------------------------------------------------------------------------------- 1 | import { PageHeader } from '@/components/layouts/page-header'; 2 | import { ResponsiveControl } from '@/components/layouts/responsive-control'; 3 | import { ComponentBlock } from '@/components/website/component-block'; 4 | import { 5 | ComponentListItemType, 6 | ComponentsList, 7 | } from './common/components-list'; 8 | 9 | export default function ComponentsPage() { 10 | return ( 11 |
12 | 13 | 14 |

{'Components'}

15 |
16 |
17 |
18 | 19 | {ComponentsList.map( 20 | (component: ComponentListItemType, index: number) => { 21 | return ( 22 | 27 | ); 28 | }, 29 | )} 30 | 31 |
32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /app/cookies/(cookies-docs)/authentication-form/page.mdx: -------------------------------------------------------------------------------- 1 | import { AuthenticationFormExample } from '@/app/cookies/common/examples/authentication-form-examples.tsx'; 2 | import CookiesDocsHeader from '@/components/website/cookies-docs-header'; 3 | import { COOKIES_SETUP_CODE } from '@/package/registry/cookies-setup-code.tsx'; 4 | import { CodeBlock } from '@/components/website/code-block.tsx'; 5 | import { CookiePreview } from '@/components/website/cookie-preview.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 21 | {COOKIES_SETUP_CODE['authentication-form'].code} 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/cookies/(cookies-docs)/empty-state/page.mdx: -------------------------------------------------------------------------------- 1 | import { EmptyStateExample } from '@/app/cookies/common/examples/empty-state-examples.tsx'; 2 | import CookiesDocsHeader from '@/components/website/cookies-docs-header'; 3 | import { COOKIES_SETUP_CODE } from '@/package/registry/cookies-setup-code.tsx'; 4 | import { CodeBlock } from '@/components/website/code-block.tsx'; 5 | import { CookiePreview } from '@/components/website/cookie-preview.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 21 | {COOKIES_SETUP_CODE['empty-state'].code} 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/cookies/(cookies-docs)/hero-section/page.mdx: -------------------------------------------------------------------------------- 1 | import { HeroSectionExample } from '@/app/cookies/common/examples/hero-section-examples.tsx'; 2 | import CookiesDocsHeader from '@/components/website/cookies-docs-header'; 3 | import { COOKIES_SETUP_CODE } from '@/package/registry/cookies-setup-code.tsx'; 4 | import { CodeBlock } from '@/components/website/code-block.tsx'; 5 | import { CookiePreview } from '@/components/website/cookie-preview.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 21 | {COOKIES_SETUP_CODE['hero-section'].code} 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/cookies/(cookies-docs)/image-card/page.mdx: -------------------------------------------------------------------------------- 1 | import { ImageCardExample } from '@/app/cookies/common/examples/image-card-examples.tsx'; 2 | import CookiesDocsHeader from '@/components/website/cookies-docs-header'; 3 | import { COOKIES_SETUP_CODE } from '@/package/registry/cookies-setup-code.tsx'; 4 | import { CodeBlock } from '@/components/website/code-block.tsx'; 5 | import { CookiePreview } from '@/components/website/cookie-preview.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 21 | {COOKIES_SETUP_CODE['image-card'].code} 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/cookies/(cookies-docs)/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ResponsiveControl } from '@/components/layouts/responsive-control'; 2 | import { ReactNode } from 'react'; 3 | 4 | export default function CookiesDocsLayout({ 5 | children, 6 | }: { 7 | children: ReactNode; 8 | }) { 9 | return ( 10 |
11 | 12 |
{children}
13 |
14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /app/cookies/(cookies-docs)/toggle-list/page.mdx: -------------------------------------------------------------------------------- 1 | import { ToggleListExample } from '@/app/cookies/common/examples/toggle-list-examples.tsx'; 2 | import CookiesDocsHeader from '@/components/website/cookies-docs-header'; 3 | import { COOKIES_SETUP_CODE } from '@/package/registry/cookies-setup-code.tsx'; 4 | import { CodeBlock } from '@/components/website/code-block.tsx'; 5 | import { CookiePreview } from '@/components/website/cookie-preview.tsx'; 6 | import { ComponentManualSetup } from '@/components/sections/component-manual-setup.tsx'; 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 21 | {COOKIES_SETUP_CODE['toggle-list'].code} 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/cookies/common/cookies-list.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { AuthenticationFormExample } from './examples/authentication-form-examples'; 3 | import { HeroSectionExample } from './examples/hero-section-examples'; 4 | import { EmptyStateExample } from './examples/empty-state-examples'; 5 | import { ImageCardExample } from './examples/image-card-examples'; 6 | import { ToggleListExample } from './examples/toggle-list-examples'; 7 | 8 | export type CookiesListItemType = { 9 | name: string; 10 | description: string; 11 | path: string; 12 | render: ReactNode; 13 | }; 14 | 15 | export const CookiesList: CookiesListItemType[] = [ 16 | { 17 | name: 'Authentication Form', 18 | description: 19 | 'A simple and clean authentication form example using local components', 20 | path: '/cookies/authentication-form', 21 | render: ( 22 |
23 | 24 |
25 | ), 26 | }, 27 | { 28 | name: 'Hero Section', 29 | description: 'A hero section component with consistent styling.', 30 | path: '/cookies/hero-section', 31 | render: ( 32 |
33 | 34 |
35 | ), 36 | }, 37 | { 38 | name: 'Empty State', 39 | description: 'An empty state component for showing empty sections.', 40 | path: '/cookies/empty-state', 41 | render: ( 42 |
43 | 44 |
45 | ), 46 | }, 47 | { 48 | name: 'Image Card', 49 | description: 50 | 'A simple image card component with cover, headling and description text', 51 | path: '/cookies/image-card', 52 | render: ( 53 |
54 | 55 |
56 | ), 57 | }, 58 | { 59 | name: 'Toggle List', 60 | description: 'A toggle list component for managing multiple toggle options', 61 | path: '/cookies/toggle-list', 62 | render: ( 63 |
64 | 65 |
66 | ), 67 | }, 68 | ]; 69 | -------------------------------------------------------------------------------- /app/cookies/common/examples/authentication-form-examples.tsx: -------------------------------------------------------------------------------- 1 | import AuthenticationForm from '@/components/cookies/authentication-form'; 2 | 3 | export const AuthenticationFormExample = () => ; 4 | -------------------------------------------------------------------------------- /app/cookies/common/examples/empty-state-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | EmptyState, 3 | EmptyStateDescription, 4 | EmptyStateHeadline, 5 | EmptyStateIcon, 6 | EmptyStatePrimaryAction, 7 | EmptyStateSecondaryAction, 8 | } from '@/components/cookies/empty-state'; 9 | import { Container } from 'lucide-react'; 10 | 11 | export const EmptyStateExample = () => ( 12 | 13 | 14 | 15 | 16 | You have no recent containers 17 | 18 | All your recent containers or projects will be listed here 19 | 20 | Create new container 21 | Learn more 22 | 23 | ); 24 | -------------------------------------------------------------------------------- /app/cookies/common/examples/hero-section-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | HeroSection, 3 | HeroSectionCTAContainer, 4 | HeroSectionCTAPrimaryAction, 5 | HeroSectionCTASecondaryAction, 6 | HeroSectionDescription, 7 | HeroSectionHeadline, 8 | } from '@/components/cookies/hero-section'; 9 | 10 | export const HeroSectionExample = () => ( 11 | 12 | This is a hero section 13 | 14 | This is a hero section description, this component helps define a 15 | consistent patter for adding hero sections. 16 | 17 | 18 | Get Started 19 | Learn more 20 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /app/cookies/common/examples/image-card-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ImageCard, 3 | ImageCardCover, 4 | ImageCardDescription, 5 | ImageCardHeadline, 6 | } from '@/components/cookies/image-card'; 7 | import Image from 'next/image'; 8 | 9 | export const ImageCardExample = () => ( 10 | 11 | 12 | cover-image 18 | 19 | Explore New Features 20 | 21 | {'Deep dive into the latest features in cookies v1.0'} 22 | 23 | 24 | ); 25 | -------------------------------------------------------------------------------- /app/cookies/common/examples/toggle-list-examples.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ToggleList, 3 | ToggleListContainer, 4 | ToggleListContent, 5 | ToggleListItem, 6 | ToggleListTrigger, 7 | } from '@/components/cookies/toggle-list'; 8 | 9 | export const ToggleListExample = () => ( 10 | 11 | 12 | Profile Settings 13 | 14 | Manage profile preview 15 | Change username 16 | Private profile 17 | 18 | 19 | 20 | Content Settings 21 | 22 | Hide stories 23 | Hide comments/likes 24 | Hide replies 25 | Manage who can reply 26 | 27 | 28 | 29 | ); 30 | -------------------------------------------------------------------------------- /app/cookies/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { PageHeader } from '@/components/layouts/page-header'; 3 | import { ResponsiveControl } from '@/components/layouts/responsive-control'; 4 | import { CookiesList, CookiesListItemType } from './common/cookies-list'; 5 | import { useEffect } from 'react'; 6 | import posthog from 'posthog-js'; 7 | import { CookieBlock } from '@/components/website/cookie-block'; 8 | 9 | export default function CookiesPage() { 10 | useEffect(() => { 11 | posthog.capture('cookies'); 12 | }, []); 13 | return ( 14 |
15 | 16 | 17 |

{'Cookies'}

18 |
19 |
20 |
21 | 22 | {CookiesList.map((cookie: CookiesListItemType, index: number) => { 23 | return ( 24 | 29 | ); 30 | })} 31 | 32 |
33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/with-tw/cookies/1a7d0f2288f655f5ef3f670a5d699584e7bff7c5/app/favicon.ico -------------------------------------------------------------------------------- /app/getting-started/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { SetupSection } from '@/components/sections/setup-section'; 3 | import posthog from 'posthog-js'; 4 | import { useEffect } from 'react'; 5 | 6 | export default function GettingStarted() { 7 | useEffect(() => { 8 | posthog.capture('project-setup'); 9 | }, []); 10 | return ( 11 |
12 | 13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | @apply tracking-tight text-neutral-200; 8 | @apply overflow-x-hidden overflow-y-scroll; 9 | } 10 | 11 | html { 12 | @apply bg-neutral-900; 13 | } 14 | 15 | body { 16 | @apply h-screen bg-gradient-to-b from-neutral-950 to-neutral-900; 17 | } 18 | 19 | html { 20 | overflow: scroll; 21 | overflow-x: hidden; 22 | } 23 | ::-webkit-scrollbar-track { 24 | width: 0; 25 | background: transparent; 26 | } 27 | 28 | ::-webkit-scrollbar-thumb { 29 | width: 0; 30 | background: transparent; 31 | } 32 | 33 | ::-webkit-scrollbar { 34 | width: 0; 35 | background: transparent; 36 | } 37 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next'; 2 | import { Inter } from 'next/font/google'; 3 | import './globals.css'; 4 | import { CSPostHogProvider } from '@/services/posthog/provider'; 5 | import WebsiteNavigation from '@/components/sections/website-navigation'; 6 | import FullPageGridDesign from '@/components/layouts/full-page-grid-design'; 7 | import { TailwindIndicator } from '@/components/dev/tailwind-breakpoint-indicator'; 8 | import { ResponsiveControl } from '@/components/layouts/responsive-control'; 9 | 10 | const inter = Inter({ 11 | subsets: ['latin'], 12 | }); 13 | 14 | export const metadata: Metadata = { 15 | title: 'Cookies | With Tailwind', 16 | description: 17 | 'Easy-to-setup Boilerplate UI Components & Layouts. Built with Radix, Styled with Tailwind', 18 | }; 19 | 20 | export default function RootLayout({ 21 | children, 22 | }: Readonly<{ 23 | children: React.ReactNode; 24 | }>) { 25 | return ( 26 | 27 | 28 | 29 |
30 | 31 |
32 |
33 | 34 | {/*
*/} 35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | {/*
*/} 43 | 44 | 45 | {children} 46 |
47 | 48 | 49 | 50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import LandingHeroSection from '@/components/sections/landing-hero-section'; 2 | 3 | export default function Home(): JSX.Element { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /common/content.ts: -------------------------------------------------------------------------------- 1 | export const SetupSectionContent = { 2 | headline: 'Project Setup and Configurations', 3 | description: 4 | "In order to use the components and cookies you must have the following dependencies and configs in your project. Here's a step-by-step setup guide.", 5 | }; 6 | -------------------------------------------------------------------------------- /common/env.ts: -------------------------------------------------------------------------------- 1 | export const POSTHOG_HOST = process.env['NEXT_PUBLIC_POSTHOG_HOST'] as string; 2 | export const POSTHOG_KEY = process.env['NEXT_PUBLIC_POSTHOG_KEY'] as string; 3 | export const CURRENT_ENVIRONMENT = process.env[ 4 | 'NEXT_PUBLIC_ENVIRONMENT' 5 | ] as string; 6 | -------------------------------------------------------------------------------- /components/configs/animation-config.ts: -------------------------------------------------------------------------------- 1 | export type ComponentAnimationType = 2 | | 'none' 3 | | 'from-top' 4 | | 'from-bottom' 5 | | 'from-left' 6 | | 'from-right'; 7 | 8 | export type ComponentAnimationFramerConfigType = { 9 | opacity?: number; 10 | y?: number; 11 | x?: number; 12 | scale?: number; 13 | zoom?: number; 14 | width?: number; 15 | height?: number; 16 | }; 17 | 18 | export const ComponentAnimation: Record< 19 | ComponentAnimationType, 20 | { 21 | initial: ComponentAnimationFramerConfigType; 22 | animate: ComponentAnimationFramerConfigType; 23 | } 24 | > = { 25 | none: { 26 | initial: {}, 27 | animate: {}, 28 | }, 29 | 'from-bottom': { 30 | initial: { 31 | opacity: 0, 32 | y: 12, 33 | }, 34 | animate: { 35 | opacity: 1, 36 | y: 0, 37 | }, 38 | }, 39 | 'from-top': { 40 | initial: { 41 | opacity: 0, 42 | y: -12, 43 | }, 44 | animate: { 45 | opacity: 1, 46 | y: 0, 47 | }, 48 | }, 49 | 'from-left': { 50 | initial: { 51 | opacity: 0, 52 | x: -12, 53 | }, 54 | animate: { 55 | opacity: 1, 56 | x: 0, 57 | }, 58 | }, 59 | 'from-right': { 60 | initial: { 61 | opacity: 0, 62 | x: 12, 63 | }, 64 | animate: { 65 | opacity: 1, 66 | x: 0, 67 | }, 68 | }, 69 | }; 70 | -------------------------------------------------------------------------------- /components/cookies/authentication-form.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { 3 | Card, 4 | CardHeader, 5 | CardHeaderDescription, 6 | CardHeaderTitle, 7 | CardContent, 8 | CardFooter, 9 | } from '@/components/ui/card'; 10 | import { useState } from 'react'; 11 | import { Input } from '@/components/ui/input'; 12 | import { Button } from '@/components/ui/button'; 13 | 14 | export default function AuthenticationForm() { 15 | const [view, setView] = useState<'login' | 'create-account'>('login'); 16 | return ( 17 | 18 | 19 | 20 | {view === 'login' && 'Log In'} 21 | {view === 'create-account' && 'Create new account'} 22 | 23 | 24 | {view === 'login' 25 | ? 'Do not have an account?' 26 | : 'Already have an account?'}{' '} 27 | 36 | 37 | 38 | 39 | {view === 'login' && ( 40 | <> 41 | 48 | 55 | 56 | )} 57 | {view === 'create-account' && ( 58 | <> 59 | 66 | 73 | 80 | 81 | )} 82 | 83 | 84 | 87 | 88 | 89 | ); 90 | } 91 | -------------------------------------------------------------------------------- /components/cookies/empty-state.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { forwardRef } from 'react'; 3 | import { Button, ButtonProps } from '@/components/ui/button'; 4 | import { cn } from '@/helpers/utils'; 5 | 6 | export interface EmptyStateProps extends React.HTMLAttributes {} 7 | export interface EmptyStateIconProps 8 | extends React.HTMLAttributes {} 9 | export interface EmptyStateHeadlineProps 10 | extends React.HTMLAttributes {} 11 | export interface EmptyStateDescriptionProps 12 | extends React.HTMLAttributes {} 13 | export interface EmptyStatePrimaryActionProps extends ButtonProps {} 14 | export interface EmptyStateSecondaryActionProps extends ButtonProps {} 15 | 16 | export const EmptyState = forwardRef( 17 | ({ className, children, ...args }, ref) => { 18 | return ( 19 |
25 |
26 | {children} 27 |
28 |
29 | ); 30 | }, 31 | ); 32 | 33 | EmptyState.displayName = 'EmptyState'; 34 | 35 | export const EmptyStateIcon = forwardRef( 36 | ({ className, ...args }, ref) => { 37 | return ( 38 |
*]:w-full [&>*]:h-full text-neutral-600 mb-2', 42 | className, 43 | )} 44 | {...args} 45 | /> 46 | ); 47 | }, 48 | ); 49 | 50 | EmptyStateIcon.displayName = 'EmptyStateIcon'; 51 | 52 | export const EmptyStateHeadline = forwardRef< 53 | HTMLHeadingElement, 54 | EmptyStateHeadlineProps 55 | >(({ className, ...args }, ref) => { 56 | return ( 57 |

65 | ); 66 | }); 67 | 68 | EmptyStateHeadline.displayName = 'EmptyStateHeadline'; 69 | 70 | export const EmptyStateDescription = forwardRef< 71 | HTMLParagraphElement, 72 | EmptyStateDescriptionProps 73 | >(({ className, ...args }, ref) => { 74 | return ( 75 |

80 | ); 81 | }); 82 | 83 | EmptyStateDescription.displayName = 'EmptyStateDescription'; 84 | 85 | export const EmptyStatePrimaryAction = forwardRef< 86 | HTMLButtonElement, 87 | EmptyStatePrimaryActionProps 88 | >(({ className, ...args }, ref) => { 89 | return ( 90 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 40 | 41 |

42 | 43 | 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /components/sections/setup-section.tsx: -------------------------------------------------------------------------------- 1 | import { SetupSectionContent } from '@/common/content'; 2 | import { ResponsiveControl } from '../layouts/responsive-control'; 3 | import { forwardRef } from 'react'; 4 | import { cn } from '@/helpers/utils'; 5 | import { PageHeader } from '../layouts/page-header'; 6 | import { Button } from '../ui/button'; 7 | import { CodeBlock } from '../website/code-block'; 8 | import { SETUP_CODE } from '@/package/registry/setup-code'; 9 | import Link from 'next/link'; 10 | 11 | type SetupStepType = { 12 | title: string; 13 | description: string; 14 | action?: { 15 | name: string; 16 | path: string; 17 | }; 18 | code?: 19 | | string 20 | | { 21 | content: string; 22 | fileName: string; 23 | }; 24 | }; 25 | 26 | export interface SetupSectionProps 27 | extends React.HTMLAttributes {} 28 | 29 | export interface SetupStepContainerProps 30 | extends React.HTMLAttributes { 31 | stepContent: SetupStepType; 32 | stepIndex: number; 33 | } 34 | 35 | const SetupData: SetupStepType[] = [ 36 | { 37 | title: 'Have a basic NextJS + Typescript + Tailwind project setup', 38 | description: 39 | 'The setup is going to require a NextJS app with Typescript & Tailwind. Make sure you have a simple project setup, If you have it already, you can go to the next step.', 40 | code: `# using npm \nnpx create-next-app app-name \n\n# using yarn \nyarn create next-app app-name`, 41 | }, 42 | { 43 | title: 'Installing dependencies', 44 | description: 45 | 'All the cookies, components and required utilities are using various npm dependencies. Install them as your first step to get started.', 46 | code: 'yarn add lucide-react framer-motion clsx tailwind-merge', 47 | }, 48 | { 49 | title: 'Add configuration for animations', 50 | description: 51 | 'The configurations are going to provide basic animations to your components. You can customize and add custom animations in this code.', 52 | code: { 53 | content: SETUP_CODE['animation-config'].code, 54 | fileName: SETUP_CODE['animation-config'].registerAt, 55 | }, 56 | }, 57 | { 58 | title: 'Add cn() as to helpers', 59 | description: 60 | 'Components are using cn() to combine the classNames, supporting tailwind-merge. All thanks to shadcn for writing this.', 61 | code: { 62 | content: SETUP_CODE.utils.code, 63 | fileName: SETUP_CODE.utils.registerAt, 64 | }, 65 | }, 66 | ]; 67 | 68 | export const SetupSection = forwardRef( 69 | ({ className, ...args }, ref) => { 70 | return ( 71 |
72 | 73 | 74 |

75 | {SetupSectionContent.headline} 76 |

77 |
78 |

79 | {SetupSectionContent.description} 80 |

81 |
82 |
83 | 84 | 85 | 86 |
87 |
88 |
89 |
90 | 91 | {SetupData.map((setup, index) => { 92 | return ( 93 | 98 | ); 99 | })} 100 | 101 |
102 |
103 | ); 104 | }, 105 | ); 106 | 107 | SetupSection.displayName = 'SetupSection'; 108 | 109 | export const SetupStepContainer = forwardRef< 110 | HTMLDivElement, 111 | SetupStepContainerProps 112 | >(({ className, stepContent, stepIndex, ...args }, ref) => { 113 | return ( 114 |
115 |
116 |
117 |

{stepContent.title}

118 |

{stepContent.description}

119 |
120 | {typeof stepContent.code === 'string' ? ( 121 | {stepContent.code} 122 | ) : ( 123 | 124 | {stepContent.code?.content} 125 | 126 | )} 127 |
128 |
129 | ); 130 | }); 131 | 132 | SetupStepContainer.displayName = 'SetupStepContainer'; 133 | -------------------------------------------------------------------------------- /components/sections/website-navigation.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import { ResponsiveControl } from '../layouts/responsive-control'; 3 | import { NavbarLogo } from '../website/navbar-logo'; 4 | import { Button } from '../ui/button'; 5 | 6 | type NavbarOptionType = { path: string; name: string }; 7 | const NavbarOptions: NavbarOptionType[] = [ 8 | { path: '/github', name: 'GitHub' }, 9 | { path: '/changelog', name: 'Changelog' }, 10 | { path: '/components', name: 'Components' }, 11 | ]; 12 | 13 | export default function WebsiteNavigation() { 14 | return ( 15 | 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /components/ui/accordion.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import * as RadixAccordion from '@radix-ui/react-accordion'; 4 | import { ChevronDown } from 'lucide-react'; 5 | 6 | import { cn } from '@/helpers/utils'; 7 | import React, { forwardRef } from 'react'; 8 | import { motion } from 'framer-motion'; 9 | import { 10 | ComponentAnimation, 11 | ComponentAnimationType, 12 | } from '@/components/configs/animation-config'; 13 | 14 | export const Accordion = forwardRef< 15 | React.ElementRef, 16 | React.ComponentPropsWithoutRef 17 | >(({ className, ...args }, ref) => { 18 | return ( 19 | 27 | ); 28 | }); 29 | 30 | Accordion.displayName = 'Accordion'; 31 | 32 | export const AccordionItem = forwardRef< 33 | React.ElementRef, 34 | React.ComponentPropsWithoutRef 35 | >(({ className, ...args }, ref) => { 36 | return ( 37 | 42 | ); 43 | }); 44 | 45 | AccordionItem.displayName = 'AccordionItem'; 46 | 47 | export const AccordionTrigger = forwardRef< 48 | React.ElementRef, 49 | React.ComponentPropsWithoutRef 50 | >(({ className, children, ...args }, ref) => { 51 | return ( 52 | 53 | svg]:rotate-180', 57 | className, 58 | )} 59 | {...args}> 60 | {children} 61 | 62 | 63 | 64 | ); 65 | }); 66 | 67 | AccordionTrigger.displayName = 'AccordionTrigger'; 68 | 69 | export const AccordionContent = forwardRef< 70 | React.ElementRef, 71 | React.ComponentPropsWithoutRef & { 72 | animationType?: ComponentAnimationType; 73 | } 74 | >(({ className, children, animationType = 'none', ...args }, ref) => { 75 | return ( 76 | 82 | 90 | {children} 91 | 92 | 93 | ); 94 | }); 95 | 96 | AccordionContent.displayName = 'AccordionContent'; 97 | -------------------------------------------------------------------------------- /components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/helpers/utils'; 3 | import { ArrowRight, ChevronRight, Loader2 } from 'lucide-react'; 4 | import { ReactNode, forwardRef, useState } from 'react'; 5 | import { motion } from 'framer-motion'; 6 | import { ComponentAnimationType } from '@/components/configs/animation-config'; 7 | import { ComponentAnimation } from '@/components/configs/animation-config'; 8 | 9 | export type ButtonVariantType = 'primary' | 'secondary' | 'ghost'; 10 | export type ButtonSizeType = 'sm' | 'md' | 'lg'; 11 | 12 | export interface ButtonProps 13 | extends React.ButtonHTMLAttributes { 14 | withArrow?: boolean; 15 | icon?: ReactNode; 16 | iconDirection?: 'left' | 'right'; 17 | variant?: ButtonVariantType; 18 | size?: ButtonSizeType; 19 | stretch?: boolean; 20 | isLoading?: boolean; 21 | animationType?: ComponentAnimationType; 22 | } 23 | 24 | const ButtonVariantStyles: Record = { 25 | primary: 26 | 'bg-gradient-to-b from-blue-500 to-blue-600 text-white shadow-md active:shadow', 27 | secondary: 'bg-white/10 hover:bg-white/20 focus:ring-neutral-700', 28 | ghost: 'bg-transparent hover:bg-white/10', 29 | }; 30 | 31 | const ButtonSizeStyles: Record = { 32 | sm: 'text-xs px-4 py-2 rounded-lg', 33 | md: 'text-sm px-4 py-2 rounded-lg', 34 | lg: 'text-base px-6 py-3 rounded-xl', 35 | }; 36 | 37 | export const Button = forwardRef( 38 | ( 39 | { 40 | className, 41 | children, 42 | variant = 'primary', 43 | size = 'md', 44 | icon = <>, 45 | iconDirection = 'left', 46 | withArrow = false, 47 | stretch = false, 48 | disabled = false, 49 | isLoading = false, 50 | animationType = 'none', 51 | ...args 52 | }, 53 | ref, 54 | ) => { 55 | const [hovering, setHovering] = useState(false); 56 | return ( 57 | { 80 | // toggling from chevron to arrow 81 | if (withArrow) setHovering(true); 82 | // Run the function passed in args (if it exists) 83 | if (args && args.onMouseEnter) { 84 | args.onMouseEnter(event); 85 | } 86 | }} 87 | onMouseLeave={(event) => { 88 | // toggling back from arrow to chevron 89 | setHovering(false); 90 | // Run the function passed in args (if it exists) 91 | if (args && args.onMouseLeave) { 92 | args.onMouseLeave(event); 93 | } 94 | }} 95 | {...(args as unknown as any)}> 96 | 97 | {isLoading && ( 98 | 108 | 109 | 110 | )} 111 | {iconDirection === 'left' && icon} 112 | {children} 113 | {iconDirection === 'right' && icon} 114 | 115 | {withArrow && 116 | (!hovering ? ( 117 | 118 | ) : ( 119 | 120 | ))} 121 | 122 | ); 123 | }, 124 | ); 125 | 126 | Button.displayName = 'Button'; 127 | -------------------------------------------------------------------------------- /components/ui/callout.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { ReactNode, forwardRef } from 'react'; 3 | import { 4 | ComponentAnimation, 5 | ComponentAnimationType, 6 | } from '@/components/configs/animation-config'; 7 | import { cn } from '@/helpers/utils'; 8 | import { MotionProps, motion } from 'framer-motion'; 9 | import { AlertCircle, AlertTriangle, CheckCircle, Info } from 'lucide-react'; 10 | 11 | export type CalloutVariantType = 12 | | 'info' 13 | | 'error' 14 | | 'warning' 15 | | 'success' 16 | | 'subtle'; 17 | export interface CalloutProps extends React.HTMLAttributes { 18 | variant?: CalloutVariantType; 19 | animationType?: ComponentAnimationType; 20 | stretch?: boolean; 21 | } 22 | 23 | const CalloutVariantStyle: Record = { 24 | info: '[&>.callout-icon]:text-blue-500', 25 | error: '[&>.callout-icon]:text-red-500', 26 | warning: '[&>.callout-icon]:text-yellow-500', 27 | success: '[&>.callout-icon]:text-green-500', 28 | subtle: '[&>.callout-icon]:text-neutral-600', 29 | }; 30 | 31 | const CalloutVariantIcon: Record = { 32 | info: , 33 | error: , 34 | warning: , 35 | success: , 36 | subtle: , 37 | }; 38 | 39 | export const Callout = forwardRef( 40 | ( 41 | { 42 | className, 43 | children, 44 | variant = 'info', 45 | animationType = 'none', 46 | stretch = false, 47 | ...args 48 | }, 49 | ref, 50 | ) => { 51 | return ( 52 | 67 | 68 | {CalloutVariantIcon[variant]} 69 | 70 |
71 | {children} 72 |
73 |
74 | ); 75 | }, 76 | ); 77 | 78 | Callout.displayName = 'Callout'; 79 | -------------------------------------------------------------------------------- /components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/helpers/utils'; 3 | import { forwardRef } from 'react'; 4 | import { MotionProps, motion } from 'framer-motion'; 5 | import { 6 | ComponentAnimation, 7 | ComponentAnimationType, 8 | } from '@/components/configs/animation-config'; 9 | 10 | export interface CardProps extends React.HTMLAttributes { 11 | animationType?: ComponentAnimationType; 12 | } 13 | export interface CardHeaderProps extends React.HTMLAttributes {} 14 | export interface CardHeaderTitleProps 15 | extends React.HTMLAttributes {} 16 | export interface CardHeaderDescriptionProps 17 | extends React.HTMLAttributes {} 18 | export interface CardContentProps 19 | extends React.HTMLAttributes {} 20 | export interface CardFooterProps extends React.HTMLAttributes {} 21 | 22 | export const Card = forwardRef( 23 | ({ className, animationType = 'none', ...args }, ref) => { 24 | return ( 25 | 36 | ); 37 | }, 38 | ); 39 | 40 | Card.displayName = 'Card'; 41 | 42 | export const CardHeader = forwardRef( 43 | ({ className, ...args }, ref) => { 44 | return ( 45 |
53 | ); 54 | }, 55 | ); 56 | 57 | CardHeader.displayName = 'CardHeader'; 58 | 59 | export const CardHeaderTitle = forwardRef< 60 | HTMLHeadingElement, 61 | CardHeaderTitleProps 62 | >(({ className, ...args }, ref) => { 63 | return ( 64 |

72 | ); 73 | }); 74 | 75 | CardHeaderTitle.displayName = 'CardHeaderTitle'; 76 | 77 | export const CardHeaderDescription = forwardRef< 78 | HTMLParagraphElement, 79 | CardHeaderDescriptionProps 80 | >(({ className, ...args }, ref) => { 81 | return ( 82 |

90 | ); 91 | }); 92 | 93 | CardHeaderDescription.displayName = 'CardHeaderDescription'; 94 | 95 | export const CardContent = forwardRef( 96 | ({ className, ...args }, ref) => { 97 | return ( 98 |

99 | ); 100 | }, 101 | ); 102 | 103 | CardContent.displayName = 'CardContent'; 104 | 105 | export const CardFooter = forwardRef( 106 | ({ className, ...args }, ref) => { 107 | return ( 108 |
116 | ); 117 | }, 118 | ); 119 | 120 | CardFooter.displayName = 'CardFooter'; 121 | -------------------------------------------------------------------------------- /components/ui/contact-input.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/helpers/utils'; 3 | import { Loader2 } from 'lucide-react'; 4 | import { forwardRef } from 'react'; 5 | import { motion } from 'framer-motion'; 6 | 7 | export interface ContactInputProps 8 | extends React.HTMLAttributes { 9 | showCountryCodeOptions?: boolean; 10 | defaultCountryCode?: string; 11 | withLabel?: string; 12 | stretch?: boolean; 13 | isLoading?: boolean; 14 | } 15 | 16 | export interface ContactInputTypeareaProps 17 | extends React.InputHTMLAttributes {} 18 | 19 | export const ContactInput = forwardRef( 20 | ( 21 | { 22 | className, 23 | showCountryCodeOptions = false, 24 | defaultCountryCode = null, 25 | stretch = false, 26 | children, 27 | isLoading = false, 28 | ...args 29 | }, 30 | ref, 31 | ) => { 32 | return ( 33 |
42 | {defaultCountryCode ? ( 43 | 44 | {showCountryCodeOptions ? <> : defaultCountryCode} 45 | 46 | ) : ( 47 | <> 48 | )} 49 |
{children}
50 | {isLoading ? ( 51 | 58 | 59 | 60 | ) : ( 61 | <> 62 | )} 63 |
64 | ); 65 | }, 66 | ); 67 | 68 | ContactInput.displayName = 'ContactInput'; 69 | 70 | export const ContactInputTypearea = forwardRef< 71 | HTMLInputElement, 72 | ContactInputTypeareaProps 73 | >(({ className, ...args }, ref) => { 74 | return ( 75 | 84 | ); 85 | }); 86 | 87 | ContactInputTypearea.displayName = 'ContactInputTypearea'; 88 | -------------------------------------------------------------------------------- /components/ui/icon-button.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { forwardRef } from 'react'; 3 | import { 4 | ComponentAnimation, 5 | ComponentAnimationType, 6 | } from '@/components/configs/animation-config'; 7 | import { MotionProps, motion } from 'framer-motion'; 8 | import { cn } from '@/helpers/utils'; 9 | import { Loader2 } from 'lucide-react'; 10 | 11 | export type IconButtonVariantType = 'primary' | 'secondary' | 'ghost'; 12 | export type IconButtonSizeType = 'sm' | 'md' | 'lg'; 13 | 14 | export interface IconButtonProps 15 | extends React.ButtonHTMLAttributes { 16 | isLoading?: boolean; 17 | animationType?: ComponentAnimationType; 18 | stretch?: boolean; 19 | variant?: IconButtonVariantType; 20 | size?: IconButtonSizeType; 21 | } 22 | 23 | const IconButtonVariantStyles: Record = { 24 | primary: 25 | 'bg-gradient-to-b from-blue-500 to-blue-600 text-white shadow-md active:shadow', 26 | secondary: 'bg-white/10 hover:bg-white/20 focus:ring-neutral-700', 27 | ghost: 'bg-transparent hover:bg-white/10', 28 | }; 29 | 30 | const IconButtonSizeStyles: Record = { 31 | sm: 'text-xs p-2 rounded-lg', 32 | md: 'text-sm p-3 rounded-lg', 33 | lg: 'text-base p-4 rounded-xl', 34 | }; 35 | 36 | export const IconButton = forwardRef( 37 | ( 38 | { 39 | className, 40 | children, 41 | isLoading = false, 42 | disabled = false, 43 | stretch = false, 44 | animationType = 'none', 45 | variant = 'primary', 46 | size = 'md', 47 | ...args 48 | }, 49 | ref, 50 | ) => { 51 | return ( 52 | 75 | {!isLoading && children} 76 | {isLoading && ( 77 | 87 | 88 | 89 | )} 90 | 91 | ); 92 | }, 93 | ); 94 | 95 | IconButton.displayName = 'IconButton'; 96 | -------------------------------------------------------------------------------- /components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/helpers/utils'; 3 | import React, { forwardRef } from 'react'; 4 | import { MotionProps, motion } from 'framer-motion'; 5 | import { 6 | ComponentAnimation, 7 | ComponentAnimationType, 8 | } from '@/components/configs/animation-config'; 9 | 10 | export interface InputProps 11 | extends React.InputHTMLAttributes { 12 | stretch?: boolean; 13 | withLabel?: string; 14 | labelDirection?: 'hl' | 'v'; 15 | animationType?: ComponentAnimationType; 16 | } 17 | 18 | export const Input = forwardRef( 19 | ( 20 | { 21 | className, 22 | stretch = false, 23 | withLabel = '', 24 | labelDirection = 'h', 25 | animationType = 'none', 26 | ...args 27 | }, 28 | ref, 29 | ) => { 30 | const inputElement = ( 31 | 47 | ); 48 | if (withLabel.length) { 49 | return ( 50 |
57 | 62 | {inputElement} 63 |
64 | ); 65 | } else { 66 | return inputElement; 67 | } 68 | }, 69 | ); 70 | 71 | Input.displayName = 'Input'; 72 | -------------------------------------------------------------------------------- /components/ui/pillar.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { Button, ButtonProps } from '@/components/ui/button'; 3 | import { cn } from '@/helpers/utils'; 4 | import { forwardRef } from 'react'; 5 | 6 | export interface PillarProps extends React.HTMLAttributes {} 7 | export interface PillarIconProps extends React.HTMLAttributes {} 8 | export interface PillarHeadlineProps 9 | extends React.HTMLAttributes {} 10 | export interface PillarDescriptionProps 11 | extends React.HTMLAttributes {} 12 | export interface PillarActionProps extends ButtonProps {} 13 | 14 | export const Pillar = forwardRef( 15 | ({ className, ...args }, ref) => { 16 | return ( 17 |
25 | ); 26 | }, 27 | ); 28 | 29 | Pillar.displayName = 'Pillar'; 30 | 31 | export const PillarIcon = forwardRef( 32 | ({ className, ...args }, ref) => { 33 | return ( 34 |
*]:w-full [&>*]:h-full mb-2 text-blue-500', 38 | className, 39 | )} 40 | {...args} 41 | /> 42 | ); 43 | }, 44 | ); 45 | 46 | PillarIcon.displayName = 'PillarIcon'; 47 | 48 | export const PillarHeadline = forwardRef< 49 | HTMLHeadingElement, 50 | PillarHeadlineProps 51 | >(({ className, ...args }, ref) => { 52 | return ( 53 |

61 | ); 62 | }); 63 | 64 | PillarHeadline.displayName = 'PillarHeadline'; 65 | 66 | export const PillarDescription = forwardRef< 67 | HTMLParagraphElement, 68 | PillarDescriptionProps 69 | >(({ className, ...args }, ref) => { 70 | return ( 71 |

76 | ); 77 | }); 78 | 79 | PillarDescription.displayName = 'PillarDescription'; 80 | 81 | export const PillarAction = forwardRef( 82 | ({ className, ...args }, ref) => { 83 | return ( 84 | 66 | ); 67 | }, 68 | ); 69 | 70 | TabMenuOption.displayName = 'TabMenuOption'; 71 | -------------------------------------------------------------------------------- /components/ui/timeline.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { ClassValue } from 'clsx'; 3 | import { ReactNode, forwardRef } from 'react'; 4 | import { Button, ButtonProps } from './button'; 5 | import { cn } from '@/helpers/utils'; 6 | import { AlertTriangle, CheckCircle, Info } from 'lucide-react'; 7 | 8 | export interface TimelineProps extends React.HTMLAttributes {} 9 | export interface TimelineItemProps 10 | extends React.HTMLAttributes {} 11 | export type TimelineItemIconVariants = 12 | | 'none' 13 | | 'info' 14 | | 'success' 15 | | 'warning' 16 | | 'error'; 17 | export interface TimelineItemIconProps 18 | extends React.HTMLAttributes { 19 | variant?: TimelineItemIconVariants; 20 | iconBG?: ClassValue; 21 | } 22 | export interface TimelineItemHeadlineProps 23 | extends React.HTMLAttributes {} 24 | export interface TimelineItemDescriptionProps 25 | extends React.HTMLAttributes {} 26 | export interface TimelineItemActionContainerProps 27 | extends React.HTMLAttributes {} 28 | export interface TimelineItemPrimaryActionProps extends ButtonProps {} 29 | export interface TimelineItemSecondaryActionProps extends ButtonProps {} 30 | 31 | export const Timeline = forwardRef( 32 | ({ className, ...args }, ref) => { 33 | return ( 34 |

42 | ); 43 | }, 44 | ); 45 | 46 | Timeline.displayName = 'Timeline'; 47 | 48 | export const TimelineItem = forwardRef( 49 | ({ className, ...args }, ref) => { 50 | return ( 51 |
59 | ); 60 | }, 61 | ); 62 | 63 | TimelineItem.displayName = 'TimelineItem'; 64 | 65 | export const TimelineItemIconStyles: Record< 66 | TimelineItemIconVariants, 67 | { style: string; render: ReactNode } 68 | > = { 69 | none: { 70 | style: 'bg-neutral-700', 71 | render: , 72 | }, 73 | info: { 74 | style: 'bg-blue-500 text-white', 75 | render: , 76 | }, 77 | error: { 78 | style: 'bg-red-500 text-white', 79 | render: , 80 | }, 81 | success: { 82 | style: 'bg-green-600 text-white', 83 | render: , 84 | }, 85 | warning: { 86 | style: 'bg-yellow-500 text-white', 87 | render: , 88 | }, 89 | }; 90 | 91 | export const TimelineItemIcon = forwardRef< 92 | HTMLDivElement, 93 | TimelineItemIconProps 94 | >(({ className, children = null, variant = 'none', ...args }, ref) => { 95 | return ( 96 |
104 |
105 | {children || TimelineItemIconStyles[variant].render} 106 |
107 |
108 | ); 109 | }); 110 | 111 | TimelineItemIcon.displayName = 'TimelineItemIcon'; 112 | 113 | export const TimelineItemHeadline = forwardRef< 114 | HTMLHeadingElement, 115 | TimelineItemHeadlineProps 116 | >(({ className, ...args }, ref) => { 117 | return ( 118 |

126 | ); 127 | }); 128 | 129 | TimelineItemHeadline.displayName = 'TimelineItemHeadline'; 130 | 131 | export const TimelineItemDescription = forwardRef< 132 | HTMLParagraphElement, 133 | TimelineItemDescriptionProps 134 | >(({ className, ...args }, ref) => { 135 | return ( 136 |

144 | ); 145 | }); 146 | 147 | TimelineItemDescription.displayName = 'TimelineItemDescription'; 148 | 149 | export const TimelineItemActionContainer = forwardRef< 150 | HTMLDivElement, 151 | TimelineItemActionContainerProps 152 | >(({ className, ...args }, ref) => { 153 | return ( 154 |

162 | ); 163 | }); 164 | 165 | TimelineItemActionContainer.displayName = 'TimelineItemActionContainer'; 166 | 167 | export const TimelineItemPrimaryAction = forwardRef< 168 | HTMLButtonElement, 169 | TimelineItemPrimaryActionProps 170 | >(({ className, ...args }, ref) => { 171 | return ( 172 | 110 | 111 | ); 112 | }, 113 | ); 114 | 115 | ToastAction.displayName = 'ToastAction'; 116 | 117 | export const ToastViewportPositionStyle: Record = { 118 | 'bottom-left': 'bottom-0 left-0', 119 | 'bottom-right': 'bottom-0 right-0', 120 | 'top-left': 'top-0 left-0', 121 | 'top-right': 'top-0 right-0', 122 | } satisfies Record; 123 | 124 | export type ToastViewportType = React.ComponentProps< 125 | typeof RadixToast.Viewport 126 | > & { 127 | position: ToastPositionType; 128 | }; 129 | 130 | export const ToastViewport = forwardRef( 131 | ({ className, position = 'bottom-right', ...args }, ref) => { 132 | return ( 133 | 142 | ); 143 | }, 144 | ); 145 | 146 | ToastViewport.displayName = 'ToastViewport'; 147 | -------------------------------------------------------------------------------- /components/website/code-block.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/helpers/utils'; 3 | import { forwardRef, useState } from 'react'; 4 | import { copyToClipboard } from '@/helpers/copy-to-clipboard'; 5 | import { Button } from '../ui/button'; 6 | import posthog from 'posthog-js'; 7 | 8 | interface CodeBlockProps extends React.HTMLAttributes { 9 | fileName?: string; 10 | hasViewMore?: boolean; 11 | } 12 | 13 | export const CodeBlock = forwardRef( 14 | ( 15 | { className, children, fileName = false, hasViewMore = false, ...args }, 16 | ref, 17 | ) => { 18 | const [viewMore, setViewMore] = useState(false); 19 | // to manage states for copy-to-clipboard 20 | const [ctc, setCTC] = useState(false); 21 | return ( 22 |
32 | {fileName && ( 33 |
34 | {fileName} 35 | 46 |
47 | )} 48 |
54 | 55 | {children} 56 | 57 |
58 | {hasViewMore && ( 59 | 71 | )} 72 |
73 | ); 74 | }, 75 | ); 76 | 77 | CodeBlock.displayName = 'CodeBlock'; 78 | -------------------------------------------------------------------------------- /components/website/component-block.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/helpers/utils'; 3 | import { ReactNode, forwardRef } from 'react'; 4 | import { MotionProps, motion } from 'framer-motion'; 5 | import Link from 'next/link'; 6 | import posthog from 'posthog-js'; 7 | 8 | export interface ComponentBlockProps 9 | extends React.HTMLAttributes { 10 | componentData: { 11 | name: string; 12 | description: string; 13 | path: string; 14 | render: ReactNode; 15 | }; 16 | animationThreshold?: number; 17 | } 18 | 19 | export const ComponentBlock = forwardRef( 20 | ( 21 | { 22 | className, 23 | componentData: { 24 | name: componentName, 25 | description: componentDescription, 26 | path: componentPath, 27 | render: componentRender = null, 28 | }, 29 | animationThreshold = 1, 30 | ...args 31 | }, 32 | ref, 33 | ) => { 34 | return ( 35 | posthog.capture(componentName)}> 48 | 49 |
50 | {componentRender} 51 |
52 |
53 |

{componentName}

54 |

{componentDescription}

55 |
56 | 57 |
58 | ); 59 | }, 60 | ); 61 | 62 | ComponentBlock.displayName = 'ComponentBlock'; 63 | -------------------------------------------------------------------------------- /components/website/component-docs-header.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { usePathname } from 'next/navigation'; 3 | import { ComponentsList } from '@/app/components/common/components-list'; 4 | 5 | export default function ComponentDocsHeader() { 6 | const pathname = usePathname(); 7 | const thisComponent = ComponentsList.find( 8 | (component) => component.path === pathname, 9 | ); 10 | return ( 11 |
12 |

13 | {thisComponent?.name} 14 |

15 |

{thisComponent?.description}

16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /components/website/component-preview.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/helpers/utils'; 3 | import { forwardRef, useState } from 'react'; 4 | import { CodeBlock } from './code-block'; 5 | import { Button } from '../ui/button'; 6 | 7 | export interface ComponentPreviewProps 8 | extends React.HTMLAttributes { 9 | headline: string; 10 | description?: string; 11 | code: string; 12 | } 13 | 14 | export const ComponentPreview = forwardRef< 15 | HTMLDivElement, 16 | ComponentPreviewProps 17 | >(({ className, children, headline, description = '', code, ...args }, ref) => { 18 | const [codeView, setCodeView] = useState(false); 19 | return ( 20 |
21 |
22 |

25 | {headline} 26 |

27 | {description &&

{description}

} 28 |
29 |
36 | 43 | {!codeView && children} 44 | {codeView && {code}} 45 |
46 |
47 | ); 48 | }); 49 | 50 | ComponentPreview.displayName = 'ComponentPreview'; 51 | -------------------------------------------------------------------------------- /components/website/cookie-block.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { cn } from '@/helpers/utils'; 3 | import { ReactNode, forwardRef } from 'react'; 4 | import { MotionProps, motion } from 'framer-motion'; 5 | import Link from 'next/link'; 6 | import posthog from 'posthog-js'; 7 | 8 | export interface CookieBlockProps extends React.HTMLAttributes { 9 | cookieData: { 10 | name: string; 11 | description: string; 12 | path: string; 13 | render: ReactNode; 14 | }; 15 | animationThreshold?: number; 16 | } 17 | 18 | export const CookieBlock = forwardRef( 19 | ( 20 | { 21 | className, 22 | cookieData: { 23 | name: cookieName, 24 | description: cookieDescription, 25 | path: cookiePath, 26 | render: cookieRender = null, 27 | }, 28 | animationThreshold = 1, 29 | ...args 30 | }, 31 | ref, 32 | ) => { 33 | return ( 34 | posthog.capture(cookieName)}> 47 | 48 |
49 | {cookieRender} 50 |
51 |
52 |

{cookieName}

53 |

{cookieDescription}

54 |
55 | 56 |
57 | ); 58 | }, 59 | ); 60 | 61 | CookieBlock.displayName = 'CookieBlock'; 62 | -------------------------------------------------------------------------------- /components/website/cookie-preview.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from '@/helpers/utils'; 2 | import { forwardRef } from 'react'; 3 | 4 | export interface CookiePreviewProps 5 | extends React.HTMLAttributes {} 6 | 7 | export const CookiePreview = forwardRef( 8 | ({ className, ...args }, ref) => { 9 | return ( 10 |
18 | ); 19 | }, 20 | ); 21 | 22 | CookiePreview.displayName = 'CookiePreview'; 23 | -------------------------------------------------------------------------------- /components/website/cookies-docs-header.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { usePathname } from 'next/navigation'; 3 | import { CookiesList } from '@/app/cookies/common/cookies-list'; 4 | 5 | export default function CookiesDocsHeader() { 6 | const pathname = usePathname(); 7 | const thisComponent = CookiesList.find( 8 | (component) => component.path === pathname, 9 | ); 10 | return ( 11 |
12 |

13 | {thisComponent?.name} 14 |

15 |

{thisComponent?.description}

16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /components/website/docs-page-outline.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import Link from 'next/link'; 3 | import { useEffect, useState } from 'react'; 4 | 5 | export default function DocsPageOutline() { 6 | const [outline, setOutline] = useState< 7 | { 8 | id: string; 9 | value: string; 10 | isInViewport: boolean; 11 | }[] 12 | >([]); 13 | 14 | useEffect(() => { 15 | const observer = new IntersectionObserver( 16 | (entries) => { 17 | const newOutline = outline.map((item) => { 18 | const entry = entries.find((entry) => entry.target.id === item.id); 19 | return { 20 | ...item, 21 | isInViewport: entry ? entry.isIntersecting : false, 22 | }; 23 | }); 24 | setOutline(newOutline); 25 | }, 26 | { threshold: 0.5 }, 27 | ); 28 | 29 | const headlineTextList: Element[] = Array.from( 30 | document.getElementsByClassName('docs-page-headline'), 31 | ); 32 | headlineTextList.forEach((element) => { 33 | observer.observe(element); 34 | }); 35 | 36 | return () => observer.disconnect(); 37 | }, [outline]); 38 | 39 | useEffect(() => { 40 | const headlineTextList: Element[] = Array.from( 41 | document.getElementsByClassName('docs-page-headline'), 42 | ); 43 | if (headlineTextList.length) { 44 | const newOutline = headlineTextList.map((outlineItem: Element) => ({ 45 | id: (outlineItem.textContent || '').toLowerCase().replace(/\s+/g, '-'), 46 | value: outlineItem.textContent || '', 47 | isInViewport: false, 48 | })); 49 | setOutline(newOutline); 50 | } 51 | }, []); 52 | 53 | return ( 54 |
55 |

Page Outline

56 | {outline.map(({ id, value, isInViewport }, index: number) => ( 57 | 61 | {value} 62 | 63 | ))} 64 |
65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /components/website/navbar-logo.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import Image from 'next/image'; 3 | import { forwardRef, useEffect, useState } from 'react'; 4 | import { motion } from 'framer-motion'; 5 | import { usePathname } from 'next/navigation'; 6 | 7 | export interface NavbarLogoProps extends React.HTMLAttributes { 8 | responsive?: boolean; 9 | } 10 | 11 | export const NavbarLogo = forwardRef( 12 | ({ className, responsive = false, ...args }, ref) => { 13 | const [hovering, setHovering] = useState(false); 14 | const pathname = usePathname(); 15 | useEffect(() => setHovering(false), [pathname]); 16 | return ( 17 |
{ 20 | if (pathname !== '/') { 21 | setHovering(true); 22 | } 23 | }} 24 | onMouseLeave={() => { 25 | if (pathname !== '/') { 26 | setHovering(false); 27 | } 28 | }}> 29 | cookies-logo 37 | {hovering && pathname !== '/' && ( 38 | 49 | {'back to home'} 50 | 51 | )} 52 |
53 | ); 54 | }, 55 | ); 56 | 57 | NavbarLogo.displayName = 'NavbarLogo'; 58 | -------------------------------------------------------------------------------- /generators/README.md: -------------------------------------------------------------------------------- 1 | # Generator Code Setup 2 | 3 | To generate updated setup-code on every commit, follow these precommit setup steps for your local dev environment. Make sure to not commit changes without setting up pre-commit. 4 | 5 | - Create a pre-commit file 6 | 7 | ```bash 8 | touch .git/hooks/pre-commit 9 | ``` 10 | 11 | - Open the file using `code` to `vim` 12 | 13 | ```bash 14 | # using vscode 15 | code .git/hooks/pre-commit 16 | 17 | # using vim 18 | vim .git/hooks/pre-commit 19 | ``` 20 | 21 | - Paste these scripts in `.git/hooks/pre-commit` 22 | 23 | ```bash 24 | #!/bin/sh 25 | 26 | set -e 27 | 28 | echo "Generator code for updating package/registry" 29 | echo "Updating package/registry/setup-code.json and package/registry/component-examples.json" 30 | yarn package:generate || (echo "Error while generating setup-code" && exit 1) 31 | 32 | yarn lint 33 | ``` 34 | -------------------------------------------------------------------------------- /generators/update-cookie-code.ts: -------------------------------------------------------------------------------- 1 | const cookiesFS = require('fs'); 2 | const cookiesPath = require('path'); 3 | 4 | type CookiesCodeRegisteryType = 5 | | 'authentication-form' 6 | | 'hero-section' 7 | | 'empty-state' 8 | | 'image-card' 9 | | 'toggle-list'; 10 | 11 | const COOKIES_OUTPUT_PATH = cookiesPath.join( 12 | __dirname, 13 | '../package/registry/cookies-setup-code.tsx', 14 | ); 15 | const COOKIES_FILES_TO_REGISTER: Record< 16 | CookiesCodeRegisteryType, 17 | { registerAt: string; path: string } 18 | > = { 19 | 'authentication-form': { 20 | registerAt: 'components/cookies/authentication-form.tsx', 21 | path: cookiesPath.join( 22 | __dirname, 23 | '../components/cookies/authentication-form.tsx', 24 | ), 25 | }, 26 | 'hero-section': { 27 | registerAt: 'components/cookies/hero-section.tsx', 28 | path: cookiesPath.join(__dirname, '../components/cookies/hero-section.tsx'), 29 | }, 30 | 'empty-state': { 31 | registerAt: 'components/cookies/empty-state.tsx', 32 | path: cookiesPath.join(__dirname, '../components/cookies/empty-state.tsx'), 33 | }, 34 | 'image-card': { 35 | registerAt: 'components/cookies/image-card.tsx', 36 | path: cookiesPath.join(__dirname, '../components/cookies/image-card.tsx'), 37 | }, 38 | 'toggle-list': { 39 | registerAt: 'components/cookies/toggle-list.tsx', 40 | path: cookiesPath.join(__dirname, '../components/cookies/toggle-list.tsx'), 41 | }, 42 | }; 43 | 44 | const cookiesSetupCode = Object.keys(COOKIES_FILES_TO_REGISTER).reduce( 45 | (acc, name) => { 46 | const { registerAt, path: filePath } = 47 | COOKIES_FILES_TO_REGISTER[name as CookiesCodeRegisteryType]; 48 | const code: string = cookiesFS.readFileSync(filePath, 'utf-8'); 49 | acc[name] = { registerAt, code }; 50 | return acc; 51 | }, 52 | {} as Record, 53 | ); 54 | 55 | const tsxContentForCookies = `\ 56 | // This file is auto-generated. Do not modify manually. 57 | 58 | type CookiesCodeRegisteryType = 59 | | 'authentication-form' 60 | | 'hero-section' 61 | | 'empty-state' 62 | | 'image-card' 63 | | 'toggle-list'; 64 | 65 | export const COOKIES_SETUP_CODE: Record = ${JSON.stringify(cookiesSetupCode, null, 2)}; 66 | `; 67 | 68 | cookiesFS.writeFileSync(COOKIES_OUTPUT_PATH, tsxContentForCookies, 'utf-8'); 69 | console.log( 70 | '[Generator > Update Cookies Setup Code]', 71 | 'Successfully updated cookies-setup-code in package/registry/cookes-setup-code.tsx', 72 | ); 73 | -------------------------------------------------------------------------------- /generators/update-setup-code.ts: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const devUtils = require('../helpers/dev'); 4 | 5 | const devConsole = devUtils.DevConsole; 6 | 7 | type CodeRegisteryType = 8 | | 'animation-config' 9 | | 'utils' 10 | | 'button' 11 | | 'icon-button' 12 | | 'input' 13 | | 'card' 14 | | 'switch' 15 | | 'accordion' 16 | | 'callout' 17 | | 'timeline' 18 | | 'tab-menu' 19 | | 'sidebar-menu' 20 | | 'pillar' 21 | | 'stepper' 22 | | 'toast' 23 | | 'responsive-control'; 24 | 25 | const OUTPUT_PATH = path.join(__dirname, '../package/registry/setup-code.tsx'); 26 | const FILES_TO_REGISTER: Record< 27 | CodeRegisteryType, 28 | { registerAt: string; path: string } 29 | > = { 30 | 'animation-config': { 31 | registerAt: 'components/configs/animation-config.ts', 32 | path: path.join(__dirname, '../components/configs/animation-config.ts'), 33 | }, 34 | utils: { 35 | registerAt: 'helpers/utils.ts', 36 | path: path.join(__dirname, '../helpers/utils.ts'), 37 | }, 38 | button: { 39 | registerAt: 'components/ui/button.tsx', 40 | path: path.join(__dirname, '../components/ui/button.tsx'), 41 | }, 42 | 'icon-button': { 43 | registerAt: 'components/ui/icon-button.tsx', 44 | path: path.join(__dirname, '../components/ui/icon-button.tsx'), 45 | }, 46 | input: { 47 | registerAt: 'components/ui/input.tsx', 48 | path: path.join(__dirname, '../components/ui/input.tsx'), 49 | }, 50 | card: { 51 | registerAt: 'components/ui/card.tsx', 52 | path: path.join(__dirname, '../components/ui/card.tsx'), 53 | }, 54 | switch: { 55 | registerAt: 'components/ui/switch.tsx', 56 | path: path.join(__dirname, '../components/ui/switch.tsx'), 57 | }, 58 | accordion: { 59 | registerAt: 'components/ui/accordion.tsx', 60 | path: path.join(__dirname, '../components/ui/accordion.tsx'), 61 | }, 62 | callout: { 63 | registerAt: 'components/ui/callout.tsx', 64 | path: path.join(__dirname, '../components/ui/callout.tsx'), 65 | }, 66 | timeline: { 67 | registerAt: 'components/ui/timeline.tsx', 68 | path: path.join(__dirname, '../components/ui/timeline.tsx'), 69 | }, 70 | 'tab-menu': { 71 | registerAt: 'components/ui/tab-menu.tsx', 72 | path: path.join(__dirname, '../components/ui/tab-menu.tsx'), 73 | }, 74 | 'sidebar-menu': { 75 | registerAt: 'components/ui/sidebar-menu.tsx', 76 | path: path.join(__dirname, '../components/ui/sidebar-menu.tsx'), 77 | }, 78 | pillar: { 79 | registerAt: 'components/ui/pillar.tsx', 80 | path: path.join(__dirname, '../components/ui/pillar.tsx'), 81 | }, 82 | stepper: { 83 | registerAt: 'components/ui/stepper.tsx', 84 | path: path.join(__dirname, '../components/ui/stepper.tsx'), 85 | }, 86 | toast: { 87 | registerAt: 'components/ui/toast.tsx', 88 | path: path.join(__dirname, '../components/ui/toast.tsx'), 89 | }, 90 | 'responsive-control': { 91 | registerAt: 'components/layouts/responsive-control.tsx', 92 | path: path.join(__dirname, '../components/layouts/responsive-control.tsx'), 93 | }, 94 | }; 95 | 96 | const setupCode = Object.keys(FILES_TO_REGISTER).reduce( 97 | (acc, name) => { 98 | const { registerAt, path: filePath } = 99 | FILES_TO_REGISTER[name as CodeRegisteryType]; 100 | const code: string = fs.readFileSync(filePath, 'utf-8'); 101 | acc[name] = { registerAt, code }; 102 | return acc; 103 | }, 104 | {} as Record, 105 | ); 106 | 107 | const tsxContent = `\ 108 | // This file is auto-generated. Do not modify manually. 109 | 110 | export type CodeRegisteryType = 111 | | 'animation-config' 112 | | 'utils' 113 | | 'button' 114 | | 'icon-button' 115 | | 'input' 116 | | 'card' 117 | | 'switch' 118 | | 'accordion' 119 | | 'callout' 120 | | 'timeline' 121 | | 'tab-menu' 122 | | 'sidebar-menu' 123 | | 'pillar' 124 | | 'stepper' 125 | | 'toast' 126 | | 'responsive-control'; 127 | 128 | export const SETUP_CODE: Record = ${JSON.stringify(setupCode, null, 2)}; 129 | `; 130 | 131 | fs.writeFileSync(OUTPUT_PATH, tsxContent, 'utf-8'); 132 | devConsole.log( 133 | '[Generator > Update Setup Code]', 134 | 'Successfully updated setup-code in package/registry/setup-code.tsx', 135 | ); 136 | -------------------------------------------------------------------------------- /helpers/copy-to-clipboard.ts: -------------------------------------------------------------------------------- 1 | export async function copyToClipboard(content: string) { 2 | if ('clipboard' in navigator) { 3 | return await navigator.clipboard.writeText(content); 4 | } else { 5 | return document.execCommand('copy', true, content); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /helpers/dev.ts: -------------------------------------------------------------------------------- 1 | type DevConsoleFunctions = { 2 | log: (...message: string[]) => void; 3 | info: (...message: string[]) => void; 4 | warn: (...message: string[]) => void; 5 | error: (...message: string[]) => void; 6 | }; 7 | 8 | const DevConsole: DevConsoleFunctions = { 9 | log: (...message) => { 10 | if (process.env.NODE_ENV === 'production') return; 11 | console.log('[DEV]', ...message); 12 | }, 13 | info: (...message) => { 14 | if (process.env.NODE_ENV === 'production') return; 15 | console.info('[DEV INFO]', ...message); 16 | }, 17 | warn: (...message) => { 18 | if (process.env.NODE_ENV === 'production') return; 19 | console.warn('[DEV WARNING]', ...message); 20 | }, 21 | error: (...message) => { 22 | if (process.env.NODE_ENV === 'production') return; 23 | console.error('[DEV ERROR]', ...message); 24 | }, 25 | }; 26 | 27 | module.exports = { 28 | DevConsole, 29 | }; 30 | -------------------------------------------------------------------------------- /helpers/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /mdx-components.tsx: -------------------------------------------------------------------------------- 1 | import type { MDXComponents } from 'mdx/types'; 2 | 3 | export function useMDXComponents(components: MDXComponents): MDXComponents { 4 | return { 5 | ...components, 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | import remarkGfm from 'remark-gfm'; 2 | import createMDX from '@next/mdx'; 3 | 4 | /** @type {import('next').NextConfig} */ 5 | const nextConfig = { 6 | // Configure `pageExtensions`` to include MDX files 7 | pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'], 8 | // Optionally, add any other Next.js config below 9 | async redirects() { 10 | return [ 11 | { 12 | source: '/github', 13 | destination: 'https://github.com/with-tw/cookies', 14 | permanent: true, 15 | }, 16 | ]; 17 | }, 18 | }; 19 | 20 | const withMDX = createMDX({ 21 | // Add markdown plugins here, as desired 22 | options: { 23 | remarkPlugins: [remarkGfm], 24 | rehypePlugins: [], 25 | }, 26 | }); 27 | 28 | // Merge MDX config with Next.js config 29 | export default withMDX(nextConfig); 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cookies", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "prettier:check": "prettier --check --ignore-path .gitignore .", 11 | "prettier:fix": "prettier --write --ignore-path .gitignore .", 12 | "package:generate:setup-code": "ts-node generators/update-setup-code.ts", 13 | "package:generate:cookies-code": "ts-node generators/update-cookie-code.ts", 14 | "package:generate": "yarn package:generate:setup-code && yarn package:generate:cookies-code" 15 | }, 16 | "dependencies": { 17 | "@mdx-js/loader": "^3.0.1", 18 | "@mdx-js/react": "^3.0.1", 19 | "@next/mdx": "^14.1.1", 20 | "@radix-ui/react-accordion": "^1.1.2", 21 | "@radix-ui/react-toast": "^1.1.5", 22 | "@types/mdx": "^2.0.11", 23 | "clsx": "^2.1.0", 24 | "framer-motion": "^11.0.6", 25 | "geist": "^1.2.2", 26 | "lucide-react": "^0.341.0", 27 | "next": "14.1.0", 28 | "posthog-js": "^1.109.0", 29 | "prism-react-renderer": "^2.3.1", 30 | "react": "^18", 31 | "react-code-block": "^1.0.0", 32 | "react-dom": "^18", 33 | "remark-gfm": "^4.0.0", 34 | "tailwind-merge": "^2.2.1" 35 | }, 36 | "devDependencies": { 37 | "@types/node": "^20", 38 | "@types/react": "^18", 39 | "@types/react-dom": "^18", 40 | "@types/react-syntax-highlighter": "15.5.11", 41 | "autoprefixer": "^10.0.1", 42 | "eslint": "^8", 43 | "eslint-config-next": "14.1.0", 44 | "postcss": "^8", 45 | "prettier": "^3.2.5", 46 | "tailwindcss": "^3.3.0", 47 | "ts-node": "^10.9.2", 48 | "typescript": "^5" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /package/registry/README.md: -------------------------------------------------------------------------------- 1 | # Package for cookies 2 | 3 | Package as registry and setup-code for all the components and example cookies in JSON format. 4 | 5 | Checkout [generators](/generators) to see the generator code setup, all the generator functions run while commiting code changes. 6 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/logos/cookies-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/with-tw/cookies/1a7d0f2288f655f5ef3f670a5d699584e7bff7c5/public/logos/cookies-logo.png -------------------------------------------------------------------------------- /public/logos/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/logos/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/media/images/portrait-test-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/with-tw/cookies/1a7d0f2288f655f5ef3f670a5d699584e7bff7c5/public/media/images/portrait-test-image.jpg -------------------------------------------------------------------------------- /public/media/images/responsive-control-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/with-tw/cookies/1a7d0f2288f655f5ef3f670a5d699584e7bff7c5/public/media/images/responsive-control-banner.png -------------------------------------------------------------------------------- /public/media/images/responsive-control-banner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /services/posthog/provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { CURRENT_ENVIRONMENT, POSTHOG_HOST, POSTHOG_KEY } from '@/common/env'; 3 | import posthog from 'posthog-js'; 4 | import { PostHogProvider } from 'posthog-js/react'; 5 | import { ReactNode } from 'react'; 6 | 7 | if (typeof window !== 'undefined' && CURRENT_ENVIRONMENT === 'production') { 8 | posthog.init(POSTHOG_KEY, { 9 | api_host: POSTHOG_HOST, 10 | }); 11 | } 12 | 13 | export function CSPostHogProvider({ children }: { children: ReactNode }) { 14 | return {children}; 15 | } 16 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss'; 2 | 3 | const config: Config = { 4 | content: [ 5 | './pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: {}, 11 | }, 12 | plugins: [], 13 | }; 14 | export default config; 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./*"] 22 | } 23 | }, 24 | "include": [ 25 | "next-env.d.ts", 26 | "**/*.ts", 27 | "**/*.tsx", 28 | ".next/types/**/*.ts", 29 | "generators/update-setup-code.ts", 30 | "app/cookies/(cookies-docs)/empty-state/page.mdx" 31 | ], 32 | "exclude": ["node_modules"] 33 | } 34 | --------------------------------------------------------------------------------