nsbp-cli 0.2.26 → 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.
- package/README.md +1 -1
- package/bin/nsbp.js +94 -74
- package/package.json +1 -1
- package/templates/basic/README.md +43 -0
- package/templates/basic/docs/DEVELOPMENT_GUIDE.md +290 -0
- package/templates/basic/docs/ESLINT_AND_PRETTIER.md +184 -0
- package/templates/basic/docs/HUSKY_9_UPGRADE.md +76 -0
- package/templates/basic/docs/HUSKY_ESLINT_SETUP.md +293 -0
- package/templates/basic/docs/SETUP_GIT_HOOKS.md +106 -0
- package/templates/basic/gitignore +3 -0
- package/templates/basic/package.json +27 -3
- package/templates/basic/scripts/setup-husky.js +24 -0
- package/templates/basic/src/Routers.tsx +4 -5
- package/templates/basic/src/client/index.tsx +6 -2
- package/templates/basic/src/component/Header.tsx +10 -10
- package/templates/basic/src/component/Layout.tsx +10 -4
- package/templates/basic/src/component/Theme.tsx +6 -2
- package/templates/basic/src/containers/Home.tsx +142 -77
- package/templates/basic/src/containers/Login.tsx +3 -3
- package/templates/basic/src/containers/Photo.tsx +37 -25
- package/templates/basic/src/externals/window.d.ts +3 -1
- package/templates/basic/src/reducers/home.ts +1 -1
- package/templates/basic/src/reducers/index.ts +1 -1
- package/templates/basic/src/reducers/photo.ts +8 -3
- package/templates/basic/src/server/index.ts +35 -26
- package/templates/basic/src/server/photo.ts +14 -7
- package/templates/basic/src/server/utils.tsx +13 -15
- package/templates/basic/src/services/home.ts +3 -28
- package/templates/basic/src/services/photo.ts +30 -32
- package/templates/basic/src/store/constants.ts +1 -1
- package/templates/basic/src/store/index.ts +3 -2
- package/templates/basic/src/styled/component/header.ts +5 -1
- package/templates/basic/src/styled/home.ts +100 -24
- package/templates/basic/src/styled/photo.ts +2 -2
- package/templates/basic/src/utils/config.ts +1 -1
- package/templates/basic/src/utils/fetch.ts +4 -8
- package/templates/basic/src/utils/index.ts +1 -1
- package/templates/basic/tsconfig.json +6 -1
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import React, { Fragment, useState, useEffect } from 'react'
|
|
2
2
|
import { connect } from 'react-redux'
|
|
3
3
|
import { Link, useLocation } from 'react-router-dom'
|
|
4
|
-
import Header from '
|
|
5
|
-
import Layout from '
|
|
4
|
+
import Header from '@components/Header'
|
|
5
|
+
import Layout from '@components/Layout'
|
|
6
6
|
import { Helmet } from 'react-helmet'
|
|
7
|
-
import { Container, Row } from '
|
|
7
|
+
import { Container, Row } from '@styled/photo'
|
|
8
8
|
import { motion } from 'framer-motion'
|
|
9
|
-
import { isSEO, getLocationParams } from '
|
|
10
|
-
import { useCurrentFlag } from '
|
|
9
|
+
import { isSEO, getLocationParams } from '@/utils'
|
|
10
|
+
import { useCurrentFlag } from '@utils/clientConfig'
|
|
11
11
|
import _ from 'lodash'
|
|
12
|
-
import { loadData } from '
|
|
12
|
+
import { loadData } from '@services/photo'
|
|
13
13
|
|
|
14
|
-
const springSettings = { type:
|
|
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) => {
|
|
18
18
|
const location = useLocation()
|
|
19
|
-
let {
|
|
19
|
+
let { from } = query
|
|
20
20
|
const photos = Array.isArray(data) ? data : []
|
|
21
21
|
const [currPhoto, setCurrPhoto] = useState(0)
|
|
22
22
|
|
|
@@ -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(
|
|
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(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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}`}>
|
|
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={
|
|
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?:
|
|
4
|
+
menu?:
|
|
5
|
+
| Record<string, any>
|
|
6
|
+
| Array<{ name: string; cover?: string; count?: number }>
|
|
5
7
|
}
|
|
6
8
|
query?: Record<string, any>
|
|
7
9
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { homeReducer } from './home'
|
|
2
2
|
import { photoReducer } from './photo'
|
|
3
|
-
import { REQUEST_QUERY } from '
|
|
3
|
+
import { REQUEST_QUERY } from '@store/constants'
|
|
4
4
|
|
|
5
5
|
const queryReducer = (state = {}, action: any) => {
|
|
6
6
|
const { type, query } = action
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { GET_PHOTO_MENU, GET_PHOTO_WIDTH_HEIGHT } from '
|
|
1
|
+
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:
|
|
5
|
+
menu:
|
|
6
|
+
| Record<string, any>
|
|
7
|
+
| Array<{ name: string; cover?: string; count?: number }>
|
|
6
8
|
}
|
|
7
9
|
|
|
8
|
-
export const photoReducer = (
|
|
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(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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
|
|
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(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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 &&
|
|
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
|
|
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 = (
|
|
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
|
|
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
|
|
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
|
|
132
|
+
res
|
|
133
|
+
.status(500)
|
|
134
|
+
.json({ error: 'Internal Server Error', details: err.message })
|
|
128
135
|
}
|
|
129
136
|
}
|
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { renderToString } from 'react-dom/server'
|
|
3
3
|
import { StaticRouter, Route, matchPath } from 'react-router-dom'
|
|
4
|
-
// @ts-ignore - Routes is available in react-router-dom v7 but not in types
|
|
5
4
|
import { Routes } from 'react-router-dom'
|
|
6
|
-
import routers from '
|
|
7
|
-
// @ts-ignore
|
|
5
|
+
import routers from '@/Routers'
|
|
8
6
|
import { Provider } from 'react-redux'
|
|
9
|
-
|
|
10
|
-
import getStore from '../store'
|
|
7
|
+
import getStore from '@store'
|
|
11
8
|
import serialize from 'serialize-javascript'
|
|
12
|
-
|
|
13
|
-
import { REQUEST_QUERY } from '../store/constants'
|
|
9
|
+
import { REQUEST_QUERY } from '@store/constants'
|
|
14
10
|
import { Helmet } from 'react-helmet'
|
|
15
11
|
import { ServerStyleSheet } from 'styled-components'
|
|
16
|
-
import Theme from '
|
|
12
|
+
import Theme from '@components/Theme'
|
|
17
13
|
import path from 'path'
|
|
18
14
|
import { ChunkExtractor } from '@loadable/server'
|
|
19
15
|
|
|
20
16
|
export const render = (req: any, res: any) => {
|
|
21
17
|
const store = getStore()
|
|
22
|
-
const { path:reqPath, query } = req
|
|
18
|
+
const { path: reqPath, query } = req
|
|
23
19
|
const matchRoutes: any = []
|
|
24
20
|
const promises = []
|
|
25
21
|
|
|
@@ -75,10 +71,7 @@ export const render = (req: any, res: any) => {
|
|
|
75
71
|
|
|
76
72
|
const helmet: any = Helmet.renderStatic()
|
|
77
73
|
|
|
78
|
-
const webStats = path.resolve(
|
|
79
|
-
__dirname,
|
|
80
|
-
'../public/loadable-stats.json',
|
|
81
|
-
)
|
|
74
|
+
const webStats = path.resolve(__dirname, '../public/loadable-stats.json')
|
|
82
75
|
|
|
83
76
|
try {
|
|
84
77
|
let webEntryPoints = ['client', 'vendor']
|
|
@@ -93,13 +86,18 @@ export const render = (req: any, res: any) => {
|
|
|
93
86
|
publicPath: '/'
|
|
94
87
|
})
|
|
95
88
|
|
|
96
|
-
const jsx = webExtractor.collectChunks(
|
|
89
|
+
const jsx = webExtractor.collectChunks(
|
|
90
|
+
sheet.collectStyles(
|
|
97
91
|
<Theme>
|
|
98
92
|
<Provider store={store}>
|
|
99
93
|
<StaticRouter location={reqPath}>
|
|
100
94
|
<Routes>
|
|
101
95
|
{routers.map((router) => (
|
|
102
|
-
<Route
|
|
96
|
+
<Route
|
|
97
|
+
key={router.key}
|
|
98
|
+
path={router.path}
|
|
99
|
+
element={router.element}
|
|
100
|
+
/>
|
|
103
101
|
))}
|
|
104
102
|
</Routes>
|
|
105
103
|
</StaticRouter>
|
|
@@ -1,30 +1,5 @@
|
|
|
1
|
-
import { doGet } from '
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
const getData = (callback: any) => {
|
|
5
|
-
|
|
6
|
-
return (dispatch: any) => {
|
|
7
|
-
doGet('https://api.apiopen.top/getJoke?page=1&count=2&type=video')
|
|
8
|
-
.then((res:any) => {
|
|
9
|
-
// console.log('res', res)
|
|
10
|
-
dispatch({
|
|
11
|
-
type: GITHUB_ZEITNEXT_GET,
|
|
12
|
-
data: res?.data
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
callback && callback()
|
|
16
|
-
})
|
|
17
|
-
.catch((e:any) => {
|
|
18
|
-
// console.log('e', e.response)
|
|
19
|
-
dispatch({
|
|
20
|
-
type: GITHUB_ZEITNEXT_GET,
|
|
21
|
-
data: e?.response?.data
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
callback && callback()
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
import { doGet } from '@utils/fetch'
|
|
2
|
+
import { GET_PHOTO_MENU } from '@store/constants'
|
|
28
3
|
|
|
29
4
|
export const loadData = (resolve: any = null) => {
|
|
30
5
|
return (dispatch: any) => {
|
|
@@ -49,4 +24,4 @@ export const loadData = (resolve: any = null) => {
|
|
|
49
24
|
resolve && resolve()
|
|
50
25
|
})
|
|
51
26
|
}
|
|
52
|
-
}
|
|
27
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { doGet } from '
|
|
2
|
-
import { GET_PHOTO_MENU, GET_PHOTO_WIDTH_HEIGHT } from '
|
|
3
|
-
|
|
1
|
+
import { doGet } from '@utils/fetch'
|
|
2
|
+
import { GET_PHOTO_MENU, GET_PHOTO_WIDTH_HEIGHT } from '@store/constants'
|
|
4
3
|
|
|
5
4
|
const getPhotoWH = (dispatch: any, callback: any, dic = '') => {
|
|
6
5
|
let action = 'getPhotoWH'
|
|
@@ -9,47 +8,46 @@ const getPhotoWH = (dispatch: any, callback: any, dic = '') => {
|
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
doGet(action)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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'
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { configureStore, combineReducers } from '@reduxjs/toolkit'
|
|
2
|
-
import reducers from '
|
|
2
|
+
import reducers from '@reducers'
|
|
3
3
|
|
|
4
4
|
const combineReducer = combineReducers({ ...reducers })
|
|
5
5
|
|
|
6
6
|
const getStore = (stateParam = {}) => {
|
|
7
7
|
return configureStore({
|
|
8
|
-
reducer: (state: any, action: any) =>
|
|
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(
|
|
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);
|