Skip to content

feat(web): UI polish — WeChat official logo, design system tokens & cloud connection UX#503

Merged
lefarcen merged 7 commits intomainfrom
feat/ui-polish-wechat-logo-design-system
Mar 24, 2026
Merged

feat(web): UI polish — WeChat official logo, design system tokens & cloud connection UX#503
lefarcen merged 7 commits intomainfrom
feat/ui-polish-wechat-logo-design-system

Conversation

@zoeforfun
Copy link
Copy Markdown
Contributor

@zoeforfun zoeforfun commented Mar 24, 2026

Summary

  • WeChat official logo: Replace the old single-color #8DC81B SVG with the official WeChat-Logo mark (gradient two-bubble icon, no gray wordmark), using useId() for unique gradient IDs. Applied everywhere: home page onboarding cards, connected/unconnected channel lists, WeChat QR modal header, and the shared PlatformIcon component.
  • Design system — success color tokens: Unify success green to #00A365 globally (--color-success, --color-success-subtle, --color-success-muted, --color-success-border). Migrate all hardcoded emerald-* / green Tailwind classes to CSS custom properties across channels, integrations, sessions, models, oauth, invite, and other pages. WeChat primary actions remain accent-colored, not green.
  • Sidebar nav visual hierarchy: Inactive nav items (icon + label) use --color-text-secondary instead of --color-text-primary; hover and active states remain primary weight for clear distinction.
  • Skills page default tab: Default to "Yours" tab on mount; reorder tab array (Yours first, Explore second).
  • WeChat setup copy: Shorten wechatSetup.desc to a single line in both EN and ZH.
  • Nexu Cloud connection UX (Settings → Nexu Official): Remove the large green/brand status card (banner + Disconnect button). Replace with a single inline text button next to the provider name showing "Connected" (brand color, clickable to disconnect) or "Not connected" (secondary, clickable to start login). Refresh button retained below as a bordered action.
  • Breathe keyframe: Remove translateY(-1px) bounce — glow-only animation.

Test plan

  • Open Home page → verify WeChat card shows official gradient icon at correct size in onboarding grid, connected list, and unconnected dashed grid
  • Open WeChat QR modal → confirm icon in header is the official mark, not the old green blob
  • Check sidebar: inactive tabs (Skills, Settings) should appear lighter than the active tab
  • Navigate to Skills → confirm "Yours" tab is selected by default
  • Go to Settings → Nexu Official provider → verify "Connected" or "Not connected" text button appears next to name, no large banner card
  • Click "Connected" → should disconnect; click "Not connected" → should start browser login flow
  • Spot-check success-colored UI (channel status dots, session badges) → should be #00A365 green, not old #346e58
  • Verify no emerald/green Tailwind hardcodes remain in changed files

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Model selection moved into per‑provider lists with cloud connect/disconnect controls
    • Shared, updated WeChat icon used across the product
  • Style

    • Success color token updated to a new green; many success styles now use theme variables
    • Button/input focus, tab/modal pill styles, nav text tone, subtle animation tweak, and loader background updated
  • Other

    • Skills page defaults to "Yours"; brand casing normalized to "nexu" and related localization/copy updated

chaoxiaoche added 2 commits March 24, 2026 17:18
…loud connection UX

- Replace WeChat icon with official SVG mark (gradient bubbles, no wordmark)
  across home page, channel cards, modal header, and platform-icons
- Unify success color to #00A365 with muted/border tokens; migrate all
  emerald/green hardcodes to CSS custom properties
- Lighten sidebar nav items (inactive → text-secondary) for visual hierarchy
- Skills page: default tab → Yours, reorder tabs
- WeChat setup desc shortened to single line (EN/ZH)
- Nexu Cloud connection: replace status banner with inline text button
  (Connected / Not connected) next to provider name
- Breathe keyframe: glow-only, remove translateY bounce

Made-with: Cursor
- Remove redundant top-level Current Model selector; model switching
  now lives inline in each provider's model list (clickable rows)
- Add "Active" badge with checkmark on selected model row
- Unify selected state to neutral gray (bg-surface-2) instead of
  brand-teal tint; sidebar active item uses font-weight, not color
- Add white bordered logo containers for sidebar providers and model
  list items for visual consistency across pages
- Move "Refresh model list" button inline with Available Models header
- Hide "Not connected" label when cloud is disconnected (login card
  already communicates this); show "Connected" as ghost button
- Separate model list from provider header with border divider
- Model picker dropdown: selected item uses brand-primary color for
  checkmark and Active badge
