Compare commits
2 Commits
5e6cfe8070
...
fe6e87f97c
| Author | SHA1 | Date | |
|---|---|---|---|
| fe6e87f97c | |||
| 948480c219 |
@ -1,3 +0,0 @@
|
||||
*.js
|
||||
*.mjs
|
||||
*.cjs
|
||||
@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@ -102,7 +102,6 @@ dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
@ -123,11 +122,9 @@ dist
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
.yarn
|
||||
|
||||
.DS_Store
|
||||
.idea
|
||||
|
||||
.idea
|
||||
.yarnrc.yml
|
||||
@ -1,6 +1 @@
|
||||
# Ignore artifacts:
|
||||
build
|
||||
coverage
|
||||
|
||||
# Ignore all HTML files:
|
||||
**/*.html
|
||||
.next
|
||||
@ -1,6 +1,39 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": false,
|
||||
"singleQuote": false
|
||||
"singleAttributePerLine": true,
|
||||
"singleQuote": false,
|
||||
"semi": true,
|
||||
"quoteProps": "consistent",
|
||||
"bracketSpacing": true,
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"bracketSameLine": true,
|
||||
"arrowParens": "avoid",
|
||||
"plugins": [
|
||||
"@ianvs/prettier-plugin-sort-imports"
|
||||
],
|
||||
"importOrder": [
|
||||
".*styles.css$",
|
||||
"dayjs",
|
||||
"^react$",
|
||||
"^next$",
|
||||
"^next/.*$",
|
||||
"<BUILTIN_MODULES>",
|
||||
"<THIRD_PARTY_MODULES>",
|
||||
"^@mantine/(.*)$",
|
||||
"^@mantinex/(.*)$",
|
||||
"^@mantine-tests/(.*)$",
|
||||
"^@docs/(.*)$",
|
||||
"^@/.*$",
|
||||
"^../(?!.*.css$).*$",
|
||||
"^./(?!.*.css$).*$",
|
||||
"\\.css$"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.mdx",
|
||||
"options": {
|
||||
"printWidth": 70
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
35
.prettierrc.mjs
Normal file
35
.prettierrc.mjs
Normal file
@ -0,0 +1,35 @@
|
||||
/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */
|
||||
const config = {
|
||||
printWidth: 100,
|
||||
singleQuote: true,
|
||||
trailingComma: 'es5',
|
||||
plugins: ['@ianvs/prettier-plugin-sort-imports'],
|
||||
importOrder: [
|
||||
'.*styles.css$',
|
||||
'',
|
||||
'dayjs',
|
||||
'^react$',
|
||||
'^next$',
|
||||
'^next/.*$',
|
||||
'<BUILTIN_MODULES>',
|
||||
'<THIRD_PARTY_MODULES>',
|
||||
'^@mantine/(.*)$',
|
||||
'^@mantinex/(.*)$',
|
||||
'^@mantine-tests/(.*)$',
|
||||
'^@docs/(.*)$',
|
||||
'^@/.*$',
|
||||
'^../(?!.*.css$).*$',
|
||||
'^./(?!.*.css$).*$',
|
||||
'\\.css$',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
files: '*.mdx',
|
||||
options: {
|
||||
printWidth: 70,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
||||
2
.stylelintignore
Normal file
2
.stylelintignore
Normal file
@ -0,0 +1,2 @@
|
||||
.next
|
||||
out
|
||||
28
.stylelintrc.json
Normal file
28
.stylelintrc.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"extends": ["stylelint-config-standard-scss"],
|
||||
"rules": {
|
||||
"custom-property-pattern": null,
|
||||
"selector-class-pattern": null,
|
||||
"scss/no-duplicate-mixins": null,
|
||||
"declaration-empty-line-before": null,
|
||||
"declaration-block-no-redundant-longhand-properties": null,
|
||||
"alpha-value-notation": null,
|
||||
"custom-property-empty-line-before": null,
|
||||
"property-no-vendor-prefix": null,
|
||||
"color-function-notation": null,
|
||||
"length-zero-no-unit": null,
|
||||
"selector-not-notation": null,
|
||||
"no-descending-specificity": null,
|
||||
"comment-empty-line-before": null,
|
||||
"scss/at-mixin-pattern": null,
|
||||
"scss/at-rule-no-unknown": null,
|
||||
"value-keyword-case": null,
|
||||
"media-feature-range-notation": null,
|
||||
"selector-pseudo-class-no-unknown": [
|
||||
true,
|
||||
{
|
||||
"ignorePseudoClasses": ["global"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
38
README.md
38
README.md
@ -1,5 +1,37 @@
|
||||
# Mantine Next Template
|
||||
# Mantine Next.js template
|
||||
|
||||
Get started with the template by clicking `Use this template` button on the top of the page.
|
||||
This is a template for [Next.js](https://nextjs.org/) app router + [Mantine](https://mantine.dev/).
|
||||
If you want to use pages router instead, see [next-pages-template](https://github.com/mantinedev/next-pages-template).
|
||||
|
||||
[Documentation](https://mantine.dev/guides/next/)
|
||||
## Features
|
||||
|
||||
This template comes with the following features:
|
||||
|
||||
- [PostCSS](https://postcss.org/) with [mantine-postcss-preset](https://mantine.dev/styles/postcss-preset)
|
||||
- [TypeScript](https://www.typescriptlang.org/)
|
||||
- [Storybook](https://storybook.js.org/)
|
||||
- [Jest](https://jestjs.io/) setup with [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
|
||||
- ESLint setup with [eslint-config-mantine](https://github.com/mantinedev/eslint-config-mantine)
|
||||
|
||||
## npm scripts
|
||||
|
||||
### Build and dev scripts
|
||||
|
||||
- `dev` – start dev server
|
||||
- `build` – bundle application for production
|
||||
- `analyze` – analyzes application bundle with [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer)
|
||||
|
||||
### Testing scripts
|
||||
|
||||
- `typecheck` – checks TypeScript types
|
||||
- `lint` – runs ESLint
|
||||
- `prettier:check` – checks files with Prettier
|
||||
- `jest` – runs jest tests
|
||||
- `jest:watch` – starts jest watch
|
||||
- `test` – runs `jest`, `prettier:check`, `lint` and `typecheck` scripts
|
||||
|
||||
### Other scripts
|
||||
|
||||
- `storybook` – starts storybook dev server
|
||||
- `storybook:build` – build production storybook bundle to `storybook-static`
|
||||
- `prettier:write` – formats all files with Prettier
|
||||
|
||||
21
eslint.config.mjs
Normal file
21
eslint.config.mjs
Normal file
@ -0,0 +1,21 @@
|
||||
import mantine from "eslint-config-mantine";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
...mantine,
|
||||
{ ignores: ["**/*.{mjs,cjs,js,d.ts,d.mts}"] },
|
||||
{
|
||||
files: ["**/*.story.tsx"],
|
||||
rules: {
|
||||
"no-console": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["**/*.{ts,tsx}"],
|
||||
rules: {
|
||||
"no-console": "off",
|
||||
"react/jsx-curly-brace-presence": "off",
|
||||
"curly": "off",
|
||||
},
|
||||
}
|
||||
);
|
||||
16
jest.config.cjs
Normal file
16
jest.config.cjs
Normal file
@ -0,0 +1,16 @@
|
||||
const nextJest = require('next/jest');
|
||||
|
||||
const createJestConfig = nextJest({
|
||||
dir: './',
|
||||
});
|
||||
|
||||
const customJestConfig = {
|
||||
setupFilesAfterEnv: ['<rootDir>/jest.setup.cjs'],
|
||||
moduleNameMapper: {
|
||||
'^@/components/(.*)$': '<rootDir>/components/$1',
|
||||
'^@/pages/(.*)$': '<rootDir>/pages/$1',
|
||||
},
|
||||
testEnvironment: 'jest-environment-jsdom',
|
||||
};
|
||||
|
||||
module.exports = createJestConfig(customJestConfig);
|
||||
27
jest.setup.cjs
Normal file
27
jest.setup.cjs
Normal file
@ -0,0 +1,27 @@
|
||||
require('@testing-library/jest-dom');
|
||||
|
||||
const { getComputedStyle } = window;
|
||||
window.getComputedStyle = (elt) => getComputedStyle(elt);
|
||||
window.HTMLElement.prototype.scrollIntoView = () => {};
|
||||
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation((query) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
})),
|
||||
});
|
||||
|
||||
class ResizeObserver {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
}
|
||||
|
||||
window.ResizeObserver = ResizeObserver;
|
||||
@ -1,12 +1,16 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
experimental: {
|
||||
optimizePackageImports: [
|
||||
"@mantine/core",
|
||||
"@mantine/hooks",
|
||||
],
|
||||
},
|
||||
}
|
||||
import bundleAnalyzer from '@next/bundle-analyzer';
|
||||
|
||||
export default nextConfig
|
||||
const withBundleAnalyzer = bundleAnalyzer({
|
||||
enabled: process.env.ANALYZE === 'true',
|
||||
});
|
||||
|
||||
export default withBundleAnalyzer({
|
||||
output: "standalone",
|
||||
reactStrictMode: false,
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
experimental: {
|
||||
optimizePackageImports: ['@mantine/core', '@mantine/hooks'],
|
||||
},
|
||||
});
|
||||
|
||||
66
package.json
66
package.json
@ -9,38 +9,64 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mantine/core": "^8.2.1",
|
||||
"@mantine/dates": "^8.2.1",
|
||||
"@mantine/dropzone": "^8.2.1",
|
||||
"@mantine/form": "^8.2.1",
|
||||
"@mantine/hooks": "^8.2.1",
|
||||
"@mantine/core": "8.1.2",
|
||||
"@mantine/form": "^8.1.3",
|
||||
"@mantine/hooks": "8.1.2",
|
||||
"@mantine/modals": "^8.2.1",
|
||||
"@mantine/notifications": "^8.2.1",
|
||||
"@next/bundle-analyzer": "^15.3.3",
|
||||
"@reduxjs/toolkit": "^2.8.2",
|
||||
"@tabler/icons-react": "^3.34.1",
|
||||
"@tabler/icons-react": "^3.34.0",
|
||||
"@tailwindcss/postcss": "^4.1.11",
|
||||
"@tanstack/react-query": "^5.83.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"lodash": "^4.17.21",
|
||||
"axios": "^1.11.0",
|
||||
"classnames": "^2.5.1",
|
||||
"framer-motion": "^12.23.7",
|
||||
"i18n-iso-countries": "^7.14.0",
|
||||
"libphonenumber-js": "^1.12.10",
|
||||
"next": "15.3.3",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-imask": "^7.6.1",
|
||||
"react-redux": "^9.2.0",
|
||||
"tailwind-preset-mantine": "^2.1.0",
|
||||
"tailwindcss": "^4.1.11"
|
||||
"redux-persist": "^6.0.0",
|
||||
"sharp": "^0.34.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4",
|
||||
"@types/node": "22.13.11",
|
||||
"@types/react": "19.0.12",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"eslint": "9.23.0",
|
||||
"eslint-config-next": "15.2.3",
|
||||
"postcss": "^8.5.3",
|
||||
"@babel/core": "^7.27.4",
|
||||
"@eslint/js": "^9.29.0",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.4.2",
|
||||
"@storybook/nextjs": "^8.6.8",
|
||||
"@storybook/react": "^8.6.8",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/eslint-plugin-jsx-a11y": "^6",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.13.11",
|
||||
"@types/react": "19.1.8",
|
||||
"@types/react-redux": "^7.1.34",
|
||||
"@types/redux-persist": "^4.3.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"babel-loader": "^10.0.0",
|
||||
"eslint": "^9.29.0",
|
||||
"eslint-config-mantine": "^4.0.3",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"jest": "^30.0.0",
|
||||
"jest-environment-jsdom": "^30.0.0",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-preset-mantine": "1.17.0",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"prettier": "3.6.2",
|
||||
"typescript": "5.8.2"
|
||||
"prettier": "^3.5.3",
|
||||
"storybook": "^8.6.8",
|
||||
"storybook-dark-mode": "^4.0.2",
|
||||
"stylelint": "^16.20.0",
|
||||
"stylelint-config-standard-scss": "^15.0.1",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"ts-jest": "^29.4.0",
|
||||
"typescript": "5.8.3",
|
||||
"typescript-eslint": "^8.34.0"
|
||||
},
|
||||
"packageManager": "yarn@4.9.2"
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
"postcss-preset-mantine": {},
|
||||
"@tailwindcss/postcss": {},
|
||||
"postcss-simple-vars": {
|
||||
variables: {
|
||||
"mantine-breakpoint-xs": "36em",
|
||||
@ -12,4 +12,4 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@ -1 +1,12 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500"><g fill="none" fill-rule="evenodd"><rect width="500" height="500" fill="#339AF0" rx="250"/><g fill="#FFF"><path fill-rule="nonzero" d="M202.055 135.706c-6.26 8.373-4.494 20.208 3.944 26.42 29.122 21.45 45.824 54.253 45.824 90.005 0 35.752-16.702 68.559-45.824 90.005-8.436 6.215-10.206 18.043-3.944 26.42 6.26 8.378 18.173 10.13 26.611 3.916a153.835 153.835 0 0024.509-22.54h53.93c10.506 0 19.023-8.455 19.023-18.885 0-10.43-8.517-18.886-19.023-18.886h-29.79c8.196-18.594 12.553-38.923 12.553-60.03s-4.357-41.436-12.552-60.03h29.79c10.505 0 19.022-8.455 19.022-18.885 0-10.43-8.517-18.886-19.023-18.886h-53.93a153.835 153.835 0 00-24.509-22.54c-8.438-6.215-20.351-4.46-26.61 3.916z"/><path d="M171.992 246.492c0-15.572 12.624-28.195 28.196-28.195 15.572 0 28.195 12.623 28.195 28.195 0 15.572-12.623 28.196-28.195 28.196-15.572 0-28.196-12.624-28.196-28.196z"/></g></g></svg>
|
||||
<svg width="41" height="47" viewBox="0 0 41 47" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_431_24446)">
|
||||
<path opacity="0.958" fill-rule="evenodd" clip-rule="evenodd" d="M20.2179 -0.0939941C20.406 -0.0939941 20.5941 -0.0939941 20.7822 -0.0939941C27.0194 3.59767 33.2885 7.26367 39.5895 10.904C33.2187 14.6831 26.8242 18.4118 20.406 22.09C13.9877 18.4118 7.59324 14.6831 1.22253 10.904C7.56616 7.23297 13.898 3.56697 20.2179 -0.0939941ZM19.6537 3.85401C19.9938 3.85239 20.3073 3.94639 20.5941 4.13601C24.2301 6.39201 27.8663 8.64801 31.5024 10.904C23.6659 11.0293 15.8296 11.0293 7.99318 10.904C11.9233 8.59642 15.8101 6.24642 19.6537 3.85401Z" fill="#44A8C6"/>
|
||||
<path opacity="0.962" fill-rule="evenodd" clip-rule="evenodd" d="M-0.0939941 13.442C6.3424 16.991 12.7369 20.6257 19.0895 24.346C19.2776 31.8649 19.3402 39.3849 19.2776 46.906C19.0895 46.906 18.9014 46.906 18.7133 46.906C12.4971 43.203 6.22796 39.5684 -0.0939941 36.002C-0.0939941 28.482 -0.0939941 20.962 -0.0939941 13.442ZM2.91518 19.646C6.9531 26.4762 10.9653 33.3382 14.9519 40.232C10.9005 38.3163 6.91964 36.2169 3.00922 33.934C2.91518 29.1718 2.88385 24.4092 2.91518 19.646Z" fill="#334B63"/>
|
||||
<path opacity="0.972" fill-rule="evenodd" clip-rule="evenodd" d="M40.906 13.442C40.906 21.0246 40.906 28.6074 40.906 36.19C34.5741 39.6675 28.305 43.2395 22.0986 46.906C21.9732 46.906 21.8479 46.906 21.7225 46.906C21.6911 39.3858 21.7225 31.8658 21.8165 24.346C28.1747 20.6832 34.5378 17.0485 40.906 13.442ZM25.8601 40.326C29.6787 33.4443 33.5969 26.6137 37.6147 19.834C37.7401 24.534 37.7401 29.234 37.6147 33.934C33.7364 36.1387 29.8183 38.2693 25.8601 40.326Z" fill="#3C83B4"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_431_24446">
|
||||
<rect width="41" height="47" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 937 B After Width: | Height: | Size: 1.8 KiB |
16
src/.storybook/main.ts
Normal file
16
src/.storybook/main.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import type { StorybookConfig } from '@storybook/nextjs';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
core: {
|
||||
disableWhatsNewNotifications: true,
|
||||
disableTelemetry: true,
|
||||
enableCrashReports: false,
|
||||
},
|
||||
stories: ['../components/**/*.(stories|story).@(js|jsx|ts|tsx)'],
|
||||
addons: ['storybook-dark-mode'],
|
||||
framework: {
|
||||
name: '@storybook/nextjs',
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
36
src/.storybook/preview.tsx
Normal file
36
src/.storybook/preview.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import '@mantine/core/styles.css';
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { addons } from '@storybook/preview-api';
|
||||
import { DARK_MODE_EVENT_NAME } from 'storybook-dark-mode';
|
||||
import { MantineProvider, useMantineColorScheme } from '@mantine/core';
|
||||
import { theme } from '../theme';
|
||||
|
||||
export const parameters = {
|
||||
layout: 'fullscreen',
|
||||
options: {
|
||||
showPanel: false,
|
||||
storySort: (a, b) => {
|
||||
return a.title.localeCompare(b.title, undefined, { numeric: true });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const channel = addons.getChannel();
|
||||
|
||||
function ColorSchemeWrapper({ children }: { children: React.ReactNode }) {
|
||||
const { setColorScheme } = useMantineColorScheme();
|
||||
const handleColorScheme = (value: boolean) => setColorScheme(value ? 'dark' : 'light');
|
||||
|
||||
useEffect(() => {
|
||||
channel.on(DARK_MODE_EVENT_NAME, handleColorScheme);
|
||||
return () => channel.off(DARK_MODE_EVENT_NAME, handleColorScheme);
|
||||
}, [channel]);
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
export const decorators = [
|
||||
(renderStory: any) => <ColorSchemeWrapper>{renderStory()}</ColorSchemeWrapper>,
|
||||
(renderStory: any) => <MantineProvider theme={theme}>{renderStory()}</MantineProvider>,
|
||||
];
|
||||
7
src/app/global.css
Normal file
7
src/app/global.css
Normal file
@ -0,0 +1,7 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
body {
|
||||
@mixin light {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
@import "tailwind-preset-mantine";
|
||||
@import "./theme.css";
|
||||
@ -1,41 +1,68 @@
|
||||
import "@mantine/core/styles.css"
|
||||
import "@mantine/dates/styles.css"
|
||||
import "@mantine/notifications/styles.css"
|
||||
import '@mantine/dropzone/styles.css';
|
||||
|
||||
import React from "react"
|
||||
import "@mantine/core/styles.css";
|
||||
import "@mantine/notifications/styles.css";
|
||||
import React, { ReactNode } from "react";
|
||||
import {
|
||||
ColorSchemeScript,
|
||||
mantineHtmlProps,
|
||||
MantineProvider,
|
||||
} from "@mantine/core"
|
||||
import { theme } from "./theme"
|
||||
import "./globals.css"
|
||||
import { Notifications } from "@mantine/notifications"
|
||||
import { ModalsProvider } from "@mantine/modals"
|
||||
} from "@mantine/core";
|
||||
import { theme } from "@/theme";
|
||||
import "@/app/global.css";
|
||||
import { Notifications } from "@mantine/notifications";
|
||||
import ReduxProvider from "@/providers/ReduxProvider";
|
||||
import { ModalsProvider } from "@mantine/modals";
|
||||
import { modals } from "@/modals/modals";
|
||||
|
||||
export const metadata = {
|
||||
title: "Mantine Next.js template",
|
||||
description: "I am using Mantine with Next.js!",
|
||||
title: "CRM LogiDex",
|
||||
description: "CRM LogiDex",
|
||||
};
|
||||
|
||||
declare module "@mantine/modals" {
|
||||
export interface MantineModalsOverride {
|
||||
modals: typeof modals;
|
||||
}
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: { children: any }) {
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: Props) {
|
||||
return (
|
||||
<html lang="en" {...mantineHtmlProps}>
|
||||
<html
|
||||
lang="ru"
|
||||
{...mantineHtmlProps}>
|
||||
<head>
|
||||
<ColorSchemeScript />
|
||||
<link rel="shortcut icon" href="/favicon.svg" />
|
||||
<ColorSchemeScript defaultColorScheme={"auto"} />
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
href="/favicon.svg"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="global.css"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
|
||||
/>
|
||||
<title />
|
||||
</head>
|
||||
<body>
|
||||
<MantineProvider theme={theme}>
|
||||
<Notifications />
|
||||
<ModalsProvider>{children}</ModalsProvider>
|
||||
<MantineProvider
|
||||
theme={theme}
|
||||
defaultColorScheme={"auto"}>
|
||||
<ReduxProvider>
|
||||
<ModalsProvider
|
||||
labels={{ confirm: "Да", cancel: "Нет" }}
|
||||
modals={modals}>
|
||||
{children}
|
||||
</ModalsProvider>
|
||||
</ReduxProvider>
|
||||
<Notifications position="bottom-right" />
|
||||
</MantineProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,52 +1,11 @@
|
||||
import { ColorSchemesSwitcher } from "@/components/color-schemes-switcher"
|
||||
import {
|
||||
AppShell,
|
||||
AppShellHeader,
|
||||
AppShellMain,
|
||||
Text,
|
||||
Title,
|
||||
} from "@mantine/core"
|
||||
import { ColorSchemeToggle } from "@/components/ColorSchemeToggle/ColorSchemeToggle";
|
||||
import { Welcome } from "@/components/Welcome/Welcome";
|
||||
|
||||
export default function Home() {
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<AppShell header={{ height: 60 }} padding="md">
|
||||
<AppShellHeader></AppShellHeader>
|
||||
<AppShellMain>
|
||||
<Title className="text-center mt-20">
|
||||
Welcome to{" "}
|
||||
<Text
|
||||
inherit
|
||||
variant="gradient"
|
||||
component="span"
|
||||
gradient={{ from: "pink", to: "yellow" }}
|
||||
>
|
||||
Mantine
|
||||
</Text>{" "}
|
||||
+
|
||||
<Text
|
||||
inherit
|
||||
variant="gradient"
|
||||
component="span"
|
||||
gradient={{ from: "blue", to: "green" }}
|
||||
>
|
||||
TailwindCSS
|
||||
</Text>
|
||||
</Title>
|
||||
<Text
|
||||
className="text-bold text-center text-gray-700 dark:text-gray-300 max-w-[500px] mx-auto mt-xl"
|
||||
ta="center"
|
||||
size="lg"
|
||||
maw={580}
|
||||
mx="auto"
|
||||
mt="xl"
|
||||
>
|
||||
This starter Next.js project includes a minimal setup for
|
||||
Mantine with TailwindCSS. To get started edit page.tsx file.
|
||||
</Text>
|
||||
<div className="flex justify-center mt-10">
|
||||
<ColorSchemesSwitcher />
|
||||
</div>
|
||||
</AppShellMain>
|
||||
</AppShell>
|
||||
)
|
||||
<>
|
||||
<Welcome />
|
||||
<ColorSchemeToggle />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,133 +0,0 @@
|
||||
/** This file is autogenerated by the script. Do not edit it manually. */
|
||||
|
||||
|
||||
@theme {
|
||||
|
||||
|
||||
/* colors - all */
|
||||
|
||||
|
||||
/* colors - variant specific */
|
||||
|
||||
|
||||
/* breakpoints */
|
||||
--breakpoint-*: initial;
|
||||
--breakpoint-xs: 36em;
|
||||
--breakpoint-sm: 48em;
|
||||
--breakpoint-md: 62em;
|
||||
--breakpoint-lg: 75em;
|
||||
--breakpoint-xl: 88em;
|
||||
|
||||
/* readd back tailwind's default containers vars to fix #24 */
|
||||
--size-3xs: 16rem;
|
||||
--size-2xs: 18rem;
|
||||
--size-xs: 20rem;
|
||||
--size-sm: 24rem;
|
||||
--size-md: 28rem;
|
||||
--size-lg: 32rem;
|
||||
--size-xl: 36rem;
|
||||
--size-2xl: 42rem;
|
||||
--size-3xl: 48rem;
|
||||
--size-4xl: 56rem;
|
||||
--size-5xl: 64rem;
|
||||
--size-6xl: 72rem;
|
||||
--size-7xl: 80rem;
|
||||
|
||||
--container-3xs: var(--size-3xs);
|
||||
--container-2xs: var(--size-2xs);
|
||||
--container-xs: var(--size-xs);
|
||||
--container-sm: var(--size-sm);
|
||||
--container-md: var(--size-md);
|
||||
--container-lg: var(--size-lg);
|
||||
--container-xl: var(--size-xl);
|
||||
--container-2xl: var(--size-2xl);
|
||||
--container-3xl: var(--size-3xl);
|
||||
--container-4xl: var(--size-4xl);
|
||||
--container-5xl: var(--size-5xl);
|
||||
--container-6xl: var(--size-6xl);
|
||||
--container-7xl: var(--size-7xl);
|
||||
|
||||
--width-3xs: var(--size-3xs);
|
||||
--width-2xs: var(--size-2xs);
|
||||
--width-xs: var(--size-xs);
|
||||
--width-sm: var(--size-sm);
|
||||
--width-md: var(--size-md);
|
||||
--width-lg: var(--size-lg);
|
||||
--width-xl: var(--size-xl);
|
||||
--width-2xl: var(--size-2xl);
|
||||
--width-3xl: var(--size-3xl);
|
||||
--width-4xl: var(--size-4xl);
|
||||
--width-5xl: var(--size-5xl);
|
||||
--width-6xl: var(--size-6xl);
|
||||
--width-7xl: var(--size-7xl);
|
||||
|
||||
--min-width-3xs: var(--size-3xs);
|
||||
--min-width-2xs: var(--size-2xs);
|
||||
--min-width-xs: var(--size-xs);
|
||||
--min-width-sm: var(--size-sm);
|
||||
--min-width-md: var(--size-md);
|
||||
--min-width-lg: var(--size-lg);
|
||||
--min-width-xl: var(--size-xl);
|
||||
--min-width-2xl: var(--size-2xl);
|
||||
--min-width-3xl: var(--size-3xl);
|
||||
--min-width-4xl: var(--size-4xl);
|
||||
--min-width-5xl: var(--size-5xl);
|
||||
--min-width-6xl: var(--size-6xl);
|
||||
--min-width-7xl: var(--size-7xl);
|
||||
|
||||
--max-width-3xs: var(--size-3xs);
|
||||
--max-width-2xs: var(--size-2xs);
|
||||
--max-width-xs: var(--size-xs);
|
||||
--max-width-sm: var(--size-sm);
|
||||
--max-width-md: var(--size-md);
|
||||
--max-width-lg: var(--size-lg);
|
||||
--max-width-xl: var(--size-xl);
|
||||
--max-width-2xl: var(--size-2xl);
|
||||
--max-width-3xl: var(--size-3xl);
|
||||
--max-width-4xl: var(--size-4xl);
|
||||
--max-width-5xl: var(--size-5xl);
|
||||
--max-width-6xl: var(--size-6xl);
|
||||
--max-width-7xl: var(--size-7xl);
|
||||
|
||||
--height-3xs: var(--size-3xs);
|
||||
--height-2xs: var(--size-2xs);
|
||||
--height-xs: var(--size-xs);
|
||||
--height-sm: var(--size-sm);
|
||||
--height-md: var(--size-md);
|
||||
--height-lg: var(--size-lg);
|
||||
--height-xl: var(--size-xl);
|
||||
--height-2xl: var(--size-2xl);
|
||||
--height-3xl: var(--size-3xl);
|
||||
--height-4xl: var(--size-4xl);
|
||||
--height-5xl: var(--size-5xl);
|
||||
--height-6xl: var(--size-6xl);
|
||||
--height-7xl: var(--size-7xl);
|
||||
|
||||
--min-height-3xs: var(--size-3xs);
|
||||
--min-height-2xs: var(--size-2xs);
|
||||
--min-height-xs: var(--size-xs);
|
||||
--min-height-sm: var(--size-sm);
|
||||
--min-height-md: var(--size-md);
|
||||
--min-height-lg: var(--size-lg);
|
||||
--min-height-xl: var(--size-xl);
|
||||
--min-height-2xl: var(--size-2xl);
|
||||
--min-height-3xl: var(--size-3xl);
|
||||
--min-height-4xl: var(--size-4xl);
|
||||
--min-height-5xl: var(--size-5xl);
|
||||
--min-height-6xl: var(--size-6xl);
|
||||
--min-height-7xl: var(--size-7xl);
|
||||
|
||||
--max-height-3xs: var(--size-3xs);
|
||||
--max-height-2xs: var(--size-2xs);
|
||||
--max-height-xs: var(--size-xs);
|
||||
--max-height-sm: var(--size-sm);
|
||||
--max-height-md: var(--size-md);
|
||||
--max-height-lg: var(--size-lg);
|
||||
--max-height-xl: var(--size-xl);
|
||||
--max-height-2xl: var(--size-2xl);
|
||||
--max-height-3xl: var(--size-3xl);
|
||||
--max-height-4xl: var(--size-4xl);
|
||||
--max-height-5xl: var(--size-5xl);
|
||||
--max-height-6xl: var(--size-6xl);
|
||||
--max-height-7xl: var(--size-7xl);
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { createTheme } from "@mantine/core"
|
||||
|
||||
export const theme = createTheme({
|
||||
breakpoints: {
|
||||
xs: "36em",
|
||||
sm: "48em",
|
||||
md: "62em",
|
||||
lg: "75em",
|
||||
xl: "88em",
|
||||
},
|
||||
})
|
||||
|
||||
export default theme
|
||||
28
src/components/ColorSchemeToggle/ColorSchemeToggle.tsx
Normal file
28
src/components/ColorSchemeToggle/ColorSchemeToggle.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Group, useMantineColorScheme } from "@mantine/core";
|
||||
import { modals } from "@mantine/modals";
|
||||
|
||||
export function ColorSchemeToggle() {
|
||||
const { setColorScheme } = useMantineColorScheme();
|
||||
|
||||
const openTestModal = () => {
|
||||
modals.openContextModal({
|
||||
modal: "testModal",
|
||||
title: "Тест",
|
||||
withCloseButton: false,
|
||||
innerProps: {},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Group
|
||||
justify="center"
|
||||
mt="xl">
|
||||
<Button onClick={() => setColorScheme("light")}>Light</Button>
|
||||
<Button onClick={() => setColorScheme("dark")}>Dark</Button>
|
||||
<Button onClick={() => setColorScheme("auto")}>Auto</Button>
|
||||
<Button onClick={() => openTestModal()}>Modal</Button>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
31
src/components/Welcome/Welcome.tsx
Normal file
31
src/components/Welcome/Welcome.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Anchor, Text, Title } from "@mantine/core";
|
||||
|
||||
export function Welcome() {
|
||||
return (
|
||||
<>
|
||||
<Title
|
||||
ta="center"
|
||||
mt={100}
|
||||
className={"font-bold underline"}>
|
||||
Welcome to Mantine
|
||||
</Title>
|
||||
<Text
|
||||
c="dimmed"
|
||||
ta="center"
|
||||
size="lg"
|
||||
maw={580}
|
||||
mx="auto"
|
||||
mt="xl">
|
||||
This starter Next.js project includes a minimal setup for server
|
||||
side rendering, if you want to learn more on Mantine + Next.js
|
||||
integration follow{" "}
|
||||
<Anchor
|
||||
href="https://mantine.dev/guides/next/"
|
||||
size="lg">
|
||||
this guide
|
||||
</Anchor>
|
||||
. To get started edit page.tsx file.
|
||||
</Text>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Button, Group, useMantineColorScheme } from "@mantine/core"
|
||||
|
||||
export function ColorSchemesSwitcher() {
|
||||
const { setColorScheme, clearColorScheme } = useMantineColorScheme()
|
||||
|
||||
return (
|
||||
<Group>
|
||||
<Button variant={"filled"} onClick={() => setColorScheme("light")}>
|
||||
Light
|
||||
</Button>
|
||||
<Button onClick={() => setColorScheme("dark")}>Dark</Button>
|
||||
<Button onClick={() => setColorScheme("auto")}>Auto</Button>
|
||||
<Button onClick={clearColorScheme}>Clear</Button>
|
||||
</Group>
|
||||
)
|
||||
}
|
||||
23
src/lib/features/auth/authSlice.ts
Normal file
23
src/lib/features/auth/authSlice.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
interface AuthState {
|
||||
phoneNumber: string | null;
|
||||
}
|
||||
|
||||
const initialState: AuthState = {
|
||||
phoneNumber: null,
|
||||
};
|
||||
|
||||
export const authSlice = createSlice({
|
||||
name: "authentication",
|
||||
initialState,
|
||||
reducers: {
|
||||
setPhoneNumber: (state, action: PayloadAction<string | null>) => {
|
||||
state.phoneNumber = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setPhoneNumber } = authSlice.actions;
|
||||
|
||||
export default authSlice.reducer;
|
||||
8
src/lib/features/rootReducer.ts
Normal file
8
src/lib/features/rootReducer.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { combineReducers } from "@reduxjs/toolkit";
|
||||
import authReducer from "@/lib/features/auth/authSlice";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
auth: authReducer,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
1
src/lib/notifications/index.ts
Normal file
1
src/lib/notifications/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./notifications";
|
||||
46
src/lib/notifications/notifications.ts
Normal file
46
src/lib/notifications/notifications.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { notifications } from "@mantine/notifications";
|
||||
|
||||
type CustomNotifications = {
|
||||
notify: (...params: Parameters<typeof notifications.show>) => void;
|
||||
success: (...params: Parameters<typeof notifications.show>) => void;
|
||||
warn: (...params: Parameters<typeof notifications.show>) => void;
|
||||
error: (...params: Parameters<typeof notifications.show>) => void;
|
||||
guess: (
|
||||
ok: boolean,
|
||||
...params: Parameters<typeof notifications.show>
|
||||
) => void;
|
||||
} & typeof notifications;
|
||||
|
||||
const customNotifications: CustomNotifications = {
|
||||
...notifications,
|
||||
notify: params => {
|
||||
return notifications.show({
|
||||
...params,
|
||||
color: "blue",
|
||||
});
|
||||
},
|
||||
success: params => {
|
||||
return notifications.show({
|
||||
...params,
|
||||
color: "green",
|
||||
});
|
||||
},
|
||||
warn: params => {
|
||||
return notifications.show({
|
||||
...params,
|
||||
color: "yellow",
|
||||
});
|
||||
},
|
||||
error: params => {
|
||||
return notifications.show({
|
||||
...params,
|
||||
color: "red",
|
||||
});
|
||||
},
|
||||
guess: (ok: boolean, params) => {
|
||||
if (ok) return customNotifications.success(params);
|
||||
return customNotifications.error(params);
|
||||
},
|
||||
};
|
||||
|
||||
export { customNotifications as notifications };
|
||||
28
src/lib/store.ts
Normal file
28
src/lib/store.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { persistReducer, persistStore } from "redux-persist";
|
||||
import storage from "redux-persist/lib/storage";
|
||||
import rootReducer from "@/lib/features/rootReducer";
|
||||
|
||||
const persistConfig = {
|
||||
key: "root",
|
||||
storage,
|
||||
whitelist: ["targetService", "verification", "auth"],
|
||||
};
|
||||
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: persistedReducer,
|
||||
middleware: getDefaultMiddleware =>
|
||||
getDefaultMiddleware({
|
||||
serializableCheck: false,
|
||||
}),
|
||||
});
|
||||
|
||||
export const persistor = persistStore(store);
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
|
||||
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
||||
16
src/modals/TestModal/TestModal.tsx
Normal file
16
src/modals/TestModal/TestModal.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
"use client"
|
||||
|
||||
import { Flex, rem, Text } from "@mantine/core";
|
||||
import { ContextModalProps } from "@mantine/modals";
|
||||
|
||||
const TestModal = ({ id, context, innerProps }: ContextModalProps) => {
|
||||
return (
|
||||
<Flex
|
||||
gap={rem(10)}
|
||||
direction={"column"}>
|
||||
<Text>Hi</Text>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default TestModal;
|
||||
5
src/modals/modals.ts
Normal file
5
src/modals/modals.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import TestModal from "@/modals/TestModal/TestModal";
|
||||
|
||||
export const modals = {
|
||||
testModal: TestModal,
|
||||
};
|
||||
23
src/providers/ReduxProvider.tsx
Normal file
23
src/providers/ReduxProvider.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { Provider } from "react-redux";
|
||||
import { PersistGate } from "redux-persist/integration/react";
|
||||
import { persistor, store } from "@/lib/store";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function ReduxProvider({ children }: Props) {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
{" "}
|
||||
<PersistGate
|
||||
loading={null}
|
||||
persistor={persistor}>
|
||||
{children}
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
5
src/redux-persist.d.ts
vendored
Normal file
5
src/redux-persist.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare module "redux-persist/lib/storage" {
|
||||
import { WebStorage } from "redux-persist/es/types";
|
||||
const localStorage: WebStorage;
|
||||
export default localStorage;
|
||||
}
|
||||
43
src/theme.ts
Normal file
43
src/theme.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { createTheme, MantineColorsTuple } from "@mantine/core";
|
||||
|
||||
export const myColor: MantineColorsTuple = [
|
||||
"#e2faff",
|
||||
"#d4eff8",
|
||||
"#afdce9",
|
||||
"#87c8db",
|
||||
"#65b7cf",
|
||||
"#4aaac7",
|
||||
"#3fa7c6",
|
||||
"#2c92af",
|
||||
"#1b829e",
|
||||
"#00718c",
|
||||
];
|
||||
|
||||
const radius = "lg";
|
||||
const size = "lg";
|
||||
|
||||
export const theme = createTheme({
|
||||
colors: {
|
||||
myColor,
|
||||
},
|
||||
primaryColor: "myColor",
|
||||
components: {
|
||||
Button: {
|
||||
defaultProps: {
|
||||
radius,
|
||||
size,
|
||||
},
|
||||
},
|
||||
InputBase: {
|
||||
defaultProps: {
|
||||
radius,
|
||||
size,
|
||||
},
|
||||
},
|
||||
Modal: {
|
||||
defaultProps: {
|
||||
radius,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -1,28 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
"compilerOptions": {
|
||||
"types": ["node", "jest", "@testing-library/jest-dom"],
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"plugins": [{ "name": "next" }]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user