Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"eslint": "^9.9.1",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.11",
"fake-indexeddb": "^6.2.5",
"github-markdown-css": "^5.9.0",
"globals": "^15.9.0",
"highlight.js": "^11.11.1",
Expand Down
38 changes: 32 additions & 6 deletions src/components/ReadmeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,39 @@ export const ReadmeModal: React.FC<ReadmeModalProps> = ({
}
}, []);

const scrollRafRef = useRef<number | null>(null);
const scrollFrameUsesRafRef = useRef(false);

// 进度条读取 scrollHeight/clientHeight 会强制布局,用 rAF 合帧避免滚动时反复重排。
const handleScroll = useCallback(() => {
if (!contentRef.current) return;
const container = contentRef.current;
const { scrollTop, scrollHeight, clientHeight } = container;
const progress = scrollHeight <= clientHeight ? 0 : (scrollTop / (scrollHeight - clientHeight)) * 100;
setScrollProgress(Math.min(100, Math.max(0, progress)));
setShowBackToTop(scrollTop > 300);
if (scrollRafRef.current !== null) return;
const run = () => {
scrollRafRef.current = null;
if (!contentRef.current) return;
const container = contentRef.current;
const { scrollTop, scrollHeight, clientHeight } = container;
const progress = scrollHeight <= clientHeight ? 0 : (scrollTop / (scrollHeight - clientHeight)) * 100;
setScrollProgress(Math.min(100, Math.max(0, progress)));
setShowBackToTop(scrollTop > 300);
};
// 记录本次调度用的 API:取消时按同一 API 取消,避免环境变化后错配 id 类型。
if (typeof window.requestAnimationFrame === 'function') {
scrollFrameUsesRafRef.current = true;
scrollRafRef.current = window.requestAnimationFrame(run);
} else {
scrollFrameUsesRafRef.current = false;
scrollRafRef.current = window.setTimeout(run, 16) as unknown as number;
}
}, []);

useEffect(() => () => {
if (scrollRafRef.current === null) return;
if (scrollFrameUsesRafRef.current) {
window.cancelAnimationFrame(scrollRafRef.current);
} else {
window.clearTimeout(scrollRafRef.current);
}
scrollRafRef.current = null;
}, []);

useEffect(() => {
Expand Down
11 changes: 8 additions & 3 deletions src/components/settings/DataManagementPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ import {
Rss,
} from 'lucide-react';
import { useAppStore } from '../../store/useAppStore';
import { removePersistedSnapshot } from '../../store/persistence/storage';
import { useShallow } from 'zustand/react/shallow';
import { isThemePresetId } from '../../constants/themePresets';
import type { ThemePresetId } from '../../constants/themePresets';
import { indexedDBStorage } from '../../services/indexedDbStorage';
import { IncludeKeysToggle } from './IncludeKeysToggle';
import type {
Repository,
Expand Down Expand Up @@ -367,9 +367,14 @@ export const DataManagementPanel: React.FC<DataManagementPanelProps> = ({ t }) =
// Clear sessionStorage - only remove app-owned keys
APP_SESSIONSTORAGE_KEYS.forEach((key) => sessionStorage.removeItem(key));

// Clear IndexedDB - only remove the specific database used by this app
// Clear IndexedDB - only remove the specific database used by this app.
// 走持久化层的串行删除:除磁盘清扫外,还会在串行写链上取消待写、完成删除并
// 重置分片判脏簿记——直接调底层 removeItem 会让随后的 store 重置写入以过期
// 基准判脏,只补写部分分片,而 meta 仍声明全部分片。
// 必须 await 删除真正落盘(zustand v4 的 clearStorage 不回传 Promise):
// 若链上还有排队的大写入,2 秒后的 reload 可能早于删除提交,数据复活。
try {
await indexedDBStorage.removeItem('github-stars-manager');
await removePersistedSnapshot(useAppStore.persist.getOptions().name ?? 'github-stars-manager');
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
} catch (error) {
console.error('Failed to clear IndexedDB', error);
throw new Error('IndexedDB clear failed');
Expand Down
Loading
Loading