├── .changeset ├── README.md └── config.json ├── .editorconfig ├── .eslintrc.js ├── .github └── workflows │ ├── code-check.yml │ └── release.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .npmrc ├── .prettierrc.js ├── README.md ├── apps └── web │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── content │ └── posts │ │ └── why-i-started-palettify-project.mdx │ ├── next-env.d.ts │ ├── next.config.js │ ├── package.json │ ├── postcss.config.js │ ├── public │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon.ico │ ├── images │ │ ├── features │ │ │ ├── next-js.svg │ │ │ ├── nextjs.png │ │ │ ├── seo.png │ │ │ └── stripe.png │ │ ├── illustration.png │ │ ├── logo.png │ │ ├── og-image.jpg │ │ ├── shadcn.svg │ │ └── thumbnail.jpg │ └── site.webmanifest │ ├── src │ ├── app │ │ ├── (app) │ │ │ ├── (auth) │ │ │ │ ├── layout.tsx │ │ │ │ └── login │ │ │ │ │ └── page.tsx │ │ │ ├── (dashboard) │ │ │ │ ├── account │ │ │ │ │ ├── loading.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── liked │ │ │ │ │ ├── loading.tsx │ │ │ │ │ └── page.tsx │ │ │ │ └── my-themes │ │ │ │ │ ├── loading.tsx │ │ │ │ │ └── page.tsx │ │ │ ├── (marketing) │ │ │ │ ├── _pricing │ │ │ │ │ ├── faq.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── pricing-plan.tsx │ │ │ │ │ ├── pricing-plans.tsx │ │ │ │ │ └── pricing.tsx │ │ │ │ ├── blog │ │ │ │ │ ├── [postSlug] │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── post-list-item.tsx │ │ │ │ │ ├── posts-explorer.tsx │ │ │ │ │ └── posts-list.tsx │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── playground │ │ │ │ ├── [themeId] │ │ │ │ │ ├── loading.tsx │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ └── themes │ │ │ │ ├── loading.tsx │ │ │ │ └── page.tsx │ │ ├── api │ │ │ ├── auth │ │ │ │ └── [...nextauth] │ │ │ │ │ └── route.ts │ │ │ └── webhooks │ │ │ │ └── stripe │ │ │ │ └── route.ts │ │ ├── layout.tsx │ │ ├── not-found.tsx │ │ └── providers.tsx │ ├── assets │ │ ├── fonts │ │ │ └── Acorn-Bold.woff2 │ │ └── images │ │ │ ├── companies │ │ │ ├── next-js.tsx │ │ │ ├── pioneer.tsx │ │ │ ├── prisma.tsx │ │ │ ├── vercel.tsx │ │ │ └── y-combinator.tsx │ │ │ └── logos │ │ │ ├── laravel.svg │ │ │ ├── mirage.svg │ │ │ ├── statamic.svg │ │ │ ├── statickit.svg │ │ │ ├── transistor.svg │ │ │ └── tuple.svg │ ├── components │ │ ├── banner.tsx │ │ ├── call-to-action.tsx │ │ ├── collect-emails-modal.tsx │ │ ├── features.tsx │ │ ├── footer │ │ │ ├── footer.tsx │ │ │ ├── index.ts │ │ │ └── wrapper.tsx │ │ ├── header │ │ │ ├── header.tsx │ │ │ └── index.ts │ │ ├── hero.tsx │ │ ├── layout │ │ │ ├── app-page-layout.tsx │ │ │ └── form-card-layout.tsx │ │ ├── mdx.tsx │ │ ├── sites-grid.tsx │ │ ├── tags-select.tsx │ │ ├── testimonials.tsx │ │ ├── theme-toggle.tsx │ │ └── user-menu.tsx │ ├── config │ │ ├── constants.ts │ │ ├── index.ts │ │ └── site-config.tsx │ ├── hooks │ │ ├── use-scroll-lock │ │ │ ├── index.ts │ │ │ └── use-scroll-lock.ts │ │ └── use-scroll.ts │ ├── lib │ │ ├── content.ts │ │ ├── posts.ts │ │ └── stripe.ts │ ├── middleware.ts │ ├── modules │ │ ├── auth │ │ │ ├── actions.ts │ │ │ ├── components │ │ │ │ ├── account-details.tsx │ │ │ │ ├── auth-login-error.tsx │ │ │ │ ├── email-login-button.tsx │ │ │ │ ├── github-login-button.tsx │ │ │ │ ├── google-login-button.tsx │ │ │ │ ├── login-modal.tsx │ │ │ │ ├── logout-button.tsx │ │ │ │ └── profile-avatar.tsx │ │ │ ├── config.ts │ │ │ ├── services.ts │ │ │ └── types.d.ts │ │ ├── email │ │ │ └── actions.ts │ │ ├── payment │ │ │ ├── actions.ts │ │ │ ├── components │ │ │ │ ├── invoices-list.tsx │ │ │ │ ├── pricing-plan-card.tsx │ │ │ │ ├── subscriptions-list.tsx │ │ │ │ └── upgrade-plan-modal.tsx │ │ │ └── services.ts │ │ ├── shadcn-ui │ │ │ └── ui │ │ │ │ ├── accordion.tsx │ │ │ │ ├── alert-dialog.tsx │ │ │ │ ├── alert.tsx │ │ │ │ ├── aspect-ratio.tsx │ │ │ │ ├── avatar.tsx │ │ │ │ ├── badge.tsx │ │ │ │ ├── button.tsx │ │ │ │ ├── calendar.tsx │ │ │ │ ├── card.tsx │ │ │ │ ├── carousel.tsx │ │ │ │ ├── checkbox.tsx │ │ │ │ ├── collapsible.tsx │ │ │ │ ├── command.tsx │ │ │ │ ├── context-menu.tsx │ │ │ │ ├── dialog.tsx │ │ │ │ ├── drawer.tsx │ │ │ │ ├── dropdown-menu.tsx │ │ │ │ ├── form.tsx │ │ │ │ ├── hover-card.tsx │ │ │ │ ├── input.tsx │ │ │ │ ├── label.tsx │ │ │ │ ├── menubar.tsx │ │ │ │ ├── navigation-menu.tsx │ │ │ │ ├── pagination.tsx │ │ │ │ ├── popover.tsx │ │ │ │ ├── progress.tsx │ │ │ │ ├── radio-group.tsx │ │ │ │ ├── resizable.tsx │ │ │ │ ├── scroll-area.tsx │ │ │ │ ├── select.tsx │ │ │ │ ├── separator.tsx │ │ │ │ ├── sheet.tsx │ │ │ │ ├── skeleton.tsx │ │ │ │ ├── slider.tsx │ │ │ │ ├── sonner.tsx │ │ │ │ ├── switch.tsx │ │ │ │ ├── table.tsx │ │ │ │ ├── tabs.tsx │ │ │ │ ├── textarea.tsx │ │ │ │ ├── toast.tsx │ │ │ │ ├── toaster.tsx │ │ │ │ ├── toggle-group.tsx │ │ │ │ ├── toggle.tsx │ │ │ │ ├── tooltip.tsx │ │ │ │ └── use-toast.ts │ │ ├── theme-previewer │ │ │ └── components │ │ │ │ ├── form-provider.tsx │ │ │ │ ├── preview │ │ │ │ ├── index.ts │ │ │ │ ├── library-preview.tsx │ │ │ │ ├── mui-preview │ │ │ │ │ └── mui-preview.tsx │ │ │ │ ├── preview.tsx │ │ │ │ └── shadcn-preview │ │ │ │ │ ├── dashboard │ │ │ │ │ ├── components │ │ │ │ │ │ ├── date-range-picker.tsx │ │ │ │ │ │ ├── main-nav.tsx │ │ │ │ │ │ ├── overview.tsx │ │ │ │ │ │ ├── recent-sales.tsx │ │ │ │ │ │ ├── search.tsx │ │ │ │ │ │ ├── team-switcher.tsx │ │ │ │ │ │ └── user-nav.tsx │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── dynamic-theme-wrapper.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── landing │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── registry.tsx │ │ │ │ │ └── shadcn-preview.tsx │ │ │ │ └── theme-form │ │ │ │ ├── color-input.tsx │ │ │ │ ├── copy-button.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── library-select.tsx │ │ │ │ ├── theme-form.tsx │ │ │ │ └── theme-select.tsx │ │ └── themes │ │ │ ├── actions.ts │ │ │ ├── components │ │ │ ├── create-theme-modal.tsx │ │ │ ├── theme-card-menu.tsx │ │ │ ├── theme-card.tsx │ │ │ └── themes-list.tsx │ │ │ ├── services.ts │ │ │ └── types.ts │ ├── styles │ │ ├── fonts.ts │ │ └── globals.css │ ├── types │ │ ├── index.d.ts │ │ └── post.d.ts │ └── utils │ │ └── index.ts │ ├── tailwind.config.ts │ ├── tsconfig.json │ └── tsconfig.tsbuildinfo ├── commitlint.config.js ├── images ├── demo.gif ├── hero.png ├── playground.jpg └── themes.jpg ├── package.json ├── packages ├── database │ ├── .eslintrc.js │ ├── .gitignore │ ├── package.json │ ├── prisma │ │ └── schema.prisma │ ├── src │ │ ├── client.ts │ │ ├── index.ts │ │ └── seed.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── eslint-config │ ├── CHANGELOG.md │ ├── README.md │ ├── basic.js │ ├── library.js │ ├── next.js │ ├── package.json │ └── react.js ├── tailwind-config │ ├── CHANGELOG.md │ ├── package.json │ └── tailwind.config.ts ├── ts-config │ ├── CHANGELOG.md │ ├── base.json │ ├── nextjs.json │ ├── package.json │ └── react-library.json ├── types │ ├── CHANGELOG.md │ ├── database.d.ts │ └── package.json ├── ui │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── components.json │ ├── package.json │ ├── postcss.config.js │ ├── src │ │ ├── components │ │ │ ├── accordion.tsx │ │ │ ├── alert.tsx │ │ │ ├── avatar.tsx │ │ │ ├── badge.tsx │ │ │ ├── button.tsx │ │ │ ├── card.tsx │ │ │ ├── carousel.tsx │ │ │ ├── command.tsx │ │ │ ├── dialog.tsx │ │ │ ├── form.tsx │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── loading-dots │ │ │ │ ├── index.ts │ │ │ │ ├── loading-dots.module.css │ │ │ │ └── loading-dots.tsx │ │ │ ├── menu.tsx │ │ │ ├── multi-select-freesolo.tsx │ │ │ ├── multi-select.tsx │ │ │ ├── popover.tsx │ │ │ ├── radio-group.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── separator.tsx │ │ │ ├── sheet.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── switch.tsx │ │ │ ├── table.tsx │ │ │ ├── tabs.tsx │ │ │ ├── textarea.tsx │ │ │ ├── toast.tsx │ │ │ ├── toaster.tsx │ │ │ ├── toggle.tsx │ │ │ └── tooltip.tsx │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── use-toast.ts │ │ ├── icons │ │ │ ├── checked-icon.tsx │ │ │ ├── google-icon.tsx │ │ │ ├── index.tsx │ │ │ └── npm-icon.tsx │ │ ├── index.tsx │ │ └── styles │ │ │ └── shared-globals.css │ ├── tailwind.config.ts │ └── tsconfig.json └── utils │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── package.json │ ├── src │ ├── array.ts │ ├── classes.ts │ ├── date.ts │ ├── fetcher.ts │ ├── index.ts │ ├── string-replace.ts │ └── tags.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── tsconfig.json ├── turbo.json └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require("@palettify/eslint-config/basic"); 2 | -------------------------------------------------------------------------------- /.github/workflows/code-check.yml: -------------------------------------------------------------------------------- 1 | name: code check 2 | on: 3 | push: 4 | branches: [dev, main] 5 | 6 | jobs: 7 | lint: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | 12 | - name: Install Node.js 13 | uses: actions/setup-node@v3 14 | with: 15 | node-version: 20.x 16 | 17 | - name: Install dependencies 18 | run: yarn install 19 | 20 | - name: Check linting 21 | run: yarn run lint 22 | 23 | format: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v3 27 | 28 | - name: Install Node.js 29 | uses: actions/setup-node@v3 30 | with: 31 | node-version: 20.x 32 | 33 | - name: Install dependencies 34 | run: yarn install 35 | 36 | - name: Check format 37 | run: yarn run format:check 38 | 39 | tsc: 40 | runs-on: ubuntu-latest 41 | steps: 42 | - uses: actions/checkout@v3 43 | 44 | - name: Install Node.js 45 | uses: actions/setup-node@v3 46 | with: 47 | node-version: 20.x 48 | 49 | - name: Install dependencies 50 | run: yarn install 51 | 52 | - name: Check types 53 | run: yarn run typecheck -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | concurrency: ${{ github.workflow }}-${{ github.ref }} 9 | 10 | jobs: 11 | release: 12 | name: Release 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout Repo 16 | uses: actions/checkout@v3 17 | 18 | - name: Setup Node.js 20.x 19 | uses: actions/setup-node@v3 20 | with: 21 | node-version: 20.x 22 | 23 | - name: Install Dependencies 24 | run: yarn 25 | 26 | # - name: Create Release Pull Request or Publish to npm 27 | # id: changesets 28 | # uses: changesets/action@v1 29 | # with: 30 | # publish: yarn release 31 | # env: 32 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /.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 | 8 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | .swc/ 16 | 17 | # misc 18 | .DS_Store 19 | *.pem 20 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # local env files 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | .env 32 | 33 | # turbo 34 | .turbo 35 | 36 | # ui 37 | dist/ 38 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit ${1} 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | singleQuote: false, 3 | bracketSpacing: true, 4 | jsxSingleQuote: false, 5 | bracketSameLine: false, 6 | trailingComma: "es5", 7 | semi: true, 8 | printWidth: 90, 9 | arrowParens: "always", 10 | endOfLine: "auto", 11 | importOrder: [ 12 | // Mocks must be at the top as they contain vi.mock calls 13 | "(.*)/__mocks__/(.*)", 14 | "^(react/(.*)$)|^(react$)", 15 | "^(next/(.*)$)|^(next$)", 16 | "", 17 | "^@(palettify)/(.*)$", 18 | "^(@/components/(.*)$)", 19 | "^(@/hooks/(.*)$)", 20 | "^(@/utils/(.*)$)", 21 | "^(@/lib/(.*)$)", 22 | "^(@/styles/(.*)$)", 23 | "^(@/assets/(.*)$)", 24 | "^(@/types/(.*)$)", 25 | "^(@/(.*)$)", 26 | "^~/(.*)$", 27 | "^[./]", 28 | ], 29 | importOrderSeparation: false, 30 | plugins: ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"], 31 | }; 32 | -------------------------------------------------------------------------------- /apps/web/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@palettify/eslint-config/basic"], 3 | }; 4 | -------------------------------------------------------------------------------- /apps/web/.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 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /apps/web/README.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | 3 | First, run the development server: 4 | 5 | ```bash 6 | yarn dev 7 | ``` 8 | 9 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 10 | 11 | You can start editing the page by modifying `src/app/page.tsx`. The page auto-updates as you edit the file. 12 | 13 | To create [API routes](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) add an `api/` directory to the `app/` directory with a `route.ts` file. For individual endpoints, create a subfolder in the `api` directory, like `api/hello/route.ts` would map to [http://localhost:3000/api/hello](http://localhost:3000/api/hello). 14 | 15 | ## Learn More 16 | 17 | To learn more about Next.js, take a look at the following resources: 18 | 19 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 20 | - [Learn Next.js](https://nextjs.org/learn/foundations/about-nextjs) - an interactive Next.js tutorial. 21 | 22 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 23 | 24 | ## Deploy on Vercel 25 | 26 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_source=github.com&utm_medium=referral&utm_campaign=turborepo-readme) from the creators of Next.js. 27 | 28 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 29 | -------------------------------------------------------------------------------- /apps/web/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /apps/web/next.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('next').NextConfig} 3 | */ 4 | module.exports = { 5 | images: { 6 | remotePatterns: [ 7 | { 8 | hostname: "github.com", 9 | }, 10 | { 11 | hostname: "avatars.githubusercontent.com", 12 | }, 13 | { 14 | hostname: "pbs.twimg.com", 15 | }, 16 | ], 17 | }, 18 | reactStrictMode: false, 19 | transpilePackages: ["@palettify/ui", "@palettify/utils", "@palettify/database"], 20 | }; 21 | -------------------------------------------------------------------------------- /apps/web/postcss.config.js: -------------------------------------------------------------------------------- 1 | // If you want to use other PostCSS plugins, see the following: 2 | // https://tailwindcss.com/docs/using-with-preprocessors 3 | 4 | module.exports = { 5 | plugins: { 6 | tailwindcss: {}, 7 | autoprefixer: {}, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /apps/web/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/web/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/favicon-16x16.png -------------------------------------------------------------------------------- /apps/web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/favicon.ico -------------------------------------------------------------------------------- /apps/web/public/images/features/next-js.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/web/public/images/features/nextjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/images/features/nextjs.png -------------------------------------------------------------------------------- /apps/web/public/images/features/seo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/images/features/seo.png -------------------------------------------------------------------------------- /apps/web/public/images/features/stripe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/images/features/stripe.png -------------------------------------------------------------------------------- /apps/web/public/images/illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/images/illustration.png -------------------------------------------------------------------------------- /apps/web/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/images/logo.png -------------------------------------------------------------------------------- /apps/web/public/images/og-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/images/og-image.jpg -------------------------------------------------------------------------------- /apps/web/public/images/shadcn.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/web/public/images/thumbnail.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mehdibha/palettify/606f4915845937344ce6725fedc780e97a02c6ac/apps/web/public/images/thumbnail.jpg -------------------------------------------------------------------------------- /apps/web/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-384x384.png", 12 | "sizes": "384x384", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(auth)/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | import { Metadata } from "next"; 3 | import Image from "next/image"; 4 | import { siteConfig } from "@/config"; 5 | 6 | export const metadata: Metadata = { 7 | title: "Login", 8 | }; 9 | 10 | export default function AuthLayout({ children }: { children: ReactNode }) { 11 | return ( 12 |
13 |
14 | {siteConfig.global.name} 21 |
{children}
22 |
23 |
24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(auth)/login/page.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from "react"; 2 | import { AuthLoginError } from "@/modules/auth/components/auth-login-error"; 3 | import { GithubLoginButton } from "@/modules/auth/components/github-login-button"; 4 | import { GoogleLoginButton } from "@/modules/auth/components/google-login-button"; 5 | 6 | export default function LoginPage() { 7 | return ( 8 |
9 |

Sign in

10 |

11 | Build incredible websites in seconds.
12 |

13 | 14 | 15 | 16 |
17 | 18 | 19 |
20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(dashboard)/account/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "@palettify/ui"; 2 | 3 | export default function Loading() { 4 | return ( 5 |
6 |

Account

7 |

8 | Manage your account settings and preferences 9 |

10 |
11 | {Array(3) 12 | .fill(null) 13 | .map((_, index) => ( 14 | 15 | ))} 16 |
17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(dashboard)/account/page.tsx: -------------------------------------------------------------------------------- 1 | import { AccountDetails } from "@/modules/auth/components/account-details"; 2 | import { getSession } from "@/modules/auth/services"; 3 | 4 | export default async function AccountPage() { 5 | const session = await getSession(); 6 | await new Promise((resolve) => setTimeout(resolve, 1000)); 7 | return ( 8 |
9 |

Account

10 |

11 | Manage your account settings and preferences 12 |

13 | 19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(dashboard)/layout.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import Link from "next/link"; 5 | import { usePathname } from "next/navigation"; 6 | import { Tabs, TabsList, TabsTrigger } from "@palettify/ui"; 7 | 8 | interface DashboardLayoutProps { 9 | children: React.ReactNode; 10 | } 11 | 12 | export default function DashboardLayout(props: DashboardLayoutProps) { 13 | const { children } = props; 14 | 15 | const pathname = usePathname(); 16 | 17 | return ( 18 | 19 | 20 | {[ 21 | { 22 | href: "/my-themes", 23 | label: "My themes", 24 | disabled: false, 25 | }, 26 | { 27 | href: "/liked", 28 | label: "Likes", 29 | disabled: false, 30 | }, 31 | { 32 | href: "/account", 33 | label: "Account", 34 | disabled: false, 35 | }, 36 | ].map((link) => ( 37 | 44 | {link.disabled ? link.label : {link.label}} 45 | 46 | ))} 47 | 48 |
{children}
49 |
50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(dashboard)/liked/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "@palettify/ui"; 2 | 3 | export default function Loading() { 4 | return ( 5 |
6 |

Liked themes

7 |

8 | Here you can find all the themes you liked 9 |

10 |
11 |
12 | 13 |
14 |
15 | {Array(10) 16 | .fill(null) 17 | .map((_, index) => ( 18 | 19 | ))} 20 |
21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(dashboard)/liked/page.tsx: -------------------------------------------------------------------------------- 1 | import { ThemesList } from "@/modules/themes/components/themes-list"; 2 | import { getUserLikedThemes, getUserLikes } from "@/modules/themes/services"; 3 | 4 | export default async function Page() { 5 | const userLikedThemes = await getUserLikedThemes(); 6 | const userLikes = await getUserLikes(); 7 | 8 | return ( 9 |
10 |

Liked themes

11 |

12 | Here you can find all the themes you liked 13 |

14 | 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(dashboard)/my-themes/loading.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "@palettify/ui"; 2 | 3 | export default function Loading() { 4 | return ( 5 |
6 |

My themes

7 |

8 | Here you can find all the themes you created 9 |

10 |
11 |
12 | 13 |
14 |
15 | {Array(10) 16 | .fill(null) 17 | .map((_, index) => ( 18 | 19 | ))} 20 |
21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(dashboard)/my-themes/page.tsx: -------------------------------------------------------------------------------- 1 | import { ThemesList } from "@/modules/themes/components/themes-list"; 2 | import { getUserLikes, getUserThemes } from "@/modules/themes/services"; 3 | import { Features } from "@/modules/themes/types"; 4 | 5 | export default async function Page() { 6 | const userThemes = await getUserThemes(); 7 | const userLikes = await getUserLikes(); 8 | 9 | return ( 10 |
11 |

My themes

12 |

13 | Here you can find all the themes you created 14 |

15 | 20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/_pricing/faq.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | Accordion, 4 | AccordionContent, 5 | AccordionItem, 6 | AccordionTrigger, 7 | } from "@palettify/ui"; 8 | import { siteConfig } from "@/config"; 9 | 10 | const config = siteConfig.pricingPage; 11 | const questions = config.faq; 12 | 13 | export const FAQ = () => { 14 | return ( 15 |
16 |

17 | Frequently asked questions 18 |

19 |
20 | 21 | {questions.map((elem, index) => ( 22 | 23 | 24 | {elem.question} 25 | 26 | {elem.answer} 27 | 28 | ))} 29 | 30 |
31 |
32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/_pricing/page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import type { Metadata } from "next"; 3 | import { CallToAction } from "@/components/call-to-action"; 4 | import { siteConfig } from "@/config"; 5 | import { FAQ } from "./faq"; 6 | import { Pricing } from "./pricing"; 7 | 8 | const config = siteConfig.pricingPage; 9 | 10 | export const metadata: Metadata = { 11 | title: "palettify pricing plans: Free, Personal, Pro", 12 | }; 13 | 14 | export default function PricingPage() { 15 | return ( 16 |
17 | 18 | 19 | 26 |
27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/_pricing/pricing-plan.tsx: -------------------------------------------------------------------------------- 1 | import { Button, CheckCircleIcon } from "@palettify/ui"; 2 | import { cn } from "@palettify/utils"; 3 | 4 | interface PlanProps { 5 | name: string; 6 | price: string; 7 | billing?: string; 8 | description: string; 9 | href: string; 10 | features: string[]; 11 | featured?: boolean; 12 | className: string; 13 | } 14 | 15 | export const PricingPlan = (props: PlanProps) => { 16 | const { 17 | name, 18 | price, 19 | billing, 20 | description, 21 | href, 22 | features, 23 | featured = false, 24 | className, 25 | } = props; 26 | 27 | return ( 28 |
35 | {featured && ( 36 |
37 | Most popular 38 |
39 | )} 40 |

{name}

41 |

{description}

42 |

43 | {price} 44 | {billing && ( 45 | 46 | {billing} 47 | 48 | )} 49 |

50 |
    56 | {features.map((feature) => ( 57 |
  • 58 | 59 | {feature} 60 |
  • 61 | ))} 62 |
63 | 72 |
73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/_pricing/pricing.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { PricingPlans } from "./pricing-plans"; 5 | 6 | export const Pricing = () => { 7 | const [billingInterval, setBillingInterval] = React.useState<"monthly" | "yearly">( 8 | "monthly" 9 | ); 10 | const handleBillingIntervalChange = (billingInterval: "monthly" | "yearly") => { 11 | setBillingInterval(billingInterval); 12 | }; 13 | return ( 14 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/blog/[postSlug]/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Metadata } from "next"; 3 | import { notFound } from "next/navigation"; 4 | import { CallToAction } from "@/components/call-to-action"; 5 | import { getAllPosts, getPostBySlug } from "@/lib/posts"; 6 | import { siteConfig } from "@/config"; 7 | 8 | interface PostLayoutProps { 9 | params: { 10 | postSlug: string; 11 | }; 12 | children: React.ReactNode; 13 | } 14 | 15 | const config = siteConfig.pricingPage; 16 | 17 | export async function generateMetadata({ params }: PostLayoutProps): Promise { 18 | const post = getPostBySlug(params.postSlug); 19 | if (!post) { 20 | notFound(); 21 | } 22 | return { 23 | title: post.metadata.title, 24 | description: post.metadata.summary, 25 | keywords: post.metadata.keywords, 26 | openGraph: { 27 | title: post.metadata.title, 28 | description: post.metadata.summary, 29 | images: post.metadata.thumbnail ? [post.metadata.thumbnail] : undefined, 30 | }, 31 | }; 32 | } 33 | 34 | export async function generateStaticParams() { 35 | const posts = getAllPosts(); 36 | 37 | return posts.map((post) => ({ 38 | postSlug: post.slug, 39 | })); 40 | } 41 | 42 | const PostLayout = (props: PostLayoutProps) => { 43 | const { children } = props; 44 | return ( 45 |
46 | {children} 47 | 54 |
55 | ); 56 | }; 57 | 58 | export default PostLayout; 59 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/blog/[postSlug]/page.tsx: -------------------------------------------------------------------------------- 1 | import { notFound } from "next/navigation"; 2 | import { Badge } from "@palettify/ui"; 3 | import { formatDate } from "@palettify/utils"; 4 | import { MDX } from "@/components/mdx"; 5 | import { getPostBySlug } from "@/lib/posts"; 6 | 7 | interface PostPageProps { 8 | params: { 9 | postSlug: string; 10 | }; 11 | } 12 | 13 | export default async function PostPage(props: PostPageProps) { 14 | const { params } = props; 15 | const post = getPostBySlug(params.postSlug); 16 | 17 | if (!post) { 18 | notFound(); 19 | } 20 | 21 | return ( 22 |
23 |

24 | {post.metadata.title} 25 |

26 |
27 |

Published in {formatDate(post.metadata.publishedAt)}

28 | 29 |

{post.timeToRead} min read

30 | 31 | {post.metadata.keywords && 32 | post.metadata.keywords.map((tag) => {tag})} 33 |
34 |
35 | {post.content && } 36 |
37 |
38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/blog/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from "next"; 2 | import { getAllPosts } from "@/lib/posts"; 3 | // import { getBlogPosts } from "@/lib/blog"; 4 | import { siteConfig } from "@/config"; 5 | import { PostsExplorer } from "./posts-explorer"; 6 | 7 | const config = siteConfig.blogPage; 8 | 9 | export const metadata: Metadata = { 10 | title: "Blog", 11 | }; 12 | 13 | export default async function BlogPage() { 14 | const posts = getAllPosts(); 15 | 16 | return ( 17 |
18 |

19 | {config.headline} 20 |

21 |

{config.subheadline}

22 | 23 |
24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/blog/posts-explorer.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import React from "react"; 4 | import { getAllTags } from "@palettify/utils"; 5 | import { TagsSelect } from "@/components/tags-select"; 6 | import { Post } from "@/types"; 7 | import { PostsList } from "./posts-list"; 8 | 9 | interface PostsExplorerProps { 10 | posts: Post[]; 11 | className?: string; 12 | } 13 | 14 | export const PostsExplorer = (props: PostsExplorerProps) => { 15 | const { posts, className } = props; 16 | 17 | const tags = getAllTags(posts.map((post) => ({ tags: post.metadata.keywords }))); 18 | const [selectedTags, setSelectedTags] = React.useState([]); 19 | 20 | const handleTagClick = (tag: string) => { 21 | const selected = selectedTags.findIndex((elem) => elem === tag) > -1; 22 | if (selected) { 23 | setSelectedTags(selectedTags.filter((elem) => elem !== tag)); 24 | } else { 25 | setSelectedTags([...selectedTags, tag]); 26 | } 27 | }; 28 | 29 | const filteredPosts = React.useMemo(() => { 30 | return posts.filter((post: Post) => { 31 | let matchesTags = post.metadata.keywords 32 | ? post.metadata.keywords.some((tag) => selectedTags.includes(tag)) 33 | : false; 34 | if (selectedTags.length === 0) matchesTags = true; 35 | return matchesTags; 36 | }); 37 | // eslint-disable-next-line react-hooks/exhaustive-deps 38 | }, [selectedTags]); 39 | 40 | return ( 41 |
42 |

Search blog by topics

43 | 49 | {filteredPosts && } 50 |
51 | ); 52 | }; 53 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/blog/posts-list.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Post } from "@/types"; 3 | import { PostListItem } from "./post-list-item"; 4 | 5 | interface PostsListProps { 6 | posts: Post[]; 7 | } 8 | 9 | export const PostsList = (props: PostsListProps) => { 10 | const { posts } = props; 11 | return ( 12 |
    13 | {posts.map((post) => ( 14 | 24 | ))} 25 |
26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/(marketing)/page.tsx: -------------------------------------------------------------------------------- 1 | import { CallToAction } from "@/components/call-to-action"; 2 | import { Features } from "@/components/features"; 3 | import { Hero } from "@/components/hero"; 4 | import { Testimonials } from "@/components/testimonials"; 5 | import { siteConfig } from "@/config"; 6 | 7 | export default function HomePage() { 8 | return ( 9 |
10 | 16 | 21 | 26 | 33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /apps/web/src/app/(app)/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Footer } from "@/components/footer"; 3 | import { Header } from "@/components/header"; 4 | 5 | export default function Appayout({ children }: { children: React.ReactNode }) { 6 | return ( 7 | <> 8 |
9 |
{children}
10 |