@pheem49/mint 1.5.5 → 1.6.1
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/.codex +0 -0
- package/.github/FUNDING.yml +2 -0
- package/.github/workflows/ci.yml +45 -0
- package/.github/workflows/release.yml +79 -0
- package/Cargo.lock +5792 -0
- package/Cargo.toml +32 -0
- package/README.md +387 -353
- package/assets/icon.png +0 -0
- package/bin/mint +0 -0
- package/crates/mint-cli/Cargo.toml +23 -0
- package/crates/mint-cli/src/agent.rs +851 -0
- package/crates/mint-cli/src/gmail.rs +216 -0
- package/crates/mint-cli/src/image.rs +142 -0
- package/crates/mint-cli/src/main.rs +2837 -0
- package/crates/mint-cli/src/mcp.rs +63 -0
- package/crates/mint-cli/src/onboard.rs +1149 -0
- package/crates/mint-cli/src/setup.rs +390 -0
- package/crates/mint-cli/src/skills.rs +8 -0
- package/crates/mint-cli/src/updater.rs +279 -0
- package/crates/mint-core/Cargo.toml +22 -0
- package/crates/mint-core/src/agent_loop.rs +94 -0
- package/crates/mint-core/src/api_server.rs +991 -0
- package/crates/mint-core/src/channels.rs +248 -0
- package/crates/mint-core/src/chat.rs +895 -0
- package/crates/mint-core/src/code_tools.rs +729 -0
- package/crates/mint-core/src/config.rs +368 -0
- package/crates/mint-core/src/files.rs +159 -0
- package/crates/mint-core/src/knowledge.rs +541 -0
- package/crates/mint-core/src/lib.rs +84 -0
- package/crates/mint-core/src/mcp.rs +273 -0
- package/crates/mint-core/src/memory.rs +673 -0
- package/crates/mint-core/src/orchestration.rs +2157 -0
- package/crates/mint-core/src/pictures.rs +314 -0
- package/crates/mint-core/src/plugins.rs +727 -0
- package/crates/mint-core/src/safety.rs +416 -0
- package/crates/mint-core/src/semantic.rs +254 -0
- package/crates/mint-core/src/shell.rs +317 -0
- package/crates/mint-core/src/skills.rs +71 -0
- package/crates/mint-core/src/symbols.rs +157 -0
- package/crates/mint-core/src/tasks.rs +308 -0
- package/crates/mint-core/src/tts.rs +92 -0
- package/crates/mint-core/src/weather.rs +93 -0
- package/crates/mint-core/src/web_search.rs +200 -0
- package/crates/mint-core/src/workflows.rs +81 -0
- package/crates/mint-core/tests/mcp_stdio.rs +45 -0
- package/crates/mint-core/tests/memory_persistence.rs +172 -0
- package/crates/mint-core/tests/pictures_storage.rs +14 -0
- package/crates/mint-core/tests/task_lifecycle.rs +87 -0
- package/package.json +35 -99
- package/src/bin/index.js +16 -0
- package/src/renderer/index-web.html +17 -0
- package/src/renderer/index.html +17 -0
- package/src/renderer/public/Live2DCubismCore.js +9 -0
- package/src/renderer/public/assets/icon.png +0 -0
- package/src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.model3.json +36 -0
- package/src/renderer/src/App.tsx +33 -0
- package/src/renderer/src/calculator.ts +47 -0
- package/src/renderer/src/components/ChatPanel.tsx +1598 -0
- package/src/renderer/src/components/DashboardSidebar.tsx +358 -0
- package/src/renderer/src/components/Live2DStage.tsx +374 -0
- package/src/renderer/src/components/MintDashboard.tsx +950 -0
- package/src/renderer/src/components/ModelPanel.tsx +154 -0
- package/src/renderer/src/components/PicturesLibrary.tsx +46 -0
- package/src/renderer/src/components/ProactiveGlow.tsx +19 -0
- package/src/renderer/src/components/ScreenPicker.tsx +579 -0
- package/src/renderer/src/components/SettingsWindow.tsx +1467 -0
- package/src/renderer/src/components/SpotlightWindow.tsx +280 -0
- package/src/renderer/src/components/WidgetWindow.tsx +36 -0
- package/src/renderer/src/components/WorkspacePanel.tsx +268 -0
- package/src/{UI → renderer/src/css}/settings.css +69 -16
- package/src/renderer/src/css/spotlight.css +113 -0
- package/src/renderer/src/css/styles.css +3722 -0
- package/src/renderer/src/css/widget.css +185 -0
- package/src/renderer/src/env.d.ts +116 -0
- package/src/renderer/src/index.css +379 -0
- package/src/renderer/src/main.tsx +13 -0
- package/src/renderer/src/tauri.ts +996 -0
- package/src/renderer/src-web/App.tsx +25 -0
- package/src/renderer/src-web/calculator.ts +47 -0
- package/src/renderer/src-web/components/ChatPanel.tsx +1662 -0
- package/src/renderer/src-web/components/DashboardSidebar.tsx +242 -0
- package/src/renderer/src-web/components/MintDashboard.tsx +763 -0
- package/src/renderer/src-web/components/PicturesLibrary.tsx +73 -0
- package/src/renderer/src-web/components/SettingsWindow.tsx +1500 -0
- package/src/renderer/src-web/css/settings.css +1100 -0
- package/src/{UI → renderer/src-web/css}/spotlight.css +4 -4
- package/src/{UI → renderer/src-web/css}/styles.css +1055 -159
- package/src/{UI → renderer/src-web/css}/widget.css +2 -2
- package/src/renderer/src-web/env.d.ts +107 -0
- package/src/renderer/src-web/index.css +379 -0
- package/src/renderer/src-web/main.tsx +13 -0
- package/src/renderer/src-web/tauri.ts +983 -0
- package/tsconfig.json +30 -0
- package/vite.config.ts +33 -0
- package/vite.config.web.ts +51 -0
- package/GUIDE_TH.md +0 -125
- package/assets/Agent_Mint.png +0 -0
- package/assets/CLI_Screen.png +0 -0
- package/assets/Settings.png +0 -0
- package/benchmark_ai.js +0 -71
- package/install.ps1 +0 -64
- package/install.sh +0 -54
- package/main.js +0 -139
- package/mint-cli-logic.js +0 -3
- package/mint-cli.js +0 -410
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.model3.json +0 -47
- package/models/Shiroko_Model/Shiroko//342/232/241/351/253/230/344/272/256/342/232/241/344/275/277/347/224/250/346/225/231/347/250/213/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.txt +0 -23
- package/preload-picker.js +0 -11
- package/preload-settings.js +0 -11
- package/preload.js +0 -41
- package/scripts/install_linux_desktop_entry.js +0 -48
- package/src/AI_Brain/Gemini_API.js +0 -813
- package/src/AI_Brain/agent_orchestrator.js +0 -73
- package/src/AI_Brain/autonomous_brain.js +0 -179
- package/src/AI_Brain/behavior_memory.js +0 -135
- package/src/AI_Brain/headless_agent.js +0 -143
- package/src/AI_Brain/knowledge_base.js +0 -349
- package/src/AI_Brain/memory_store.js +0 -662
- package/src/AI_Brain/proactive_engine.js +0 -172
- package/src/AI_Brain/provider_adapter.js +0 -365
- package/src/Automation_Layer/browser_automation.js +0 -149
- package/src/Automation_Layer/file_operations.js +0 -286
- package/src/Automation_Layer/open_app.js +0 -85
- package/src/Automation_Layer/open_website.js +0 -38
- package/src/CLI/approval_handler.js +0 -47
- package/src/CLI/chat_router.js +0 -247
- package/src/CLI/chat_ui.js +0 -1159
- package/src/CLI/cli_colors.js +0 -115
- package/src/CLI/cli_formatters.js +0 -94
- package/src/CLI/code_agent.js +0 -1667
- package/src/CLI/code_session_memory.js +0 -62
- package/src/CLI/gmail_auth.js +0 -210
- package/src/CLI/image_input.js +0 -90
- package/src/CLI/intent_detectors.js +0 -181
- package/src/CLI/interactive_chat.js +0 -658
- package/src/CLI/list_features.js +0 -64
- package/src/CLI/onboarding.js +0 -416
- package/src/CLI/repo_summarizer.js +0 -282
- package/src/CLI/semantic_code_search.js +0 -312
- package/src/CLI/skill_manager.js +0 -41
- package/src/CLI/slash_command_handler.js +0 -418
- package/src/CLI/symbol_indexer.js +0 -231
- package/src/CLI/updater.js +0 -230
- package/src/CLI/workspace_manager.js +0 -90
- package/src/Channels/brave_search_bridge.js +0 -35
- package/src/Channels/discord_bridge.js +0 -66
- package/src/Channels/google_search_bridge.js +0 -38
- package/src/Channels/line_bridge.js +0 -60
- package/src/Channels/slack_bridge.js +0 -48
- package/src/Channels/telegram_bridge.js +0 -41
- package/src/Channels/whatsapp_bridge.js +0 -57
- package/src/Command_Parser/parser.js +0 -45
- package/src/Plugins/dev_tools.js +0 -41
- package/src/Plugins/discord.js +0 -20
- package/src/Plugins/docker.js +0 -47
- package/src/Plugins/gmail.js +0 -251
- package/src/Plugins/google_calendar.js +0 -252
- package/src/Plugins/mcp_manager.js +0 -95
- package/src/Plugins/notion.js +0 -256
- package/src/Plugins/obsidian.js +0 -54
- package/src/Plugins/plugin_manager.js +0 -81
- package/src/Plugins/spotify.js +0 -173
- package/src/Plugins/system_metrics.js +0 -31
- package/src/Plugins/system_monitor.js +0 -72
- package/src/System/action_executor.js +0 -178
- package/src/System/bridge_manager.js +0 -76
- package/src/System/chat_history_manager.js +0 -83
- package/src/System/config_manager.js +0 -194
- package/src/System/custom_workflows.js +0 -163
- package/src/System/daemon_manager.js +0 -67
- package/src/System/google_tts_urls.js +0 -51
- package/src/System/granular_automation.js +0 -157
- package/src/System/ipc_handlers.js +0 -332
- package/src/System/notifications.js +0 -23
- package/src/System/optional_require.js +0 -23
- package/src/System/picture_store.js +0 -109
- package/src/System/proactive_loop.js +0 -153
- package/src/System/safety_manager.js +0 -273
- package/src/System/sandbox_runner.js +0 -182
- package/src/System/screen_capture.js +0 -175
- package/src/System/smart_context.js +0 -227
- package/src/System/system_automation.js +0 -162
- package/src/System/system_events.js +0 -79
- package/src/System/system_info.js +0 -125
- package/src/System/task_manager.js +0 -222
- package/src/System/tool_registry.js +0 -293
- package/src/System/window_manager.js +0 -220
- package/src/UI/floating.css +0 -80
- package/src/UI/floating.html +0 -17
- package/src/UI/floating.js +0 -67
- package/src/UI/live2d_manager.js +0 -600
- package/src/UI/preload-floating.js +0 -7
- package/src/UI/preload-spotlight.js +0 -11
- package/src/UI/preload-widget.js +0 -5
- package/src/UI/proactive-glow.html +0 -42
- package/src/UI/renderer.js +0 -2127
- package/src/UI/screenPicker.html +0 -214
- package/src/UI/screenPicker.js +0 -262
- package/src/UI/settings.html +0 -577
- package/src/UI/settings.js +0 -770
- package/src/UI/spotlight.html +0 -23
- package/src/UI/spotlight.js +0 -185
- package/src/UI/widget.html +0 -29
- package/src/UI/widget.js +0 -10
- /package/{models → src/renderer/public/models}/Shiroko_Model/Shiroko/Shiroko_Core/72d86db84cfa9730b894c241fd24c0db.png +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/233/264/350/243/231.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/apron.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/214/253/345/222/252/346/273/244/351/225/234.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/catfilter.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/202/271/344/270/200/344/270/213.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/click.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/dazed.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253/347/234/274/347/217/240/346/221/207/346/231/203.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/dazedeyes.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/234/274/351/225/234.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/glasses.exp3.json} +0 -0
- /package/{models → src/renderer/public/models}/Shiroko_Model/Shiroko/Shiroko_Core/items_pinned_to_model.json +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/277/347/254/224.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/pen.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/215/347/205/247.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/photo.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_00.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_00.png} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_01.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_01.png} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_02.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_02.png} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_03.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_03.png} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.cdi3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.cdi3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.moc3" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.moc3} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.physics3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.physics3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.vtube.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.vtube.json} +0 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react'
|
|
2
|
+
import { evaluateArithmetic } from '../calculator'
|
|
3
|
+
|
|
4
|
+
const COMMANDS = [
|
|
5
|
+
{ label: 'Open YouTube', desc: 'เปิดเว็บไซต์ YouTube', icon: '📺', action: { type: 'open_url', target: 'https://youtube.com' } },
|
|
6
|
+
{ label: 'Open Facebook', desc: 'เปิดเว็บไซต์ Facebook', icon: '📘', action: { type: 'open_url', target: 'https://facebook.com' } },
|
|
7
|
+
{ label: 'Open Instagram', desc: 'เปิดเว็บไซต์ Instagram', icon: '📸', action: { type: 'open_url', target: 'https://instagram.com' } },
|
|
8
|
+
{ label: 'Open GitHub', desc: 'เปิดเว็บไซต์ GitHub', icon: '🐙', action: { type: 'open_url', target: 'https://github.com' } },
|
|
9
|
+
{ label: 'System Info', desc: 'ดูข้อมูลระบบ', icon: '💻', action: { type: 'chat', query: 'ขอข้อมูลระบบหน่อย' } },
|
|
10
|
+
{ label: 'Weather', desc: 'เช็คสภาพอากาศ', icon: '🌤️', action: { type: 'chat', query: 'อากาศที่กรุงเทพเป็นยังไง' } },
|
|
11
|
+
{ label: 'Open Spotify', desc: 'เปิดโปรแกรม Spotify', icon: '🎵', action: { type: 'open_app', target: 'spotify' } },
|
|
12
|
+
{ label: 'Open VS Code', desc: 'เปิดโปรแกรม VS Code', icon: '💻', action: { type: 'open_app', target: 'code' } },
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
function getCommandIcon(iconName: string) {
|
|
16
|
+
const props = { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round" as const, strokeLinejoin: "round" as const, style: { display: 'inline-block', verticalAlign: 'middle' } }
|
|
17
|
+
switch (iconName) {
|
|
18
|
+
case '📺':
|
|
19
|
+
return (
|
|
20
|
+
<svg {...props}>
|
|
21
|
+
<path d="M22.54 6.42a2.78 2.78 0 0 0-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 0 0-1.94 2A29 29 0 0 0 1 11.75a29 29 0 0 0 .46 5.33A2.78 2.78 0 0 0 3.4 19c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 0 0 1.94-2 29 29 0 0 0 .46-5.25 29 29 0 0 0-.46-5.33z"></path>
|
|
22
|
+
<polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02"></polygon>
|
|
23
|
+
</svg>
|
|
24
|
+
)
|
|
25
|
+
case '📘':
|
|
26
|
+
return (
|
|
27
|
+
<svg {...props}>
|
|
28
|
+
<path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path>
|
|
29
|
+
</svg>
|
|
30
|
+
)
|
|
31
|
+
case '📸':
|
|
32
|
+
return (
|
|
33
|
+
<svg {...props}>
|
|
34
|
+
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
|
|
35
|
+
<circle cx="12" cy="12" r="4"></circle>
|
|
36
|
+
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
|
|
37
|
+
</svg>
|
|
38
|
+
)
|
|
39
|
+
case '🐙':
|
|
40
|
+
return (
|
|
41
|
+
<svg {...props}>
|
|
42
|
+
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
|
43
|
+
</svg>
|
|
44
|
+
)
|
|
45
|
+
case '💻':
|
|
46
|
+
return (
|
|
47
|
+
<svg {...props}>
|
|
48
|
+
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
|
|
49
|
+
<line x1="8" y1="21" x2="16" y2="21"></line>
|
|
50
|
+
<line x1="12" y1="17" x2="12" y2="21"></line>
|
|
51
|
+
</svg>
|
|
52
|
+
)
|
|
53
|
+
case '🌤️':
|
|
54
|
+
return (
|
|
55
|
+
<svg {...props}>
|
|
56
|
+
<path d="M12 2v2"></path>
|
|
57
|
+
<path d="M12 20v2"></path>
|
|
58
|
+
<path d="M4.93 4.93l1.41 1.41"></path>
|
|
59
|
+
<path d="M17.66 17.66l1.41 1.41"></path>
|
|
60
|
+
<path d="M2 12h2"></path>
|
|
61
|
+
<path d="M20 12h2"></path>
|
|
62
|
+
<path d="M6.34 17.66l-1.41 1.41"></path>
|
|
63
|
+
<path d="M19.07 4.93l-1.41 1.41"></path>
|
|
64
|
+
<circle cx="12" cy="12" r="4"></circle>
|
|
65
|
+
</svg>
|
|
66
|
+
)
|
|
67
|
+
case '🎵':
|
|
68
|
+
return (
|
|
69
|
+
<svg {...props}>
|
|
70
|
+
<path d="M9 18V5l12-2v13"></path>
|
|
71
|
+
<circle cx="6" cy="18" r="3"></circle>
|
|
72
|
+
<circle cx="18" cy="16" r="3"></circle>
|
|
73
|
+
</svg>
|
|
74
|
+
)
|
|
75
|
+
case '🧮':
|
|
76
|
+
return (
|
|
77
|
+
<svg {...props}>
|
|
78
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
79
|
+
<line x1="9" y1="9" x2="15" y2="15"></line>
|
|
80
|
+
<line x1="15" y1="9" x2="9" y2="15"></line>
|
|
81
|
+
</svg>
|
|
82
|
+
)
|
|
83
|
+
case '✨':
|
|
84
|
+
return (
|
|
85
|
+
<svg {...props}>
|
|
86
|
+
<path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"></path>
|
|
87
|
+
</svg>
|
|
88
|
+
)
|
|
89
|
+
default:
|
|
90
|
+
return <span>{iconName}</span>
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export default function SpotlightWindow() {
|
|
95
|
+
const [query, setQuery] = useState('')
|
|
96
|
+
const [results, setResults] = useState<any[]>([])
|
|
97
|
+
const [selectedIndex, setSelectedIndex] = useState(-1)
|
|
98
|
+
const inputRef = useRef<HTMLInputElement>(null)
|
|
99
|
+
|
|
100
|
+
// Sync theme
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const applyThemeVariables = (config: any) => {
|
|
103
|
+
if (config.systemTextColor) {
|
|
104
|
+
document.documentElement.style.setProperty('--text-main', config.systemTextColor)
|
|
105
|
+
}
|
|
106
|
+
document.documentElement.setAttribute('data-theme', config.theme || 'dark')
|
|
107
|
+
if (config.theme === 'custom') {
|
|
108
|
+
if (config.customBgStart && config.customBgEnd) {
|
|
109
|
+
const gradient = `linear-gradient(135deg, ${config.customBgStart} 0%, ${config.customBgEnd} 100%)`
|
|
110
|
+
document.documentElement.style.setProperty('--bg-gradient', gradient)
|
|
111
|
+
}
|
|
112
|
+
if (config.customPanelBg) {
|
|
113
|
+
const rgb = hexToRgb(config.customPanelBg)
|
|
114
|
+
document.documentElement.style.setProperty('--panel-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.75)`)
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
document.documentElement.style.removeProperty('--bg-gradient')
|
|
118
|
+
document.documentElement.style.removeProperty('--panel-bg')
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (window.spotlightAPI) {
|
|
123
|
+
window.spotlightAPI.getSettings().then(applyThemeVariables)
|
|
124
|
+
window.spotlightAPI.onSettingsChanged(applyThemeVariables)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const handleFocus = () => {
|
|
128
|
+
inputRef.current?.focus()
|
|
129
|
+
inputRef.current?.select()
|
|
130
|
+
}
|
|
131
|
+
window.addEventListener('focus', handleFocus)
|
|
132
|
+
handleFocus()
|
|
133
|
+
|
|
134
|
+
return () => window.removeEventListener('focus', handleFocus)
|
|
135
|
+
}, [])
|
|
136
|
+
|
|
137
|
+
const hexToRgb = (hex: string) => {
|
|
138
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
|
139
|
+
return result ? {
|
|
140
|
+
r: parseInt(result[1], 16),
|
|
141
|
+
g: parseInt(result[2], 16),
|
|
142
|
+
b: parseInt(result[3], 16)
|
|
143
|
+
} : { r: 15, g: 23, b: 42 }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Calculate matches when query text changes
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
const trimmed = query.trim()
|
|
149
|
+
if (!trimmed) {
|
|
150
|
+
setResults([])
|
|
151
|
+
setSelectedIndex(-1)
|
|
152
|
+
window.spotlightAPI?.resize(600, 80)
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Try math evaluation
|
|
157
|
+
if (/^[0-9+\-*/().\s]+$/.test(trimmed) && /[0-9]/.test(trimmed)) {
|
|
158
|
+
try {
|
|
159
|
+
const mathVal = evaluateArithmetic(trimmed)
|
|
160
|
+
const mathResult = [{
|
|
161
|
+
label: `Result: ${mathVal}`,
|
|
162
|
+
desc: 'Calculation result (Press Enter to copy)',
|
|
163
|
+
icon: '🧮',
|
|
164
|
+
action: { type: 'clipboard_write', target: mathVal.toString() }
|
|
165
|
+
}]
|
|
166
|
+
setResults(mathResult)
|
|
167
|
+
setSelectedIndex(0)
|
|
168
|
+
window.spotlightAPI?.resize(600, 80 + 64 + 16)
|
|
169
|
+
return
|
|
170
|
+
} catch {}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Normal commands
|
|
174
|
+
const matches = COMMANDS.filter(c =>
|
|
175
|
+
c.label.toLowerCase().includes(trimmed.toLowerCase()) ||
|
|
176
|
+
c.desc.toLowerCase().includes(trimmed.toLowerCase())
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
// Add default chat fallback
|
|
180
|
+
matches.push({
|
|
181
|
+
label: `Ask Mint: "${trimmed}"`,
|
|
182
|
+
desc: 'Send query to AI Chat',
|
|
183
|
+
icon: '✨',
|
|
184
|
+
action: { type: 'chat', query: trimmed }
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
setResults(matches)
|
|
188
|
+
setSelectedIndex(0)
|
|
189
|
+
const newHeight = Math.min(80 + (matches.length * 64) + 16, 500)
|
|
190
|
+
window.spotlightAPI?.resize(600, newHeight)
|
|
191
|
+
}, [query])
|
|
192
|
+
|
|
193
|
+
const handleAction = async (action: any) => {
|
|
194
|
+
if (action.type === 'chat') {
|
|
195
|
+
window.spotlightAPI?.submit(action.query)
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (window.spotlightAPI?.executeAction) {
|
|
200
|
+
const result = await window.spotlightAPI.executeAction(action)
|
|
201
|
+
if (!result || result.success === false) {
|
|
202
|
+
window.spotlightAPI.submit(`Spotlight action failed: ${result?.message || 'Unknown error'}`)
|
|
203
|
+
}
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
window.spotlightAPI?.submit(action.target || action.value || '')
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
211
|
+
if (e.key === 'Escape') {
|
|
212
|
+
window.spotlightAPI?.hide()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (e.key === 'ArrowDown') {
|
|
216
|
+
e.preventDefault()
|
|
217
|
+
setSelectedIndex(prev => Math.min(prev + 1, results.length - 1))
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (e.key === 'ArrowUp') {
|
|
221
|
+
e.preventDefault()
|
|
222
|
+
setSelectedIndex(prev => Math.max(prev - 1, -1))
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (e.key === 'Enter') {
|
|
226
|
+
if (selectedIndex >= 0 && results[selectedIndex]) {
|
|
227
|
+
handleAction(results[selectedIndex].action)
|
|
228
|
+
} else {
|
|
229
|
+
const trimmed = query.trim()
|
|
230
|
+
if (trimmed) {
|
|
231
|
+
window.spotlightAPI?.submit(trimmed)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return (
|
|
238
|
+
<div className="spotlight-container">
|
|
239
|
+
<div className="input-wrapper">
|
|
240
|
+
<div className="spotlight-icon" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
241
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
242
|
+
<path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z"></path>
|
|
243
|
+
</svg>
|
|
244
|
+
</div>
|
|
245
|
+
<input
|
|
246
|
+
type="text"
|
|
247
|
+
id="spotlight-input"
|
|
248
|
+
placeholder="What can I help with?"
|
|
249
|
+
autoComplete="off"
|
|
250
|
+
ref={inputRef}
|
|
251
|
+
value={query}
|
|
252
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
253
|
+
onKeyDown={handleKeyDown}
|
|
254
|
+
autoFocus
|
|
255
|
+
/>
|
|
256
|
+
<div className="shortcut-tip">ESC to close</div>
|
|
257
|
+
</div>
|
|
258
|
+
{results.length > 0 && (
|
|
259
|
+
<div id="spotlight-results" className="results-container">
|
|
260
|
+
{results.map((cmd, i) => (
|
|
261
|
+
<div
|
|
262
|
+
key={i}
|
|
263
|
+
className={`result-item ${i === selectedIndex ? 'selected' : ''}`}
|
|
264
|
+
onClick={() => handleAction(cmd.action)}
|
|
265
|
+
onMouseEnter={() => setSelectedIndex(i)}
|
|
266
|
+
>
|
|
267
|
+
<div className="result-icon" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
268
|
+
{getCommandIcon(cmd.icon)}
|
|
269
|
+
</div>
|
|
270
|
+
<div className="result-content">
|
|
271
|
+
<div className="result-title">{cmd.label}</div>
|
|
272
|
+
<div className="result-desc">{cmd.desc}</div>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
))}
|
|
276
|
+
</div>
|
|
277
|
+
)}
|
|
278
|
+
</div>
|
|
279
|
+
)
|
|
280
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react'
|
|
2
|
+
|
|
3
|
+
export default function WidgetWindow() {
|
|
4
|
+
const [state, setState] = useState('idle')
|
|
5
|
+
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (window.widgetAPI?.onStateChange) {
|
|
8
|
+
window.widgetAPI.onStateChange((newState: string) => {
|
|
9
|
+
setState(newState || 'idle')
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
}, [])
|
|
13
|
+
|
|
14
|
+
const stateLabel = state.charAt(0).toUpperCase() + state.slice(1)
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div id="widget-container" className={`state-${state}`}>
|
|
18
|
+
<div className="aura-container">
|
|
19
|
+
<div className="aura"></div>
|
|
20
|
+
</div>
|
|
21
|
+
<div className="character-body">
|
|
22
|
+
{/* Eyes / Face */}
|
|
23
|
+
<div className="eyes">
|
|
24
|
+
<div className="eye left"></div>
|
|
25
|
+
<div className="eye right"></div>
|
|
26
|
+
</div>
|
|
27
|
+
{/* Mouth/Indicator */}
|
|
28
|
+
<div className="mouth"></div>
|
|
29
|
+
</div>
|
|
30
|
+
{/* Status Badge */}
|
|
31
|
+
<div className="status-badge" id="status-badge">
|
|
32
|
+
{stateLabel}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import { getWorkspaceTree, type WorkspaceTreeEntry } from '../tauri'
|
|
3
|
+
import folderIcon from 'material-icon-theme/icons/folder.svg?url'
|
|
4
|
+
import folderOpenIcon from 'material-icon-theme/icons/folder-open.svg?url'
|
|
5
|
+
import folderComponentsIcon from 'material-icon-theme/icons/folder-components.svg?url'
|
|
6
|
+
import folderComponentsOpenIcon from 'material-icon-theme/icons/folder-components-open.svg?url'
|
|
7
|
+
import folderConfigIcon from 'material-icon-theme/icons/folder-config.svg?url'
|
|
8
|
+
import folderConfigOpenIcon from 'material-icon-theme/icons/folder-config-open.svg?url'
|
|
9
|
+
import folderDistIcon from 'material-icon-theme/icons/folder-dist.svg?url'
|
|
10
|
+
import folderDistOpenIcon from 'material-icon-theme/icons/folder-dist-open.svg?url'
|
|
11
|
+
import folderDocsIcon from 'material-icon-theme/icons/folder-docs.svg?url'
|
|
12
|
+
import folderDocsOpenIcon from 'material-icon-theme/icons/folder-docs-open.svg?url'
|
|
13
|
+
import folderGitIcon from 'material-icon-theme/icons/folder-git.svg?url'
|
|
14
|
+
import folderGitOpenIcon from 'material-icon-theme/icons/folder-git-open.svg?url'
|
|
15
|
+
import folderGithubIcon from 'material-icon-theme/icons/folder-github.svg?url'
|
|
16
|
+
import folderGithubOpenIcon from 'material-icon-theme/icons/folder-github-open.svg?url'
|
|
17
|
+
import folderImagesIcon from 'material-icon-theme/icons/folder-images.svg?url'
|
|
18
|
+
import folderImagesOpenIcon from 'material-icon-theme/icons/folder-images-open.svg?url'
|
|
19
|
+
import folderLogIcon from 'material-icon-theme/icons/folder-log.svg?url'
|
|
20
|
+
import folderLogOpenIcon from 'material-icon-theme/icons/folder-log-open.svg?url'
|
|
21
|
+
import folderNodeIcon from 'material-icon-theme/icons/folder-node.svg?url'
|
|
22
|
+
import folderNodeOpenIcon from 'material-icon-theme/icons/folder-node-open.svg?url'
|
|
23
|
+
import folderPublicIcon from 'material-icon-theme/icons/folder-public.svg?url'
|
|
24
|
+
import folderPublicOpenIcon from 'material-icon-theme/icons/folder-public-open.svg?url'
|
|
25
|
+
import folderRustIcon from 'material-icon-theme/icons/folder-rust.svg?url'
|
|
26
|
+
import folderRustOpenIcon from 'material-icon-theme/icons/folder-rust-open.svg?url'
|
|
27
|
+
import folderScriptsIcon from 'material-icon-theme/icons/folder-scripts.svg?url'
|
|
28
|
+
import folderScriptsOpenIcon from 'material-icon-theme/icons/folder-scripts-open.svg?url'
|
|
29
|
+
import folderSrcIcon from 'material-icon-theme/icons/folder-src.svg?url'
|
|
30
|
+
import folderSrcOpenIcon from 'material-icon-theme/icons/folder-src-open.svg?url'
|
|
31
|
+
import folderSrcTauriIcon from 'material-icon-theme/icons/folder-src-tauri.svg?url'
|
|
32
|
+
import folderSrcTauriOpenIcon from 'material-icon-theme/icons/folder-src-tauri-open.svg?url'
|
|
33
|
+
import folderTestIcon from 'material-icon-theme/icons/folder-test.svg?url'
|
|
34
|
+
import folderTestOpenIcon from 'material-icon-theme/icons/folder-test-open.svg?url'
|
|
35
|
+
import folderUiIcon from 'material-icon-theme/icons/folder-ui.svg?url'
|
|
36
|
+
import folderUiOpenIcon from 'material-icon-theme/icons/folder-ui-open.svg?url'
|
|
37
|
+
import folderUtilsIcon from 'material-icon-theme/icons/folder-utils.svg?url'
|
|
38
|
+
import folderUtilsOpenIcon from 'material-icon-theme/icons/folder-utils-open.svg?url'
|
|
39
|
+
import cssIcon from 'material-icon-theme/icons/css.svg?url'
|
|
40
|
+
import documentIcon from 'material-icon-theme/icons/document.svg?url'
|
|
41
|
+
import htmlIcon from 'material-icon-theme/icons/html.svg?url'
|
|
42
|
+
import imageIcon from 'material-icon-theme/icons/image.svg?url'
|
|
43
|
+
import javascriptIcon from 'material-icon-theme/icons/javascript.svg?url'
|
|
44
|
+
import jsonIcon from 'material-icon-theme/icons/json.svg?url'
|
|
45
|
+
import lockIcon from 'material-icon-theme/icons/lock.svg?url'
|
|
46
|
+
import logIcon from 'material-icon-theme/icons/log.svg?url'
|
|
47
|
+
import markdownIcon from 'material-icon-theme/icons/markdown.svg?url'
|
|
48
|
+
import npmIcon from 'material-icon-theme/icons/npm.svg?url'
|
|
49
|
+
import reactIcon from 'material-icon-theme/icons/react.svg?url'
|
|
50
|
+
import reactTsIcon from 'material-icon-theme/icons/react_ts.svg?url'
|
|
51
|
+
import rustIcon from 'material-icon-theme/icons/rust.svg?url'
|
|
52
|
+
import settingsIcon from 'material-icon-theme/icons/settings.svg?url'
|
|
53
|
+
import tauriIcon from 'material-icon-theme/icons/tauri.svg?url'
|
|
54
|
+
import tomlIcon from 'material-icon-theme/icons/toml.svg?url'
|
|
55
|
+
import typescriptIcon from 'material-icon-theme/icons/typescript.svg?url'
|
|
56
|
+
import viteIcon from 'material-icon-theme/icons/vite.svg?url'
|
|
57
|
+
import yamlIcon from 'material-icon-theme/icons/yaml.svg?url'
|
|
58
|
+
|
|
59
|
+
interface WorkspacePanelProps {
|
|
60
|
+
agentMode: boolean
|
|
61
|
+
sending: boolean
|
|
62
|
+
workspacePath: string
|
|
63
|
+
onEnableAgentMode: () => void
|
|
64
|
+
onSetMessage: (message: string) => void
|
|
65
|
+
onWorkspaceReady: (path: string) => void
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const FILE_LABEL: Record<string, string> = {
|
|
69
|
+
css: '#',
|
|
70
|
+
html: '<>',
|
|
71
|
+
js: 'JS',
|
|
72
|
+
json: '{}',
|
|
73
|
+
md: 'MD',
|
|
74
|
+
rs: 'RS',
|
|
75
|
+
ts: 'TS',
|
|
76
|
+
tsx: 'TS',
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const FOLDER_ICONS: Record<string, { closed: string; open: string }> = {
|
|
80
|
+
'.cargo_home': { closed: folderRustIcon, open: folderRustOpenIcon },
|
|
81
|
+
'.github': { closed: folderGithubIcon, open: folderGithubOpenIcon },
|
|
82
|
+
'.git': { closed: folderGitIcon, open: folderGitOpenIcon },
|
|
83
|
+
'.rustup': { closed: folderRustIcon, open: folderRustOpenIcon },
|
|
84
|
+
'.rustup_copy': { closed: folderRustIcon, open: folderRustOpenIcon },
|
|
85
|
+
'.rustup_home': { closed: folderRustIcon, open: folderRustOpenIcon },
|
|
86
|
+
assets: { closed: folderImagesIcon, open: folderImagesOpenIcon },
|
|
87
|
+
components: { closed: folderComponentsIcon, open: folderComponentsOpenIcon },
|
|
88
|
+
crates: { closed: folderRustIcon, open: folderRustOpenIcon },
|
|
89
|
+
css: { closed: folderUiIcon, open: folderUiOpenIcon },
|
|
90
|
+
dist: { closed: folderDistIcon, open: folderDistOpenIcon },
|
|
91
|
+
docs: { closed: folderDocsIcon, open: folderDocsOpenIcon },
|
|
92
|
+
logs: { closed: folderLogIcon, open: folderLogOpenIcon },
|
|
93
|
+
node_modules: { closed: folderNodeIcon, open: folderNodeOpenIcon },
|
|
94
|
+
out: { closed: folderDistIcon, open: folderDistOpenIcon },
|
|
95
|
+
public: { closed: folderPublicIcon, open: folderPublicOpenIcon },
|
|
96
|
+
renderer: { closed: folderUiIcon, open: folderUiOpenIcon },
|
|
97
|
+
scripts: { closed: folderScriptsIcon, open: folderScriptsOpenIcon },
|
|
98
|
+
src: { closed: folderSrcIcon, open: folderSrcOpenIcon },
|
|
99
|
+
'src-tauri': { closed: folderSrcTauriIcon, open: folderSrcTauriOpenIcon },
|
|
100
|
+
tests: { closed: folderTestIcon, open: folderTestOpenIcon },
|
|
101
|
+
utils: { closed: folderUtilsIcon, open: folderUtilsOpenIcon },
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const FILE_ICONS_BY_EXTENSION: Record<string, string> = {
|
|
105
|
+
css: cssIcon,
|
|
106
|
+
html: htmlIcon,
|
|
107
|
+
jpeg: imageIcon,
|
|
108
|
+
jpg: imageIcon,
|
|
109
|
+
js: javascriptIcon,
|
|
110
|
+
json: jsonIcon,
|
|
111
|
+
lock: lockIcon,
|
|
112
|
+
log: logIcon,
|
|
113
|
+
md: markdownIcon,
|
|
114
|
+
png: imageIcon,
|
|
115
|
+
rs: rustIcon,
|
|
116
|
+
svg: imageIcon,
|
|
117
|
+
toml: tomlIcon,
|
|
118
|
+
ts: typescriptIcon,
|
|
119
|
+
tsx: reactTsIcon,
|
|
120
|
+
yaml: yamlIcon,
|
|
121
|
+
yml: yamlIcon,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const FILE_ICONS_BY_NAME: Record<string, string> = {
|
|
125
|
+
'package-lock.json': npmIcon,
|
|
126
|
+
'package.json': npmIcon,
|
|
127
|
+
'tauri.conf.json': tauriIcon,
|
|
128
|
+
'vite.config.ts': viteIcon,
|
|
129
|
+
'vite.config.web.ts': viteIcon,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function extension(name: string) {
|
|
133
|
+
const index = name.lastIndexOf('.')
|
|
134
|
+
return index === -1 ? '' : name.slice(index + 1).toLowerCase()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function materialFolderIcon(name: string, open: boolean) {
|
|
138
|
+
const icon = FOLDER_ICONS[name] || FOLDER_ICONS[name.toLowerCase()]
|
|
139
|
+
if (!icon) return open ? folderOpenIcon : folderIcon
|
|
140
|
+
return open ? icon.open : icon.closed
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function materialFileIcon(name: string, fileExtension: string) {
|
|
144
|
+
if (name.endsWith('.config.ts') || name.endsWith('.config.js')) return settingsIcon
|
|
145
|
+
if (name.endsWith('.tsx')) return reactTsIcon
|
|
146
|
+
if (name.endsWith('.jsx')) return reactIcon
|
|
147
|
+
return FILE_ICONS_BY_NAME[name.toLowerCase()] || FILE_ICONS_BY_EXTENSION[fileExtension] || documentIcon
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number; key?: string }) {
|
|
151
|
+
const [open, setOpen] = useState(level < 1)
|
|
152
|
+
const isDirectory = entry.kind === 'directory'
|
|
153
|
+
const hasChildren = entry.children.length > 0
|
|
154
|
+
const fileExtension = extension(entry.name)
|
|
155
|
+
const fileLabel = FILE_LABEL[fileExtension] || ''
|
|
156
|
+
const materialIcon = isDirectory ? materialFolderIcon(entry.name, open) : materialFileIcon(entry.name, fileExtension)
|
|
157
|
+
const dragText = `@${entry.path}`
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<div className="workspace-tree-node">
|
|
161
|
+
<button
|
|
162
|
+
type="button"
|
|
163
|
+
className={`workspace-tree-row ${isDirectory ? 'is-directory' : 'is-file'}`}
|
|
164
|
+
style={{ paddingLeft: `${level * 16 + 8}px` }}
|
|
165
|
+
onClick={() => isDirectory && hasChildren && setOpen((current) => !current)}
|
|
166
|
+
title={entry.path}
|
|
167
|
+
draggable
|
|
168
|
+
onDragStart={(event) => {
|
|
169
|
+
event.dataTransfer.setData('application/x-mint-workspace-path', dragText)
|
|
170
|
+
event.dataTransfer.setData('text/plain', dragText)
|
|
171
|
+
event.dataTransfer.effectAllowed = 'copy'
|
|
172
|
+
}}
|
|
173
|
+
>
|
|
174
|
+
<span
|
|
175
|
+
className={`workspace-tree-chevron ${isDirectory && hasChildren ? '' : 'is-spacer'}`}
|
|
176
|
+
data-open={open}
|
|
177
|
+
aria-hidden="true"
|
|
178
|
+
>
|
|
179
|
+
{isDirectory && hasChildren ? '' : null}
|
|
180
|
+
</span>
|
|
181
|
+
<span className={`workspace-tree-icon material-icon ${isDirectory ? 'folder' : fileExtension || 'file'}`} aria-hidden="true">
|
|
182
|
+
{materialIcon ? <img src={materialIcon} alt="" draggable={false} /> : isDirectory ? '' : fileLabel}
|
|
183
|
+
</span>
|
|
184
|
+
<span className="workspace-tree-name">{entry.name}</span>
|
|
185
|
+
</button>
|
|
186
|
+
{isDirectory && open && hasChildren && (
|
|
187
|
+
<div className="workspace-tree-children">
|
|
188
|
+
{entry.children.map((child) => (
|
|
189
|
+
<TreeNode key={child.path} entry={child} level={level + 1} />
|
|
190
|
+
))}
|
|
191
|
+
</div>
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export default function WorkspacePanel({ agentMode, sending, workspacePath, onEnableAgentMode, onSetMessage, onWorkspaceReady }: WorkspacePanelProps) {
|
|
198
|
+
const [tree, setTree] = useState<WorkspaceTreeEntry | null>(null)
|
|
199
|
+
const [error, setError] = useState('')
|
|
200
|
+
|
|
201
|
+
const refresh = async () => {
|
|
202
|
+
if (!workspacePath.trim()) {
|
|
203
|
+
setError('')
|
|
204
|
+
setTree(null)
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
setError('')
|
|
210
|
+
const nextTree = await getWorkspaceTree(workspacePath)
|
|
211
|
+
setTree(nextTree)
|
|
212
|
+
if (nextTree.path !== workspacePath) onWorkspaceReady(nextTree.path)
|
|
213
|
+
} catch (reason) {
|
|
214
|
+
setError(reason instanceof Error ? reason.message : String(reason))
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
refresh()
|
|
220
|
+
}, [workspacePath])
|
|
221
|
+
|
|
222
|
+
const startWorkspacePrompt = () => {
|
|
223
|
+
onEnableAgentMode()
|
|
224
|
+
onSetMessage('ดู workspace นี้แล้วช่วยวางแผนงานต่อไปให้หน่อย')
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<section className="workspace-panel">
|
|
229
|
+
<header className="workspace-panel-header">
|
|
230
|
+
<div>
|
|
231
|
+
<span className="workspace-kicker">Agent Workspace</span>
|
|
232
|
+
<h2>Workspace</h2>
|
|
233
|
+
</div>
|
|
234
|
+
<span className="workspace-agent-pill" data-state={sending ? 'thinking' : agentMode ? 'agent' : 'idle'}>
|
|
235
|
+
{sending ? 'Running' : agentMode ? 'Agent mode' : 'Manual'}
|
|
236
|
+
</span>
|
|
237
|
+
</header>
|
|
238
|
+
|
|
239
|
+
<div className="workspace-panel-actions">
|
|
240
|
+
<button type="button" onClick={startWorkspacePrompt}>Use Agent</button>
|
|
241
|
+
<button type="button" onClick={refresh} disabled={!workspacePath.trim()}>Refresh</button>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<div className="workspace-tree-shell">
|
|
245
|
+
{error ? (
|
|
246
|
+
<div className="workspace-tree-empty">{error}</div>
|
|
247
|
+
) : tree ? (
|
|
248
|
+
<>
|
|
249
|
+
<div className="workspace-root-row">
|
|
250
|
+
<span className="workspace-tree-chevron" data-open="true" aria-hidden="true" />
|
|
251
|
+
<span className="workspace-tree-icon material-icon folder" aria-hidden="true">
|
|
252
|
+
<img src={folderOpenIcon} alt="" draggable={false} />
|
|
253
|
+
</span>
|
|
254
|
+
<span>{tree.name}</span>
|
|
255
|
+
</div>
|
|
256
|
+
<div className="workspace-tree">
|
|
257
|
+
{tree.children.map((entry) => (
|
|
258
|
+
<TreeNode key={entry.path} entry={entry} level={0} />
|
|
259
|
+
))}
|
|
260
|
+
</div>
|
|
261
|
+
</>
|
|
262
|
+
) : (
|
|
263
|
+
<div className="workspace-tree-empty">Select a project to show workspace files.</div>
|
|
264
|
+
)}
|
|
265
|
+
</div>
|
|
266
|
+
</section>
|
|
267
|
+
)
|
|
268
|
+
}
|