├── .husky
├── .gitignore
├── pre-commit
└── pre-push
├── __tests__
├── styleMock.js
├── stubs
│ ├── index.js
│ ├── useStubs.ts
│ ├── buildUser.js
│ └── utils.js
├── mocks
│ ├── index.js
│ ├── browser.js
│ ├── server.js
│ ├── handlers
│ │ ├── index.js
│ │ ├── graphql
│ │ │ └── query_users_me.js
│ │ ├── rest
│ │ │ └── mswping.js
│ │ └── storage.js
│ └── MswProvider.tsx
├── chance.js
├── test-utils.js
└── components
│ └── SanityCheck.test.js
├── src
├── styles
│ ├── globals.css
│ ├── tailwind.css
│ ├── antd.less
│ ├── tailwind-antd-compat.less
│ └── Home.module.css
├── components
│ ├── LinkPreview
│ │ ├── index.tsx
│ │ ├── controller.tsx
│ │ └── elements.tsx
│ ├── _preview
│ │ ├── containers
│ │ │ ├── StripePreview
│ │ │ │ ├── index.tsx
│ │ │ │ ├── controller.tsx
│ │ │ │ └── elements.tsx
│ │ │ ├── VercelPreview
│ │ │ │ ├── style.module.css
│ │ │ │ └── index.tsx
│ │ │ ├── TailwindPreview.tsx
│ │ │ ├── BaseWebPreview
│ │ │ │ ├── Rating.tsx
│ │ │ │ ├── PinCode.tsx
│ │ │ │ ├── DragAndDrop.tsx
│ │ │ │ ├── Select.tsx
│ │ │ │ ├── Menu.tsx
│ │ │ │ ├── PaymentCard.tsx
│ │ │ │ ├── ProgressBar.tsx
│ │ │ │ ├── DatePicker.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── FileUploader.tsx
│ │ │ ├── AntdPreview
│ │ │ │ ├── Progress.tsx
│ │ │ │ ├── ProgressCircle.tsx
│ │ │ │ ├── Buttons.tsx
│ │ │ │ ├── ModalBasic.tsx
│ │ │ │ ├── CardWithLoading.tsx
│ │ │ │ ├── Badge.tsx
│ │ │ │ ├── Collapse.tsx
│ │ │ │ ├── ProgressWithCustomStroke.tsx
│ │ │ │ ├── SwitchablePicker.tsx
│ │ │ │ ├── DatePickerSize.tsx
│ │ │ │ ├── ModalDialog.tsx
│ │ │ │ ├── Tabs.tsx
│ │ │ │ ├── Carousel.tsx
│ │ │ │ ├── Drawer.tsx
│ │ │ │ ├── ModalWithFooter.tsx
│ │ │ │ ├── DynamicBadge.tsx
│ │ │ │ ├── AvatarGroup.tsx
│ │ │ │ ├── TabsCloseable.tsx
│ │ │ │ ├── Calendar.tsx
│ │ │ │ ├── ModalDraggable.tsx
│ │ │ │ ├── Table.tsx
│ │ │ │ ├── Popconfirm.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── LottiePreview.tsx
│ │ │ ├── ContentPlaceholder.tsx
│ │ │ ├── Grid.tsx
│ │ │ └── TransitionsPreview.tsx
│ │ ├── getGithubUrl.ts
│ │ ├── components.tsx
│ │ ├── index.tsx
│ │ └── DisGui.tsx
│ ├── base
│ │ ├── transitions
│ │ │ ├── types.tsx
│ │ │ ├── FadeIn.tsx
│ │ │ ├── Rotate90.tsx
│ │ │ ├── SlideOver.tsx
│ │ │ ├── FadeInScale.tsx
│ │ │ ├── Collapse.tsx
│ │ │ ├── PopOut.tsx
│ │ │ └── SlideDown.tsx
│ │ ├── Error404.tsx
│ │ ├── lazyload.tsx
│ │ ├── FullPageContainer.tsx
│ │ ├── ErrorFallback.tsx
│ │ ├── ErrorBoundary.tsx
│ │ └── DotsLoader.tsx
│ ├── SendFeedback.tsx
│ ├── SEO.tsx
│ └── ToggleDarkMode.tsx
├── lib
│ ├── github
│ │ └── getGithubUrl.ts
│ ├── date
│ │ └── dateFromSecond.ts
│ ├── parseUrls.ts
│ ├── unfurl
│ │ └── getMetadata.ts
│ ├── stripe
│ │ ├── init.ts
│ │ └── formatAmountForStripe.ts
│ ├── analytic
│ │ ├── nextjs-hook.ts
│ │ └── index.ts
│ └── logger.ts
├── config
│ ├── app.ts
│ ├── seo.ts
│ └── analytic.ts
├── hooks
│ └── useDarkMode.ts
├── utils
│ └── trackGoal.ts
└── services
│ └── stripe-webhook
│ ├── mock-db.ts
│ └── index.ts
├── .vercelignore
├── docs
├── buildsize.jpeg
└── lighthouse-report.jpg
├── public
├── favicon.ico
├── og-default.jpg
├── vercel.svg
└── darkmode-noflash.js
├── next-env.d.ts
├── pages
├── _preview
│ ├── [component].tsx
│ └── StripePreview.tsx
├── api
│ ├── hello.js
│ ├── stripe
│ │ ├── [...nextstripe].js
│ │ ├── checkPayment.ts
│ │ └── getCustomerPlans.ts
│ ├── unfurl.ts
│ └── webhook
│ │ └── stripe.js
├── _app.tsx
├── robots.txt.tsx
├── _document.tsx
└── index.tsx
├── .prettierrc
├── postcss.config.js
├── checkly
├── snippets
│ ├── viewports_desktop.js
│ ├── viewports_mobile.js
│ ├── wait.js
│ ├── publicPages.js
│ ├── takeScreenshots.js
│ └── takeScreenshot.js
└── visual_tests
│ └── public_pages.js
├── .github
├── test_checker.yml
├── stale.yml
└── config.yml
├── .lintstagedrc
├── .babelrc
├── .vscode
├── settings.sample.json
└── extensions.json
├── apollo.config.js
├── tailwind.config.js
├── .gitignore
├── jest.setup.js
├── jest.config.js
├── tsconfig.json
├── .env
├── next.config.js
├── README.md
├── next-handlers.js
└── package.json
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/__tests__/styleMock.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | @import './tailwind.css';
2 |
--------------------------------------------------------------------------------
/.vercelignore:
--------------------------------------------------------------------------------
1 | checkly
2 |
3 | # Ignore test files
4 | jest*
5 | __tests__/pages
--------------------------------------------------------------------------------
/__tests__/stubs/index.js:
--------------------------------------------------------------------------------
1 | export * from './buildUser';
2 | export * from './utils';
3 |
--------------------------------------------------------------------------------
/docs/buildsize.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wzulfikar/nextjs-10/HEAD/docs/buildsize.jpeg
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wzulfikar/nextjs-10/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | yarn husky:pre-commit
5 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/public/og-default.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wzulfikar/nextjs-10/HEAD/public/og-default.jpg
--------------------------------------------------------------------------------
/docs/lighthouse-report.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wzulfikar/nextjs-10/HEAD/docs/lighthouse-report.jpg
--------------------------------------------------------------------------------
/pages/_preview/[component].tsx:
--------------------------------------------------------------------------------
1 | import Preview from '@src/components/_preview';
2 |
3 | export default Preview;
4 |
--------------------------------------------------------------------------------
/src/components/LinkPreview/index.tsx:
--------------------------------------------------------------------------------
1 | import controller from './controller';
2 |
3 | export default controller;
4 |
--------------------------------------------------------------------------------
/src/components/_preview/containers/StripePreview/index.tsx:
--------------------------------------------------------------------------------
1 | import controller from './controller';
2 |
3 | export default controller;
4 |
--------------------------------------------------------------------------------
/.husky/pre-push:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | # Make sure all codes are type-checked before pushing
5 | yarn husky:pre-push
6 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true,
6 | "printWidth": 80
7 | }
--------------------------------------------------------------------------------
/src/components/_preview/containers/VercelPreview/style.module.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@900&display=swap');
2 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | "@tailwindcss/jit": {},
4 | autoprefixer: {},
5 | "postcss-preset-env": {},
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/__tests__/mocks/index.js:
--------------------------------------------------------------------------------
1 | if (typeof window === 'undefined') {
2 | require('./server').default.listen();
3 | } else {
4 | require('./browser').default.start();
5 | }
6 |
--------------------------------------------------------------------------------
/__tests__/mocks/browser.js:
--------------------------------------------------------------------------------
1 | import { setupWorker } from 'msw';
2 | import handlers from './handlers';
3 |
4 | const worker = setupWorker(...handlers);
5 |
6 | export default worker;
7 |
--------------------------------------------------------------------------------
/checkly/snippets/viewports_desktop.js:
--------------------------------------------------------------------------------
1 | const viewports = [{ width: 1280, height: 1280 }];
2 |
3 | // [CHECKLY] Omit these lines when adding to checkly
4 | module.exports = viewports;
5 |
--------------------------------------------------------------------------------
/src/lib/github/getGithubUrl.ts:
--------------------------------------------------------------------------------
1 | export default function getGithubUrl({ owner, repo, branch, file }) {
2 | return `https://github.com/${owner}/${repo}/blob/${branch}/${file}`;
3 | }
4 |
--------------------------------------------------------------------------------
/__tests__/mocks/server.js:
--------------------------------------------------------------------------------
1 | import { setupServer } from 'msw/node';
2 | import handlers from './handlers';
3 |
4 | const server = setupServer(...handlers);
5 |
6 | export default server;
7 |
--------------------------------------------------------------------------------
/pages/api/hello.js:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | export default (req, res) => {
4 | res.status(200).json({ name: 'John Doe' })
5 | }
6 |
--------------------------------------------------------------------------------
/checkly/snippets/viewports_mobile.js:
--------------------------------------------------------------------------------
1 | const viewports = [{ width: 375, height: 812 }]; // iPhone 11 Pro
2 |
3 | // [CHECKLY] Omit these lines when adding to checkly
4 | module.exports = viewports;
5 |
--------------------------------------------------------------------------------
/src/config/app.ts:
--------------------------------------------------------------------------------
1 | export const appName = process.env.NEXT_PUBLIC_APP_NAME;
2 | export const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
3 |
4 | export default {
5 | appName,
6 | baseUrl,
7 | };
8 |
--------------------------------------------------------------------------------
/__tests__/mocks/handlers/index.js:
--------------------------------------------------------------------------------
1 | export default [
2 | /* GraphQL handlers */
3 | require('./graphql/query_users_me').handler,
4 |
5 | /* REST handlers */
6 | require('./rest/mswping').handler,
7 | ];
8 |
--------------------------------------------------------------------------------
/__tests__/chance.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Wrapper for chance.js
3 | */
4 |
5 | import Chance from 'chance';
6 |
7 | const seed = '123123';
8 | const chance = new Chance(seed);
9 |
10 | export default chance;
11 |
--------------------------------------------------------------------------------
/src/lib/date/dateFromSecond.ts:
--------------------------------------------------------------------------------
1 | export default function dateFromSecond(secs: number): Date {
2 | const t = new Date('1970-01-01T00:30:00Z'); // Unix epoch start.
3 | t.setSeconds(secs);
4 | return t;
5 | }
6 |
--------------------------------------------------------------------------------
/checkly/snippets/wait.js:
--------------------------------------------------------------------------------
1 | const wait = (time) =>
2 | new Promise(function (resolve) {
3 | setTimeout(resolve, time);
4 | });
5 |
6 | // [CHECKLY] Omit these lines when adding to checkly
7 | module.exports = wait;
8 |
--------------------------------------------------------------------------------
/src/components/base/transitions/types.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react';
2 |
3 | export type TransitionProps = {
4 | show: boolean;
5 | appear?: boolean;
6 | duration?: string;
7 | children: ReactNode;
8 | };
9 |
--------------------------------------------------------------------------------
/.github/test_checker.yml:
--------------------------------------------------------------------------------
1 | # See docs: https://github.com/infection/tests-checker
2 | comment: "Hello! Please consider adding a test to make sure this change works as expected."
3 | fileExtensions: [".ts", ".js", ".tsx", ".jsx"]
4 | testDir: "__tests__"
5 |
--------------------------------------------------------------------------------
/src/hooks/useDarkMode.ts:
--------------------------------------------------------------------------------
1 | import _useDarkMode from 'use-dark-mode';
2 |
3 | export default function useDarkMode(initialValue: boolean) {
4 | return _useDarkMode(initialValue, {
5 | classNameDark: 'dark',
6 | classNameLight: 'light',
7 | });
8 | }
9 |
--------------------------------------------------------------------------------
/checkly/snippets/publicPages.js:
--------------------------------------------------------------------------------
1 | const publicPages = [
2 | '/',
3 | '/signup',
4 | '/login',
5 | '/blog',
6 | '/legal/privacy-policy',
7 | '/help',
8 | '/features',
9 | ];
10 |
11 | // [CHECKLY] Omit below lines when adding to checkly
12 | module.exports = publicPages;
13 |
--------------------------------------------------------------------------------
/pages/api/stripe/[...nextstripe].js:
--------------------------------------------------------------------------------
1 | import NextStripe from 'next-stripe';
2 |
3 | /**
4 | * Run this command to see what routes are handled by next-stripe:
5 | * `ls -1 node_modules/next-stripe/dist/server/routes`
6 | */
7 | export default NextStripe({
8 | stripe_key: process.env.STRIPE_RESTRICTED_KEY,
9 | });
10 |
--------------------------------------------------------------------------------
/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "src/**/*.{js,jsx,ts,tsx,json,css}": [
3 | "prettier --write"
4 | ],
5 | "__tests__/**/*.{js,ts,json}": [
6 | "prettier --write"
7 | ],
8 | "pages/**/*.{js,ts,jsx,tsx}": [
9 | "prettier --write"
10 | ],
11 | "checkly/**/*.{js}": [
12 | "prettier --write"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/__tests__/mocks/handlers/graphql/query_users_me.js:
--------------------------------------------------------------------------------
1 | import { graphql } from 'msw';
2 | import { buildUser } from '@tests/stubs';
3 |
4 | const user = buildUser();
5 |
6 | const stub = {
7 | user: user,
8 | };
9 |
10 | export const handler = graphql.query('users_me', (req, res, ctx) => {
11 | return res(ctx.data(stub));
12 | });
13 |
--------------------------------------------------------------------------------
/src/lib/parseUrls.ts:
--------------------------------------------------------------------------------
1 | import linkifyIt from 'linkify-it';
2 |
3 | let linkify = null;
4 |
5 | /**
6 | * Parse http(s) urls from text
7 | */
8 | export default function parseUrls(text: string): linkifyIt.Match[] | null {
9 | if (!linkify) linkify = linkifyIt();
10 |
11 | return linkify.match(text)?.filter(({ url }) => url.startsWith('http'));
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/_preview/containers/TailwindPreview.tsx:
--------------------------------------------------------------------------------
1 | export default function TailwindPreview() {
2 | return (
3 |
4 |
5 | Hello from Tailwind v2!
6 |
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "next/babel"
4 | ],
5 | "plugins": [
6 | [
7 | "import",
8 | {
9 | "libraryName": "antd"
10 | }
11 | ]
12 | ],
13 | "env": {
14 | "test": {
15 | "plugins": [
16 | "dynamic-import-node"
17 | ]
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/.vscode/settings.sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.exclude": {
3 | ".next": true,
4 | ".build": true,
5 | "node_modules": true
6 | },
7 | "jest.autoEnable": false,
8 | "githubIssues.issueBranchTitle": "${user}/issue-${issueNumber}",
9 | "githubIssues.workingIssueFormatScm": "${issueTitle}. ${issueNumberLabel}",
10 | "githubPullRequests.telemetry.enabled": false
11 | }
--------------------------------------------------------------------------------
/apollo.config.js:
--------------------------------------------------------------------------------
1 | if (!process.env.APOLLO_KEY) {
2 | throw new Error(
3 | 'Environment error: could not load `APOLLO_KEY` from `.env.local` file.'
4 | );
5 | }
6 |
7 | module.exports = {
8 | client: {
9 | service: {
10 | name: process.env.NEXT_PUBLIC_APOLLO_SERVICE,
11 | url: process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT,
12 | },
13 | includes: ['./src/**/*.ts'],
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/src/components/base/Error404.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import Error from 'next/error';
3 |
4 | import logger from '@src/lib/logger';
5 |
6 | /**
7 | * `Error404` renders a full page 404 error message and logs the request.
8 | */
9 | export default function Error404() {
10 | useEffect(() => {
11 | logger.info('page not found:', window.location.href);
12 | }, []);
13 |
14 | return ;
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/base/lazyload.tsx:
--------------------------------------------------------------------------------
1 | import dynamic from 'next/dynamic';
2 |
3 | import DotsLoader from './DotsLoader';
4 |
5 | /**
6 | * `lazyload` wraps next/dynamic with common defaults for our app context.
7 | */
8 | const lazyload: typeof dynamic = (
9 | component,
10 | { ssr = true, loading = () => } = {}
11 | ) =>
12 | dynamic(component, {
13 | loading,
14 | ssr,
15 | });
16 |
17 | export default lazyload;
18 |
--------------------------------------------------------------------------------
/src/utils/trackGoal.ts:
--------------------------------------------------------------------------------
1 | import { events } from '@src/config/analytic';
2 | import { trackGoal as _trackGoal } from '@src/lib/analytic';
3 |
4 | export default function trackGoal(
5 | event: keyof typeof events,
6 | centValue?: number
7 | ) {
8 | if (process.env.NODE_ENV === 'production') {
9 | _trackGoal({ ...events[event], centValue });
10 | } else {
11 | console.log('[dev][analytic] trackGoal:', events[event]);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/lib/unfurl/getMetadata.ts:
--------------------------------------------------------------------------------
1 | type MetadataResponse = {
2 | metadata?: any;
3 | error?: any;
4 | };
5 |
6 | export default async function getMetadata(
7 | unfurlEndpoint: string,
8 | targetUrl: string
9 | ): Promise {
10 | return fetch(`${unfurlEndpoint}?url=${encodeURI(targetUrl)}`)
11 | .then(async (res) => ({ metadata: await res.json() }))
12 | .catch((e) => ({ error: '[unfurl] getMetadata failed: ' + e.message }));
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/_preview/containers/BaseWebPreview/Rating.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {StarRating} from 'baseui/rating';
3 |
4 | RatingDemo.title ="Rating"
5 | RatingDemo.url ="https://v9-9-0.baseweb.design/components/rating"
6 |
7 | export default function RatingDemo() {
8 | const [value, setValue] = React.useState(1);
9 | return (
10 | setValue(value)}
13 | />
14 | );
15 | };
--------------------------------------------------------------------------------
/src/components/_preview/containers/BaseWebPreview/PinCode.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { PinCode } from 'baseui/pin-code';
3 |
4 | PinCodeDemo.title = 'PinCode';
5 | PinCodeDemo.url = 'https://v9-9-0.baseweb.design/components/pin-code';
6 |
7 | export default function PinCodeDemo() {
8 | const [values, setValues] = React.useState(['', '', '', '']);
9 | return (
10 | setValues(values)} />
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/__tests__/mocks/handlers/rest/mswping.js:
--------------------------------------------------------------------------------
1 | import { rest } from 'msw';
2 |
3 | /**
4 | * /mswping is a handler to verify that msw is actually running.
5 | * To test, run this code in your browser console:
6 | *
7 | * `fetch('/mswping').then(res => res.json()).then(console.log).catch(console.log)`
8 | */
9 | export const handler = rest.get('/mswping', (req, res, ctx) => {
10 | return res(
11 | ctx.json({
12 | ok: true,
13 | msg: 'msw is running!',
14 | })
15 | );
16 | });
17 |
--------------------------------------------------------------------------------
/__tests__/mocks/handlers/storage.js:
--------------------------------------------------------------------------------
1 | let storage = {};
2 |
3 | function put(key, fn) {
4 | if (!process.browser) return;
5 |
6 | const data = fn(get(key));
7 |
8 | console.log('[msw] storage.put:', key, data);
9 |
10 | storage[key] = data;
11 | }
12 |
13 | function get(key) {
14 | if (!process.browser) return;
15 |
16 | console.log('[msw] storage.get:', key, storage[key]);
17 |
18 | return storage[key];
19 | }
20 |
21 | module.exports.get = get;
22 | module.exports.put = put;
23 |
--------------------------------------------------------------------------------
/__tests__/test-utils.js:
--------------------------------------------------------------------------------
1 | import { render } from '@testing-library/react';
2 |
3 | // Add in any providers here if necessary:
4 | // (ReduxProvider, ThemeProvider, etc)
5 | const Providers = ({ children }) => {
6 | return children;
7 | };
8 |
9 | const customRender = (ui, options = {}) =>
10 | render(ui, { wrapper: Providers, ...options });
11 |
12 | // re-export everything
13 | export * from '@testing-library/react';
14 |
15 | // override render method
16 | export { customRender as render };
17 |
--------------------------------------------------------------------------------
/src/components/base/FullPageContainer.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Get css class for FullPageContainer.
3 | * By default, `bgColor` is not specified.
4 | */
5 | export const className = ({ bgColor = '' } = {} as any) =>
6 | `${bgColor} h-screen flex flex-col xy-center`;
7 |
8 | export default function FullPageContainer({
9 | bgColor = undefined,
10 | children,
11 | ...props
12 | }) {
13 | return (
14 |
15 | {children}
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | // NOTE: somehow the styles won't be applied if using `import`
2 | require('@src/styles/globals.css');
3 |
4 | import { DefaultSeo } from 'next-seo';
5 |
6 | import useAnalytic from '@src/lib/analytic/nextjs-hook';
7 | import seoConfig from '@src/config/seo';
8 |
9 | function MyApp({ Component, pageProps }) {
10 | useAnalytic();
11 |
12 | return (
13 | <>
14 |
15 |
16 | >
17 | );
18 | }
19 |
20 | export default MyApp;
21 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | purge: [
3 | "./pages/**/*.{js,jsx,ts,tsx}",
4 | "./src/**/*.{js,jsx,ts,tsx}"
5 | ],
6 | darkMode: 'class',
7 | theme: {},
8 | corePlugins: {
9 | // If tailwind conflicts with your existing styles, try set `preflight`
10 | // to false to disable tailwind css reset.
11 | // See: https://tailwindcss.com/docs/preflight#disabling-preflight
12 | preflight: true,
13 | },
14 | plugins: [
15 | require('@tailwindcss/line-clamp'),
16 | ]
17 | };
18 |
--------------------------------------------------------------------------------
/src/lib/stripe/init.ts:
--------------------------------------------------------------------------------
1 | import Stripe from 'stripe';
2 |
3 | /**
4 | * @description
5 | * Create stripe instance (server-side) using `STRIPE_RESTRICTED_KEY` environment variable.
6 | *
7 | * @example
8 | * import initStripe from '@src/lib/stripe/init
9 | * const stripe = initStripe()
10 | */
11 | const initStripe = () =>
12 | new Stripe(process.env.STRIPE_RESTRICTED_KEY, {
13 | // https://github.com/stripe/stripe-node#configuration
14 | apiVersion: '2020-08-27',
15 | });
16 |
17 | export default initStripe;
18 |
--------------------------------------------------------------------------------
/pages/robots.txt.tsx:
--------------------------------------------------------------------------------
1 | const getRobots = () => `# Welcome to ${process.env.NEXT_PUBLIC_APP_NAME}
2 | Sitemap: ${process.env.NEXT_PUBLIC_BASE_URL}/sitemap.xml
3 |
4 | User-agent: *
5 | Allow: /*
6 |
7 | Disallow: /api/*
8 | Disallow: /_preview/*
9 | `;
10 |
11 | export default function RobotsTxtPage() {
12 | return null;
13 | }
14 |
15 | export async function getServerSideProps({ res }) {
16 | res.setHeader('Content-Type', 'text/plain');
17 | res.write(getRobots());
18 | res.end();
19 |
20 | return { props: {} };
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/_preview/containers/AntdPreview/Progress.tsx:
--------------------------------------------------------------------------------
1 | import { Progress } from 'antd';
2 |
3 | ProgressDemo.title = 'Progress';
4 | ProgressDemo.url = 'https://ant.design/components/progress/';
5 |
6 | export default function ProgressDemo() {
7 | return (
8 | <>
9 |
10 |
11 |
12 |
13 |
14 | >
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/_preview/containers/AntdPreview/ProgressCircle.tsx:
--------------------------------------------------------------------------------
1 | import { Space, Progress } from 'antd';
2 |
3 | ProgressCircle.title = 'ProgressCircle';
4 | ProgressCircle.url = 'https://ant.design/components/progress/';
5 |
6 | export default function ProgressCircle() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import Document, { Html, Head, Main, NextScript } from 'next/document';
2 |
3 | class MyDocument extends Document {
4 | render() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 | }
19 |
20 | export default MyDocument;
21 |
--------------------------------------------------------------------------------
/src/lib/stripe/formatAmountForStripe.ts:
--------------------------------------------------------------------------------
1 | export default function formatAmountForStripe(
2 | amount: number,
3 | currency: string
4 | ): number {
5 | let numberFormat = new Intl.NumberFormat(['en-US'], {
6 | style: 'currency',
7 | currency: currency,
8 | currencyDisplay: 'symbol',
9 | });
10 | const parts = numberFormat.formatToParts(amount);
11 | let zeroDecimalCurrency: boolean = true;
12 | for (let part of parts) {
13 | if (part.type === 'decimal') {
14 | zeroDecimalCurrency = false;
15 | }
16 | }
17 | return zeroDecimalCurrency ? amount : Math.round(amount * 100);
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/base/transitions/FadeIn.tsx:
--------------------------------------------------------------------------------
1 | import { Transition } from '@headlessui/react';
2 |
3 | export default function FadeInTransition({
4 | show,
5 | appear = undefined,
6 | duration = 'duration-200',
7 | children,
8 | }) {
9 | return (
10 |
20 | {children}
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/.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 |
36 | .tsbuildinfo
37 | .vscode/settings.json
38 | checkly/_screenshots
39 | public/sitemap.xml
--------------------------------------------------------------------------------
/pages/api/stripe/checkPayment.ts:
--------------------------------------------------------------------------------
1 | import initStripe from '@src/lib/stripe/init';
2 |
3 | const stripe = initStripe();
4 |
5 | export default async function handler(req, res) {
6 | const id: string = req.query.session_id as string;
7 | try {
8 | if (!id.startsWith('cs_')) {
9 | throw Error('Incorrect CheckoutSession ID.');
10 | }
11 | const checkout_session = await stripe.checkout.sessions.retrieve(id, {
12 | expand: ['payment_intent'],
13 | });
14 |
15 | res.status(200).json(checkout_session);
16 | } catch (err) {
17 | res.status(500).json({ statusCode: 500, message: err.message });
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "christianalfoni.overmind-devtools-vscode",
4 | "jsayol.firebase-explorer",
5 | "esbenp.prettier-vscode",
6 | "bradlc.vscode-tailwindcss",
7 | "wix.vscode-import-cost",
8 | "steoates.autoimport",
9 | "kisstkondoros.vscode-gutter-preview",
10 | "formulahendry.auto-rename-tag",
11 | "eamodio.gitlens",
12 | "jpoissonnier.vscode-styled-components",
13 | "deerawan.vscode-faker",
14 | "gruntfuggly.todo-tree",
15 | "github.vscode-pull-request-github",
16 | "gimenete.github-linker"
17 | ]
18 | }
--------------------------------------------------------------------------------
/src/lib/analytic/nextjs-hook.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import { useRouter } from 'next/router';
3 |
4 | import analytic from '.';
5 |
6 | export default function useAnalytic() {
7 | const router = useRouter();
8 | useEffect(() => {
9 | analytic.init();
10 | analytic.trackPageview(); // Track initial page
11 |
12 | function onRouteChangeComplete() {
13 | analytic.trackPageview();
14 | }
15 |
16 | router.events.on('routeChangeComplete', onRouteChangeComplete);
17 |
18 | // Unassign event listener
19 | return () => {
20 | router.events.off('routeChangeComplete', onRouteChangeComplete);
21 | };
22 | }, []);
23 | }
24 |
--------------------------------------------------------------------------------
/__tests__/stubs/useStubs.ts:
--------------------------------------------------------------------------------
1 | import { useAsync } from 'react-use';
2 |
3 | /**
4 | * @description
5 | * Lazy load tests/stubs using react hook
6 | *
7 | * @example
8 | * ```
9 | * import useStubs from '@tests/stubs/useStubs';
10 | *
11 | * // Use in component
12 | * const stubs = useStubs();
13 | * if (stubs.loading) return 'loading..';
14 | * const org = stubs.buildUser();
15 | * ```
16 | */
17 | export default function useStubs() {
18 | const { value: stubs, loading, error } = useAsync(
19 | async () => import(/* webpackChunkName: "tests_stubs" */ '@tests/stubs')
20 | );
21 |
22 | return {
23 | ...stubs,
24 | loading,
25 | error,
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/pages/_preview/StripePreview.tsx:
--------------------------------------------------------------------------------
1 | import initStripe from '@src/lib/stripe/init';
2 |
3 | import StripePreview from '@src/components/_preview/containers/StripePreview';
4 |
5 | export default StripePreview;
6 |
7 | export async function getStaticProps() {
8 | const stripe = initStripe();
9 | const prices = await stripe.prices.list({
10 | active: true,
11 | limit: 10,
12 |
13 | // Inline product info in response
14 | expand: ['data.product'],
15 |
16 | // Only return prices of type `recurring` or `one_time`.
17 | // Leave it empty to inlude both types.
18 | // type: 'recurring',
19 | });
20 |
21 | return { props: { prices: prices.data } };
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/base/transitions/Rotate90.tsx:
--------------------------------------------------------------------------------
1 | import { Transition } from '@headlessui/react';
2 |
3 | import { TransitionProps } from './types';
4 |
5 | export default function Rotate90Transition({
6 | show,
7 | appear = undefined,
8 | children,
9 | }: TransitionProps) {
10 | return (
11 |
21 | {children}
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 60
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 7
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - documentation
8 | - security
9 | # Label to use when marking an issue as stale
10 | staleLabel: stale
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 | This issue has been automatically marked as stale because it has not had
14 | recent activity. It will be closed if no further activity occurs.
15 | # Comment to post when closing a stale issue. Set to `false` to disable
16 | closeComment: false
17 |
--------------------------------------------------------------------------------
/src/components/SendFeedback.tsx:
--------------------------------------------------------------------------------
1 | import { FeedbackFish } from '@feedback-fish/react';
2 |
3 | /**
4 | * @description
5 | * Headless component that triggers a feedback handler (eg. FeedbackFish).
6 | *
7 | * @example
8 | *
9 | *
10 | *
11 | */
12 | export default function SendFeedback({
13 | userId = undefined,
14 | metadata = {},
15 | children,
16 | }) {
17 | return (
18 |
23 | {children}
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/base/transitions/SlideOver.tsx:
--------------------------------------------------------------------------------
1 | import { Transition } from '@headlessui/react';
2 |
3 | import { TransitionProps } from './types';
4 |
5 | export default function SlideOverTransition({
6 | show,
7 | appear = undefined,
8 | children,
9 | }: TransitionProps) {
10 | return (
11 |
21 | {children}
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/base/transitions/FadeInScale.tsx:
--------------------------------------------------------------------------------
1 | import { Transition } from '@headlessui/react';
2 |
3 | import { TransitionProps } from './types';
4 |
5 | export default function FadeInScaleTransition({
6 | show,
7 | appear = undefined,
8 | children,
9 | }: TransitionProps) {
10 | return (
11 |
21 | {children}
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/styles/tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer components {
6 | .invert {
7 | -webkit-filter: invert(100%);
8 | filter: invert(100%);
9 | }
10 | .text-loading {
11 | @apply text-gray-600;
12 | }
13 | .xy-center {
14 | @apply justify-center items-center;
15 | }
16 |
17 | /* Unreset vercel page */
18 | .vercel p {
19 | margin-block-start: 1em;
20 | margin-block-end: 1em;
21 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
22 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif !important;
23 | }
24 | .vercel h1,
25 | .vercel h2,
26 | .vercel h3 {
27 | font-weight: bold;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/base/transitions/Collapse.tsx:
--------------------------------------------------------------------------------
1 | import { Transition } from '@headlessui/react';
2 |
3 | import { TransitionProps } from './types';
4 |
5 | export default function CollapseTransition({
6 | show,
7 | appear = undefined,
8 | children,
9 | }: TransitionProps) {
10 | return (
11 |
21 | {children}
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/logger.ts:
--------------------------------------------------------------------------------
1 | let logger: any = {
2 | dev: (msg, opts = '') => console.info('[DEV]', msg, opts),
3 | debug: (msg, opts = '') => console.info('[DEBUG]', msg, opts),
4 | info: (msg, opts = '') => console.info('[INFO]', msg, opts),
5 | warn: (msg, opts = '') => console.warn('[WARN]', msg, opts),
6 | error: (msg, opts = '') => console.error('[ERROR]', msg, opts),
7 | fatal: (msg, opts = '') => console.error('[FATAL]', msg, opts),
8 | };
9 |
10 | // Override logger for production
11 | if (process.env.NODE_ENV === 'production') {
12 | // logger.debug = () => {};
13 | // logger.info = () => {};
14 | // logger.warn = () => {};
15 | // logger.error = () => {};
16 | // logger.fatal = () => {};
17 | }
18 |
19 | export default logger;
20 |
--------------------------------------------------------------------------------
/src/components/base/transitions/PopOut.tsx:
--------------------------------------------------------------------------------
1 | import { Transition } from '@headlessui/react';
2 |
3 | import { TransitionProps } from './types';
4 |
5 | export default function PopOutTransition({
6 | show,
7 | appear = undefined,
8 | children,
9 | }: TransitionProps) {
10 | return (
11 |
21 | {children}
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/base/transitions/SlideDown.tsx:
--------------------------------------------------------------------------------
1 | import { Transition } from '@headlessui/react';
2 |
3 | import { TransitionProps } from './types';
4 |
5 | export default function SlideDownTransition({
6 | show,
7 | appear = undefined,
8 | children,
9 | }: TransitionProps) {
10 | return (
11 |
21 | {children}
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/_preview/containers/BaseWebPreview/DragAndDrop.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { List, arrayMove, arrayRemove } from 'baseui/dnd-list';
3 |
4 | DragAndDrop.title = 'DragAndDrop';
5 | DragAndDrop.url = 'https://v9-9-0.baseweb.design/components/dnd-list';
6 |
7 | export default function DragAndDrop() {
8 | const [items, setItems] = React.useState([
9 | 'Item 1',
10 | 'Item 2',
11 | 'Item 3',
12 | 'Item 4',
13 | ]);
14 | return (
15 |
19 | setItems(
20 | newIndex === -1
21 | ? arrayRemove(items, oldIndex)
22 | : arrayMove(items, oldIndex, newIndex)
23 | )
24 | }
25 | />
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/_preview/containers/AntdPreview/Buttons.tsx:
--------------------------------------------------------------------------------
1 | import { Space, Button } from 'antd';
2 |
3 | ButtonsDemo.title = 'Buttons';
4 | ButtonsDemo.url = 'https://ant.design/components/button';
5 |
6 | export default function ButtonsDemo() {
7 | function onClick(...args) {
8 | console.log('Button clicked:', args);
9 | }
10 |
11 | return (
12 |
13 |
14 |
17 |
20 |
23 |
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/_preview/containers/BaseWebPreview/Select.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {Select, Value} from 'baseui/select';
3 |
4 | SelectDemo.title ="Select"
5 | SelectDemo.url ="https://v9-9-0.baseweb.design/components/select"
6 |
7 | export default function SelectDemo() {
8 | const [value, setValue] = React.useState([]);
9 | return (
10 |