Skip to content

feat: what new#1172

Merged
mengxi-ream merged 6 commits intomainfrom
feat/what-new
Mar 21, 2026
Merged

feat: what new#1172
mengxi-ream merged 6 commits intomainfrom
feat/what-new

Conversation

@ananaBMaster
Copy link
Copy Markdown
Collaborator

@ananaBMaster ananaBMaster commented Mar 21, 2026

Type of Changes

  • ✨ New feature (feat)
  • 💄 UI/style change (style)
  • 🐛 Bug fix (fix)
  • 📝 Documentation change (docs)
  • ♻️ Code refactoring (refactor)
  • ⚡ Performance improvement (perf)
  • ✅ Test related (test)
  • 🔧 Build or dependencies update (build)
  • 🔄 CI/CD related (ci)
  • 🌐 Internationalization (i18n)
  • 🧠 AI model related (ai)
  • 🔄 Revert a previous commit (revert)
  • 📦 Other changes that do not modify src or test files (chore)

Description

This PR moves the blog update entry point out of the product navigation and into a dedicated sidebar footer popover.

It adds a richer "What's New" surface that:

  • shows the latest blog title and description inline
  • embeds the latest bilibili video preview when present
  • auto-opens for unread posts without syncing popover state through useEffect
  • keeps the unread tracking in blog storage utilities and updates related tests

The branch also includes the icon asset refresh from the earlier style: change icon commit.

Related Issue

Closes #

How Has This Been Tested?

  • Added unit tests
  • Verified through manual testing

Tested locally with:

  • pnpm eslint src/entrypoints/options/app-sidebar/index.tsx src/entrypoints/options/app-sidebar/product-nav.tsx src/entrypoints/options/app-sidebar/whats-new-footer.tsx src/utils/blog.ts src/utils/__tests__/blog.test.ts
  • SKIP_FREE_API=true pnpm vitest run src/utils/__tests__/blog.test.ts

pnpm type-check currently fails on an existing unrelated error at src/utils/atoms/provider.ts:54:

  • TS2589: Type instantiation is excessively deep and possibly infinite.

Screenshots

Not included.

Checklist

  • I have tested these changes locally
  • I have updated the documentation accordingly if necessary
  • My code follows the code style of this project
  • My changes do not break existing functionality
  • If my code was generated by AI, I have proofread and improved it as necessary.

Additional Information

The changeset file is included in the branch as:

  • .changeset/whats-new-footer-popover.md

Summary by cubic

Moved “What’s New” from the product nav to a sidebar footer popover with inline blog previews and controlled open state for reliable unread tracking. Refreshed the extension icons.

  • New Features

    • Added a footer popover for “What’s New”; removed the product-nav entry.
    • Controlled popover state: auto-opens only when the post is unread and marks it as read after the popover is visible; added tests for auto-open and manual-open flows.
    • Expanded getLatestBlogDate to return full post metadata (title, description, optional videoUrl); added extractBilibiliVideoId and buildBilibiliEmbedUrl with unit tests.
  • Bug Fixes

    • Fixed a React warning by adding setAnchor to selection-popover dependencies.
    • Made provider config updates safer via mergeUnknown + Zod validation; added tests for updateLLMProviderConfig and updateProviderConfig.

Written for commit 465b3df. Summary will update on new commits.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 21, 2026

🦋 Changeset detected

Latest commit: 465b3df

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@read-frog/extension Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Mar 21, 2026
@github-actions github-actions bot added the feat label Mar 21, 2026
@dosubot dosubot bot added the app: browser extension Related to browser extension label Mar 21, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ef53a75f8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

