Skip to content

Commit 2fb4372

Browse files
authored
Merge pull request #9 from weizwz/dev
Dev
2 parents cd5ce4f + a5814d5 commit 2fb4372

File tree

11 files changed

+193
-69
lines changed

11 files changed

+193
-69
lines changed

components/navigation/CategorySidebar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
} from '@dnd-kit/sortable';
2323
import { CSS } from '@dnd-kit/utilities';
2424
import { useAppDispatch, useAppSelector } from '@/store/hooks';
25-
import { setCurrentCategory } from '@/store/slices/settingsSlice';
25+
import { setCurrentCategory } from '@/store/slices/uiSlice';
2626
import {
2727
addCategory,
2828
deleteCategory,
@@ -135,7 +135,7 @@ const DraggableCategoryItem: React.FC<DraggableCategoryItemProps> = ({
135135
*/
136136
const CategorySidebarBase: React.FC<CategorySidebarProps> = ({ className, style }) => {
137137
const dispatch = useAppDispatch();
138-
const currentCategory = useAppSelector((state) => state.settings.currentCategory || '主页');
138+
const currentCategory = useAppSelector((state) => state.ui.currentCategory || '主页');
139139
const categories = useAppSelector((state) => state.categories.items);
140140
const links = useAppSelector((state) => state.links.items);
141141
const [mounted, setMounted] = useState(false);

components/navigation/LinkGrid.tsx

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import { reorderLinks } from '@/store/slices/linksSlice';
2121
import { LinkCard } from './LinkCard';
2222
import { Link } from '@/types/link';
2323
import { showSuccess } from '@/utils/feedback';
24-
import { getDefaultCategoryName } from '@/services/defaultData';
2524

2625
interface LinkGridProps {
2726
onEdit?: (link: Link) => void;
@@ -36,15 +35,10 @@ interface LinkGridProps {
3635
* 支持根据分类和搜索状态过滤链接
3736
* 使用 React.memo 和 useMemo 优化性能
3837
*/
39-
const LinkGridBase: React.FC<LinkGridProps> = ({
40-
onEdit,
41-
onDelete,
42-
className,
43-
style
44-
}) => {
38+
const LinkGridBase: React.FC<LinkGridProps> = ({ onEdit, onDelete, className, style }) => {
4539
const dispatch = useAppDispatch();
4640
const links = useAppSelector((state) => state.links.items);
47-
const currentCategory = useAppSelector((state) => state.settings.currentCategory || getDefaultCategoryName());
41+
const currentCategory = useAppSelector((state) => state.ui.currentCategory || '主页');
4842
const searchQuery = useAppSelector((state) => state.search.query);
4943
const searchResults = useAppSelector((state) => state.search.results);
5044

@@ -97,20 +91,23 @@ const LinkGridBase: React.FC<LinkGridProps> = ({
9791
}, [links, currentCategory, searchQuery, searchResults]);
9892

9993
// 处理拖拽结束
100-
const handleDragEnd = useCallback((event: DragEndEvent) => {
101-
const { active, over } = event;
102-
103-
if (over && active.id !== over.id) {
104-
// 在所有链接中查找索引(不是 displayedLinks)
105-
const oldIndex = links.findIndex((link) => link.id === active.id);
106-
const newIndex = links.findIndex((link) => link.id === over.id);
107-
108-
if (oldIndex !== -1 && newIndex !== -1) {
109-
dispatch(reorderLinks({ fromIndex: oldIndex, toIndex: newIndex }));
110-
showSuccess('链接排序已更新');
94+
const handleDragEnd = useCallback(
95+
(event: DragEndEvent) => {
96+
const { active, over } = event;
97+
98+
if (over && active.id !== over.id) {
99+
// 在所有链接中查找索引(不是 displayedLinks)
100+
const oldIndex = links.findIndex((link) => link.id === active.id);
101+
const newIndex = links.findIndex((link) => link.id === over.id);
102+
103+
if (oldIndex !== -1 && newIndex !== -1) {
104+
dispatch(reorderLinks({ fromIndex: oldIndex, toIndex: newIndex }));
105+
showSuccess('链接排序已更新');
106+
}
111107
}
112-
}
113-
}, [links, dispatch]);
108+
},
109+
[links, dispatch]
110+
);
114111

115112
// 空状态判断
116113
const isEmpty = displayedLinks.length === 0;
@@ -121,24 +118,34 @@ const LinkGridBase: React.FC<LinkGridProps> = ({
121118
if (isEmpty) {
122119
if (isSearchEmpty) {
123120
return (
124-
<div className={className} style={{ ...style, display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '400px' }}>
125-
<Empty
126-
description={
127-
<span>
128-
没有找到与 &quot;{searchQuery}&quot; 相关的链接
129-
</span>
130-
}
131-
/>
121+
<div
122+
className={className}
123+
style={{
124+
...style,
125+
display: 'flex',
126+
alignItems: 'center',
127+
justifyContent: 'center',
128+
minHeight: '400px',
129+
}}
130+
>
131+
<Empty description={<span>没有找到与 &quot;{searchQuery}&quot; 相关的链接</span>} />
132132
</div>
133133
);
134134
}
135135

136136
if (isCategoryEmpty) {
137137
return (
138-
<div className={className} style={{ ...style, display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '400px' }}>
139-
<Empty
140-
description={`${currentCategory}分类暂无链接`}
141-
/>
138+
<div
139+
className={className}
140+
style={{
141+
...style,
142+
display: 'flex',
143+
alignItems: 'center',
144+
justifyContent: 'center',
145+
minHeight: '400px',
146+
}}
147+
>
148+
<Empty description={`${currentCategory}分类暂无链接`} />
142149
</div>
143150
);
144151
}
@@ -159,11 +166,17 @@ const LinkGridBase: React.FC<LinkGridProps> = ({
159166
strategy={rectSortingStrategy}
160167
disabled={!isDraggingEnabled}
161168
>
162-
<div
163-
className={`grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 3xl:grid-cols-6 4xl:grid-cols-7 5xl:grid-cols-8 6xl:grid-cols-9 7xl:grid-cols-10 gap-x-8 gap-y-6 p-4 sm:p-8 md:px-10 max-w-full ${className || ''}`}
169+
<div
170+
className={`grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 3xl:grid-cols-6 4xl:grid-cols-7 5xl:grid-cols-8 6xl:grid-cols-9 7xl:grid-cols-10 gap-x-8 gap-y-6 p-4 sm:p-8 md:px-10 max-w-full ${
171+
className || ''
172+
}`}
164173
style={{ ...style, width: '100%', boxSizing: 'border-box' }}
165174
role="region"
166-
aria-label={searchQuery.trim() ? `搜索结果:${displayedLinks.length} 个链接` : `${currentCategory}分类:${displayedLinks.length} 个链接`}
175+
aria-label={
176+
searchQuery.trim()
177+
? `搜索结果:${displayedLinks.length} 个链接`
178+
: `${currentCategory}分类:${displayedLinks.length} 个链接`
179+
}
167180
>
168181
{displayedLinks.map((link) => (
169182
<LinkCard

next.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import type { NextConfig } from 'next';
2+
import { updateVersion } from './scripts/update-version';
3+
4+
// 自动更新版本号
5+
updateVersion();
26

37
const nextConfig: NextConfig = {
48
// 启用静态导出

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "frontend-navigation-site",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"private": true,
55
"scripts": {
66
"dev": "next dev",
@@ -49,4 +49,4 @@
4949
"tailwindcss": "^4.0.0",
5050
"typescript": "^5.6.0"
5151
}
52-
}
52+
}

public/sw.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Service Worker for PWA
2-
const CACHE_NAME = 'weiz-nav-v4';
3-
const RUNTIME_CACHE = 'weiz-nav-runtime-v4';
4-
const IMAGE_CACHE = 'weiz-nav-images-v4';
2+
const CACHE_NAME = 'weiz-nav-v0_1_1';
3+
const RUNTIME_CACHE = 'weiz-nav-runtime-v0_1_1';
4+
const IMAGE_CACHE = 'weiz-nav-images-v0_1_1';
55

66
// 需要预缓存的静态资源
77
const PRECACHE_URLS = [

public/version.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"version": "1.0.4",
3-
"buildTime": "2025-11-19T15:26:00.000Z",
4-
"cacheVersion": "v4",
2+
"version": "0.1.1",
3+
"buildTime": "2025-12-02T08:58:52.853Z",
4+
"cacheVersion": "v0_1_1",
55
"changelog": [
66
"修复 CSP 策略,支持所有 HTTPS 资源",
77
"优化图标缓存策略",

scripts/update-version.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
4+
/**
5+
* 更新版本号
6+
* 读取 package.json 的版本号,同步到 public/version.json 和 public/sw.js
7+
*/
8+
export function updateVersion() {
9+
// 路径配置
10+
const PATHS = {
11+
package: path.join(process.cwd(), 'package.json'),
12+
version: path.join(process.cwd(), 'public/version.json'),
13+
sw: path.join(process.cwd(), 'public/sw.js'),
14+
};
15+
16+
try {
17+
// 读取 package.json
18+
const pkg = JSON.parse(fs.readFileSync(PATHS.package, 'utf8'));
19+
const version = pkg.version;
20+
const cacheVersion = `v${version.replace(/\./g, '_')}`; // e.g., 1.0.5 -> v1_0_5
21+
22+
// 1. 更新 public/version.json
23+
let versionData: any = {};
24+
if (fs.existsSync(PATHS.version)) {
25+
versionData = JSON.parse(fs.readFileSync(PATHS.version, 'utf8'));
26+
}
27+
28+
// 检查是否需要更新
29+
if (versionData.version === version) {
30+
// 版本号相同,不更新
31+
return;
32+
}
33+
34+
console.log(`Updating version to ${version} (Cache: ${cacheVersion})...`);
35+
36+
versionData.version = version;
37+
versionData.buildTime = new Date().toISOString();
38+
versionData.cacheVersion = cacheVersion;
39+
40+
fs.writeFileSync(PATHS.version, JSON.stringify(versionData, null, 2) + '\n');
41+
console.log('✓ Updated public/version.json');
42+
43+
// 2. 更新 public/sw.js
44+
let swContent = fs.readFileSync(PATHS.sw, 'utf8');
45+
46+
// 更新 CACHE_NAME
47+
swContent = swContent.replace(
48+
/const CACHE_NAME = ['"]weiz-nav-v[^'"]+['"];/,
49+
`const CACHE_NAME = 'weiz-nav-${cacheVersion}';`
50+
);
51+
52+
// 更新 RUNTIME_CACHE
53+
swContent = swContent.replace(
54+
/const RUNTIME_CACHE = ['"]weiz-nav-runtime-v[^'"]+['"];/,
55+
`const RUNTIME_CACHE = 'weiz-nav-runtime-${cacheVersion}';`
56+
);
57+
58+
// 更新 IMAGE_CACHE
59+
swContent = swContent.replace(
60+
/const IMAGE_CACHE = ['"]weiz-nav-images-v[^'"]+['"];/,
61+
`const IMAGE_CACHE = 'weiz-nav-images-${cacheVersion}';`
62+
);
63+
64+
fs.writeFileSync(PATHS.sw, swContent);
65+
console.log('✓ Updated public/sw.js');
66+
67+
console.log('Version update complete!');
68+
} catch (error) {
69+
console.error('✗ Failed to update version:', error);
70+
// 不抛出错误,以免影响构建流程
71+
}
72+
}

store/index.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import linksReducer from './slices/linksSlice';
33
import searchReducer from './slices/searchSlice';
44
import settingsReducer from './slices/settingsSlice';
55
import categoriesReducer from './slices/categoriesSlice';
6+
import uiReducer from './slices/uiSlice';
67
import { storageService } from '@/services/storage';
78

89
/**
@@ -12,10 +13,10 @@ import { storageService } from '@/services/storage';
1213
*/
1314
const localStorageSyncMiddleware: Middleware = (store) => (next) => (action) => {
1415
const result = next(action);
15-
16+
1617
// 获取 action 的类型
1718
const actionType = (action as { type?: string }).type || '';
18-
19+
1920
// 如果是 links 相关的 action,同步 links 数据
2021
if (typeof actionType === 'string' && actionType.startsWith('links/')) {
2122
const state = store.getState();
@@ -28,7 +29,7 @@ const localStorageSyncMiddleware: Middleware = (store) => (next) => (action) =>
2829
console.error('Failed to sync links to LocalStorage:', error);
2930
}
3031
}
31-
32+
3233
// 如果是 categories 相关的 action,同步 categories 数据
3334
if (typeof actionType === 'string' && actionType.startsWith('categories/')) {
3435
const state = store.getState();
@@ -38,7 +39,7 @@ const localStorageSyncMiddleware: Middleware = (store) => (next) => (action) =>
3839
console.error('Failed to sync categories to LocalStorage:', error);
3940
}
4041
}
41-
42+
4243
// 如果是 settings 相关的 action,同步 settings 数据
4344
if (typeof actionType === 'string' && actionType.startsWith('settings/')) {
4445
const state = store.getState();
@@ -53,7 +54,7 @@ const localStorageSyncMiddleware: Middleware = (store) => (next) => (action) =>
5354
console.error('Failed to sync settings to LocalStorage:', error);
5455
}
5556
}
56-
57+
5758
return result;
5859
};
5960

@@ -66,6 +67,7 @@ export const store = configureStore({
6667
search: searchReducer,
6768
settings: settingsReducer,
6869
categories: categoriesReducer,
70+
ui: uiReducer,
6971
},
7072
middleware: (getDefaultMiddleware) =>
7173
getDefaultMiddleware({

store/slices/settingsSlice.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
22
import { Settings, ThemeMode, LayoutMode, UpdateSettingsInput } from '@/types';
3-
import { getDefaultCategoryName } from '@/services/defaultData';
43

54
/**
65
* Settings 状态接口
@@ -19,7 +18,6 @@ const defaultSettings: Settings = {
1918
theme: 'system',
2019
searchEngine: 'google',
2120
layout: 'grid',
22-
currentCategory: getDefaultCategoryName(),
2321
showDescription: true,
2422
gridColumns: 6,
2523
};
@@ -65,14 +63,6 @@ const settingsSlice = createSlice({
6563
state.error = null;
6664
},
6765

68-
/**
69-
* 设置当前分类
70-
*/
71-
setCurrentCategory: (state, action: PayloadAction<string>) => {
72-
state.currentCategory = action.payload;
73-
state.error = null;
74-
},
75-
7666
/**
7767
* 设置是否显示描述
7868
*/
@@ -148,7 +138,6 @@ export const {
148138
setTheme,
149139
setSearchEngine,
150140
setLayout,
151-
setCurrentCategory,
152141
setShowDescription,
153142
setGridColumns,
154143
updateSettings,

0 commit comments

Comments
 (0)