- Input component: unify focus ring to brand-primary color globally
- Feishu setup: remove BookOpen icon from help link, use text-link
  style consistent with other external links

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 24, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Consolidates success/green styling onto CSS variables, replaces inline WeChat SVG with a gradient-capable WechatIcon using runtime IDs, moves model selection into per-provider interactive rows (onSelectModel), applies widespread lowercase brand text updates, and includes assorted UI/layout/styling tweaks.

Changes

Cohort / File(s) Summary
Theme & Tokens
apps/web/src/index.css, apps/desktop/src/runtime-page.css
Updated --color-success to #00a365, added --color-success-muted/--color-success-border, replaced hardcoded success colors; adjusted .nav-item color and breathe keyframes.
Global Success UI
apps/web/src/pages/...
apps/web/src/pages/channels.tsx, apps/web/src/pages/invite.tsx, apps/web/src/pages/feishu-bind.tsx, apps/web/src/pages/oauth-callback.tsx, apps/web/src/pages/slack-claim.tsx, apps/web/src/pages/slack-oauth-callback.tsx, apps/web/src/pages/welcome.tsx, apps/web/src/layouts/workspace-layout.tsx, apps/web/src/pages/integrations.tsx, apps/web/src/pages/sessions.tsx
Replaced many hardcoded emerald Tailwind classes with var(--color-success*) arbitrary-value classes for icons, dots, banners, borders, and backgrounds.
Channel Setup Components
apps/web/src/components/channel-setup/...
discord-setup-view.tsx, feishu-setup-view.tsx, wechat-setup-view.tsx
Switched success icon/text to CSS variables; simplified Feishu help link (removed BookOpen); adjusted WeChat spacing/theming and changed action buttons to accent styles.
Model Selection / Models Page
apps/web/src/pages/models.tsx, apps/web/src/components/model-picker-dropdown.tsx
Removed global current-model selector; model switching moved into per-provider interactive <button> rows via onSelectModel(modelId); added cloudDisconnecting state and loading handling; updated selected styling to brand palette.
Platform Icons & Home
apps/web/src/components/platform-icons.tsx, apps/web/src/pages/home.tsx
Replaced inline WECHAT_ICON with WechatIcon component using useId()-scoped gradient defs; home now uses homeChannelIcon() helper calling shared WechatIcon.
UI Primitives & Toolkit
apps/web/src/components/ui/badge.tsx, apps/web/src/components/toolkit-icon.tsx, apps/web/src/components/ui/input.tsx, apps/web/src/components/skills/import-skill-modal.tsx
Badge and toolkit fallback palettes now use --color-success vars; Input focus styles updated to focus:shadow-focus/focus:border-brand-primary/30; import-skill modal tabs and controls restyled and GitHub input enabled.
Branding / Lowercase Text
multiple files
apps/web/src/i18n/locales/*, apps/desktop/*, apps/web/*, docs/.vitepress/config.ts, apps/controller/*
Lowercased brand text (Nexunexu) across i18n strings, titles, alt/aria labels, OpenAPI/app titles, default bot name, and related keys (some i18n keys renamed/added).
Home / Pages / Layout
apps/web/src/pages/home.tsx, apps/web/src/pages/skills.tsx, apps/web/src/pages/integrations.tsx, apps/web/src/pages/channels.tsx, apps/web/src/pages/feishu-bind.tsx, apps/web/src/pages/invite.tsx
Home imports shared WechatIcon; Skills default tab changed to yours; pages updated to use --color-success tokens for connected/success visuals.
Misc / Tests / Scripts
apps/controller/*, apps/desktop/src/components/surface-frame.tsx, apps/desktop/index.html, apps/web/index.html, docs/.vitepress/config.ts
Lowercased OpenAPI/title/app names and default bot name; updated corresponding test; changed desktop loader background to solid white; updated docs logo alt text.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ProviderDetail
    participant ModelRow
    participant onSelectModel
    participant Server

    rect rgba(0,128,0,0.5)
    User->>ProviderDetail: Open provider detail (model list)
    ProviderDetail->>ModelRow: Render interactive model rows (buttons)
    end

    User->>ModelRow: Click model row (if not active)
    ModelRow->>onSelectModel: call onSelectModel(modelId)
    onSelectModel->>Server: send model-switch request
    Server-->>onSelectModel: return success/failure
    onSelectModel-->>ProviderDetail: update selected model state
    ProviderDetail-->>User: refresh UI (active indicator / loading)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • anthhub

Poem

🐰
From fixed emerald stems I hop and sing,
Variables now make the colors ring.
WeChat gleams with gradients, soft and new,
Models click and settle—choices made true,
A little rabbit cheers: hip-hop-hooray!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: WeChat official logo update, design system success color tokens, and cloud connection UX improvements.
Description check ✅ Passed The description is comprehensive, covering all major changes (WeChat logo, design tokens, sidebar nav, skills tab, cloud UX) with clear implementation details and an organized test plan.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ui-polish-wechat-logo-design-system

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
apps/web/src/i18n/locales/en.ts (1)

687-687: Optional English copy polish for readability.

Line 687 reads a bit more naturally as: “Scan with WeChat on your phone to connect.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/i18n/locales/en.ts` at line 687, Update the English copy for the
"wechatSetup.desc" locale entry so the value reads "Scan with WeChat on your
phone to connect." instead of "Scan in WeChat on your phone to connect."; locate
the "wechatSetup.desc" key in the locales file and replace the string
accordingly to improve readability.
apps/desktop/src/runtime-page.css (1)

1339-1339: Consider centralizing this success color to avoid drift.

Both rules now use the right value, but extracting to a shared desktop CSS variable would reduce future mismatch risk.

Also applies to: 1351-1351

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/runtime-page.css` at line 1339, Extract the hard-coded
success hex (`#00a365`) into a shared CSS variable (e.g., --desktop-success-color)
defined at a common scope (for example :root or the top-level .desktop runtime
container) and replace the two occurrences of background: `#00a365`; with
background: var(--desktop-success-color); to ensure a single source of truth and
prevent future drift.
apps/web/src/pages/sessions.tsx (1)

414-427: Inconsistent use of hardcoded color value.

Line 416 uses bg-[rgba(0,163,101,0.12)] while the surrounding code uses CSS variables like var(--color-success). For consistency with the PR's design token migration, consider using bg-[var(--color-success-muted)] or a similar token.

♻️ Suggested fix for consistency
-      <span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-[rgba(0,163,101,0.12)] text-[var(--color-success)]">
+      <span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-[var(--color-success-muted)] text-[var(--color-success)]">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/pages/sessions.tsx` around lines 414 - 427, Replace the
hardcoded background rgba in the success badge with the design token variable to
match surrounding usage: change the span using bg-[rgba(0,163,101,0.12)] (the
element rendering the CheckCircle2 icon inside the success badge in
sessions.tsx) to use a CSS variable like bg-[var(--color-success-muted)] (or the
appropriate --color-success token available in the codebase), keeping the rest
of the classes and semantics (formattedSummary, CheckCircle2, and
t("sessions.chat.toolCompleted")) unchanged; ensure the chosen CSS variable
exists or add it to the theme tokens before updating the class.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/components/channel-setup/feishu-setup-view.tsx`:
- Around line 432-441: The help sentence is missing the trailing translation key
and becomes incomplete; update the JSX in feishu-setup-view.tsx to render the
missing t("feishuSetup.helpSuffix") immediately after
t("feishuSetup.helpLinkText") (preserving spacing/punctuation) so the full
sentence is produced alongside the ExternalLink icon; ensure you reference the
same translation key t("feishuSetup.helpSuffix") used in locales/en.ts and keep
target="_blank" rel attributes intact.

In `@apps/web/src/components/model-picker-dropdown.tsx`:
- Line 393: The selected-model label currently uses the low-contrast utility
"text-brand-primary" on a near-white surface; update the JSX in the
ModelPickerDropdown component where "text-brand-primary" is applied (adjacent to
"bg-brand-primary/5" and the check/highlight logic) to use the primary
foreground utility (e.g., "text-foreground" or "text-primary") instead, leaving
the check/highlight classes (like "bg-brand-primary/5") unchanged so the brand
accent remains only in the check/highlight while the label uses the readable
primary text color.

---

Nitpick comments:
In `@apps/desktop/src/runtime-page.css`:
- Line 1339: Extract the hard-coded success hex (`#00a365`) into a shared CSS
variable (e.g., --desktop-success-color) defined at a common scope (for example
:root or the top-level .desktop runtime container) and replace the two
occurrences of background: `#00a365`; with background:
var(--desktop-success-color); to ensure a single source of truth and prevent
future drift.

In `@apps/web/src/i18n/locales/en.ts`:
- Line 687: Update the English copy for the "wechatSetup.desc" locale entry so
the value reads "Scan with WeChat on your phone to connect." instead of "Scan in
WeChat on your phone to connect."; locate the "wechatSetup.desc" key in the
locales file and replace the string accordingly to improve readability.

In `@apps/web/src/pages/sessions.tsx`:
- Around line 414-427: Replace the hardcoded background rgba in the success
badge with the design token variable to match surrounding usage: change the span
using bg-[rgba(0,163,101,0.12)] (the element rendering the CheckCircle2 icon
inside the success badge in sessions.tsx) to use a CSS variable like
bg-[var(--color-success-muted)] (or the appropriate --color-success token
available in the codebase), keeping the rest of the classes and semantics
(formattedSummary, CheckCircle2, and t("sessions.chat.toolCompleted"))
unchanged; ensure the chosen CSS variable exists or add it to the theme tokens
before updating the class.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1951f7cc-e7d7-4f4b-b308-8d280d1bf7d2

📥 Commits

Reviewing files that changed from the base of the PR and between 08c6d8e and b11f35d.

📒 Files selected for processing (25)
  • apps/desktop/src/runtime-page.css
  • apps/web/src/components/channel-setup/discord-setup-view.tsx
  • apps/web/src/components/channel-setup/feishu-setup-view.tsx
  • apps/web/src/components/channel-setup/wechat-setup-view.tsx
  • apps/web/src/components/model-picker-dropdown.tsx
  • apps/web/src/components/platform-icons.tsx
  • apps/web/src/components/toolkit-icon.tsx
  • apps/web/src/components/ui/badge.tsx
  • apps/web/src/components/ui/input.tsx
  • apps/web/src/i18n/locales/en.ts
  • apps/web/src/i18n/locales/zh-CN.ts
  • apps/web/src/index.css
  • apps/web/src/layouts/workspace-layout.tsx
  • apps/web/src/pages/channels.tsx
  • apps/web/src/pages/feishu-bind.tsx
  • apps/web/src/pages/home.tsx
  • apps/web/src/pages/integrations.tsx
  • apps/web/src/pages/invite.tsx
  • apps/web/src/pages/models.tsx
  • apps/web/src/pages/oauth-callback.tsx
  • apps/web/src/pages/sessions.tsx
  • apps/web/src/pages/skills.tsx
  • apps/web/src/pages/slack-claim.tsx
  • apps/web/src/pages/slack-oauth-callback.tsx
  • apps/web/src/pages/welcome.tsx

Comment thread apps/web/src/components/channel-setup/feishu-setup-view.tsx
Comment thread apps/web/src/components/model-picker-dropdown.tsx
- Import Skill modal: switch tab control from underline to macOS-style
  capsule (rounded-full, bg-surface-2, white active state with shadow);
  left-align tabs; increase spacing between header, tabs, and content
- Import Skill modal: deepen dashed drop-zone border (border-strong);
  enable GitHub URL input (remove disabled prop)
- Input component: replace shadow-sm with no shadow; use bg-surface-1
  for contrast against white dialogs; unify focus ring to brand-primary
  via shadow-focus token
- Desktop loader: change loading page background from warm beige
  gradient to white

Made-with: Cursor
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/web/src/components/skills/import-skill-modal.tsx (1)

121-134: Consider extracting duplicate TabsTrigger className to a constant.

Both TabsTrigger components use identical className strings. Extracting to a const improves maintainability if styling needs to change.

♻️ Optional refactor
+const tabTriggerClassName =
+  "rounded-full px-4 py-1.5 text-[13px] font-medium text-text-secondary transition-all data-[state=active]:bg-white data-[state=active]:text-text-primary data-[state=active]:shadow-sm";
+
 <TabsList className="inline-flex h-9 bg-surface-2 p-1 gap-1 rounded-full">
   <TabsTrigger
     value="zip"
-    className="rounded-full px-4 py-1.5 text-[13px] font-medium text-text-secondary transition-all data-[state=active]:bg-white data-[state=active]:text-text-primary data-[state=active]:shadow-sm"
+    className={tabTriggerClassName}
   >
     {t("skills.uploadZip")}
   </TabsTrigger>
   <TabsTrigger
     value="github"
-    className="rounded-full px-4 py-1.5 text-[13px] font-medium text-text-secondary transition-all data-[state=active]:bg-white data-[state=active]:text-text-primary data-[state=active]:shadow-sm"
+    className={tabTriggerClassName}
   >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/skills/import-skill-modal.tsx` around lines 121 -
134, The two identical className strings on the TabsTrigger components should be
extracted to a single constant to avoid duplication; define a descriptive
constant (e.g. tabTriggerClass) near the component (in the same module or
component scope) and replace both TabsTrigger className props with that constant
so styling changes only need to be made in one place; ensure the constant is
exported or scoped appropriately if used elsewhere and keep the original class
string exactly as-is when moving it into the constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/web/src/components/skills/import-skill-modal.tsx`:
- Around line 121-134: The two identical className strings on the TabsTrigger
components should be extracted to a single constant to avoid duplication; define
a descriptive constant (e.g. tabTriggerClass) near the component (in the same
module or component scope) and replace both TabsTrigger className props with
that constant so styling changes only need to be made in one place; ensure the
constant is exported or scoped appropriately if used elsewhere and keep the
original class string exactly as-is when moving it into the constant.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0fdbd762-dfac-4fa4-8e95-d4bd061e21cc

📥 Commits

Reviewing files that changed from the base of the PR and between b11f35d and 00800d1.

📒 Files selected for processing (3)
  • apps/desktop/src/components/surface-frame.tsx
  • apps/web/src/components/skills/import-skill-modal.tsx
  • apps/web/src/components/ui/input.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/desktop/src/components/surface-frame.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/src/components/ui/input.tsx

Replace all instances of capitalized "Nexu" with lowercase "nexu" in
user-facing strings: i18n locales (en/zh-CN), HTML titles, Electron
app name/window title, Slack manifest, model provider labels, aria
labels, alt text, controller API titles, default bot name, and docs.

Code identifiers (class names, variable names) remain PascalCase/
camelCase as per convention.

Made-with: Cursor
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Mar 24, 2026

Deploying nexu-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: bb1ddcc
Status: ✅  Deploy successful!
Preview URL: https://8ffc000f.nexu-docs.pages.dev
Branch Preview URL: https://feat-ui-polish-wechat-logo-d.nexu-docs.pages.dev

View logs

@zoeforfun zoeforfun requested review from Siri-Ray and lefarcen March 24, 2026 10:49
@zoeforfun zoeforfun requested a review from mrcfps March 24, 2026 10:52
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/web/src/pages/models.tsx (1)

869-870: Guard model-switch mutation against rapid repeated clicks.

These callbacks call updateModel.mutate directly; quick repeated selections can enqueue overlapping switches. Consider ignoring clicks while updateModel.isPending.

Also applies to: 881-882

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/pages/models.tsx` around lines 869 - 870, Guard the model-switch
mutation by checking the updateModel mutation state before calling it: in the
onSelectModel handlers that currently call updateModel.mutate(modelId) (and the
similar handler at the other occurrence), return early if updateModel.isPending
(or otherwise use a boolean flag) to ignore clicks while a switch is in
progress, and also consider disabling the model selection UI prop when
updateModel.isPending to prevent further input.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/i18n/locales/zh-CN.ts`:
- Line 217: Some i18n keys were renamed but call sites still use the old IDs,
causing runtime missing translations; add alias entries in the zh-CN locale
mapping so old IDs point to the same strings as the new IDs. Locate the new keys
such as "home.starnexu" and create duplicates for the old IDs used in code
(e.g., add "home.starNexu" mapping to the same value), and similarly add aliases
for claim.teamUsesNexu.* and claim.exploreNexu, feishuBind.exploreNexu,
slackSetup.addNexuTitle, and slackSetup.addNexuDesc so callers continue to
resolve until callers are migrated. Ensure each alias key uses the identical
string value as its new counterpart to preserve behavior.

In `@apps/web/src/pages/models.tsx`:
- Around line 1152-1155: The "Active" badge is hardcoded; replace the literal
text with a localized string using the app's i18n pattern (e.g., useTranslation
or existing t() function used elsewhere in this file) and a key like
"status.active". Update both occurrences (the span containing <Check /> at the
shown block and the same block around lines 1520-1523) to call
t('status.active') (or the project's equivalent) so the badge text is
translated; add the translation key to the locale files if missing and
import/use the same translation hook used in this component (e.g., const { t } =
useTranslation()).
- Around line 1013-1050: The button currently only renders for cloudConnected ||
loginBusy and its onClick only handles disconnect; add the missing "connect"
path so the same header action appears when not connected and clicking initiates
a connect flow. Specifically, keep the existing props (cloudToggleBusy,
aria-label, loader, translations) but extend the onClick handler to: if
(!cloudConnected) return early when already connecting, set a new
cloudConnecting state (e.g., cloudConnecting / setCloudConnecting), call the
appropriate connect API (e.g., postApiInternalDesktopCloudConnect) with
try/catch/finally, setCloudConnected(true) on success and invalidate the same
queries via queryClient.invalidateQueries(["models"]) and
["desktop-default-model"], and clear cloudConnecting in finally; also update
aria-label and button text to use the "connect" translations when cloudConnected
is false and ensure the loader shows when cloudConnecting || loginBusy. Use the
existing symbols cloudConnected, loginBusy, cloudToggleBusy, cloudDisconnecting,
setCloudDisconnecting, setCloudConnected, queryClient.invalidateQueries and add
cloudConnecting / setCloudConnecting and postApiInternalDesktopCloudConnect to
locate where to implement the fix.

---

Nitpick comments:
In `@apps/web/src/pages/models.tsx`:
- Around line 869-870: Guard the model-switch mutation by checking the
updateModel mutation state before calling it: in the onSelectModel handlers that
currently call updateModel.mutate(modelId) (and the similar handler at the other
occurrence), return early if updateModel.isPending (or otherwise use a boolean
flag) to ignore clicks while a switch is in progress, and also consider
disabling the model selection UI prop when updateModel.isPending to prevent
further input.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 78921915-a2d4-43f0-96b4-9805bd0d11b5

📥 Commits

Reviewing files that changed from the base of the PR and between 00800d1 and bb1ddcc.

📒 Files selected for processing (23)
  • apps/controller/scripts/generate-openapi.ts
  • apps/controller/src/app/create-app.ts
  • apps/controller/src/store/nexu-config-store.ts
  • apps/controller/tests/route-compat.test.ts
  • apps/desktop/index.html
  • apps/desktop/main/index.ts
  • apps/desktop/main/runtime/manifests.ts
  • apps/desktop/src/components/desktop-shell.tsx
  • apps/desktop/src/lib/host-api.ts
  • apps/desktop/src/main.tsx
  • apps/desktop/src/pages/runtime-page.tsx
  • apps/web/index.html
  • apps/web/src/components/brand-rail.tsx
  • apps/web/src/components/channel-setup/slack-oauth-view.tsx
  • apps/web/src/components/model-picker-dropdown.tsx
  • apps/web/src/components/provider-logo.tsx
  • apps/web/src/i18n/locales/en.ts
  • apps/web/src/i18n/locales/zh-CN.ts
  • apps/web/src/layouts/workspace-layout.tsx
  • apps/web/src/pages/invite.tsx
  • apps/web/src/pages/models.tsx
  • apps/web/src/pages/slack-claim.tsx
  • docs/.vitepress/config.ts
✅ Files skipped from review due to trivial changes (16)
  • apps/web/index.html
  • apps/controller/src/app/create-app.ts
  • apps/controller/scripts/generate-openapi.ts
  • apps/desktop/src/lib/host-api.ts
  • apps/web/src/components/provider-logo.tsx
  • apps/desktop/src/components/desktop-shell.tsx
  • apps/desktop/src/pages/runtime-page.tsx
  • docs/.vitepress/config.ts
  • apps/controller/tests/route-compat.test.ts
  • apps/web/src/components/brand-rail.tsx
  • apps/desktop/main/runtime/manifests.ts
  • apps/desktop/main/index.ts
  • apps/web/src/layouts/workspace-layout.tsx
  • apps/desktop/src/main.tsx
  • apps/web/src/pages/slack-claim.tsx
  • apps/desktop/index.html
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/src/pages/invite.tsx
  • apps/web/src/components/model-picker-dropdown.tsx
  • apps/web/src/i18n/locales/en.ts

Comment thread apps/web/src/i18n/locales/zh-CN.ts
Comment thread apps/web/src/pages/models.tsx
Comment thread apps/web/src/pages/models.tsx
Comment thread apps/desktop/main/index.ts
Copy link
Copy Markdown
Collaborator

@lefarcen lefarcen left a comment

Choose a reason for hiding this comment

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

功能回退风险 — 必须修复

🔴 严重:i18n key 重命名但 TSX 调用站未同步更新

locale 文件删除了旧 key、新增了小写 key,但以下 TSX 文件仍在调用旧 key,上线后这些位置会直接显示 raw key 字符串而非翻译文本:

TSX 文件 仍在使用的旧 key locale 里已改为
apps/web/src/pages/home.tsx t("home.starNexu") home.starnexu
apps/web/src/pages/feishu-bind.tsx t("feishuBind.exploreNexu") feishuBind.explorenexu
apps/web/src/pages/slack-claim.tsx t("claim.exploreNexu") claim.explorenexu
apps/web/src/pages/slack-claim.tsx t("claim.teamUsesNexu.line1/2/3") claim.teamUsesnexu.line1/2/3
apps/web/src/components/channel-setup/slack-oauth-view.tsx t("slackSetup.addNexuTitle") slackSetup.addnexuTitle
apps/web/src/components/channel-setup/slack-oauth-view.tsx t("slackSetup.addNexuDesc") slackSetup.addnexuDesc

修复方式(二选一):

  • 同步更新上述所有 t("...") 调用点为新 key;
  • 或者 locale 文件不重命名 key(只改 value 里的文字内容),这样调用站不需要改动。

🟡 中:GitHub Skill import input 被启用但无提交逻辑

import-skill-modal.tsx 删除了 GitHub URL input 的 disabled 属性,用户现在可以输入 URL,但 diff 中未见对应的提交/拉取 handler。如果后端尚未支持 GitHub URL 导入,请恢复 disabled 直到实现完整,避免用户输入后无任何反应。


✅ 关于 Nexunexu rename 是否造成已有用户数据丢失

不会。 核心状态目录是 ~/.nexu/(controller 状态),与 app.setName() 无关。Electron userData 路径虽受 app name 影响,但 macOS 文件系统默认大小写不敏感,~/Library/Application Support/Nexu~/Library/Application Support/nexu 指向同一目录,不存在数据迁移问题。

chaoxiaoche added 2 commits March 24, 2026 19:07
The "Connected" label was ambiguous — users didn't realize it was
clickable to disconnect. Rename to "Log out" / "退出登录" to make the
action clear.

Made-with: Cursor
- feishu-setup-view: restore missing helpSuffix translation in help
  link so the sentence is grammatically complete
- model-picker-dropdown: change selected model label from
  text-brand-primary to text-text-primary for better contrast
- en.ts: fix WeChat setup desc wording ("Scan in" → "Scan with")
- sessions.tsx: replace hardcoded rgba(0,163,101,0.12) with
  var(--color-success-muted) design token for consistency

Made-with: Cursor
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/src/i18n/locales/en.ts (1)

290-293: Consider renaming models.managed.connected key for semantic clarity.

The key models.managed.connected now holds the value "Log out", which is semantically mismatched. Per the PR commit message, this label change clarifies the disconnect action—however, maintaining a key named connected with a value of "Log out" may confuse future maintainers.

Consider renaming to models.managed.logOut or models.managed.disconnectAction for clarity:

-  "models.managed.connected": "Log out",
+  "models.managed.logOut": "Log out",

The new keys (notConnected, cloudConnectAria, cloudDisconnectAria, refreshModelList) are well-named and consistent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/i18n/locales/en.ts` around lines 290 - 293, Rename the i18n key
models.managed.connected (value "Log out") to a semantically correct key like
models.managed.logOut and update every reference to it across the codebase
(components, hooks, tests) to use models.managed.logOut instead of
models.managed.connected; also update other locale files and any snapshot/tests
that expect the old key, and ensure no fallback relies on
models.managed.connected to avoid runtime missing-key errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/i18n/locales/en.ts`:
- Around line 708-710: Update the slack-oauth-view component to use the new
lowercase locale keys: replace any references to slackSetup.addNexuTitle and
slackSetup.addNexuDesc in the Slack OAuth view with slackSetup.addnexuTitle and
slackSetup.addnexuDesc (i.e., update the getString/useTranslation calls or JSX
t('...') usages inside the slack-oauth-view component to the new key names so
they match the updated en locale).
- Line 221: Update the translation keys used in components to match the new
lowercase keys: replace occurrences of "home.starNexu" with "home.starnexu"
(e.g., any t('home.starNexu') calls in the home component), and replace
"slackSetup.addNexuTitle" and "slackSetup.addNexuDesc" with
"slackSetup.addnexuTitle" and "slackSetup.addnexuDesc" respectively (e.g., the
t(...) usages in the Slack OAuth view component); ensure all string literals
passed to the i18n translator (t or similar) use the new lowercase keys so
lookups succeed.

---

Nitpick comments:
In `@apps/web/src/i18n/locales/en.ts`:
- Around line 290-293: Rename the i18n key models.managed.connected (value "Log
out") to a semantically correct key like models.managed.logOut and update every
reference to it across the codebase (components, hooks, tests) to use
models.managed.logOut instead of models.managed.connected; also update other
locale files and any snapshot/tests that expect the old key, and ensure no
fallback relies on models.managed.connected to avoid runtime missing-key errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b736f9c-a7b6-43e0-ab67-070782aa8f08

📥 Commits

Reviewing files that changed from the base of the PR and between bb1ddcc and 88e840b.

📒 Files selected for processing (2)
  • apps/web/src/i18n/locales/en.ts
  • apps/web/src/i18n/locales/zh-CN.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/src/i18n/locales/zh-CN.ts

Comment thread apps/web/src/i18n/locales/en.ts
Comment thread apps/web/src/i18n/locales/en.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/web/src/pages/sessions.tsx (1)

414-414: Inconsistent hardcoded color value.

Line 414 uses a hardcoded rgba(0,163,101,0.06) for the background while the border on the same line uses color-mix with var(--color-success). This is inconsistent with the PR goal of migrating hardcoded colors to CSS tokens.

Consider using a token (--color-success-subtle) or color-mix for the background as well to maintain consistency and ease future theme adjustments.

♻️ Suggested fix for consistency
-      className="mt-0.5 inline-flex max-w-full items-center gap-2 rounded-full border border-[color-mix(in_srgb,var(--color-success)_12%,transparent)] bg-[rgba(0,163,101,0.06)] px-2.5 py-1.5 text-[12px] shadow-none"
+      className="mt-0.5 inline-flex max-w-full items-center gap-2 rounded-full border border-[color-mix(in_srgb,var(--color-success)_12%,transparent)] bg-[color-mix(in_srgb,var(--color-success)_6%,transparent)] px-2.5 py-1.5 text-[12px] shadow-none"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/pages/sessions.tsx` at line 414, The background uses a hardcoded
rgba value inside the className on the Sessions page which conflicts with the
border's use of the CSS token var(--color-success) via color-mix; replace the
hardcoded background (rgba(0,163,101,0.06)) with a CSS token or color-mix (for
example define and use --color-success-subtle or use color-mix(in srgb,
var(--color-success) 6%, transparent)) so both border and background derive from
the same theme token—update the className in apps/web/src/pages/sessions.tsx
where that long className string appears to reference the new token/mix instead
of the rgba literal.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/web/src/pages/sessions.tsx`:
- Line 414: The background uses a hardcoded rgba value inside the className on
the Sessions page which conflicts with the border's use of the CSS token
var(--color-success) via color-mix; replace the hardcoded background
(rgba(0,163,101,0.06)) with a CSS token or color-mix (for example define and use
--color-success-subtle or use color-mix(in srgb, var(--color-success) 6%,
transparent)) so both border and background derive from the same theme
token—update the className in apps/web/src/pages/sessions.tsx where that long
className string appears to reference the new token/mix instead of the rgba
literal.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f0a85d4-1a66-448e-af08-3cb3e83d3a21

📥 Commits

Reviewing files that changed from the base of the PR and between 88e840b and fdf93e5.

📒 Files selected for processing (4)
  • apps/web/src/components/channel-setup/feishu-setup-view.tsx
  • apps/web/src/components/model-picker-dropdown.tsx
  • apps/web/src/i18n/locales/en.ts
  • apps/web/src/pages/sessions.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/i18n/locales/en.ts
  • apps/web/src/components/model-picker-dropdown.tsx

@lefarcen
Copy link
Copy Markdown
Collaborator

@$(gh pr view 503 --json author --jq '.author.login') 修复 commit fdf93e56 没有解决我指出的 i18n 问题,旧 key 仍然已从 locale 文件删除,但以下 TSX 调用站至今仍引用已删除的 key,直接在 PR branch 上验证:

apps/web/src/pages/home.tsx:935              t("home.starNexu")           → 应为 home.starnexu
apps/web/src/pages/feishu-bind.tsx:88        t("feishuBind.exploreNexu")  → 应为 feishuBind.explorenexu
apps/web/src/pages/slack-claim.tsx:135/137/139  t("claim.teamUsesNexu.*") → 应为 claim.teamUsesnexu.*
apps/web/src/pages/slack-claim.tsx:629       t("claim.exploreNexu")       → 应为 claim.explorenexu
apps/web/src/components/channel-setup/slack-oauth-view.tsx:266/269
                                             t("slackSetup.addNexuTitle/Desc") → 应为 addnexuTitle/Desc

这 8 处上线后都会渲染 raw key 字符串。请把这些 t("...") 调用也一并更新。

Replace two hardcoded #00a365 hex values in update-dot styles with
var(--color-success) to avoid drift from the token already defined
in the same file.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants