@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>
|
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
listSavedPictures,
|
|
12
12
|
saveInteractionAgentActivity,
|
|
13
13
|
streamChatMessage,
|
|
14
|
+
cancelChatMessage,
|
|
14
15
|
submitToolApproval,
|
|
15
16
|
listen,
|
|
16
|
-
readClipboardImage as readTauriClipboardImage,
|
|
17
17
|
type AgentProgress,
|
|
18
18
|
type ChatResponse,
|
|
19
19
|
type ChatSession,
|
|
@@ -25,6 +25,13 @@ import ChatPanel from './ChatPanel'
|
|
|
25
25
|
import DashboardSidebar, { type DashboardView } from './DashboardSidebar'
|
|
26
26
|
import PicturesLibrary from './PicturesLibrary'
|
|
27
27
|
import ImageStudioPanel from './ImageStudioPanel'
|
|
28
|
+
import {
|
|
29
|
+
errorMessage,
|
|
30
|
+
readImage,
|
|
31
|
+
readDocument,
|
|
32
|
+
createTrimmedImagePreview,
|
|
33
|
+
applyThemeStyles,
|
|
34
|
+
} from '../../shared/utils/ui'
|
|
28
35
|
|
|
29
36
|
const DEFAULT_CONFIG = {
|
|
30
37
|
theme: 'dark',
|
|
@@ -66,142 +73,6 @@ const MOCK_WELCOME_INTERACTION = {
|
|
|
66
73
|
createdAt: new Date().toISOString(),
|
|
67
74
|
}
|
|
68
75
|
|
|
69
|
-
function errorMessage(reason: unknown) {
|
|
70
|
-
return reason instanceof Error ? reason.message : String(reason)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function readImage(file: File): Promise<string> {
|
|
74
|
-
return new Promise((resolve, reject) => {
|
|
75
|
-
const reader = new FileReader()
|
|
76
|
-
reader.onload = () => resolve(String(reader.result))
|
|
77
|
-
reader.onerror = () => reject(reader.error ?? new Error('Unable to read image'))
|
|
78
|
-
reader.readAsDataURL(file)
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function readDocument(file: File): Promise<string> {
|
|
83
|
-
return new Promise((resolve, reject) => {
|
|
84
|
-
const reader = new FileReader()
|
|
85
|
-
reader.onload = () => resolve(String(reader.result))
|
|
86
|
-
reader.onerror = () => reject(reader.error ?? new Error('Unable to read document'))
|
|
87
|
-
reader.readAsDataURL(file)
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async function createTrimmedImagePreview(dataUri: string): Promise<string> {
|
|
92
|
-
const image = await new Promise<HTMLImageElement>((resolve, reject) => {
|
|
93
|
-
const nextImage = new Image()
|
|
94
|
-
nextImage.onload = () => resolve(nextImage)
|
|
95
|
-
nextImage.onerror = () => reject(new Error('Unable to prepare image preview'))
|
|
96
|
-
nextImage.src = dataUri
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
const canvas = document.createElement('canvas')
|
|
100
|
-
canvas.width = image.naturalWidth || image.width
|
|
101
|
-
canvas.height = image.naturalHeight || image.height
|
|
102
|
-
const context = canvas.getContext('2d', { willReadFrequently: true })
|
|
103
|
-
if (!context || canvas.width === 0 || canvas.height === 0) return dataUri
|
|
104
|
-
|
|
105
|
-
context.drawImage(image, 0, 0)
|
|
106
|
-
const pixels = context.getImageData(0, 0, canvas.width, canvas.height)
|
|
107
|
-
let minX = canvas.width
|
|
108
|
-
let minY = canvas.height
|
|
109
|
-
let maxX = -1
|
|
110
|
-
let maxY = -1
|
|
111
|
-
|
|
112
|
-
for (let y = 0; y < canvas.height; y += 1) {
|
|
113
|
-
for (let x = 0; x < canvas.width; x += 1) {
|
|
114
|
-
const alpha = pixels.data[(y * canvas.width + x) * 4 + 3]
|
|
115
|
-
if (alpha > 12) {
|
|
116
|
-
minX = Math.min(minX, x)
|
|
117
|
-
minY = Math.min(minY, y)
|
|
118
|
-
maxX = Math.max(maxX, x)
|
|
119
|
-
maxY = Math.max(maxY, y)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (maxX < minX || maxY < minY) return dataUri
|
|
125
|
-
|
|
126
|
-
const padding = 8
|
|
127
|
-
const sx = Math.max(0, minX - padding)
|
|
128
|
-
const sy = Math.max(0, minY - padding)
|
|
129
|
-
const sw = Math.min(canvas.width - sx, maxX - minX + 1 + padding * 2)
|
|
130
|
-
const sh = Math.min(canvas.height - sy, maxY - minY + 1 + padding * 2)
|
|
131
|
-
|
|
132
|
-
if (sw >= canvas.width * 0.92 && sh >= canvas.height * 0.92) return dataUri
|
|
133
|
-
|
|
134
|
-
const previewCanvas = document.createElement('canvas')
|
|
135
|
-
previewCanvas.width = sw
|
|
136
|
-
previewCanvas.height = sh
|
|
137
|
-
const previewContext = previewCanvas.getContext('2d')
|
|
138
|
-
if (!previewContext) return dataUri
|
|
139
|
-
previewContext.drawImage(canvas, sx, sy, sw, sh, 0, 0, sw, sh)
|
|
140
|
-
return previewCanvas.toDataURL('image/png')
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const lightenColor = (hex: string, amount: number) => {
|
|
144
|
-
const clean = hex.replace('#', '')
|
|
145
|
-
if (clean.length !== 6) return hex
|
|
146
|
-
const num = parseInt(clean, 16)
|
|
147
|
-
const r = Math.min(255, (num >> 16) + amount)
|
|
148
|
-
const g = Math.min(255, ((num >> 8) & 0x00FF) + amount)
|
|
149
|
-
const b = Math.min(255, (num & 0x0000FF) + amount)
|
|
150
|
-
return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const hexToRgb = (hex: string) => {
|
|
154
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
|
155
|
-
return result ? {
|
|
156
|
-
r: parseInt(result[1], 16),
|
|
157
|
-
g: parseInt(result[2], 16),
|
|
158
|
-
b: parseInt(result[3], 16),
|
|
159
|
-
} : { r: 15, g: 23, b: 42 }
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const applyThemeStyles = (cfg: any) => {
|
|
163
|
-
const theme = cfg.theme || 'dark'
|
|
164
|
-
const accentColor = cfg.accentColor || '#4f83e6'
|
|
165
|
-
const systemTextColor = cfg.systemTextColor || '#f8fafc'
|
|
166
|
-
|
|
167
|
-
document.documentElement.setAttribute('data-theme', theme)
|
|
168
|
-
document.documentElement.style.setProperty('--accent', accentColor)
|
|
169
|
-
document.documentElement.style.setProperty('--accent-hover', lightenColor(accentColor, 20))
|
|
170
|
-
document.documentElement.style.setProperty('--text-main', systemTextColor)
|
|
171
|
-
document.documentElement.style.setProperty('--glass-blur', cfg.glassBlur || 'blur(16px)')
|
|
172
|
-
document.body.style.fontFamily = cfg.fontFamily || "'Outfit', sans-serif"
|
|
173
|
-
document.documentElement.style.fontSize = cfg.fontSize || '18px'
|
|
174
|
-
|
|
175
|
-
if (theme === 'custom') {
|
|
176
|
-
if (cfg.customBgStart && cfg.customBgEnd) {
|
|
177
|
-
document.documentElement.style.setProperty('--bg-color', cfg.customBgStart)
|
|
178
|
-
document.documentElement.style.setProperty('--bg-gradient', `linear-gradient(135deg, ${cfg.customBgStart} 0%, ${cfg.customBgEnd} 100%)`)
|
|
179
|
-
}
|
|
180
|
-
if (cfg.customPanelBg) {
|
|
181
|
-
const rgb = hexToRgb(cfg.customPanelBg)
|
|
182
|
-
document.documentElement.style.setProperty('--panel-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.75)`)
|
|
183
|
-
document.documentElement.style.setProperty('--panel-raised', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.82)`)
|
|
184
|
-
document.documentElement.style.setProperty('--panel-soft', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.46)`)
|
|
185
|
-
document.documentElement.style.setProperty('--chrome-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.88)`)
|
|
186
|
-
document.documentElement.style.setProperty('--surface-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.62)`)
|
|
187
|
-
document.documentElement.style.setProperty('--surface-strong', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.86)`)
|
|
188
|
-
document.documentElement.style.setProperty('--input-bg', `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.72)`)
|
|
189
|
-
}
|
|
190
|
-
return
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
;[
|
|
194
|
-
'--bg-color',
|
|
195
|
-
'--bg-gradient',
|
|
196
|
-
'--panel-bg',
|
|
197
|
-
'--panel-raised',
|
|
198
|
-
'--panel-soft',
|
|
199
|
-
'--chrome-bg',
|
|
200
|
-
'--surface-bg',
|
|
201
|
-
'--surface-strong',
|
|
202
|
-
'--input-bg',
|
|
203
|
-
].forEach((name) => document.documentElement.style.removeProperty(name))
|
|
204
|
-
}
|
|
205
76
|
|
|
206
77
|
export default function MintDashboard() {
|
|
207
78
|
const [view, setView] = useState<DashboardView>('chat')
|
|
@@ -384,6 +255,10 @@ export default function MintDashboard() {
|
|
|
384
255
|
}
|
|
385
256
|
|
|
386
257
|
const toggleSidebar = () => {
|
|
258
|
+
if (window.innerWidth <= 760) {
|
|
259
|
+
setMobileSidebarOpen(false)
|
|
260
|
+
return
|
|
261
|
+
}
|
|
387
262
|
const next = !sidebarCollapsed
|
|
388
263
|
window.localStorage.setItem('mint:sidebar-collapsed', String(next))
|
|
389
264
|
setSidebarCollapsed(next)
|
|
@@ -400,10 +275,10 @@ export default function MintDashboard() {
|
|
|
400
275
|
setAgentMode(enabled)
|
|
401
276
|
}
|
|
402
277
|
|
|
403
|
-
async function handleApproval(approved: boolean, _autoApproveSession = false) {
|
|
278
|
+
async function handleApproval(approved: boolean, _autoApproveSession = false, answer?: string) {
|
|
404
279
|
if (!pendingApproval) return
|
|
405
280
|
try {
|
|
406
|
-
await submitToolApproval(pendingApproval.token, approved)
|
|
281
|
+
await submitToolApproval(pendingApproval.token, approved, answer)
|
|
407
282
|
} catch (reason) {
|
|
408
283
|
setError(errorMessage(reason))
|
|
409
284
|
} finally {
|
|
@@ -411,6 +286,20 @@ export default function MintDashboard() {
|
|
|
411
286
|
}
|
|
412
287
|
}
|
|
413
288
|
|
|
289
|
+
async function handleCancelMessage() {
|
|
290
|
+
if (!sending || !streamingConversationId) return
|
|
291
|
+
try {
|
|
292
|
+
await cancelChatMessage(streamingConversationId)
|
|
293
|
+
} catch (e) {
|
|
294
|
+
console.error("Failed to cancel message stream:", e)
|
|
295
|
+
} finally {
|
|
296
|
+
setSending(false)
|
|
297
|
+
setStreamingConversationId(null)
|
|
298
|
+
setSendingMessage('')
|
|
299
|
+
setSendingImageCount(0)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
414
303
|
async function sendPrompt(
|
|
415
304
|
promptText: string,
|
|
416
305
|
options: {
|
|
@@ -583,37 +472,6 @@ export default function MintDashboard() {
|
|
|
583
472
|
return true
|
|
584
473
|
}
|
|
585
474
|
|
|
586
|
-
async function readClipboardImage() {
|
|
587
|
-
try {
|
|
588
|
-
const dataUri = await readTauriClipboardImage()
|
|
589
|
-
if (dataUri) {
|
|
590
|
-
const previewDataUri = await createTrimmedImagePreview(dataUri).catch(() => dataUri)
|
|
591
|
-
setImageAttachments((current) => [...current, { dataUri, previewDataUri, name: 'Pasted image' }])
|
|
592
|
-
return true
|
|
593
|
-
}
|
|
594
|
-
} catch (err) {
|
|
595
|
-
console.warn('Tauri clipboard fallback error:', err)
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
try {
|
|
599
|
-
if (!navigator.clipboard?.read) return false
|
|
600
|
-
const items = await navigator.clipboard.read()
|
|
601
|
-
for (const item of items) {
|
|
602
|
-
const imageType = item.types.find((type) => type.startsWith('image/'))
|
|
603
|
-
if (!imageType) continue
|
|
604
|
-
const blob = await item.getType(imageType)
|
|
605
|
-
const file = new File([blob], 'Pasted image', { type: imageType })
|
|
606
|
-
const dataUri = await readImage(file)
|
|
607
|
-
const previewDataUri = await createTrimmedImagePreview(dataUri).catch(() => dataUri)
|
|
608
|
-
setImageAttachments((current) => [...current, { dataUri, previewDataUri, name: 'Pasted image' }])
|
|
609
|
-
return true
|
|
610
|
-
}
|
|
611
|
-
return false
|
|
612
|
-
} catch {
|
|
613
|
-
// Some environments expose pasted images only through ClipboardEvent.
|
|
614
|
-
return false
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
475
|
|
|
618
476
|
async function selectDocument(event: ChangeEvent<HTMLInputElement>) {
|
|
619
477
|
const file = event.target.files?.[0]
|
|
@@ -825,7 +683,7 @@ export default function MintDashboard() {
|
|
|
825
683
|
|
|
826
684
|
return (
|
|
827
685
|
<div className={`app-container ${startupReady ? '' : 'is-loading'}`}>
|
|
828
|
-
<div className={`app-body ${sidebarCollapsed ? 'sidebar-collapsed' : ''} ${view === 'pictures' ? 'pictures-open' : ''} ${mobileSidebarOpen ? 'mobile-sidebar-open' : ''}`}>
|
|
686
|
+
<div className={`app-body ${(sidebarCollapsed && window.innerWidth > 760) ? 'sidebar-collapsed' : ''} ${view === 'pictures' ? 'pictures-open' : ''} ${mobileSidebarOpen ? 'mobile-sidebar-open' : ''}`}>
|
|
829
687
|
{mobileSidebarOpen && (
|
|
830
688
|
<div
|
|
831
689
|
className="sidebar-backdrop"
|
|
@@ -882,7 +740,6 @@ export default function MintDashboard() {
|
|
|
882
740
|
onSelectImage={selectImage}
|
|
883
741
|
onSelectDocument={selectDocument}
|
|
884
742
|
onPasteImage={pasteImage}
|
|
885
|
-
onReadClipboardImage={readClipboardImage}
|
|
886
743
|
onSetMessage={setMessage}
|
|
887
744
|
onSendVoiceMessage={sendVoiceMessage}
|
|
888
745
|
onRemoveImage={(idx: number) => {
|
|
@@ -897,6 +754,7 @@ export default function MintDashboard() {
|
|
|
897
754
|
settingsConfig={settingsConfig}
|
|
898
755
|
onSetModel={changeModel}
|
|
899
756
|
onApproval={handleApproval}
|
|
757
|
+
onCancelMessage={handleCancelMessage}
|
|
900
758
|
onToggleMobileSidebar={() => setMobileSidebarOpen(!mobileSidebarOpen)}
|
|
901
759
|
/>
|
|
902
760
|
</main>
|
|
@@ -908,6 +766,7 @@ export default function MintDashboard() {
|
|
|
908
766
|
setView('chat')
|
|
909
767
|
setMessage(imgPrompt)
|
|
910
768
|
}}
|
|
769
|
+
onToggleMobileSidebar={() => setMobileSidebarOpen(!mobileSidebarOpen)}
|
|
911
770
|
/>
|
|
912
771
|
</div>
|
|
913
772
|
<div className={`startup-loading ${startupReady ? 'is-hidden' : ''}`} aria-live="polite" aria-busy={!startupReady}>
|
|
@@ -2,10 +2,6 @@ import { useEffect, useMemo, useState } from 'react'
|
|
|
2
2
|
import { type PictureEntry, convertFileSrc } from '../tauri'
|
|
3
3
|
import type { DashboardView } from './DashboardSidebar'
|
|
4
4
|
|
|
5
|
-
const INITIAL_VISIBLE_PICTURES = 18
|
|
6
|
-
const PICTURE_RENDER_BATCH_SIZE = 18
|
|
7
|
-
const PICTURE_RENDER_BATCH_DELAY_MS = 80
|
|
8
|
-
|
|
9
5
|
interface PicturesLibraryProps {
|
|
10
6
|
view: DashboardView
|
|
11
7
|
pictures: PictureEntry[]
|
|
@@ -14,31 +10,16 @@ interface PicturesLibraryProps {
|
|
|
14
10
|
}
|
|
15
11
|
|
|
16
12
|
export default function PicturesLibrary({ view, pictures, onSetView, onRefreshPictures }: PicturesLibraryProps) {
|
|
17
|
-
const [visibleCount, setVisibleCount] = useState(
|
|
13
|
+
const [visibleCount, setVisibleCount] = useState(24)
|
|
18
14
|
const visiblePictures = useMemo(
|
|
19
15
|
() => pictures.slice(0, visibleCount),
|
|
20
16
|
[pictures, visibleCount],
|
|
21
17
|
)
|
|
22
18
|
|
|
23
19
|
useEffect(() => {
|
|
24
|
-
|
|
25
|
-
setVisibleCount(INITIAL_VISIBLE_PICTURES)
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
setVisibleCount(INITIAL_VISIBLE_PICTURES)
|
|
20
|
+
setVisibleCount(24)
|
|
30
21
|
}, [view, pictures])
|
|
31
22
|
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (view !== 'pictures' || visibleCount >= pictures.length) return
|
|
34
|
-
|
|
35
|
-
const timer = window.setTimeout(() => {
|
|
36
|
-
setVisibleCount((current) => Math.min(current + PICTURE_RENDER_BATCH_SIZE, pictures.length))
|
|
37
|
-
}, PICTURE_RENDER_BATCH_DELAY_MS)
|
|
38
|
-
|
|
39
|
-
return () => window.clearTimeout(timer)
|
|
40
|
-
}, [view, pictures.length, visibleCount])
|
|
41
|
-
|
|
42
23
|
return (
|
|
43
24
|
<section className={`pictures-library ${view === 'pictures' ? 'is-visible' : ''}`} aria-hidden={view !== 'pictures'}>
|
|
44
25
|
<header className="pictures-header">
|
|
@@ -61,14 +42,27 @@ export default function PicturesLibrary({ view, pictures, onSetView, onRefreshPi
|
|
|
61
42
|
<span>Images appear here after a message with an attachment is sent successfully.</span>
|
|
62
43
|
</div>
|
|
63
44
|
) : (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
45
|
+
<>
|
|
46
|
+
<div className="pictures-grid">
|
|
47
|
+
{visiblePictures.map((picture, index) => (
|
|
48
|
+
<article className="picture-card" key={picture.id}>
|
|
49
|
+
<img src={convertFileSrc(picture.thumbnailPath || picture.thumbnailUrl || picture.path)} alt={picture.message || picture.filename} loading={index < 6 ? 'eager' : 'lazy'} decoding="async" />
|
|
50
|
+
<div className="picture-card-meta"><span>{picture.message || picture.filename}</span></div>
|
|
51
|
+
</article>
|
|
52
|
+
))}
|
|
53
|
+
</div>
|
|
54
|
+
{visibleCount < pictures.length && (
|
|
55
|
+
<div className="pictures-load-more-container">
|
|
56
|
+
<button
|
|
57
|
+
type="button"
|
|
58
|
+
className="pictures-load-more-btn"
|
|
59
|
+
onClick={() => setVisibleCount((prev) => prev + 24)}
|
|
60
|
+
>
|
|
61
|
+
Load More ({pictures.length - visibleCount} remaining)
|
|
62
|
+
</button>
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
</>
|
|
72
66
|
)}
|
|
73
67
|
</section>
|
|
74
68
|
)
|