init
This commit is contained in:
commit
688c77d90a
4
.env
Normal file
4
.env
Normal file
@ -0,0 +1,4 @@
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXTAUTH_SECRET=changeit
|
||||
RUN_ADMIN_USER_SEED=true
|
||||
RUN_DB_MIGRATIONS=true
|
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
.idea/
|
||||
.vscode/
|
||||
node_modules/
|
||||
build/
|
||||
tmp/
|
||||
temp/
|
||||
.next
|
||||
.env.local
|
||||
!.vscode
|
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
.next
|
||||
node_modules
|
||||
*.ico
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none"
|
||||
}
|
28
.vscode/launch.json
vendored
Normal file
28
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Next.js: debug server-side",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "npm run dev"
|
||||
},
|
||||
{
|
||||
"name": "Next.js: debug client-side",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:3000"
|
||||
},
|
||||
{
|
||||
"name": "Next.js: debug full stack",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "npm run dev",
|
||||
"serverReadyAction": {
|
||||
"pattern": "- Local:.+(https?://.+)",
|
||||
"uriFormat": "%s",
|
||||
"action": "debugWithChrome"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
36
README.md
Normal file
36
README.md
Normal file
@ -0,0 +1,36 @@
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
20
jest.config.json
Normal file
20
jest.config.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"testPathIgnorePatterns": ["node_modules", "tests"],
|
||||
"collectCoverage": true,
|
||||
"collectCoverageFrom": [
|
||||
"**/*.ts",
|
||||
"!**/cli-tools/*",
|
||||
"!**/*.config.js",
|
||||
"!**/*.spec.ts",
|
||||
"!**/lcov-report/*",
|
||||
"!**/node_modules/**",
|
||||
"!**/tests/*"
|
||||
],
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"branches": 50,
|
||||
"functions": 40,
|
||||
"lines": 70
|
||||
}
|
||||
}
|
||||
}
|
5
next-env.d.ts
vendored
Normal file
5
next-env.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
25
next.config.js
Normal file
25
next.config.js
Normal file
@ -0,0 +1,25 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true,
|
||||
experimental: {
|
||||
instrumentationHook: true
|
||||
},
|
||||
modularizeImports: {
|
||||
'@mui/icons-material': {
|
||||
transform: '@mui/icons-material/{{member}}'
|
||||
}
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: 'https',
|
||||
hostname: 'source.unsplash.com',
|
||||
port: '',
|
||||
pathname: '/random'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
9843
package-lock.json
generated
Normal file
9843
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
41
package.json
Normal file
41
package.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "nextjs-mui-starter",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint && prettier .",
|
||||
"lint:fix": "next lint --fix && prettier --write .",
|
||||
"generate:migrations": "drizzle-kit generate:sqlite --config=./src/db/drizzle.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@casl/ability": "^6.5.0",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@fontsource/roboto": "^5.0.8",
|
||||
"@mui/icons-material": "^6.0.0",
|
||||
"@mui/material": "^6.0.0",
|
||||
"argon2": "^0.41.0",
|
||||
"better-sqlite3": "^11.0.0",
|
||||
"drizzle-orm": "^0.39.0",
|
||||
"next-auth": "^4.24.5",
|
||||
"pino": "^9.0.0",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/better-sqlite3": "^7.6.8",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"drizzle-kit": "^0.30.0",
|
||||
"eslint": "^9.0.0",
|
||||
"eslint-config-next": "15.1.7",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.1.0",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
5
renovate.json
Normal file
5
renovate.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:recommended"],
|
||||
"automerge": true
|
||||
}
|
BIN
src/app/favicon.ico
Normal file
BIN
src/app/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
45
src/app/layout.tsx
Normal file
45
src/app/layout.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import * as React from 'react'
|
||||
import Link from 'next/link'
|
||||
import AppBar from '@mui/material/AppBar'
|
||||
import Box from '@mui/material/Box'
|
||||
import Drawer from '@mui/material/Drawer'
|
||||
import Toolbar from '@mui/material/Toolbar'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Divider from '@mui/material/Divider'
|
||||
import List from '@mui/material/List'
|
||||
import ListItem from '@mui/material/ListItem'
|
||||
import ListItemButton from '@mui/material/ListItemButton'
|
||||
import ListItemIcon from '@mui/material/ListItemIcon'
|
||||
import ListItemText from '@mui/material/ListItemText'
|
||||
import DashboardIcon from '@mui/icons-material/Dashboard'
|
||||
import HomeIcon from '@mui/icons-material/Home'
|
||||
import UsersIcon from '@mui/icons-material/People'
|
||||
import ThemeRegistry from '@/components/ThemeRegistry/ThemeRegistry'
|
||||
|
||||
export const metadata = {
|
||||
title: 'Next.js MUI Starter Template',
|
||||
description: 'Next.js App Router + Material UI v5 Starter Template'
|
||||
}
|
||||
|
||||
const DRAWER_WIDTH = 240
|
||||
|
||||
const LINKS = [
|
||||
{ text: 'Home', href: '/', icon: HomeIcon },
|
||||
{ text: 'Users', href: '/users', icon: UsersIcon }
|
||||
]
|
||||
|
||||
export default function RootLayout({
|
||||
children
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<ThemeRegistry>
|
||||
{children}
|
||||
</ThemeRegistry>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
9
src/app/page.tsx
Normal file
9
src/app/page.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import * as React from 'react'
|
||||
import Box from '@mui/material/Box';
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<Box sx={{ display: 'flex' }}>
|
||||
</Box>
|
||||
)
|
||||
}
|
99
src/components/ThemeRegistry/EmotionCache.tsx
Normal file
99
src/components/ThemeRegistry/EmotionCache.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
'use client'
|
||||
import * as React from 'react'
|
||||
import createCache from '@emotion/cache'
|
||||
import { useServerInsertedHTML } from 'next/navigation'
|
||||
import { CacheProvider as DefaultCacheProvider } from '@emotion/react'
|
||||
import type {
|
||||
EmotionCache,
|
||||
Options as OptionsOfCreateCache
|
||||
} from '@emotion/cache'
|
||||
|
||||
export type NextAppDirEmotionCacheProviderProps = {
|
||||
/** This is the options passed to createCache() from 'import createCache from "@emotion/cache"' */
|
||||
options: Omit<OptionsOfCreateCache, 'insertionPoint'>
|
||||
/** By default <CacheProvider /> from 'import { CacheProvider } from "@emotion/react"' */
|
||||
CacheProvider?: (props: {
|
||||
value: EmotionCache
|
||||
children: React.ReactNode
|
||||
}) => React.JSX.Element | null
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/garronej/tss-react/blob/main/src/next/appDir.tsx
|
||||
export default function NextAppDirEmotionCacheProvider(
|
||||
props: NextAppDirEmotionCacheProviderProps
|
||||
) {
|
||||
const { options, CacheProvider = DefaultCacheProvider, children } = props
|
||||
|
||||
const [registry] = React.useState(() => {
|
||||
const cache = createCache(options)
|
||||
cache.compat = true
|
||||
const prevInsert = cache.insert
|
||||
let inserted: { name: string; isGlobal: boolean }[] = []
|
||||
cache.insert = (...args) => {
|
||||
const [selector, serialized] = args
|
||||
if (cache.inserted[serialized.name] === undefined) {
|
||||
inserted.push({
|
||||
name: serialized.name,
|
||||
isGlobal: !selector
|
||||
})
|
||||
}
|
||||
return prevInsert(...args)
|
||||
}
|
||||
const flush = () => {
|
||||
const prevInserted = inserted
|
||||
inserted = []
|
||||
return prevInserted
|
||||
}
|
||||
return { cache, flush }
|
||||
})
|
||||
|
||||
useServerInsertedHTML(() => {
|
||||
const inserted = registry.flush()
|
||||
if (inserted.length === 0) {
|
||||
return null
|
||||
}
|
||||
let styles = ''
|
||||
let dataEmotionAttribute = registry.cache.key
|
||||
|
||||
const globals: {
|
||||
name: string
|
||||
style: string
|
||||
}[] = []
|
||||
|
||||
inserted.forEach(({ name, isGlobal }) => {
|
||||
const style = registry.cache.inserted[name]
|
||||
|
||||
if (typeof style !== 'boolean') {
|
||||
if (isGlobal) {
|
||||
globals.push({ name, style })
|
||||
} else {
|
||||
styles += style
|
||||
dataEmotionAttribute += ` ${name}`
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{globals.map(({ name, style }) => (
|
||||
<style
|
||||
key={name}
|
||||
data-emotion={`${registry.cache.key}-global ${name}`}
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{ __html: style }}
|
||||
/>
|
||||
))}
|
||||
{styles && (
|
||||
<style
|
||||
data-emotion={dataEmotionAttribute}
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{ __html: styles }}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
|
||||
return <CacheProvider value={registry.cache}>{children}</CacheProvider>
|
||||
}
|
22
src/components/ThemeRegistry/ThemeRegistry.tsx
Normal file
22
src/components/ThemeRegistry/ThemeRegistry.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
'use client'
|
||||
import * as React from 'react'
|
||||
import { ThemeProvider } from '@mui/material/styles'
|
||||
import CssBaseline from '@mui/material/CssBaseline'
|
||||
import NextAppDirEmotionCacheProvider from './EmotionCache'
|
||||
import theme from './theme'
|
||||
|
||||
export default function ThemeRegistry({
|
||||
children
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<NextAppDirEmotionCacheProvider options={{ key: 'mui' }}>
|
||||
<ThemeProvider theme={theme}>
|
||||
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
|
||||
<CssBaseline />
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</NextAppDirEmotionCacheProvider>
|
||||
)
|
||||
}
|
30
src/components/ThemeRegistry/theme.ts
Normal file
30
src/components/ThemeRegistry/theme.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Roboto } from 'next/font/google'
|
||||
import { createTheme } from '@mui/material/styles'
|
||||
|
||||
const roboto = Roboto({
|
||||
weight: ['300', '400', '500', '700'],
|
||||
subsets: ['latin'],
|
||||
display: 'swap'
|
||||
})
|
||||
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
mode: 'dark'
|
||||
},
|
||||
typography: {
|
||||
fontFamily: roboto.style.fontFamily
|
||||
},
|
||||
components: {
|
||||
MuiAlert: {
|
||||
styleOverrides: {
|
||||
root: ({ ownerState }) => ({
|
||||
...(ownerState.severity === 'info' && {
|
||||
backgroundColor: '#60a5fa'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default theme
|
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user