@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.
- package/CHANGELOG.md +15 -0
- package/dist/.vite/manifest.json +366 -365
- package/dist/assets/{account-panel-ZM2qzKF4.js → account-panel-DIdHjKG-.js} +1 -1
- package/dist/assets/{api-Cjq-o1VN.js → api-DkLJrSCd.js} +2 -2
- package/dist/assets/app-presenter-provider-Co8uKOyW.js +124 -0
- package/dist/assets/{appearance-settings-page-B4zouKzg.js → appearance-settings-page-DI8aDY2G.js} +1 -1
- package/dist/assets/{book-open-AteA89HX.js → book-open-BPMkKSci.js} +1 -1
- package/dist/assets/{card-BLXvBstA.js → card-Bqu8zWLq.js} +1 -1
- package/dist/assets/{channels-list-page-fj8kMo-T.js → channels-list-page-CCIaTQu7.js} +1 -1
- package/dist/assets/{circle-dashed-LSYZTzM7.js → circle-dashed-B48a0t6p.js} +1 -1
- package/dist/assets/{client-DudCRJw4.js → client-imrVphQb.js} +1 -1
- package/dist/assets/{config-split-page-G7Kt2BnV.js → config-split-page-Bd-bGKsw.js} +1 -1
- package/dist/assets/{confirm-dialog-DShT64F6.js → confirm-dialog-10Qb3dpZ.js} +1 -1
- package/dist/assets/context-menu-CRqH2SEk.js +1 -0
- package/dist/assets/{createLucideIcon-D7hvIHV-.js → createLucideIcon-B4xj2I2g.js} +1 -1
- package/dist/assets/{desktop-capabilities-page-CzqzFZUY.js → desktop-capabilities-page-CFcT2g8-.js} +1 -1
- package/dist/assets/{desktop-update-config-CgeQ0Ffo.js → desktop-update-config-CRJd_An1.js} +1 -1
- package/dist/assets/{dialog-C7glmAQJ.js → dialog-BgL3vKJQ.js} +2 -2
- package/dist/assets/doc-browser-52t2_rSF.js +1 -0
- package/dist/assets/{doc-browser-context-BlhBAOLH.js → doc-browser-context-DH4aWvkS.js} +1 -1
- package/dist/assets/{download-BYgECE0n.js → download-Cr337h4W.js} +1 -1
- package/dist/assets/{es2015-CsjAAQ6X.js → es2015-D-CRf3_Z.js} +1 -1
- package/dist/assets/{extensions-qYL-NpL3.js → extensions-CsmJPz7g.js} +1 -1
- package/dist/assets/{eye-BBuTzJ53.js → eye-DrQRSAfJ.js} +1 -1
- package/dist/assets/{form-actions-CLGWO52v.js → form-actions-BEeWTGUZ.js} +1 -1
- package/dist/assets/{i18n-qBGEbcW6.js → i18n-OGmF0Ws_.js} +2 -2
- package/dist/assets/{keyboard-shortcuts-settings-page-B-wK_6zG.js → keyboard-shortcuts-settings-page-DQU56SrW.js} +1 -1
- package/dist/assets/loader-circle-DbOQWT9C.js +1 -0
- package/dist/assets/login-page-DW1AZXqX.js +1 -0
- package/dist/assets/{login-page-Cd84lpVV.js → login-page-sgivRYG1.js} +1 -1
- package/dist/assets/main-B-oxUq-o.js +2 -0
- package/dist/assets/main-BpL6OjwM.css +1 -0
- package/dist/assets/main-i18n-catalog.config-Bpu5GcwF.js +1 -0
- package/dist/assets/mcp-marketplace-page-DSLRpJEB.js +1 -0
- package/dist/assets/{model-config-page-D0DQlSDa.js → model-config-page-CDQBhmVr.js} +1 -1
- package/dist/assets/{navigation-link-32iM1-e6.js → navigation-link-D3pzNHeA.js} +1 -1
- package/dist/assets/panel-app-BYfQu_TS.js +1 -0
- package/dist/assets/panel-app-i18n-catalog.config-D44qmtfk.js +1 -0
- package/dist/assets/{panelStandalone-C9EKaApN.js → panelStandalone-CGkYeMK5.js} +2 -2
- package/dist/assets/panelStandalone-D-mhAGNa.css +1 -0
- package/dist/assets/{privacy-settings-page-Bxxx12OO.js → privacy-settings-page-CjoAkoDt.js} +1 -1
- package/dist/assets/projects-C7Zxpcoi.js +1 -0
- package/dist/assets/{provider-models-C3frdXeW.js → provider-models-YW7rIeOD.js} +1 -1
- package/dist/assets/{provider-scoped-model-input-CYetrPYZ.js → provider-scoped-model-input-axJ-pTEu.js} +1 -1
- package/dist/assets/{providers-config-page-DESB1h8g.js → providers-config-page-_QhBXQ4M.js} +1 -1
- package/dist/assets/{puzzle-CWHfFyYN.js → puzzle--RLCeYML.js} +1 -1
- package/dist/assets/{pwa-CiGUjpcd.js → pwa-DcizGowz.js} +1 -1
- package/dist/assets/{refresh-cw-y3L6PyLt.js → refresh-cw-syCVj_nw.js} +1 -1
- package/dist/assets/remote-BLQU7aY5.js +1 -0
- package/dist/assets/{rotate-cw-CNE9qSHi.js → rotate-cw-BlH9El3x.js} +1 -1
- package/dist/assets/{runtime-config-page-5o98T-TD.js → runtime-config-page-Cco9dS73.js} +1 -1
- package/dist/assets/{save-B0p5a0ET.js → save-BWynuRQ2.js} +1 -1
- package/dist/assets/{search-config-page-CpGcnIzi.js → search-config-page-Cc74_SAU.js} +1 -1
- package/dist/assets/{secrets-config-page-C4VTiW3r.js → secrets-config-page-raYDzlFC.js} +1 -1
- package/dist/assets/security-config-aE_jOwy-.js +1 -0
- package/dist/assets/{select-CctTN205.js → select-6Uq4chZW.js} +1 -1
- package/dist/assets/{service-apps-panel-CKE5HKNY.js → service-apps-panel-jBWAa4qZ.js} +1 -1
- package/dist/assets/{settings-2-EPflrNk6.js → settings-2-COvVf1XX.js} +1 -1
- package/dist/assets/{status-dot-CensgJZC.js → status-dot-DZlxa5zW.js} +1 -1
- package/dist/assets/{tag-chip-Bjzb4-qW.js → tag-chip-DXHtZ8AS.js} +1 -1
- package/dist/assets/{theme-provider-hlle7Skk.js → theme-provider-C5PCDBPB.js} +1 -1
- package/dist/assets/{trash-2-C5KH5Rw9.js → trash-2-DazgBvmJ.js} +1 -1
- package/dist/assets/{use-config-CPl_F79t.js → use-config-DRRGF9Zb.js} +1 -1
- package/dist/assets/{use-desktop-capabilities-CEg9-DrQ.js → use-desktop-capabilities-CdfOUjdE.js} +1 -1
- package/dist/assets/{use-viewport-layout-CPZUmTPi.js → use-viewport-layout-DdxVnCYc.js} +1 -1
- package/dist/assets/x-CQIp_nJT.js +1 -0
- package/dist/index.html +34 -34
- package/dist/panel-standalone.html +11 -11
- package/package.json +3 -3
- package/src/app/components/layout/page-layout.tsx +5 -2
- package/src/app/configs/__tests__/app-navigation.config.test.ts +10 -0
- package/src/app/configs/app-navigation.config.ts +6 -2
- package/src/app/styles/charcoal-theme.css +1 -1
- package/src/app/styles/design-system.css +8 -2
- package/src/app/styles/island-theme.css +1 -1
- package/src/features/agents/components/agent-details-dialog.tsx +1 -1
- package/src/features/agents/components/agents-page.tsx +5 -3
- package/src/features/apps/components/app-package-card.tsx +7 -6
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -3
- package/src/features/chat/components/conversation/chat-conversation-header.tsx +4 -4
- package/src/features/chat/components/layout/chat-page-shell.tsx +1 -1
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +12 -5
- package/src/features/chat/features/session/components/chat-mobile-session-row.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +1 -1
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +3 -5
- package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +4 -3
- package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +1 -1
- package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +3 -1
- package/src/features/cron/components/cron-config.tsx +1 -0
- package/src/features/cron/components/cron-job-row.tsx +4 -4
- package/src/features/inbox/components/inbox-delivery-content.tsx +1 -1
- package/src/features/inbox/pages/inbox-page.tsx +24 -28
- package/src/features/marketplace/components/marketplace-page-parts.tsx +4 -3
- package/src/features/marketplace/components/marketplace-page.tsx +2 -2
- package/src/features/panel-apps/components/panel-app-open-standalone-menu-item.tsx +3 -1
- package/src/features/projects/components/project-overview.tsx +1 -1
- package/src/features/projects/pages/project-home-page.tsx +11 -2
- package/src/features/projects/pages/projects-page.test.tsx +4 -2
- package/src/platforms/mobile/components/mobile-app-shell.tsx +1 -1
- package/src/platforms/mobile/components/mobile-bottom-nav.tsx +8 -7
- package/src/platforms/mobile/components/mobile-settings-shell.tsx +24 -23
- package/src/platforms/mobile/components/mobile-topbar.tsx +10 -11
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +34 -2
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +36 -5
- package/src/shared/components/doc-browser/doc-browser.tsx +5 -1
- package/src/shared/components/settings/settings-page.tsx +1 -1
- package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +5 -5
- package/src/shared/components/ui/actions/action-feedback.ts +8 -0
- package/src/shared/components/ui/actions/icon-action-button.tsx +13 -12
- package/src/shared/components/ui/button.tsx +1 -1
- package/src/shared/components/ui/context-menu/context-menu-items.tsx +4 -3
- package/src/shared/components/ui/dialog.tsx +4 -3
- package/src/shared/components/ui/input.tsx +1 -0
- package/src/shared/components/ui/select.tsx +2 -1
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +5 -3
- package/src/shared/components/ui/tabs.tsx +2 -2
- package/src/shared/components/ui/textarea.tsx +1 -0
- package/src/shared/components/workbench/workbench-surface-toolbar.tsx +3 -4
- package/src/shared/components/workbench/workbench-surface.tsx +2 -2
- package/src/shared/lib/i18n/locales/en-US/agents.json +2 -0
- package/src/shared/lib/i18n/locales/en-US/core.json +1 -0
- package/src/shared/lib/i18n/locales/en-US/desktop-update.json +1 -1
- package/src/shared/lib/i18n/locales/zh-CN/agents.json +2 -0
- package/src/shared/lib/i18n/locales/zh-CN/core.json +1 -0
- package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +1 -1
- package/dist/assets/app-presenter-provider-C02YPoMr.js +0 -124
- package/dist/assets/context-menu-rd7b_kVD.js +0 -1
- package/dist/assets/doc-browser-dBiR9Qi0.js +0 -1
- package/dist/assets/loader-circle-BA7EMkih.js +0 -1
- package/dist/assets/login-page-VdMyNkFf.js +0 -1
- package/dist/assets/main-CR0SrTBf.js +0 -2
- package/dist/assets/main-DXH6EdXI.css +0 -1
- package/dist/assets/main-i18n-catalog.config-Btp_OowF.js +0 -1
- package/dist/assets/mcp-marketplace-page-jacRwiI-.js +0 -1
- package/dist/assets/panel-app-CC0bVSu4.js +0 -1
- package/dist/assets/panel-app-i18n-catalog.config-LUSBp5Ce.js +0 -1
- package/dist/assets/panelStandalone-Y91OJkgV.css +0 -1
- package/dist/assets/projects-D56yAPNT.js +0 -1
- package/dist/assets/remote-DiGFV8nP.js +0 -1
- package/dist/assets/security-config-C5-RQVpS.js +0 -1
- 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(--
|
|
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(
|
|
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(--
|
|
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(
|
|
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
|
-
|
|
101
|
+
ACTION_MENU_ITEM_CLASS,
|
|
101
102
|
destructive
|
|
102
|
-
?
|
|
103
|
-
:
|
|
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
|
-
|
|
318
|
-
destructive ?
|
|
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
|
-
<
|
|
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
|
-
</
|
|
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-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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-
|
|
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')}
|
|
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')}
|
|
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}
|
|
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-
|
|
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
|
});
|
package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx
CHANGED
|
@@ -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
|
-
<
|
|
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
|
-
</
|
|
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
|
-
|
|
24
|
+
ACTION_MENU_ITEM_CLASS,
|
|
24
25
|
destructive
|
|
25
|
-
?
|
|
26
|
-
:
|
|
26
|
+
? ACTION_FEEDBACK.destructive
|
|
27
|
+
: `text-foreground ${ACTION_FEEDBACK.item}`
|
|
27
28
|
)}
|
|
28
29
|
onClick={onClick}
|
|
29
30
|
disabled={disabled}
|
package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx
CHANGED
|
@@ -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-
|
|
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
|
}
|
|
@@ -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
|
|
@@ -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,
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
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
|
-
<
|
|
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-
|
|
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-
|
|
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"
|