@nextclaw/ui 0.26.2 → 0.26.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/.vite/manifest.json +366 -365
  3. package/dist/assets/{account-panel-ZM2qzKF4.js → account-panel-DIdHjKG-.js} +1 -1
  4. package/dist/assets/{api-Cjq-o1VN.js → api-DkLJrSCd.js} +2 -2
  5. package/dist/assets/app-presenter-provider-Co8uKOyW.js +124 -0
  6. package/dist/assets/{appearance-settings-page-B4zouKzg.js → appearance-settings-page-DI8aDY2G.js} +1 -1
  7. package/dist/assets/{book-open-AteA89HX.js → book-open-BPMkKSci.js} +1 -1
  8. package/dist/assets/{card-BLXvBstA.js → card-Bqu8zWLq.js} +1 -1
  9. package/dist/assets/{channels-list-page-fj8kMo-T.js → channels-list-page-CCIaTQu7.js} +1 -1
  10. package/dist/assets/{circle-dashed-LSYZTzM7.js → circle-dashed-B48a0t6p.js} +1 -1
  11. package/dist/assets/{client-DudCRJw4.js → client-imrVphQb.js} +1 -1
  12. package/dist/assets/{config-split-page-G7Kt2BnV.js → config-split-page-Bd-bGKsw.js} +1 -1
  13. package/dist/assets/{confirm-dialog-DShT64F6.js → confirm-dialog-10Qb3dpZ.js} +1 -1
  14. package/dist/assets/context-menu-CRqH2SEk.js +1 -0
  15. package/dist/assets/{createLucideIcon-D7hvIHV-.js → createLucideIcon-B4xj2I2g.js} +1 -1
  16. package/dist/assets/{desktop-capabilities-page-CzqzFZUY.js → desktop-capabilities-page-CFcT2g8-.js} +1 -1
  17. package/dist/assets/{desktop-update-config-CgeQ0Ffo.js → desktop-update-config-CRJd_An1.js} +1 -1
  18. package/dist/assets/{dialog-C7glmAQJ.js → dialog-BgL3vKJQ.js} +2 -2
  19. package/dist/assets/doc-browser-52t2_rSF.js +1 -0
  20. package/dist/assets/{doc-browser-context-BlhBAOLH.js → doc-browser-context-DH4aWvkS.js} +1 -1
  21. package/dist/assets/{download-BYgECE0n.js → download-Cr337h4W.js} +1 -1
  22. package/dist/assets/{es2015-CsjAAQ6X.js → es2015-D-CRf3_Z.js} +1 -1
  23. package/dist/assets/{extensions-qYL-NpL3.js → extensions-CsmJPz7g.js} +1 -1
  24. package/dist/assets/{eye-BBuTzJ53.js → eye-DrQRSAfJ.js} +1 -1
  25. package/dist/assets/{form-actions-CLGWO52v.js → form-actions-BEeWTGUZ.js} +1 -1
  26. package/dist/assets/{i18n-qBGEbcW6.js → i18n-OGmF0Ws_.js} +2 -2
  27. package/dist/assets/{keyboard-shortcuts-settings-page-B-wK_6zG.js → keyboard-shortcuts-settings-page-DQU56SrW.js} +1 -1
  28. package/dist/assets/loader-circle-DbOQWT9C.js +1 -0
  29. package/dist/assets/login-page-DW1AZXqX.js +1 -0
  30. package/dist/assets/{login-page-Cd84lpVV.js → login-page-sgivRYG1.js} +1 -1
  31. package/dist/assets/main-B-oxUq-o.js +2 -0
  32. package/dist/assets/main-BpL6OjwM.css +1 -0
  33. package/dist/assets/main-i18n-catalog.config-Bpu5GcwF.js +1 -0
  34. package/dist/assets/mcp-marketplace-page-DSLRpJEB.js +1 -0
  35. package/dist/assets/{model-config-page-D0DQlSDa.js → model-config-page-CDQBhmVr.js} +1 -1
  36. package/dist/assets/{navigation-link-32iM1-e6.js → navigation-link-D3pzNHeA.js} +1 -1
  37. package/dist/assets/panel-app-BYfQu_TS.js +1 -0
  38. package/dist/assets/panel-app-i18n-catalog.config-D44qmtfk.js +1 -0
  39. package/dist/assets/{panelStandalone-C9EKaApN.js → panelStandalone-CGkYeMK5.js} +2 -2
  40. package/dist/assets/panelStandalone-D-mhAGNa.css +1 -0
  41. package/dist/assets/{privacy-settings-page-Bxxx12OO.js → privacy-settings-page-CjoAkoDt.js} +1 -1
  42. package/dist/assets/projects-C7Zxpcoi.js +1 -0
  43. package/dist/assets/{provider-models-C3frdXeW.js → provider-models-YW7rIeOD.js} +1 -1
  44. package/dist/assets/{provider-scoped-model-input-CYetrPYZ.js → provider-scoped-model-input-axJ-pTEu.js} +1 -1
  45. package/dist/assets/{providers-config-page-DESB1h8g.js → providers-config-page-_QhBXQ4M.js} +1 -1
  46. package/dist/assets/{puzzle-CWHfFyYN.js → puzzle--RLCeYML.js} +1 -1
  47. package/dist/assets/{pwa-CiGUjpcd.js → pwa-DcizGowz.js} +1 -1
  48. package/dist/assets/{refresh-cw-y3L6PyLt.js → refresh-cw-syCVj_nw.js} +1 -1
  49. package/dist/assets/remote-BLQU7aY5.js +1 -0
  50. package/dist/assets/{rotate-cw-CNE9qSHi.js → rotate-cw-BlH9El3x.js} +1 -1
  51. package/dist/assets/{runtime-config-page-5o98T-TD.js → runtime-config-page-Cco9dS73.js} +1 -1
  52. package/dist/assets/{save-B0p5a0ET.js → save-BWynuRQ2.js} +1 -1
  53. package/dist/assets/{search-config-page-CpGcnIzi.js → search-config-page-Cc74_SAU.js} +1 -1
  54. package/dist/assets/{secrets-config-page-C4VTiW3r.js → secrets-config-page-raYDzlFC.js} +1 -1
  55. package/dist/assets/security-config-aE_jOwy-.js +1 -0
  56. package/dist/assets/{select-CctTN205.js → select-6Uq4chZW.js} +1 -1
  57. package/dist/assets/{service-apps-panel-CKE5HKNY.js → service-apps-panel-jBWAa4qZ.js} +1 -1
  58. package/dist/assets/{settings-2-EPflrNk6.js → settings-2-COvVf1XX.js} +1 -1
  59. package/dist/assets/{status-dot-CensgJZC.js → status-dot-DZlxa5zW.js} +1 -1
  60. package/dist/assets/{tag-chip-Bjzb4-qW.js → tag-chip-DXHtZ8AS.js} +1 -1
  61. package/dist/assets/{theme-provider-hlle7Skk.js → theme-provider-C5PCDBPB.js} +1 -1
  62. package/dist/assets/{trash-2-C5KH5Rw9.js → trash-2-DazgBvmJ.js} +1 -1
  63. package/dist/assets/{use-config-CPl_F79t.js → use-config-DRRGF9Zb.js} +1 -1
  64. package/dist/assets/{use-desktop-capabilities-CEg9-DrQ.js → use-desktop-capabilities-CdfOUjdE.js} +1 -1
  65. package/dist/assets/{use-viewport-layout-CPZUmTPi.js → use-viewport-layout-DdxVnCYc.js} +1 -1
  66. package/dist/assets/x-CQIp_nJT.js +1 -0
  67. package/dist/index.html +34 -34
  68. package/dist/panel-standalone.html +11 -11
  69. package/package.json +3 -3
  70. package/src/app/components/layout/page-layout.tsx +5 -2
  71. package/src/app/configs/__tests__/app-navigation.config.test.ts +10 -0
  72. package/src/app/configs/app-navigation.config.ts +6 -2
  73. package/src/app/styles/charcoal-theme.css +1 -1
  74. package/src/app/styles/design-system.css +8 -2
  75. package/src/app/styles/island-theme.css +1 -1
  76. package/src/features/agents/components/agent-details-dialog.tsx +1 -1
  77. package/src/features/agents/components/agents-page.tsx +5 -3
  78. package/src/features/apps/components/app-package-card.tsx +7 -6
  79. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -3
  80. package/src/features/chat/components/conversation/chat-conversation-header.tsx +4 -4
  81. package/src/features/chat/components/layout/chat-page-shell.tsx +1 -1
  82. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +12 -5
  83. package/src/features/chat/features/session/components/chat-mobile-session-row.tsx +1 -1
  84. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +1 -1
  85. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +3 -5
  86. package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +4 -3
  87. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +1 -1
  88. package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +3 -1
  89. package/src/features/cron/components/cron-config.tsx +1 -0
  90. package/src/features/cron/components/cron-job-row.tsx +4 -4
  91. package/src/features/inbox/components/inbox-delivery-content.tsx +1 -1
  92. package/src/features/inbox/pages/inbox-page.tsx +24 -28
  93. package/src/features/marketplace/components/marketplace-page-parts.tsx +4 -3
  94. package/src/features/marketplace/components/marketplace-page.tsx +2 -2
  95. package/src/features/panel-apps/components/panel-app-open-standalone-menu-item.tsx +3 -1
  96. package/src/features/projects/components/project-overview.tsx +1 -1
  97. package/src/features/projects/pages/project-home-page.tsx +11 -2
  98. package/src/features/projects/pages/projects-page.test.tsx +4 -2
  99. package/src/platforms/mobile/components/mobile-app-shell.tsx +1 -1
  100. package/src/platforms/mobile/components/mobile-bottom-nav.tsx +8 -7
  101. package/src/platforms/mobile/components/mobile-settings-shell.tsx +24 -23
  102. package/src/platforms/mobile/components/mobile-topbar.tsx +10 -11
  103. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +34 -2
  104. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +36 -5
  105. package/src/shared/components/doc-browser/doc-browser.tsx +5 -1
  106. package/src/shared/components/settings/settings-page.tsx +1 -1
  107. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +5 -5
  108. package/src/shared/components/ui/actions/action-feedback.ts +8 -0
  109. package/src/shared/components/ui/actions/icon-action-button.tsx +13 -12
  110. package/src/shared/components/ui/button.tsx +1 -1
  111. package/src/shared/components/ui/context-menu/context-menu-items.tsx +4 -3
  112. package/src/shared/components/ui/dialog.tsx +4 -3
  113. package/src/shared/components/ui/input.tsx +1 -0
  114. package/src/shared/components/ui/select.tsx +2 -1
  115. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +5 -3
  116. package/src/shared/components/ui/tabs.tsx +2 -2
  117. package/src/shared/components/ui/textarea.tsx +1 -0
  118. package/src/shared/components/workbench/workbench-surface-toolbar.tsx +3 -4
  119. package/src/shared/components/workbench/workbench-surface.tsx +2 -2
  120. package/src/shared/lib/i18n/locales/en-US/agents.json +2 -0
  121. package/src/shared/lib/i18n/locales/en-US/core.json +1 -0
  122. package/src/shared/lib/i18n/locales/en-US/desktop-update.json +1 -1
  123. package/src/shared/lib/i18n/locales/zh-CN/agents.json +2 -0
  124. package/src/shared/lib/i18n/locales/zh-CN/core.json +1 -0
  125. package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +1 -1
  126. package/dist/assets/app-presenter-provider-C02YPoMr.js +0 -124
  127. package/dist/assets/context-menu-rd7b_kVD.js +0 -1
  128. package/dist/assets/doc-browser-dBiR9Qi0.js +0 -1
  129. package/dist/assets/loader-circle-BA7EMkih.js +0 -1
  130. package/dist/assets/login-page-VdMyNkFf.js +0 -1
  131. package/dist/assets/main-CR0SrTBf.js +0 -2
  132. package/dist/assets/main-DXH6EdXI.css +0 -1
  133. package/dist/assets/main-i18n-catalog.config-Btp_OowF.js +0 -1
  134. package/dist/assets/mcp-marketplace-page-jacRwiI-.js +0 -1
  135. package/dist/assets/panel-app-CC0bVSu4.js +0 -1
  136. package/dist/assets/panel-app-i18n-catalog.config-LUSBp5Ce.js +0 -1
  137. package/dist/assets/panelStandalone-Y91OJkgV.css +0 -1
  138. package/dist/assets/projects-D56yAPNT.js +0 -1
  139. package/dist/assets/remote-DiGFV8nP.js +0 -1
  140. package/dist/assets/security-config-C5-RQVpS.js +0 -1
  141. package/dist/assets/x--xxUvHKW.js +0 -1
