@nextclaw/ui 0.15.2 → 0.15.4
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 +41 -0
- package/dist/assets/aiden0z-pptx-renderer.es-Bd99vut2.js +94 -0
- package/dist/assets/api-BOXOrpcJ.js +13 -0
- package/dist/assets/app-presenter-provider-CkHLbvZQ.js +106 -0
- package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
- package/dist/assets/appearance-settings-page-fLIJbx1C.js +1 -0
- package/dist/assets/{book-open-Ba2f7YiG.js → book-open-DWUjS6aW.js} +1 -1
- package/dist/assets/channels-list-page-CvCTJraa.js +8 -0
- package/dist/assets/chat-page-B42UUIFR.js +1 -0
- package/dist/assets/chunk-DseTPa7n.js +1 -0
- package/dist/assets/config-split-page-DBgt9S8b.js +1 -0
- package/dist/assets/confirm-dialog-GSXIvoRU.js +5 -0
- package/dist/assets/desktop-update-config-7bmNeWIC.js +1 -0
- package/dist/assets/dist-DC7f4TJH.js +41 -0
- package/dist/assets/doc-browser-CgdoLUT92.js +1 -0
- package/dist/assets/doc-browser-D0monHjG.js +1 -0
- package/dist/assets/doc-browser-context-CGwEOhBy.js +1 -0
- package/dist/assets/docx-preview-eFH9DRsS.js +20 -0
- package/dist/assets/download-DiP9zx-J.js +1 -0
- package/dist/assets/{external-link-DxuPaDoK.js → external-link-C6ZeSPef.js} +1 -1
- package/dist/assets/eye-suvKmtwn.js +1 -0
- package/dist/assets/folder-CMELbQGG.js +1 -0
- package/dist/assets/{form-actions-BztL7P_T.js → form-actions-CUAzpNe_.js} +1 -1
- package/dist/assets/index-BFeNDQ4R.css +1 -0
- package/dist/assets/index-D_6U-M94.js +2 -0
- package/dist/assets/jszip.min-Das2IAnb.js +2 -0
- package/dist/assets/loader-circle-tYHStefV.js +1 -0
- package/dist/assets/logo-badge-Cu5UGH_4.js +1 -0
- package/dist/assets/mcp-marketplace-page-BUzHDwW6.js +9 -0
- package/dist/assets/mcp-marketplace-page-ohUAdfqJ.js +1 -0
- package/dist/assets/model-config-page-CWP6pyBm.js +1 -0
- package/dist/assets/plus-tywizkeY.js +1 -0
- package/dist/assets/popover-DImguRok.js +1 -0
- package/dist/assets/provider-models-C_yOh6DE.js +1 -0
- package/dist/assets/provider-scoped-model-input-CE7p4SbJ.js +1 -0
- package/dist/assets/providers-config-page-BKPo8SjH.js +1 -0
- package/dist/assets/react-5sjAT_6d.js +8 -0
- package/dist/assets/{refresh-cw-eT8BF-8B.js → refresh-cw-CHLBzWWj.js} +1 -1
- package/dist/assets/remote-DXJryUxB.js +1 -0
- package/dist/assets/rotate-cw-BefO5brU.js +1 -0
- package/dist/assets/runtime-config-page-1Axv4QGu.js +1 -0
- package/dist/assets/{save-Cb2g0BOi.js → save-BABzyrjB.js} +1 -1
- package/dist/assets/{search-BcHjwdsb.js → search-BTqxG3ZG.js} +1 -1
- package/dist/assets/search-config-page-BkKKmxmS.js +1 -0
- package/dist/assets/secrets-config-page-CWJMyu-k.js +3 -0
- package/dist/assets/security-config-DeQUIXfi.js +1 -0
- package/dist/assets/select-TYZDBNmq.js +1 -0
- package/dist/assets/setting-row-DR23Z_5I.js +1 -0
- package/dist/assets/{settings-2-2DWauOjY.js → settings-2-D8WWcBnw.js} +1 -1
- package/dist/assets/{skeleton-P5oM14E1.js → skeleton-CloHeg0S.js} +1 -1
- package/dist/assets/tabs-CX-ckWoo.js +1 -0
- package/dist/assets/tag-chip-mCc23Rhb.js +1 -0
- package/dist/assets/trash-2-SAW1Z4Po.js +1 -0
- package/dist/assets/use-config-BucdaK23.js +1 -0
- package/dist/assets/use-confirm-dialog-C95F6sT1.js +1 -0
- package/dist/assets/use-viewport-layout-C6m3Nte7.js +1 -0
- package/dist/assets/x-DtCPHwCu.js +1 -0
- package/dist/assets/xlsx-B6zVt1RK.js +64 -0
- package/dist/index.html +34 -28
- package/package.json +14 -9
- package/src/app/components/layout/sidebar-items.tsx +3 -3
- package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
- package/src/app/components/layout/sidebar.tsx +1 -1
- package/src/app/styles/design-system.css +17 -4
- package/src/features/chat/components/__tests__/chat-popover-content.test.tsx +41 -0
- package/src/features/chat/components/chat-popover-content.tsx +26 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +13 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +21 -11
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +2 -2
- package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +28 -1
- package/src/features/chat/components/conversation/chat-conversation-content.tsx +5 -4
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +9 -18
- package/src/features/chat/components/conversation/chat-conversation-track.tsx +35 -0
- package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +1 -0
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +7 -7
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +4 -15
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +20 -1
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +69 -54
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +62 -1
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +63 -2
- package/src/features/chat/features/message/utils/__tests__/chat-message-file-operation.utils.test.ts +30 -0
- package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +11 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +23 -0
- package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +5 -0
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +138 -0
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +37 -0
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -4
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +3 -8
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +65 -20
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +26 -28
- package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
- package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +5 -5
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +4 -4
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +4 -4
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +463 -99
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +113 -2
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +1 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +197 -44
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +11 -5
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +8 -6
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +99 -67
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +239 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +56 -6
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +29 -7
- package/src/features/chat/features/workspace/components/file-content-preview/use-workspace-file-buffer.ts +42 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-document-preview-state.tsx +18 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-docx-preview.css +89 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-docx-preview.tsx +87 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-presentation-preview.tsx +82 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-spreadsheet-preview.tsx +180 -0
- package/src/features/chat/features/workspace/components/workspace-file-content-preview.tsx +191 -0
- package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +1 -4
- package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +53 -10
- package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +68 -2
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +21 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +63 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-viewer.utils.ts +49 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils.ts +13 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +120 -38
- package/src/features/chat/index.ts +1 -0
- package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +76 -0
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +44 -60
- package/src/features/chat/managers/chat-thread.manager.ts +123 -124
- package/src/features/chat/pages/ncp-chat-page.tsx +1 -2
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +78 -1
- package/src/features/chat/stores/chat-message-layout.store.test.ts +37 -0
- package/src/features/chat/stores/chat-message-layout.store.ts +41 -0
- package/src/features/chat/stores/chat-thread.store.ts +73 -13
- package/src/features/cron/components/cron-config.tsx +63 -80
- package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +44 -6
- package/src/features/marketplace/components/marketplace-detail-doc.tsx +8 -4
- package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
- package/src/features/marketplace/hooks/use-marketplace-detail-doc-entry.ts +84 -0
- package/src/features/panel-apps/components/panel-apps-list.tsx +2 -2
- package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
- package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +25 -8
- package/src/features/settings/pages/appearance-settings-page.tsx +92 -13
- package/src/features/side-dock/components/side-dock.tsx +3 -3
- package/src/index.css +275 -15
- package/src/shared/components/__tests__/file-type-icon.test.tsx +61 -0
- package/src/shared/components/actions/action-link.tsx +1 -1
- package/src/shared/components/doc-browser/__tests__/doc-browser-context.test.tsx +19 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +16 -0
- package/src/shared/components/doc-browser/doc-browser-context.tsx +1 -0
- package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +1 -1
- package/src/shared/components/doc-browser/doc-browser.tsx +11 -3
- package/src/shared/components/doc-browser/managers/doc-browser.manager.ts +5 -0
- package/src/shared/components/doc-browser/stores/doc-browser.store.ts +6 -1
- package/src/shared/components/doc-browser/types/doc-browser.types.ts +2 -0
- package/src/shared/components/doc-browser/utils/doc-browser-state.utils.ts +11 -0
- package/src/shared/components/file-type-icon.tsx +272 -0
- package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +22 -0
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +17 -2
- package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
- package/src/shared/components/ui/button.tsx +1 -1
- package/src/shared/components/ui/dialog.tsx +1 -1
- package/src/shared/components/ui/input.tsx +1 -1
- package/src/shared/components/ui/select.tsx +1 -1
- package/src/shared/components/ui/switch.tsx +1 -1
- package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +38 -0
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +82 -2
- package/src/shared/components/ui/tabs.tsx +1 -1
- package/src/shared/components/ui/textarea.tsx +1 -1
- package/src/shared/lib/api/__tests__/server-path.utils.test.ts +28 -0
- package/src/shared/lib/api/utils/server-path.utils.ts +19 -20
- package/src/shared/lib/i18n/locales/en-US/chat.json +99 -0
- package/src/shared/lib/i18n/locales/en-US/core.json +6 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +99 -0
- package/src/shared/lib/i18n/locales/zh-CN/core.json +6 -0
- package/dist/assets/api-B7Qigvtm.js +0 -13
- package/dist/assets/appearance-settings-page-CuE0Iiqj.js +0 -1
- package/dist/assets/channels-list-page-CTsM6TcP.js +0 -8
- package/dist/assets/chat-page-C_5dcuE3.js +0 -1
- package/dist/assets/config-split-page-Fbb4PtTf.js +0 -1
- package/dist/assets/confirm-dialog-D2EG3nqE.js +0 -5
- package/dist/assets/desktop-update-config-BGR3HUi1.js +0 -1
- package/dist/assets/dist-7JTjycxE.js +0 -1
- package/dist/assets/dist-wXLhk4hl.js +0 -1
- package/dist/assets/doc-browser-bHyXnxlj.js +0 -1
- package/dist/assets/doc-browser-context-CYAGm5d5.js +0 -1
- package/dist/assets/doc-browser-gTrQ3jCF.js +0 -1
- package/dist/assets/es2015-j1SRCIX5.js +0 -41
- package/dist/assets/i18n-provider-B4oMxOFx.js +0 -1
- package/dist/assets/index-CvrvblgX.css +0 -1
- package/dist/assets/index-Obd4JYU2.js +0 -104
- package/dist/assets/loader-circle-CdzgK4eH.js +0 -1
- package/dist/assets/mcp-marketplace-page-Bt7CuOoq.js +0 -9
- package/dist/assets/mcp-marketplace-page-Ck3t78_n.js +0 -1
- package/dist/assets/model-config-page-DeKk9gvE.js +0 -1
- package/dist/assets/plus-Bx7wQbhG.js +0 -1
- package/dist/assets/provider-scoped-model-input-DsH2LF1q.js +0 -1
- package/dist/assets/providers-config-page-BFnGp68F.js +0 -1
- package/dist/assets/react-UirzUuST.js +0 -8
- package/dist/assets/remote-CDkHZtA8.js +0 -1
- package/dist/assets/rotate-cw-1JqxHTuw.js +0 -1
- package/dist/assets/runtime-config-page-BelAqiNG.js +0 -1
- package/dist/assets/search-config-page-zPm6--Ig.js +0 -1
- package/dist/assets/secrets-config-page-Cxyp-KuQ.js +0 -3
- package/dist/assets/security-config-B_gCq9fn.js +0 -1
- package/dist/assets/select-CdSEOwVM.js +0 -1
- package/dist/assets/setting-row-CTAtGexr.js +0 -1
- package/dist/assets/side-dock-DPvakJ0a.js +0 -3
- package/dist/assets/switch-BU_UEULb.js +0 -1
- package/dist/assets/tag-chip-D-WsKoT1.js +0 -1
- package/dist/assets/tooltip-CjkOaHW7.js +0 -1
- package/dist/assets/use-config--hx5oxQn.js +0 -1
- package/dist/assets/use-confirm-dialog-CD9a_SK1.js +0 -1
- package/dist/assets/x-DT5x45JU.js +0 -1
- /package/dist/assets/{config-hints-C_iP1zl_.js → config-hints-fDrYfl0l.js} +0 -0
- /package/dist/assets/{host-capabilities-9bB_998Z.js → host-capabilities-zZvY9U63.js} +0 -0
- /package/dist/assets/{middleware-BILWbJE4.js → middleware-BLMHv9YF.js} +0 -0
|
@@ -8,9 +8,9 @@ import type {
|
|
|
8
8
|
import { Skeleton } from '@/shared/components/ui/skeleton';
|
|
9
9
|
import { t } from '@/shared/lib/i18n';
|
|
10
10
|
import { cn } from '@/shared/lib/utils';
|
|
11
|
+
import { useMarketplaceDetailDocEntry } from '@/features/marketplace/hooks/use-marketplace-detail-doc-entry';
|
|
11
12
|
import {
|
|
12
13
|
setMarketplaceDetailDocEntry,
|
|
13
|
-
useMarketplaceDetailDocStore,
|
|
14
14
|
type MarketplaceDetailDocEntry,
|
|
15
15
|
} from '@/features/marketplace/stores/marketplace-detail-doc.store';
|
|
16
16
|
|
|
@@ -422,13 +422,17 @@ function MarketplaceDetailDocContent({ entry }: { entry: MarketplaceDetailDocEnt
|
|
|
422
422
|
|
|
423
423
|
function MarketplaceDetailDoc({ currentUrl }: { currentUrl: string }) {
|
|
424
424
|
const detailId = readMarketplaceDetailDocId(currentUrl);
|
|
425
|
-
const entry =
|
|
426
|
-
|
|
425
|
+
const entry = useMarketplaceDetailDocEntry(detailId);
|
|
426
|
+
|
|
427
|
+
if (!detailId) {
|
|
427
428
|
return <MarketplaceDetailUnavailable />;
|
|
428
429
|
}
|
|
429
|
-
if (entry.status === 'loading') {
|
|
430
|
+
if (!entry || entry.status === 'loading') {
|
|
430
431
|
return <MarketplaceDetailSkeleton />;
|
|
431
432
|
}
|
|
433
|
+
if (entry.status === 'error' && !entry.contentRaw) {
|
|
434
|
+
return <MarketplaceDetailUnavailable />;
|
|
435
|
+
}
|
|
432
436
|
return <MarketplaceDetailDocContent entry={entry} />;
|
|
433
437
|
}
|
|
434
438
|
|
|
@@ -37,7 +37,7 @@ export function FilterPanel({
|
|
|
37
37
|
value={searchText}
|
|
38
38
|
onChange={(event) => onSearchTextChange(event.target.value)}
|
|
39
39
|
placeholder={searchPlaceholder}
|
|
40
|
-
className="h-9 w-full rounded-xl border border-
|
|
40
|
+
className="h-9 w-full rounded-xl border border-border/75 bg-card pl-9 pr-9 text-sm transition-colors focus:outline-none focus:ring-0 focus:border-border"
|
|
41
41
|
/>
|
|
42
42
|
{isRefreshing && (
|
|
43
43
|
<Loader2
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { fetchMarketplaceSkillContent } from '@/shared/lib/api';
|
|
3
|
+
import { t } from '@/shared/lib/i18n';
|
|
4
|
+
import {
|
|
5
|
+
setMarketplaceDetailDocEntry,
|
|
6
|
+
useMarketplaceDetailDocStore,
|
|
7
|
+
} from '@/features/marketplace/stores/marketplace-detail-doc.store';
|
|
8
|
+
|
|
9
|
+
function parseMarketplaceDetailScopeKey(
|
|
10
|
+
detailId: string,
|
|
11
|
+
): { scope: string; key: string } | null {
|
|
12
|
+
const separator = detailId.indexOf(':');
|
|
13
|
+
if (separator <= 0 || separator >= detailId.length - 1) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
scope: detailId.slice(0, separator),
|
|
18
|
+
key: detailId.slice(separator + 1),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isRehydratableSkillScope(scope: string): boolean {
|
|
23
|
+
return scope === 'skill' || scope === 'skill-preview';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function useMarketplaceDetailDocEntry(detailId: string | null) {
|
|
27
|
+
const entry = useMarketplaceDetailDocStore((state) =>
|
|
28
|
+
detailId ? state.entries[detailId] : undefined,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!detailId || useMarketplaceDetailDocStore.getState().entries[detailId]) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const parsed = parseMarketplaceDetailScopeKey(detailId);
|
|
36
|
+
if (!parsed || !isRehydratableSkillScope(parsed.scope)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
const title = parsed.key;
|
|
42
|
+
const typeLabel = t('marketplaceTypeSkill');
|
|
43
|
+
|
|
44
|
+
void fetchMarketplaceSkillContent(parsed.key)
|
|
45
|
+
.then((content) => {
|
|
46
|
+
if (cancelled) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
setMarketplaceDetailDocEntry({
|
|
50
|
+
id: detailId,
|
|
51
|
+
title,
|
|
52
|
+
typeLabel,
|
|
53
|
+
spec: parsed.key,
|
|
54
|
+
status: 'ready',
|
|
55
|
+
summary: t('marketplaceInstalledLocalSummary'),
|
|
56
|
+
metadataRaw: content.metadataRaw,
|
|
57
|
+
contentRaw: content.bodyRaw || content.raw,
|
|
58
|
+
sourceUrl: content.sourceUrl,
|
|
59
|
+
sourceLabel: content.source ? `Source (${content.source})` : undefined,
|
|
60
|
+
});
|
|
61
|
+
})
|
|
62
|
+
.catch(() => {
|
|
63
|
+
if (cancelled) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
setMarketplaceDetailDocEntry({
|
|
67
|
+
id: detailId,
|
|
68
|
+
title,
|
|
69
|
+
typeLabel,
|
|
70
|
+
spec: parsed.key,
|
|
71
|
+
status: 'error',
|
|
72
|
+
summary: t('marketplaceInstalledLocalSummary'),
|
|
73
|
+
metadataRaw: JSON.stringify({ skill: parsed.key }, null, 2),
|
|
74
|
+
contentRaw: t('marketplaceDetailUnavailableDescription'),
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return () => {
|
|
79
|
+
cancelled = true;
|
|
80
|
+
};
|
|
81
|
+
}, [detailId]);
|
|
82
|
+
|
|
83
|
+
return entry;
|
|
84
|
+
}
|
|
@@ -204,7 +204,7 @@ function PanelAppsEmptyGuide({
|
|
|
204
204
|
<button
|
|
205
205
|
type="button"
|
|
206
206
|
onClick={onRefresh}
|
|
207
|
-
className="mt-4 inline-flex items-center justify-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-
|
|
207
|
+
className="mt-4 inline-flex items-center justify-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
|
|
208
208
|
>
|
|
209
209
|
<RefreshCw className="h-3.5 w-3.5" />
|
|
210
210
|
{t('panelAppsRefresh')}
|
|
@@ -245,7 +245,7 @@ function PanelAppsEmptyGuideStep({
|
|
|
245
245
|
<button
|
|
246
246
|
type="button"
|
|
247
247
|
onClick={onAction}
|
|
248
|
-
className="flex w-full gap-2 rounded-md bg-muted/60 px-3 py-2.5 text-left transition-colors hover:bg-accent/70 focus-visible:outline-none focus-visible:ring-
|
|
248
|
+
className="flex w-full gap-2 rounded-md bg-muted/60 px-3 py-2.5 text-left transition-colors hover:bg-accent/70 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
|
|
249
249
|
>
|
|
250
250
|
{content}
|
|
251
251
|
</button>
|
|
@@ -80,7 +80,7 @@ export function RightPanelResourceHomePage({ open }: RightPanelResourceHomePageP
|
|
|
80
80
|
key={item.id}
|
|
81
81
|
type="button"
|
|
82
82
|
onClick={() => openTarget(item.target)}
|
|
83
|
-
className="group flex min-h-[68px] flex-col items-center gap-1.5 rounded-md px-1.5 py-1.5 text-center focus-visible:outline-none focus-visible:ring-
|
|
83
|
+
className="group flex min-h-[68px] flex-col items-center gap-1.5 rounded-md px-1.5 py-1.5 text-center focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
|
|
84
84
|
>
|
|
85
85
|
<span className={cn('flex h-10 w-10 shrink-0 items-center justify-center rounded-md transition-colors', view.accentClassName, view.hoverAccentClassName)}>
|
|
86
86
|
{view.icon}
|
|
@@ -1,25 +1,42 @@
|
|
|
1
|
-
import { fireEvent, render, screen } from
|
|
2
|
-
import { beforeEach, describe, expect, it } from
|
|
3
|
-
import { AppearanceSettingsPage } from
|
|
4
|
-
import {
|
|
1
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
2
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { AppearanceSettingsPage } from "@/features/settings/pages/appearance-settings-page";
|
|
4
|
+
import { useChatMessageLayoutStore } from "@/features/chat";
|
|
5
|
+
import { useSideDockStore } from "@/features/side-dock";
|
|
5
6
|
|
|
6
|
-
describe(
|
|
7
|
+
describe("AppearanceSettingsPage", () => {
|
|
7
8
|
beforeEach(() => {
|
|
8
9
|
window.localStorage.clear();
|
|
10
|
+
useChatMessageLayoutStore.getState().setLayout("card");
|
|
9
11
|
useSideDockStore.getState().setVisible(true);
|
|
10
12
|
useSideDockStore.getState().setPinnedItems([]);
|
|
11
13
|
});
|
|
12
14
|
|
|
13
|
-
it(
|
|
15
|
+
it("reopens the SideDock from the appearance settings switch", () => {
|
|
14
16
|
useSideDockStore.getState().setVisible(false);
|
|
15
17
|
|
|
16
18
|
render(<AppearanceSettingsPage />);
|
|
17
19
|
|
|
18
|
-
const visibilitySwitch = screen.getByRole(
|
|
19
|
-
|
|
20
|
+
const visibilitySwitch = screen.getByRole("switch", {
|
|
21
|
+
name: "Show SideDock",
|
|
22
|
+
});
|
|
23
|
+
expect(visibilitySwitch.getAttribute("aria-checked")).toBe("false");
|
|
20
24
|
|
|
21
25
|
fireEvent.click(visibilitySwitch);
|
|
22
26
|
|
|
23
27
|
expect(useSideDockStore.getState().isVisible).toBe(true);
|
|
24
28
|
});
|
|
29
|
+
|
|
30
|
+
it("switches the chat message layout from appearance settings", () => {
|
|
31
|
+
render(<AppearanceSettingsPage />);
|
|
32
|
+
|
|
33
|
+
const cardOption = screen.getByRole("radio", { name: /^Cards/ });
|
|
34
|
+
const flatOption = screen.getByRole("radio", { name: /^Flat/ });
|
|
35
|
+
expect(cardOption.getAttribute("aria-checked")).toBe("true");
|
|
36
|
+
|
|
37
|
+
fireEvent.click(flatOption);
|
|
38
|
+
|
|
39
|
+
expect(flatOption.getAttribute("aria-checked")).toBe("true");
|
|
40
|
+
expect(useChatMessageLayoutStore.getState().layout).toBe("flat");
|
|
41
|
+
});
|
|
25
42
|
});
|
|
@@ -1,33 +1,112 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
1
|
+
import type { ChatMessageLayout } from "@nextclaw/agent-chat-ui";
|
|
2
|
+
import { Check, Palette } from "lucide-react";
|
|
3
|
+
import { PageHeader, PageLayout } from "@/app/components/layout/page-layout";
|
|
4
|
+
import { useChatMessageLayoutStore } from "@/features/chat";
|
|
5
|
+
import { SettingRow } from "@/shared/components/settings/setting-row";
|
|
6
|
+
import {
|
|
7
|
+
Card,
|
|
8
|
+
CardContent,
|
|
9
|
+
CardHeader,
|
|
10
|
+
CardTitle,
|
|
11
|
+
} from "@/shared/components/ui/card";
|
|
12
|
+
import { Switch } from "@/shared/components/ui/switch";
|
|
13
|
+
import { useSideDockStore } from "@/features/side-dock";
|
|
14
|
+
import { t } from "@/shared/lib/i18n";
|
|
15
|
+
import { cn } from "@/shared/lib/utils";
|
|
16
|
+
|
|
17
|
+
const CHAT_MESSAGE_LAYOUT_OPTIONS: Array<{
|
|
18
|
+
value: ChatMessageLayout;
|
|
19
|
+
labelKey: string;
|
|
20
|
+
descriptionKey: string;
|
|
21
|
+
}> = [
|
|
22
|
+
{
|
|
23
|
+
value: "card",
|
|
24
|
+
labelKey: "chatMessageLayoutCard",
|
|
25
|
+
descriptionKey: "chatMessageLayoutCardDescription",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
value: "flat",
|
|
29
|
+
labelKey: "chatMessageLayoutFlat",
|
|
30
|
+
descriptionKey: "chatMessageLayoutFlatDescription",
|
|
31
|
+
},
|
|
32
|
+
];
|
|
8
33
|
|
|
9
34
|
export function AppearanceSettingsPage() {
|
|
35
|
+
const messageLayout = useChatMessageLayoutStore((state) => state.layout);
|
|
36
|
+
const setMessageLayout = useChatMessageLayoutStore(
|
|
37
|
+
(state) => state.setLayout,
|
|
38
|
+
);
|
|
10
39
|
const isSideDockVisible = useSideDockStore((state) => state.isVisible);
|
|
11
40
|
const setSideDockVisible = useSideDockStore((state) => state.setVisible);
|
|
12
41
|
|
|
13
42
|
return (
|
|
14
43
|
<PageLayout>
|
|
15
|
-
<PageHeader title={t(
|
|
44
|
+
<PageHeader title={t("appearance")} />
|
|
16
45
|
<Card>
|
|
17
46
|
<CardHeader>
|
|
18
47
|
<CardTitle className="flex items-center gap-2">
|
|
19
48
|
<Palette className="h-4 w-4" />
|
|
20
|
-
{t(
|
|
49
|
+
{t("appearance")}
|
|
21
50
|
</CardTitle>
|
|
22
51
|
</CardHeader>
|
|
23
|
-
<CardContent>
|
|
52
|
+
<CardContent className="space-y-4">
|
|
53
|
+
<SettingRow
|
|
54
|
+
title={t("chatMessageLayoutTitle")}
|
|
55
|
+
description={t("chatMessageLayoutDescription")}
|
|
56
|
+
>
|
|
57
|
+
<div
|
|
58
|
+
role="radiogroup"
|
|
59
|
+
aria-label={t("chatMessageLayoutTitle")}
|
|
60
|
+
className="grid gap-2 sm:grid-cols-2"
|
|
61
|
+
>
|
|
62
|
+
{CHAT_MESSAGE_LAYOUT_OPTIONS.map((option) => {
|
|
63
|
+
const selected = option.value === messageLayout;
|
|
64
|
+
return (
|
|
65
|
+
<button
|
|
66
|
+
key={option.value}
|
|
67
|
+
type="button"
|
|
68
|
+
role="radio"
|
|
69
|
+
aria-checked={selected}
|
|
70
|
+
onClick={() => setMessageLayout(option.value)}
|
|
71
|
+
className={cn(
|
|
72
|
+
"flex min-w-0 items-start gap-3 rounded-xl border px-3 py-3 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/35",
|
|
73
|
+
selected
|
|
74
|
+
? "border-primary/35 bg-primary/5 text-foreground"
|
|
75
|
+
: "border-border bg-card text-muted-foreground hover:border-border/80 hover:bg-muted/45 hover:text-foreground",
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
<span
|
|
79
|
+
className={cn(
|
|
80
|
+
"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border",
|
|
81
|
+
selected
|
|
82
|
+
? "border-primary bg-primary text-primary-foreground"
|
|
83
|
+
: "border-border bg-background",
|
|
84
|
+
)}
|
|
85
|
+
>
|
|
86
|
+
{selected ? (
|
|
87
|
+
<Check className="h-2.5 w-2.5" strokeWidth={3} />
|
|
88
|
+
) : null}
|
|
89
|
+
</span>
|
|
90
|
+
<span className="min-w-0">
|
|
91
|
+
<span className="block text-sm font-medium">
|
|
92
|
+
{t(option.labelKey)}
|
|
93
|
+
</span>
|
|
94
|
+
<span className="mt-1 block text-xs leading-5 text-muted-foreground">
|
|
95
|
+
{t(option.descriptionKey)}
|
|
96
|
+
</span>
|
|
97
|
+
</span>
|
|
98
|
+
</button>
|
|
99
|
+
);
|
|
100
|
+
})}
|
|
101
|
+
</div>
|
|
102
|
+
</SettingRow>
|
|
24
103
|
<SettingRow
|
|
25
|
-
title={t(
|
|
26
|
-
description={t(
|
|
104
|
+
title={t("sideDockVisibilityTitle")}
|
|
105
|
+
description={t("sideDockVisibilityDescription")}
|
|
27
106
|
control={
|
|
28
107
|
<Switch
|
|
29
108
|
id="appearance-side-dock-visible"
|
|
30
|
-
aria-label={t(
|
|
109
|
+
aria-label={t("sideDockVisibilityTitle")}
|
|
31
110
|
checked={isSideDockVisible}
|
|
32
111
|
onCheckedChange={setSideDockVisible}
|
|
33
112
|
/>
|
|
@@ -95,7 +95,7 @@ function SideDockButton({
|
|
|
95
95
|
onClick={() => onOpen(item)}
|
|
96
96
|
className={cn(
|
|
97
97
|
'flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors',
|
|
98
|
-
'hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-
|
|
98
|
+
'hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
|
|
99
99
|
active
|
|
100
100
|
? 'bg-primary/10 text-primary'
|
|
101
101
|
: 'bg-transparent',
|
|
@@ -113,7 +113,7 @@ function SideDockButton({
|
|
|
113
113
|
event.stopPropagation();
|
|
114
114
|
onUnpin(item);
|
|
115
115
|
}}
|
|
116
|
-
className="absolute -right-1 -top-1 hidden h-4 w-4 items-center justify-center rounded-full bg-background text-muted-foreground shadow-sm ring-1 ring-border/70 transition-colors hover:bg-muted hover:text-foreground group-hover:flex focus-visible:flex focus-visible:outline-none focus-visible:ring-
|
|
116
|
+
className="absolute -right-1 -top-1 hidden h-4 w-4 items-center justify-center rounded-full bg-background text-muted-foreground shadow-sm ring-1 ring-border/70 transition-colors hover:bg-muted hover:text-foreground group-hover:flex focus-visible:flex focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
|
|
117
117
|
>
|
|
118
118
|
<X className="h-3 w-3" aria-hidden="true" />
|
|
119
119
|
</button>
|
|
@@ -144,7 +144,7 @@ function SideDockActionButton({
|
|
|
144
144
|
onClick={onClick}
|
|
145
145
|
className={cn(
|
|
146
146
|
'flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors',
|
|
147
|
-
'hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-
|
|
147
|
+
'hover:bg-primary/10 hover:text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border',
|
|
148
148
|
)}
|
|
149
149
|
>
|
|
150
150
|
<Icon className="h-5 w-5" aria-hidden="true" />
|