Conversation
refactor(RepositoryEditModal): 修复自定义描述为空时的处理逻辑
移除传统的分页组件,改为实现无限滚动加载模式 新增加载更多按钮组件,优化大数据量下的用户体验 简化页码管理逻辑,减少不必要的状态和计算
添加 discoveryIsLoadingMore 和 discoveryLoadMoreError 状态用于管理加载更多操作 实现加载更多时的滚动定位和错误处理 优化频道切换时的状态重置逻辑
扩展 AI 服务类型以支持兼容 OpenAI API 的自定义端点,包括: 1. 在类型定义中添加 'openai-compatible' 选项 2. 修改请求处理逻辑以直接使用自定义端点的完整 URL 3. 在配置面板中增加相关说明和最终请求地址预览
当选择搜索频道时,显示不同的空状态UI和提示信息,包括搜索图标和搜索引导文本,而非默认的刷新按钮和数据提示
实现使用IndexedDB存储和加载仓库AI分析结果,包括保存、加载、批量加载和删除功能。在DiscoveryView组件中集成该存储服务,确保分析结果在页面刷新后仍可保留。
调整卡片悬停时的阴影、边框和位移效果,统一桌面安全模式和非安全模式下的交互体验
改进标题ID生成算法以避免重复,添加对Markdown格式文本的处理 优化目录提取逻辑,正确处理重复标题并去除Markdown格式 添加错误处理以防止平滑滚动失败时页面无法滚动
添加 Tailwind Typography 插件以增强 Markdown 渲染样式 重构 ReadmeModal 组件,移除进度条并优化 TOC 显示 为模态框添加状态管理,自动隐藏底部导航按钮 重构 MarkdownRenderer 组件,优化代码块样式和暗色模式支持 添加自定义滚动条样式,提升阅读体验
将提示信息从“当前页面所有项目”改为“已加载的所有项目”,以更准确地反映实际分析范围
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Vitest testing and setup, Tailwind typography, README modal TOC/scrolling and stable heading IDs, readmeModalOpen store flag with UI suppression for scroll buttons, per-channel discovery load-more state and persistence tweaks, DB open timeout/onLate handling, and extensive Markdown renderer/CSS refactors. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant UI as Readme Modal / DiscoveryView
participant Store as App Store
participant API as Server/API
participant DB as Analysis Storage
U->>UI: Click "Load more" / Open README
UI->>Store: setDiscoveryLoadingMore(channel, true)
UI->>API: fetch next page for channel
API-->>UI: return repos
UI->>DB: loadAllAnalyses() withTimeout(3000, onLate -> close)
alt DB responds before timeout
DB-->>UI: analyses
else DB late
DB->>DB: onLate callback -> close late connection
end
UI->>Store: append repos, setDiscoveryLoadingMore(channel,false)
Store->>UI: render updated repo list / modal open state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Read md up
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
src/components/RepositoryEditModal.tsx (1)
723-760: Inconsistent defensive handling offormData.description.The hardening to
(formData.description || '').trim()was applied to lines 647, 652, 723, and 280/460-462, but two sibling branches still accessformData.descriptiondirectly:
- Line 640:
formData.description.length > 0- Line 748:
formData.description.trim() !== ''If the intent is to defend against
null/undefinedsneaking intoformData.description, these two spots will still throw (and line 748 sits in the same ternary chain as the guarded line 723, making the inconsistency more visible). IfformData.descriptionis guaranteed to be a string (it's initialized to''and every setter passes a string), the added|| ''guards elsewhere are unnecessary.Pick one direction and apply it consistently.
♻️ Proposed fix — consistent guarding
- {formData.description.length > 0 ? `${formData.description.length} ${t('字符', 'chars')}` : t('无内容', 'Empty')} + {(formData.description || '').length > 0 ? `${(formData.description || '').length} ${t('字符', 'chars')}` : t('无内容', 'Empty')}- ) : editIntent.description === 'keep-custom' && formData.description.trim() !== '' && !customStatus.description ? ( + ) : editIntent.description === 'keep-custom' && (formData.description || '').trim() !== '' && !customStatus.description ? (Alternatively, if
formData.descriptionis trusted to always be a string, revert the other(formData.description || '')additions and rely on the type.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/RepositoryEditModal.tsx` around lines 723 - 760, Inconsistent defensive access to formData.description can cause runtime errors; make handling uniform by always guarding against null/undefined (e.g. replace direct uses of formData.description.length > 0 and formData.description.trim() !== '' with (formData.description || '').length > 0 and (formData.description || '').trim() !== ''), keeping the current guarded checks (e.g. existing (formData.description || '').trim()) and leave checks on editIntent.description and customStatus.description unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/MarkdownRenderer.tsx`:
- Around line 783-797: The inline code renderer destructures an unused node
variable which ESLint flags and risks being forwarded via {...props}; update the
renderer signature from "({ className, children, node, ...props }) =>" to "({
className, children, ...props }) =>" and keep the rest of the logic the same
(preserve isInline, match / language extraction, and the CodeBlock usage) so
node is no longer present or passed through.
- Around line 706-716: getHeadingId can produce duplicate IDs because headingIds
contains generated IDs like "heading-0" while the fallback returns the same
pattern using headingCounter; update getHeadingId to avoid collisions by
namespacing or offsetting the fallback IDs: either (a) prefix fallback IDs
(e.g., "fallback-heading-") when returning `heading-${headingCounter++}` so they
never collide with ReadmeModal.extractToc IDs, or (b) on initialization when
headingIds is present seed/advance headingCounter to a value greater than any
numeric suffix in headingIds (compute max numeric suffix from headingIds values
and set headingCounter = max+1) so subsequent fallback IDs won’t collide; apply
this change around getHeadingId and where headingCounter/headingIds are
initialized (refer to getHeadingId, headingIds, headingTextCountMap,
headingCounter, and ReadmeModal.extractToc).
In `@src/index.css`:
- Line 232: The font-family declaration contains a quoted single-word font
'Consolas' which violates the font-family-name-quotes rule; update the
font-family list in the CSS (the font-family declaration line) by removing the
quotes around Consolas only, leaving multi-word names like 'Cascadia Code',
'Fira Code', and 'JetBrains Mono' quoted so stylelint no longer flags the rule.
In `@src/services/discoveryAnalysisStorage.ts`:
- Around line 16-39: withTimeout can leak an open IDBDatabase when the timeout
rejects before openDb() resolves; fix by changing withTimeout<T>(promise,
timeoutMs, onLateResolve?) to, when the timeout fires, attach promise.then(value
=> onLateResolve?.(value)). This ensures that if openDb() (the IDBOpenDBRequest
resolving to an IDBDatabase) completes after the timeout you invoke the provided
cleanup (e.g., pass db => db.close() at each withTimeout(openDb(), ... ) call
site). Keep openDb as-is (it returns IDBDatabase) and only add the optional
cleanup callback to withTimeout so late resolutions can be closed to avoid
leaking connections and blocking future onupgradeneeded.
In `@src/store/useAppStore.ts`:
- Around line 1182-1208: The setSelectedDiscoveryChannel updater currently
always clears discoveryRepos[selectedDiscoveryChannel], causing unnecessary
wipes and refetches when the user re-selects the same tab; update the
setSelectedDiscoveryChannel function in useAppStore.ts to early-return/no-op
when the new selectedDiscoveryChannel equals the current
state.selectedDiscoveryChannel (i.e., add a same-channel guard) and add a brief
inline comment above the reset logic explaining that repos are reset when
switching channels to trigger an auto-fetch for empty channels (but should not
reset when re-selecting the active channel).
---
Nitpick comments:
In `@src/components/RepositoryEditModal.tsx`:
- Around line 723-760: Inconsistent defensive access to formData.description can
cause runtime errors; make handling uniform by always guarding against
null/undefined (e.g. replace direct uses of formData.description.length > 0 and
formData.description.trim() !== '' with (formData.description || '').length > 0
and (formData.description || '').trim() !== ''), keeping the current guarded
checks (e.g. existing (formData.description || '').trim()) and leave checks on
editIntent.description and customStatus.description unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0fe2b535-d668-45fa-9fc8-cb8f33b21ed2
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (17)
package.jsonserver/src/routes/proxy.tssrc/components/BackToTop.tsxsrc/components/DiscoveryView.tsxsrc/components/MarkdownRenderer.tsxsrc/components/ReadmeModal.tsxsrc/components/RepositoryEditModal.tsxsrc/components/ScrollToBottom.tsxsrc/components/SubscriptionRepoCard.tsxsrc/components/settings/AIConfigPanel.tsxsrc/index.csssrc/services/aiService.tssrc/services/discoveryAnalysisStorage.tssrc/store/useAppStore.tssrc/types/index.tssrc/utils/apiUrlBuilder.tstailwind.config.js
当用户重复选择当前已选频道时,避免不必要的滚动位置保存和更新操作
PR #98 审计:阅读 MD 增强🟢 正面评价
🔴 需修复1. Heading ID 冲突风险(
修复方案: fallback ID 用不同前缀(如 🟡 建议修复2. 未使用的 code: ({ className, children, node, ...props }) => {
3. CSS
4. timeout 先触发时, 5. 点当前已激活的 tab 会无脑清空 repos 触发重新 fetch。加个 ⚪ 观察项(不影响合并)
结论1 个必须修复(heading ID 冲突),4 个建议修复。冲突问题在复杂 README(含 h4+ 或图片标题)下必现,应在合并前处理。其余几项是 Lint 和防御性编码问题,建议一并修掉。 |
调整代码块字体设置,移除Consolas的引号以修复显示问题 修改标题ID生成逻辑,使用headingIds作为初始值并添加extra前缀
添加onLate回调参数以处理超时后的资源清理 重构withTimeout函数以支持更健壮的超时处理 在所有数据库操作中添加超时后的数据库连接关闭
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/components/DiscoveryView.tsx (1)
861-871: Good no-op guard on channel re-selection.Short-circuiting when the user taps the already-active channel prevents the
setSelectedDiscoveryChannelreducer insrc/store/useAppStore.ts(lines 1182–1208) from wipingdiscoveryRepos,discoveryNextPage,discoveryHasMore,discoveryTotalCount,discoveryIsLoadingMore, anddiscoveryLoadMoreErrorfor the current channel, which would otherwise force an unnecessary re-fetch via the auto-fetch effect at lines 601–615.Optional nit: the guard + scroll-position save +
setSelectedDiscoveryChannelblock is now duplicated between the mobile (862–871) and desktop (881–890) handlers. Consider extracting into a smallhandleChannelSelectcallback inside the component to keep the two call sites in sync going forward.♻️ Optional extraction
+ const handleChannelSelect = useCallback((channel: DiscoveryChannelId) => { + if (channel === selectedDiscoveryChannel) return; + if (scrollContainerRef.current) { + const scrollTop = scrollContainerRef.current.scrollTop; + discoveryScrollPositionsRef.current[selectedDiscoveryChannel] = scrollTop; + setDiscoveryScrollPosition(selectedDiscoveryChannel, scrollTop); + } + setSelectedDiscoveryChannel(channel); + }, [selectedDiscoveryChannel, setDiscoveryScrollPosition, setSelectedDiscoveryChannel]);Then reuse it in both
MobileTabNavandDiscoverySidebaronChannelSelectprops.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/DiscoveryView.tsx` around lines 861 - 871, The onChannelSelect logic is duplicated in MobileTabNav and DiscoverySidebar; extract a shared handler (e.g., handleChannelSelect) inside the DiscoveryView component that accepts a channel and performs the same steps: no-op if channel === selectedDiscoveryChannel, save scrollTop into discoveryScrollPositionsRef.current[selectedDiscoveryChannel] and call setDiscoveryScrollPosition(selectedDiscoveryChannel, scrollTop) when scrollContainerRef.current exists, then call setSelectedDiscoveryChannel(channel); replace both inline onChannelSelect props with this new handleChannelSelect to keep behavior consistent across MobileTabNav and DiscoverySidebar.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/MarkdownRenderer.tsx`:
- Around line 696-716: The heading text extraction currently returns raw
concatenated child text in extractTextFromChildren, causing mismatches with
ReadmeModal.extractToc keys; update extractTextFromChildren to normalize the
extracted text the same way stripMarkdownFormatting does (or import and call
stripMarkdownFormatting) so that getHeadingId uses normalized keys for
headingTextCountMap and headingIds lookups, ensuring images, extra/multiple
whitespace, and leading/trailing spaces are collapsed/trimmed consistently and
preventing fallback to heading-extra-* IDs.
In `@src/services/discoveryAnalysisStorage.ts`:
- Around line 32-56: The withTimeout helper currently calls onLate when the
primary promise resolves before the timeout (inverting the intended logic) and
keeps an unused lateValue; fix by inverting the guard so onLate is invoked only
when the timeout already fired (i.e. call onLate when isSettled === true),
remove the unused lateValue binding, and ensure the wrapped promise has a
.catch(() => {}) to swallow any late rejection after the timeout; use the
existing symbols withTimeout, isSettled, onLate, wrappedPromise, and
timeoutPromise to locate and apply these changes.
---
Nitpick comments:
In `@src/components/DiscoveryView.tsx`:
- Around line 861-871: The onChannelSelect logic is duplicated in MobileTabNav
and DiscoverySidebar; extract a shared handler (e.g., handleChannelSelect)
inside the DiscoveryView component that accepts a channel and performs the same
steps: no-op if channel === selectedDiscoveryChannel, save scrollTop into
discoveryScrollPositionsRef.current[selectedDiscoveryChannel] and call
setDiscoveryScrollPosition(selectedDiscoveryChannel, scrollTop) when
scrollContainerRef.current exists, then call
setSelectedDiscoveryChannel(channel); replace both inline onChannelSelect props
with this new handleChannelSelect to keep behavior consistent across
MobileTabNav and DiscoverySidebar.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 652a4539-19c9-4254-a700-e3cb64c54caf
📒 Files selected for processing (4)
src/components/DiscoveryView.tsxsrc/components/MarkdownRenderer.tsxsrc/index.csssrc/services/discoveryAnalysisStorage.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/index.css
|
可以测试后合并 |
|
调整超时处理逻辑,修正条件判断错误并添加对异步操作错误的处理
refactor(ReadmeModal): 重构目录导航和滚动功能 feat(MarkdownRenderer): 增强链接和图片处理逻辑 test: 添加markdownUtils和MarkdownRenderer的单元测试 build: 配置Vitest测试环境 style: 调整代码块和目录样式
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/components/MarkdownRenderer.tsx (1)
773-811:⚠️ Potential issue | 🟠 Major
extractTextFromChildrenstill doesn't match ReadmeModal's key normalization — headings with images or irregular whitespace miss the map and fall back toheading-extra-*.
ReadmeModal.extractTocbuildsidMapkeys viastripMarkdownFormatting, which (a) replaceswithalt, (b) collapses\s+to a single space, and (c) trims.extractTextFromChildrenhere does none of those, and additionally returns''for<img>elements becauseimg.props.childrenis undefined. Concrete mismatches:
#  Title→ TOC keylogo Title, renderer key' Title'(alt lost).## Hello world(double space) → TOC keyHello world, renderer keyHello world.## Title(leading/trailing whitespace in source) → TOC keyTitle, renderer key depends on parser trimming.When keys diverge the renderer falls back to
heading-extra-${n}, and the corresponding TOC item inReadmeModal.scrollToHeadingwon't find#heading-Nin the DOM. ThefallbackTextscan only helps whenheading.textContentexactly matches the TOC label, which is also not guaranteed here (e.g., images render as<img>with no text content).Suggested fix — either reuse
stripMarkdownFormattingon the extracted text, or handle the<img>case explicitly and normalize whitespace:🔧 Proposed fix
+import { stripMarkdownFormatting } from '../utils/markdownUtils'; + const extractTextFromChildren = (children: React.ReactNode): string => { if (typeof children === 'string') return children; if (typeof children === 'number') return String(children); if (Array.isArray(children)) return children.map(extractTextFromChildren).join(''); if (React.isValidElement(children)) { + const props = children.props as { children?: React.ReactNode; alt?: string }; + if (children.type === 'img' || children.type === MarkdownImage) { + return props.alt ?? ''; + } - return extractTextFromChildren((children.props as { children?: React.ReactNode }).children); + return extractTextFromChildren(props.children); } return ''; }; @@ const getHeadingId = useCallback((children: React.ReactNode): string | undefined => { if (headingIds && headingIds.size > 0) { - const text = extractTextFromChildren(children); + const text = stripMarkdownFormatting(extractTextFromChildren(children)); const count = headingTextCountMapRef.current.get(text) || 0;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/MarkdownRenderer.tsx` around lines 773 - 811, The heading id lookup fails because extractTextFromChildren doesn't normalize text the same way ReadmeModal.extractToc does; update extractTextFromChildren (and/or getHeadingId) to return the same canonical key: when encountering React elements handle <img> by using props.alt (or props['alt'] fallback) instead of children, collapse consecutive whitespace to a single space, and trim leading/trailing spaces (or simply call the existing stripMarkdownFormatting utility on the extracted string if available) before using headingTextCountMapRef/getHeadingId so keys match ReadmeModal.extractToc's idMap.
🧹 Nitpick comments (2)
src/services/discoveryAnalysisStorage.ts (1)
32-61: Critical fix from prior review is correctly applied — with one small redundancy left.Tracing the four paths confirms the inverted-guard bug from the previous review (fingerprint
0d479ab2) is resolved:
- Fast resolve (happy path):
isSettledisfalseat.then, soonLateis skipped and the caller receives an openIDBDatabase. ✓- Timeout wins, promise resolves late:
isSettled === truewhen.thenruns, soonLate(value)fires andlateDb.close()releases the connection. ✓- Early rejection: re-thrown,
Promise.racerejects, caller'stry/catchlogs a warning. ✓- Late rejection:
Promise.racealready observes both promises internally, so the rethrow on Line 50 won't surface as an unhandled rejection. ✓All four call sites (Lines 67, 89, 124, 161) pass
(lateDb) => lateDb.close(), so the original IDB-leak concern is addressed end-to-end.One tiny follow-up you could fold in later (not blocking):
♻️ Optional polish
The
onLate &&guard on Line 47 only gates aconsole.warn, which has nothing to do with cleanup — a late rejection is worth logging even when noonLateis wired up. RenamingisSettled→timedOutalso reads more accurately since the flag flips only on the timeout path, not on normal settlement.- let isSettled = false; + let timedOut = false; const wrappedPromise = promise .then((value) => { - if (isSettled && onLate) { + if (timedOut && onLate) { onLate(value); } return value; }) .catch((error) => { - if (isSettled && onLate) { + if (timedOut) { console.warn('[discoveryAnalysisStorage] Late error after timeout:', error); } throw error; }); const timeoutPromise = new Promise<T>((_, reject) => setTimeout(() => { - isSettled = true; + timedOut = true; reject(new Error('DiscoveryAnalysisStorage timeout')); }, timeoutMs) );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/services/discoveryAnalysisStorage.ts` around lines 32 - 61, The withTimeout helper currently uses isSettled and gates the console.warn in the .catch on the presence of onLate; change the flag name isSettled to timedOut to reflect it only flips on timeout, and remove the onLate guard around the late-error log so the .catch always logs late rejections (leave the onLate call in .then as-is to handle late success cleanup). Update references to isSettled to timedOut and keep the rest of withTimeout (promise wrapping, timeoutPromise, Promise.race) unchanged.src/index.css (1)
148-335: LGTM on the prose/scrollbar reorg and hljs dark-mode coverage.Moving prose styles under
@layer components(so they can be overridden by utilities) and scoping the newreadme-scrollbarseparately fromcategory-scrollbar/scrollbar-autois a clean split. The extended.dark .hljs-*rules (params/property/punctuation/tag/title) properly backfill what was lost by removing thegithub-dark.min.cssimport.One minor follow-up to keep in mind (not blocking): the structural selectors
.prose p > span > span > imgand.prose pre div[class*="border-r"] > divare tightly coupled to the exact JSX tree emitted byMarkdownRenderer/CodeBlock. If that structure changes (e.g., another wrapper), these rules will silently stop applying. A class hook on the relevant elements would be more refactor-proof.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/index.css` around lines 148 - 335, The structural CSS selectors (.prose p > span > span > img and .prose pre div[class*="border-r"] > div) are fragile; update the renderer and styles to use class hooks instead: add stable classNames in the MarkdownRenderer/CodeBlock JSX (e.g., md-image for images and code-gutter-item for the gutter/div wrapper) and replace the selectors in src/index.css with .prose .md-image:hover and .prose pre .code-gutter-item:hover (and their .dark variants), ensuring behavior stays the same but no longer depends on the exact DOM nesting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/ReadmeModal.tsx`:
- Around line 311-321: The TOC indent function tocIndentClass uses a
non-existent Tailwind class 'pl-15' for case 6, so level-6 headings get no
indent; update the case 6 return in tocIndentClass to a valid spacing class
(e.g., 'pl-16') or an arbitrary value (e.g., 'pl-[15px]') so level 6 renders
with the intended indentation.
In `@src/test/setup.ts`:
- Around line 32-33: The variable originalFetch is captured but never used;
either remove the assignment or restore the real fetch in teardown. Fix by
either deleting the line that assigns originalFetch or, if you intend to restore
native fetch between tests, add an afterEach (or afterAll) hook that sets
window.fetch = originalFetch and keep the existing window.fetch = vi.fn();
reference originalFetch, window.fetch, afterEach/afterAll, and vi.fn() to locate
and update the test setup.
---
Duplicate comments:
In `@src/components/MarkdownRenderer.tsx`:
- Around line 773-811: The heading id lookup fails because
extractTextFromChildren doesn't normalize text the same way
ReadmeModal.extractToc does; update extractTextFromChildren (and/or
getHeadingId) to return the same canonical key: when encountering React elements
handle <img> by using props.alt (or props['alt'] fallback) instead of children,
collapse consecutive whitespace to a single space, and trim leading/trailing
spaces (or simply call the existing stripMarkdownFormatting utility on the
extracted string if available) before using headingTextCountMapRef/getHeadingId
so keys match ReadmeModal.extractToc's idMap.
---
Nitpick comments:
In `@src/index.css`:
- Around line 148-335: The structural CSS selectors (.prose p > span > span >
img and .prose pre div[class*="border-r"] > div) are fragile; update the
renderer and styles to use class hooks instead: add stable classNames in the
MarkdownRenderer/CodeBlock JSX (e.g., md-image for images and code-gutter-item
for the gutter/div wrapper) and replace the selectors in src/index.css with
.prose .md-image:hover and .prose pre .code-gutter-item:hover (and their .dark
variants), ensuring behavior stays the same but no longer depends on the exact
DOM nesting.
In `@src/services/discoveryAnalysisStorage.ts`:
- Around line 32-61: The withTimeout helper currently uses isSettled and gates
the console.warn in the .catch on the presence of onLate; change the flag name
isSettled to timedOut to reflect it only flips on timeout, and remove the onLate
guard around the late-error log so the .catch always logs late rejections (leave
the onLate call in .then as-is to handle late success cleanup). Update
references to isSettled to timedOut and keep the rest of withTimeout (promise
wrapping, timeoutPromise, Promise.race) unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7cc35bc7-87d3-4d54-8eb6-55a14de8357e
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
package.jsonsrc/components/MarkdownRenderer.test.tsxsrc/components/MarkdownRenderer.tsxsrc/components/ReadmeModal.tsxsrc/index.csssrc/services/discoveryAnalysisStorage.tssrc/test/setup.tssrc/utils/markdownUtils.test.tssrc/utils/markdownUtils.tsvitest.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
Read md up
移除测试文件中未使用的originalFetch变量 修正ReadmeModal中6级标题的缩进样式从pl-15改为pl-16
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/ReadmeModal.tsx`:
- Around line 130-173: The IntersectionObserver created inside the setTimeout
callback is never reachable by the effect cleanup, causing a leak; hoist a
variable (e.g., let observer: IntersectionObserver | null = null) in the
useEffect scope (alongside the existing timer variable), assign the new
IntersectionObserver instance to that variable inside the timeout, and before
creating a new observer disconnect any existing one; update the effect's
returned cleanup to clearTimeout(timer) and also disconnect observer if non-null
so observer.disconnect() runs on re-run/unmount; keep references to contentRef,
tocItems, readmeContent and continue using setActiveHeadingId as is.
- Around line 54-75: extractToc is picking up lines starting with # inside
fenced code blocks, producing TOC entries that MarkdownRenderer (which ignores
code fences) will never render; to fix, strip fenced code blocks (both ```...```
and ~~~...~~~) out of content before running the heading-regex (keep using
TOC_MAX_LEVEL and the same regex) so regex.exec runs against the cleaned string,
and then ensure id generation (heading-<n>) still matches
MarkdownRenderer.getHeadingId() for sample READMEs; also re-run the
scrollToHeading checks to confirm no fallback matching is needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d79f706b-f4f9-4ae1-b3c3-1b1d80b56ae0
📒 Files selected for processing (2)
src/components/ReadmeModal.tsxsrc/test/setup.ts
✅ Files skipped from review due to trivial changes (1)
- src/test/setup.ts
在提取目录时排除代码块内容以避免干扰,同时改进IntersectionObserver的清理逻辑
feat(UI): 优化移动端布局和响应式设计 - 在DiscoveryView和SubscriptionRepoCard中添加移动端适配样式 - 隐藏小屏幕上的非必要按钮以节省空间 - 修复滚动和溢出问题 refactor(aiService): 调整推理参数条件判断逻辑
调整工具提示和平台筛选器的位置及宽度以适应移动端 重构发现视图的侧边栏布局,改为固定定位 移除重复的滚动容器,优化内容区域结构
|
可以合并 |
Read md up
实现仓库批量还原功能,支持选择还原字段(描述、标签、分类)和目标来源(原始或AI)。新增还原按钮、模态框和相关处理逻辑,提供详细的还原选项和状态统计。当还原分类时自动解锁分类锁定,并支持显示还原结果统计。
当还原到默认来源可能导致AI数据丢失时,显示警告信息提醒用户
添加API密钥解密失败和配置不完整的验证提示 移除不必要的分类锁定条件判断 优化AI分析工作器的中止控制和并发管理
有冲突了 |
添加 NumberInput、StepperInput 和 SliderInput 组件 在设置面板和搜索栏中使用新组件替换原生输入 优化输入交互体验并添加预设值和验证提示
Bulk restore
|
看来黑白化得不够彻底。。。 |
|
现在是深色浅色模式,要再加就得弄换皮肤了 |
|
这我也不知道怎么改好,之前是因为定位不起效果才做的固定位置。这个你来改吧 |

Summary by CodeRabbit
New Features
Bug Fixes & Improvements
Tests
Chores