@@ -29,6 +29,16 @@ describe("panel app main navigation", () => {
29
29
  describe("project home navigation", () => {
30
30
  const translate = (key: string) => key;
31
31
 
32
+ it("returns project details to the project picker", () => {
33
+ expect(resolveMobileRouteMeta("/projects/example/overview", translate).backTarget).toBe("/projects");
34
+ });
35
+
36
+ it("labels scheduled tasks and returns to chat", () => {
37
+ expect(resolveMobileRouteMeta("/cron", translate)).toEqual({
38
+ title: "cron", backTarget: "/chat", backLabel: "chat",
39
+ });
40
+ });
41
+
32
42
  it("keeps projects in the main workspace without a parallel global nav item", () => {
33
43
  expect(isMainWorkspaceRoute("/projects")).toBe(true);
34
44
  expect(getMainSidebarNavItems(translate).map((item) => item.target)).not.toContain("/projects");
@@ -259,8 +259,8 @@ export function resolveMobileRouteMeta(
259
259
  if (normalized === "/projects" || normalized.startsWith("/projects/")) {
260
260
  return {
261
261
  title: translate("projectsTitle"),
262
- backTarget: "/chat",
263
- backLabel: translate("chat"),
262
+ backTarget: normalized === "/projects" ? "/chat" : "/projects",
263
+ backLabel: translate(normalized === "/projects" ? "chat" : "projectsTitle"),
264
264
  };
265
265
  }
266
266
 
@@ -280,6 +280,10 @@ export function resolveMobileRouteMeta(
280
280
  };
281
281
  }
282
282
 
283
+ if (normalized === "/cron" || normalized.startsWith("/cron/")) {
284
+ return { title: translate("cron"), backTarget: "/chat", backLabel: translate("chat") };
285
+ }
286
+
283
287
  for (const item of settingsItems) {
284
288
  if (matchesRouteTarget(normalized, item.target)) {
285
289
  return {
@@ -42,7 +42,7 @@
42
42
  --secondary-foreground: var(--gray-800);
43
43
  --accent: 0 0% 19%;
44
44
  --accent-foreground: var(--gray-900);
45
- --interaction-hover: hsl(var(--gray-200));
45
+ --interaction-hover: hsl(var(--muted));
46
46
  --interaction-selection: hsl(202 38% 27%);
47
47
  --interaction-selection-border: hsl(202 48% 40%);
48
48
  --muted: var(--gray-100);
@@ -14,6 +14,12 @@
14
14
  :root {
15
15
  color-scheme: light;
16
16
 
17
+ /* Mobile density: hit target, visual feedback, and chrome are separate. */
18
+ --control-touch-size: 2.75rem;
19
+ --icon-control-size: 2.5rem;
20
+ --icon-feedback-size: 2rem;
21
+ --mobile-header-height: 3rem;
22
+
17
23
  /* ========================================
18
24
  BRAND COLORS (Natural Olive)
19
25
  ======================================== */
@@ -80,7 +86,7 @@
80
86
  /* Accent */
81
87
  --accent: var(--brand-50);
82
88
  --accent-foreground: var(--brand-700);
83
- --interaction-hover: hsl(0 0% 96%);
89
+ --interaction-hover: hsl(var(--muted));
84
90
  --interaction-selection: hsl(211 100% 92%);
85
91
  --interaction-selection-border: hsl(211 75% 84%);
86
92
 
@@ -717,7 +723,7 @@
717
723
  --secondary-foreground: var(--gray-800);
718
724
  --accent: 151 32% 18%;
719
725
  --accent-foreground: 148 34% 84%;
720
- --interaction-hover: hsl(var(--gray-200));
726
+ --interaction-hover: hsl(var(--muted));
721
727
  --interaction-selection: hsl(211 48% 30%);
722
728
  --interaction-selection-border: hsl(211 48% 42%);
723
729
  --muted: var(--gray-100);
@@ -44,7 +44,7 @@
44
44
  --secondary-foreground: var(--gray-800);
45
45
  --accent: 151 28% 88%;
46
46
  --accent-foreground: var(--brand-800);
47
- --interaction-hover: hsl(151 25% 86% / 0.72);
47
+ --interaction-hover: hsl(var(--muted));
48
48
  --interaction-selection: hsl(153 35% 80% / 0.82);
49
49
  --interaction-selection-border: hsl(157 37% 58% / 0.88);
50
50
  --muted: var(--gray-100);
@@ -350,7 +350,7 @@ function DetailItem(props: {
350
350
  return (
351
351
  <div
352
352
  className={cn(
353
- "grid min-w-0 grid-cols-[10rem_minmax(0,1fr)] items-baseline gap-x-2",
353
+ "grid min-w-0 grid-cols-1 sm:grid-cols-[10rem_minmax(0,1fr)] items-baseline gap-x-2 gap-y-1",
354
354
  (wide || isStructuredValue) && "sm:col-span-2",
355
355
  )}
356
356
  >
@@ -1,4 +1,5 @@
1
1
  import { PageResourceActionItems } from '@/features/right-panel-resources';
2
+ import { ACTION_FEEDBACK, ACTION_MENU_ITEM_CLASS } from '@/shared/components/ui/actions/action-feedback';
2
3
  import { pageResourceFromSystemObject } from '@/features/right-panel-resources';
3
4
  import { useMemo, useState } from "react";
4
5
  import {
@@ -97,10 +98,10 @@ function AgentActionMenuItem(props: {
97
98
  <button
98
99
  type="button"
99
100
  className={cn(
100
- "flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50",
101
+ ACTION_MENU_ITEM_CLASS,
101
102
  destructive
102
- ? "text-destructive hover:bg-destructive/10"
103
- : "text-foreground hover:bg-muted",
103
+ ? ACTION_FEEDBACK.destructive
104
+ : `text-foreground ${ACTION_FEEDBACK.item}`,
104
105
  )}
105
106
  onClick={onClick}
106
107
  disabled={disabled}
@@ -342,6 +343,7 @@ export function AgentsPage() {
342
343
  return (
343
344
  <PageLayout className="space-y-6">
344
345
  <PageHeader
346
+ mobileTitleInShell
345
347
  headingLevel={1}
346
348
  title={t("agentsHeroEyebrow")}
347
349
  description={t("agentsHeroDescription")}
@@ -1,4 +1,5 @@
1
1
  import { useRef, useState } from "react";
2
+ import { ACTION_FEEDBACK, ACTION_MENU_ITEM_CLASS } from '@/shared/components/ui/actions/action-feedback';
2
3
  import type { AppDataEntry, AppPackageOperationView, AppPackageView } from "@nextclaw/client-sdk";
3
4
  import {
4
5
  AlertCircle,
@@ -80,11 +81,11 @@ export function AppPackageCard({
80
81
 
81
82
  return (
82
83
  <Card surface="flat" hover={false} className="overflow-hidden border-border/60 shadow-[0_1px_2px_rgba(0,0,0,0.025)]">
83
- <div className="flex items-start gap-3.5 px-4 pb-3.5 pt-4">
84
+ <div className="flex max-md:grid max-md:grid-cols-[auto_minmax(0,1fr)] items-start gap-3.5 px-4 pb-3.5 pt-4">
84
85
  <AppArtwork icon={appPackage.icon} name={displayName} />
85
86
  <div className="min-w-0 flex-1">
86
87
  <div className="flex min-w-0 items-center gap-2">
87
- <h2 className="truncate text-sm font-semibold text-foreground">{displayName}</h2>
88
+ <h2 className="truncate max-md:whitespace-normal max-md:break-words text-sm font-semibold text-foreground">{displayName}</h2>
88
89
  <span className={cn("shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium", availability.className)}>{availability.label}</span>
89
90
  </div>
90
91
  {availability.message ? (
@@ -125,7 +126,7 @@ export function AppPackageCard({
125
126
  <code className="min-w-0 truncate font-mono text-[10px]">{appPackage.storage.dataDirectory}</code>
126
127
  </div>
127
128
  </div>
128
- <div className="flex shrink-0 items-center gap-1">
129
+ <div className="flex shrink-0 items-center gap-1 max-md:col-start-2 max-md:justify-end">
129
130
  <Button
130
131
  type="button"
131
132
  size="sm"
@@ -148,7 +149,7 @@ export function AppPackageCard({
148
149
  aria-label={t("appPackagesMoreActions")}
149
150
  title={t("appPackagesMoreActions")}
150
151
  disabled={pending}
151
- className="rounded-full p-2 text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:opacity-50"
152
+ className="max-md:min-h-11 max-md:min-w-11 inline-flex items-center justify-center rounded-full p-2 text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:opacity-50"
152
153
  >
153
154
  <MoreVertical className="h-4 w-4" />
154
155
  </button>
@@ -314,8 +315,8 @@ function AppPackageMenuItem({ destructive = false, icon: Icon, label, onClick }:
314
315
  type="button"
315
316
  onClick={onClick}
316
317
  className={cn(
317
- "flex w-full items-center gap-2 rounded-lg px-2.5 py-2 text-left text-sm transition-colors",
318
- destructive ? "text-destructive hover:bg-destructive/10" : "text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-accent-foreground",
318
+ ACTION_MENU_ITEM_CLASS,
319
+ destructive ? ACTION_FEEDBACK.destructive : `text-foreground ${ACTION_FEEDBACK.item}`,
319
320
  )}
320
321
  >
321
322
  <Icon className="h-4 w-4 shrink-0" />
@@ -19,7 +19,7 @@ import { useChatSessionListStore } from "@/features/chat/stores/chat-session-lis
19
19
  import { useChatThreadStore } from "@/features/chat/stores/chat-thread.store";
20
20
  import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
21
21
  import { AgentIdentityAvatar } from "@/shared/components/common/agent-identity";
22
- import { IconActionButton } from "@/shared/components/ui/actions/icon-action-button";
22
+ import { IconActionButton, IconActionGroup } from "@/shared/components/ui/actions/icon-action-button";
23
23
  import {
24
24
  getSessionProjectName,
25
25
  normalizeSessionProjectRootValue,
@@ -150,7 +150,7 @@ export function ChatConversationHeaderSection({
150
150
  ) : null
151
151
  }
152
152
  actions={
153
- <div className="flex shrink-0 items-center gap-1.5">
153
+ <IconActionGroup>
154
154
  {layoutMode === "mobile" && sessionKey ? (
155
155
  <IconActionButton
156
156
  icon={<SquarePen className="h-4 w-4" />}
@@ -180,7 +180,7 @@ export function ChatConversationHeaderSection({
180
180
  onToggleWorkspace={toggleWorkspace}
181
181
  onDeleteSession={presenter.chatThreadManager.deleteSession}
182
182
  />
183
- </div>
183
+ </IconActionGroup>
184
184
  }
185
185
  />
186
186
  );
@@ -66,21 +66,21 @@ export function ChatConversationHeader({
66
66
  "bg-background/80 backdrop-blur-sm flex items-center justify-between shrink-0 overflow-hidden transition-colors duration-200",
67
67
  isMobileLayout ? "px-3 sm:px-3" : "px-4 sm:px-5",
68
68
  shouldShow ? "opacity-100" : "h-0 py-0 opacity-0",
69
- shouldShow && (isMobileLayout ? "min-h-12 pb-2 pt-2" : "h-[52px]"),
69
+ shouldShow && (isMobileLayout ? "min-h-[var(--mobile-header-height)] pb-0.5 pt-0.5" : "h-[52px]"),
70
70
  )}
71
71
  style={
72
72
  isMobileLayout && shouldShow
73
- ? { paddingTop: "calc(env(safe-area-inset-top, 0px) + 0.5rem)" }
73
+ ? { paddingTop: "calc(env(safe-area-inset-top, 0px) + 0.125rem)" }
74
74
  : undefined
75
75
  }
76
76
  >
77
- <div className="min-w-0 flex-1 flex items-center gap-2">
77
+ <div className="min-w-0 flex-1 flex items-center gap-2 max-md:gap-0">
78
78
  {isMobileLayout && onBackToList ? (
79
79
  <IconActionButton
80
80
  icon={<ArrowLeft className="h-4 w-4" />}
81
81
  label={t("chat")}
82
82
  onClick={onBackToList}
83
- className="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground"
83
+ size="lg"
84
84
  />
85
85
  ) : null}
86
86
  {leading}
@@ -55,7 +55,7 @@ function ManagementPageContent({ view }: ChatPageProps) {
55
55
  case 'resource': return <ResourcePage />;
56
56
  case 'projects': return <Suspense fallback={<div className="h-full animate-pulse bg-card/30" />}><ProjectsPage /></Suspense>;
57
57
  case 'panel-app': return <PanelAppMainPage />;
58
- case 'inbox': return <div className={`mx-auto flex h-full min-h-0 w-full flex-col py-4 sm:px-6 sm:py-5 ${MANAGEMENT_PAGE_CANVAS_WIDTH_CLASS}`}><InboxPage /></div>;
58
+ case 'inbox': return <div className={`mx-auto flex h-full min-h-0 w-full flex-col md:px-6 md:py-5 ${MANAGEMENT_PAGE_CANVAS_WIDTH_CLASS}`}><InboxPage /></div>;
59
59
  case 'cron':
60
60
  case 'agents': return <div ref={scrollRef} onScroll={onScroll} className="h-full overflow-auto custom-scrollbar">
61
61
  <div className={`mx-auto w-full px-4 py-4 sm:px-6 sm:py-5 ${MANAGEMENT_PAGE_CANVAS_WIDTH_CLASS}`}>
@@ -1,7 +1,9 @@
1
1
  import { useState } from 'react';
2
- import { ChevronDown, Clock3, Folder, FolderPlus, Plus, Search, X } from 'lucide-react';
2
+ import { Link } from 'react-router-dom';
3
+ import { AlarmClock, ChevronDown, Clock3, Folder, FolderPlus, Plus, Search, X } from 'lucide-react';
3
4
  import { Button } from '@/shared/components/ui/button';
4
- import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
5
+ import { IconActionButton, IconActionGroup } from '@/shared/components/ui/actions/icon-action-button';
6
+ import { ACTION_FEEDBACK, ACTION_MENU_ITEM_CLASS } from '@/shared/components/ui/actions/action-feedback';
5
7
  import { Input } from '@/shared/components/ui/input';
6
8
  import { Popover, PopoverTrigger } from '@/shared/components/ui/popover';
7
9
  import { ChatPopoverContent } from '@/features/chat/components/chat-popover-content';
@@ -50,7 +52,7 @@ export function ChatSidebarMobileToolbar(props: ChatSidebarToolbarProps & {
50
52
  const [viewMenuOpen, setViewMenuOpen] = useState(false);
51
53
  return (
52
54
  <div className="shrink-0 border-b border-border/50 bg-background px-3 text-foreground" style={{ paddingTop: 'env(safe-area-inset-top, 0px)' }}>
53
- <div className="flex h-14 items-center gap-1">
55
+ <div className="flex h-[var(--mobile-header-height)] items-center gap-1">
54
56
  <Popover open={viewMenuOpen} onOpenChange={setViewMenuOpen}>
55
57
  <h1>
56
58
  <PopoverTrigger asChild>
@@ -65,14 +67,19 @@ export function ChatSidebarMobileToolbar(props: ChatSidebarToolbarProps & {
65
67
  <ChatSessionHeaderMenuItem icon={Clock3} label={t('chatSidebarViewTime')} onClick={() => onSelectMode('time-first')} />
66
68
  <ChatSessionHeaderMenuItem icon={Folder} label={t('chatSidebarViewProject')} onClick={() => onSelectMode('project-first')} />
67
69
  <ChatSessionHeaderMenuItem icon={FolderPlus} label={t('chatProjectAdd')} onClick={onAddProject} />
70
+ <Link to="/cron" className={`${ACTION_MENU_ITEM_CLASS} text-foreground ${ACTION_FEEDBACK.item}`}>
71
+ <AlarmClock className="h-4 w-4 text-muted-foreground" />{t('cron')}
72
+ </Link>
68
73
  </div>
69
74
  </ChatPopoverContent>
70
75
  </Popover>
71
76
  <div className="flex-1" />
77
+ <IconActionGroup>
72
78
  <IconActionButton icon={searchOpen ? <X className="h-5 w-5" /> : <Search className="h-5 w-5" />}
73
- label={t(searchOpen ? 'chatSidebarCloseSearch' : 'chatSidebarSearchPlaceholder')} className="h-11 w-11" tooltip={false}
79
+ label={t(searchOpen ? 'chatSidebarCloseSearch' : 'chatSidebarSearchPlaceholder')} tooltip={false}
74
80
  onClick={() => { setSearchOpen(!searchOpen); if (searchOpen) onQueryChange(''); }} />
75
- <IconActionButton icon={<Plus className="h-5 w-5" />} label={t('chatSidebarNewTask')} className="h-11 w-11" tooltip={false} onClick={onCreateSession} />
81
+ <IconActionButton icon={<Plus className="h-5 w-5" />} label={t('chatSidebarNewTask')} tooltip={false} onClick={onCreateSession} />
82
+ </IconActionGroup>
76
83
  </div>
77
84
  {searchOpen ? <div className="pb-2">
78
85
  <Input autoFocus value={query} onChange={event => onQueryChange(event.target.value)} placeholder={t('chatSidebarSearchPlaceholder')}
@@ -51,7 +51,7 @@ export function ChatMobileSessionRow(props: ChatSidebarSessionItemProps) {
51
51
  </span>
52
52
  </span>
53
53
  </button>
54
- <ChatSessionMoreActionsMenu sessionKey={sessionKey} sessionTitle={title} className="h-11 w-9 shrink-0 rounded-none text-muted-foreground">
54
+ <ChatSessionMoreActionsMenu sessionKey={sessionKey} sessionTitle={title}>
55
55
  <ChatSessionHeaderMenuItem icon={Pin} label={t(isPinned ? 'chatSidebarUnpinSession' : 'chatSidebarPinSession')} onClick={onTogglePinned} />
56
56
  <ChatSessionHeaderMenuItem icon={Pencil} label={t('edit')} onClick={onStartEditing} />
57
57
  <ChatSessionHeaderMenuItem icon={Trash2} label={t('delete')} onClick={onDelete} destructive />
@@ -187,7 +187,7 @@ describe('ChatSessionHeaderActions', () => {
187
187
 
188
188
  const actionGroup = screen.getByRole('button', { name: 'More actions' }).parentElement;
189
189
 
190
- expect(actionGroup?.className).toContain('gap-1.5');
190
+ expect(actionGroup?.className).toContain('max-md:gap-0');
191
191
  expect(screen.getByRole('button', { name: 'Open session workspace' }).className).toContain('h-7');
192
192
  expect(screen.getByRole('button', { name: 'Open session workspace' }).className).toContain('w-7');
193
193
  });
@@ -1,6 +1,6 @@
1
1
  import { useState } from 'react';
2
2
  import { Braces, FolderOpen, PanelRightClose, PanelRightOpen, Trash2 } from 'lucide-react';
3
- import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
3
+ import { IconActionButton, IconActionGroup } from '@/shared/components/ui/actions/icon-action-button';
4
4
  import { useChatSessionProject } from '@/features/chat/features/session/hooks/use-chat-session-project';
5
5
  import { ChatSessionHeaderMenuItem } from './chat-session-header-menu-item';
6
6
  import { ChatSessionMoreActionsMenu } from './chat-session-more-actions-menu';
@@ -8,8 +8,6 @@ import { ChatSessionMetadataDialog } from './chat-session-metadata-dialog';
8
8
  import { ChatSessionProjectDialog } from './chat-session-project-dialog';
9
9
  import { t } from '@/shared/lib/i18n';
10
10
 
11
- const SESSION_HEADER_ACTION_GROUP_CLASS = 'flex shrink-0 items-center gap-1.5';
12
-
13
11
  type ChatSessionHeaderActionsProps = {
14
12
  sessionKey: string | null;
15
13
  sessionTitle?: string;
@@ -60,7 +58,7 @@ export function ChatSessionHeaderActions({
60
58
  };
61
59
 
62
60
  return (
63
- <div className={SESSION_HEADER_ACTION_GROUP_CLASS}>
61
+ <IconActionGroup>
64
62
  <IconActionButton
65
63
  icon={
66
64
  isWorkspaceOpen ? (
@@ -123,6 +121,6 @@ export function ChatSessionHeaderActions({
123
121
  />
124
122
  </>
125
123
  ) : null}
126
- </div>
124
+ </IconActionGroup>
127
125
  );
128
126
  }
@@ -1,5 +1,6 @@
1
1
  import type { LucideIcon } from 'lucide-react';
2
2
  import { cn } from '@/shared/lib/utils';
3
+ import { ACTION_FEEDBACK, ACTION_MENU_ITEM_CLASS } from '@/shared/components/ui/actions/action-feedback';
3
4
 
4
5
  type ChatSessionHeaderMenuItemProps = {
5
6
  icon: LucideIcon;
@@ -20,10 +21,10 @@ export function ChatSessionHeaderMenuItem({
20
21
  <button
21
22
  type="button"
22
23
  className={cn(
23
- 'flex h-8 w-full items-center gap-2 rounded-lg px-2.5 text-left text-[13px] font-medium outline-none transition-colors disabled:cursor-not-allowed disabled:opacity-50',
24
+ ACTION_MENU_ITEM_CLASS,
24
25
  destructive
25
- ? 'text-destructive hover:bg-destructive/10 focus-visible:bg-destructive/10'
26
- : 'text-foreground hover:bg-muted focus-visible:bg-muted'
26
+ ? ACTION_FEEDBACK.destructive
27
+ : `text-foreground ${ACTION_FEEDBACK.item}`
27
28
  )}
28
29
  onClick={onClick}
29
30
  disabled={disabled}
@@ -29,7 +29,7 @@ import { cn } from "@/shared/lib/utils";
29
29
  import { useProjects } from "@/shared/hooks/use-projects";
30
30
 
31
31
  const SWITCHER_TRIGGER_CLASS =
32
- "group inline-flex min-w-0 max-w-full items-center gap-1.5 rounded-md px-1.5 py-1 text-sm font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border";
32
+ "group inline-flex min-w-0 max-w-full items-center gap-1.5 max-md:gap-1 rounded-md px-2 py-1 text-sm font-medium text-foreground transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border";
33
33
 
34
34
  function ChatSessionTitle({ title }: { title: string }) {
35
35
  return (
@@ -1,5 +1,5 @@
1
1
  import { ChevronsUp, FilePlus2, FolderPlus, MoreVertical, RefreshCw } from 'lucide-react';
2
- import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
2
+ import { IconActionButton, IconActionGroup } from '@/shared/components/ui/actions/icon-action-button';
3
3
  import { ContextMenuTrigger } from '@/shared/components/ui/context-menu/context-menu';
4
4
  import { t } from '@/shared/lib/i18n';
5
5
 
@@ -26,6 +26,7 @@ export function WorkspaceProjectFilesToolbar({
26
26
  >
27
27
  {rootLabel}
28
28
  </span>
29
+ <IconActionGroup>
29
30
  <IconActionButton
30
31
  icon={<FilePlus2 className="h-4 w-4" />}
31
32
  label={t('chatWorkspaceNewFile')}
@@ -59,6 +60,7 @@ export function WorkspaceProjectFilesToolbar({
59
60
  size="sm"
60
61
  />
61
62
  </ContextMenuTrigger>
63
+ </IconActionGroup>
62
64
  </div>
63
65
  );
64
66
  }
@@ -220,6 +220,7 @@ export function CronConfig() {
220
220
  return (
221
221
  <PageLayout className="space-y-6">
222
222
  <PageHeader
223
+ mobileTitleInShell
223
224
  headingLevel={1}
224
225
  title={t("cronPageTitle")}
225
226
  description={t("cronPageDescription")}
@@ -109,10 +109,10 @@ export function CronJobRow({
109
109
  expanded && "bg-muted/35",
110
110
  )}
111
111
  >
112
- <div className="flex items-center gap-3 px-1 py-3.5">
112
+ <div className="flex flex-wrap items-center gap-3 px-1 py-3.5">
113
113
  <button
114
114
  type="button"
115
- className="grid min-w-0 flex-1 grid-cols-[36px_minmax(0,1fr)] items-center gap-3 rounded-lg pr-16 text-left focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
115
+ className="grid min-w-0 flex-1 max-md:basis-full grid-cols-[36px_minmax(0,1fr)] items-center gap-3 rounded-lg md:pr-16 text-left focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
116
116
  aria-controls={previewId}
117
117
  aria-expanded={expanded}
118
118
  aria-label={`${t(expanded ? "cronCollapseTask" : "cronExpandTask")} ${jobLabel}`}
@@ -159,14 +159,14 @@ export function CronJobRow({
159
159
  </button>
160
160
 
161
161
  <TooltipProvider delayDuration={250}>
162
- <div className="relative flex shrink-0 items-center gap-1">
162
+ <div className="relative flex shrink-0 items-center gap-1 max-md:ml-auto">
163
163
  <Switch
164
164
  checked={job.enabled}
165
165
  onCheckedChange={(checked) => onToggle(job, checked)}
166
166
  aria-label={job.enabled ? t("cronDisable") : t("cronEnable")}
167
167
  />
168
168
 
169
- <div className="flex items-center gap-0.5 opacity-100 transition-opacity duration-150 [@media(hover:hover)]:pointer-events-none [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-focus-within:pointer-events-auto [@media(hover:hover)]:group-focus-within:opacity-100 [@media(hover:hover)]:group-hover:pointer-events-auto [@media(hover:hover)]:group-hover:opacity-100">
169
+ <div className="flex items-center gap-0.5 opacity-100 transition-opacity duration-150 md:[@media(hover:hover)]:pointer-events-none md:[@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-focus-within:pointer-events-auto [@media(hover:hover)]:group-focus-within:opacity-100 [@media(hover:hover)]:group-hover:pointer-events-auto [@media(hover:hover)]:group-hover:opacity-100">
170
170
  <Tooltip>
171
171
  <TooltipTrigger asChild>
172
172
  <Button
@@ -74,7 +74,7 @@ function InboxHtmlContent({
74
74
  return (
75
75
  <iframe
76
76
  className={cn(
77
- "w-full rounded-xl bg-background",
77
+ "w-full md:rounded-xl bg-background",
78
78
  fillHeight
79
79
  ? "h-full min-h-0 border-0"
80
80
  : "h-[min(60vh,680px)] min-h-[360px] border border-border/70",
@@ -2,7 +2,9 @@ import { PageResourceActionsMenu } from '@/features/right-panel-resources';
2
2
  import { pageResourceFromSystemObject } from '@/features/right-panel-resources';
3
3
  import { useEffect, useMemo, useState } from "react";
4
4
  import type { InboxDelivery } from "@nextclaw/shared";
5
- import { Archive, ArrowLeft, Inbox, MessageCircle, RotateCcw, Trash2 } from "lucide-react";
5
+ import { Archive, Inbox, MessageCircle, MoreVertical, RotateCcw, Trash2 } from "lucide-react";
6
+ import { ContextMenu, ContextMenuTrigger } from '@/shared/components/ui/context-menu/context-menu';
7
+ import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
6
8
  import { Link, useNavigate, useParams } from "react-router-dom";
7
9
  import { useAppPresenter } from "@/app/components/app-presenter-provider";
8
10
  import { PageHeader } from "@/app/components/layout/page-layout";
@@ -93,8 +95,9 @@ function InboxListPane({
93
95
  key={item.id}
94
96
  type="button"
95
97
  onClick={() => onFilterChange(item.id)}
98
+ aria-pressed={filter === item.id}
96
99
  className={cn(
97
- "inline-flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
100
+ "inline-flex min-h-11 items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border md:min-h-0 md:px-2.5 md:text-xs",
98
101
  filter === item.id
99
102
  ? "bg-[var(--interaction-selection)] text-foreground"
100
103
  : "text-muted-foreground hover:bg-[var(--interaction-hover)] hover:text-foreground",
@@ -122,7 +125,7 @@ function InboxListPane({
122
125
  <Link
123
126
  to={`/inbox/${encodeURIComponent(delivery.id)}`}
124
127
  className={cn(
125
- "block rounded-lg px-2.5 py-2 pr-10 text-[13px] transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
128
+ "block rounded-lg px-2.5 py-3 pr-12 text-sm md:py-2 md:pr-10 md:text-[13px] transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border",
126
129
  activeDeliveryId === delivery.id
127
130
  ? "text-foreground"
128
131
  : "text-foreground/80 hover:text-foreground",
@@ -165,20 +168,16 @@ function InboxListPane({
165
168
  function InboxDetailPane({
166
169
  delivery,
167
170
  error,
168
- isMobile,
169
171
  pending,
170
172
  onArchiveToggle,
171
- onBack,
172
173
  onContinue,
173
174
  onDelete,
174
175
  onReadToggle,
175
176
  }: {
176
177
  delivery: InboxDelivery | null;
177
178
  error: string | null;
178
- isMobile: boolean;
179
179
  pending: boolean;
180
180
  onArchiveToggle: () => void;
181
- onBack: () => void;
182
181
  onContinue: () => void;
183
182
  onDelete: () => void;
184
183
  onReadToggle: () => void;
@@ -193,17 +192,7 @@ function InboxDetailPane({
193
192
  const isHtml = delivery.contentType === "html";
194
193
  return (
195
194
  <main className="flex min-h-0 flex-col">
196
- <div className="shrink-0 border-b border-border/50 px-5 py-3 sm:px-6">
197
- {isMobile ? (
198
- <button
199
- type="button"
200
- onClick={onBack}
201
- className="mb-3 inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground"
202
- >
203
- <ArrowLeft className="h-4 w-4" />
204
- {t("inboxTitle")}
205
- </button>
206
- ) : null}
195
+ <div className="shrink-0 px-4 py-2 md:border-b md:border-border/50 md:px-6 md:py-3">
207
196
  <div className="flex min-h-7 min-w-0 items-center gap-2">
208
197
  <h2
209
198
  title={delivery.title}
@@ -223,7 +212,7 @@ function InboxDetailPane({
223
212
  <div className={cn(
224
213
  "min-h-0 flex-1",
225
214
  isHtml
226
- ? "p-3 sm:p-4"
215
+ ? "p-0 md:p-4"
227
216
  : "custom-scrollbar overflow-y-auto px-5 py-5 sm:px-6 sm:py-6",
228
217
  )}
229
218
  ref={scrollRef}
@@ -239,10 +228,10 @@ function InboxDetailPane({
239
228
  />
240
229
  </div>
241
230
  </div>
242
- <div className="shrink-0 border-t border-border/50 px-5 py-3 sm:px-6">
231
+ <div className="shrink-0 border-t border-border/50 px-4 py-2 md:px-6 md:py-3">
243
232
  {error ? <p role="alert" className="mb-2 text-sm text-destructive">{error}</p> : null}
244
- <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
245
- <div className="flex flex-wrap items-center gap-1">
233
+ <div className="flex items-center justify-between gap-2">
234
+ <div className="hidden md:flex flex-wrap items-center gap-1">
246
235
  <Button size="sm" variant="outline" disabled={pending} onClick={onReadToggle}>
247
236
  {delivery.readAt ? t("inboxMarkUnread") : t("inboxMarkRead")}
248
237
  </Button>
@@ -257,6 +246,15 @@ function InboxDetailPane({
257
246
  {t("inboxDelete")}
258
247
  </Button>
259
248
  </div>
249
+ <div className="md:hidden">
250
+ <ContextMenu label={t('inboxTitle')} groups={[{ key: 'delivery', items: [
251
+ { key: 'read', label: delivery.readAt ? t('inboxMarkUnread') : t('inboxMarkRead'), disabled: pending, onSelect: onReadToggle },
252
+ { key: 'archive', label: delivery.archivedAt ? t('inboxRestore') : t('inboxArchive'), icon: <Archive className="h-4 w-4" />, disabled: pending, onSelect: onArchiveToggle },
253
+ { key: 'delete', label: t('inboxDelete'), icon: <Trash2 className="h-4 w-4" />, destructive: true, disabled: pending, onSelect: onDelete },
254
+ ] }]}>
255
+ <div><ContextMenuTrigger><IconActionButton icon={<MoreVertical className="h-4 w-4" />} label={t('more')} /></ContextMenuTrigger></div>
256
+ </ContextMenu>
257
+ </div>
260
258
  <Button size="sm" disabled={pending} onClick={onContinue}>
261
259
  <MessageCircle className="mr-2 h-4 w-4" />
262
260
  {t("inboxContinueChat")}
@@ -365,14 +363,14 @@ export function InboxPage() {
365
363
  const showDetail = !isMobile || Boolean(activeDelivery);
366
364
 
367
365
  return (
368
- <div className="flex h-full min-h-0 flex-col gap-6">
369
- <PageHeader
366
+ <div className="flex h-full min-h-0 flex-col md:gap-6">
367
+ {!isMobile ? <PageHeader
370
368
  headingLevel={1}
371
369
  title={t("inboxTitle")}
372
370
  className="px-4 sm:px-0"
373
- />
371
+ /> : null}
374
372
 
375
- <div className="min-h-0 flex-1 overflow-hidden border-y border-border/60 bg-background sm:rounded-2xl sm:border">
373
+ <div className="min-h-0 flex-1 overflow-hidden bg-background md:rounded-2xl md:border md:border-border/60">
376
374
  {deliveriesQuery.isError ? (
377
375
  <div role="alert" className="p-6 text-sm text-destructive">{t("inboxLoadError")}</div>
378
376
  ) : (
@@ -386,10 +384,8 @@ export function InboxPage() {
386
384
  {showDetail ? <InboxDetailPane
387
385
  delivery={activeDelivery}
388
386
  error={error}
389
- isMobile={isMobile}
390
387
  pending={pendingAction !== null}
391
388
  onArchiveToggle={toggleArchive}
392
- onBack={() => navigate("/inbox")}
393
389
  onContinue={continueInChat}
394
390
  onDelete={() => void deleteDelivery()}
395
391
  onReadToggle={toggleRead}
@@ -7,6 +7,7 @@ import {
7
7
  SelectValue,
8
8
  } from "@/shared/components/ui/select";
9
9
  import { Skeleton } from "@/shared/components/ui/skeleton";
10
+ import { Input } from "@/shared/components/ui/input";
10
11
  import { t } from "@/shared/lib/i18n";
11
12
  import { Loader2, PackageSearch } from "lucide-react";
12
13
  import type { Ref } from "react";
@@ -30,10 +31,10 @@ export function FilterPanel({
30
31
  }) {
31
32
  return (
32
33
  <div className="mb-4">
33
- <div className="flex items-center gap-3">
34
+ <div className="flex flex-wrap items-center gap-3">
34
35
  <div className="relative min-w-0 flex-1">
35
36
  <PackageSearch className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
36
- <input
37
+ <Input
37
38
  value={searchText}
38
39
  onChange={(event) => onSearchTextChange(event.target.value)}
39
40
  placeholder={searchPlaceholder}
@@ -52,7 +53,7 @@ export function FilterPanel({
52
53
  value={sort}
53
54
  onValueChange={(value) => onSortChange(value as MarketplaceSort)}
54
55
  >
55
- <SelectTrigger className="h-9 w-[150px] shrink-0 rounded-lg">
56
+ <SelectTrigger className="h-9 w-[110px] sm:w-[150px] shrink-0 rounded-lg">
56
57
  <SelectValue />
57
58
  </SelectTrigger>
58
59
  <SelectContent>
@@ -142,12 +142,12 @@ export function MarketplacePage({
142
142
  <PageLayout className="flex h-full min-h-0 flex-col pb-0">
143
143
  {!curatedSceneRoute.isSceneRoute && (
144
144
  <>
145
- <div className="mb-3 flex items-start justify-between gap-3 border-b border-gray-200/60">
145
+ <div className="mb-3 flex flex-wrap items-start justify-between gap-3 border-b border-border/60">
146
146
  <Tabs
147
147
  value={scope}
148
148
  onValueChange={(value) => setScope(value as ScopeType)}
149
149
  >
150
- <TabsList className="mb-0 h-auto flex-1 justify-start gap-6 rounded-none border-b-0 bg-transparent p-0 text-gray-500">
150
+ <TabsList className="mb-0 h-auto flex-1 justify-start gap-4 sm:gap-6 rounded-none border-b-0 bg-transparent p-0 text-muted-foreground">
151
151
  <TabsTrigger
152
152
  value="all"
153
153
  className="rounded-none border-b-2 border-transparent bg-transparent px-0 pb-3 pt-0 shadow-none hover:bg-transparent data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-gray-950 data-[state=active]:shadow-none"