@pheem49/mint 1.8.0 → 1.8.2
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/.github/workflows/release.yml +1 -1
- package/Cargo.lock +34 -3
- package/Cargo.toml +2 -2
- package/README.md +20 -6
- package/Release_Note.md +129 -0
- package/assets/Mint_CLI.png +0 -0
- package/bin/mint +0 -0
- package/crates/mint-cli/Cargo.toml +1 -0
- package/crates/mint-cli/src/agent.rs +242 -54
- package/crates/mint-cli/src/main.rs +397 -74
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +64 -2
- package/crates/mint-core/src/browser.rs +456 -0
- package/crates/mint-core/src/channels.rs +1 -0
- package/crates/mint-core/src/chat.rs +3 -0
- package/crates/mint-core/src/config.rs +130 -1
- package/crates/mint-core/src/lib.rs +19 -0
- package/crates/mint-core/src/orchestration.rs +317 -12
- package/crates/mint-core/src/skills.rs +113 -4
- package/crates/mint-core/src/tts.rs +3 -1
- package/crates/mint-core/src/workflows.rs +1 -22
- package/flatpak/com.pheem49.mint.desktop +9 -0
- package/flatpak/com.pheem49.mint.metainfo.xml +35 -0
- package/flatpak/com.pheem49.mint.yaml +52 -0
- package/package.json +1 -1
- package/shared-modules/.github/workflows/ci.yml +120 -0
- package/shared-modules/.github/workflows/update.yaml +28 -0
- package/shared-modules/CODEOWNERS +23 -0
- package/shared-modules/README.md +79 -0
- package/shared-modules/SDL/README.md +3 -0
- package/shared-modules/SDL/SDL-1.2.15.json +51 -0
- package/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch +118 -0
- package/shared-modules/SDL/SDL_image-1.2.12.json +25 -0
- package/shared-modules/SDL/SDL_mixer-1.2.12.json +27 -0
- package/shared-modules/SDL/SDL_net-1.2.8.json +19 -0
- package/shared-modules/SDL/SDL_pango-0.1.2.json +26 -0
- package/shared-modules/SDL/SDL_ttf-2.0.11.json +28 -0
- package/shared-modules/SDL/libsdl-1.2.15-strict-prototypes.patch +316 -0
- package/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch +24 -0
- package/shared-modules/SDL/sdl-libx11-build.patch +59 -0
- package/shared-modules/SDL/sdl-sysloadso-buffer-length.patch +27 -0
- package/shared-modules/SDL/sdl12-compat.json +22 -0
- package/shared-modules/SDL2/SDL2_image.json +27 -0
- package/shared-modules/SDL2/SDL2_ttf.json +29 -0
- package/shared-modules/cld2/CMakeLists.txt +157 -0
- package/shared-modules/cld2/cld2.json +24 -0
- package/shared-modules/clutter/clutter.json +72 -0
- package/shared-modules/dbus-glib/dbus-glib.json +29 -0
- package/shared-modules/glew/glew.json +36 -0
- package/shared-modules/glu/glu-9.json +12 -0
- package/shared-modules/gtk2/arc-gtk2-theme-Replace-Inkscape-dependency-with-rsvg-convert.patch +180 -0
- package/shared-modules/gtk2/gtk2-common-themes.json +360 -0
- package/shared-modules/gtk2/gtk2-fix-crash-in-show-uri.patch +30 -0
- package/shared-modules/gtk2/gtk2-gcc14.patch +281 -0
- package/shared-modules/gtk2/gtk2-gcc15.patch +250 -0
- package/shared-modules/gtk2/gtk2-murrine-c99.patch +34 -0
- package/shared-modules/gtk2/gtk2-use-adwaita-theme.patch +80 -0
- package/shared-modules/gtk2/gtk2.json +120 -0
- package/shared-modules/gtk2/ibus-gcc15.patch +13 -0
- package/shared-modules/gtk2/murrine-engine-fix-crash.patch +12 -0
- package/shared-modules/gtk2/readme.md +10 -0
- package/shared-modules/intltool/intltool-0.51.json +20 -0
- package/shared-modules/intltool/intltool-perl5.26-regex-fixes.patch +59 -0
- package/shared-modules/lame/0001-Build-xmm_quantize_sub.c-with-msse.patch +34 -0
- package/shared-modules/lame/0002-Include-GTK-1-autoconf-directives-in-build-system.patch +222 -0
- package/shared-modules/lame/0003-Patch-out-remaining-ansi2knr.patch +70 -0
- package/shared-modules/lame/0004-initscr-is-not-used-anywhere-in-lame-sourcetree.patch +41 -0
- package/shared-modules/lame/0005-Update-autoconf.patch +81 -0
- package/shared-modules/lame/lame-3.99.5.json +32 -0
- package/shared-modules/libappindicator/libappindicator-gtk2-12.10.json +140 -0
- package/shared-modules/libappindicator/libappindicator-gtk3-12.10.json +140 -0
- package/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json +140 -0
- package/shared-modules/libappindicator/patches/0001-libappindicator-ftbfs.patch +20 -0
- package/shared-modules/libappindicator/patches/0002-libappindicator-no-python.patch +888 -0
- package/shared-modules/libappindicator/patches/0003-libappindicator-fix-crash-from-incorrect-signal-emission.patch +74 -0
- package/shared-modules/libappindicator/patches/0004-libappindicator-fix-crash-iterating-icon-themes.patch +11 -0
- package/shared-modules/libayatana-appindicator/0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch +51 -0
- package/shared-modules/libayatana-appindicator/0001-Make-introspection-configurable.patch +44 -0
- package/shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json +121 -0
- package/shared-modules/libcanberra/0001-gtk-Don-t-assume-all-GdkDisplays-are-GdkX11Displays-.patch +123 -0
- package/shared-modules/libcanberra/libcanberra.json +44 -0
- package/shared-modules/libmad/libmad.json +19 -0
- package/shared-modules/libsecret/libsecret.json +23 -0
- package/shared-modules/libsoup/libsoup-2.4.json +14 -0
- package/shared-modules/libusb/libusb.json +27 -0
- package/shared-modules/linux-audio/dssi.json +31 -0
- package/shared-modules/linux-audio/fftw3f-static.json +44 -0
- package/shared-modules/linux-audio/fftw3f.json +42 -0
- package/shared-modules/linux-audio/fluidsynth2-static.json +30 -0
- package/shared-modules/linux-audio/fluidsynth2.json +19 -0
- package/shared-modules/linux-audio/ladspa.json +26 -0
- package/shared-modules/linux-audio/lash.json +35 -0
- package/shared-modules/linux-audio/libinstpatch.json +16 -0
- package/shared-modules/linux-audio/liblo-static.json +22 -0
- package/shared-modules/linux-audio/liblo.json +17 -0
- package/shared-modules/linux-audio/lilv-static.json +94 -0
- package/shared-modules/linux-audio/lilv.json +82 -0
- package/shared-modules/linux-audio/lrdf.json +57 -0
- package/shared-modules/linux-audio/lv2.json +21 -0
- package/shared-modules/linux-audio/patches/lash/0001-configure-remove-aclocal-m4.patch +29 -0
- package/shared-modules/linux-audio/patches/lash/0002-Fix-build-with-recent-gcc.patch +73 -0
- package/shared-modules/linux-audio/patches/lash/0003-Fix-linking.patch +136 -0
- package/shared-modules/linux-audio/patches/raptor-libxml.patch +31 -0
- package/shared-modules/linux-audio/patches/stk-install.sh +54 -0
- package/shared-modules/linux-audio/stk.json +28 -0
- package/shared-modules/lua5.1/0004-Fix-stack-overflow-in-vararg-functions.patch +21 -0
- package/shared-modules/lua5.1/lua-5.1.5-so.patch +43 -0
- package/shared-modules/lua5.1/lua-5.1.5.json +42 -0
- package/shared-modules/lua5.3/lua-5.3.5.json +41 -0
- package/shared-modules/lua5.3/lua.pc.in +8 -0
- package/shared-modules/lua5.3/luaconf.patch +47 -0
- package/shared-modules/lua5.3/makefile-add-liblua.so-rule.patch +47 -0
- package/shared-modules/lua5.4/lua-5.4.json +41 -0
- package/shared-modules/lua5.4/lua.pc.in +8 -0
- package/shared-modules/lua5.4/luaconf.patch +34 -0
- package/shared-modules/lua5.4/makefile-add-liblua.so-rule.patch +42 -0
- package/shared-modules/luajit/luajit.json +30 -0
- package/shared-modules/lzo/lzo.json +27 -0
- package/shared-modules/mac/mac.json +18 -0
- package/shared-modules/physfs/physfs.json +26 -0
- package/shared-modules/pygame/audiofile-gcc6.patch +21 -0
- package/shared-modules/pygame/cython-fixes.patch +34 -0
- package/shared-modules/pygame/fluidsynth-no-rawmidi.patch +69 -0
- package/shared-modules/pygame/glib.patch +25 -0
- package/shared-modules/pygame/pygame1-python2.json +157 -0
- package/shared-modules/pygtk/pygtk-c99.patch +15 -0
- package/shared-modules/pygtk/pygtk.json +117 -0
- package/shared-modules/pygtk/pygtk.patch +39 -0
- package/shared-modules/python2.7/python-2.7.json +48 -0
- package/shared-modules/smpeg/smpeg-0.4.5.json +50 -0
- package/shared-modules/smpeg/smpeg-am-prog-as.patch +12 -0
- package/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch +17 -0
- package/shared-modules/smpeg/smpeg-gcc6.patch +40 -0
- package/shared-modules/smpeg/smpeg-no-gtk.patch +37 -0
- package/shared-modules/squashfs-tools/squashfs-tools.json +25 -0
- package/shared-modules/update-checker.sh +50 -0
- package/shared-modules/vorbisgain/0001-temp_files.patch +75 -0
- package/shared-modules/vorbisgain/0002-errno.patch +33 -0
- package/shared-modules/vorbisgain/0003-manpage.patch +248 -0
- package/shared-modules/vorbisgain/0004-vorbisgain_mtime.patch +183 -0
- package/shared-modules/vorbisgain/0005-double_fclose.patch +21 -0
- package/shared-modules/vorbisgain/0006-manpage_hyphens.patch +56 -0
- package/shared-modules/vorbisgain/0007-recursively_spelling.patch +14 -0
- package/shared-modules/vorbisgain/0008-manpage_recursion_mistake.patch +23 -0
- package/shared-modules/vorbisgain/0009-hardening.patch +13 -0
- package/shared-modules/vorbisgain/0010-fclose.patch +13 -0
- package/shared-modules/vorbisgain/README.md +23 -0
- package/shared-modules/vorbisgain/vorbisgain_0.37-2.json +29 -0
- package/src/renderer/shared/agentProgress.ts +145 -0
- package/src/renderer/shared/calculator.ts +52 -0
- package/src/renderer/shared/components/AgentActivityDrawer.tsx +72 -0
- package/src/renderer/shared/components/AgentActivityTable.tsx +66 -0
- package/src/renderer/shared/components/ApprovalCard.tsx +93 -0
- package/src/renderer/shared/components/ChatCodeBlock.tsx +75 -0
- package/src/renderer/shared/components/ThinkingBlock.tsx +101 -0
- package/src/renderer/shared/constants/models.ts +91 -0
- package/src/renderer/shared/platform.ts +82 -0
- package/src/renderer/shared/types.ts +140 -0
- package/src/renderer/shared/utils/agentActivity.ts +187 -0
- package/src/renderer/shared/utils/approval.ts +1 -0
- package/src/renderer/shared/utils/approval.tsx +64 -0
- package/src/renderer/shared/utils/markdown.tsx +347 -0
- package/src/renderer/shared/utils/providers.ts +36 -0
- package/src/renderer/shared/utils/speech.ts +216 -0
- package/src/renderer/shared/utils/ui.ts +147 -0
- package/src/renderer/src/agentProgress.ts +11 -39
- package/src/renderer/src/calculator.ts +3 -46
- package/src/renderer/src/components/ChatPanel.tsx +230 -1202
- package/src/renderer/src/components/ImageStudioPanel.tsx +11 -1
- package/src/renderer/src/components/MintDashboard.tsx +63 -171
- package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
- package/src/renderer/src/components/Settings/AgentsTab.tsx +362 -0
- package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src/components/Settings/PluginsTab.tsx +221 -41
- package/src/renderer/src/components/SettingsWindow.tsx +54 -12
- package/src/renderer/src/components/WorkspacePanel.tsx +66 -9
- package/src/renderer/src/css/image-studio.css +6 -0
- package/src/renderer/src/css/styles.css +148 -11
- package/src/renderer/src/index.css +12 -1
- package/src/renderer/src/tauri.ts +169 -143
- package/src/renderer/src-web/agentProgress.ts +11 -39
- package/src/renderer/src-web/calculator.ts +3 -46
- package/src/renderer/src-web/components/ChatPanel.tsx +223 -1199
- package/src/renderer/src-web/components/ImageStudioPanel.tsx +11 -1
- package/src/renderer/src-web/components/MintDashboard.tsx +31 -172
- package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
- package/src/renderer/src-web/components/Settings/AgentsTab.tsx +362 -0
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src-web/components/Settings/PluginsTab.tsx +221 -41
- package/src/renderer/src-web/components/SettingsWindow.tsx +54 -12
- package/src/renderer/src-web/css/image-studio.css +6 -0
- package/src/renderer/src-web/css/styles.css +184 -12
- package/src/renderer/src-web/index.css +12 -1
- package/src/renderer/src-web/tauri.ts +204 -104
- package/src-tauri/src/browser.rs +1 -141
- package/src-tauri/src/headless.rs +3 -2
- package/src-tauri/src/lib.rs +254 -59
- package/src-tauri/src/webhooks.rs +1 -0
- package/src-tauri/src/workflows.rs +57 -4
- package/src-tauri/tauri.conf.json +1 -1
|
@@ -16,6 +16,7 @@ interface ImageStudioPanelProps {
|
|
|
16
16
|
view: string
|
|
17
17
|
onRefreshPictures?: () => void
|
|
18
18
|
onSendToChat?: (dataUri: string, prompt: string) => void
|
|
19
|
+
onToggleMobileSidebar?: () => void
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
const ASPECT_OPTIONS: { value: AspectRatio; label: string; icon: string }[] = [
|
|
@@ -85,7 +86,7 @@ function SkeletonCard() {
|
|
|
85
86
|
)
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
export default function ImageStudioPanel({ view, onRefreshPictures, onSendToChat }: ImageStudioPanelProps) {
|
|
89
|
+
export default function ImageStudioPanel({ view, onRefreshPictures, onSendToChat, onToggleMobileSidebar }: ImageStudioPanelProps) {
|
|
89
90
|
const [prompt, setPrompt] = useState('')
|
|
90
91
|
const [negativePrompt, setNegativePrompt] = useState('')
|
|
91
92
|
const [showNegative, setShowNegative] = useState(false)
|
|
@@ -206,6 +207,15 @@ export default function ImageStudioPanel({ view, onRefreshPictures, onSendToChat
|
|
|
206
207
|
{/* Header */}
|
|
207
208
|
<header className="img-studio-header">
|
|
208
209
|
<div className="img-studio-header-title">
|
|
210
|
+
<button
|
|
211
|
+
className="mobile-menu-btn"
|
|
212
|
+
type="button"
|
|
213
|
+
onClick={onToggleMobileSidebar}
|
|
214
|
+
aria-label="Toggle menu"
|
|
215
|
+
style={{ marginRight: '8px' }}
|
|
216
|
+
>
|
|
217
|
+
☰
|
|
218
|
+
</button>
|
|
209
219
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
210
220
|
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
|
|
211
221
|
</svg>
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
selectWorkspaceDirectory,
|
|
13
13
|
saveInteractionAgentActivity,
|
|
14
14
|
streamChatMessage,
|
|
15
|
+
cancelChatMessage,
|
|
15
16
|
submitToolApproval,
|
|
16
17
|
listen,
|
|
17
|
-
readClipboardImage as readTauriClipboardImage,
|
|
18
18
|
type AgentProgress,
|
|
19
19
|
type ChatResponse,
|
|
20
20
|
type ChatSession,
|
|
@@ -30,6 +30,13 @@ import type { ModelInteraction } from './ModelPanel'
|
|
|
30
30
|
import PicturesLibrary from './PicturesLibrary'
|
|
31
31
|
import WorkspacePanel from './WorkspacePanel'
|
|
32
32
|
import WorkflowBuilderPanel from './WorkflowBuilderPanel'
|
|
33
|
+
import {
|
|
34
|
+
errorMessage,
|
|
35
|
+
readImage,
|
|
36
|
+
readDocument,
|
|
37
|
+
createTrimmedImagePreview,
|
|
38
|
+
applyThemeStyles,
|
|
39
|
+
} from '../../shared/utils/ui'
|
|
33
40
|
|
|
34
41
|
const EXPRESSIONS = [
|
|
35
42
|
"Default",
|
|
@@ -88,142 +95,6 @@ const MOCK_WELCOME_INTERACTION = {
|
|
|
88
95
|
createdAt: new Date().toISOString(),
|
|
89
96
|
}
|
|
90
97
|
|
|
91
|
-
function errorMessage(reason: unknown) {
|
|
92
|
-
return reason instanceof Error ? reason.message : String(reason)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function readImage(file: File): Promise<string> {
|
|
96
|
-
return new Promise((resolve, reject) => {
|
|
97
|
-
const reader = new FileReader()
|
|
98
|
-
reader.onload = () => resolve(String(reader.result))
|
|
99
|
-
reader.onerror = () => reject(reader.error ?? new Error('Unable to read image'))
|
|
100
|
-
reader.readAsDataURL(file)
|
|
101
|
-
})
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function readDocument(file: File): Promise<string> {
|
|
105
|
-
return new Promise((resolve, reject) => {
|
|
106
|
-
const reader = new FileReader()
|
|
107
|
-
reader.onload = () => resolve(String(reader.result))
|
|
108
|
-
reader.onerror = () => reject(reader.error ?? new Error('Unable to read document'))
|
|
109
|
-
reader.readAsDataURL(file)
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async function createTrimmedImagePreview(dataUri: string): Promise<string> {
|
|
114
|
-
const image = await new Promise<HTMLImageElement>((resolve, reject) => {
|
|
115
|
-
const nextImage = new Image()
|
|
116
|
-
nextImage.onload = () => resolve(nextImage)
|
|
117
|
-
nextImage.onerror = () => reject(new Error('Unable to prepare image preview'))
|
|
118
|
-
nextImage.src = dataUri
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
const canvas = document.createElement('canvas')
|
|
122
|
-
canvas.width = image.naturalWidth || image.width
|
|
123
|
-
canvas.height = image.naturalHeight || image.height
|
|
124
|
-
const context = canvas.getContext('2d', { willReadFrequently: true })
|
|
125
|
-
if (!context || canvas.width === 0 || canvas.height === 0) return dataUri
|
|
126
|
-
|
|
127
|
-
context.drawImage(image, 0, 0)
|
|
128
|
-
const pixels = context.getImageData(0, 0, canvas.width, canvas.height)
|
|
129
|
-
let minX = canvas.width
|
|
130
|
-
let minY = canvas.height
|
|
131
|
-
let maxX = -1
|
|
132
|
-
let maxY = -1
|
|
133
|
-
|
|
134
|
-
for (let y = 0; y < canvas.height; y += 1) {
|
|
135
|
-
for (let x = 0; x < canvas.width; x += 1) {
|
|
136
|
-
const alpha = pixels.data[(y * canvas.width + x) * 4 + 3]
|
|
137
|
-
if (alpha > 12) {
|
|
138
|
-
minX = Math.min(minX, x)
|
|
139
|
-
minY = Math.min(minY, y)
|
|
140
|
-
maxX = Math.max(maxX, x)
|
|
141
|
-
maxY = Math.max(maxY, y)
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (maxX < minX || maxY < minY) return dataUri
|
|
147
|
-
|
|
148
|
-
const padding = 8
|
|
149
|
-
const sx = Math.max(0, minX - padding)
|
|
150
|
-
const sy = Math.max(0, minY - padding)
|
|
151
|
-
const sw = Math.min(canvas.width - sx, maxX - minX + 1 + padding * 2)
|
|
152
|
-
const sh = Math.min(canvas.height - sy, maxY - minY + 1 + padding * 2)
|
|
153
|
-
|
|
154
|
-
if (sw >= canvas.width * 0.92 && sh >= canvas.height * 0.92) return dataUri
|
|
155
|
-
|
|
156
|
-
const previewCanvas = document.createElement('canvas')
|
|
157
|
-
previewCanvas.width = sw
|
|
158
|
-
previewCanvas.height = sh
|
|
159
|
-
const previewContext = previewCanvas.getContext('2d')
|
|
160
|
-
if (!previewContext) return dataUri
|
|
161
|
-
previewContext.drawImage(canvas, sx, sy, sw, sh, 0, 0, sw, sh)
|
|
162
|
-
return previewCanvas.toDataURL('image/png')
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const lightenColor = (hex: string, amount: number) => {
|
|
166
|
-
const clean = hex.replace('#', '')
|
|
167
|
-
if (clean.length !== 6) return hex
|
|
168
|
-
const num = parseInt(clean, 16)
|
|
169
|
-
const r = Math.min(255, (num >> 16) + amount)
|
|
170
|
-
const g = Math.min(255, ((num >> 8) & 0x00FF) + amount)
|
|
171
|
-
const b = Math.min(255, (num & 0x0000FF) + amount)
|
|
172
|
-
return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const hexToRgb = (hex: string) => {
|
|
176
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
|
177
|
-
return result ? {
|
|
178
|
-
r: parseInt(result[1], 16),
|
|
179
|
-
g: parseInt(result[2], 16),
|
|
180
|
-
b: parseInt(result[3], 16),
|
|
181
|
-
} : { r: 15, g: 23, b: 42 }
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const applyThemeStyles = (cfg: any) => {
|
|
185
|
-
const theme = cfg.theme || 'dark'
|
|
186
|
-
const accentColor = cfg.accentColor || '#4f83e6'
|
|
187
|
-
const systemTextColor = cfg.systemTextColor || '#f8fafc'
|
|
188
|
-
|
|
189
|
-
document.documentElement.setAttribute('data-theme', theme)
|
|
190
|
-
document.documentElement.style.setProperty('--accent', accentColor)
|
|
191
|
-
document.documentElement.style.setProperty('--accent-hover', lightenColor(accentColor, 20))
|
|
192
|
-
document.documentElement.style.setProperty('--text-main', systemTextColor)
|
|
193
|
-
document.documentElement.style.setProperty('--glass-blur', cfg.glassBlur || 'blur(16px)')
|
|
194
|
-
document.body.style.fontFamily = cfg.fontFamily || "'Outfit', sans-serif"
|
|
195
|
-
document.documentElement.style.fontSize = cfg.fontSize || '18px'
|
|
196
|
-
|
|
197
|
-
if (theme === 'custom') {
|
|
198
|
-
if (cfg.customBgStart && cfg.customBgEnd) {
|
|
199
|
-
document.documentElement.style.setProperty('--bg-color', cfg.customBgStart)
|
|
200
|
-
document.documentElement.style.setProperty('--bg-gradient', `linear-gradient(135deg, ${cfg.customBgStart} 0%, ${cfg.customBgEnd} 100%)`)
|
|
201
|
-
}
|
|
202
|
-
if (cfg.customPanelBg) {
|
|
203
|
-
const rgb = hexToRgb(cfg.customPanelBg)
|
|
204
|
-
document.documentElement.style.setProperty('--panel-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.75)`)
|
|
205
|
-
document.documentElement.style.setProperty('--panel-raised', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.82)`)
|
|
206
|
-
document.documentElement.style.setProperty('--panel-soft', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.46)`)
|
|
207
|
-
document.documentElement.style.setProperty('--chrome-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.88)`)
|
|
208
|
-
document.documentElement.style.setProperty('--surface-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.62)`)
|
|
209
|
-
document.documentElement.style.setProperty('--surface-strong', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.86)`)
|
|
210
|
-
document.documentElement.style.setProperty('--input-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.72)`)
|
|
211
|
-
}
|
|
212
|
-
return
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
;[
|
|
216
|
-
'--bg-color',
|
|
217
|
-
'--bg-gradient',
|
|
218
|
-
'--panel-bg',
|
|
219
|
-
'--panel-raised',
|
|
220
|
-
'--panel-soft',
|
|
221
|
-
'--chrome-bg',
|
|
222
|
-
'--surface-bg',
|
|
223
|
-
'--surface-strong',
|
|
224
|
-
'--input-bg',
|
|
225
|
-
].forEach((name) => document.documentElement.style.removeProperty(name))
|
|
226
|
-
}
|
|
227
98
|
|
|
228
99
|
export default function MintDashboard() {
|
|
229
100
|
const [view, setView] = useState<DashboardView>('chat')
|
|
@@ -268,6 +139,7 @@ export default function MintDashboard() {
|
|
|
268
139
|
const [chatSessions, setChatSessions] = useState<ChatSession[]>([])
|
|
269
140
|
const chatEnd = useRef<HTMLDivElement | null>(null)
|
|
270
141
|
const startupReady = (dashboardDataReady && modelReady) || startupTimedOut
|
|
142
|
+
const [proactiveSuggestion, setProactiveSuggestion] = useState<any>(null)
|
|
271
143
|
|
|
272
144
|
const [isSearchOpen, setIsSearchOpen] = useState(false)
|
|
273
145
|
const [searchQuery, setSearchQuery] = useState('')
|
|
@@ -419,10 +291,14 @@ export default function MintDashboard() {
|
|
|
419
291
|
setPendingApproval(event.payload)
|
|
420
292
|
}
|
|
421
293
|
})
|
|
294
|
+
const unlistenProactive = window.api.onProactiveSuggestion?.((suggestion: any) => {
|
|
295
|
+
setProactiveSuggestion(suggestion)
|
|
296
|
+
})
|
|
422
297
|
return () => {
|
|
423
298
|
unlistenPromise?.then?.((unlisten) => unlisten?.())
|
|
424
299
|
unlistenSpotlight?.then?.((unlisten) => unlisten?.())
|
|
425
300
|
unlistenVision?.then?.((unlisten) => unlisten?.())
|
|
301
|
+
unlistenProactive?.then?.((unlisten) => unlisten?.())
|
|
426
302
|
}
|
|
427
303
|
}, [])
|
|
428
304
|
|
|
@@ -502,14 +378,14 @@ export default function MintDashboard() {
|
|
|
502
378
|
}
|
|
503
379
|
}, [sending])
|
|
504
380
|
|
|
505
|
-
async function handleApproval(approved: boolean, autoApproveSession = false) {
|
|
381
|
+
async function handleApproval(approved: boolean, autoApproveSession = false, answer?: string) {
|
|
506
382
|
if (!pendingApproval) return
|
|
507
383
|
try {
|
|
508
384
|
if (autoApproveSession) {
|
|
509
385
|
sessionAutoApprovedRef.current = true
|
|
510
386
|
setSessionAutoApproved(true)
|
|
511
387
|
}
|
|
512
|
-
await submitToolApproval(pendingApproval.token, approved)
|
|
388
|
+
await submitToolApproval(pendingApproval.token, approved, answer)
|
|
513
389
|
} catch (reason) {
|
|
514
390
|
setError(errorMessage(reason))
|
|
515
391
|
} finally {
|
|
@@ -517,6 +393,20 @@ export default function MintDashboard() {
|
|
|
517
393
|
}
|
|
518
394
|
}
|
|
519
395
|
|
|
396
|
+
async function handleCancelMessage() {
|
|
397
|
+
if (!sending || !streamingConversationId) return
|
|
398
|
+
try {
|
|
399
|
+
await cancelChatMessage(streamingConversationId)
|
|
400
|
+
} catch (e) {
|
|
401
|
+
console.error("Failed to cancel message stream:", e)
|
|
402
|
+
} finally {
|
|
403
|
+
setSending(false)
|
|
404
|
+
setStreamingConversationId(null)
|
|
405
|
+
setSendingMessage('')
|
|
406
|
+
setSendingImageCount(0)
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
520
410
|
async function sendPrompt(
|
|
521
411
|
promptText: string,
|
|
522
412
|
options: {
|
|
@@ -608,6 +498,17 @@ export default function MintDashboard() {
|
|
|
608
498
|
}
|
|
609
499
|
}
|
|
610
500
|
|
|
501
|
+
const handleProactiveAction = async (action: any) => {
|
|
502
|
+
setProactiveSuggestion(null)
|
|
503
|
+
if (action && action.type !== 'none') {
|
|
504
|
+
try {
|
|
505
|
+
await window.api.executeProactiveAction(action)
|
|
506
|
+
} catch (err) {
|
|
507
|
+
setError(String(err))
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
611
512
|
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
|
|
612
513
|
event.preventDefault()
|
|
613
514
|
const trimmed = message.trim()
|
|
@@ -689,37 +590,6 @@ export default function MintDashboard() {
|
|
|
689
590
|
return true
|
|
690
591
|
}
|
|
691
592
|
|
|
692
|
-
async function readClipboardImage() {
|
|
693
|
-
try {
|
|
694
|
-
const dataUri = await readTauriClipboardImage()
|
|
695
|
-
if (dataUri) {
|
|
696
|
-
const previewDataUri = await createTrimmedImagePreview(dataUri).catch(() => dataUri)
|
|
697
|
-
setImageAttachments((current) => [...current, { dataUri, previewDataUri, name: 'Pasted image' }])
|
|
698
|
-
return true
|
|
699
|
-
}
|
|
700
|
-
} catch (err) {
|
|
701
|
-
console.warn('Tauri clipboard fallback error:', err)
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
try {
|
|
705
|
-
if (!navigator.clipboard?.read) return false
|
|
706
|
-
const items = await navigator.clipboard.read()
|
|
707
|
-
for (const item of items) {
|
|
708
|
-
const imageType = item.types.find((type) => type.startsWith('image/'))
|
|
709
|
-
if (!imageType) continue
|
|
710
|
-
const blob = await item.getType(imageType)
|
|
711
|
-
const file = new File([blob], 'Pasted image', { type: imageType })
|
|
712
|
-
const dataUri = await readImage(file)
|
|
713
|
-
const previewDataUri = await createTrimmedImagePreview(dataUri).catch(() => dataUri)
|
|
714
|
-
setImageAttachments((current) => [...current, { dataUri, previewDataUri, name: 'Pasted image' }])
|
|
715
|
-
return true
|
|
716
|
-
}
|
|
717
|
-
return false
|
|
718
|
-
} catch {
|
|
719
|
-
// Some environments expose pasted images only through ClipboardEvent.
|
|
720
|
-
return false
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
593
|
|
|
724
594
|
async function selectDocument(event: ChangeEvent<HTMLInputElement>) {
|
|
725
595
|
const file = event.target.files?.[0]
|
|
@@ -1018,6 +888,28 @@ export default function MintDashboard() {
|
|
|
1018
888
|
onSetSearchOpen={setIsSearchOpen}
|
|
1019
889
|
/>
|
|
1020
890
|
<main className={`assistant-workspace ${layoutPreset === 'chat-wide' ? 'layout-chat-wide' : 'layout-model-wide'} ${modelVisible || view === 'workspace' ? '' : 'model-hidden'} ${view === 'workspace' ? 'workspace-open' : ''}`}>
|
|
891
|
+
{proactiveSuggestion && (
|
|
892
|
+
<div className="proactive-bar" style={{ position: 'absolute', top: 0, left: 0, right: 0, zIndex: 100 }}>
|
|
893
|
+
<div className="proactive-header">
|
|
894
|
+
<span className="proactive-icon">✨</span>
|
|
895
|
+
<div className="proactive-message">{proactiveSuggestion.message}</div>
|
|
896
|
+
<button className="proactive-dismiss-btn" onClick={() => setProactiveSuggestion(null)}>
|
|
897
|
+
Dismiss
|
|
898
|
+
</button>
|
|
899
|
+
</div>
|
|
900
|
+
<div className="proactive-chips">
|
|
901
|
+
{proactiveSuggestion.suggestions?.map((sug: any, i: number) => (
|
|
902
|
+
<button
|
|
903
|
+
key={i}
|
|
904
|
+
className="suggestion-chip"
|
|
905
|
+
onClick={() => handleProactiveAction(sug.action)}
|
|
906
|
+
>
|
|
907
|
+
{sug.label}
|
|
908
|
+
</button>
|
|
909
|
+
))}
|
|
910
|
+
</div>
|
|
911
|
+
</div>
|
|
912
|
+
)}
|
|
1021
913
|
{view === 'workspace' && (
|
|
1022
914
|
<WorkspacePanel
|
|
1023
915
|
agentMode={agentMode}
|
|
@@ -1072,7 +964,6 @@ export default function MintDashboard() {
|
|
|
1072
964
|
onSelectImage={selectImage}
|
|
1073
965
|
onSelectDocument={selectDocument}
|
|
1074
966
|
onPasteImage={pasteImage}
|
|
1075
|
-
onReadClipboardImage={readClipboardImage}
|
|
1076
967
|
onSetMessage={setMessage}
|
|
1077
968
|
onSendVoiceMessage={sendVoiceMessage}
|
|
1078
969
|
onRemoveImage={(idx: number) => {
|
|
@@ -1088,6 +979,7 @@ export default function MintDashboard() {
|
|
|
1088
979
|
settingsConfig={settingsConfig}
|
|
1089
980
|
onSetModel={changeModel}
|
|
1090
981
|
onApproval={handleApproval}
|
|
982
|
+
onCancelMessage={handleCancelMessage}
|
|
1091
983
|
/>
|
|
1092
984
|
</main>
|
|
1093
985
|
<PicturesLibrary view={view} pictures={pictures} onSetView={setView} onRefreshPictures={refreshPictures} />
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
1
2
|
import { type PictureEntry, convertFileSrc } from '../tauri'
|
|
2
3
|
import type { DashboardView } from './DashboardSidebar'
|
|
3
4
|
|
|
@@ -9,6 +10,16 @@ interface PicturesLibraryProps {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export default function PicturesLibrary({ view, pictures, onSetView, onRefreshPictures }: PicturesLibraryProps) {
|
|
13
|
+
const [visibleCount, setVisibleCount] = useState(24)
|
|
14
|
+
const visiblePictures = useMemo(
|
|
15
|
+
() => pictures.slice(0, visibleCount),
|
|
16
|
+
[pictures, visibleCount],
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
setVisibleCount(24)
|
|
21
|
+
}, [view, pictures])
|
|
22
|
+
|
|
12
23
|
return (
|
|
13
24
|
<section className={`pictures-library ${view === 'pictures' ? 'is-visible' : ''}`} aria-hidden={view !== 'pictures'}>
|
|
14
25
|
<header className="pictures-header">
|
|
@@ -34,14 +45,27 @@ export default function PicturesLibrary({ view, pictures, onSetView, onRefreshPi
|
|
|
34
45
|
<span>Images appear here after a message with an attachment is sent successfully.</span>
|
|
35
46
|
</div>
|
|
36
47
|
) : (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
<>
|
|
49
|
+
<div className="pictures-grid">
|
|
50
|
+
{visiblePictures.map((picture, index) => (
|
|
51
|
+
<article className="picture-card" key={picture.id}>
|
|
52
|
+
<img src={convertFileSrc(picture.thumbnailPath || picture.thumbnailUrl || picture.path)} alt={picture.message || picture.filename} loading={index < 6 ? 'eager' : 'lazy'} decoding="async" />
|
|
53
|
+
<div className="picture-card-meta"><span>{picture.message || picture.filename}</span></div>
|
|
54
|
+
</article>
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
{visibleCount < pictures.length && (
|
|
58
|
+
<div className="pictures-load-more-container">
|
|
59
|
+
<button
|
|
60
|
+
type="button"
|
|
61
|
+
className="pictures-load-more-btn"
|
|
62
|
+
onClick={() => setVisibleCount((prev) => prev + 24)}
|
|
63
|
+
>
|
|
64
|
+
Load More ({pictures.length - visibleCount} remaining)
|
|
65
|
+
</button>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
</>
|
|
45
69
|
)}
|
|
46
70
|
</section>
|
|
47
71
|
)
|