You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by as...@apache.org on 2026/09/25 09:25:36 UTC

(maka) branch main updated: fix(ui): make the project picker match the model and thinking selectors (#5717)

This is an automated email from the ASF dual-hosted git repository.

Astro-Han pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/maka.git


The following commit(s) were added to refs/heads/main by this push:
     new 69a0a63fd1 fix(ui): make the project picker match the model and thinking selectors (#5717)
69a0a63fd1 is described below

commit 69a0a63fd1b5e8dcd254b1b9d5c45c25232be62a
Author: AstroHan <le...@outlook.com>
AuthorDate: Fri Sep 25 17:25:30 2026 +0800

    fix(ui): make the project picker match the model and thinking selectors (#5717)
    
    #5444 moved the composer's model and thinking pickers to Astryx Selector
    but left the project picker a ghost-button DropdownMenu, so the three
    footer triggers hovered, pointed and loaded differently.
    
    The picker stays a DropdownMenu, because its menu carries actions, and
    only its trigger chrome now matches the Selectors:
    
    - It keeps --radius-element instead of the composer's concentric 16px
      --_button-radius.
    - It draws a secondary chevronDown next to the host badge and turns it
      over while open, with the Selector's motion tokens.
    - The badge and chevron hide while the trigger is aria-busy, so the
      spinner no longer sits beside a stranded badge.
    
    No persisted state or API changes.
    
    Generated-by: Claude Code
---
 .../desktop/src/renderer/styles/model-switcher.css | 31 +++++++++++++++++++---
 apps/desktop/stories/app-shell.stories.tsx         | 11 ++++++++
 docs/astryx-surface-file-inventory.md              |  2 +-
 packages/ui/src/workspace-picker.tsx               | 19 ++++++++-----
 4 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/apps/desktop/src/renderer/styles/model-switcher.css b/apps/desktop/src/renderer/styles/model-switcher.css
index 1c5b2652e0..4ed3387c72 100644
--- a/apps/desktop/src/renderer/styles/model-switcher.css
+++ b/apps/desktop/src/renderer/styles/model-switcher.css
@@ -40,21 +40,44 @@
   max-width: 100%;
 }
 
-/* The project picker's trigger is now a ghost-button DropdownMenu like the
-   model and thinking chips beside it (workspace-picker.tsx), so resting,
-   hover, focus, disabled and tooltip chrome all derive from Astryx Button —
-   no field overlay needed here.
+/* The project picker stays a DropdownMenu because its menu carries actions
+   (new, manage, no project, retry), not just options. It still has to read as
+   the model and thinking Selectors beside it: a Selector keeps the element
+   radius and ignores the concentric --_button-radius the composer gives its
+   footer buttons.
    Geometry sizes to the project name rather than holding the model pair's
    column width: it is the last control in a row that already wraps, so a
    fixed width would spend space the model chip beside it needs. The cap is
    what keeps a long directory name from pushing the send button off the
    row. */
 .maka-workspace-picker {
+  --_button-radius: var(--radius-element);
   min-width: 0;
   max-width: min(280px, 60vw);
   flex: 0 0 auto;
 }
 
+.maka-workspace-picker-end {
+  display: inline-flex;
+  align-items: center;
+  gap: var(--space-2);
+}
+
+/* Turns over while open, as the Selector chevrons do. */
+.maka-workspace-picker-chevron {
+  transition: transform var(--duration-fast) var(--ease-standard);
+}
+
+.maka-workspace-picker[aria-expanded="true"] .maka-workspace-picker-chevron {
+  transform: rotate(180deg);
+}
+
+/* A loading Button hides its content by making it transparent text; the
+   badge and chevron paint their own colors, so they have to be hidden with it. */
+.maka-workspace-picker[aria-busy="true"] .maka-workspace-picker-end {
+  visibility: hidden;
+}
+
 /* Cursor: product-wide native-cursor.css (maka.legacy) owns default vs pointer. */
 
 /* The one rem that stays, and the reason is the icon scale rather than the
diff --git a/apps/desktop/stories/app-shell.stories.tsx b/apps/desktop/stories/app-shell.stories.tsx
index 82f8f00041..6bf8aa62c1 100644
--- a/apps/desktop/stories/app-shell.stories.tsx
+++ b/apps/desktop/stories/app-shell.stories.tsx
@@ -1362,6 +1362,11 @@ export const NewChatComposer: Story = {
     await waitFor(() => expect(editor.textContent).toBe(''));
     await expect(editor.getBoundingClientRect().height).toBe(initialEditorHeight);
     await expect(card.getBoundingClientRect().height).toBe(initialCardHeight);
+
+    const projectPicker = canvasElement.querySelector<HTMLElement>('.maka-workspace-picker')!;
+    const modelPicker = canvasElement.querySelector<HTMLElement>('.maka-new-chat-model-selector')!;
+    await expect(getComputedStyle(projectPicker).borderRadius).toBe(getComputedStyle(modelPicker).borderRadius);
+    await expect(projectPicker.querySelector('.maka-workspace-picker-chevron svg')).not.toBeNull();
   },
 };
 
@@ -1408,6 +1413,12 @@ export const NewChatComposerProjectPending: Story = {
       }}
     />
   ),
+  play: async ({ canvasElement }) => {
+    // The spinner replaces the whole trigger content, host badge included.
+    const end = canvasElement.querySelector<HTMLElement>('.maka-workspace-picker .maka-workspace-picker-end')!;
+    await expect(end.querySelector('.maka-workspace-picker-host-badge')).not.toBeNull();
+    await expect(getComputedStyle(end).visibility).toBe('hidden');
+  },
 };
 
 const longConversation: StoredMessage[] = [
diff --git a/docs/astryx-surface-file-inventory.md b/docs/astryx-surface-file-inventory.md
index f0ba153dc7..e97630c219 100644
--- a/docs/astryx-surface-file-inventory.md
+++ b/docs/astryx-surface-file-inventory.md
@@ -326,7 +326,7 @@ Wiki bar: Design Conventions · API Use-the-System · Theming · Container Paddi
 | `packages/ui/src/transcript-scroll-authority.tsx` | ui-composition | ChatLayoutScrollButton | aligned — uses Astryx (ChatLayoutScrollButton) | aligned |
 | `packages/ui/src/ui.tsx` | ui-composition | none | aligned — no raw controls; no Astryx JSX usage | aligned |
 | `packages/ui/src/user-question-prompt.tsx` | ui-composition | Button, ChatComposer, ChatComposerInput | aligned — uses Astryx (Button, ChatComposer, ChatComposerInput) | aligned |
-| `packages/ui/src/workspace-picker.tsx` | ui-composition | DropdownMenu, DropdownMenuItem | aligned — uses Astryx (DropdownMenu, DropdownMenuItem) | aligned |
+| `packages/ui/src/workspace-picker.tsx` | ui-composition | DropdownMenu, DropdownMenuItem, Icon | aligned — uses Astryx (DropdownMenu, DropdownMenuItem, Icon) | aligned |
 
 ## Severity legend
 
diff --git a/packages/ui/src/workspace-picker.tsx b/packages/ui/src/workspace-picker.tsx
index e7bb33d4dd..9032933972 100644
--- a/packages/ui/src/workspace-picker.tsx
+++ b/packages/ui/src/workspace-picker.tsx
@@ -21,6 +21,7 @@ import type { ProjectRecord } from '@maka/core/project';
 import { useState } from 'react';
 import { createPortal } from 'react-dom';
 import { DropdownMenu, DropdownMenuItem } from '@astryxdesign/core/DropdownMenu';
+import { Icon } from '@astryxdesign/core/Icon';
 import { ICON_SIZE, AlertTriangle, Check, FolderOpen, Network, Plus, RefreshCcw, Settings, X } from './icons.js';
 import { useUiLocale } from './locale-context.js';
 import { getConversationCopy } from './conversation-copy.js';
@@ -77,7 +78,6 @@ export function WorkspacePicker({ workspacePicker: picker }: {
     <>
     <DropdownMenu
       placement="above"
-      hasChevron={false}
       isMenuOpen={picker.isMenuOpen}
       onOpenChange={picker.onOpenChange}
       className="maka-composer-quiet-menu"
@@ -90,12 +90,19 @@ export function WorkspacePicker({ workspacePicker: picker }: {
         isLoading: locked,
         tooltip: copy.chooseTitle(picker.branch ?? undefined),
         className: 'maka-workspace-picker',
-        endContent: picker.hostBadge ? (
-          <span className="maka-workspace-picker-host-badge">
-            <Network size={ICON_SIZE.meta} aria-hidden="true" />
-            <span>{picker.hostBadge}</span>
+        // Any endContent replaces DropdownMenu's own chevron, so the chevron is
+        // drawn here, as the model and thinking Selectors draw theirs.
+        endContent: (
+          <span className="maka-workspace-picker-end">
+            {picker.hostBadge ? (
+              <span className="maka-workspace-picker-host-badge">
+                <Network size={ICON_SIZE.meta} aria-hidden="true" />
+                <span>{picker.hostBadge}</span>
+              </span>
+            ) : null}
+            <Icon icon="chevronDown" size="sm" color="secondary" className="maka-workspace-picker-chevron" />
           </span>
-        ) : undefined,
+        ),
         'aria-label': copy.chooseAriaLabel(
           picker.hostBadge
             ? `${picker.hostBadge} · ${picker.label ?? copy.current}`


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org