Compare commits

..
3 Commits
Author SHA1 Message Date
jiawei 7b03222922 fix(chapter2): align shadcn button with Tailwind prefix
Configure shadcn aliases and regenerate the Button component with the tw: utility prefix so its styles are emitted by Tailwind.
2026-08-30 10:26:59 +08:00
jiawei a1401c68f5 feat(chapter2): set up styled app shell
Add the App Router page and nested layout, configure Tailwind and shadcn styling, include local fonts and background assets, and install the supporting UI and lint dependencies.
2026-08-30 10:20:06 +08:00
jiawei 5ce6f24569 chore(chapter2): configure compatible lint tooling
Use the Next.js-compatible ESLint 9 toolchain, add CSS linting scripts and dependencies, and export the Stylelint config through a named constant.
2026-08-30 00:06:40 +08:00
38 changed files with 17402 additions and 124 deletions
+26
View File
@@ -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
+11
View File
@@ -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;
+25
View File
@@ -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": {}
}
+36 -6
View File
@@ -3,26 +3,56 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"dev": "rimraf .next && next dev --turbopack",
"build": "rimraf .next && next build",
"start": "next start",
"lint": "eslint"
"lint": "pnpm lint:es && pnpm lint:style",
"lint:es": "eslint . --fix",
"lint:style": "stylelint \"**/*.css\" --fix --cache --cache-location node_modules/.cache/stylelint"
},
"dependencies": {
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.37.0",
"next": "16.3.3",
"radix-ui": "^1.6.7",
"react": "19.2.8",
"react-dom": "19.2.8"
"react-dom": "19.2.8",
"shadcn": "^4.19.0",
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0"
},
"devDependencies": {
"@eslint-react/eslint-plugin": "^5.18.6",
"@eslint/eslintrc": "^3.3.6",
"@next/eslint-plugin-next": "^16.3.3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"babel-plugin-react-compiler": "1.0.0",
"eslint": "^9",
"eslint": "^9.39.5",
"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",
"typescript": "^5"
},
"packageManager": "pnpm@10.34.5"
"packageManager": "pnpm@10.34.5",
"imports": {
"#tailwind.css": "./src/app/styles/tailwind.css"
}
}
+4514 -1
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
/* src/app/(pages)/layout.module.css */
@reference "#tailwind.css";
.layout {
@apply tw:min-h-full tw:w-full tw:flex tw:flex-col tw:bg-background tw:bg-cover tw:bg-fixed tw:bg-center tw:bg-no-repeat tw:bg-[url('../styles/images/bg-light.png')] tw:p-0 tw:m-0;
html.dark &,
html[data-theme='dark'] & {
background-image: url('../styles/images/bg-dark.png');
}
}
+19
View File
@@ -0,0 +1,19 @@
// src/app/(pages)/layout.tsx
import type { Metadata } from 'next';
import type { FC, PropsWithChildren } from 'react';
import { Header } from '../_components/header';
import $styles from './layout.module.css';
export const metadata: Metadata = {
title: 'pincman的博客',
description:
'pincman的个人博客,提供一些ts、react、node.js、php、golang相关的技术文档以及分享一些生活琐事',
};
const AppLayout: FC<PropsWithChildren> = ({ children }) => (
<div className={$styles.layout}>
<Header />
{children}
</div>
);
export default AppLayout;
+9
View File
@@ -0,0 +1,9 @@
/* src/app/(pages)/page.module.css */
@reference "#tailwind.css";
.block {
@apply tw:page-container tw:flex tw:flex-col tw:flex-none! tw:w-full tw:space-y-4 tw:p-5 tw:items-center tw:justify-center
tw:rounded-sm tw:backdrop-blur-sm tw:shadow-nysm tw:shadow-neutral-800 tw:duration-300
tw:text-lg tw:text-center tw:text-white tw:bg-black/30
tw:hover:shadow-nylg tw:font-lxgw;
}
+22
View File
@@ -0,0 +1,22 @@
// src/app/(pages)/page.tsx
import { FC } from 'react';
import { ArrowBigRight } from 'lucide-react';
import Link from 'next/link';
import $styles from './page.module.css';
import { Button } from '../_components/shadcn/ui/button';
const App: FC = () => (
<main className={$styles.container}>
<div className={$styles.block}>
欢迎来到3R教室,这是Nextjs课程的开始
<Button asChild>
<Link href="https://3rcd.com" target="_blank">
<ArrowBigRight /> 查看官网
</Link>
</Button>
</div>
</main>
);
export default App;
@@ -0,0 +1 @@
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 801 802"><defs><style>.cls-1{fill:#fff;}.cls-1,.cls-2{stroke:#000;stroke-miterlimit:10;}.cls-2{fill:#224740;}</style></defs><rect class="cls-1" x="0.5" y="0.5" width="800" height="801"/><path class="cls-2" d="M255.61,517.24,182.5,569.53c-16.57,13.4-68.15,8.09-74.37-.12-8.7-11.49-23.82-26.39-14-35.29s37.18-8.36,37.18-8.36l30.06-.58s19.51-4,27.92-4.89c11.23-1.23,13-3.43,10.56-5.93-.67.24-.48-.48-.48-.48-5.6-4.86-25.35-10.58-22.23-12.31l62-52.44c-1.87,1.12-163.29,65.48-163.29,65.48L62.67,526.27s-2.17-1.48-20.75,27.34c-2.5,3.88,37.87,28.51,37.87,28.51C209.06,671.81,328.12,475,353.3,420.12l-.24-2.29,5.15-5.58c18.53,15.86,32.57,37.32,45.87,45.14,20.4,12-.15-8.39,38.94,24.3s39.47,148.93,36.6,175.53-29.74,29.64-29.74,29.64,9.93-28.87,7.36-78.72c-2.57-49.16-81.43-51.44-83.41-51.51C471,602.21,394,738.52,394,738.52s35,4.34,93.39-56.92-25.93-226.14-20.1-253.09c2.69-12.37,95.24-19.54,95.24-19.54s117.86,1.61,120.76,5.78c5.4,7.7,9.11,22.5,4.08,46.84-5,23.83-78.09,90.15-81.16,93,2.29-.59,39.63-11.61,96.61-69.39,58.81-59.69-1.66-127.51-58.34-103.49S528,381.27,528,381.27c-7.7-8.51-11.89-18.92-13.46-30.47h0l-27.48-5.14,27.46-18.19h0c7.21-63.27,66.28-143.75,74.05-152.62,10.38-11.8,15.63-11.29,7.31-23-6.65-9.35-3-12.33-.71-13.37l.64-.2c-9.26,2.67-52.44,13.88-116.82,11.24-72-2.92-111-84.78-112-87.12l-2.21-2.86s-38.57,66-12.6,108.84c20.18,33.3,153.43,44.76,153.43,44.76s.82,14.78-9.7,21.19-32.69-2.77-72.55-15.43l-8.88-1.7c-11.23-1.51-36.36-13.58-64-40.62l-26.19,218,5.65,18-67.34,97.66c-2.6,2.47-2.6,2.47-6.91,7m68.6-122.67M407,285.14s13.38-5.44,25.85.58,19.25,21.2,19.25,21.2-13.37,5.47-25.84-.55S407,285.14,407,285.14Z"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,11 @@
// src/app/_components/header/index.tsx
import type { FC } from 'react';
import { HeaderLogo } from './logo';
import $styles from './styles.module.css';
export const Header: FC = () => (
<header className={$styles.header}>
<HeaderLogo />
</header>
);
@@ -0,0 +1,17 @@
/* src/app/_components/header/logo.module.css */
@reference "#tailwind.css";
.link {
@apply tw:w-20 tw:h-20 tw:block tw:rounded-full tw:shadow-nymd tw:p-1 tw:bg-white;
transition-duration: 300ms;
animation: breathe-light 4s ease-in-out infinite;
&:hover {
@apply tw:shadow-nylg tw:shadow-amber-400;
transform: scale(1.2) rotate(360deg);
}
& > img {
@apply tw:rounded-full;
}
}
@@ -0,0 +1,20 @@
// src/app/_components/header/logo.tsx
import Image from 'next/image';
import Link from 'next/link';
import Avatar from './avatar.svg';
import $styles from './logo.module.css';
export const HeaderLogo = () => (
<Link href="/" className={$styles.link}>
<Image
src={Avatar}
alt="avatar logo"
sizes="100vw"
style={{
width: '100%',
height: 'auto',
}}
/>
</Link>
);
@@ -0,0 +1,6 @@
/* src/app/_components/header/styles.module.css */
@reference "#tailwind.css";
.header {
@apply tw:flex tw:justify-center tw:items-center tw:pt-6 tw:max-h-24 tw:flex-auto;
}
@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
@@ -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(
"group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className
)}
{...props}
/>
)
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-header"
className={cn(
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
className
)}
{...props}
/>
)
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
className={cn(
"font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
className
)}
{...props}
/>
)
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
)
}
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className
)}
{...props}
/>
)
}
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
className={cn("px-(--card-spacing)", className)}
{...props}
/>
)
}
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
className={cn(
"flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)",
className
)}
{...props}
/>
)
}
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
}
-26
View File
@@ -1,26 +0,0 @@
@import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}
+12 -22
View File
@@ -1,29 +1,19 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
// src/app/layout.tsx
import type { Metadata } from 'next';
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
import './styles/index.css';
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
import type { FC, PropsWithChildren } from 'react';
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: 'nextapp',
description: '3r教室Next.js全栈开发课程',
};
export default function RootLayout({ children }: LayoutProps<"/">) {
return (
<html
lang="en"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">{children}</body>
const RootLayout: FC<PropsWithChildren> = ({ children }) => (
<html lang="en">
<body>{children}</body>
</html>
);
}
);
export default RootLayout;
-69
View File
@@ -1,69 +0,0 @@
import Image from "next/image";
export default function Home() {
return (
<div className="flex flex-col flex-1 items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex flex-1 w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert h-5 w-[100px]"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the{" "}
<code className="rounded bg-black/[.06] px-1.5 py-0.5 font-mono text-[0.9em] dark:bg-white/[.08]">
page.tsx
</code>{" "}
file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert h-[14px] w-4"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={14}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
</div>
</main>
</div>
);
}
+5
View File
@@ -0,0 +1,5 @@
/* src/app/styles/app.css */
.lucide {
@apply tw:w-4 tw:h-4 tw:stroke-[1px];
}
@@ -0,0 +1,55 @@
@font-face {
font-family: 'Fira Code';
font-style: normal;
font-weight: 300;
src:
url('/fonts/firacode/woff2/FiraCode-Light.woff2') format('woff2'),
url('/fonts/firacode/woff/FiraCode-Light.woff') format('woff');
}
@font-face {
font-family: 'Fira Code';
font-style: normal;
font-weight: 400;
src:
url('/fonts/firacode/woff2/FiraCode-Regular.woff2') format('woff2'),
url('/fonts/firacode/woff/FiraCode-Regular.woff') format('woff');
}
@font-face {
font-family: 'Fira Code';
font-style: normal;
font-weight: 500;
src:
url('/fonts/firacode/woff2/FiraCode-Medium.woff2') format('woff2'),
url('/fonts/firacode/woff/FiraCode-Medium.woff') format('woff');
}
@font-face {
font-family: 'Fira Code';
font-style: normal;
font-weight: 600;
src:
url('/fonts/firacode/woff2/FiraCode-SemiBold.woff2') format('woff2'),
url('/fonts/firacode/woff/FiraCode-SemiBold.woff') format('woff');
}
@font-face {
font-family: 'Fira Code';
font-style: normal;
font-weight: 700;
src:
url('/fonts/firacode/woff2/FiraCode-Bold.woff2') format('woff2'),
url('/fonts/firacode/woff/FiraCode-Bold.woff') format('woff');
}
@font-face {
font-family: 'Fira Code VF';
font-style: normal;
/* font-weight requires a range: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide#Using_a_variable_font_font-face_changes */
font-weight: 300 700;
src:
url('/fonts/firacode/woff2/FiraCode-VF.woff2') format('woff2-variations'),
url('/fonts/firacode/woff/FiraCode-VF.woff') format('woff-variations');
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 KiB

+5
View File
@@ -0,0 +1,5 @@
@import './fonts/fira-code.css';
@import './fonts/lxgwwenkai-regular.css';
@import './fonts/lxgwwenkaimono-regular.css';
@import './tailwind.css';
@import './app.css';
+118
View File
@@ -0,0 +1,118 @@
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
:root {
--radius: 0.625rem;
--background: oklch(100% 0 0deg);
--foreground: oklch(14.1% 0.005 285.823deg);
--card: oklch(100% 0 0deg);
--card-foreground: oklch(14.1% 0.005 285.823deg);
--popover: oklch(100% 0 0deg);
--popover-foreground: oklch(14.1% 0.005 285.823deg);
--primary: oklch(21% 0.006 285.885deg);
--primary-foreground: oklch(98.5% 0 0deg);
--secondary: oklch(96.7% 0.001 286.375deg);
--secondary-foreground: oklch(21% 0.006 285.885deg);
--muted: oklch(96.7% 0.001 286.375deg);
--muted-foreground: oklch(55.2% 0.016 285.938deg);
--accent: oklch(96.7% 0.001 286.375deg);
--accent-foreground: oklch(21% 0.006 285.885deg);
--destructive: oklch(57.7% 0.245 27.325deg);
--border: oklch(92% 0.004 286.32deg);
--input: oklch(92% 0.004 286.32deg);
--ring: oklch(70.5% 0.015 286.067deg);
--chart-1: oklch(64.6% 0.222 41.116deg);
--chart-2: oklch(60% 0.118 184.704deg);
--chart-3: oklch(39.8% 0.07 227.392deg);
--chart-4: oklch(82.8% 0.189 84.429deg);
--chart-5: oklch(76.9% 0.188 70.08deg);
--sidebar: oklch(98.5% 0 0deg);
--sidebar-foreground: oklch(14.1% 0.005 285.823deg);
--sidebar-primary: oklch(21% 0.006 285.885deg);
--sidebar-primary-foreground: oklch(98.5% 0 0deg);
--sidebar-accent: oklch(96.7% 0.001 286.375deg);
--sidebar-accent-foreground: oklch(21% 0.006 285.885deg);
--sidebar-border: oklch(92% 0.004 286.32deg);
--sidebar-ring: oklch(70.5% 0.015 286.067deg);
}
.dark {
--background: oklch(14.1% 0.005 285.823deg);
--foreground: oklch(98.5% 0 0deg);
--card: oklch(21% 0.006 285.885deg);
--card-foreground: oklch(98.5% 0 0deg);
--popover: oklch(21% 0.006 285.885deg);
--popover-foreground: oklch(98.5% 0 0deg);
--primary: oklch(92% 0.004 286.32deg);
--primary-foreground: oklch(21% 0.006 285.885deg);
--secondary: oklch(27.4% 0.006 286.033deg);
--secondary-foreground: oklch(98.5% 0 0deg);
--muted: oklch(27.4% 0.006 286.033deg);
--muted-foreground: oklch(70.5% 0.015 286.067deg);
--accent: oklch(27.4% 0.006 286.033deg);
--accent-foreground: oklch(98.5% 0 0deg);
--destructive: oklch(70.4% 0.191 22.216deg);
--border: oklch(100% 0 0deg / 10%);
--input: oklch(100% 0 0deg / 15%);
--ring: oklch(55.2% 0.016 285.938deg);
--chart-1: oklch(48.8% 0.243 264.376deg);
--chart-2: oklch(69.6% 0.17 162.48deg);
--chart-3: oklch(76.9% 0.188 70.08deg);
--chart-4: oklch(62.7% 0.265 303.9deg);
--chart-5: oklch(64.5% 0.246 16.439deg);
--sidebar: oklch(21% 0.006 285.885deg);
--sidebar-foreground: oklch(98.5% 0 0deg);
--sidebar-primary: oklch(48.8% 0.243 264.376deg);
--sidebar-primary-foreground: oklch(98.5% 0 0deg);
--sidebar-accent: oklch(27.4% 0.006 286.033deg);
--sidebar-accent-foreground: oklch(98.5% 0 0deg);
--sidebar-border: oklch(100% 0 0deg / 10%);
--sidebar-ring: oklch(55.2% 0.016 285.938deg);
}
@layer base {
* {
@apply tw:border-border;
}
body {
@apply tw:bg-background tw:text-foreground;
}
}
+136
View File
@@ -0,0 +1,136 @@
/* src/app/styles/tailwind.css */
@layer theme, base, components, utilities;
@import 'tailwindcss' prefix(tw);
@import 'tw-animate-css';
@import './tailwind/base.css';
@import './tailwind/utilities.css';
@import './tailwind/theme.css';
@import './tailwind/shadcn.css';
@custom-variant dark (&:is(.dark, .dark *, [data-theme='dark'], [data-theme='dark'] *));
@theme inline {
--font-heading: var(--font-sans);
--font-sans: var(--font-sans);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--color-foreground: var(--foreground);
--color-background: var(--background);
--radius-sm: calc(var(--radius) * 0.6);
--radius-md: calc(var(--radius) * 0.8);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.4);
--radius-2xl: calc(var(--radius) * 1.8);
--radius-3xl: calc(var(--radius) * 2.2);
--radius-4xl: calc(var(--radius) * 2.6);
}
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply tw:border-border tw:outline-ring/50;
}
body {
@apply tw:bg-background tw:text-foreground;
}
html {
@apply tw:font-sans;
}
}
+50
View File
@@ -0,0 +1,50 @@
/********************************************************* 自定义tailwind基本样式 *********************************************************/
@layer base {
html {
font-size: 100%;
}
/* 以下为自定义样式 */
html,
body {
@apply tw:font-base tw:h-[100vh] tw:w-full tw:p-0 tw:m-0;
}
body {
@apply tw:text-sm;
}
h1 {
@apply tw:text-3xl;
}
h2 {
@apply tw:text-2xl;
}
h3 {
@apply tw:text-xl;
}
h4 {
@apply tw:text-lg;
}
h5 {
@apply tw:text-sm;
}
h6 {
@apply tw:text-xs;
}
button,
[role='button'] {
cursor: pointer;
}
:disabled {
cursor: default;
}
}
+118
View File
@@ -0,0 +1,118 @@
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar: var(--sidebar);
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
:root {
--radius: 0.625rem;
--background: oklch(100% 0 0deg);
--foreground: oklch(14.1% 0.005 285.823deg);
--card: oklch(100% 0 0deg);
--card-foreground: oklch(14.1% 0.005 285.823deg);
--popover: oklch(100% 0 0deg);
--popover-foreground: oklch(14.1% 0.005 285.823deg);
--primary: oklch(21% 0.006 285.885deg);
--primary-foreground: oklch(98.5% 0 0deg);
--secondary: oklch(96.7% 0.001 286.375deg);
--secondary-foreground: oklch(21% 0.006 285.885deg);
--muted: oklch(96.7% 0.001 286.375deg);
--muted-foreground: oklch(55.2% 0.016 285.938deg);
--accent: oklch(96.7% 0.001 286.375deg);
--accent-foreground: oklch(21% 0.006 285.885deg);
--destructive: oklch(57.7% 0.245 27.325deg);
--border: oklch(92% 0.004 286.32deg);
--input: oklch(92% 0.004 286.32deg);
--ring: oklch(70.5% 0.015 286.067deg);
--chart-1: oklch(64.6% 0.222 41.116deg);
--chart-2: oklch(60% 0.118 184.704deg);
--chart-3: oklch(39.8% 0.07 227.392deg);
--chart-4: oklch(82.8% 0.189 84.429deg);
--chart-5: oklch(76.9% 0.188 70.08deg);
--sidebar: oklch(98.5% 0 0deg);
--sidebar-foreground: oklch(14.1% 0.005 285.823deg);
--sidebar-primary: oklch(21% 0.006 285.885deg);
--sidebar-primary-foreground: oklch(98.5% 0 0deg);
--sidebar-accent: oklch(96.7% 0.001 286.375deg);
--sidebar-accent-foreground: oklch(21% 0.006 285.885deg);
--sidebar-border: oklch(92% 0.004 286.32deg);
--sidebar-ring: oklch(70.5% 0.015 286.067deg);
}
.dark {
--background: oklch(14.1% 0.005 285.823deg);
--foreground: oklch(98.5% 0 0deg);
--card: oklch(21% 0.006 285.885deg);
--card-foreground: oklch(98.5% 0 0deg);
--popover: oklch(21% 0.006 285.885deg);
--popover-foreground: oklch(98.5% 0 0deg);
--primary: oklch(92% 0.004 286.32deg);
--primary-foreground: oklch(21% 0.006 285.885deg);
--secondary: oklch(27.4% 0.006 286.033deg);
--secondary-foreground: oklch(98.5% 0 0deg);
--muted: oklch(27.4% 0.006 286.033deg);
--muted-foreground: oklch(70.5% 0.015 286.067deg);
--accent: oklch(27.4% 0.006 286.033deg);
--accent-foreground: oklch(98.5% 0 0deg);
--destructive: oklch(70.4% 0.191 22.216deg);
--border: oklch(100% 0 0deg / 10%);
--input: oklch(100% 0 0deg / 15%);
--ring: oklch(55.2% 0.016 285.938deg);
--chart-1: oklch(48.8% 0.243 264.376deg);
--chart-2: oklch(69.6% 0.17 162.48deg);
--chart-3: oklch(76.9% 0.188 70.08deg);
--chart-4: oklch(62.7% 0.265 303.9deg);
--chart-5: oklch(64.5% 0.246 16.439deg);
--sidebar: oklch(21% 0.006 285.885deg);
--sidebar-foreground: oklch(98.5% 0 0deg);
--sidebar-primary: oklch(48.8% 0.243 264.376deg);
--sidebar-primary-foreground: oklch(98.5% 0 0deg);
--sidebar-accent: oklch(27.4% 0.006 286.033deg);
--sidebar-accent-foreground: oklch(98.5% 0 0deg);
--sidebar-border: oklch(100% 0 0deg / 10%);
--sidebar-ring: oklch(55.2% 0.016 285.938deg);
}
@layer base {
* {
@apply tw:border-border;
}
body {
@apply tw:bg-background tw:text-foreground;
}
}
@@ -0,0 +1,33 @@
/********************************************************* 自定义tailwind主题扩展 *********************************************************/
@theme {
--breakpoint-xs: 30rem;
--breakpoint-sm: 36rem;
--breakpoint-md: 48rem;
--breakpoint-lg: 62rem;
--breakpoint-xl: 75rem;
--breakpoint-2xl: 87.5rem;
--shadow-nysm: 0 0 2px 0 rgb(0 0 0 / 5%);
--shadow-ny: 0 0 3px 0 rgb(0 0 0 / 10%), 0 0 2px - 1px rgb(0 0 0 / 10%);
--shadow-nymd: 0 0 6px -1px rgb(0 0 0 / 10%), 0 0 4px -2px rgb(0 0 0 / 10%);
--shadow-nylg: 0 0 15px -3px rgb(0 0 0 / 10%), 0 0 6px -4px rgb(0 0 0 / 10%);
--shadow-spread: 0 5px 40px rgb(0 0 0 / 10%);
/* 默认字体 */
--font-base:
-apple-system, blinkmacsystemfont, tahoma, arial, 'Hiragino Sans GB', 'Microsoft YaHei',
'WenQuanYi Micro Hei', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
/* 霞鹜文楷字体 */
--font-lxgw:
'LXGW WenKai', '楷体', 'STKaiti', -apple-system, blinkmacsystemfont, tahoma, arial,
'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
/* 默认代码字体 */
--font-code:
'Fira Code', -apple-system, blinkmacsystemfont, tahoma, arial, 'Hiragino Sans GB',
'Microsoft YaHei', 'WenQuanYi Micro Hei', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
}
@@ -0,0 +1,107 @@
/********************************************************* 自定义tailwind工具类 *********************************************************/
@utility page-item {
@apply tw:flex tw:flex-auto tw:flex-col tw:mt-20 tw:items-center;
}
/* 页面包装容器 */
@utility page-container {
@apply tw:max-w-[90%] tw:md:max-w-[80%] tw:lg:max-w-[70%] tw:xl:max-w-[60%] tw:flex-auto tw:mb-5;
}
/* 页面包装容器 */
/* 空白页样式,一般用于404和error页面 */
@utility page-blank {
@apply tw:bg-white/80 tw:backdrop-blur-sm tw:h-full tw:w-full tw:drop-shadow-lg tw:rounded-md tw:flex tw:justify-center tw:items-center;
html.dark & {
@apply tw:bg-black/50;
}
}
/* 全透明图标按钮 */
@utility btn-icon-transparent {
@apply tw:block tw:w-auto! tw:border-none! tw:bg-transparent! tw:shadow-none! tw:ring-0! tw:hover:bg-transparent! tw:focus-visible:ring-0!;
}
@utility page-block {
@apply tw:bg-zinc-100/80;
html.dark & {
@apply tw:bg-zinc-800/50;
}
}
@utility page-block-hover {
@apply tw:hover:bg-white/90;
html.dark & {
@apply tw:hover:bg-black/80;
}
}
/* 只显示一行文字, 溢出部分以省略号代替 */
@utility ellips {
@apply tw:inline-block tw:overflow-hidden tw:max-w-full tw:whitespace-nowrap tw:text-ellipsis tw:break-all;
}
/* 鼠标移动到文字或链接出现动画下划线 */
@utility animate-decoration {
padding-bottom: 2px;
background: linear-gradient(hsl(var(--foreground)), hsl(var(--foreground))) 0% 100% / 0% 1px
no-repeat;
transition: background-size ease-out 200ms;
&:not(:focus):hover {
background-size: 100% 1px;
}
}
/* 粗下划线 */
@utility animate-decoration-lg {
&:not(:focus):hover {
background-size: 100% 2px;
}
}
/* 取消下划线 */
@utility none-animate-decoration {
background-size: 0 !important;
transition: none !important;
&:hover,
&:not(:focus):hover {
background-size: 100% 0 !important;
}
}
/* 透明滚动条 */
@utility transparent-scrollbar {
&::-webkit-scrollbar {
@apply tw:w-1 tw:h-1;
}
&::-webkit-scrollbar-track {
@apply tw:bg-gray-100;
}
html.dark &::-webkit-scrollbar-track {
@apply tw:bg-zinc-800;
}
&::-webkit-scrollbar-thumb {
@apply tw:bg-gray-300 tw:rounded;
}
html.dark &::-webkit-scrollbar-thumb {
@apply tw:bg-zinc-600;
}
&::-webkit-scrollbar-corner {
@apply tw:bg-gray-100;
}
html.dark &::-webkit-scrollbar-corner {
@apply tw:bg-zinc-800;
}
}
+93
View File
@@ -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;