return (
<Popover
key={`${latestBlogPost.url}:${latestBlogPost.date.toISOString()}`}
defaultOpen={shouldAutoOpenPopover}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Control popover open state when unread status arrives late

Popover is used in uncontrolled mode via defaultOpen, so if latestBlogPost resolves before lastViewedDate, shouldAutoOpenPopover flips from false to true after mount but the popover remains closed. In that race, the effect still calls markLatestBlogPostViewed, which clears the unread state even though the user never saw the “What’s New” content. Because both queries execute independently, this can happen in normal runtime and silently drop the intended announcement.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 15 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/entrypoints/options/app-sidebar/whats-new-footer.tsx">

<violation number="1" location="src/entrypoints/options/app-sidebar/whats-new-footer.tsx:84">
P1: `defaultOpen` is computed before both queries are ready, so unread posts may never auto-open when `lastViewedDate` resolves after `latestBlogPost`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/entrypoints/options/app-sidebar/whats-new-footer.tsx Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c19d81f849

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/utils/blog.ts
extensionVersion: semanticVersionSchema.nullable().optional(),
}).nullable()
videoUrl: bilibiliVideoUrlSchema.optional(),
extensionVersion: semanticVersionSchema.optional(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow null extensionVersion in blog response schema

Changing extensionVersion from nullable+optional to only optional makes previously accepted payloads fail validation when the API returns "extensionVersion": null. In that case blogApiResponseSchema.parse throws, getLatestBlogDate falls back to null, and both the popup notification and the new footer lose latest-post data entirely even though the post is otherwise valid. Keep null accepted (or normalize it) to preserve compatibility with existing responses.

Useful? React with 👍 / 👎.

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Mar 21, 2026
@mengxi-ream mengxi-ream merged commit 288cc2c into main Mar 21, 2026
3 checks passed
@mengxi-ream mengxi-ream deleted the feat/what-new branch March 21, 2026 02:54
@dosubot
Copy link
Copy Markdown

dosubot bot commented Mar 21, 2026

Documentation Updates

1 document(s) were updated by changes in this PR:

Internationalization and Localization
View Changes
@@ -782,8 +782,31 @@
 
 The recovery boundary is used in both the popup and options pages to provide graceful degradation when the extension encounters unrecoverable errors.
 
-### Sidebar Group Labels and Survey Navigation
+### Sidebar Group Labels and Navigation
 Sidebar group labels are localized under `options.sidebar.settings` and `options.sidebar.product`. The survey navigation item is localized under `options.survey.title` in all locale files.
+
+#### What's New Footer
+The sidebar includes a "What's New" footer component that displays the latest blog post preview in a popover. This feature has moved from the product navigation to a dedicated `WhatsNewFooter` component located in the sidebar footer.
+
+**i18n Key:**
+- **`options.whatsNew.title`**: Label for the "What's New" footer button (displays an RSS icon)
+
+The footer button uses the key `options.whatsNew.title` to label the RSS icon button. When clicked, it opens a popover at the bottom of the sidebar displaying:
+- Blog post title (as a clickable external link to the full post)
+- Blog post description
+- Optional embedded video preview (Bilibili videos when available)
+
+The popover automatically opens when a new blog post is detected (comparing the latest blog post date with the user's last viewed date). Once opened, the post is marked as viewed. The feature tracks unread status using blog storage utilities and does not sync popover state through configuration.
+
+**Example:**
+
+```yaml
+options:
+  whatsNew:
+    title: What's New
+```
+
+This footer component replaced the previous "What's New" entry in the product navigation section, providing a richer preview experience with inline blog content and video embeds.
 
 ### Blog System Localization
 The website's blog system uses the `blog` namespace in locale files for all blog-related UI strings, including titles, descriptions, navigation, author/date labels, sharing, and minimum extension version requirements. To add or update blog UI strings, add new keys under `blog` in each locale file.

How did I do? Any feedback?  Join Discord

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 465b3df793

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/utils/blog.ts
url: z.string(),
extensionVersion: semanticVersionSchema.nullable().optional(),
}).nullable()
videoUrl: bilibiliVideoUrlSchema.optional(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Relax videoUrl validation to avoid dropping blog posts

latestBlogPostSchema requires videoUrl to be a Bilibili URL with a valid BV id, and getLatestBlogDate parses the entire response in one shot. That means any post carrying a non-Bilibili or malformed videoUrl will make parsing fail and return null, which suppresses both popup and sidebar “What’s New” data even when date/title/url are otherwise valid. This should degrade by omitting the embed, not by discarding the whole post.

Useful? React with 👍 / 👎.

Comment on lines +94 to +95
if (!latestBlogPost) {
return null
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep a fallback What's New entry when blog fetch is empty

The footer now returns null when latestBlogPost is unavailable, which removes the only sidebar entry point to “What’s New” during transient fetch/validation failures. In the previous navigation flow this menu item always rendered with a /blog fallback URL, so users could still open updates even if latest-post metadata could not be loaded. Hiding the entry entirely is a regression in availability.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: browser extension Related to browser extension feat size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants