Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<svg>` 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.
Binary file modified desktop/src-tauri/icons/128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/128x128@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/64x64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square107x107Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square142x142Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square150x150Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square284x284Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square30x30Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square310x310Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square44x44Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square71x71Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/Square89x89Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/StoreLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified desktop/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
Binary file modified desktop/src-tauri/icons/icon.icns
Binary file not shown.
Binary file modified desktop/src-tauri/icons/icon.ico
Binary file not shown.
Binary file modified desktop/src-tauri/icons/icon.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-20x20@1x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-20x20@2x-1.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-20x20@2x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-20x20@3x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-29x29@1x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-29x29@2x-1.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-29x29@2x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-29x29@3x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-40x40@1x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-40x40@2x-1.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-40x40@2x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-40x40@3x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-512@2x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-60x60@2x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-60x60@3x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-76x76@1x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-76x76@2x.png
Binary file modified desktop/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
43 changes: 43 additions & 0 deletions internal/web/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package web

import (
"encoding/json"
"io"
"net/http"
"time"

Expand Down Expand Up @@ -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
11 changes: 11 additions & 0 deletions internal/web/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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{
Expand Down
22 changes: 21 additions & 1 deletion web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en" class="dark">
<head>
<meta charset="UTF-8">
<link rel="icon" type="image/svg+xml" href="/icon.svg">
<link rel="icon" type="image/png" href="/icon.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#111111">
<script>
Expand All @@ -24,6 +24,26 @@
html.setAttribute('data-theme', id);
html.classList.toggle('dark', !/-light$/.test(id));
} catch (e) {}

// Pre-mount <html lang> application to match the stored UI locale. i18n
// re-applies this after boot, but setting it early avoids a flash and
// keeps screen readers / translation prompts correct from first paint.
try {
var map = { en: 'en', 'zh-Hans': 'zh-Hans', 'zh-Hant': 'zh-Hant', ja: 'ja', ko: 'ko' };
var loc = localStorage.getItem('jcode_locale');
if (!loc && navigator.languages) {
for (var i = 0; i < navigator.languages.length; i++) {
var l = (navigator.languages[i] || '').toLowerCase();
if (l === 'zh' || l.indexOf('zh-cn') === 0 || l.indexOf('zh-sg') === 0 || l.indexOf('zh-hans') === 0) { loc = 'zh-Hans'; break; }
if (l.indexOf('zh-tw') === 0 || l.indexOf('zh-hk') === 0 || l.indexOf('zh-mo') === 0 || l.indexOf('zh-hant') === 0) { loc = 'zh-Hant'; break; }
var p = l.split('-')[0];
if (p === 'ja') { loc = 'ja'; break; }
if (p === 'ko') { loc = 'ko'; break; }
if (p === 'en') { loc = 'en'; break; }
}
}
if (loc && map[loc]) document.documentElement.lang = map[loc];
} catch (e) {}
})();
</script>
<title>JCODE — Coding Assistant</title>
Expand Down
4 changes: 2 additions & 2 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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": {
Expand Down
81 changes: 68 additions & 13 deletions web/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added web/public/icon.png
55 changes: 0 additions & 55 deletions web/public/icon.svg
Diff not rendered.
Loading
Loading