Skip to content

Commit c2c4f3a

Browse files
committed
Initial commit
0 parents  commit c2c4f3a

23 files changed

+12140
-0
lines changed

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.js

.eslintrc.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module.exports = {
2+
extends: [
3+
'mantine',
4+
'plugin:@next/next/recommended',
5+
'plugin:jest/recommended',
6+
'plugin:storybook/recommended',
7+
],
8+
plugins: ['testing-library', 'jest'],
9+
overrides: [
10+
{
11+
files: ['**/?(*.)+(spec|test).[jt]s?(x)'],
12+
extends: ['plugin:testing-library/react'],
13+
},
14+
],
15+
parserOptions: {
16+
project: './tsconfig.json',
17+
},
18+
rules: {
19+
'react/react-in-jsx-scope': 'off',
20+
},
21+
};

.gitignore

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
*.tsbuildinfo
36+
37+
# storybook
38+
storybook-static

.prettierrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('eslint-config-mantine/.prettierrc.js');

.storybook/main.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = {
2+
stories: ['../**/*.story.mdx', '../**/*.story.@(js|jsx|ts|tsx)'],
3+
addons: [
4+
'storybook-dark-mode',
5+
{
6+
name: 'storybook-addon-turbo-build',
7+
options: { optimizationLevel: 2 },
8+
},
9+
],
10+
framework: '@storybook/react',
11+
};

.storybook/preview.tsx

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { useDarkMode } from 'storybook-dark-mode';
2+
import { MantineProvider, ColorSchemeProvider } from '@mantine/core';
3+
import { NotificationsProvider } from '@mantine/notifications';
4+
5+
export const parameters = { layout: 'fullscreen' };
6+
7+
function ThemeWrapper(props: { children: React.ReactNode }) {
8+
const a = 2;
9+
return (
10+
<ColorSchemeProvider colorScheme="light" toggleColorScheme={() => {}}>
11+
<MantineProvider
12+
theme={{ colorScheme: useDarkMode() ? 'dark' : 'light' }}
13+
withGlobalStyles
14+
withNormalizeCSS
15+
>
16+
<NotificationsProvider>{props.children}</NotificationsProvider>
17+
</MantineProvider>
18+
</ColorSchemeProvider>
19+
);
20+
}
21+
22+
export const decorators = [(renderStory: Function) => <ThemeWrapper>{renderStory()}</ThemeWrapper>];

