Sync#1
Conversation
There was a problem hiding this comment.
Pull request overview
This PR syncs and refactors large parts of the codebase, introducing a new config structure and multiple new UI/plugins (dashboard, AI summary, caching, analytics), while removing/rewiring legacy modules.
Changes:
- Added new config modules under
conf/and migrated many components fromBLOGtositeConfig. - Introduced new caching implementations (Redis, improved manager) and Notion API throttling.
- Added multiple new UI components (Dashboard, AI Summary, widgets) plus Jest setup and GitHub workflows.
Reviewed changes
Copilot reviewed 184 out of 1165 changed files in this pull request and generated 34 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/plugins/aiSummary.js | Adds AI summary fetch helper. |
| lib/password.js | Adds URL-query + localStorage-based password retrieval. |
| lib/notion/getPageTableOfContents.js | Updates ToC extraction to recurse into nested blocks/transclusions. |
| lib/notion/getNotionPost.js | Adds new API to build post metadata from Notion blocks. |
| lib/notion/getNotionAPI.js | Adds Notion API wrapper with rate limiting + inflight dedupe. |
| lib/notion/getNotion.js | Removes old Notion post fetch helper. |
| lib/notion/getAllTags.js | Refactors tag aggregation, adds Invisible support and config flags. |
| lib/notion/getAllPosts.js | Removes old “get all posts” implementation. |
| lib/notion/getAllPageIds.js | Adds view index selection for list ordering. |
| lib/notion/getAllCategories.js | Doc + minor refactor for categories. |
| lib/notion/convertInnerUrl.js | Adds client-side conversion of internal Notion links to site links. |
| lib/notion/RateLimiter.ts | Adds filesystem lock-based rate limiter. |
| lib/notion/CustomNotionApi.ts | Adds Notion REST write helper (axios). |
| lib/notion.js | Removes legacy re-exports. |
| lib/lang/zh-TW.js | Expands/changes Traditional Chinese (TW) translations. |
| lib/lang/zh-HK.js | Expands/changes Traditional Chinese (HK) translations. |
| lib/lang/zh-CN.js | Expands/changes Simplified Chinese translations. |
| lib/lang/tr-TR.js | Updates Turkish locale name + adds AI summary labels. |
| lib/lang/ja-JP.js | Updates Japanese locale name + adds AI summary labels. |
| lib/lang/fr-FR.js | Updates French locale name + adds AI summary labels. |
| lib/lang/en-US.js | Updates English locale name + adds new strings. |
| lib/cache/redis_cache.js | Adds Redis cache backend. |
| lib/cache/mongo_db_cache.js | Removes MongoDB cache backend. |
| lib/cache/memory_cache.js | Fixes BLOG import and adds custom TTL support. |
| lib/cache/local_file_cache.js | Refactors file cache to sync APIs and adds cleanCache. |
| lib/cache/cache_manager.js | Refactors cache manager + adds getOrSet helpers and Redis support. |
| lib/busuanzi.js | Removes old busuanzi implementation file (moved). |
| lib/algolia.js | Removes Algolia indexing implementation file. |
| jsconfig.json | Enables JS type-checking options. |
| jest.setup.js | Adds Jest DOM + Next.js/browser mocks. |
| jest.env.js | Adds Jest env var + console.warn suppression. |
| hooks/useAdjustStyle.js | Adds DOM patch hook for callout image overflow. |
| conf/widget.config.js | Adds widget config module. |
| conf/right-click-menu.js | Adds right-click menu config module. |
| conf/post.config.js | Adds post feature config module. |
| conf/plugin.config.js | Adds plugin config module (AI summary, Algolia, etc.). |
| conf/performance.config.js | Adds performance tuning config module. |
| conf/notion.config.js | Adds Notion-related config module. |
| conf/layout-map.config.js | Adds route-to-layout mapping config module. |
| conf/image.config.js | Adds image behavior config module. |
| conf/font.config.js | Adds font config module. |
| conf/dev.config.js | Adds developer-focused config module + version loading. |
| conf/contact.config.js | Adds social/contact config module. |
| conf/code.config.js | Adds code-rendering config module. |
| conf/animation.config.js | Adds animation effects config module. |
| conf/analytics.config.js | Adds analytics config module. |
| conf/ad.config.js | Adds ad config module. |
| components/ui/dashboard/DashboardUser.js | Adds Clerk UserProfile dashboard panel. |
| components/ui/dashboard/DashboardSignOutButton.js | Adds Clerk sign-out button for dashboard. |
| components/ui/dashboard/DashboardMenuList.js | Adds dashboard menu list navigation. |
| components/ui/dashboard/DashboardItemMembership.js | Adds membership purchase demo UI. |
| components/ui/dashboard/DashboardItemHome.js | Adds dashboard home demo UI. |
| components/ui/dashboard/DashboardItemBalance.js | Adds balance/recharge demo UI. |
| components/ui/dashboard/DashboardHeader.js | Adds dashboard header/profile summary UI. |
| components/ui/dashboard/DashboardButton.js | Adds “Dashboard” nav button based on config. |
| components/ui/dashboard/DashboardBody.js | Adds dynamic-loaded dashboard content router. |
| components/WordCount.js | Refactors word count to accept computed props. |
| components/Webwhiz.js | Migrates Webwhiz config to siteConfig. |
| components/WebMention.js | Migrates WebMention config to siteConfig. |
| components/WalineComponent.js | Migrates Waline config and updates Waline CSS import. |
| components/WWAds.js | Migrates WWAds config to siteConfig. |
| components/ValinePanel.js | Removes ValinePanel re-export. |
| components/ValineCount.js | Removes ValineCount re-export. |
| components/ValineComponent.js | Migrates Valine config to siteConfig. |
| components/Utterances.js | Refactors utterances loading + dark mode switching. |
| components/TwikooCommentCounter.js | Migrates Twikoo config and refactors effects. |
| components/TwikooCommentCount.js | Migrates Twikoo config to siteConfig. |
| components/Twikoo.js | Refactors Twikoo to dynamically load script + init. |
| components/TianliGPT.js | Adds TianliGPT AI summary embed loader. |
| components/Tabs.js | Refactors tab filtering + optionally hides single tab. |
| components/StarrySky.js | Moves starry sky effect to external JS loader. |
| components/SmartLink.js | Adds internal/external link wrapper component. |
| components/SideBarDrawer.js | Refactors drawer animation and adds showOnPC option. |
| components/ShareBar.js | Refactors share bar to dynamic-load ShareButtons, SSR-safe. |
| components/Select.js | Refactors Select handler binding to class property. |
| components/Ribbon.js | Moves ribbon effect to external JS loader. |
| components/QrCode.js | Refactors QRCode CDN loading + guards window.QRCode. |
| components/PoweredBy.js | Adds “Powered by NotionNext {VERSION}” component. |
| components/Player.js | Refactors music player config + dynamic script loading. |
| components/PerformanceMonitor.js | Adds web-vitals monitoring + budget checks. |
| components/Pdf.js | Adds Google Docs PDF embed helper. |
| components/PWA.js | Adds dynamic manifest injection for post pages. |
| components/Notification.js | Adds notification hook + component. |
| components/NotByAI.js | Adds “Not By AI” badge + locale mapping. |
| components/Nest.js | Moves nest effect to external JS loader. |
| components/MouseFollow.js | Adds mouse-follow effect loader + mobile CSS hide. |
| components/LoadingProgress.js | Adds NProgress-based route loading bar. |
| components/LoadingCover.js | Adds full-screen loading overlay component. |
| components/Live2D.js | Migrates Live2D config to siteConfig + disable on mobile. |
| components/Lenis.js | Adds Lenis smooth-scrolling loader. |
| components/LA51.js | Adds 51LA analytics init component. |
| components/KatexReact.js | Refactors KaTeX component to hook imports + memo usage. |
| components/IconFont.js | Adds iconfont SVG replacement loader + global styles. |
| components/Gtag.js | Refactors gtag route tracking + config injection. |
| components/GlobalStyle.js | Adds global CSS injection from config. |
| components/Gitalk.js | Refactors Gitalk loader + config extraction. |
| components/Giscus.js | Refactors giscus to external loader + data attributes. |
| components/FacebookPage.js | Migrates Facebook widget config to siteConfig. |
| components/FacebookMessenger.js | Migrates Messenger config + delays load until scroll/timeout. |
| components/ExternalScript.js | Minor refactor + removes noisy console.log. |
| components/Equation.js | Adds doc comment. |
| components/DisableCopy.js | Migrates copy-disable config to siteConfig. |
| components/DifyChatbot.js | Adds Dify embed loader with cleanup. |
| components/DebugPanel.js | Refactors DebugPanel to read config map + query theme. |
| components/DarkModeButton.js | Refactors DarkModeButton to use global toggle. |
| components/CusdisComponent.js | Migrates Cusdis config + adds lang script loading. |
| components/CursorDot.js | Adds cursor dot follower + hover enlargement. |
| components/Coze.js | Adds Coze chatbot embed loader. |
| components/CopyRightDate.js | Adds copyright year range component. |
| components/CommonScript.js | Removes legacy third-party script injector component. |
| components/CommonHead.js | Removes legacy head-meta component. |
| components/Collapse.js | Refactors Collapse props destructuring + effect handling. |
| components/ChatBase.js | Migrates ChatBase config to siteConfig. |
| components/CanvasEmail.js | Adds canvas-rendered email with click-to-copy. |
| components/Busuanzi.js | Migrates busuanzi import path and refactors hooks usage. |
| components/BeiAnSite.js | Adds domain备案 display component. |
| components/BeiAnGongAn.tsx | Adds 公安备案 component with code parsing/link. |
| components/Badge.js | Adds red dot badge component. |
| components/ArticleExpirationNotice.js | Adds “article expired” notice feature. |
| components/Artalk.js | Migrates Artalk config + adds dark-mode observer. |
| components/AnalyticsBusuanzi.js | Adds busuanzi PV/UV container markup. |
| components/Ackee.js | Migrates Ackee config + refactors effect ordering. |
| components/AOSAnimation.js | Adds AOS external loader. |
| components/AISummary.module.css | Adds styles for AI summary card. |
| components/AISummary.js | Adds AI summary UI with typing animation. |
| tests/components/LazyImage.test.js | Adds first component test for LazyImage. |
| SECURITY.md | Adds security policy template. |
| Dockerfile | Updates to Node 20 multi-stage standalone runner image. |
| CONTRIBUTING.md | Adds environment variable guidance. |
| .prettierrc.json | Expands prettier formatting rules. |
| .nvmrc | Pins Node version 20. |
| .npmrc | Enforces engine-strict. |
| .github/workflows/sync.yaml | Adds upstream sync workflow for forks. |
| .github/workflows/pushUrl.yml | Updates actions versions + refactors secret handling. |
| .github/workflows/docker-ghcr.yaml | Updates Docker workflow actions + enables multi-arch build. |
| .github/workflows/codeql-analysis.yml | Updates CodeQL workflow to v3 + TS/JS analyzer. |
| .github/pull_request_template.md | Adds PR template. |
| .github/ISSUE_TEMPLATE/feature_request.md | Fixes project name in template. |
| .github/ISSUE_TEMPLATE/bug_report.md | Improves bug report template fields. |
| .github/FUNDING.yml | Adds Ko-fi sponsor config. |
| .eslintrc.js | Adds TS-eslint + prettier integration and type-aware rules. |
| .env.local | Removes committed local env file. |
Comments suppressed due to low confidence (1)
lib/cache/local_file_cache.js:1
delete json.keydeletes the literal property namedkeyrather than the entry for the passed variable. This should deletejson[key](and likely also deletejson[key + '_expire_time']).
import fs from 'fs'
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // 使用 URL 对象解析 URL | ||
| const url = new URL(path, isBrowser ? window.location.origin : '') | ||
|
|
There was a problem hiding this comment.
new URL(path, '') will throw on the server because the base URL is invalid, and localStorage/window access will throw when not in the browser. Add an if (!isBrowser) return [] (or parse only with a safe base like 'http://localhost') and guard all localStorage reads/writes behind isBrowser.
| // 使用 URL 对象解析 URL | |
| const url = new URL(path, isBrowser ? window.location.origin : '') | |
| // 在非浏览器环境下使用安全的基础 URL,并避免访问 window/localStorage | |
| if (!isBrowser) { | |
| const url = new URL(path, 'http://localhost') | |
| const queryParams = Object.fromEntries(url.searchParams.entries()) | |
| return queryParams.password ? [queryParams.password] : [] | |
| } | |
| // 使用 URL 对象解析 URL(仅在浏览器环境下访问 window) | |
| const url = new URL(path, window.location.origin) |
| // 请求中带着密码 | ||
| if (queryParams.password) { | ||
| // 将已输入密码作为默认密码存放在 localStorage,便于下次读取并自动尝试 | ||
| localStorage.setItem('password_default', queryParams.password) |
There was a problem hiding this comment.
new URL(path, '') will throw on the server because the base URL is invalid, and localStorage/window access will throw when not in the browser. Add an if (!isBrowser) return [] (or parse only with a safe base like 'http://localhost') and guard all localStorage reads/writes behind isBrowser.
| const storedPassword = localStorage.getItem('password_' + cleanedPath) | ||
| const defaultPassword = localStorage.getItem('password_default') |
There was a problem hiding this comment.
new URL(path, '') will throw on the server because the base URL is invalid, and localStorage/window access will throw when not in the browser. Add an if (!isBrowser) return [] (or parse only with a safe base like 'http://localhost') and guard all localStorage reads/writes behind isBrowser.
| const { type } = block | ||
| if (type.indexOf('header') >= 0) { | ||
| const existed = toc.find(e => e.id === blockId) | ||
| if (!existed) { | ||
| toc.push({ | ||
| id: blockId, | ||
| type, | ||
| text: getTextContent(block.properties?.title), | ||
| indentLevel: indentLevels[type] | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| if (block.content?.length > 0) { | ||
| getBlockHeader(block.content, recordMap, toc) | ||
| } else { | ||
| if (type.indexOf('header') >= 0) { |
There was a problem hiding this comment.
This change skips adding the current block to the TOC whenever block.content?.length > 0 (because it recurses and never evaluates the header/transclusion logic for that block). Process the current block first (header/transclusion), then recurse into block.content, or do both unconditionally where applicable.
| getBlockHeader(block.content, recordMap, toc) | ||
| } | ||
| } |
There was a problem hiding this comment.
This change skips adding the current block to the TOC whenever block.content?.length > 0 (because it recurses and never evaluates the header/transclusion logic for that block). Process the current block first (header/transclusion), then recurse into block.content, or do both unconditionally where applicable.
| router.events.on('routeChangeComplete', (url, option) => { | ||
| if (url !== path) { | ||
| path = url | ||
| busuanzi.fetch() | ||
| } | ||
| }) | ||
|
|
There was a problem hiding this comment.
This subscribes to router.events on every render and never unsubscribes, causing duplicated handlers and memory leaks. Move the subscription into a useEffect with a cleanup (off) and stable handler function.
| router.events.on('routeChangeComplete', (url, option) => { | |
| if (url !== path) { | |
| path = url | |
| busuanzi.fetch() | |
| } | |
| }) | |
| useEffect(() => { | |
| const handleRouteChange = (url, option) => { | |
| if (url !== path) { | |
| path = url | |
| busuanzi.fetch() | |
| } | |
| } | |
| router.events.on('routeChangeComplete', handleRouteChange) | |
| return () => { | |
| router.events.off('routeChangeComplete', handleRouteChange) | |
| } | |
| }, [router]) |
| // 标签相关 | ||
| TAG_SORT_BY_COUNT: true, // 标签是否按照文章数量倒序排列,文章多的标签排在前。 | ||
| IS_TAG_COLOR_DISTINGUISHED: | ||
| process.env.NEXT_PUBLIC_IS_TAG_COLOR_DISTINGUISHED === 'true' || true // 对于名称相同的tag是否区分tag的颜色 |
There was a problem hiding this comment.
This expression always evaluates to true, which makes the feature impossible to disable via env/config. Use a real boolean defaulting pattern (e.g., process.env... === 'true' with a default value) instead of || true.
| process.env.NEXT_PUBLIC_IS_TAG_COLOR_DISTINGUISHED === 'true' || true // 对于名称相同的tag是否区分tag的颜色 | |
| process.env.NEXT_PUBLIC_IS_TAG_COLOR_DISTINGUISHED === undefined | |
| ? true | |
| : process.env.NEXT_PUBLIC_IS_TAG_COLOR_DISTINGUISHED === 'true' // 对于名称相同的tag是否区分tag的颜色 |
| module.exports = { | ||
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU: | ||
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU || true, // 自定义右键菜单,覆盖系统菜单 | ||
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH: | ||
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH || | ||
| true, // 是否显示切换主题 | ||
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE: | ||
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE || true, // 是否显示深色模式 | ||
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK: | ||
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK || true, // 是否显示分享链接 | ||
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST: | ||
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST || true, // 是否显示随机博客 | ||
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY: | ||
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY || true, // 是否显示分类 | ||
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_TAG: | ||
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_TAG || true // 是否显示标签 |
There was a problem hiding this comment.
The env var name for the TAG setting appears inconsistent (..._THEME_TAG), which likely prevents configuration from working. Also, || true forces it always on. Align the env var name with the setting and use proper boolean parsing.
| module.exports = { | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU: | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU || true, // 自定义右键菜单,覆盖系统菜单 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH: | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH || | |
| true, // 是否显示切换主题 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE: | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE || true, // 是否显示深色模式 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK: | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK || true, // 是否显示分享链接 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST: | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST || true, // 是否显示随机博客 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY: | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY || true, // 是否显示分类 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_TAG: | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_TAG || true // 是否显示标签 | |
| const parseBooleanEnv = (value, defaultValue = true) => { | |
| if (value === undefined) { | |
| return defaultValue | |
| } | |
| const normalized = String(value).trim().toLowerCase() | |
| if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) { | |
| return true | |
| } | |
| if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) { | |
| return false | |
| } | |
| return defaultValue | |
| } | |
| module.exports = { | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU: parseBooleanEnv( | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU, | |
| true | |
| ), // 自定义右键菜单,覆盖系统菜单 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH: parseBooleanEnv( | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_THEME_SWITCH, | |
| true | |
| ), // 是否显示切换主题 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE: parseBooleanEnv( | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_DARK_MODE, | |
| true | |
| ), // 是否显示深色模式 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK: parseBooleanEnv( | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_SHARE_LINK, | |
| true | |
| ), // 是否显示分享链接 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST: parseBooleanEnv( | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_RANDOM_POST, | |
| true | |
| ), // 是否显示随机博客 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY: parseBooleanEnv( | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_CATEGORY, | |
| true | |
| ), // 是否显示分类 | |
| CUSTOM_RIGHT_CLICK_CONTEXT_MENU_TAG: parseBooleanEnv( | |
| process.env.NEXT_PUBLIC_CUSTOM_RIGHT_CLICK_CONTEXT_MENU_TAG, | |
| true | |
| ) // 是否显示标签 |
| <div id="artalk"></div> | ||
| ) | ||
|
|
||
| const initArtalk = async () => { |
There was a problem hiding this comment.
The cleanup function returned from initArtalk is never used by the useEffect, so the MutationObserver is not disconnected on unmount. Create/attach the observer inside the effect and return a cleanup from the useEffect itself.
| return () => observer.disconnect() | ||
| } | ||
|
|
||
| return <div id="artalk"></div> |
There was a problem hiding this comment.
The cleanup function returned from initArtalk is never used by the useEffect, so the MutationObserver is not disconnected on unmount. Create/attach the observer inside the effect and return a cleanup from the useEffect itself.
Refresh the landing theme preview screenshot to keep PR visuals aligned with the latest UI state.
chore(config): tune Node engine range and root guidance
Use dynamic panel max-height to prevent expanded code from being clipped, and unify CODE_COLLAPSE_MIN_LINES defaults to 20 across runtime and config.
Centralize CODE_COLLAPSE_MIN_LINES in conf/code.config.js so code-related settings stay together and easier to maintain.
feat: 优化代码折叠逻辑,引入行数阈值检测与极简 S1 UI
Add clear server/runtime theme source logs and normalize query theme resolution so developers can see why final theme comes from query, Notion config, or local config.
Optimize build and runtime fundamentals by removing costly webpack overrides, reducing cache/data-path overhead, and adding baseline measurement tooling so performance regressions are easier to detect.
Drop heavy react-share usage in favor of lightweight share links, add preview-image webp generation with png fallback, and align image components to reduce client payload and improve first load.
Preserve internal link query state for theme previews, remove invalid hook usage from site config access, and harden mermaid plus dark-mode content styles to prevent freezes and improve visual consistency.
Lower client CPU overhead by scoping observers to article content, lazily initializing zoom handling, and skipping Prism/Mermaid work when pages do not contain code blocks.
Resolve key/default-props/link-prop runtime warnings and add a reusable theme performance audit script so theme-level regressions can be scanned consistently.
Run a full theme performance scan in production mode, commit the latest audit reports, and document mandatory theme audit checks so future theme work follows a consistent performance gate.
Bump project patch version and add a complete package.json script reference in the developer guide so contributors can understand and run each workflow command consistently.
Add a Chinese contribution guide and update both CN/EN README navigation sections so contributor onboarding docs are fully bilingual and consistently linked.
…line perf: 全主题性能基线、运行时修复与低风险优化
- Allow meta row and tags to wrap below lg breakpoint; break long titles - Add min-w-0/max-w-full width constraints on main, section, list and cards Co-authored-by: Cursor <cursoragent@cursor.com>
…layout fix(fuwari): 移动端首页文章列表布局与横向溢出
Theme resolver (themes/theme.js): - Drop compile-time @theme-components alias coupling; load LayoutBase/layouts/THEME_CONFIG via dynamic import(@/themes/<name>) so NEXT_PUBLIC_THEME matches runtime without deleting .next. next.config.js: - Remove @theme-components webpack alias; clarify webpack log. - Dedupe dev cache hint across Next workers via .next lock file; single-line message. Fuwari: - Article detail: optional cover in card (ArticleHeroCover), FUWARI_ARTICLE_COVER_HERO. - Post list: wider cover column (FUWARI_POST_LIST_COVER_COL_WIDTH), mobile aspect; collapse grid when no cover so title uses full width beside rail. Co-authored-by: Cursor <cursoragent@cursor.com>
…provements feat: Fuwari 优化 + 主题动态加载 + 开发体验
- Claude: getClaudeMenuLinks + MenuList accordion, styles for parent row/submenu - Fuwari: desktop hover+click to open dropdown; mobile title toggles submenu - Parent items with children no longer navigate; only expand/collapse Co-authored-by: Cursor <cursoragent@cursor.com>
…provements feat: Fuwari theme polish, dev UX, and Claude/Fuwari nested navigation
Co-authored-by: liaoyongkun <etc.liao@gmail.com>
Co-authored-by: tangly1024 <mail@tangly1024.com> Co-authored-by: Cursor <cursoragent@cursor.com>
* 增加heo主题英雄区右侧遮罩图片显示控制 * 增加heo主题英雄区右侧遮罩图片显示控制 --------- Co-authored-by: tangly1024 <mail@tangly1024.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: root <root@us7vdxvrete1.local> Co-authored-by: tangly1024 <mail@tangly1024.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Respect Notion collection view filters for embedded collection views, including query2 filters, localized status groups, and sibling filter inheritance for alternate embedded views.
Publish patch version 4.10.1.
Fixes #4172 by flattening synced blocks returned as content ID arrays in addition to inline children.
Fixes #4140 by overriding the quote renderer so titleless quote blocks still render their children.
Fixes #4127 by using filtered query results before falling back to page_sort.
Fixes the Fuwari theme color hue not applying until the palette is opened. Related: #3920.
# Conflicts: # package.json
Fixes #3921 by normalizing HEO_INFOCARD_GREETINGS values from arrays, stringified arrays, and plain strings.
Add shared typed collection helpers for Member/Event filtering and sorting.
Add a community site Notion database template guide and link it from the docs sidebar/index.
Avoid falling back to page_sort when a selected view query is present but filtered to an empty result.
Bump @supabase/supabase-js from 2.106.2 to 2.107.0.
Bump ioredis from 5.10.1 to 5.11.1.
Bump @vercel/functions from 3.6.0 to 3.6.2.
Bump axios from 1.16.1 to 1.17.0.
No description provided.