diff --git a/AGENTS.md b/AGENTS.md index b219e78..c5ff4ac 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -159,3 +159,11 @@ script/ # Build-time code generation - **Output:** builds to `internal/web/dist/`, embedded in Go binary via `//go:embed` - **Lint:** `cd web && pnpm lint` (eslint + oxlint) - Changes to the frontend require rebuilding via `make build-web` for the Go binary to pick them up + +### Icons & Styling + +- **Icons:** use `@heroicons/vue/24/outline` exclusively. Import each icon by name from its subpath (`import { XMarkIcon } from '@heroicons/vue/24/outline'`) for per-file tree-shaking. Do **not** hand-write inline `` icons or `v-html` SVG path strings. +- **Icon sizing:** use Tailwind `w-N h-N` classes (e.g. `class="w-3.5 h-3.5"`), never a `:size` prop. +- **Colors:** every color must come from a CSS custom property defined in `src/styles/tokens.css`. Never hardcode hex/rgb/`#fff`/`white` in `.vue` or `.css`. Text on the primary/destructive fills uses `--color-on-primary` / `--color-on-destructive`; code blocks use `--code-bg` / `--code-border`; syntax highlighting uses `--hljs-*`. +- **Terminal (xterm) colors:** live in tokens (`--term-*` and the 16-color ANSI palette) and are read at runtime via `getComputedStyle` in `TerminalInstance.vue` — see `termTheme()`. Do not define terminal colors inline. +- **Adding a new color:** add the token to `tokens.css` (both `:root` light and `.dark`) first, then reference it by `var(...)`. To theme it per generated theme, edit `internal/theme/palette.go` and regenerate — never edit `tokens.generated.css` by hand. diff --git a/desktop/src-tauri/icons/128x128.png b/desktop/src-tauri/icons/128x128.png index 62e7471..a2b1089 100644 Binary files a/desktop/src-tauri/icons/128x128.png and b/desktop/src-tauri/icons/128x128.png differ diff --git a/desktop/src-tauri/icons/128x128@2x.png b/desktop/src-tauri/icons/128x128@2x.png index 1240ff7..1304454 100644 Binary files a/desktop/src-tauri/icons/128x128@2x.png and b/desktop/src-tauri/icons/128x128@2x.png differ diff --git a/desktop/src-tauri/icons/32x32.png b/desktop/src-tauri/icons/32x32.png index dbab144..eb5dfef 100644 Binary files a/desktop/src-tauri/icons/32x32.png and b/desktop/src-tauri/icons/32x32.png differ diff --git a/desktop/src-tauri/icons/64x64.png b/desktop/src-tauri/icons/64x64.png index 5c871d2..b28a62a 100644 Binary files a/desktop/src-tauri/icons/64x64.png and b/desktop/src-tauri/icons/64x64.png differ diff --git a/desktop/src-tauri/icons/Square107x107Logo.png b/desktop/src-tauri/icons/Square107x107Logo.png index 6863dbe..0253c51 100644 Binary files a/desktop/src-tauri/icons/Square107x107Logo.png and b/desktop/src-tauri/icons/Square107x107Logo.png differ diff --git a/desktop/src-tauri/icons/Square142x142Logo.png b/desktop/src-tauri/icons/Square142x142Logo.png index 618193e..ecaa9d0 100644 Binary files a/desktop/src-tauri/icons/Square142x142Logo.png and b/desktop/src-tauri/icons/Square142x142Logo.png differ diff --git a/desktop/src-tauri/icons/Square150x150Logo.png b/desktop/src-tauri/icons/Square150x150Logo.png index a10b2f4..360a892 100644 Binary files a/desktop/src-tauri/icons/Square150x150Logo.png and b/desktop/src-tauri/icons/Square150x150Logo.png differ diff --git a/desktop/src-tauri/icons/Square284x284Logo.png b/desktop/src-tauri/icons/Square284x284Logo.png index 7f42d60..3afd80e 100644 Binary files a/desktop/src-tauri/icons/Square284x284Logo.png and b/desktop/src-tauri/icons/Square284x284Logo.png differ diff --git a/desktop/src-tauri/icons/Square30x30Logo.png b/desktop/src-tauri/icons/Square30x30Logo.png index ce55f01..a891981 100644 Binary files a/desktop/src-tauri/icons/Square30x30Logo.png and b/desktop/src-tauri/icons/Square30x30Logo.png differ diff --git a/desktop/src-tauri/icons/Square310x310Logo.png b/desktop/src-tauri/icons/Square310x310Logo.png index d1876c0..9c4cee9 100644 Binary files a/desktop/src-tauri/icons/Square310x310Logo.png and b/desktop/src-tauri/icons/Square310x310Logo.png differ diff --git a/desktop/src-tauri/icons/Square44x44Logo.png b/desktop/src-tauri/icons/Square44x44Logo.png index 544fcb3..3fad16dd 100644 Binary files a/desktop/src-tauri/icons/Square44x44Logo.png and b/desktop/src-tauri/icons/Square44x44Logo.png differ diff --git a/desktop/src-tauri/icons/Square71x71Logo.png b/desktop/src-tauri/icons/Square71x71Logo.png index 8d22ebc..e7c455f 100644 Binary files a/desktop/src-tauri/icons/Square71x71Logo.png and b/desktop/src-tauri/icons/Square71x71Logo.png differ diff --git a/desktop/src-tauri/icons/Square89x89Logo.png b/desktop/src-tauri/icons/Square89x89Logo.png index 01008f2..0369d8d 100644 Binary files a/desktop/src-tauri/icons/Square89x89Logo.png and b/desktop/src-tauri/icons/Square89x89Logo.png differ diff --git a/desktop/src-tauri/icons/StoreLogo.png b/desktop/src-tauri/icons/StoreLogo.png index 020e823..52ed5d6 100644 Binary files a/desktop/src-tauri/icons/StoreLogo.png and b/desktop/src-tauri/icons/StoreLogo.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png index b66c449..6949244 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png index cd40909..9807e75 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png index fb93e5b..22c13f3 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png index a2d367e..2bf3c34 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png index 1b2c344..ea0fe96 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png index 4dbc543..3b485db 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png index 9481608..1cc7b93 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png index 58aa4c8..2d8de92 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png index 6d75c5e..eb1cd4a 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png index 12a2533..3812604 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png index e199ac2..07b45fa 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png index a612334..86cb521 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png index 147ed1e..8471438 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png and b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png index 117b887..46bad65 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png and b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png index b2ab90c..334757b 100644 Binary files a/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png and b/desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/desktop/src-tauri/icons/icon.icns b/desktop/src-tauri/icons/icon.icns index 673b3f4..39d0b28 100644 Binary files a/desktop/src-tauri/icons/icon.icns and b/desktop/src-tauri/icons/icon.icns differ diff --git a/desktop/src-tauri/icons/icon.ico b/desktop/src-tauri/icons/icon.ico index ec32956..b95036a 100644 Binary files a/desktop/src-tauri/icons/icon.ico and b/desktop/src-tauri/icons/icon.ico differ diff --git a/desktop/src-tauri/icons/icon.png b/desktop/src-tauri/icons/icon.png index 549d775..b11407a 100644 Binary files a/desktop/src-tauri/icons/icon.png and b/desktop/src-tauri/icons/icon.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png index 5a6813e..1021f8e 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png and b/desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png index cfae1d9..b0fcc61 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png and b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png index cfae1d9..b0fcc61 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png b/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png index e869354..fc26f88 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png and b/desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png index eec3f02..be0daa6 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png and b/desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png index 5697fa5..18d4486 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png and b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png index 5697fa5..18d4486 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png b/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png index e76d9fa..3d54494 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png and b/desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png index cfae1d9..b0fcc61 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png and b/desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png index 2a636ab..3ccee70 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png and b/desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png index 2a636ab..3ccee70 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png b/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png index 271f1fc..fadeb9b 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png and b/desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-512@2x.png b/desktop/src-tauri/icons/ios/AppIcon-512@2x.png index 98983ad..9ec03a1 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-512@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-512@2x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png b/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png index 271f1fc..fadeb9b 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png b/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png index 8cae339..6201340 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png and b/desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png b/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png index 84853ce..0cc3cc4 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png and b/desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png b/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png index d9f6870..6529316 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png differ diff --git a/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png index a2e584e..56a15e8 100644 Binary files a/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png and b/desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png differ diff --git a/internal/web/channel.go b/internal/web/channel.go index 3cc81de..5f95123 100644 --- a/internal/web/channel.go +++ b/internal/web/channel.go @@ -2,6 +2,7 @@ package web import ( "encoding/json" + "io" "net/http" "time" @@ -104,5 +105,47 @@ func (s *Server) handleChannelDisable(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]string{"status": "ok", "state": "disabled"}) } +// handleChannelBLEStatus reports whether the Bluetooth (BLE) status channel is +// enabled in config. The actual BLE notifier is only wired at startup (and only +// on desktop builds with CoreBluetooth), so this reflects the persisted +// preference, which takes effect on the next launch. +func (s *Server) handleChannelBLEStatus(w http.ResponseWriter, r *http.Request) { + enabled := false + if s.cfg != nil && s.cfg.Channel != nil { + enabled = s.cfg.Channel.BLEEnabled + } + writeJSON(w, http.StatusOK, map[string]any{"enabled": enabled}) +} + +// handleSetChannelBLE persists the Bluetooth (BLE) status-channel preference. +// Like the proxy/cert settings, it takes effect after an app restart (the BLE +// notifier is created once at startup when channel.ble_enabled is true). +func (s *Server) handleSetChannelBLE(w http.ResponseWriter, r *http.Request) { + var req struct { + Enabled bool `json:"enabled"` + } + if err := json.NewDecoder(io.LimitReader(r.Body, 1<<16)).Decode(&req); err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid request"}) + return + } + s.mu.Lock() + if s.cfg == nil { + s.mu.Unlock() + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "config unavailable"}) + return + } + if s.cfg.Channel == nil { + s.cfg.Channel = &config.ChannelConfig{} + } + s.cfg.Channel.BLEEnabled = req.Enabled + if err := config.SaveConfig(s.cfg); err != nil { + s.mu.Unlock() + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + s.mu.Unlock() + writeJSON(w, http.StatusOK, map[string]any{"enabled": req.Enabled}) +} + // Ensure writeJSON is used (defined in server.go). var _ = json.Marshal diff --git a/internal/web/server.go b/internal/web/server.go index 545b24f..6ccddeb 100644 --- a/internal/web/server.go +++ b/internal/web/server.go @@ -330,6 +330,8 @@ func (s *Server) Start(ctx context.Context) error { mux.HandleFunc("POST /api/channel/logout", s.handleChannelLogout) mux.HandleFunc("POST /api/channel/enable", s.handleChannelEnable) mux.HandleFunc("POST /api/channel/disable", s.handleChannelDisable) + mux.HandleFunc("GET /api/channel/ble", s.handleChannelBLEStatus) + mux.HandleFunc("POST /api/channel/ble", s.handleSetChannelBLE) // Setup API — available in setup mode (no provider configured yet). mux.HandleFunc("GET /api/setup/providers", s.handleSetupProviders) @@ -2230,6 +2232,15 @@ func (s *Server) handleSetApprovalMode(w http.ResponseWriter, r *http.Request) { config.Logger().Printf("[web] approval mode agent rebuild error: %v", err) } } + // Persist as the default startup mode so the preference survives restarts — + // resolveStartupMode reads cfg.DefaultMode. This makes the Settings toggle a + // true "default", not just a one-off runtime flip. + if s.cfg != nil { + s.cfg.DefaultMode = sm.String() + if err := config.SaveConfig(s.cfg); err != nil { + config.Logger().Printf("[web] approval mode save config failed: %v", err) + } + } s.mu.Unlock() s.wsBroker.Broadcast(WSEvent{ diff --git a/web/index.html b/web/index.html index e8835ee..672f41e 100644 --- a/web/index.html +++ b/web/index.html @@ -2,7 +2,7 @@ - + JCODE — Coding Assistant diff --git a/web/package.json b/web/package.json index d47f8c4..0cef742 100644 --- a/web/package.json +++ b/web/package.json @@ -17,6 +17,7 @@ "dependencies": { "@headlessui/tailwindcss": "^0.2.2", "@headlessui/vue": "^1.7.23", + "@heroicons/vue": "^2.2.0", "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.2.2", "@tauri-apps/api": "^2.9.0", @@ -30,13 +31,12 @@ "@xterm/xterm": "^6.0.0", "dompurify": "^3.4.11", "highlight.js": "^11.11.1", - "lucide-vue-next": "^1.0.0", - "marked": "^18.0.0", "marked": "^18.0.2", "marked-highlight": "^2.2.4", "pinia": "^3.0.4", "qrcode": "^1.5.4", "vue": "^3.5.31", + "vue-i18n": "^11.4.6", "vue-router": "^5.0.4" }, "devDependencies": { diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index bbaeec9..49e4abc 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@headlessui/vue': specifier: ^1.7.23 version: 1.7.23(vue@3.5.32(typescript@6.0.2)) + '@heroicons/vue': + specifier: ^2.2.0 + version: 2.2.0(vue@3.5.32(typescript@6.0.2)) '@tailwindcss/typography': specifier: ^0.5.19 version: 0.5.19(tailwindcss@4.2.2) @@ -53,9 +56,6 @@ importers: highlight.js: specifier: ^11.11.1 version: 11.11.1 - lucide-vue-next: - specifier: ^1.0.0 - version: 1.0.0(vue@3.5.32(typescript@6.0.2)) marked: specifier: ^18.0.2 version: 18.0.2 @@ -71,6 +71,9 @@ importers: vue: specifier: ^3.5.31 version: 3.5.32(typescript@6.0.2) + vue-i18n: + specifier: ^11.4.6 + version: 11.4.6(vue@3.5.32(typescript@6.0.2)) vue-router: specifier: ^5.0.4 version: 5.0.4(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@6.0.2)(vue@3.5.32(typescript@6.0.2)))(vue@3.5.32(typescript@6.0.2)) @@ -332,6 +335,11 @@ packages: peerDependencies: vue: ^3.2.0 + '@heroicons/vue@2.2.0': + resolution: {integrity: sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw==} + peerDependencies: + vue: '>= 3' + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -348,6 +356,22 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@intlify/core-base@11.4.6': + resolution: {integrity: sha512-EOeHO95XESK9IFHgHeZXunsM/WBAoCA0DlaWODvx14vKmetAuS97t+l6Xe9hTUqntPpF93vtVSjjUDafw3wXMw==} + engines: {node: '>= 22'} + + '@intlify/devtools-types@11.4.6': + resolution: {integrity: sha512-wowQPpNem56b2d43IJmqbrzG2FeBKe5f/kUGlpNuBmXs6OSqncF8m1+1lxHuW8ISZJF0ma2RkW3iLkw0g0G4VA==} + engines: {node: '>= 22'} + + '@intlify/message-compiler@11.4.6': + resolution: {integrity: sha512-5nj3jULqeTAC1WovwMs1LQWgatTa2pM/rXN9T3XW8rdOtXW9ZF6/GLSNFTKDQmPLwclhPdgUWLJ/4w3fMeeC/Q==} + engines: {node: '>= 22'} + + '@intlify/shared@11.4.6': + resolution: {integrity: sha512-m1p1HHAMLhqSpTRH7VnXdrN0CQ4y+9vunFkpLkbD8soIuBsnQdawZXqMCgvwI2UVF9Ww7sVaw7g9tV2VO7shoA==} + engines: {node: '>= 22'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1015,6 +1039,9 @@ packages: '@vue/compiler-ssr@3.5.32': resolution: {integrity: sha512-Gp4gTs22T3DgRotZ8aA/6m2jMR+GMztvBXUBEUOYOcST+giyGWJ4WvFd7QLHBkzTxkfOt8IELKNdpzITLbA2rw==} + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + '@vue/devtools-api@7.7.9': resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} @@ -1617,12 +1644,6 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-vue-next@1.0.0: - resolution: {integrity: sha512-V6SPvx1IHTj/UY+FrIYWV5faISsPSb8BnWSFDxAtezWKvWc9ZZ40PDrdu1/Qb5vg4lHWr1hs1BAMGVGm6V1Xdg==} - deprecated: Package deprecated. Please use @lucide/vue instead. - peerDependencies: - vue: '>=3.0.1' - magic-string-ast@1.0.3: resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==} engines: {node: '>=20.19.0'} @@ -2072,6 +2093,12 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + vue-i18n@11.4.6: + resolution: {integrity: sha512-l0gE7Rfy0phCa5ChKYkOq543Wgd39BCK6hkktfr1Ed4D99oRkgPK9ffShASZdeC8OJxGfdWmpYoAaAH6iLEuIg==} + engines: {node: '>= 22'} + peerDependencies: + vue: ^3.0.0 + vue-router@5.0.4: resolution: {integrity: sha512-lCqDLCI2+fKVRl2OzXuzdSWmxXFLQRxQbmHugnRpTMyYiT+hNaycV0faqG5FBHDXoYrZ6MQcX87BvbY8mQ20Bg==} peerDependencies: @@ -2404,6 +2431,10 @@ snapshots: '@tanstack/vue-virtual': 3.13.23(vue@3.5.32(typescript@6.0.2)) vue: 3.5.32(typescript@6.0.2) + '@heroicons/vue@2.2.0(vue@3.5.32(typescript@6.0.2))': + dependencies: + vue: 3.5.32(typescript@6.0.2) + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -2415,6 +2446,24 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@intlify/core-base@11.4.6': + dependencies: + '@intlify/devtools-types': 11.4.6 + '@intlify/message-compiler': 11.4.6 + '@intlify/shared': 11.4.6 + + '@intlify/devtools-types@11.4.6': + dependencies: + '@intlify/core-base': 11.4.6 + '@intlify/shared': 11.4.6 + + '@intlify/message-compiler@11.4.6': + dependencies: + '@intlify/shared': 11.4.6 + source-map-js: 1.2.1 + + '@intlify/shared@11.4.6': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2965,6 +3014,8 @@ snapshots: '@vue/compiler-dom': 3.5.32 '@vue/shared': 3.5.32 + '@vue/devtools-api@6.6.4': {} + '@vue/devtools-api@7.7.9': dependencies: '@vue/devtools-kit': 7.7.9 @@ -3504,10 +3555,6 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-vue-next@1.0.0(vue@3.5.32(typescript@6.0.2)): - dependencies: - vue: 3.5.32(typescript@6.0.2) - magic-string-ast@1.0.3: dependencies: magic-string: 0.30.21 @@ -3959,6 +4006,14 @@ snapshots: transitivePeerDependencies: - supports-color + vue-i18n@11.4.6(vue@3.5.32(typescript@6.0.2)): + dependencies: + '@intlify/core-base': 11.4.6 + '@intlify/devtools-types': 11.4.6 + '@intlify/shared': 11.4.6 + '@vue/devtools-api': 6.6.4 + vue: 3.5.32(typescript@6.0.2) + vue-router@5.0.4(@vue/compiler-sfc@3.5.32)(pinia@3.0.4(typescript@6.0.2)(vue@3.5.32(typescript@6.0.2)))(vue@3.5.32(typescript@6.0.2)): dependencies: '@babel/generator': 7.29.1 diff --git a/web/public/icon.png b/web/public/icon.png new file mode 100644 index 0000000..adf13e0 Binary files /dev/null and b/web/public/icon.png differ diff --git a/web/public/icon.svg b/web/public/icon.svg deleted file mode 100644 index ee1e3ff..0000000 --- a/web/public/icon.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CODE - - diff --git a/web/src/App.vue b/web/src/App.vue index 77c2081..4514a34 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -1,5 +1,7 @@ @@ -48,7 +55,7 @@ const tokensLabel = computed(() => { class="mx-3 mt-2 rounded-md border px-3 py-2 flex items-start gap-2" :style="{ borderColor: 'var(--color-border)', backgroundColor: 'var(--color-secondary)' }" > - +
@@ -63,12 +70,23 @@ const tokensLabel = computed(() => {
+ + diff --git a/web/src/components/ProjectSwitcher.vue b/web/src/components/ProjectSwitcher.vue index bdfea3f..72b14ee 100644 --- a/web/src/components/ProjectSwitcher.vue +++ b/web/src/components/ProjectSwitcher.vue @@ -11,7 +11,8 @@ import { TransitionRoot, TransitionChild, } from '@headlessui/vue' -import { Folder } from 'lucide-vue-next' +import { FolderIcon, TrashIcon } from '@heroicons/vue/24/outline' +import { useI18n } from 'vue-i18n' const props = defineProps<{ open: boolean @@ -23,6 +24,7 @@ const emit = defineEmits<{ }>() const projectStore = useProjectStore() +const { t } = useI18n() const openRemoteConnect = inject<(prefill?: RemoteMeta) => void>('openRemoteConnect') const { @@ -126,7 +128,7 @@ function deleteProject(id: string) {
- {{ showBrowser ? 'Open Folder' : 'Projects' }} + {{ showBrowser ? t('projectSwitcher.openFolder') : t('projectSwitcher.title') }}
@@ -137,12 +139,12 @@ function deleteProject(id: string) { v-model="pathInput" type="text" class="ps-input flex-1 px-3 py-1.5 text-sm font-mono rounded-md outline-none" - placeholder="/path/to/folder" + :placeholder="t('projectSwitcher.pathPlaceholder')" @keydown.enter="handlePathSubmit" />
- Loading... + {{ t('projectSwitcher.loading') }}
- No folders found + {{ t('projectSwitcher.noFolders') }}
@@ -191,10 +193,10 @@ function deleteProject(id: string) { @@ -208,12 +210,12 @@ function deleteProject(id: string) {
- Switching project... + {{ t('projectSwitcher.switching') }}
- No projects yet + {{ t('projectSwitcher.noProjects') }}
- - - +
@@ -253,21 +253,21 @@ function deleteProject(id: string) { style="color: var(--color-primary)" @click="openFolderAction" > - + Open Folder + {{ t('projectSwitcher.openFolderBtn') }} diff --git a/web/src/components/RemoteConnectWizard.vue b/web/src/components/RemoteConnectWizard.vue index f022f1e..23b8f5b 100644 --- a/web/src/components/RemoteConnectWizard.vue +++ b/web/src/components/RemoteConnectWizard.vue @@ -7,15 +7,16 @@ import { TransitionChild, } from '@headlessui/vue' import { - Server, - Container, - X, - ArrowLeft, - Folder, - Loader2, - Check, - ChevronRight, -} from 'lucide-vue-next' + ServerIcon, + CubeIcon, + XMarkIcon, + ArrowLeftIcon, + FolderIcon, + ArrowPathIcon, + CheckIcon, + ChevronRightIcon, +} from '@heroicons/vue/24/outline' +import { useI18n } from 'vue-i18n' import { useChatStore } from '@/stores/chat' import { useProjectStore } from '@/stores/project' import { api } from '@/composables/api' @@ -23,6 +24,8 @@ import type { RemoteMeta, SSHAlias, RemoteAuthMethod } from '@/types/api' type Prefill = RemoteMeta & { loadTaskUuid?: string } +const { t } = useI18n() + const props = defineProps<{ open: boolean prefill?: Prefill | null @@ -66,13 +69,13 @@ const dirLoading = ref(false) const saveAlias = ref(false) const aliasName = ref('') -const steps: { key: Step; label: string }[] = [ - { key: 'method', label: 'Choose method' }, - { key: 'config', label: 'Configure' }, - { key: 'connecting', label: 'Connecting' }, - { key: 'dir', label: 'Select directory' }, -] -const stepIndex = computed(() => steps.findIndex((s) => s.key === step.value)) +const steps = computed<{ key: Step; label: string }[]>(() => [ + { key: 'method', label: t('wizard.steps.chooseMethod') }, + { key: 'config', label: t('wizard.steps.configure') }, + { key: 'connecting', label: t('wizard.steps.connecting') }, + { key: 'dir', label: t('wizard.steps.selectDirectory') }, +]) +const stepIndex = computed(() => steps.value.findIndex((s) => s.key === step.value)) watch(() => props.open, (isOpen) => { if (!isOpen) return @@ -326,7 +329,7 @@ function close() {
-
Remote connect
+
{{ t('wizard.title') }}
  1. - + {{ i + 1 }} {{ s.label }} @@ -345,110 +348,110 @@ function close() {
    - + @@ -552,7 +555,7 @@ function close() { .rcw-step.done .rcw-step-dot { background: var(--color-success); border-color: var(--color-success); - color: #fff; + color: var(--color-on-primary); } .rcw-step-label { font-size: 13px; @@ -798,7 +801,7 @@ function close() { border: none; border-radius: var(--radius-lg); background: var(--color-primary); - color: var(--color-on-primary, #fff); + color: var(--color-on-primary); font-size: 13px; font-weight: 500; cursor: pointer; diff --git a/web/src/components/RightPanel.vue b/web/src/components/RightPanel.vue index db9159f..0536811 100644 --- a/web/src/components/RightPanel.vue +++ b/web/src/components/RightPanel.vue @@ -1,6 +1,7 @@ @@ -193,40 +198,40 @@ function relativeTime(ts: string): string {
    - Workspace + {{ t('nav.workspace') }}
    -
    No projects yet
    +
    {{ t('sidebar.noProjects') }}
    -
    No tasks
    +
    {{ t('sidebar.noTasks') }}
    - - + +
    @@ -297,18 +302,12 @@ function relativeTime(ts: string): string { diff --git a/web/src/components/TaskList.vue b/web/src/components/TaskList.vue index e20bef0..9bff843 100644 --- a/web/src/components/TaskList.vue +++ b/web/src/components/TaskList.vue @@ -1,6 +1,6 @@