[chapter3]: add config
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
public
|
||||||
|
node_modules
|
||||||
|
src/database/migrations
|
||||||
|
pnpm-lock.yaml
|
||||||
|
package-lock.json
|
||||||
|
docker
|
||||||
|
Dockerfile*
|
||||||
|
LICENSE
|
||||||
|
yarn-error.log
|
||||||
|
.next
|
||||||
|
.history
|
||||||
|
.dockerignore
|
||||||
|
.DS_Store
|
||||||
|
.eslintignore
|
||||||
|
.editorconfig
|
||||||
|
.gitignore
|
||||||
|
.prettierignore
|
||||||
|
.eslintcache
|
||||||
|
*.lock
|
||||||
|
*.png
|
||||||
|
*.jpg
|
||||||
|
*.jpeg
|
||||||
|
*.eot
|
||||||
|
*.ttf
|
||||||
|
*.woff
|
||||||
|
*.sql
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
const config = {
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'all',
|
||||||
|
printWidth: 100,
|
||||||
|
proseWrap: 'never',
|
||||||
|
endOfLine: 'auto',
|
||||||
|
semi: true,
|
||||||
|
tabWidth: 4,
|
||||||
|
htmlWhitespaceSensitivity: 'strict',
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
|
"style": "radix-nova",
|
||||||
|
"rsc": true,
|
||||||
|
"tsx": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "",
|
||||||
|
"css": "src/app/styles/tailwind.css",
|
||||||
|
"baseColor": "neutral",
|
||||||
|
"cssVariables": true,
|
||||||
|
"prefix": "tw"
|
||||||
|
},
|
||||||
|
"iconLibrary": "lucide",
|
||||||
|
"rtl": false,
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/app/_components/shadcn/ui",
|
||||||
|
"utils": "@/app/_components/shadcn/libs/utils",
|
||||||
|
"ui": "@/app/_components/shadcn/ui",
|
||||||
|
"lib": "@/app/_components/shadcn/libs",
|
||||||
|
"hooks": "@/app/_components/shadcn/hooks"
|
||||||
|
},
|
||||||
|
"menuColor": "default",
|
||||||
|
"menuAccent": "subtle",
|
||||||
|
"registries": {}
|
||||||
|
}
|
||||||
@@ -9,18 +9,40 @@
|
|||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"lodash": "^4.18.1",
|
||||||
"next": "16.3.3",
|
"next": "16.3.3",
|
||||||
"react": "19.2.8",
|
"react": "19.2.8",
|
||||||
"react-dom": "19.2.8"
|
"react-dom": "19.2.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@antfu/eslint-config": "^9.3.0",
|
||||||
|
"@eslint-react/eslint-plugin": "^5.18.6",
|
||||||
|
"@eslint/eslintrc": "^3.3.6",
|
||||||
|
"@next/eslint-plugin-next": "^16.3.3",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/lodash": "^4.17.25",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"babel-plugin-react-compiler": "1.0.0",
|
"babel-plugin-react-compiler": "1.0.0",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "16.3.3",
|
"eslint-config-next": "16.3.3",
|
||||||
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||||
|
"eslint-plugin-perfectionist": "^5.10.1",
|
||||||
|
"eslint-plugin-prettier": "^5.5.6",
|
||||||
|
"eslint-plugin-react": "^7.37.5",
|
||||||
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
|
"eslint-plugin-react-refresh": "^0.5.5",
|
||||||
|
"eslint-plugin-unused-imports": "^4.4.1",
|
||||||
|
"prettier": "^3.9.6",
|
||||||
|
"rimraf": "^6.1.3",
|
||||||
|
"stylelint": "^17.14.1",
|
||||||
|
"stylelint-config-css-modules": "^4.6.0",
|
||||||
|
"stylelint-config-recess-order": "^7.8.0",
|
||||||
|
"stylelint-config-standard": "^40.0.0",
|
||||||
|
"stylelint-prettier": "^5.0.3",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+3147
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
import { Slot } from "radix-ui"
|
||||||
|
|
||||||
|
import { cn } from "@/app/_components/shadcn/libs/utils"
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"tw:group/button tw:inline-flex tw:shrink-0 tw:items-center tw:justify-center tw:rounded-lg tw:border tw:border-transparent tw:bg-clip-padding tw:text-sm tw:font-medium tw:whitespace-nowrap tw:transition-all tw:outline-none tw:select-none tw:focus-visible:border-ring tw:focus-visible:ring-3 tw:focus-visible:ring-ring/50 tw:active:not-aria-[haspopup]:translate-y-px tw:disabled:pointer-events-none tw:disabled:opacity-50 tw:aria-invalid:border-destructive tw:aria-invalid:ring-3 tw:aria-invalid:ring-destructive/20 tw:dark:aria-invalid:border-destructive/50 tw:dark:aria-invalid:ring-destructive/40 tw:[&_svg]:pointer-events-none tw:[&_svg]:shrink-0 tw:[&_svg:not([class*=size-])]:size-4",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "tw:bg-primary tw:text-primary-foreground tw:hover:bg-primary/80",
|
||||||
|
outline:
|
||||||
|
"tw:border-border tw:bg-background tw:hover:bg-muted tw:hover:text-foreground tw:aria-expanded:bg-muted tw:aria-expanded:text-foreground tw:dark:border-input tw:dark:bg-input/30 tw:dark:hover:bg-input/50",
|
||||||
|
secondary:
|
||||||
|
"tw:bg-secondary tw:text-secondary-foreground tw:hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] tw:aria-expanded:bg-secondary tw:aria-expanded:text-secondary-foreground",
|
||||||
|
ghost:
|
||||||
|
"tw:hover:bg-muted tw:hover:text-foreground tw:aria-expanded:bg-muted tw:aria-expanded:text-foreground tw:dark:hover:bg-muted/50",
|
||||||
|
destructive:
|
||||||
|
"tw:bg-destructive/10 tw:text-destructive tw:hover:bg-destructive/20 tw:focus-visible:border-destructive/40 tw:focus-visible:ring-destructive/20 tw:dark:bg-destructive/20 tw:dark:hover:bg-destructive/30 tw:dark:focus-visible:ring-destructive/40",
|
||||||
|
link: "tw:text-primary tw:underline-offset-4 tw:hover:underline",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default:
|
||||||
|
"tw:h-8 tw:gap-1.5 tw:px-2.5 tw:has-data-[icon=inline-end]:pr-2 tw:has-data-[icon=inline-start]:pl-2",
|
||||||
|
xs: "tw:h-6 tw:gap-1 tw:rounded-[min(var(--radius-md),10px)] tw:px-2 tw:text-xs tw:in-data-[slot=button-group]:rounded-lg tw:has-data-[icon=inline-end]:pr-1.5 tw:has-data-[icon=inline-start]:pl-1.5 tw:[&_svg:not([class*=size-])]:size-3",
|
||||||
|
sm: "tw:h-7 tw:gap-1 tw:rounded-[min(var(--radius-md),12px)] tw:px-2.5 tw:text-[0.8rem] tw:in-data-[slot=button-group]:rounded-lg tw:has-data-[icon=inline-end]:pr-1.5 tw:has-data-[icon=inline-start]:pl-1.5 tw:[&_svg:not([class*=size-])]:size-3.5",
|
||||||
|
lg: "tw:h-9 tw:gap-1.5 tw:px-2.5 tw:has-data-[icon=inline-end]:pr-2 tw:has-data-[icon=inline-start]:pl-2",
|
||||||
|
icon: "tw:size-8",
|
||||||
|
"icon-xs":
|
||||||
|
"tw:size-6 tw:rounded-[min(var(--radius-md),10px)] tw:in-data-[slot=button-group]:rounded-lg tw:[&_svg:not([class*=size-])]:size-3",
|
||||||
|
"icon-sm":
|
||||||
|
"tw:size-7 tw:rounded-[min(var(--radius-md),12px)] tw:in-data-[slot=button-group]:rounded-lg",
|
||||||
|
"icon-lg": "tw:size-9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function Button({
|
||||||
|
className,
|
||||||
|
variant = "default",
|
||||||
|
size = "default",
|
||||||
|
asChild = false,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"button"> &
|
||||||
|
VariantProps<typeof buttonVariants> & {
|
||||||
|
asChild?: boolean
|
||||||
|
}) {
|
||||||
|
const Comp = asChild ? Slot.Root : "button"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
data-slot="button"
|
||||||
|
data-variant={variant}
|
||||||
|
data-size={size}
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Button, buttonVariants }
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/app/_components/shadcn/libs/utils"
|
||||||
|
|
||||||
|
function Card({
|
||||||
|
className,
|
||||||
|
size = "default",
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card"
|
||||||
|
data-size={size}
|
||||||
|
className={cn(
|
||||||
|
"tw:group/card tw:flex tw:flex-col tw:gap-(--card-spacing) tw:overflow-hidden tw:rounded-xl tw:bg-card tw:py-(--card-spacing) tw:text-sm tw:text-card-foreground tw:ring-1 tw:ring-foreground/10 tw:[--card-spacing:--spacing(4)] tw:has-data-[slot=card-footer]:pb-0 tw:has-[>img:first-child]:pt-0 tw:data-[size=sm]:[--card-spacing:--spacing(3)] tw:data-[size=sm]:has-data-[slot=card-footer]:pb-0 tw:*:[img:first-child]:rounded-t-xl tw:*:[img:last-child]:rounded-b-xl",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-header"
|
||||||
|
className={cn(
|
||||||
|
"tw:group/card-header tw:@container/card-header tw:grid tw:auto-rows-min tw:items-start tw:gap-1 tw:rounded-t-xl tw:px-(--card-spacing) tw:has-data-[slot=card-action]:grid-cols-[1fr_auto] tw:has-data-[slot=card-description]:grid-rows-[auto_auto] tw:[.border-b]:pb-(--card-spacing)",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-title"
|
||||||
|
className={cn(
|
||||||
|
"tw: tw:text-base tw:leading-snug tw:font-medium tw:group-data-[size=sm]/card:text-sm",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-description"
|
||||||
|
className={cn("tw:text-sm tw:text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-action"
|
||||||
|
className={cn(
|
||||||
|
"tw:col-start-2 tw:row-span-2 tw:row-start-1 tw:self-start tw:justify-self-end",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-content"
|
||||||
|
className={cn("tw:px-(--card-spacing)", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-footer"
|
||||||
|
className={cn(
|
||||||
|
"tw:flex tw:items-center tw:rounded-b-xl tw:border-t tw:bg-muted/50 tw:p-(--card-spacing)",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardAction,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/** @type {import('stylelint').Config} */
|
||||||
|
const stylelintConfig = {
|
||||||
|
extends: [
|
||||||
|
'stylelint-config-standard',
|
||||||
|
'stylelint-config-css-modules',
|
||||||
|
'stylelint-config-recess-order',
|
||||||
|
'stylelint-prettier/recommended',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'import-notation': 'string', // 使用string方式引入其它css文件,而不是url()
|
||||||
|
'selector-type-no-unknown': null,
|
||||||
|
'selector-class-pattern': null,
|
||||||
|
'custom-property-pattern': null,
|
||||||
|
'no-duplicate-selectors': null, // 取消禁止重复定义,这样可以在css module中单独定义变量
|
||||||
|
'block-no-empty': null, // 禁止出现空块
|
||||||
|
'declaration-empty-line-before': 'never',
|
||||||
|
'declaration-block-no-duplicate-properties': true, // 在声明的块中中禁止出现重复的属性
|
||||||
|
'declaration-block-no-redundant-longhand-properties': true, // 禁止使用可以缩写却不缩写的属性
|
||||||
|
'shorthand-property-no-redundant-values': true, // 禁止在简写属性中使用冗余值
|
||||||
|
'color-hex-length': 'short', // 指定十六进制颜色是否使用缩写
|
||||||
|
'comment-no-empty': true, // 禁止空注释
|
||||||
|
'font-family-name-quotes': 'always-unless-keyword', // 指定字体名称是否需要使用引号引起来 | 期待每一个不是关键字的字体名都使用引号引起来
|
||||||
|
// 'font-weight-notation': 'numeric', // 要求使用数字或命名的 (可能的情况下) font-weight 值
|
||||||
|
'function-url-quotes': 'always', // 要求或禁止 url 使用引号
|
||||||
|
'property-no-vendor-prefix': true, // 禁止属性使用浏览器引擎前缀
|
||||||
|
'value-no-vendor-prefix': true, // 禁止给值添加浏览器引擎前缀
|
||||||
|
'selector-no-vendor-prefix': true, // 禁止使用浏览器引擎前缀
|
||||||
|
'no-descending-specificity': null, // 禁止低优先级的选择器出现在高优先级的选择器之后
|
||||||
|
'at-rule-no-deprecated': null, // 禁止使用未知指令报错
|
||||||
|
'at-rule-no-unknown': null, // 禁止使用未知指令报错
|
||||||
|
'property-no-unknown': [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
ignoreProperties: [
|
||||||
|
// CSS Modules composition
|
||||||
|
// https://github.com/css-modules/css-modules#composition
|
||||||
|
'composes',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'selector-pseudo-class-no-unknown': [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
ignorePseudoClasses: [
|
||||||
|
// CSS Modules :global scope
|
||||||
|
// https://github.com/css-modules/css-modules#exceptions
|
||||||
|
'global',
|
||||||
|
'local',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'rule-empty-line-before': [
|
||||||
|
// 要求或禁止在规则声明之前有空行
|
||||||
|
'always-multi-line',
|
||||||
|
{
|
||||||
|
except: ['first-nested'],
|
||||||
|
ignore: ['after-comment'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'at-rule-empty-line-before': [
|
||||||
|
// 要求或禁止在 at 规则之前有空行
|
||||||
|
'always',
|
||||||
|
{
|
||||||
|
except: ['blockless-after-same-name-blockless', 'first-nested'],
|
||||||
|
ignore: ['after-comment'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'comment-empty-line-before': [
|
||||||
|
// 要求或禁止在注释之前有空行
|
||||||
|
'always',
|
||||||
|
{
|
||||||
|
except: ['first-nested'],
|
||||||
|
ignore: ['stylelint-commands'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
ignoreFiles: [
|
||||||
|
'public',
|
||||||
|
'node_modules',
|
||||||
|
'build',
|
||||||
|
'.history',
|
||||||
|
'.next',
|
||||||
|
'**/*.js',
|
||||||
|
'**/*.jsx',
|
||||||
|
'**/*.tsx',
|
||||||
|
'**/*.ts',
|
||||||
|
'**/*.json',
|
||||||
|
'**/*.md',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default stylelintConfig;
|
||||||
Reference in New Issue
Block a user