@geminilight/mindos 0.6.57 → 0.6.59
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/_standalone/.mindos-build-version +1 -1
- package/_standalone/.next/BUILD_ID +1 -1
- package/_standalone/.next/app-path-routes-manifest.json +24 -24
- package/_standalone/.next/build-manifest.json +3 -3
- package/_standalone/.next/cache/.previewinfo +1 -1
- package/_standalone/.next/cache/.rscinfo +1 -1
- package/_standalone/.next/cache/config.json +3 -3
- package/_standalone/.next/prerender-manifest.json +3 -3
- package/_standalone/.next/react-loadable-manifest.json +1 -1
- package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error.html +2 -2
- package/_standalone/.next/server/app/_global-error.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/_standalone/.next/server/app/_not-found/page.js +1 -1
- package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page.js +2 -2
- package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/page.js +2 -2
- package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/config/route.js +1 -1
- package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/detect/route.js +1 -1
- package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/detect/route.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/route.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask/route.js +5 -5
- package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/raw/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/status/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/reset-token/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/test-key/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/route.js +1 -1
- package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/skills/route.js +1 -1
- package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/changes/page.js +2 -2
- package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page.js +3 -3
- package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/echo/page.js +1 -1
- package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/explore/page.js +3 -3
- package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/help/page.js +2 -2
- package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/inbox/history/page.js +1 -1
- package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/login/page.js +2 -2
- package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/page.js +2 -8
- package/_standalone/.next/server/app/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/setup/page.js +2 -2
- package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/trash/page.js +3 -3
- package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/view/[...path]/page.js +3 -3
- package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/wiki/page.js +2 -2
- package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app-paths-manifest.json +24 -24
- package/_standalone/.next/server/chunks/1550.js +1 -1
- package/_standalone/.next/server/chunks/1750.js +1 -1
- package/_standalone/.next/server/chunks/3484.js +1 -1
- package/_standalone/.next/server/chunks/530.js +61 -62
- package/_standalone/.next/server/chunks/6539.js +1 -1
- package/_standalone/.next/server/chunks/{2159.js → 8343.js} +2 -2
- package/_standalone/.next/server/chunks/9787.js +2 -0
- package/_standalone/.next/server/middleware-build-manifest.js +1 -1
- package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/_standalone/.next/server/pages/500.html +2 -2
- package/_standalone/.next/server/server-reference-manifest.js +1 -1
- package/_standalone/.next/server/server-reference-manifest.json +1 -1
- package/_standalone/.next/static/chunks/{1814.a7c127b2c73d1f70.js → 1814.a79b84d37df75c43.js} +1 -1
- package/_standalone/.next/static/chunks/3427-2e61a5df1f5e55fb.js +1 -0
- package/_standalone/.next/static/chunks/5581-dac72e9f16e5ea29.js +29 -0
- package/_standalone/.next/static/chunks/6297-085daa21037d5f81.js +1 -0
- package/_standalone/.next/static/chunks/7249-6cf8f2b78718c59e.js +11 -0
- package/_standalone/.next/static/chunks/8520-56ec9ff087c15204.js +22 -0
- package/_standalone/.next/static/chunks/9905-a19d379cb225246e.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/{page-7bdeab5af8e4f5f2.js → page-35ea6de1af2be3b5.js} +1 -1
- package/_standalone/.next/static/chunks/app/agents/page-b172ea3743adb047.js +1 -0
- package/_standalone/.next/static/chunks/app/changes/{page-5a72144d1080a699.js → page-6d2f49651c0061f7.js} +1 -1
- package/_standalone/.next/static/chunks/app/echo/[segment]/page-84b95256f6e38aae.js +11 -0
- package/_standalone/.next/static/chunks/app/explore/{page-d3d99308146c2240.js → page-d9f58000bc445360.js} +2 -2
- package/_standalone/.next/static/chunks/app/help/{page-222df603080b5fab.js → page-f8cb806371b3175f.js} +1 -1
- package/_standalone/.next/static/chunks/app/inbox/history/{page-07819cf95cb0805f.js → page-26e71fb6f716a4c4.js} +1 -1
- package/_standalone/.next/static/chunks/app/layout-b89b0d955f39a753.js +164 -0
- package/_standalone/.next/static/chunks/app/login/{page-0eeef685052869a6.js → page-18fb00d568cd1f0e.js} +1 -1
- package/_standalone/.next/static/chunks/app/page-a8e6f085f38388bf.js +1 -0
- package/_standalone/.next/static/chunks/app/setup/{page-99fcfc460fa29733.js → page-821714e7477be46c.js} +1 -1
- package/_standalone/.next/static/chunks/app/trash/page-f92b728b78ac0f7e.js +1 -0
- package/_standalone/.next/static/chunks/app/view/[...path]/{not-found-fc04c2bd4f35bc6f.js → not-found-6e0c75ad26ce8572.js} +1 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-f87f4901b5e1a88f.js +12 -0
- package/_standalone/.next/static/chunks/app/wiki/page-641edb1f3cff2f93.js +1 -0
- package/_standalone/.next/static/chunks/{webpack-2c19436659aa657b.js → webpack-72e8d9e9073fd1f9.js} +1 -1
- package/_standalone/.next/static/css/6c104b118d3bc9b7.css +1 -0
- package/_standalone/.next/trace +64 -64
- package/_standalone/__tests__/api/mcp-install.test.ts +3 -2
- package/_standalone/__tests__/ask/non-streaming-api.test.ts +281 -0
- package/_standalone/__tests__/core/skill-install-logic.test.ts +1 -0
- package/_standalone/app/globals.css +2 -1
- package/_standalone/components/AskFab.tsx +4 -4
- package/_standalone/components/AskModal.tsx +1 -1
- package/_standalone/components/GuideCard.tsx +101 -152
- package/_standalone/components/RightAskPanel.tsx +2 -2
- package/_standalone/components/agents/CustomAgentModal.tsx +32 -8
- package/_standalone/components/ask/AskContent.tsx +90 -51
- package/_standalone/components/ask/AskHeader.tsx +218 -18
- package/_standalone/components/ask/MessageList.tsx +66 -47
- package/_standalone/components/ask/SessionHistory.tsx +86 -60
- package/_standalone/components/ask/SessionTabBar.tsx +29 -21
- package/_standalone/components/ask/ThinkingBlock.tsx +6 -5
- package/_standalone/components/ask/ToolCallBlock.tsx +10 -9
- package/_standalone/components/settings/SettingsContent.tsx +1 -1
- package/_standalone/data/skills/mindos/SKILL.md +72 -15
- package/_standalone/data/skills/mindos-zh/SKILL.md +73 -8
- package/_standalone/hooks/useAskSession.ts +23 -1
- package/_standalone/lib/stores/locale-store.ts +20 -6
- package/_standalone/tsconfig.tsbuildinfo +1 -1
- package/app/app/api/agents/custom/route.ts +8 -0
- package/app/app/api/ask/route.ts +171 -10
- package/app/app/api/mcp/agents/route.ts +5 -3
- package/app/app/api/settings/route.ts +9 -0
- package/app/app/api/settings/test-key/route.ts +13 -1
- package/app/app/globals.css +2 -1
- package/app/app/layout.tsx +16 -4
- package/app/components/AskFab.tsx +4 -4
- package/app/components/AskModal.tsx +1 -1
- package/app/components/GuideCard.tsx +101 -152
- package/app/components/HomeContent.tsx +116 -575
- package/app/components/RightAskPanel.tsx +2 -2
- package/app/components/WikiHomeContent.tsx +151 -3
- package/app/components/agents/CustomAgentModal.tsx +32 -8
- package/app/components/ask/AskContent.tsx +90 -51
- package/app/components/ask/AskHeader.tsx +218 -18
- package/app/components/ask/MessageList.tsx +66 -47
- package/app/components/ask/SessionHistory.tsx +86 -60
- package/app/components/ask/SessionTabBar.tsx +29 -21
- package/app/components/ask/ThinkingBlock.tsx +6 -5
- package/app/components/ask/ToolCallBlock.tsx +10 -9
- package/app/components/settings/SettingsContent.tsx +1 -1
- package/app/data/skills/mindos/SKILL.md +72 -15
- package/app/data/skills/mindos-zh/SKILL.md +73 -8
- package/app/hooks/useAskSession.ts +23 -1
- package/app/lib/custom-agents.ts +45 -2
- package/app/lib/i18n/modules/ai-chat.ts +97 -10
- package/app/lib/i18n/modules/onboarding.ts +12 -12
- package/app/lib/i18n/modules/panels.ts +10 -2
- package/app/lib/mcp-agents.ts +10 -0
- package/app/lib/stores/LocaleStoreInit.tsx +24 -1
- package/app/lib/stores/locale-store.ts +20 -6
- package/app/lib/types.ts +1 -0
- package/bin/lib/mcp-agents.js +10 -0
- package/package.json +1 -1
- package/skills/mindos/SKILL.md +69 -11
- package/skills/mindos/references/knowledge-health.md +120 -0
- package/skills/mindos-max/SKILL.md +238 -0
- package/skills/mindos-max-workspace/evals/evals.json +23 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/eval_metadata.json +11 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/old_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/old_skill/outputs/transcript.md +203 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/with_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/capture-debugging-experience-en/with_skill/outputs/transcript.md +271 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/eval_metadata.json +11 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/old_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/old_skill/outputs/transcript.md +121 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/with_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/save-meeting-decision-zh/with_skill/outputs/transcript.md +168 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/eval_metadata.json +11 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/old_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/old_skill/outputs/transcript.md +143 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/with_skill/grading.json +28 -0
- package/skills/mindos-max-workspace/iteration-1/search-past-decision-zh/with_skill/outputs/transcript.md +233 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/SKILL.md +165 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/README.md +12 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/post-task-hooks.md +27 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/preference-capture.md +41 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/sop-template.md +74 -0
- package/skills/mindos-max-workspace/skill-snapshot/mindos-original/references/write-supplement.md +119 -0
- package/skills/mindos-max-zh/SKILL.md +241 -0
- package/skills/mindos-zh/SKILL.md +72 -8
- package/_standalone/.next/server/chunks/2364.js +0 -2
- package/_standalone/.next/server/chunks/357.js +0 -1
- package/_standalone/.next/static/chunks/1053-5cb008a24930e271.js +0 -29
- package/_standalone/.next/static/chunks/178-105779afb62d36d9.js +0 -1
- package/_standalone/.next/static/chunks/2218-d54538000574ffef.js +0 -1
- package/_standalone/.next/static/chunks/2549-e63cf57fa927a41d.js +0 -1
- package/_standalone/.next/static/chunks/7249-8cd568ad23656622.js +0 -11
- package/_standalone/.next/static/chunks/9274-296ab35f9f09e42e.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/page-5d1446665ddb3801.js +0 -1
- package/_standalone/.next/static/chunks/app/echo/[segment]/page-b0103509ce34444b.js +0 -11
- package/_standalone/.next/static/chunks/app/layout-b3919384ec2eb979.js +0 -186
- package/_standalone/.next/static/chunks/app/page-6436a99cda35132b.js +0 -7
- package/_standalone/.next/static/chunks/app/trash/page-8dc388695344fdd4.js +0 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-b292b55305ecc021.js +0 -12
- package/_standalone/.next/static/chunks/app/wiki/page-d492256a93f0b8bc.js +0 -1
- package/_standalone/.next/static/css/fd84c8316ead16eb.css +0 -1
- /package/_standalone/.next/static/{zOaEtgJbdRMncnCBucULp → u8p6oIRTcr_ns-ElNZ9rl}/_buildManifest.js +0 -0
- /package/_standalone/.next/static/{zOaEtgJbdRMncnCBucULp → u8p6oIRTcr_ns-ElNZ9rl}/_ssgManifest.js +0 -0
|
@@ -1,623 +1,164 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import { FileText, Table, Clock, Sparkles, ArrowRight, FilePlus, Search, ChevronDown, Folder, Brain, Plus, Trash2, Check, Loader2, X, FolderInput, History, Star } from 'lucide-react';
|
|
5
|
-
import { useState, useEffect, useMemo, useCallback } from 'react';
|
|
3
|
+
import { useState, useCallback } from 'react';
|
|
6
4
|
import { useLocale } from '@/lib/stores/locale-store';
|
|
7
|
-
import {
|
|
8
|
-
import { usePinnedFiles } from '@/lib/hooks/usePinnedFiles';
|
|
5
|
+
import { FolderSync, PenLine, BarChart3, Sparkles, ArrowUpRight } from 'lucide-react';
|
|
9
6
|
import OnboardingView from './OnboardingView';
|
|
10
7
|
import Logo from './Logo';
|
|
11
8
|
import GuideCard from './GuideCard';
|
|
12
|
-
import
|
|
13
|
-
import { InboxSection } from './home/InboxSection';
|
|
14
|
-
import { scanExampleFilesAction, cleanupExamplesAction } from '@/lib/actions';
|
|
9
|
+
import AskContent from '@/components/ask/AskContent';
|
|
15
10
|
import type { SpaceInfo } from '@/app/page';
|
|
16
|
-
import RecentActivityFeed from '@/components/agents/RecentActivityFeed';
|
|
17
11
|
|
|
18
12
|
interface RecentFile {
|
|
19
13
|
path: string;
|
|
20
14
|
mtime: number;
|
|
21
15
|
}
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
spacePath: string;
|
|
26
|
-
files: RecentFile[];
|
|
27
|
-
latestMtime: number;
|
|
28
|
-
totalFiles: number;
|
|
17
|
+
function injectAskInput(text: string) {
|
|
18
|
+
window.dispatchEvent(new CustomEvent('mindos:home-suggestion', { detail: { text } }));
|
|
29
19
|
}
|
|
30
20
|
|
|
31
|
-
|
|
32
|
-
window.dispatchEvent(new KeyboardEvent('keydown', { key: 'k', metaKey: true, bubbles: true }));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function triggerAsk() {
|
|
36
|
-
window.dispatchEvent(new KeyboardEvent('keydown', { key: '/', metaKey: true, bubbles: true }));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Group recent files by their top-level directory (Space) */
|
|
40
|
-
function groupBySpace(recent: RecentFile[], spaces: SpaceInfo[]): { groups: SpaceGroup[]; rootFiles: RecentFile[] } {
|
|
41
|
-
const groupMap = new Map<string, SpaceGroup>();
|
|
42
|
-
const rootFiles: RecentFile[] = [];
|
|
43
|
-
|
|
44
|
-
for (const file of recent) {
|
|
45
|
-
const parts = file.path.split('/');
|
|
46
|
-
if (parts.length < 2) {
|
|
47
|
-
rootFiles.push(file);
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
const spaceName = parts[0];
|
|
51
|
-
const spaceInfo = spaces.find(s => s.name === spaceName);
|
|
52
|
-
|
|
53
|
-
if (!groupMap.has(spaceName)) {
|
|
54
|
-
groupMap.set(spaceName, {
|
|
55
|
-
space: spaceName,
|
|
56
|
-
spacePath: spaceName + '/',
|
|
57
|
-
files: [],
|
|
58
|
-
latestMtime: 0,
|
|
59
|
-
totalFiles: spaceInfo?.fileCount ?? 0,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
const g = groupMap.get(spaceName)!;
|
|
63
|
-
g.files.push(file);
|
|
64
|
-
g.latestMtime = Math.max(g.latestMtime, file.mtime);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const groups = [...groupMap.values()].sort((a, b) => b.latestMtime - a.latestMtime);
|
|
68
|
-
return { groups, rootFiles };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/* ── Shared small components ── */
|
|
72
|
-
|
|
73
|
-
interface SectionTitleProps {
|
|
74
|
-
icon: React.ReactNode;
|
|
75
|
-
children: React.ReactNode;
|
|
76
|
-
count?: number;
|
|
77
|
-
action?: React.ReactNode;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function SectionTitle({ icon, children, count, action }: SectionTitleProps) {
|
|
81
|
-
return (
|
|
82
|
-
<div className="flex items-center gap-2.5 mb-5">
|
|
83
|
-
<div className="flex items-center justify-center w-6 h-6 rounded-md bg-[var(--amber-subtle)] text-[var(--amber)]">
|
|
84
|
-
{icon}
|
|
85
|
-
</div>
|
|
86
|
-
<h2 className="text-[13px] font-semibold text-foreground tracking-wide">
|
|
87
|
-
{children}
|
|
88
|
-
</h2>
|
|
89
|
-
{count != null && count > 0 && (
|
|
90
|
-
<span className="inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 text-[10px] font-semibold rounded-full bg-muted text-muted-foreground tabular-nums">{count}</span>
|
|
91
|
-
)}
|
|
92
|
-
{action ? <div className="ml-auto">{action}</div> : null}
|
|
93
|
-
</div>
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** Reusable "Show more / Show less" toggle */
|
|
98
|
-
function ToggleButton({ expanded, onToggle, showLabel, hideLabel, className = '' }: {
|
|
99
|
-
expanded: boolean;
|
|
100
|
-
onToggle: () => void;
|
|
101
|
-
showLabel: string;
|
|
102
|
-
hideLabel: string;
|
|
103
|
-
className?: string;
|
|
104
|
-
}) {
|
|
105
|
-
return (
|
|
106
|
-
<button
|
|
107
|
-
onClick={onToggle}
|
|
108
|
-
aria-expanded={expanded}
|
|
109
|
-
className={`flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer ${className}`}
|
|
110
|
-
>
|
|
111
|
-
<ChevronDown size={12} className={`transition-transform duration-200 ${expanded ? 'rotate-180' : ''}`} />
|
|
112
|
-
<span>{expanded ? hideLabel : showLabel}</span>
|
|
113
|
-
</button>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** Reusable file row for recent-file lists */
|
|
118
|
-
function FileRow({ filePath, mtime, formatTime, subPath }: {
|
|
119
|
-
filePath: string;
|
|
120
|
-
mtime: number;
|
|
121
|
-
formatTime: (t: number) => string;
|
|
122
|
-
subPath?: string;
|
|
123
|
-
}) {
|
|
124
|
-
const isCSV = filePath.endsWith('.csv');
|
|
125
|
-
const name = filePath.split('/').pop() || filePath;
|
|
126
|
-
return (
|
|
127
|
-
<Link
|
|
128
|
-
href={`/view/${encodePath(filePath)}`}
|
|
129
|
-
className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted group overflow-hidden"
|
|
130
|
-
>
|
|
131
|
-
{isCSV
|
|
132
|
-
? <Table size={12} className="shrink-0 text-success" />
|
|
133
|
-
: <FileText size={12} className="shrink-0 text-muted-foreground" />
|
|
134
|
-
}
|
|
135
|
-
<div className="flex-1 min-w-0">
|
|
136
|
-
<span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
|
|
137
|
-
{subPath && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{subPath}</span>}
|
|
138
|
-
</div>
|
|
139
|
-
<span className="text-xs shrink-0 tabular-nums text-muted-foreground/40" suppressHydrationWarning>
|
|
140
|
-
{formatTime(mtime)}
|
|
141
|
-
</span>
|
|
142
|
-
</Link>
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const FILES_PER_GROUP = 3;
|
|
147
|
-
const SPACES_PER_ROW = 6;
|
|
21
|
+
const TAB_ICONS = [FolderSync, PenLine, BarChart3, Sparkles];
|
|
148
22
|
|
|
149
23
|
export default function HomeContent({ recent, existingFiles, spaces }: { recent: RecentFile[]; existingFiles?: string[]; spaces?: SpaceInfo[] }) {
|
|
150
24
|
const { t } = useLocale();
|
|
151
|
-
const [
|
|
152
|
-
const [
|
|
153
|
-
const [suggestionIdx, setSuggestionIdx] = useState(0);
|
|
25
|
+
const [activeTab, setActiveTab] = useState(0);
|
|
26
|
+
const [maximized, setMaximized] = useState(false);
|
|
154
27
|
|
|
155
|
-
const
|
|
156
|
-
'Summarize this document',
|
|
157
|
-
'List all action items and TODOs',
|
|
158
|
-
'What are the key points?',
|
|
159
|
-
'Find related notes on this topic',
|
|
160
|
-
];
|
|
28
|
+
const toggleMaximize = useCallback(() => setMaximized(v => !v), []);
|
|
161
29
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return () => clearInterval(interval);
|
|
167
|
-
}, [suggestions.length]);
|
|
168
|
-
|
|
169
|
-
const spaceList = spaces ?? [];
|
|
170
|
-
const { groups, rootFiles } = useMemo(() => groupBySpace(recent, spaceList), [recent, spaceList]);
|
|
30
|
+
// Auto-fullscreen when user sends the first message in a session
|
|
31
|
+
const handleFirstMessage = useCallback(() => {
|
|
32
|
+
setMaximized(true);
|
|
33
|
+
}, []);
|
|
171
34
|
|
|
172
35
|
if (recent.length === 0) {
|
|
173
36
|
return <OnboardingView />;
|
|
174
37
|
}
|
|
175
38
|
|
|
176
|
-
const
|
|
39
|
+
const categories: { label: string; items: { label: string; desc: string; prompt: string }[] }[] =
|
|
40
|
+
(t.ask as Record<string, unknown>)?.homeCategories as typeof categories ?? [];
|
|
177
41
|
|
|
178
|
-
const
|
|
42
|
+
const current = categories[activeTab];
|
|
179
43
|
|
|
44
|
+
/*
|
|
45
|
+
* Single render tree — AskContent is always mounted in the same position.
|
|
46
|
+
* Normal vs fullscreen is purely a CSS layout change, so chat state is preserved.
|
|
47
|
+
*/
|
|
180
48
|
return (
|
|
181
|
-
<div className="
|
|
182
|
-
|
|
183
|
-
|
|
49
|
+
<div className="flex flex-col h-[100dvh]">
|
|
50
|
+
|
|
51
|
+
{/* ── Landing chrome: hidden when maximized ── */}
|
|
52
|
+
{!maximized && (
|
|
53
|
+
<>
|
|
54
|
+
{/* Guide Card */}
|
|
55
|
+
<div className="flex-shrink-0 px-4 md:px-6 pt-4 pb-6">
|
|
56
|
+
<div className="max-w-4xl mx-auto">
|
|
57
|
+
<GuideCard />
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
184
60
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
{/* Brand mark */}
|
|
188
|
-
<div className="flex items-center gap-5 mb-1">
|
|
189
|
-
<Logo id="home-hero" className="w-14 h-7 opacity-90" />
|
|
190
|
-
<h1 className="text-[2rem] font-brand leading-none">
|
|
191
|
-
<span className="text-foreground">Mind</span><span className="text-[var(--amber)]">OS</span>
|
|
192
|
-
</h1>
|
|
193
|
-
</div>
|
|
194
|
-
<p className="text-sm text-muted-foreground/50 mt-3 max-w-md leading-relaxed">
|
|
195
|
-
{t.app.tagline}
|
|
196
|
-
</p>
|
|
61
|
+
{/* Spacer top */}
|
|
62
|
+
<div className="flex-1 min-h-0" />
|
|
197
63
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
>
|
|
206
|
-
<Sparkles size={16} className="shrink-0 text-[var(--amber)] group-hover:scale-110 transition-transform duration-150" />
|
|
207
|
-
<div className="flex-1 min-h-[1.5rem] flex items-center">
|
|
208
|
-
<span
|
|
209
|
-
key={suggestionIdx}
|
|
210
|
-
className="text-sm text-left text-muted-foreground animate-in fade-in duration-300"
|
|
211
|
-
>
|
|
212
|
-
{suggestions[suggestionIdx]}
|
|
213
|
-
</span>
|
|
64
|
+
{/* Hero */}
|
|
65
|
+
<div className="flex-shrink-0 flex flex-col items-center text-center px-4 md:px-6 pb-8">
|
|
66
|
+
<div className="flex items-center gap-4 mb-3">
|
|
67
|
+
<Logo id="home-hero" className="w-10 h-5 opacity-90" />
|
|
68
|
+
<h1 className="text-2xl font-brand leading-none">
|
|
69
|
+
<span className="text-foreground">Mind</span><span className="text-[var(--amber)]">OS</span>
|
|
70
|
+
</h1>
|
|
214
71
|
</div>
|
|
215
|
-
<
|
|
216
|
-
|
|
217
|
-
</
|
|
218
|
-
</
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
title="⌘K"
|
|
222
|
-
className="flex items-center gap-2 px-3.5 py-3.5 rounded-xl border border-border/50 text-sm text-muted-foreground transition-all duration-200 shrink-0 hover:bg-muted/60 hover:shadow-sm hover:-translate-y-0.5"
|
|
223
|
-
>
|
|
224
|
-
<Search size={14} />
|
|
225
|
-
<kbd className="hidden sm:inline-flex items-center px-1.5 py-0.5 rounded text-xs font-mono bg-muted">
|
|
226
|
-
⌘K
|
|
227
|
-
</kbd>
|
|
228
|
-
</button>
|
|
229
|
-
</div>
|
|
72
|
+
<p className="text-sm text-muted-foreground/50 max-w-sm leading-relaxed">
|
|
73
|
+
{t.app.tagline}
|
|
74
|
+
</p>
|
|
75
|
+
</div>
|
|
76
|
+
</>
|
|
77
|
+
)}
|
|
230
78
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
<span className="text-xs opacity-40 truncate max-w-32" suppressHydrationWarning>
|
|
248
|
-
{lastFile.path.split('/').pop()}
|
|
249
|
-
</span>
|
|
250
|
-
</Link>
|
|
251
|
-
)}
|
|
79
|
+
{/* ── Chatbot area: always mounted, layout changes with maximized ── */}
|
|
80
|
+
<div className={
|
|
81
|
+
maximized
|
|
82
|
+
? 'flex-1 min-h-0 flex flex-col overflow-hidden'
|
|
83
|
+
: 'flex-shrink-0 px-4 md:px-6 flex justify-center'
|
|
84
|
+
}>
|
|
85
|
+
<div className={maximized ? 'flex-1 min-h-0 flex flex-col overflow-hidden' : 'w-full max-w-4xl'}>
|
|
86
|
+
<div className={maximized ? 'flex-1 min-h-0 flex flex-col overflow-hidden' : 'rounded-xl border border-border/50 shadow-sm overflow-hidden flex flex-col max-h-[50vh]'}>
|
|
87
|
+
<AskContent
|
|
88
|
+
visible={true}
|
|
89
|
+
variant="home"
|
|
90
|
+
maximized={maximized}
|
|
91
|
+
onMaximize={toggleMaximize}
|
|
92
|
+
onFirstMessage={handleFirstMessage}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
252
95
|
</div>
|
|
253
96
|
</div>
|
|
254
97
|
|
|
255
|
-
{/*
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
98
|
+
{/* ── Bottom chrome: hidden when maximized ── */}
|
|
99
|
+
{!maximized && (
|
|
100
|
+
<>
|
|
101
|
+
{/* Tabs + Prompt Grid */}
|
|
102
|
+
{categories.length > 0 && current && (
|
|
103
|
+
<div className="flex-shrink-0 flex justify-center px-4 md:px-6 pt-6">
|
|
104
|
+
<div className="w-full max-w-4xl">
|
|
105
|
+
|
|
106
|
+
{/* Pill Tabs */}
|
|
107
|
+
<div className="flex items-center justify-center gap-1.5 mb-5">
|
|
108
|
+
{categories.map((cat, i) => {
|
|
109
|
+
const Icon = TAB_ICONS[i % TAB_ICONS.length];
|
|
110
|
+
const isActive = i === activeTab;
|
|
111
|
+
return (
|
|
112
|
+
<button
|
|
113
|
+
key={cat.label}
|
|
114
|
+
type="button"
|
|
115
|
+
onClick={() => setActiveTab(i)}
|
|
116
|
+
className={`flex items-center gap-1.5 px-4 py-2 text-xs font-medium rounded-full transition-all duration-150 ${
|
|
117
|
+
isActive
|
|
118
|
+
? 'bg-[var(--amber)]/12 text-[var(--amber)]'
|
|
119
|
+
: 'text-muted-foreground/50 hover:text-muted-foreground hover:bg-muted/40'
|
|
120
|
+
}`}
|
|
121
|
+
>
|
|
122
|
+
<Icon size={13} />
|
|
123
|
+
<span>{cat.label}</span>
|
|
124
|
+
</button>
|
|
125
|
+
);
|
|
126
|
+
})}
|
|
127
|
+
</div>
|
|
268
128
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
{t.home.spaces}
|
|
278
|
-
</SectionTitle>
|
|
279
|
-
{spaceList.length > 0 ? (
|
|
280
|
-
<>
|
|
281
|
-
<div className="grid grid-cols-2 sm:grid-cols-3 gap-2.5">
|
|
282
|
-
{(showAllSpaces ? spaceList : spaceList.slice(0, SPACES_PER_ROW)).map(s => {
|
|
283
|
-
const emoji = extractEmoji(s.name);
|
|
284
|
-
const label = stripEmoji(s.name);
|
|
285
|
-
const isEmpty = s.fileCount === 0;
|
|
286
|
-
return (
|
|
287
|
-
<Link
|
|
288
|
-
key={s.name}
|
|
289
|
-
href={`/view/${encodePath(s.path)}`}
|
|
290
|
-
className={`flex items-start gap-3 px-4 py-3.5 rounded-xl border transition-all duration-200 ${
|
|
291
|
-
isEmpty
|
|
292
|
-
? 'border-dashed border-border/50 opacity-50 hover:opacity-70'
|
|
293
|
-
: 'border-border/60 hover:border-[var(--amber)]/30 hover:shadow-md hover:-translate-y-0.5 bg-card/40'
|
|
294
|
-
}`}
|
|
129
|
+
{/* Prompt Cards — 2x2 grid */}
|
|
130
|
+
<div className="grid grid-cols-2 gap-2">
|
|
131
|
+
{current.items.map((item, i) => (
|
|
132
|
+
<button
|
|
133
|
+
key={`${activeTab}-${i}`}
|
|
134
|
+
type="button"
|
|
135
|
+
onClick={() => injectAskInput(item.prompt)}
|
|
136
|
+
className="group relative text-left px-4 py-3.5 rounded-xl border border-border/30 hover:border-border/60 transition-all duration-150 hover:shadow-sm"
|
|
295
137
|
>
|
|
296
|
-
|
|
297
|
-
<
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
<span className="text-sm font-medium truncate block text-foreground">{label}</span>
|
|
303
|
-
{s.description && (
|
|
304
|
-
<span className="text-xs text-muted-foreground line-clamp-1 mt-0.5" suppressHydrationWarning>{s.description}</span>
|
|
305
|
-
)}
|
|
306
|
-
<span className="text-xs text-muted-foreground/50 mt-0.5 block tabular-nums">
|
|
307
|
-
{t.home.nFiles(s.fileCount)}
|
|
308
|
-
</span>
|
|
138
|
+
<div className="flex items-start justify-between gap-2">
|
|
139
|
+
<div className="min-w-0">
|
|
140
|
+
<div className="text-[13px] font-medium text-foreground/90 leading-snug mb-0.5">{item.label}</div>
|
|
141
|
+
<div className="text-xs text-muted-foreground/60 leading-relaxed">{item.desc}</div>
|
|
142
|
+
</div>
|
|
143
|
+
<ArrowUpRight size={14} className="shrink-0 mt-0.5 text-muted-foreground/20 group-hover:text-[var(--amber)] transition-colors" />
|
|
309
144
|
</div>
|
|
310
|
-
</
|
|
311
|
-
)
|
|
312
|
-
})}
|
|
313
|
-
</div>
|
|
314
|
-
{spaceList.length > SPACES_PER_ROW && (
|
|
315
|
-
<ToggleButton
|
|
316
|
-
expanded={showAllSpaces}
|
|
317
|
-
onToggle={() => setShowAllSpaces(v => !v)}
|
|
318
|
-
showLabel={t.home.showMore}
|
|
319
|
-
hideLabel={t.home.showLess}
|
|
320
|
-
className="mt-2"
|
|
321
|
-
/>
|
|
322
|
-
)}
|
|
323
|
-
</>
|
|
324
|
-
) : (
|
|
325
|
-
<p className="text-xs text-muted-foreground py-2">
|
|
326
|
-
{t.home.noSpacesYet ?? 'No spaces yet. Create one to organize your knowledge.'}
|
|
327
|
-
</p>
|
|
328
|
-
)}
|
|
329
|
-
</section>
|
|
330
|
-
)}
|
|
331
|
-
|
|
332
|
-
{/* ══════════ Pinned Files ══════════ */}
|
|
333
|
-
<PinnedFilesSection formatTime={formatTime} />
|
|
334
|
-
|
|
335
|
-
{/* ── Visual divider ── */}
|
|
336
|
-
<div className="border-t border-border/30 mb-10" />
|
|
337
|
-
|
|
338
|
-
{/* ══════════ Recently Edited ══════════ */}
|
|
339
|
-
{recent.length > 0 && (
|
|
340
|
-
<section className="mb-12">
|
|
341
|
-
<SectionTitle
|
|
342
|
-
icon={<Clock size={14} />}
|
|
343
|
-
count={recent.length}
|
|
344
|
-
action={
|
|
345
|
-
<Link
|
|
346
|
-
href="/changes"
|
|
347
|
-
className="flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80"
|
|
348
|
-
>
|
|
349
|
-
<History size={12} />
|
|
350
|
-
<span>{t.home.changeHistory}</span>
|
|
351
|
-
</Link>
|
|
352
|
-
}
|
|
353
|
-
>
|
|
354
|
-
{t.home.recentlyEdited}
|
|
355
|
-
</SectionTitle>
|
|
356
|
-
|
|
357
|
-
{groups.length > 0 ? (
|
|
358
|
-
<div className="flex flex-col gap-3">
|
|
359
|
-
{groups.map((group) => {
|
|
360
|
-
const visibleFiles = showAll ? group.files : group.files.slice(0, FILES_PER_GROUP);
|
|
361
|
-
const hasMoreFiles = group.files.length > FILES_PER_GROUP;
|
|
362
|
-
return (
|
|
363
|
-
<div key={group.space}>
|
|
364
|
-
<Link
|
|
365
|
-
href={`/view/${encodePath(group.spacePath)}`}
|
|
366
|
-
className="flex items-center gap-2 px-1 py-1.5 rounded-lg group transition-colors hover:bg-muted/50"
|
|
367
|
-
>
|
|
368
|
-
<Folder size={14} className="shrink-0 text-[var(--amber)]" />
|
|
369
|
-
<span className="text-xs font-semibold text-foreground group-hover:text-[var(--amber)] transition-colors" suppressHydrationWarning>
|
|
370
|
-
{group.space}
|
|
371
|
-
</span>
|
|
372
|
-
<span className="text-xs text-muted-foreground/50 tabular-nums" suppressHydrationWarning>
|
|
373
|
-
{t.home.nFiles(group.totalFiles)} · {formatTime(group.latestMtime)}
|
|
374
|
-
</span>
|
|
375
|
-
{hasMoreFiles && !showAll && (
|
|
376
|
-
<span className="text-xs text-muted-foreground/30 tabular-nums">
|
|
377
|
-
+{group.files.length - FILES_PER_GROUP}
|
|
378
|
-
</span>
|
|
379
|
-
)}
|
|
380
|
-
</Link>
|
|
381
|
-
<div className="flex flex-col gap-0.5 ml-2 border-l-2 border-border/20 pl-3">
|
|
382
|
-
{visibleFiles.map(({ path: filePath, mtime }) => (
|
|
383
|
-
<FileRow
|
|
384
|
-
key={filePath}
|
|
385
|
-
filePath={filePath}
|
|
386
|
-
mtime={mtime}
|
|
387
|
-
formatTime={formatTime}
|
|
388
|
-
subPath={filePath.split('/').slice(1, -1).join('/')}
|
|
389
|
-
/>
|
|
390
|
-
))}
|
|
391
|
-
</div>
|
|
392
|
-
</div>
|
|
393
|
-
);
|
|
394
|
-
})}
|
|
395
|
-
|
|
396
|
-
{rootFiles.length > 0 && (
|
|
397
|
-
<div>
|
|
398
|
-
<div className="flex items-center gap-2 px-1 py-1.5">
|
|
399
|
-
<FileText size={14} className="shrink-0 text-muted-foreground/50" />
|
|
400
|
-
<span className="text-xs font-semibold text-muted-foreground/60">
|
|
401
|
-
{t.home.other}
|
|
402
|
-
</span>
|
|
403
|
-
</div>
|
|
404
|
-
<div className="flex flex-col gap-0.5 ml-2 border-l-2 border-border/20 pl-3">
|
|
405
|
-
{rootFiles.map(({ path: filePath, mtime }) => (
|
|
406
|
-
<FileRow key={filePath} filePath={filePath} mtime={mtime} formatTime={formatTime} />
|
|
407
|
-
))}
|
|
408
|
-
</div>
|
|
145
|
+
</button>
|
|
146
|
+
))}
|
|
409
147
|
</div>
|
|
410
|
-
)}
|
|
411
|
-
|
|
412
|
-
{groups.some(g => g.files.length > FILES_PER_GROUP) && (
|
|
413
|
-
<ToggleButton
|
|
414
|
-
expanded={showAll}
|
|
415
|
-
onToggle={() => setShowAll(v => !v)}
|
|
416
|
-
showLabel={t.home.showMore}
|
|
417
|
-
hideLabel={t.home.showLess}
|
|
418
|
-
className="mt-1 ml-1"
|
|
419
|
-
/>
|
|
420
|
-
)}
|
|
421
|
-
</div>
|
|
422
|
-
) : (
|
|
423
|
-
<div className="relative pl-4">
|
|
424
|
-
<div className="absolute left-0 top-1 bottom-1 w-0.5 rounded-full bg-gradient-to-b from-[var(--amber)]/20 via-border/30 to-transparent" />
|
|
425
|
-
<div className="flex flex-col gap-0.5">
|
|
426
|
-
{(showAll ? recent : recent.slice(0, 5)).map(({ path: filePath, mtime }, idx) => {
|
|
427
|
-
const isCSV = filePath.endsWith('.csv');
|
|
428
|
-
const name = filePath.split('/').pop() || filePath;
|
|
429
|
-
const dir = filePath.split('/').slice(0, -1).join('/');
|
|
430
|
-
return (
|
|
431
|
-
<div key={filePath} className="relative group">
|
|
432
|
-
<div
|
|
433
|
-
aria-hidden="true"
|
|
434
|
-
className={`absolute -left-[5px] top-1/2 -translate-y-1/2 rounded-full transition-all duration-200 group-hover:scale-125 ${
|
|
435
|
-
idx === 0
|
|
436
|
-
? 'w-2.5 h-2.5 bg-[var(--amber)] ring-[3px] ring-[var(--amber)]/15 shadow-sm shadow-[var(--amber)]/20'
|
|
437
|
-
: 'w-1.5 h-1.5 bg-muted-foreground/25 group-hover:bg-[var(--amber)]/50'
|
|
438
|
-
}`}
|
|
439
|
-
/>
|
|
440
|
-
<Link
|
|
441
|
-
href={`/view/${encodePath(filePath)}`}
|
|
442
|
-
className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 group-hover:translate-x-0.5 hover:bg-muted overflow-hidden"
|
|
443
|
-
>
|
|
444
|
-
{isCSV
|
|
445
|
-
? <Table size={12} className="shrink-0 text-success" />
|
|
446
|
-
: <FileText size={12} className="shrink-0 text-muted-foreground/50" />
|
|
447
|
-
}
|
|
448
|
-
<div className="flex-1 min-w-0">
|
|
449
|
-
<span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
|
|
450
|
-
{dir && <span className="text-xs truncate block text-muted-foreground/40" suppressHydrationWarning>{dir}</span>}
|
|
451
|
-
</div>
|
|
452
|
-
<span className="text-xs shrink-0 tabular-nums text-muted-foreground/40" suppressHydrationWarning>
|
|
453
|
-
{formatTime(mtime)}
|
|
454
|
-
</span>
|
|
455
|
-
</Link>
|
|
456
|
-
</div>
|
|
457
|
-
);
|
|
458
|
-
})}
|
|
459
148
|
</div>
|
|
460
|
-
{recent.length > 5 && (
|
|
461
|
-
<ToggleButton
|
|
462
|
-
expanded={showAll}
|
|
463
|
-
onToggle={() => setShowAll(v => !v)}
|
|
464
|
-
showLabel={t.home.showMore}
|
|
465
|
-
hideLabel={t.home.showLess}
|
|
466
|
-
className="mt-2 ml-3"
|
|
467
|
-
/>
|
|
468
|
-
)}
|
|
469
149
|
</div>
|
|
470
150
|
)}
|
|
471
|
-
</section>
|
|
472
|
-
)}
|
|
473
|
-
|
|
474
|
-
{/* Footer */}
|
|
475
|
-
<div className="mt-6 py-8 border-t border-border/20 flex items-center justify-center gap-2 text-[11px] text-muted-foreground/25">
|
|
476
|
-
<Logo id="home-footer" className="w-5 h-2.5 opacity-30" />
|
|
477
|
-
<span>{t.app.footer}</span>
|
|
478
|
-
</div>
|
|
479
|
-
</div>
|
|
480
|
-
);
|
|
481
|
-
}
|
|
482
151
|
|
|
483
|
-
/*
|
|
484
|
-
|
|
485
|
-
const { t } = useLocale();
|
|
486
|
-
const { pinnedFiles, removePin } = usePinnedFiles();
|
|
152
|
+
{/* Spacer bottom */}
|
|
153
|
+
<div className="flex-1 min-h-0" />
|
|
487
154
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
{t.pinnedFiles.title}
|
|
493
|
-
</SectionTitle>
|
|
494
|
-
<div className="py-8 px-6 rounded-xl border border-border/40 bg-card/30 text-center">
|
|
495
|
-
<div className="inline-flex items-center justify-center w-10 h-10 rounded-full bg-[var(--amber-subtle)] mb-3">
|
|
496
|
-
<Star size={18} className="text-[var(--amber)]/60" />
|
|
155
|
+
{/* Footer */}
|
|
156
|
+
<div className="flex-shrink-0 py-4 flex items-center justify-center gap-2 text-[11px] text-muted-foreground/20">
|
|
157
|
+
<Logo id="home-footer" className="w-4 h-2 opacity-20" />
|
|
158
|
+
<span>{t.app.footer}</span>
|
|
497
159
|
</div>
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
</p>
|
|
501
|
-
<p className="text-xs text-muted-foreground/40 max-w-xs mx-auto leading-relaxed">
|
|
502
|
-
{t.pinnedFiles.emptyHint ?? 'Click the star icon on any file to pin it here'}
|
|
503
|
-
</p>
|
|
504
|
-
</div>
|
|
505
|
-
</section>
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
return (
|
|
510
|
-
<section className="mb-12">
|
|
511
|
-
<SectionTitle icon={<Star size={14} />} count={pinnedFiles.length}>
|
|
512
|
-
{t.pinnedFiles.title}
|
|
513
|
-
</SectionTitle>
|
|
514
|
-
<div className="flex flex-col gap-0.5">
|
|
515
|
-
{pinnedFiles.map((filePath) => {
|
|
516
|
-
const name = filePath.split('/').pop() || filePath;
|
|
517
|
-
const dir = filePath.split('/').slice(0, -1).join('/');
|
|
518
|
-
const isCSV = filePath.endsWith('.csv');
|
|
519
|
-
return (
|
|
520
|
-
<div key={filePath} className="group/pin relative">
|
|
521
|
-
<Link
|
|
522
|
-
href={`/view/${encodePath(filePath)}`}
|
|
523
|
-
className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted overflow-hidden"
|
|
524
|
-
>
|
|
525
|
-
<Star size={12} className="shrink-0 fill-[var(--amber)] text-[var(--amber)]" />
|
|
526
|
-
{isCSV
|
|
527
|
-
? <Table size={12} className="shrink-0 text-success" />
|
|
528
|
-
: <FileText size={12} className="shrink-0 text-muted-foreground" />
|
|
529
|
-
}
|
|
530
|
-
<div className="flex-1 min-w-0">
|
|
531
|
-
<span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
|
|
532
|
-
{dir && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{dir}</span>}
|
|
533
|
-
</div>
|
|
534
|
-
</Link>
|
|
535
|
-
<button
|
|
536
|
-
onClick={(e) => { e.preventDefault(); e.stopPropagation(); removePin(filePath); }}
|
|
537
|
-
className="absolute right-2 top-1/2 -translate-y-1/2 hidden group-hover/pin:flex p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
|
|
538
|
-
title={t.pinnedFiles.removedToast}
|
|
539
|
-
>
|
|
540
|
-
<X size={12} />
|
|
541
|
-
</button>
|
|
542
|
-
</div>
|
|
543
|
-
);
|
|
544
|
-
})}
|
|
545
|
-
</div>
|
|
546
|
-
</section>
|
|
547
|
-
);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/* ── Create Space: title-bar button ── */
|
|
551
|
-
function CreateSpaceButton({ t }: { t: ReturnType<typeof useLocale>['t'] }) {
|
|
552
|
-
return (
|
|
553
|
-
<button
|
|
554
|
-
onClick={() => window.dispatchEvent(new Event('mindos:create-space'))}
|
|
555
|
-
className="flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer"
|
|
556
|
-
>
|
|
557
|
-
<Plus size={12} />
|
|
558
|
-
<span>{t.home.newSpace}</span>
|
|
559
|
-
</button>
|
|
560
|
-
);
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
/* ── Example files cleanup banner ── */
|
|
564
|
-
function ExampleCleanupBanner() {
|
|
565
|
-
const { t } = useLocale();
|
|
566
|
-
const [count, setCount] = useState<number | null>(null);
|
|
567
|
-
const [cleaning, setCleaning] = useState(false);
|
|
568
|
-
const [done, setDone] = useState(false);
|
|
569
|
-
const [dismissed, setDismissed] = useState(false);
|
|
570
|
-
|
|
571
|
-
useEffect(() => {
|
|
572
|
-
scanExampleFilesAction().then(r => {
|
|
573
|
-
if (r.files.length > 0) setCount(r.files.length);
|
|
574
|
-
}).catch((err) => { console.warn("[HomeContent] scanExampleFilesAction failed:", err); });
|
|
575
|
-
}, []);
|
|
576
|
-
|
|
577
|
-
const handleCleanup = useCallback(async () => {
|
|
578
|
-
if (count === null) return;
|
|
579
|
-
setCleaning(true);
|
|
580
|
-
try {
|
|
581
|
-
const r = await cleanupExamplesAction();
|
|
582
|
-
if (r.success) {
|
|
583
|
-
setDone(true);
|
|
584
|
-
setTimeout(() => setDismissed(true), 2500);
|
|
585
|
-
}
|
|
586
|
-
} catch { /* silent — banner stays, user can retry */ }
|
|
587
|
-
setCleaning(false);
|
|
588
|
-
}, [count]);
|
|
589
|
-
|
|
590
|
-
if (dismissed || count === null || count === 0) return null;
|
|
591
|
-
|
|
592
|
-
if (done) {
|
|
593
|
-
return (
|
|
594
|
-
<div className="mb-6 flex items-center gap-2.5 px-4 py-3 rounded-xl border border-success/30 bg-success/5 animate-in fade-in duration-300">
|
|
595
|
-
<Check size={14} className="text-success shrink-0" />
|
|
596
|
-
<span className="text-xs text-success">{t.home.cleanupExamplesDone}</span>
|
|
597
|
-
</div>
|
|
598
|
-
);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
return (
|
|
602
|
-
<div className="mb-6 flex items-center gap-3 px-4 py-3 rounded-xl border border-border bg-muted/30 animate-in fade-in duration-300">
|
|
603
|
-
<span className="text-sm leading-none shrink-0">🧪</span>
|
|
604
|
-
<span className="text-xs text-muted-foreground flex-1">
|
|
605
|
-
{t.home.cleanupExamples(count)}
|
|
606
|
-
</span>
|
|
607
|
-
<button
|
|
608
|
-
onClick={handleCleanup}
|
|
609
|
-
disabled={cleaning}
|
|
610
|
-
className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-lg transition-colors shrink-0 disabled:opacity-50 bg-[var(--amber-dim)] text-[var(--amber-text)] hover:opacity-80"
|
|
611
|
-
>
|
|
612
|
-
{cleaning ? <Loader2 size={12} className="animate-spin" /> : <Trash2 size={12} />}
|
|
613
|
-
{t.home.cleanupExamplesButton}
|
|
614
|
-
</button>
|
|
615
|
-
<button
|
|
616
|
-
onClick={() => setDismissed(true)}
|
|
617
|
-
className="p-1 rounded hover:bg-muted transition-colors text-muted-foreground shrink-0"
|
|
618
|
-
>
|
|
619
|
-
<X size={12} />
|
|
620
|
-
</button>
|
|
160
|
+
</>
|
|
161
|
+
)}
|
|
621
162
|
</div>
|
|
622
163
|
);
|
|
623
164
|
}
|