README.md

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Mantine Next Template
2+
3+
Get started with Mantine + Next with just a few button clicks.
4+
Click `Use this template` button at the header of repository or [follow this link](https://github.com/mantinedev/mantine-next-template/generate) and
5+
create new repository with `@mantine` packages. Note that you have to be logged in to GitHub to generate template.
6+
7+
## Features
8+
9+
This template comes with several essential features:
10+
11+
- Server side rendering setup for Mantine
12+
- Color scheme is stored in cookie to avoid color scheme mismatch after hydration
13+
- Storybook with color scheme toggle
14+
- Jest with react testing library
15+
- ESLint setup with [eslint-config-mantine](https://github.com/mantinedev/eslint-config-mantine)
16+
17+
## npm scripts
18+
19+
### Build and dev scripts
20+
21+
- `dev` – start dev server
22+
- `build` – bundle application for production
23+
- `export` – exports static website to `out` folder
24+
- `analyze` – analyzes application bundle with [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer)
25+
26+
### Testing scripts
27+
28+
- `typecheck` – checks TypeScript types
29+
- `lint` – runs ESLint
30+
- `prettier:check` – checks files with Prettier
31+
- `jest` – runs jest tests
32+
- `jest:watch` – starts jest watch
33+
- `test` – runs `jest`, `prettier:check`, `lint` and `typecheck` scripts
34+
35+
### Other scripts
36+
37+
- `storybook` – starts storybook dev server
38+
- `storybook:build` – build production storybook bundle to `storybook-static`
39+
- `prettier:write` – formats all files with Prettier
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { ActionIcon, Group, useMantineColorScheme } from '@mantine/core';
2+
import { SunIcon, MoonIcon } from '@modulz/radix-icons';
3+
4+
export function ColorSchemeToggle() {
5+
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
6+
7+
return (
8+
<Group position="center" mt="xl">
9+
<ActionIcon
10+
onClick={() => toggleColorScheme()}
11+
size="xl"
12+
sx={(theme) => ({
13+
backgroundColor:
14+
theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
15+
color: theme.colorScheme === 'dark' ? theme.colors.yellow[4] : theme.colors.blue[6],
16+
})}
17+
>
18+
{colorScheme === 'dark' ? (
19+
<SunIcon width={20} height={20} />
20+
) : (
21+
<MoonIcon width={20} height={20} />
22+
)}
23+
</ActionIcon>
24+
</Group>
25+
);
26+
}

components/Welcome/Welcome.story.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { Welcome } from './Welcome';
2+
3+
export default {
4+
title: 'Welcome',
5+
};
6+
7+
export const Usage = () => <Welcome />;

components/Welcome/Welcome.styles.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { createStyles } from '@mantine/core';
2+
3+
export default createStyles((theme) => ({
4+
title: {
5+
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
6+
fontSize: 100,
7+
fontWeight: 900,
8+
letterSpacing: -2,
9+
10+
[theme.fn.smallerThan('md')]: {
11+
fontSize: 50,
12+
},
13+
},
14+
}));

components/Welcome/Welcome.test.tsx

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { Welcome } from './Welcome';
3+
4+
describe('Welcome component', () => {
5+
it('has correct Next.js theming section link', () => {
6+
render(<Welcome />);
7+
expect(screen.getByText('this guide')).toHaveAttribute(
8+
'href',
9+
'https://mantine.dev/theming/next/'
10+
);
11+
});
12+
});

components/Welcome/Welcome.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Title, Text, Anchor } from '@mantine/core';
2+
import useStyles from './Welcome.styles';
3+
4+
export function Welcome() {
5+
const { classes } = useStyles();
6+
7+
return (
8+
<>
9+
<Title className={classes.title} align="center" mt={100}>
10+
Welcome to{' '}
11+
<Text inherit variant="gradient" component="span">
12+
Mantine
13+
</Text>
14+
</Title>
15+
<Text color="dimmed" align="center" size="lg" sx={{ maxWidth: 580 }} mx="auto" mt="xl">
16+
This starter Next.js project includes a minimal setup for server side rendering, if you want
17+
to learn more on Mantine + Next.js integration follow{' '}
18+
<Anchor href="https://mantine.dev/theming/next/" size="lg">
19+
this guide
20+
</Anchor>
21+
. To get started edit index.tsx file.
22+
</Text>
23+
</>
24+
);
25+
}

jest.config.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const nextJest = require('next/jest');
2+
3+
const createJestConfig = nextJest({
4+
dir: './',
5+
});
6+
7+
const customJestConfig = {
8+
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
9+
moduleNameMapper: {
10+
'^@/components/(.*)$': '<rootDir>/components/$1',
11+
'^@/pages/(.*)$': '<rootDir>/pages/$1',
12+
},
13+
testEnvironment: 'jest-environment-jsdom',
14+
};
15+
16+
module.exports = createJestConfig(customJestConfig);

jest.setup.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import '@testing-library/jest-dom/extend-expect';

next-env.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.

next.config.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const withBundleAnalyzer = require('@next/bundle-analyzer')({
2+
enabled: process.env.ANALYZE === 'true',
3+
});
4+
5+
module.exports = withBundleAnalyzer({
6+
reactStrictMode: true,
7+
eslint: {
8+
ignoreDuringBuilds: true,
9+
},
10+
});

package.json

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"name": "mantine-next-template",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"dev": "next dev",
7+
"build": "next build",
8+
"analyze": "ANALYZE=true next build",
9+
"start": "next start",
10+
"typecheck": "tsc --noEmit",
11+
"export": "next build && next export",
12+
"lint": "next lint",
13+
"jest": "jest",
14+
"jest:watch": "jest --watch",
15+
"prettier:check": "prettier --check \"**/*.{ts,tsx}\"",
16+
"prettier:write": "prettier --write \"**/*.{ts,tsx}\"",
17+
"test": "npm run prettier:check && npm run lint && npm run typecheck && npm run jest",
18+
"storybook": "start-storybook -p 7001",
19+
"storybook:build": "build-storybook"
20+
},
21+
"dependencies": {
22+
"@mantine/core": "4.1.3",
23+
"@mantine/dates": "4.1.3",
24+
"@mantine/hooks": "4.1.3",
25+
"@mantine/next": "4.1.3",
26+
"@mantine/notifications": "4.1.3",
27+
"@mantine/prism": "4.1.3",
28+
"@modulz/radix-icons": "^4.0.0",
29+
"cookies-next": "^2.0.4",
30+
"dayjs": "^1.11.0",
31+
"next": "12.1.4",
32+
"prism-react-renderer": "^1.3.1",
33+
"react": "18.0.0",
34+
"react-dom": "18.0.0"
35+
},
36+
"devDependencies": {
37+
"@babel/core": "^7.17.8",
38+
"@next/bundle-analyzer": "^12.1.4",
39+
"@next/eslint-plugin-next": "^12.1.4",
40+
"@storybook/react": "^6.4.20",
41+
"@testing-library/dom": "^8.12.0",
42+
"@testing-library/jest-dom": "^5.16.3",
43+
"@testing-library/react": "^13.0.0",
44+
"@testing-library/user-event": "^14.0.4",
45+
"@types/jest": "^27.4.1",
46+
"@types/node": "^17.0.23",
47+
"@types/react": "17.0.43",
48+
"@typescript-eslint/eslint-plugin": "^5.16.0",
49+
"@typescript-eslint/parser": "^5.16.0",
50+
"babel-loader": "^8.2.4",
51+
"eslint": "^8.11.0",
52+
"eslint-config-airbnb": "19.0.4",
53+
"eslint-config-airbnb-typescript": "^16.1.4",
54+
"eslint-config-mantine": "1.1.0",
55+
"eslint-plugin-import": "^2.25.4",
56+
"eslint-plugin-jest": "^26.1.3",
57+
"eslint-plugin-jsx-a11y": "^6.5.1",
58+
"eslint-plugin-react": "^7.29.4",
59+
"eslint-plugin-react-hooks": "^4.3.0",
60+
"eslint-plugin-storybook": "^0.5.7",
61+
"eslint-plugin-testing-library": "^5.2.0",
62+
"jest": "^27.5.1",
63+
"prettier": "^2.6.2",
64+
"storybook-addon-turbo-build": "^1.1.0",
65+
"storybook-dark-mode": "^1.0.9",
66+
"ts-jest": "^27.1.4",
67+
"typescript": "4.6.3"
68+
}
69+
}

