nsbp-cli 0.2.27 → 0.2.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/bin/nsbp.js +94 -74
  3. package/package.json +1 -1
  4. package/templates/basic/README.md +43 -0
  5. package/templates/basic/docs/DEVELOPMENT_GUIDE.md +290 -0
  6. package/templates/basic/docs/ESLINT_AND_PRETTIER.md +184 -0
  7. package/templates/basic/docs/HUSKY_9_UPGRADE.md +76 -0
  8. package/templates/basic/docs/HUSKY_ESLINT_SETUP.md +293 -0
  9. package/templates/basic/docs/SETUP_GIT_HOOKS.md +106 -0
  10. package/templates/basic/gitignore +3 -0
  11. package/templates/basic/package.json +27 -3
  12. package/templates/basic/scripts/setup-husky.js +24 -0
  13. package/templates/basic/src/Routers.tsx +4 -5
  14. package/templates/basic/src/client/index.tsx +5 -1
  15. package/templates/basic/src/component/Header.tsx +10 -10
  16. package/templates/basic/src/component/Layout.tsx +9 -3
  17. package/templates/basic/src/component/Theme.tsx +5 -1
  18. package/templates/basic/src/containers/Home.tsx +141 -76
  19. package/templates/basic/src/containers/Photo.tsx +30 -18
  20. package/templates/basic/src/externals/window.d.ts +3 -1
  21. package/templates/basic/src/reducers/photo.ts +7 -2
  22. package/templates/basic/src/server/index.ts +35 -26
  23. package/templates/basic/src/server/photo.ts +14 -7
  24. package/templates/basic/src/server/utils.tsx +9 -7
  25. package/templates/basic/src/services/home.ts +1 -1
  26. package/templates/basic/src/services/photo.ts +28 -30
  27. package/templates/basic/src/store/constants.ts +1 -1
  28. package/templates/basic/src/store/index.ts +2 -1
  29. package/templates/basic/src/styled/component/header.ts +5 -1
  30. package/templates/basic/src/styled/home.ts +100 -24
  31. package/templates/basic/src/styled/photo.ts +2 -2
  32. package/templates/basic/src/utils/config.ts +1 -1
  33. package/templates/basic/src/utils/fetch.ts +4 -8
  34. package/templates/basic/src/utils/index.ts +1 -1
@@ -11,7 +11,7 @@ import { useCurrentFlag } from '@utils/clientConfig'
11
11
  import _ from 'lodash'
12
12
  import { loadData } from '@services/photo'
13
13
 
14
- const springSettings = { type: "spring" as const, stiffness: 170, damping: 26 }
14
+ const springSettings = { type: 'spring' as const, stiffness: 170, damping: 26 }
15
15
  const NEXT = 'show-next'
16
16
 
