@geminilight/mindos 0.1.0
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/.env.local.example +38 -0
- package/LICENSE +21 -0
- package/README.md +423 -0
- package/README_zh.md +423 -0
- package/app/README.md +152 -0
- package/app/app/api/ask/route.ts +170 -0
- package/app/app/api/ask-sessions/route.ts +90 -0
- package/app/app/api/auth/route.ts +37 -0
- package/app/app/api/backlinks/route.ts +22 -0
- package/app/app/api/bootstrap/route.ts +37 -0
- package/app/app/api/extract-pdf/route.ts +82 -0
- package/app/app/api/file/route.ts +138 -0
- package/app/app/api/files/route.ts +12 -0
- package/app/app/api/git/route.ts +42 -0
- package/app/app/api/graph/route.ts +113 -0
- package/app/app/api/recent-files/route.ts +10 -0
- package/app/app/api/search/route.ts +17 -0
- package/app/app/api/settings/reset-token/route.ts +21 -0
- package/app/app/api/settings/route.ts +123 -0
- package/app/app/error.tsx +33 -0
- package/app/app/globals.css +368 -0
- package/app/app/icon.svg +35 -0
- package/app/app/layout.tsx +103 -0
- package/app/app/login/page.tsx +120 -0
- package/app/app/page.tsx +12 -0
- package/app/app/view/[...path]/ViewPageClient.tsx +343 -0
- package/app/app/view/[...path]/error.tsx +33 -0
- package/app/app/view/[...path]/loading.tsx +15 -0
- package/app/app/view/[...path]/page.tsx +93 -0
- package/app/components/AskFab.tsx +59 -0
- package/app/components/AskModal.tsx +398 -0
- package/app/components/Backlinks.tsx +75 -0
- package/app/components/Breadcrumb.tsx +31 -0
- package/app/components/CsvView.tsx +325 -0
- package/app/components/DirView.tsx +138 -0
- package/app/components/Editor.tsx +124 -0
- package/app/components/EditorWrapper.tsx +17 -0
- package/app/components/ErrorBoundary.tsx +53 -0
- package/app/components/FileTree.tsx +369 -0
- package/app/components/HomeContent.tsx +262 -0
- package/app/components/JsonView.tsx +27 -0
- package/app/components/MarkdownEditor.tsx +95 -0
- package/app/components/MarkdownView.tsx +118 -0
- package/app/components/SearchModal.tsx +193 -0
- package/app/components/SettingsModal.tsx +237 -0
- package/app/components/Sidebar.tsx +136 -0
- package/app/components/SidebarLayout.tsx +36 -0
- package/app/components/TableOfContents.tsx +150 -0
- package/app/components/ThemeToggle.tsx +34 -0
- package/app/components/WysiwygEditor.tsx +75 -0
- package/app/components/ask/FileChip.tsx +30 -0
- package/app/components/ask/MentionPopover.tsx +52 -0
- package/app/components/ask/MessageList.tsx +126 -0
- package/app/components/ask/SessionHistory.tsx +49 -0
- package/app/components/renderers/AgentInspectorRenderer.tsx +277 -0
- package/app/components/renderers/BacklinksRenderer.tsx +147 -0
- package/app/components/renderers/ConfigRenderer.tsx +236 -0
- package/app/components/renderers/CsvRenderer.tsx +77 -0
- package/app/components/renderers/DiffRenderer.tsx +310 -0
- package/app/components/renderers/GraphRenderer.tsx +428 -0
- package/app/components/renderers/SummaryRenderer.tsx +251 -0
- package/app/components/renderers/TimelineRenderer.tsx +213 -0
- package/app/components/renderers/TodoRenderer.tsx +474 -0
- package/app/components/renderers/WorkflowRenderer.tsx +404 -0
- package/app/components/renderers/csv/BoardView.tsx +146 -0
- package/app/components/renderers/csv/ConfigPanel.tsx +117 -0
- package/app/components/renderers/csv/EditableCell.tsx +43 -0
- package/app/components/renderers/csv/GalleryView.tsx +40 -0
- package/app/components/renderers/csv/TableView.tsx +164 -0
- package/app/components/renderers/csv/types.ts +87 -0
- package/app/components/settings/AiTab.tsx +111 -0
- package/app/components/settings/AppearanceTab.tsx +101 -0
- package/app/components/settings/KnowledgeTab.tsx +157 -0
- package/app/components/settings/PluginsTab.tsx +82 -0
- package/app/components/settings/Primitives.tsx +60 -0
- package/app/components/settings/ShortcutsTab.tsx +22 -0
- package/app/components/settings/types.ts +41 -0
- package/app/components/ui/button.tsx +60 -0
- package/app/components/ui/dialog.tsx +157 -0
- package/app/components/ui/input.tsx +20 -0
- package/app/components/ui/scroll-area.tsx +55 -0
- package/app/components/ui/toggle.tsx +44 -0
- package/app/components/ui/tooltip.tsx +66 -0
- package/app/components.json +25 -0
- package/app/data/pages/home-dark.png +0 -0
- package/app/data/pages/home-mobile-crop.png +0 -0
- package/app/data/pages/home-mobile.png +0 -0
- package/app/data/pages/home.png +0 -0
- package/app/data/pages/view-dir.png +0 -0
- package/app/data/pages/view-file-bot.png +0 -0
- package/app/data/pages/view-file-dark-crop.png +0 -0
- package/app/data/pages/view-file-dark.png +0 -0
- package/app/data/pages/view-file-mobile.png +0 -0
- package/app/data/pages/view-file-sm.png +0 -0
- package/app/data/pages/view-file-top.png +0 -0
- package/app/data/pages/view-file.png +0 -0
- package/app/eslint.config.mjs +18 -0
- package/app/hooks/useAskSession.ts +181 -0
- package/app/hooks/useFileUpload.ts +126 -0
- package/app/hooks/useMention.ts +65 -0
- package/app/lib/LocaleContext.tsx +40 -0
- package/app/lib/actions.ts +40 -0
- package/app/lib/agent/index.ts +3 -0
- package/app/lib/agent/model.ts +18 -0
- package/app/lib/agent/prompt.ts +32 -0
- package/app/lib/agent/tools.ts +151 -0
- package/app/lib/api.ts +55 -0
- package/app/lib/core/backlinks.ts +40 -0
- package/app/lib/core/csv.ts +28 -0
- package/app/lib/core/fs-ops.ts +118 -0
- package/app/lib/core/git.ts +50 -0
- package/app/lib/core/index.ts +58 -0
- package/app/lib/core/lines.ts +89 -0
- package/app/lib/core/search.ts +79 -0
- package/app/lib/core/security.ts +43 -0
- package/app/lib/core/tree.ts +113 -0
- package/app/lib/core/types.ts +40 -0
- package/app/lib/fs.ts +467 -0
- package/app/lib/i18n.ts +300 -0
- package/app/lib/jwt.ts +58 -0
- package/app/lib/renderers/index.ts +79 -0
- package/app/lib/renderers/registry.ts +70 -0
- package/app/lib/settings.ts +150 -0
- package/app/lib/types.ts +32 -0
- package/app/lib/utils.ts +34 -0
- package/app/next-env.d.ts +6 -0
- package/app/next.config.ts +10 -0
- package/app/package-lock.json +15306 -0
- package/app/package.json +71 -0
- package/app/postcss.config.mjs +7 -0
- package/app/proxy.ts +64 -0
- package/app/public/file.svg +1 -0
- package/app/public/globe.svg +1 -0
- package/app/public/landing/index.html +353 -0
- package/app/public/landing/style.css +216 -0
- package/app/public/logo-square.svg +37 -0
- package/app/public/logo.svg +37 -0
- package/app/public/next.svg +1 -0
- package/app/public/vercel.svg +1 -0
- package/app/public/window.svg +1 -0
- package/app/scripts/extract-pdf.cjs +56 -0
- package/app/tsconfig.json +34 -0
- package/app/vitest.config.ts +14 -0
- package/assets/demo-flow-zh.html +622 -0
- package/assets/images/demo-flow-dark.png +0 -0
- package/assets/images/demo-flow-light.png +0 -0
- package/assets/images/demo-flow-zh-dark.png +0 -0
- package/assets/images/demo-flow-zh-light.png +0 -0
- package/assets/images/gui-sync-cv.png +0 -0
- package/assets/logo-square.svg +37 -0
- package/bin/cli.js +894 -0
- package/mcp/README.md +113 -0
- package/mcp/package-lock.json +1717 -0
- package/mcp/package.json +18 -0
- package/mcp/src/index.ts +494 -0
- package/mcp/tsconfig.json +13 -0
- package/package.json +49 -0
- package/scripts/setup.js +675 -0
- package/scripts/upgrade-prompt.md +147 -0
- package/skills/mindos/SKILL.md +319 -0
- package/skills/mindos-zh/SKILL.md +318 -0
- package/templates/README.md +31 -0
- package/templates/empty/CHANGELOG.md +9 -0
- package/templates/empty/CONFIG.json +197 -0
- package/templates/empty/CONFIG.md +73 -0
- package/templates/empty/INSTRUCTION.md +177 -0
- package/templates/empty/README.md +27 -0
- package/templates/en/CHANGELOG.md +9 -0
- package/templates/en/CONFIG.json +197 -0
- package/templates/en/CONFIG.md +73 -0
- package/templates/en/INSTRUCTION.md +177 -0
- package/templates/en/README.md +27 -0
- package/templates/en/TODO.md +13 -0
- package/templates/en//360/237/221/244 Profile/INSTRUCTION.md" +21 -0
- package/templates/en//360/237/221/244 Profile/README.md" +15 -0
- package/templates/en//360/237/221/244 Profile//342/232/231/357/270/217 Preferences.md" +21 -0
- package/templates/en//360/237/221/244 Profile//360/237/216/257 Focus.md" +31 -0
- package/templates/en//360/237/221/244 Profile//360/237/221/244 Identity.md" +22 -0
- package/templates/en//360/237/223/232 Resources/INSTRUCTION.md" +29 -0
- package/templates/en//360/237/223/232 Resources/README.md" +21 -0
- package/templates/en//360/237/223/232 Resources//360/237/247/276 AI Influencers.csv" +1 -0
- package/templates/en//360/237/223/232 Resources//360/237/247/276 AI Products.csv" +1 -0
- package/templates/en//360/237/223/232 Resources//360/237/247/276 AI Scholars.csv" +1 -0
- package/templates/en//360/237/223/232 Resources//360/237/247/276 AI Tools.csv" +1 -0
- package/templates/en//360/237/223/235 Notes/INSTRUCTION.md" +31 -0
- package/templates/en//360/237/223/235 Notes/Ideas/README.md" +8 -0
- package/templates/en//360/237/223/235 Notes/Ideas//360/237/247/252_example_product_idea.md" +16 -0
- package/templates/en//360/237/223/235 Notes/Inbox/README.md" +8 -0
- package/templates/en//360/237/223/235 Notes/Inbox//360/237/247/252_example_quick_capture.md" +14 -0
- package/templates/en//360/237/223/235 Notes/Meetings/README.md" +8 -0
- package/templates/en//360/237/223/235 Notes/Meetings//360/237/247/252_example_meeting_note.md" +17 -0
- package/templates/en//360/237/223/235 Notes/README.md" +24 -0
- package/templates/en//360/237/223/235 Notes/Waiting/README.md" +8 -0
- package/templates/en//360/237/223/235 Notes/Waiting//360/237/247/252_example_blocked_item.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Configurations/README.md" +3 -0
- package/templates/en//360/237/224/204 Workflows/Configurations//360/237/247/252_example_config_update_sop.md" +14 -0
- package/templates/en//360/237/224/204 Workflows/INSTRUCTION.md" +21 -0
- package/templates/en//360/237/224/204 Workflows/Information/README.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Information//360/237/247/252_example_info_capture_sop.md" +13 -0
- package/templates/en//360/237/224/204 Workflows/Media/README.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Media//360/237/247/252_example_content_publish_sop.md" +13 -0
- package/templates/en//360/237/224/204 Workflows/README.md" +22 -0
- package/templates/en//360/237/224/204 Workflows/Research/README.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Research//360/237/247/252_example_lit_review_sop.md" +16 -0
- package/templates/en//360/237/224/204 Workflows/Startup/README.md" +3 -0
- package/templates/en//360/237/224/204 Workflows/Startup//360/237/247/252_example_weekly_founder_ops.md" +22 -0
- package/templates/en//360/237/224/227 Connections/Classmates/README.md" +11 -0
- package/templates/en//360/237/224/227 Connections/Classmates//360/237/247/252_example_leo_chen.md" +16 -0
- package/templates/en//360/237/224/227 Connections/Colleagues/README.md" +11 -0
- package/templates/en//360/237/224/227 Connections/Colleagues//360/237/247/252_example_ethan_zhao.md" +16 -0
- package/templates/en//360/237/224/227 Connections/Connections Overview.csv" +5 -0
- package/templates/en//360/237/224/227 Connections/Family/README.md" +11 -0
- package/templates/en//360/237/224/227 Connections/Family//360/237/247/252_example_james_wang.md" +16 -0
- package/templates/en//360/237/224/227 Connections/Friends/README.md" +11 -0
- package/templates/en//360/237/224/227 Connections/Friends//360/237/247/252_example_lily_lin.md" +16 -0
- package/templates/en//360/237/224/227 Connections/INSTRUCTION.md" +56 -0
- package/templates/en//360/237/224/227 Connections/README.md" +20 -0
- package/templates/en//360/237/232/200 Projects/Archived/README.md" +9 -0
- package/templates/en//360/237/232/200 Projects/Archived//360/237/247/252_example_archived_project_note.md" +14 -0
- package/templates/en//360/237/232/200 Projects/INSTRUCTION.md" +29 -0
- package/templates/en//360/237/232/200 Projects/Products/README.md" +16 -0
- package/templates/en//360/237/232/200 Projects/Products//360/237/247/252_example_product_project_brief.md" +20 -0
- package/templates/en//360/237/232/200 Projects/README.md" +21 -0
- package/templates/en//360/237/232/200 Projects/Research/README.md" +16 -0
- package/templates/en//360/237/232/200 Projects/Research//360/237/247/252_example_research_project_brief.md" +16 -0
- package/templates/template-generation-skill.md +79 -0
- package/templates/zh/CHANGELOG.md +9 -0
- package/templates/zh/CONFIG.json +197 -0
- package/templates/zh/CONFIG.md +66 -0
- package/templates/zh/INSTRUCTION.md +177 -0
- package/templates/zh/README.md +27 -0
- package/templates/zh/TODO.md +13 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217/INSTRUCTION.md" +28 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217/README.md" +20 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217//342/232/231/357/270/217 Preferences.md" +21 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217//360/237/216/257 Focus.md" +31 -0
- package/templates/zh//360/237/221/244 /347/224/273/345/203/217//360/237/221/244 Identity.md" +22 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220/INSTRUCTION.md" +29 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220/README.md" +21 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220//360/237/247/276 AI Inferencers.csv" +1 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220//360/237/247/276 AI /344/272/247/345/223/201.csv" +1 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220//360/237/247/276 AI /345/255/246/350/200/205/346/270/205/345/215/225.csv" +1 -0
- package/templates/zh//360/237/223/232 /350/265/204/346/272/220//360/237/247/276 AI /345/267/245/345/205/267/346/270/205/345/215/225.csv" +1 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260/INSTRUCTION.md" +31 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260/README.md" +24 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//344/274/232/350/256/256/README.md" +8 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//344/274/232/350/256/256//360/237/247/252_example_/344/274/232/350/256/256/347/272/252/350/246/201.md" +17 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//345/276/205/345/217/215/351/246/210/README.md" +8 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//345/276/205/345/217/215/351/246/210//360/237/247/252_example_/345/276/205/345/217/215/351/246/210/344/272/213/351/241/271.md" +16 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//346/203/263/346/263/225/README.md" +8 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//346/203/263/346/263/225//360/237/247/252_example_/344/272/247/345/223/201/346/203/263/346/263/225.md" +16 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//346/224/266/344/273/266/347/256/261/README.md" +8 -0
- package/templates/zh//360/237/223/235 /347/254/224/350/256/260//346/224/266/344/273/266/347/256/261//360/237/247/252_example_/344/270/264/346/227/266/351/200/237/350/256/260.md" +13 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213/INSTRUCTION.md" +29 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213/README.md" +21 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//344/277/241/346/201/257/README.md" +16 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//344/277/241/346/201/257//360/237/247/252_example_/344/277/241/346/201/257/351/207/207/351/233/206/346/265/201/347/250/213.md" +13 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//345/252/222/344/275/223/README.md" +16 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//345/252/222/344/275/223//360/237/247/252_example_/345/206/205/345/256/271/345/217/221/345/270/203/346/265/201/347/250/213.md" +13 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//347/247/221/347/240/224/README.md" +16 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//347/247/221/347/240/224//360/237/247/252_example_/346/226/207/347/214/256/347/273/274/350/277/260/346/265/201/347/250/213.md" +16 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//351/205/215/347/275/256/README.md" +3 -0
- package/templates/zh//360/237/224/204 /346/265/201/347/250/213//351/205/215/347/275/256//360/237/247/252_example_/351/205/215/347/275/256/346/233/264/346/226/260/346/265/201/347/250/213.md" +26 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273/INSTRUCTION.md" +62 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273/README.md" +20 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/205/263/347/263/273/346/200/273/350/247/210.csv" +5 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/220/214/344/272/213/README.md" +11 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/220/214/344/272/213//360/237/247/252_example_/345/220/214/344/272/213/350/265/265/344/270/200/350/276/260.md" +16 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/220/214/345/255/246/README.md" +11 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/220/214/345/255/246//360/237/247/252_example_/345/220/214/345/255/246/351/231/210/347/253/213/346/254/247.md" +16 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/256/266/344/272/272/README.md" +11 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//345/256/266/344/272/272//360/237/247/252_example_/345/256/266/344/272/272/347/216/213/345/273/272/345/233/275.md" +16 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//346/234/213/345/217/213/README.md" +11 -0
- package/templates/zh//360/237/224/227 /345/205/263/347/263/273//346/234/213/345/217/213//360/237/247/252_example_/346/234/213/345/217/213/346/236/227/345/260/217/344/270/275.md" +16 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256/INSTRUCTION.md" +31 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256/README.md" +21 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//344/272/247/345/223/201/README.md" +16 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//344/272/247/345/223/201//360/237/247/252_example_/344/272/247/345/223/201/351/241/271/347/233/256/347/256/200/346/212/245.md" +20 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//345/267/262/345/275/222/346/241/243/README.md" +9 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//345/267/262/345/275/222/346/241/243//360/237/247/252_example_/345/275/222/346/241/243/351/241/271/347/233/256/350/256/260/345/275/225.md" +15 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//347/247/221/347/240/224/README.md" +16 -0
- package/templates/zh//360/237/232/200 /351/241/271/347/233/256//347/247/221/347/240/224//360/237/247/252_example_/347/247/221/347/240/224/351/241/271/347/233/256/347/256/200/346/212/245.md" +16 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Copy, Check, RefreshCw, Trash2 } from 'lucide-react';
|
|
5
|
+
import type { SettingsData } from './types';
|
|
6
|
+
import { Field, Input, EnvBadge, SectionLabel } from './Primitives';
|
|
7
|
+
import { apiFetch } from '@/lib/api';
|
|
8
|
+
|
|
9
|
+
interface KnowledgeTabProps {
|
|
10
|
+
data: SettingsData;
|
|
11
|
+
setData: React.Dispatch<React.SetStateAction<SettingsData | null>>;
|
|
12
|
+
t: any;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function KnowledgeTab({ data, setData, t }: KnowledgeTabProps) {
|
|
16
|
+
const env = data.envOverrides ?? {};
|
|
17
|
+
const k = t.settings.knowledge;
|
|
18
|
+
|
|
19
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
20
|
+
const isPasswordMasked = data.webPassword === '***set***';
|
|
21
|
+
|
|
22
|
+
const [copied, setCopied] = useState(false);
|
|
23
|
+
const [resetting, setResetting] = useState(false);
|
|
24
|
+
// revealed holds the plaintext token after regenerate, until user navigates away
|
|
25
|
+
const [revealedToken, setRevealedToken] = useState<string | null>(null);
|
|
26
|
+
|
|
27
|
+
const hasToken = !!(data.authToken);
|
|
28
|
+
const displayToken = revealedToken ?? data.authToken ?? '';
|
|
29
|
+
|
|
30
|
+
async function handleResetToken() {
|
|
31
|
+
if (!confirm(k.authTokenResetConfirm)) return;
|
|
32
|
+
setResetting(true);
|
|
33
|
+
try {
|
|
34
|
+
const res = await apiFetch<{ ok: boolean; token: string }>('/api/settings/reset-token', { method: 'POST' });
|
|
35
|
+
setRevealedToken(res.token);
|
|
36
|
+
setData(d => d ? { ...d, authToken: res.token } : d);
|
|
37
|
+
} finally {
|
|
38
|
+
setResetting(false);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function handleClearToken() {
|
|
43
|
+
setData(d => d ? { ...d, authToken: '' } : d);
|
|
44
|
+
setRevealedToken(null);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function handleCopy() {
|
|
48
|
+
const text = revealedToken ?? data.authToken ?? '';
|
|
49
|
+
if (!text) return;
|
|
50
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
51
|
+
setCopied(true);
|
|
52
|
+
setTimeout(() => setCopied(false), 2000);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className="space-y-5">
|
|
58
|
+
<SectionLabel>Knowledge Base</SectionLabel>
|
|
59
|
+
|
|
60
|
+
<Field
|
|
61
|
+
label={<>{k.sopRoot} <EnvBadge overridden={env.MIND_ROOT} /></>}
|
|
62
|
+
hint={env.MIND_ROOT ? k.envNote : k.sopRootHint}
|
|
63
|
+
>
|
|
64
|
+
<Input
|
|
65
|
+
value={data.mindRoot}
|
|
66
|
+
onChange={e => setData(d => d ? { ...d, mindRoot: e.target.value } : d)}
|
|
67
|
+
placeholder="/path/to/your/notes"
|
|
68
|
+
/>
|
|
69
|
+
</Field>
|
|
70
|
+
|
|
71
|
+
<div className="border-t border-border pt-5">
|
|
72
|
+
<SectionLabel>Security</SectionLabel>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<Field label={k.webPassword} hint={k.webPasswordHint}>
|
|
76
|
+
<div className="flex gap-2">
|
|
77
|
+
<Input
|
|
78
|
+
type={showPassword ? 'text' : 'password'}
|
|
79
|
+
value={isPasswordMasked ? '••••••••' : (data.webPassword ?? '')}
|
|
80
|
+
onChange={e => setData(d => d ? { ...d, webPassword: e.target.value } : d)}
|
|
81
|
+
onFocus={() => { if (isPasswordMasked) setData(d => d ? { ...d, webPassword: '' } : d); }}
|
|
82
|
+
placeholder="Leave empty to disable"
|
|
83
|
+
/>
|
|
84
|
+
<button
|
|
85
|
+
type="button"
|
|
86
|
+
onClick={() => setShowPassword(v => !v)}
|
|
87
|
+
className="px-3 py-2 text-xs rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted transition-colors shrink-0"
|
|
88
|
+
>
|
|
89
|
+
{showPassword ? 'Hide' : 'Show'}
|
|
90
|
+
</button>
|
|
91
|
+
</div>
|
|
92
|
+
</Field>
|
|
93
|
+
|
|
94
|
+
<Field
|
|
95
|
+
label={k.authToken}
|
|
96
|
+
hint={hasToken ? k.authTokenHint : k.authTokenNone}
|
|
97
|
+
>
|
|
98
|
+
<div className="space-y-2">
|
|
99
|
+
{/* Token display */}
|
|
100
|
+
<div className="flex items-center gap-2 px-3 py-2 bg-background border border-border rounded-lg min-h-[38px]">
|
|
101
|
+
<code className="flex-1 text-xs font-mono text-foreground break-all select-all">
|
|
102
|
+
{displayToken || <span className="text-muted-foreground italic">— not set —</span>}
|
|
103
|
+
</code>
|
|
104
|
+
{displayToken && (
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
onClick={handleCopy}
|
|
108
|
+
className="shrink-0 p-1 rounded text-muted-foreground hover:text-foreground transition-colors"
|
|
109
|
+
title={k.authTokenCopy}
|
|
110
|
+
>
|
|
111
|
+
{copied ? <Check size={13} className="text-green-500" /> : <Copy size={13} />}
|
|
112
|
+
</button>
|
|
113
|
+
)}
|
|
114
|
+
</div>
|
|
115
|
+
{/* MCP port info */}
|
|
116
|
+
{data.mcpPort && (
|
|
117
|
+
<p className="text-xs text-muted-foreground">
|
|
118
|
+
{k.authTokenMcpPort}: <code className="font-mono">{data.mcpPort}</code>
|
|
119
|
+
{displayToken && (
|
|
120
|
+
<> · MCP URL: <code className="font-mono select-all">
|
|
121
|
+
{typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.hostname}:${data.mcpPort}/mcp` : `http://localhost:${data.mcpPort}/mcp`}
|
|
122
|
+
</code></>
|
|
123
|
+
)}
|
|
124
|
+
</p>
|
|
125
|
+
)}
|
|
126
|
+
{/* Action buttons */}
|
|
127
|
+
<div className="flex gap-2">
|
|
128
|
+
<button
|
|
129
|
+
type="button"
|
|
130
|
+
onClick={handleResetToken}
|
|
131
|
+
disabled={resetting}
|
|
132
|
+
className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-lg border border-border text-muted-foreground hover:text-foreground hover:bg-muted disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
|
133
|
+
>
|
|
134
|
+
<RefreshCw size={12} className={resetting ? 'animate-spin' : ''} />
|
|
135
|
+
{k.authTokenReset}
|
|
136
|
+
</button>
|
|
137
|
+
{hasToken && (
|
|
138
|
+
<button
|
|
139
|
+
type="button"
|
|
140
|
+
onClick={handleClearToken}
|
|
141
|
+
className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-lg border border-border text-muted-foreground hover:text-destructive hover:border-destructive/50 transition-colors"
|
|
142
|
+
>
|
|
143
|
+
<Trash2 size={12} />
|
|
144
|
+
{k.authTokenClear}
|
|
145
|
+
</button>
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
{revealedToken && (
|
|
149
|
+
<p className="text-xs text-amber-500">
|
|
150
|
+
New token generated. Copy it now — it won't be shown in full again.
|
|
151
|
+
</p>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
</Field>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Puzzle } from 'lucide-react';
|
|
4
|
+
import { getAllRenderers, setRendererEnabled } from '@/lib/renderers/registry';
|
|
5
|
+
|
|
6
|
+
interface PluginsTabProps {
|
|
7
|
+
pluginStates: Record<string, boolean>;
|
|
8
|
+
setPluginStates: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
|
|
9
|
+
t: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function PluginsTab({ pluginStates, setPluginStates, t }: PluginsTabProps) {
|
|
13
|
+
return (
|
|
14
|
+
<div className="space-y-5">
|
|
15
|
+
<p className="text-xs font-medium text-muted-foreground uppercase tracking-wider">{t.settings.plugins.title}</p>
|
|
16
|
+
|
|
17
|
+
{getAllRenderers().length === 0 ? (
|
|
18
|
+
<p className="text-sm text-muted-foreground">{t.settings.plugins.noPlugins}</p>
|
|
19
|
+
) : (
|
|
20
|
+
<div className="flex flex-col gap-3">
|
|
21
|
+
{getAllRenderers().map(renderer => {
|
|
22
|
+
const enabled = pluginStates[renderer.id] ?? true;
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
key={renderer.id}
|
|
26
|
+
className={`border rounded-xl p-4 transition-colors ${enabled ? 'border-border bg-card' : 'border-border/50 bg-muted/30 opacity-60'}`}
|
|
27
|
+
>
|
|
28
|
+
<div className="flex items-start justify-between gap-3">
|
|
29
|
+
<div className="flex items-start gap-3">
|
|
30
|
+
<span className="text-2xl leading-none mt-0.5">{renderer.icon}</span>
|
|
31
|
+
<div className="min-w-0">
|
|
32
|
+
<div className="flex items-center gap-2 flex-wrap">
|
|
33
|
+
<span className="text-sm font-medium text-foreground">{renderer.name}</span>
|
|
34
|
+
{renderer.builtin && (
|
|
35
|
+
<span className="text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground font-mono">
|
|
36
|
+
{t.settings.plugins.builtinBadge}
|
|
37
|
+
</span>
|
|
38
|
+
)}
|
|
39
|
+
<div className="flex gap-1 flex-wrap">
|
|
40
|
+
{renderer.tags.map(tag => (
|
|
41
|
+
<span key={tag} className="text-[10px] px-1.5 py-0.5 rounded bg-muted/60 text-muted-foreground">
|
|
42
|
+
{tag}
|
|
43
|
+
</span>
|
|
44
|
+
))}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<p className="text-xs text-muted-foreground mt-1 leading-relaxed">{renderer.description}</p>
|
|
48
|
+
<p className="text-[11px] text-muted-foreground/60 mt-1.5 font-mono">
|
|
49
|
+
{t.settings.plugins.matchHint}: <code className="bg-muted px-1 rounded">{renderer.match.toString().match(/\/(.+)\//)?.[1] ?? '—'}</code>
|
|
50
|
+
</p>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<button
|
|
55
|
+
onClick={() => {
|
|
56
|
+
const next = !enabled;
|
|
57
|
+
setRendererEnabled(renderer.id, next);
|
|
58
|
+
setPluginStates(s => ({ ...s, [renderer.id]: next }));
|
|
59
|
+
}}
|
|
60
|
+
role="switch"
|
|
61
|
+
aria-checked={enabled}
|
|
62
|
+
className={`shrink-0 w-9 h-5 rounded-full transition-colors relative ${enabled ? 'bg-amber-600' : 'bg-muted border border-border'}`}
|
|
63
|
+
title={enabled ? t.settings.plugins.enabled : t.settings.plugins.disabled}
|
|
64
|
+
>
|
|
65
|
+
<span
|
|
66
|
+
className={`absolute top-[3px] w-3.5 h-3.5 rounded-full shadow-sm transition-all ${enabled ? 'left-[18px] bg-white' : 'left-[3px] bg-muted-foreground/50'}`}
|
|
67
|
+
/>
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
})}
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
<div className="flex items-center gap-2 text-xs text-muted-foreground border border-dashed border-border rounded-xl px-4 py-3">
|
|
77
|
+
<Puzzle size={13} className="shrink-0" />
|
|
78
|
+
<span>{t.settings.plugins.comingSoon}</span>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
export function SectionLabel({ children }: { children: React.ReactNode }) {
|
|
4
|
+
return <p className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3">{children}</p>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function Field({ label, hint, children }: { label: React.ReactNode; hint?: string; children: React.ReactNode }) {
|
|
8
|
+
return (
|
|
9
|
+
<div className="space-y-1.5">
|
|
10
|
+
<label className="text-sm text-foreground font-medium">{label}</label>
|
|
11
|
+
{children}
|
|
12
|
+
{hint && <p className="text-xs text-muted-foreground">{hint}</p>}
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function Input({ className = '', ...props }: React.InputHTMLAttributes<HTMLInputElement>) {
|
|
18
|
+
return (
|
|
19
|
+
<input
|
|
20
|
+
{...props}
|
|
21
|
+
className={`w-full px-3 py-2 text-sm bg-background border border-border rounded-lg text-foreground placeholder:text-muted-foreground outline-none focus:ring-1 focus:ring-ring disabled:opacity-50 ${className}`}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function Select({ className = '', ...props }: React.SelectHTMLAttributes<HTMLSelectElement>) {
|
|
27
|
+
return (
|
|
28
|
+
<select
|
|
29
|
+
{...props}
|
|
30
|
+
className={`w-full px-3 py-2 text-sm bg-background border border-border rounded-lg text-foreground outline-none focus:ring-1 focus:ring-ring disabled:opacity-50 ${className}`}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function EnvBadge({ overridden }: { overridden: boolean }) {
|
|
36
|
+
if (!overridden) return null;
|
|
37
|
+
return (
|
|
38
|
+
<span className="text-[10px] px-1.5 py-0.5 rounded bg-amber-500/15 text-amber-500 font-mono ml-1.5">env</span>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function ApiKeyInput({ value, onChange, placeholder, disabled }: {
|
|
43
|
+
value: string;
|
|
44
|
+
onChange: (v: string) => void;
|
|
45
|
+
placeholder?: string;
|
|
46
|
+
disabled?: boolean;
|
|
47
|
+
}) {
|
|
48
|
+
const isMasked = value === '***set***';
|
|
49
|
+
return (
|
|
50
|
+
<input
|
|
51
|
+
type="password"
|
|
52
|
+
value={isMasked ? '••••••••••••••••' : value}
|
|
53
|
+
onChange={e => onChange(e.target.value)}
|
|
54
|
+
placeholder={placeholder ?? 'sk-...'}
|
|
55
|
+
disabled={disabled}
|
|
56
|
+
className="w-full px-3 py-2 text-sm bg-background border border-border rounded-lg text-foreground placeholder:text-muted-foreground outline-none focus:ring-1 focus:ring-ring disabled:opacity-50"
|
|
57
|
+
onFocus={() => { if (isMasked) onChange(''); }}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
interface ShortcutsTabProps {
|
|
4
|
+
t: any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function ShortcutsTab({ t }: ShortcutsTabProps) {
|
|
8
|
+
return (
|
|
9
|
+
<div className="space-y-1">
|
|
10
|
+
{t.shortcuts.map((s: { description: string; keys: string[] }, i: number) => (
|
|
11
|
+
<div key={i} className="flex items-center justify-between py-2.5 border-b border-border last:border-0">
|
|
12
|
+
<span className="text-sm text-foreground">{s.description}</span>
|
|
13
|
+
<div className="flex items-center gap-1">
|
|
14
|
+
{s.keys.map((k: string, j: number) => (
|
|
15
|
+
<kbd key={j} className="px-2 py-0.5 text-xs font-mono bg-muted border border-border rounded text-foreground">{k}</kbd>
|
|
16
|
+
))}
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
))}
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Locale } from '@/lib/i18n';
|
|
2
|
+
|
|
3
|
+
export interface ProviderConfig {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
model: string;
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface AiSettings {
|
|
10
|
+
provider: 'anthropic' | 'openai';
|
|
11
|
+
providers: {
|
|
12
|
+
anthropic?: ProviderConfig;
|
|
13
|
+
openai?: ProviderConfig;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface SettingsData {
|
|
18
|
+
ai: AiSettings;
|
|
19
|
+
mindRoot: string;
|
|
20
|
+
webPassword?: string;
|
|
21
|
+
authToken?: string; // masked: first-xxxx-••••-last pattern
|
|
22
|
+
mcpPort?: number;
|
|
23
|
+
envOverrides?: Record<string, boolean>;
|
|
24
|
+
envValues?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type Tab = 'ai' | 'appearance' | 'knowledge' | 'plugins' | 'shortcuts';
|
|
28
|
+
|
|
29
|
+
export const CONTENT_WIDTHS = [
|
|
30
|
+
{ value: '680px', label: 'Narrow (680px)' },
|
|
31
|
+
{ value: '780px', label: 'Default (780px)' },
|
|
32
|
+
{ value: '960px', label: 'Wide (960px)' },
|
|
33
|
+
{ value: '100%', label: 'Full width' },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export const FONTS = [
|
|
37
|
+
{ value: 'lora', label: 'Lora (serif)', style: { fontFamily: 'Lora, Georgia, serif' } },
|
|
38
|
+
{ value: 'ibm-plex-sans', label: 'IBM Plex Sans', style: { fontFamily: "'IBM Plex Sans', sans-serif" } },
|
|
39
|
+
{ value: 'geist', label: 'Geist', style: { fontFamily: 'var(--font-geist-sans), sans-serif' } },
|
|
40
|
+
{ value: 'ibm-plex-mono', label: 'IBM Plex Mono (mono)', style: { fontFamily: "'IBM Plex Mono', monospace" } },
|
|
41
|
+
];
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
const buttonVariants = cva(
|
|
9
|
+
"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
14
|
+
outline:
|
|
15
|
+
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
16
|
+
secondary:
|
|
17
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
18
|
+
ghost:
|
|
19
|
+
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
20
|
+
destructive:
|
|
21
|
+
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
|
22
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
default:
|
|
26
|
+
"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
27
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
28
|
+
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
29
|
+
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
|
|
30
|
+
icon: "size-8",
|
|
31
|
+
"icon-xs":
|
|
32
|
+
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
|
|
33
|
+
"icon-sm":
|
|
34
|
+
"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
|
|
35
|
+
"icon-lg": "size-9",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultVariants: {
|
|
39
|
+
variant: "default",
|
|
40
|
+
size: "default",
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
function Button({
|
|
46
|
+
className,
|
|
47
|
+
variant = "default",
|
|
48
|
+
size = "default",
|
|
49
|
+
...props
|
|
50
|
+
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
|
51
|
+
return (
|
|
52
|
+
<ButtonPrimitive
|
|
53
|
+
data-slot="button"
|
|
54
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { Button } from "@/components/ui/button"
|
|
8
|
+
import { XIcon } from "lucide-react"
|
|
9
|
+
|
|
10
|
+
function Dialog({ ...props }: DialogPrimitive.Root.Props) {
|
|
11
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
|
|
15
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
|
|
19
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
|
|
23
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function DialogOverlay({
|
|
27
|
+
className,
|
|
28
|
+
...props
|
|
29
|
+
}: DialogPrimitive.Backdrop.Props) {
|
|
30
|
+
return (
|
|
31
|
+
<DialogPrimitive.Backdrop
|
|
32
|
+
data-slot="dialog-overlay"
|
|
33
|
+
className={cn(
|
|
34
|
+
"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
35
|
+
className
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function DialogContent({
|
|
43
|
+
className,
|
|
44
|
+
children,
|
|
45
|
+
showCloseButton = true,
|
|
46
|
+
...props
|
|
47
|
+
}: DialogPrimitive.Popup.Props & {
|
|
48
|
+
showCloseButton?: boolean
|
|
49
|
+
}) {
|
|
50
|
+
return (
|
|
51
|
+
<DialogPortal>
|
|
52
|
+
<DialogOverlay />
|
|
53
|
+
<DialogPrimitive.Popup
|
|
54
|
+
data-slot="dialog-content"
|
|
55
|
+
className={cn(
|
|
56
|
+
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-background p-4 text-sm ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
57
|
+
className
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
>
|
|
61
|
+
{children}
|
|
62
|
+
{showCloseButton && (
|
|
63
|
+
<DialogPrimitive.Close
|
|
64
|
+
data-slot="dialog-close"
|
|
65
|
+
render={
|
|
66
|
+
<Button
|
|
67
|
+
variant="ghost"
|
|
68
|
+
className="absolute top-2 right-2"
|
|
69
|
+
size="icon-sm"
|
|
70
|
+
/>
|
|
71
|
+
}
|
|
72
|
+
>
|
|
73
|
+
<XIcon
|
|
74
|
+
/>
|
|
75
|
+
<span className="sr-only">Close</span>
|
|
76
|
+
</DialogPrimitive.Close>
|
|
77
|
+
)}
|
|
78
|
+
</DialogPrimitive.Popup>
|
|
79
|
+
</DialogPortal>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
data-slot="dialog-header"
|
|
87
|
+
className={cn("flex flex-col gap-2", className)}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function DialogFooter({
|
|
94
|
+
className,
|
|
95
|
+
showCloseButton = false,
|
|
96
|
+
children,
|
|
97
|
+
...props
|
|
98
|
+
}: React.ComponentProps<"div"> & {
|
|
99
|
+
showCloseButton?: boolean
|
|
100
|
+
}) {
|
|
101
|
+
return (
|
|
102
|
+
<div
|
|
103
|
+
data-slot="dialog-footer"
|
|
104
|
+
className={cn(
|
|
105
|
+
"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
|
|
106
|
+
className
|
|
107
|
+
)}
|
|
108
|
+
{...props}
|
|
109
|
+
>
|
|
110
|
+
{children}
|
|
111
|
+
{showCloseButton && (
|
|
112
|
+
<DialogPrimitive.Close render={<Button variant="outline" />}>
|
|
113
|
+
Close
|
|
114
|
+
</DialogPrimitive.Close>
|
|
115
|
+
)}
|
|
116
|
+
</div>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
|
|
121
|
+
return (
|
|
122
|
+
<DialogPrimitive.Title
|
|
123
|
+
data-slot="dialog-title"
|
|
124
|
+
className={cn("text-base leading-none font-medium", className)}
|
|
125
|
+
{...props}
|
|
126
|
+
/>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function DialogDescription({
|
|
131
|
+
className,
|
|
132
|
+
...props
|
|
133
|
+
}: DialogPrimitive.Description.Props) {
|
|
134
|
+
return (
|
|
135
|
+
<DialogPrimitive.Description
|
|
136
|
+
data-slot="dialog-description"
|
|
137
|
+
className={cn(
|
|
138
|
+
"text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
139
|
+
className
|
|
140
|
+
)}
|
|
141
|
+
{...props}
|
|
142
|
+
/>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export {
|
|
147
|
+
Dialog,
|
|
148
|
+
DialogClose,
|
|
149
|
+
DialogContent,
|
|
150
|
+
DialogDescription,
|
|
151
|
+
DialogFooter,
|
|
152
|
+
DialogHeader,
|
|
153
|
+
DialogOverlay,
|
|
154
|
+
DialogPortal,
|
|
155
|
+
DialogTitle,
|
|
156
|
+
DialogTrigger,
|
|
157
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Input as InputPrimitive } from "@base-ui/react/input"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
7
|
+
return (
|
|
8
|
+
<InputPrimitive
|
|
9
|
+
type={type}
|
|
10
|
+
data-slot="input"
|
|
11
|
+
className={cn(
|
|
12
|
+
"h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { Input }
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
function ScrollArea({
|
|
9
|
+
className,
|
|
10
|
+
children,
|
|
11
|
+
...props
|
|
12
|
+
}: ScrollAreaPrimitive.Root.Props) {
|
|
13
|
+
return (
|
|
14
|
+
<ScrollAreaPrimitive.Root
|
|
15
|
+
data-slot="scroll-area"
|
|
16
|
+
className={cn("relative", className)}
|
|
17
|
+
{...props}
|
|
18
|
+
>
|
|
19
|
+
<ScrollAreaPrimitive.Viewport
|
|
20
|
+
data-slot="scroll-area-viewport"
|
|
21
|
+
className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
|
|
22
|
+
>
|
|
23
|
+
{children}
|
|
24
|
+
</ScrollAreaPrimitive.Viewport>
|
|
25
|
+
<ScrollBar />
|
|
26
|
+
<ScrollAreaPrimitive.Corner />
|
|
27
|
+
</ScrollAreaPrimitive.Root>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ScrollBar({
|
|
32
|
+
className,
|
|
33
|
+
orientation = "vertical",
|
|
34
|
+
...props
|
|
35
|
+
}: ScrollAreaPrimitive.Scrollbar.Props) {
|
|
36
|
+
return (
|
|
37
|
+
<ScrollAreaPrimitive.Scrollbar
|
|
38
|
+
data-slot="scroll-area-scrollbar"
|
|
39
|
+
data-orientation={orientation}
|
|
40
|
+
orientation={orientation}
|
|
41
|
+
className={cn(
|
|
42
|
+
"flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent",
|
|
43
|
+
className
|
|
44
|
+
)}
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
<ScrollAreaPrimitive.Thumb
|
|
48
|
+
data-slot="scroll-area-thumb"
|
|
49
|
+
className="relative flex-1 rounded-full bg-border"
|
|
50
|
+
/>
|
|
51
|
+
</ScrollAreaPrimitive.Scrollbar>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { ScrollArea, ScrollBar }
|