pages/_app.tsx

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { GetServerSidePropsContext } from 'next';
2+
import { useState } from 'react';
3+
import { AppProps } from 'next/app';
4+
import { getCookie, setCookies } from 'cookies-next';
5+
import Head from 'next/head';
6+
import { MantineProvider, ColorScheme, ColorSchemeProvider } from '@mantine/core';
7+
import { NotificationsProvider } from '@mantine/notifications';
8+
9+
export default function App(props: AppProps & { colorScheme: ColorScheme }) {
10+
const { Component, pageProps } = props;
11+
const [colorScheme, setColorScheme] = useState<ColorScheme>(props.colorScheme);
12+
13+
const toggleColorScheme = (value?: ColorScheme) => {
14+
const nextColorScheme = value || (colorScheme === 'dark' ? 'light' : 'dark');
15+
setColorScheme(nextColorScheme);
16+
setCookies('mantine-color-scheme', nextColorScheme, { maxAge: 60 * 60 * 24 * 30 });
17+
};
18+
19+
return (
20+
<>
21+
<Head>
22+
<title>Mantine next example</title>
23+
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
24+
<link rel="shortcut icon" href="/favicon.svg" />
25+
</Head>
26+
27+
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
28+
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
29+
<NotificationsProvider>
30+
<Component {...pageProps} />
31+
</NotificationsProvider>
32+
</MantineProvider>
33+
</ColorSchemeProvider>
34+
</>
35+
);
36+
}
37+
38+
App.getInitialProps = ({ ctx }: { ctx: GetServerSidePropsContext }) => ({
39+
colorScheme: getCookie('mantine-color-scheme', ctx) || 'light',
40+
});

pages/_document.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Document from 'next/document';
2+
import { createGetInitialProps } from '@mantine/next';
3+
4+
const getInitialProps = createGetInitialProps();
5+
6+
export default class _Document extends Document {
7+
static getInitialProps = getInitialProps;
8+
}

pages/index.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Welcome } from '../components/Welcome/Welcome';
2+
import { ColorSchemeToggle } from '../components/ColorSchemeToggle/ColorSchemeToggle';
3+
4+
export default function HomePage() {
5+
return (
6+
<>
7+
<Welcome />
8+
<ColorSchemeToggle />
9+
</>
10+
);
11+
}

0 commit comments

Comments
 (0)