17
17
  const Photo = ({ query, data, menu, getPhotoMenu }: any) => {
@@ -24,7 +24,9 @@ const Photo = ({ query, data, menu, getPhotoMenu }: any) => {
24
24
 
25
25
  const [currWidth, currHeight] = currPhotoData
26
26
 
27
- const widths = photos.map(([origW, origH]:any) => (currHeight / origH) * origW)
27
+ const widths = photos.map(
28
+ ([origW, origH]: any) => (currHeight / origH) * origW
29
+ )
28
30
 
29
31
  // 同步 currPhoto 和 currPhotoData
30
32
  useEffect(() => {
@@ -35,18 +37,22 @@ const Photo = ({ query, data, menu, getPhotoMenu }: any) => {
35
37
 
36
38
  const leftStartCoords = widths
37
39
  .slice(0, currPhoto)
38
- .reduce((sum:any, width:any) => sum - width, 0)
40
+ .reduce((sum: any, width: any) => sum - width, 0)
39
41
 
40
42
  // Calculate position for each photo
41
- const photoPositions = photos.reduce((acc:any, [_origW, _origH]:any, i:any, _arr:any) => {
42
- const prevLeft = i === 0 ? leftStartCoords : acc[i-1].left + acc[i-1].width
43
- acc.push({
44
- left: prevLeft,
45
- height: currHeight,
46
- width: widths[i] || 0
47
- })
48
- return acc
49
- }, [])
43
+ const photoPositions = photos.reduce(
44
+ (acc: any, [_origW, _origH]: any, i: any, _arr: any) => {
45
+ const prevLeft =
46
+ i === 0 ? leftStartCoords : acc[i - 1].left + acc[i - 1].width
47
+ acc.push({
48
+ left: prevLeft,
49
+ height: currHeight,
50
+ width: widths[i] || 0
51
+ })
52
+ return acc
53
+ },
54
+ []
55
+ )
50
56
 
51
57
  // console.log('photoPositions', photoPositions)
52
58
 
@@ -93,13 +99,13 @@ const Photo = ({ query, data, menu, getPhotoMenu }: any) => {
93
99
  <Layout query={query}>
94
100
  <Container>
95
101
  <Row>
96
- {
97
- _.map(menu, (item:any, index:number) => {
102
+ {_.map(menu, (item: any, index: number) => {
98
103
  return (
99
- <Link key={`menu${index}`} to={`/photo?dic=${item.name}`}>{item.name}</Link>
104
+ <Link key={`menu${index}`} to={`/photo?dic=${item.name}`}>
105
+ {item.name}
106
+ </Link>
100
107
  )
101
- })
102
- }
108
+ })}
103
109
  </Row>
104
110
  <Row>Scroll Me</Row>
105
111
  <Row>
@@ -123,7 +129,13 @@ const Photo = ({ query, data, menu, getPhotoMenu }: any) => {
123
129
  <motion.img
124
130
  key={i}
125
131
  className="demo4-photo"
126
- src={photos[i][2] ? (useCurrentFlag ? `/images/${photos[i][2]}` : photos[i][2]) : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='}
132
+ src={
133
+ photos[i][2]
134
+ ? useCurrentFlag
135
+ ? `/images/${photos[i][2]}`
136
+ : photos[i][2]
137
+ : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='
138
+ }
127
139
  initial={false}
128
140
  animate={{
129
141
  left: pos.left,
@@ -1,7 +1,9 @@
1
1
  interface ServerState {
2
2
  photo?: {
3
3
  data?: [number, number, string][]
4
- menu?: Record<string, any> | Array<{ name: string; cover?: string; count?: number }>
4
+ menu?:
5
+ | Record<string, any>
6
+ | Array<{ name: string; cover?: string; count?: number }>
5
7
  }
6
8
  query?: Record<string, any>
7
9
  }
@@ -2,10 +2,15 @@ import { GET_PHOTO_MENU, GET_PHOTO_WIDTH_HEIGHT } from '@store/constants'
2
2
 
3
3
  interface PhotoState {
4
4
  data: [number, number, string][]
5
- menu: Record<string, any> | Array<{ name: string; cover?: string; count?: number }>
5
+ menu:
6
+ | Record<string, any>
7
+ | Array<{ name: string; cover?: string; count?: number }>
6
8
  }
7
9
 
8
- export const photoReducer = (state: PhotoState = { data: [[0, 0, '']], menu: {} }, action: any) => {
10
+ export const photoReducer = (
11
+ state: PhotoState = { data: [[0, 0, '']], menu: {} },
12
+ action: any
13
+ ) => {
9
14
  const { type, data, menu } = action
10
15
 
11
16
  switch (type) {
@@ -8,23 +8,25 @@ import { useCurrentFlag, outPhotoDicPath } from '@utils/config'
8
8
  const app = express()
9
9
 
10
10
  // 1. Security headers (helmet)
11
- app.use(helmet({
12
- contentSecurityPolicy: {
13
- directives: {
14
- defaultSrc: ["'self'"],
15
- scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
16
- styleSrc: ["'self'", "'unsafe-inline'"],
17
- imgSrc: ["'self'", "data:", "https:"],
18
- connectSrc: ["'self'", "https:"],
19
- fontSrc: ["'self'", "data:"],
20
- objectSrc: ["'none'"],
21
- mediaSrc: ["'self'"],
22
- frameSrc: ["'none'"],
11
+ app.use(
12
+ helmet({
13
+ contentSecurityPolicy: {
14
+ directives: {
15
+ defaultSrc: ["'self'"],
16
+ scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
17
+ styleSrc: ["'self'", "'unsafe-inline'"],
18
+ imgSrc: ["'self'", 'data:', 'https:'],
19
+ connectSrc: ["'self'", 'https:'],
20
+ fontSrc: ["'self'", 'data:'],
21
+ objectSrc: ["'none'"],
22
+ mediaSrc: ["'self'"],
23
+ frameSrc: ["'none'"]
24
+ }
23
25
  },
24
- },
25
- crossOriginEmbedderPolicy: false, // Allow inline scripts for SSR
26
- crossOriginOpenerPolicy: false, // Allow window.open for development
27
- }))
26
+ crossOriginEmbedderPolicy: false, // Allow inline scripts for SSR
27
+ crossOriginOpenerPolicy: false // Allow window.open for development
28
+ })
29
+ )
28
30
 
29
31
  // 2. Hide X-Powered-By header
30
32
  app.disable('x-powered-by')
@@ -36,23 +38,30 @@ if (process.env.ENABLE_RATE_LIMIT === '1') {
36
38
  max: 100, // Limit each IP to 100 requests per windowMs
37
39
  message: 'Too many requests from this IP, please try again later.',
38
40
  standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
39
- legacyHeaders: false, // Disable the `X-RateLimit-*` headers
41
+ legacyHeaders: false // Disable the `X-RateLimit-*` headers
40
42
  })
41
43
  app.use('/api', limiter)
42
44
  console.log('🛡️ Rate limiting enabled for /api routes')
43
45
  }
44
46
 
45
47
  // 4. Static file serving (disable dotfiles access)
46
- app.use(express.static('public', {
47
- dotfiles: 'ignore',
48
- setHeaders: (res, filePath) => {
49
- // Cache static assets for 1 year
50
- if (filePath.match(/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$/)) {
51
- res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
48
+ app.use(
49
+ express.static('public', {
50
+ dotfiles: 'ignore',
51
+ setHeaders: (res, filePath) => {
52
+ // Cache static assets for 1 year
53
+ if (
54
+ filePath.match(
55
+ /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$/
56
+ )
57
+ ) {
58
+ res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
59
+ }
52
60
  }
53
- }
54
- }))
55
- !useCurrentFlag && app.use(express.static(outPhotoDicPath, { dotfiles: 'ignore' }))
61
+ })
62
+ )
63
+ !useCurrentFlag &&
64
+ app.use(express.static(outPhotoDicPath, { dotfiles: 'ignore' }))
56
65
 
57
66
  // 5. Body parsing with size limits
58
67
  app.use(express.json({ limit: '10mb' }))
@@ -1,6 +1,5 @@
1
-
2
- import fs from "fs"
3
- import path from "path"
1
+ import fs from 'fs'
2
+ import path from 'path'
4
3
  import probe from 'probe-image-size'
5
4
 
6
5
  // 获取项目根目录(无论从哪个目录运行服务器)
@@ -29,7 +28,9 @@ const getPhotosDicPath = () => {
29
28
  }
30
29
 
31
30
  // 获取目录下的子目录(分类),并为每个分类找封面图和图片数量
32
- const getFileMenu = (dir: string): { name: string; cover?: string; count?: number }[] => {
31
+ const getFileMenu = (
32
+ dir: string
33
+ ): { name: string; cover?: string; count?: number }[] => {
33
34
  const arr = fs.readdirSync(dir)
34
35
  const result: { name: string; cover?: string; count?: number }[] = []
35
36
 
@@ -40,7 +41,9 @@ const getFileMenu = (dir: string): { name: string; cover?: string; count?: numbe
40
41
  // 分类名
41
42
  const name = item
42
43
  // 计算图片数量
43
- const files = fs.readdirSync(fullPath).filter(f => /\.(jpg|jpeg|png|webp)$/i.test(f))
44
+ const files = fs
45
+ .readdirSync(fullPath)
46
+ .filter((f) => /\.(jpg|jpeg|png|webp)$/i.test(f))
44
47
  const count = files.length
45
48
 
46
49
  // 在该目录下找 cover.jpg
@@ -110,7 +113,9 @@ export const getPhotoWH = (req: any, res: any) => {
110
113
  res.json({ data: whArr })
111
114
  } catch (err: any) {
112
115
  console.error('getPhotoWH error:', err)
113
- res.status(500).json({ error: 'Internal Server Error', details: err.message })
116
+ res
117
+ .status(500)
118
+ .json({ error: 'Internal Server Error', details: err.message })
114
119
  }
115
120
  }
116
121
 
@@ -124,6 +129,8 @@ export const getPhotoMenu = (_req: any, res: any) => {
124
129
  res.json({ data: fileMenu })
125
130
  } catch (err: any) {
126
131
  console.error('getPhotoMenu error:', err)
127
- res.status(500).json({ error: 'Internal Server Error', details: err.message })
132
+ res
133
+ .status(500)
134
+ .json({ error: 'Internal Server Error', details: err.message })
128
135
  }
129
136
  }
@@ -15,7 +15,7 @@ import { ChunkExtractor } from '@loadable/server'
15
15
 
16
16
  export const render = (req: any, res: any) => {
17
17
  const store = getStore()
18
- const { path:reqPath, query } = req
18
+ const { path: reqPath, query } = req
19
19
  const matchRoutes: any = []
20
20
  const promises = []
21
21
 
@@ -71,10 +71,7 @@ export const render = (req: any, res: any) => {
71
71
 
72
72
  const helmet: any = Helmet.renderStatic()
73
73
 
74
- const webStats = path.resolve(
75
- __dirname,
76
- '../public/loadable-stats.json',
77
- )
74
+ const webStats = path.resolve(__dirname, '../public/loadable-stats.json')
78
75
 
79
76
  try {
80
77
  let webEntryPoints = ['client', 'vendor']
@@ -89,13 +86,18 @@ export const render = (req: any, res: any) => {
89
86
  publicPath: '/'
90
87
  })
91
88
 
92
- const jsx = webExtractor.collectChunks(sheet.collectStyles(
89
+ const jsx = webExtractor.collectChunks(
90
+ sheet.collectStyles(
93
91
  <Theme>
94
92
  <Provider store={store}>
95
93
  <StaticRouter location={reqPath}>
96
94
  <Routes>
97
95
  {routers.map((router) => (
98
- <Route key={router.key} path={router.path} element={router.element} />
96
+ <Route
97
+ key={router.key}
98
+ path={router.path}
99
+ element={router.element}
100
+ />
99
101
  ))}
100
102
  </Routes>
101
103
  </StaticRouter>
@@ -24,4 +24,4 @@ export const loadData = (resolve: any = null) => {
24
24
  resolve && resolve()
25
25
  })
26
26
  }
27
- }
27
+ }
@@ -1,7 +1,6 @@
1
1
  import { doGet } from '@utils/fetch'
2
2
  import { GET_PHOTO_MENU, GET_PHOTO_WIDTH_HEIGHT } from '@store/constants'
3
3
 
4
-
5
4
  const getPhotoWH = (dispatch: any, callback: any, dic = '') => {
6
5
  let action = 'getPhotoWH'
7
6
  if (dic) {
@@ -9,47 +8,46 @@ const getPhotoWH = (dispatch: any, callback: any, dic = '') => {
9
8
  }
10
9
 
11
10
  doGet(action)
12
- .then((res:any) => {
13
- // console.log('getPhotoWH_res', res)
14
- // axios 响应格式是 { data: { data: [...] }, status: ... },需要取 res.data.data
15
- dispatch({
16
- type: GET_PHOTO_WIDTH_HEIGHT,
17
- data: res?.data?.data || []
18
- })
19
- callback && callback()
20
- })
21
- .catch((_e:any) => {
22
- callback && callback()
11
+ .then((res: any) => {
12
+ // console.log('getPhotoWH_res', res)
13
+ // axios 响应格式是 { data: { data: [...] }, status: ... },需要取 res.data.data
14
+ dispatch({
15
+ type: GET_PHOTO_WIDTH_HEIGHT,
16
+ data: res?.data?.data || []
23
17
  })
18
+ callback && callback()
19
+ })
20
+ .catch((_e: any) => {
21
+ callback && callback()
22
+ })
24
23
  }
25
24
 
26
- const getPhotoMenu = (dispatch:any, callback:any) => {
25
+ const getPhotoMenu = (dispatch: any, callback: any) => {
27
26
  doGet('getPhotoMenu')
28
- .then((res:any) => {
29
- // console.log('getPhotoMenu_res', res)
30
- // axios 响应格式是 { data: { data: [...] }, status: ... },需要取 res.data.data
31
- const { data } = res?.data || {}
32
- dispatch({
33
- type: GET_PHOTO_MENU,
34
- menu: data
35
- })
36
-
37
- callback && callback(data)
38
- })
39
- .catch((_e:any) => {
40
- callback && callback()
27
+ .then((res: any) => {
28
+ // console.log('getPhotoMenu_res', res)
29
+ // axios 响应格式是 { data: { data: [...] }, status: ... },需要取 res.data.data
30
+ const { data } = res?.data || {}
31
+ dispatch({
32
+ type: GET_PHOTO_MENU,
33
+ menu: data
41
34
  })
35
+
36
+ callback && callback(data)
37
+ })
38
+ .catch((_e: any) => {
39
+ callback && callback()
40
+ })
42
41
  }
43
42
 
44
- const getData = (callback:any, dic:any) => {
43
+ const getData = (callback: any, dic: any) => {
45
44
  return (dispatch: any) => {
46
-
47
45
  if (dic) {
48
46
  getPhotoMenu(dispatch, () => {
49
47
  getPhotoWH(dispatch, callback, dic)
50
48
  })
51
49
  } else {
52
- getPhotoMenu(dispatch, (data:any) => {
50
+ getPhotoMenu(dispatch, (data: any) => {
53
51
  if (data && data.length > 0) {
54
52
  // data[0] 是对象 {name, cover},需要取 name
55
53
  getPhotoWH(dispatch, callback, data[0].name)
@@ -59,6 +57,6 @@ const getData = (callback:any, dic:any) => {
59
57
  }
60
58
  }
61
59
 
62
- export const loadData = (resolve: any = null, dic='') => {
60
+ export const loadData = (resolve: any = null, dic = '') => {
63
61
  return getData(resolve, dic)
64
62
  }
@@ -1,4 +1,4 @@
1
1
  export const GITHUB_ZEITNEXT_GET = 'GITHUB_ZEITNEXT_GET'
2
2
  export const REQUEST_QUERY = 'REQUEST_QUERY'
3
3
  export const GET_PHOTO_MENU = 'GET_PHOTO_MENU'
4
- export const GET_PHOTO_WIDTH_HEIGHT= 'GET_PHOTO_WIDTH_HEIGHT'
4
+ export const GET_PHOTO_WIDTH_HEIGHT = 'GET_PHOTO_WIDTH_HEIGHT'
@@ -5,7 +5,8 @@ const combineReducer = combineReducers({ ...reducers })
5
5
 
6
6
  const getStore = (stateParam = {}) => {
7
7
  return configureStore({
8
- reducer: (state: any, action: any) => combineReducer(state || stateParam, action),
8
+ reducer: (state: any, action: any) =>
9
+ combineReducer(state || stateParam, action),
9
10
  preloadedState: stateParam || {},
10
11
  middleware: (getDefaultMiddleware) => getDefaultMiddleware()
11
12
  })
@@ -6,7 +6,11 @@ export const Container = styled.header`
6
6
  align-items: center;
7
7
  justify-content: space-between;
8
8
  padding: 0.75rem 2rem;
9
- background: linear-gradient(135deg, rgba(255,255,255, 0.95), rgba(255,255,255, 0.85));
9
+ background: linear-gradient(
10
+ 135deg,
11
+ rgba(255, 255, 255, 0.95),
12
+ rgba(255, 255, 255, 0.85)
13
+ );
10
14
  backdrop-filter: blur(20px);
11
15
  -webkit-backdrop-filter: blur(20px);
12
16
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
@@ -12,12 +12,16 @@ export const GlobalStyle = styled.div`
12
12
  padding: 0;
13
13
  }
14
14
 
15
- html, body, #root {
15
+ html,
16
+ body,
17
+ #root {
16
18
  height: 100%;
17
19
  }
18
20
 
19
21
  body {
20
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
22
+ font-family:
23
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
24
+ Arial, sans-serif;
21
25
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
22
26
  color: #2d3748;
23
27
  -webkit-font-smoothing: antialiased;
@@ -57,7 +61,9 @@ export const GlobalStyle = styled.div`
57
61
  }
58
62
 
59
63
  @keyframes spin {
60
- to { transform: rotate(360deg); }
64
+ to {
65
+ transform: rotate(360deg);
66
+ }
61
67
  }
62
68
 
63
69
  /* 淡入动画 */
@@ -129,9 +135,21 @@ export const HeroSection = styled.section`
129
135
  right: 0;
130
136
  bottom: 0;
131
137
  background-image:
132
- radial-gradient(circle at 20% 80%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
133
- radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
134
- radial-gradient(circle at 40% 40%, rgba(255, 255, 255, 0.05) 0%, transparent 50%);
138
+ radial-gradient(
139
+ circle at 20% 80%,
140
+ rgba(255, 255, 255, 0.1) 0%,
141
+ transparent 50%
142
+ ),
143
+ radial-gradient(
144
+ circle at 80% 20%,
145
+ rgba(255, 255, 255, 0.1) 0%,
146
+ transparent 50%
147
+ ),
148
+ radial-gradient(
149
+ circle at 40% 40%,
150
+ rgba(255, 255, 255, 0.05) 0%,
151
+ transparent 50%
152
+ );
135
153
  z-index: -1;
136
154
  }
137
155
 
@@ -141,7 +159,11 @@ export const HeroSection = styled.section`
141
159
  width: 300px;
142
160
  height: 300px;
143
161
  border-radius: 50%;
144
- background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
162
+ background: radial-gradient(
163
+ circle,
164
+ rgba(255, 255, 255, 0.1) 0%,
165
+ transparent 70%
166
+ );
145
167
  filter: blur(40px);
146
168
  animation: float 6s ease-in-out infinite;
147
169
  }
@@ -159,8 +181,13 @@ export const HeroSection = styled.section`
159
181
  }
160
182
 
161
183
  @keyframes float {
162
- 0%, 100% { transform: translateY(0px) scale(1); }
163
- 50% { transform: translateY(-20px) scale(1.1); }
184
+ 0%,
185
+ 100% {
186
+ transform: translateY(0px) scale(1);
187
+ }
188
+ 50% {
189
+ transform: translateY(-20px) scale(1.1);
190
+ }
164
191
  }
165
192
 
166
193
  @media (max-width: 768px) {
@@ -219,7 +246,11 @@ export const HeroSubtitle = styled.p`
219
246
 
220
247
  export const HeroBadge = styled.span`
221
248
  display: inline-block;
222
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1));
249
+ background: linear-gradient(
250
+ 135deg,
251
+ rgba(255, 255, 255, 0.2),
252
+ rgba(255, 255, 255, 0.1)
253
+ );
223
254
  backdrop-filter: blur(15px);
224
255
  padding: 0.75rem 1.5rem;
225
256
  border-radius: 999px;
@@ -239,13 +270,22 @@ export const HeroBadge = styled.span`
239
270
  left: -100%;
240
271
  width: 100%;
241
272
  height: 100%;
242
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
273
+ background: linear-gradient(
274
+ 90deg,
275
+ transparent,
276
+ rgba(255, 255, 255, 0.2),
277
+ transparent
278
+ );
243
279
  animation: shine 3s infinite;
244
280
  }
245
281
 
246
282
  @keyframes shine {
247
- 0% { left: -100%; }
248
- 100% { left: 100%; }
283
+ 0% {
284
+ left: -100%;
285
+ }
286
+ 100% {
287
+ left: 100%;
288
+ }
249
289
  }
250
290
  `
251
291
 
@@ -271,7 +311,11 @@ export const HeroStats = styled.div`
271
311
  `
272
312
 
273
313
  export const StatCard = styled.div`
274
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1));
314
+ background: linear-gradient(
315
+ 135deg,
316
+ rgba(255, 255, 255, 0.2),
317
+ rgba(255, 255, 255, 0.1)
318
+ );
275
319
  backdrop-filter: blur(20px);
276
320
  padding: 1.75rem;
277
321
  border-radius: 16px;
@@ -292,12 +336,21 @@ export const StatCard = styled.div`
292
336
  left: 0;
293
337
  right: 0;
294
338
  height: 1px;
295
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
339
+ background: linear-gradient(
340
+ 90deg,
341
+ transparent,
342
+ rgba(255, 255, 255, 0.4),
343
+ transparent
344
+ );
296
345
  }
297
346
 
298
347
  &:hover {
299
348
  transform: translateY(-8px) scale(1.02);
300
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.15));
349
+ background: linear-gradient(
350
+ 135deg,
351
+ rgba(255, 255, 255, 0.25),
352
+ rgba(255, 255, 255, 0.15)
353
+ );
301
354
  box-shadow:
302
355
  0 12px 40px rgba(0, 0, 0, 0.15),
303
356
  inset 0 1px 0 rgba(255, 255, 255, 0.3);
@@ -337,7 +390,11 @@ export const StatLabel = styled.div`
337
390
 
338
391
  export const TechSection = styled.section`
339
392
  padding: 6rem 0;
340
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
393
+ background: linear-gradient(
394
+ 135deg,
395
+ rgba(255, 255, 255, 0.1) 0%,
396
+ rgba(255, 255, 255, 0.05) 100%
397
+ );
341
398
  display: flex;
342
399
  flex-direction: column;
343
400
  align-items: center;
@@ -353,8 +410,16 @@ export const TechSection = styled.section`
353
410
  right: 0;
354
411
  bottom: 0;
355
412
  background-image:
356
- radial-gradient(circle at 10% 20%, rgba(102, 126, 234, 0.05) 0%, transparent 50%),
357
- radial-gradient(circle at 90% 80%, rgba(118, 75, 162, 0.05) 0%, transparent 50%);
413
+ radial-gradient(
414
+ circle at 10% 20%,
415
+ rgba(102, 126, 234, 0.05) 0%,
416
+ transparent 50%
417
+ ),
418
+ radial-gradient(
419
+ circle at 90% 80%,
420
+ rgba(118, 75, 162, 0.05) 0%,
421
+ transparent 50%
422
+ );
358
423
  pointer-events: none;
359
424
  }
360
425
  `
@@ -461,7 +526,8 @@ export const CodeExample = styled.pre`
461
526
  padding: 1rem;
462
527
  border-radius: 8px;
463
528
  overflow-x: auto;
464
- font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace;
529
+ font-family:
530
+ 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace;
465
531
  font-size: 0.85rem;
466
532
  line-height: 1.6;
467
533
  margin-bottom: 1rem;
@@ -757,7 +823,8 @@ export const QuickStartCode = styled.pre`
757
823
  padding: 1rem;
758
824
  border-radius: 8px;
759
825
  overflow-x: auto;
760
- font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace;
826
+ font-family:
827
+ 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace;
761
828
  font-size: 0.85rem;
762
829
  line-height: 1.6;
763
830
  max-width: 100%;
@@ -806,13 +873,22 @@ export const DemoButtonLink = styled.a`
806
873
  left: -100%;
807
874
  width: 100%;
808
875
  height: 100%;
809
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
876
+ background: linear-gradient(
877
+ 90deg,
878
+ transparent,
879
+ rgba(255, 255, 255, 0.1),
880
+ transparent
881
+ );
810
882
  animation: shine 2s infinite;
811
883
  }
812
884
 
813
885
  @keyframes shine {
814
- 0% { left: -100%; }
815
- 100% { left: 100%; }
886
+ 0% {
887
+ left: -100%;
888
+ }
889
+ 100% {
890
+ left: 100%;
891
+ }
816
892
  }
817
893
 
818
894
  &:hover {
@@ -33,8 +33,8 @@ export const Row = styled.div`
33
33
  justify-content: flex-start;
34
34
  align-items: center;
35
35
  font-size: 20px;
36
- word-wrap: break-word;
37
- word-break: break-all;
36
+ word-wrap: break-word;
37
+ word-break: break-all;
38
38
  overflow: hidden;
39
39
  padding-bottom: 10px;
40
40
 
@@ -4,4 +4,4 @@ export const useCurrentFlag = true // 是否使用当前目录环境
4
4
 
5
5
  export const outPhotoDic = 'Photos'
6
6
 
7
- export const outPhotoDicPath = path.join('D:', outPhotoDic)
7
+ export const outPhotoDicPath = path.join('D:', outPhotoDic)