Compare commits

..

98 commits
master ... main

Author SHA1 Message Date
b01a02d396 Fix Bedrock config for OpenAI GPT-OSS models
All checks were successful
BotUI CI / build (push) Successful in 6m12s
2026-03-10 12:37:07 -03:00
6db01bf6c6 feat: Update organizations settings UI
All checks were successful
BotUI CI / build (push) Successful in 4m26s
- Enhanced organizations.html with new features (+63 lines)
2026-03-04 15:43:45 -03:00
9a84dfad28 Update chat and desktop UI components 2026-03-03 14:57:43 -03:00
054e57e074 fix: make maximized window fill entire screen with 100vh height
- Add height: 100vh !important to maximized window-element
- Add width: 100vw !important to maximized window-element
- Window now fills entire screen (1920x1080) when maximized
- Recovers 28px of vertical space previously lost to minibar offset
2026-03-03 13:36:15 -03:00
befa48edfb fix: remove 28px top offset for maximized windows
- Change window-element top from 28px to 0 when maximized
- Minibar is not present, so window should fill screen from top
- Removes blank space at top when window is maximized
2026-03-03 13:29:36 -03:00
027a7aa8e2 fix: hide toolbar when window is maximized to remove blank space at top
- Add .toolbar to hide rule for maximized windows
- Toolbar was taking up 50px of space at the top even when maximized
- This removes the blank space before the window title
2026-03-03 13:24:03 -03:00
a4e641a1d5 refactor: remove quick action chips (Full-Stack, Writing, Data Insight, Magic Design)
All checks were successful
BotUI CI / build (push) Successful in 1m59s
- Removed quick-actions-container from chat footer
- Keeps suggestions-container for dynamic two-row suggestions display
- Cleaner chat interface without fixed action chips
2026-03-03 09:46:17 -03:00
61d90da409 feat: add dynamic window title updates
All checks were successful
BotUI CI / build (push) Successful in 2m48s
- Window title now shows current window name followed by 'General Bots'
- Title format: '{Window Name} - General Bots' (e.g., 'Chat - General Bots')
- Resets to 'General Bots Desktop' when all windows are closed
- Updated default title from 'BUILD V3 - Web Desktop Environment' to 'General Bots Desktop'
- Added cache-busting parameter to window-manager.js to ensure browser reloads updated code
2026-03-03 09:33:38 -03:00
84b7cb63f9 fix: Change desktop title from 'Agent Farm' to 'General Bots'
- Update minibar brand title to use product name from .product configuration
- Replace hardcoded 'Agent Farm' text with 'General Bots'
- Improves brand consistency across the UI
2026-03-03 08:42:10 -03:00
e2f1efef8c Fix window transparency and theme dropdown background issues
- Fixed chat footer background to use var(--surface) CSS variable instead of hardcoded colors, ensuring proper theme adaptation
- Fixed theme dropdown background by changing from var(--input-bg) to var(--surface) in theme-sentient.css
- Added CSS override rules in desktop.css to ensure dropdown uses correct background
- Added JavaScript fix in theme-manager.js to automatically apply correct dropdown background on theme load

This resolves issues where theme dropdown and chat footer had black backgrounds in light themes.
2026-03-03 08:27:17 -03:00
48d773c0b3 Fix window maximization and suggestion button visibility issues
All checks were successful
BotUI CI / build (push) Successful in 2m43s
- Fix window title hidden behind minibar when maximized
  - Adjust window top position to account for 28px minibar height
  - Adjust window height calculation to account for minibar
  - Set maximized window z-index to 9998 (below minibar's 9999)

- Remove transparency from chat window
  - Change window-header background from rgba to solid white
  - Remove backdrop-filter blur effect
  - Add explicit opacity rules to prevent transparency

- Hide background content when window is maximized
  - Add 'window-maximized' class to body when window is maximized
  - Add CSS rules to hide sidebar, desktop icons, and other background elements

- Hide initial suggestion buttons when dynamic suggestions displayed
  - Add 'has-suggestions' class to footer when suggestions are rendered
  - Add CSS rule to hide .quick-action-chip buttons when footer has 'has-suggestions' class
  - Update CSS version parameter to force cache reload
2026-03-02 18:05:47 -03:00
3e81991e8b feat: Add Phase 1 Code Editor UI component
All checks were successful
BotUI CI / build (push) Successful in 2m6s
- Add Monaco Editor vendor files (vs directory)
- Create editor.html component (631 lines)
- Full-featured code editor with:
  - Monaco Editor integration
  - File tree sidebar
  - Multi-file tab management
  - Syntax highlighting for HTML, CSS, JS, JSON, TS, BAS, Python, Rust, Markdown, etc.
  - Save/Publish functionality
  - Keyboard shortcuts
  - Status bar
  - Modified state tracking
  - Language auto-detection
  - Custom GB dark theme
2026-03-02 07:26:36 -03:00
b26d3ef4a5 feat: Add Phase 0 deployment UI in Vibe (CRITICAL)
All checks were successful
BotUI CI / build (push) Successful in 2m37s
Phase 0.3: Deployment UI
- Add deployment modal with internal/external options
- Create configuration forms for GB Platform and Forgejo
- Add JavaScript functions for modal handling
- Implement deployment execution flow
- Add real-time route preview

Features:
- Visual deployment target selection
- Internal deployment: route configuration, shared resources
- External deployment: repository name, custom domain, CI/CD toggle, app type
- User-friendly deployment status messages
2026-03-02 07:12:30 -03:00
dd6e1aa2bc style: Format vibe.html for better readability
All checks were successful
BotUI CI / build (push) Successful in 2m4s
- Improve indentation and line breaks in vibe.html
- No functional changes, only code formatting
2026-03-01 22:36:15 -03:00
0c2dd80f30 fix(theme): map sentient css variables properly to avoid black boxes on light themes
All checks were successful
BotUI CI / build (push) Successful in 3m57s
2026-02-28 13:28:56 -03:00
6bbfa2989e fix: change body height back to 100vh on desktop.html to fix gray cut-off at bottom 2026-02-28 12:15:08 -03:00
d13c82b7c8 fix: replace tailwind utility classes with custom css in window manager to ensure theme consistency 2026-02-28 12:09:04 -03:00
7279104bbc fix: final layout and theme fixes for absolute full screen without black frames 2026-02-28 12:01:44 -03:00
aef91abc1c fix: remove background grid pattern and ensure absolute full screen desktop 2026-02-28 11:25:16 -03:00
7a06f954fb fix: final pass of hardcoded CSS colors for seamless window manager theme support 2026-02-28 11:20:40 -03:00
8075f9701c fix: remove black frame caused by hardcoded window wrapper colors 2026-02-28 11:08:54 -03:00
4a2c28e252 fix: resolve background grid hardcoded colours and stray inline hex values 2026-02-28 11:06:40 -03:00
76ec8f9bb5 fix: resolve background grid hardcoded colours and stray inline hex values 2026-02-28 10:58:17 -03:00
a570d7bd11 fix: make desktop icons themable instead of hardcoded green squares 2026-02-28 10:26:44 -03:00
9444d3892c fix: make suite UI elements fully themable and resolve black frame on desktop-inner 2026-02-28 10:05:36 -03:00
afb13cb397 Clean up mock Vibe UI 2026-02-26 12:40:44 -03:00
7c1deca8ae fix: resolve infinite WebSocket reconnection loop
The ui_server proxies WebSocket connections. It was accepting the client's WebSocket connection (ws.onopen triggered on the client), but if it couldn't connect to the backend (or if the backend disconnected), it would drop the client connection right away (ws.onclose triggered).

The issue was that reconnectAttempts was being reset to 0 inside the ws.onopen handler. Because the connection was briefly succeeding before failing, the reconnectAttempts counter was resetting to 0 on every attempt, completely circumventing the exponential backoff mechanism and causing a tight reconnection loop.

Modified the WebSocket logic across all relevant UI components to delay resetting reconnectAttempts = 0. Instead of resetting immediately upon the TCP socket opening, it now safely waits until a valid JSON payload {"type": "connected"} is successfully received from the backend.
2026-02-25 10:15:47 -03:00
bfc8f4da77 fix: improve WebSocket reconnection logic and add debugging
- Add connection timeout (5s) to detect silent failures
- Log WebSocket close events with code and reason
- Prevent infinite reconnection loops after max attempts
- Clear connection timeout when WebSocket opens or closes
- Show user-friendly error after max reconnection attempts

This helps diagnose why WebSocket connections are failing
and prevents the infinite reconnection loop issue.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-24 22:11:26 -03:00
8bfe97e92e fix: allow anonymous chat connections when auth fails
- Modified chat auth failure handler to proceed with WebSocket connection
- Generates anonymous user_id and session_id using crypto.randomUUID()
- WebSocket handler already supports anonymous connections (creates UUIDs if not provided)
- Removes error notification and retry loop that prevented chat from working

This allows chat to work publicly without requiring authentication,
which is the expected behavior for public bots.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-24 21:47:09 -03:00
e89e87d2b2 fix: use full app paths for desktop icons (not partials)
- Reverted chat path from /suite/partials/chat.html to /suite/chat/chat.html (full app)
- Kept tasks path as /suite/tasks/tasks.html (full app, already correct)
- Kept vibe path as /suite/partials/vibe.html (no dedicated vibe directory exists yet)
- All other apps already using correct full app paths

The partials directory should only contain fragments for embedding in other pages,
not standalone apps. Desktop icons must load full apps into windows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-24 21:20:58 -03:00
76e8df36ee fix: correct desktop icon app paths for suite apps
- Fixed tasks.html: replaced incomplete file with content from partials/tasks.html
- Fixed vibe icon: renamed from "Mantis (Vibe)" to "Vibe" and updated path to /suite/partials/vibe.html
- Fixed chat icon: updated path from /suite/chat/chat.html to /suite/partials/chat.html
- Fixed tasks icon: updated path from /suite/tasks/tasks.html to /suite/partials/tasks.html
- Verified all other app paths (terminal, drive, editor, browser) are correct

All desktop icons now point to the correct app fragment files for the Window Manager.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-24 20:32:46 -03:00
09bb9ee55d fix(ui): resolve Cannot read properties of null (reading 'appendChild') in window-manager.js
- Lazy load workspace and taskbar containers to prevent crashes when WindowManager is instantiated in the head before the body DOM is ready
2026-02-24 19:49:04 -03:00
6d07aa4bdd fix(ui): resolve 404 asset paths and replace missing icons with SVGs
- Fixed 404 errors on desktop shell assets by explicitly routing to /suite/ absolute paths
- Replaced missing FontAwesome icons in window-manager.js with inline SVGs since CDNs are banned
2026-02-24 19:20:41 -03:00
2f53b65aeb feat(ui): implement Window Manager desktop shell based on BUILD V3 design
- Built custom vanilla JS Window Manager (window-manager.js)
- Replaced default.gbui with new desktop.html featuring Windows 95 spatial metaphor + Tailwind aesthetics
- Redesigned icons, taskbar, sidebar, and workspace to exactly match the target PDF layout
- Migrated Chat, Tasks, and Terminal into pure HTMX fragments to load seamlessly inside floating panels
- Added missing CSS rules to handle window rendering without CDNs
2026-02-24 19:02:48 -03:00
6afeeb311f chore: update htmx and suite_app javascript
All checks were successful
BotUI CI / build (push) Successful in 2m51s
2026-02-22 15:56:05 -03:00
756da22dd5 fix(ui): robust contrast calculation for named colors and variables
All checks were successful
BotUI CI / build (push) Successful in 3m22s
2026-02-20 20:37:47 -03:00
093f417ff7 fix(ui): dynamic suggestion text and borders contrast, cache busting
Some checks failed
BotUI CI / build (push) Failing after 5s
2026-02-20 17:43:28 -03:00
84684c6687 fix(ui): dynamic text contrast for chat balloons and suggestion chips 2026-02-20 17:08:41 -03:00
a7991dd3dc trigger ci on main branch for alm 2026-02-20 15:27:25 -03:00
138ad31a32 update: sync for alm 2026-02-20 12:59:02 -03:00
4987a15858 fix: Update chat UI theme management
Some checks failed
BotUI CI / build (push) Failing after 49m45s
2026-02-20 01:14:14 +00:00
785187868e fix(ui): prevent empty chat bubbles when message content is empty 2026-02-18 21:36:03 +00:00
68bb516ec2 fix(ui): disable dynamic theme dropdown injection entirely 2026-02-18 21:19:28 +00:00
ea8003e213 fix(ui): remove theme selector from suite layout and projector 2026-02-18 20:52:11 +00:00
a3747a794f fix(ui): remove floating menu button from minimal chat UI 2026-02-18 20:41:58 +00:00
e5796fa64c fix: remove theme selector button from minimal chat UI
- Non-logged users no longer see the theme toggle (⚙/🌙/☀️) button
- Theme still auto-detects based on system preference (light/dark)
- Logged-in users have a separate theme menu with preview in the suite
2026-02-18 20:31:50 +00:00
a8bff4e1a7 fix: Send tool display text instead of internal ID when clicking tools
All checks were successful
BotUI CI / build (push) Successful in 5m42s
Fixed issue where clicking a tool button sent the internal ID (e.g., "03-missa")
instead of the display text (e.g., " Agendar Missa") to the chat.

The bug was in chat.html where invoke_tool actions were sending action.tool
(the internal ID) instead of sugg.text (the user-friendly display text).

Now tool buttons work correctly on the first click without sending internal IDs.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-16 00:04:37 +00:00
f0aba607e9 feat: Use typewriter theme for cristo and make suggestion buttons smaller
All checks were successful
BotUI CI / build (push) Successful in 4m31s
- Change cristo bot default theme from mellowgold to typewriter
- Reduce suggestion button size: padding 6px 12px (was 10px 18px)
- Reduce font size to 12px (was 14px)
- Reduce min-height to 30px (was 40px)
- Reduce border-radius to 20px (was 24px)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-15 23:48:40 +00:00
cbbcc58ad7 fix: Avoid workspace conflict in Forgejo CI
All checks were successful
BotUI CI / build (push) Successful in 4m41s
Remove actions/checkout with custom path that causes multiple workspace
roots error. Clone botui repository directly in Setup Workspace step
instead of using checkout action.

Fixes error: "multiple workspace roots found in the same workspace"

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-15 23:26:37 +00:00
9b417bf4f2 fix: Remove body data-theme attribute to prevent CSS override
Some checks failed
BotUI CI / build (push) Has been cancelled
This fixes the issue where theme changes required a page refresh to apply
to the chat client area. The body element's data-theme attribute was
applying base.css theme rules that overrode the inline styles set by the
theme manager.

Changes:
- Add data-theme="sentient" to html element in base.html
- Remove body's data-theme attribute when loading themes in theme-manager.js
- This prevents base.css [data-theme="*"] selectors from overriding inline styles

Now both header and body background update immediately when switching themes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-15 23:19:16 +00:00
8bb8f9d96a fix: Hide search bar and Drive/Tasks nav when logged out, improve theme switching
- Hide omnibox search bar when user is not logged in
- Hide Drive, Tasks, CRM, and Calendar navigation items when logged out
- Update theme manager to use correct CSS path (/suite/public/themes/)
- Improve theme switching to update all color variables including --color1/--color2
- Fix bot config color override logic to respect user's theme selection
- Add disconnect notification flag to prevent duplicate notifications

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-15 21:53:50 +00:00
ccee337522 chore: Bump asset versions for cache invalidation
Update JS asset version from 20260207 to 20260215 to force
browser cache reload after theme/logo fixes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-15 21:34:59 +00:00
a29255c848 fix: Update theme selector to change chat colors and add login page logo
- Fix theme CSS path from /public/themes/ to /suite/public/themes/
- When user selects theme, update chat color variables to match
- Only apply bot config colors if user hasn't selected custom theme
- Add bot logo support to login page
- Add CSS styling for login logo image

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-15 21:33:18 +00:00
4f654dd95d fix(i18n): Invalidate cache to fix placeholder translations
All checks were successful
BotUI CI / build (push) Successful in 2m55s
- Increment CACHE_VERSION from v1 to v2
- Forces all users to fetch fresh translations from API
- Fixes issue where old cache with placeholders was overriding correct HTML
- Browser cache had stale translations from before i18n embed fix

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-14 20:05:28 +00:00
8732738622 chore: Remove CI workflow
All checks were successful
BotUI CI / build (push) Successful in 3m19s
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-14 19:57:42 +00:00
8611472d4e ci: Add GitHub Actions CI workflow
All checks were successful
BotUI CI / build (push) Successful in 3m42s
- Add basic CI pipeline for Rust project
- Build, test, format check, and clippy

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-14 17:39:33 +00:00
fb66708cdc Debug: Add warning for missing translation keys
All checks were successful
BotUI CI / build (push) Successful in 4m13s
2026-02-14 12:25:53 +00:00
be802201fd feat(i18n): Add cache versioning to prevent stale translations
All checks were successful
BotUI CI / build (push) Successful in 3m45s
- Add CACHE_VERSION constant (v1)
- Include version in cache key to auto-invalidate old caches
- Update clearCache to handle versioned keys
- Add comment explaining when to increment version
2026-02-14 12:09:26 +00:00
4164b75c89 fix(i18n): Add comprehensive cache and fetch logging
All checks were successful
BotUI CI / build (push) Successful in 4m13s
2026-02-14 12:04:33 +00:00
2bb7959666 fix(i18n): Add logging to debug translation loading
All checks were successful
BotUI CI / build (push) Successful in 5m12s
2026-02-14 11:54:08 +00:00
b68fc0aa85 Update chat UI
All checks were successful
BotUI CI / build (push) Successful in 4m42s
2026-02-14 10:13:40 +00:00
161012c6a6 Update submodule changes
Some checks failed
BotUI CI / build (push) Failing after 18m37s
2026-02-13 22:31:49 +00:00
af78f31565 Remove chat header and fix theming from config.csv
Some checks failed
BotUI CI / build (push) Has been cancelled
- Remove chat header (logo and title) from chat window since logo
  will be displayed in top bar from config.csv
- Update CSS to use --chat-color1 and --chat-color2 for all themed elements
- Remove hardcoded theme overrides that interfered with config colors
- Fix text contrast: bot messages now use color2 background with black text
- Update suggestion buttons to use theme colors from config.csv
- Clean up JavaScript to remove references to deleted header elements

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-10 14:07:23 +00:00
a8bc5530b0 Add config-colors.css and update UI components
- Add config-colors.css for dynamic color theming
- Update base.html, chat components for better UX
- Improve theme manager and HTMX app integration
2026-02-10 13:54:16 +00:00
123787378f Update suite_app.js for tool calling fixes 2026-02-09 15:12:19 +00:00
Claude Sonnet 4.5
1bf9510c7d WIP: Various UI updates from previous session
- Update UI server module
- Update suite index and JavaScript files
- Add public directory

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 12:21:11 +00:00
Claude Sonnet 4.5
6b1dcc9d3f Update default port from 8088 to 9000
- Update embedded/index.html WebSocket URL
- Update minimal/index.html BotServer URL

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 12:14:01 +00:00
root
607ad076d9 Fix email module integration - update build and UI server 2026-02-07 16:28:36 +00:00
661edc09fa Fix 404 errors for static assets with bot name prefixes
All checks were successful
BotUI CI / build (push) Successful in 3m42s
Removed root-level static routes (/:dir/*path) that conflicted with
bot name prefixes like /edu. Now all assets are served under /suite/
path, allowing the fallback handler to properly detect and strip
bot prefixes before resolving file paths.

Fixes:
- /edu/suite/js/api-client.js now returns 200 OK
- /edu/suite/css/apps-extended.css now returns 200 OK
- /edu/suite/admin/admin.js now returns 200 OK
- Base href injection working correctly for bot prefixes
2026-02-06 16:24:56 -03:00
1a1de27fd7 Fix CI: build release mode with embed-ui feature
All checks were successful
BotUI CI / build (push) Successful in 4m30s
2026-02-06 12:24:03 -03:00
924f7660a0 Trigger CI: build with embed-ui feature
All checks were successful
BotUI CI / build (push) Successful in 1m35s
2026-02-06 12:12:52 -03:00
e286d64ce3 Fix CI: remove path filters that don't match standalone repo structure
All checks were successful
BotUI CI / build (push) Successful in 2m10s
- Remove 'paths' filter from push/pull_request triggers
- Path filters like 'botui/**' only work in main gb repo
- In standalone botui repo, files are at root level (src/, Cargo.toml, etc.)
- CI will now run on all pushes to main branch
2026-02-06 11:51:21 -03:00
07da8a4e88 Fix rust-embed: correct folder path and remove duplicate feature
- Fix RustEmbed folder path to use $CARGO_MANIFEST_DIR/ui
- Remove duplicate interpolate-folder-path feature (now in workspace)
- Verified: 13 HTML files embedded, binary works from any directory
2026-02-06 11:36:48 -03:00
f5ab1799a6 Trigger CI: manual workflow run
All checks were successful
BotUI CI / build (push) Successful in 2m1s
2026-02-06 10:57:04 -03:00
95f856b080 Reduce CARGO_BUILD_JOBS to 6 for CI stability
All checks were successful
BotUI CI / build (push) Successful in 1m57s
2026-02-06 10:18:00 -03:00
a1a30adb2c Fix embed-ui feature: correct rust-embed folder path
- Changed rust-embed folder from '../ui' to 'ui' (relative to crate root)
- Added conditional imports to eliminate unused import warnings
- Now UI files properly embed into botui binary during compilation
- Resolves production error: 'Asset suite/index.html not found in embedded binary'
2026-02-06 09:26:30 -03:00
cdf8bea155 Fix RustEmbed folder path for embedded UI 2026-02-05 18:40:34 -03:00
1ad929e3ff Enable embed-ui feature by default to fix UI directory not found error
All checks were successful
BotUI CI / build (push) Successful in 5m59s
2026-02-05 13:42:52 -03:00
802219d8cd Bump version to 6.1.2 2026-02-05 11:20:06 -03:00
414d277ae1 Bump version to 6.1.1: Trigger CI rebuild with embed-ui fix 2026-02-05 10:30:12 -03:00
abdd2ff615 Fix UI directory detection: skip filesystem checks when embed-ui is enabled 2026-02-05 09:44:20 -03:00
77374ae638 Fix workflow trigger path: use .forgejo instead of .github
All checks were successful
BotUI CI / build (push) Successful in 3m50s
2026-02-05 09:20:40 -03:00
e0504f3703 Create dedicated BotUI CI workflow
- New workflow for botui-only builds and deployments
- Trigger only on botui/**, botlib/** changes
- Build only botui package with embed-ui feature
- Deploy only botui binary
- Restart only ui service
- Separate cache key to avoid conflicts with botserver
2026-02-05 08:45:20 -03:00
91a750127c Fix ServeDir import compilation error 2026-02-05 08:00:37 -03:00
5618ed4367 Update: UI files and add error-reporter.js 2026-02-04 13:54:26 -03:00
5e10222a94 Fix login redirect to use absolute URL
- Use window.location.origin for redirect to ensure it works from any path
- Redirects to chat (#chat) after successful authentication
- Maintains support for custom redirect parameter
2026-02-04 13:20:14 -03:00
375b457f48 Fix login redirect to chat after authentication
- Change default redirect from '/' to '/#chat' after successful login
- Ensures users go directly to chat interface instead of root
2026-02-04 12:52:47 -03:00
e135ebf2e6 Hide voice icon, use light theme, add cursor blink
- Hide voice input button in chat interface
- Change default theme from 'sentient' to 'light'
- Add blinking cursor animation to chat input field
2026-02-04 09:56:24 -03:00
b69ea06ad3 Fix logged-out user menu - show only Sign in button
Removed Profile, Settings, and Help & Support items from user menu
when user is not authenticated. Now only Sign in button is visible.
2026-02-04 08:57:31 -03:00
bd49ee3892 Add logged-out navigation menu component
- Simplified menu showing only Sign in button
- Uses HTMX for authentication redirect
- Follows existing UI component patterns
- Responsive design with CSS variables
2026-02-04 00:03:10 -03:00
34d55825bc feat: Hide omnibox and apps menu based on product configuration
- Hide omnibox search mechanism when search_enabled=false in product config
- Hide apps menu launcher when menu_launcher_enabled=false or when no apps are visible
- Check effectiveApps (after filtering by compiled features) to determine if menu should be shown
- Automatically hide the apps menu button when there are no apps to display

This provides UI controls that respect the new search_enabled and menu_launcher_enabled
directives added to the .product configuration.
2026-01-29 23:56:00 -03:00
27e839f22a Fix bot_id routing: Extract bot name from URL path
- Add bot_name field to WsQuery struct
- Extract bot_name from URL path (e.g., /edu, /chat/edu)
- Pass bot_name to backend WebSocket URL
- Use URL path for bot identification instead of relying on client message
2026-01-28 17:17:36 -03:00
db0f0c1178 fix(ui): Use absolute paths for CSS/JS assets in suite apps to resolve loading errors 2026-01-28 16:26:09 -03:00
f4dcae288a chore: Revert default log level to info 2026-01-27 18:44:22 -03:00
bb8b35d885 chore: Set default internal log level to trace 2026-01-27 18:37:21 -03:00
497d0dd18c fix(ui): add filesystem fallback for embedded mode
Some checks failed
GBCI / build (push) Failing after 11s
2026-01-26 14:53:32 -03:00
22fa29b3ec fix(ui): improve asset discovery and error logging
Some checks failed
GBCI / build (push) Failing after 11s
2026-01-26 14:50:27 -03:00
12c1e3210f feat(ui): implement embedded ui assets and robust path resolution
Some checks failed
GBCI / build (push) Failing after 12s
2026-01-26 11:44:47 -03:00
206 changed files with 77280 additions and 11029 deletions

View file

@ -1,4 +1,4 @@
name: GBCI
name: BotUI CI
on:
push:
@ -6,18 +6,37 @@ on:
pull_request:
branches: ["main"]
env:
CARGO_BUILD_JOBS: 6
CARGO_NET_RETRY: 10
jobs:
build:
runs-on: gbo
steps:
- name: Disable SSL verification (temporary)
- name: Disable SSL verification
run: git config --global http.sslVerify false
- uses: actions/checkout@v4
- name: Setup Workspace
run: |
# Clone the main gb repository
git clone --depth 1 --branch main https://alm.pragmatismo.com.br/GeneralBots/gb.git workspace
cd workspace
git submodule update --init --depth 1 botlib
- name: Clone botlib dependency
run: git clone --depth 1 https://github.com/GeneralBots/botlib.git ../botlib
# Clone botui separately
git clone --depth 1 --branch main https://alm.pragmatismo.com.br/GeneralBots/botui.git botui
# Remove all members except botui and botlib from workspace
sed -i '/"botapp",/d' Cargo.toml
sed -i '/"botdevice",/d' Cargo.toml
sed -i '/"bottest",/d' Cargo.toml
sed -i '/"botserver",/d' Cargo.toml
sed -i '/"botbook",/d' Cargo.toml
sed -i '/"botmodels",/d' Cargo.toml
sed -i '/"botplugin",/d' Cargo.toml
sed -i '/"bottemplates",/d' Cargo.toml
- name: Cache Cargo registry
uses: actions/cache@v4
@ -25,34 +44,54 @@ jobs:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-botui-${{ hashFiles('**/Cargo.lock') }}
~/.cache/sccache
workspace/target
key: ${{ runner.os }}-cargo-v2-debug-ui-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-botui-
${{ runner.os }}-cargo-v2-debug-ui-
${{ runner.os }}-cargo-v2-debug-
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libpq-dev libssl-dev liblzma-dev pkg-config
- name: Install Rust
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
echo "/root/.cargo/bin" >> $GITHUB_PATH
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Install sccache
run: |
wget https://github.com/mozilla/sccache/releases/download/v0.8.2/sccache-v0.8.2-x86_64-unknown-linux-musl.tar.gz
tar xzf sccache-v0.8.2-x86_64-unknown-linux-musl.tar.gz
mv sccache-v0.8.2-x86_64-unknown-linux-musl/sccache $HOME/.cargo/bin/sccache
chmod +x $HOME/.cargo/bin/sccache
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
$HOME/.cargo/bin/sccache --start-server || true
- name: Setup environment
run: sudo cp /opt/gbo/bin/system/.env . 2>/dev/null || true
- name: Build BotUI
working-directory: workspace
run: |
sudo cp /opt/gbo/bin/system/botui.env .env
cargo build --release -p botui --features embed-ui -j 8 2>&1 | tee /tmp/build.log
ls -lh target/release/botui
sccache --show-stats || true
- name: Build Linux x86_64
run: /root/.cargo/bin/cargo build --locked --release
- name: Prepare release artifacts
- name: Save build log
if: always()
run: |
sudo mkdir -p /opt/gbo/releases/botui/linux-x86_64
sudo cp ./target/release/botui /opt/gbo/releases/botui/linux-x86_64/ || true
sudo chmod -R 755 /opt/gbo/releases/botui/
sudo mkdir -p /opt/gbo/logs
sudo cp /tmp/build.log /opt/gbo/logs/botui-$(date +%Y%m%d-%H%M%S).log || true
- name: Deploy and restart local service
- name: Deploy
working-directory: workspace
run: |
lxc exec bot:pragmatismo-system -- systemctl stop botui
lxc exec bot:pragmatismo-system -- systemctl stop ui || true
sudo cp ./target/release/botui /opt/gbo/bin/botui
sudo chmod +x /opt/gbo/bin/botui
sudo cp target/release/botui /opt/gbo/bin/system/
sudo chmod +x /opt/gbo/bin/system/botui
lxc exec bot:pragmatismo-system -- systemctl start botui
lxc exec bot:pragmatismo-system -- systemctl start ui || true# CI trigger: Fri Feb 6 10:57:04 AM -03 2026

View file

@ -1,6 +1,6 @@
[package]
name = "botui"
version = "6.1.0"
version = "6.1.2"
edition = "2021"
description = "General Bots UI - Pure web interface"
license = "AGPL-3.0"
@ -13,8 +13,10 @@ workspace = true
features = ["http-client"]
[features]
default = ["ui-server", "chat", "drive", "tasks"]
default = ["ui-server", "chat", "drive", "tasks", "admin"]
ui-server = []
embed-ui = ["rust-embed"]
# App Features
chat = []
@ -56,8 +58,10 @@ anyhow = { workspace = true }
axum = { workspace = true }
futures-util = { workspace = true }
log = { workspace = true }
mime_guess.workspace = true
native-tls = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
rust-embed = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["full"] }

278
PROMPT.md
View file

@ -1,278 +0,0 @@
# BotUI Development Guide
**Version:** 6.2.0
**Purpose:** Web UI server for General Bots (Axum + HTMX + CSS)
---
## ZERO TOLERANCE POLICY
**EVERY SINGLE WARNING MUST BE FIXED. NO EXCEPTIONS.**
---
## ❌ ABSOLUTE PROHIBITIONS
```
❌ NEVER use #![allow()] or #[allow()] in source code
❌ NEVER use _ prefix for unused variables - DELETE or USE them
❌ NEVER use .unwrap() - use ? or proper error handling
❌ NEVER use .expect() - use ? or proper error handling
❌ NEVER use panic!() or unreachable!()
❌ NEVER use todo!() or unimplemented!()
❌ NEVER leave unused imports or dead code
❌ NEVER add comments - code must be self-documenting
❌ NEVER use CDN links - all assets must be local
```
---
## 🏗️ ARCHITECTURE
### Dual Modes
| Mode | Command | Description |
|------|---------|-------------|
| Web | `cargo run` | Axum server on port 3000 |
| Desktop | `cargo tauri dev` | Tauri native window |
### Code Organization
```
src/
├── main.rs # Entry point - mode detection
├── lib.rs # Feature-gated module exports
├── http_client.rs # HTTP wrapper for botserver
├── ui_server/
│ └── mod.rs # Axum router + UI serving
├── desktop/
│ ├── mod.rs # Desktop module organization
│ ├── drive.rs # File operations via Tauri
│ └── tray.rs # System tray
└── shared/
└── state.rs # Shared application state
ui/
├── suite/ # Main UI (HTML/CSS/JS)
│ ├── js/vendor/ # Local JS libraries
│ └── css/ # Stylesheets
└── minimal/ # Minimal chat UI
```
---
## 🎨 HTMX-FIRST FRONTEND
### Core Principle
- **Use HTMX** to minimize JavaScript
- **Server returns HTML fragments**, not JSON
- **Delegate ALL logic** to Rust server
### HTMX Usage
| Use Case | Solution |
|----------|----------|
| Data fetching | `hx-get`, `hx-post` |
| Form submission | `hx-post`, `hx-put` |
| Real-time updates | `hx-ext="ws"` |
| Content swapping | `hx-target`, `hx-swap` |
| Polling | `hx-trigger="every 5s"` |
| Loading states | `hx-indicator` |
### When JS is Required
| Use Case | Why JS Required |
|----------|-----------------|
| Modal show/hide | DOM manipulation |
| Toast notifications | Dynamic element creation |
| Clipboard operations | `navigator.clipboard` API |
| Keyboard shortcuts | `keydown` event handling |
| Complex animations | GSAP or custom |
---
## 📦 LOCAL ASSETS ONLY - NO CDN
```
ui/suite/js/vendor/
├── htmx.min.js
├── htmx-ws.js
├── marked.min.js
├── gsap.min.js
└── livekit-client.umd.min.js
```
```html
<!-- ✅ CORRECT -->
<script src="js/vendor/htmx.min.js"></script>
<!-- ❌ WRONG -->
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
```
---
## 🎨 OFFICIAL ICONS - MANDATORY
**NEVER generate icons with LLM. Use official SVG icons:**
```
ui/suite/assets/icons/
├── gb-logo.svg # Main GB logo
├── gb-bot.svg # Bot/assistant
├── gb-analytics.svg # Analytics
├── gb-calendar.svg # Calendar
├── gb-chat.svg # Chat
├── gb-drive.svg # File storage
├── gb-mail.svg # Email
├── gb-meet.svg # Video meetings
├── gb-tasks.svg # Task management
└── ...
```
All icons use `stroke="currentColor"` for CSS theming.
---
## 🔒 SECURITY ARCHITECTURE
### Centralized Auth Engine
All authentication is handled by `security-bootstrap.js` which MUST be loaded immediately after HTMX:
```html
<head>
<!-- 1. HTMX first -->
<script src="js/vendor/htmx.min.js"></script>
<script src="js/vendor/htmx-ws.js"></script>
<!-- 2. Security bootstrap immediately after -->
<script src="js/security-bootstrap.js"></script>
<!-- 3. Other scripts -->
<script src="js/api-client.js"></script>
</head>
```
### DO NOT Duplicate Auth Logic
```javascript
// ❌ WRONG - Don't add auth headers manually
fetch("/api/data", {
headers: { "Authorization": "Bearer " + token }
});
// ✅ CORRECT - Let security-bootstrap.js handle it
fetch("/api/data");
```
---
## 🎨 DESIGN SYSTEM
### Layout Standards
```css
.app-container {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
.main-content {
display: grid;
grid-template-columns: 320px 1fr;
flex: 1;
overflow: hidden;
}
.list-panel {
overflow-y: scroll;
scrollbar-width: auto;
}
.detail-panel {
display: flex;
flex-direction: column;
overflow: hidden;
}
```
### Theme Variables Required
```css
[data-theme="your-theme"] {
--bg: #0a0a0a;
--surface: #161616;
--surface-hover: #1e1e1e;
--border: #2a2a2a;
--text: #ffffff;
--text-secondary: #888888;
--primary: #c5f82a;
--success: #22c55e;
--warning: #f59e0b;
--error: #ef4444;
}
```
---
## ✅ CODE PATTERNS
### Error Handling
```rust
// ❌ WRONG
let value = something.unwrap();
// ✅ CORRECT
let value = something?;
let value = something.ok_or_else(|| Error::NotFound)?;
```
### Self Usage
```rust
impl MyStruct {
fn new() -> Self { Self { } } // ✅ Not MyStruct
}
```
### Format Strings
```rust
format!("Hello {name}") // ✅ Not format!("{}", name)
```
### Derive Eq with PartialEq
```rust
#[derive(PartialEq, Eq)] // ✅ Always both
struct MyStruct { }
```
---
## 📦 KEY DEPENDENCIES
| Library | Version | Purpose |
|---------|---------|---------|
| axum | 0.7.5 | Web framework |
| reqwest | 0.12 | HTTP client |
| tokio | 1.41 | Async runtime |
| askama | 0.12 | HTML Templates |
---
## 🔑 REMEMBER
- **ZERO WARNINGS** - Every clippy warning must be fixed
- **NO ALLOW IN CODE** - Never use #[allow()] in source files
- **NO DEAD CODE** - Delete unused code
- **NO UNWRAP/EXPECT** - Use ? operator
- **HTMX first** - Minimize JS, delegate to server
- **Local assets** - No CDN, all vendor files local
- **No business logic** - All logic in botserver
- **HTML responses** - Server returns fragments, not JSON
- **Version 6.2.0** - do not change without approval

317
README.md
View file

@ -1,39 +1,314 @@
# BotUI - General Bots Web Interface
# General Bots Desktop
**Version:** 6.2.0
**Purpose:** Web UI server for General Bots (Axum + HTMX + CSS)
An AI-powered desktop automation tool that records and plays back user interactions useful for legacy systems and common desktop tasks. The BotDesktop automation tool fills a critical gap in the enterprise automation landscape by addressing legacy systems and desktop applications that lack modern APIs or integration capabilities. While botserver excels at creating conversational bots for modern channels like web, mobile and messaging platforms, many organizations still rely heavily on traditional desktop applications, mainframe systems, and custom internal tools that can only be accessed through their user interface. BotDesktop's ability to record and replay user interactions provides a practical bridge between these legacy systems and modern automation needs.
---
## Overview
![image](https://github.com/user-attachments/assets/477b7472-81d8-4e38-a541-70a7e2496a02)
BotUI is a modern web interface for General Bots, built with Rust, Axum, and HTMX. It provides a clean, responsive interface for interacting with the General Bots platform, featuring real-time updates via WebSocket connections and a minimalist JavaScript approach powered by HTMX.
The interface supports multiple features including chat, file management, tasks, calendar, analytics, and more - all served through a fast, efficient Rust backend with a focus on server-rendered HTML and minimal client-side JavaScript.
The tool's AI-powered approach to desktop automation represents a significant advancement over traditional robotic process automation (RPA) tools. By leveraging machine learning to understand screen elements and user interactions, BotDesktop can adapt to minor UI changes and variations that would break conventional scripted automation. This resilience is particularly valuable in enterprise environments where applications receive regular updates or where slight variations exist between different versions or installations of the same software. The AI component also simplifies the creation of automation scripts - instead of requiring complex programming, users can simply demonstrate the desired actions which BotDesktop observes and learns to replicate.
For comprehensive documentation, see **[docs.pragmatismo.com.br](https://docs.pragmatismo.com.br)** or the **[BotBook](./botbook)** for detailed guides and API references.
---
From an integration perspective, BotDesktop complements botserver by enabling end-to-end automation scenarios that span both modern and legacy systems. For example, a bot created in botserver could collect information from users through a modern chat interface, then use BotDesktop to input that data into a legacy desktop application that lacks API access. This hybrid approach allows organizations to modernize their user interactions while still leveraging their existing IT investments. Additionally, BotDesktop can automate routine desktop tasks like file management, data entry, and application monitoring that fall outside the scope of conversational bot interactions.
## Quick Start
The combined toolset of botserver and BotDesktop provides organizations with comprehensive automation capabilities across their entire technology stack. While botserver handles the modern, API-driven interactions with users across multiple channels, BotDesktop extends automation capabilities to the desktop environment where many critical business processes still reside. This dual approach allows organizations to progressively modernize their systems while maintaining operational efficiency through automation of both new and legacy components. The result is a more flexible and complete automation solution that can adapt to various technical environments and business needs.
## Setup
1. Install dependencies:
```bash
npm install
# Development mode - starts Axum server on port 9000
cargo run
# Desktop mode (Tauri) - starts native window
cargo tauri dev
```
2. Create a .env file with your Azure OpenAI credentials
### Environment Variables
3. Development:
```bash
npm run dev
- `BOTUI_PORT` - Server port (default: 9000)
---
## ZERO TOLERANCE POLICY
**EVERY SINGLE WARNING MUST BE FIXED. NO EXCEPTIONS.**
---
## ❌ ABSOLUTE PROHIBITIONS
```
❌ NEVER use #![allow()] or #[allow()] in source code
❌ NEVER use _ prefix for unused variables - DELETE or USE them
❌ NEVER use .unwrap() - use ? or proper error handling
❌ NEVER use .expect() - use ? or proper error handling
❌ NEVER use panic!() or unreachable!()
❌ NEVER use todo!() or unimplemented!()
❌ NEVER leave unused imports or dead code
❌ NEVER add comments - code must be self-documenting
❌ NEVER use CDN links - all assets must be local
```
4. Build:
```bash
npm run build
---
## 🏗️ ARCHITECTURE
### Dual Modes
| Mode | Command | Description |
|------|---------|-------------|
| Web | `cargo run` | Axum server on port 9000 |
| Desktop | `cargo tauri dev` | Tauri native window |
### Code Organization
```
src/
├── main.rs # Entry point - mode detection
├── lib.rs # Feature-gated module exports
├── http_client.rs # HTTP wrapper for botserver
├── ui_server/
│ └── mod.rs # Axum router + UI serving
├── desktop/
│ ├── mod.rs # Desktop module organization
│ ├── drive.rs # File operations via Tauri
│ └── tray.rs # System tray
└── shared/
└── state.rs # Shared application state
ui/
├── suite/ # Main UI (HTML/CSS/JS)
│ ├── js/vendor/ # Local JS libraries
│ └── css/ # Stylesheets
└── minimal/ # Minimal chat UI
```
## Testing
```bash
npm test
---
## 🎨 HTMX-FIRST FRONTEND
### Core Principle
- **Use HTMX** to minimize JavaScript
- **Server returns HTML fragments**, not JSON
- **Delegate ALL logic** to Rust server
### HTMX Usage
| Use Case | Solution |
|----------|----------|
| Data fetching | `hx-get`, `hx-post` |
| Form submission | `hx-post`, `hx-put` |
| Real-time updates | `hx-ext="ws"` |
| Content swapping | `hx-target`, `hx-swap` |
| Polling | `hx-trigger="every 5s"` |
| Loading states | `hx-indicator` |
### When JS is Required
| Use Case | Why JS Required |
|----------|-----------------|
| Modal show/hide | DOM manipulation |
| Toast notifications | Dynamic element creation |
| Clipboard operations | `navigator.clipboard` API |
| Keyboard shortcuts | `keydown` event handling |
| Complex animations | GSAP or custom |
---
## 📦 LOCAL ASSETS ONLY - NO CDN
```
ui/suite/js/vendor/
├── htmx.min.js
├── htmx-ws.js
├── marked.min.js
├── gsap.min.js
└── livekit-client.umd.min.js
```
```html
<!-- ✅ CORRECT -->
<script src="js/vendor/htmx.min.js"></script>
<!-- ❌ WRONG -->
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
```
---
## 🎨 OFFICIAL ICONS - MANDATORY
**NEVER generate icons with LLM. Use official SVG icons:**
```
ui/suite/assets/icons/
├── gb-logo.svg # Main GB logo
├── gb-bot.svg # Bot/assistant
├── gb-analytics.svg # Analytics
├── gb-calendar.svg # Calendar
├── gb-chat.svg # Chat
├── gb-drive.svg # File storage
├── gb-mail.svg # Email
├── gb-meet.svg # Video meetings
├── gb-tasks.svg # Task management
└── ...
```
All icons use `stroke="currentColor"` for CSS theming.
---
## 🔒 SECURITY ARCHITECTURE
### Centralized Auth Engine
All authentication is handled by `security-bootstrap.js` which MUST be loaded immediately after HTMX:
```html
<head>
<!-- 1. HTMX first -->
<script src="js/vendor/htmx.min.js"></script>
<script src="js/vendor/htmx-ws.js"></script>
<!-- 2. Security bootstrap immediately after -->
<script src="js/security-bootstrap.js"></script>
<!-- 3. Other scripts -->
<script src="js/api-client.js"></script>
</head>
```
### DO NOT Duplicate Auth Logic
```javascript
// ❌ WRONG - Don't add auth headers manually
fetch("/api/data", {
headers: { "Authorization": "Bearer " + token }
});
// ✅ CORRECT - Let security-bootstrap.js handle it
fetch("/api/data");
```
---
## 🎨 DESIGN SYSTEM
### Layout Standards
```css
.app-container {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
.main-content {
display: grid;
grid-template-columns: 320px 1fr;
flex: 1;
overflow: hidden;
}
.list-panel {
overflow-y: scroll;
scrollbar-width: auto;
}
.detail-panel {
display: flex;
flex-direction: column;
overflow: hidden;
}
```
### Theme Variables Required
```css
[data-theme="your-theme"] {
--bg: #0a0a0a;
--surface: #161616;
--surface-hover: #1e1e1e;
--border: #2a2a2a;
--text: #ffffff;
--text-secondary: #888888;
--primary: #c5f82a;
--success: #22c55e;
--warning: #f59e0b;
--error: #ef4444;
}
```
---
## ✅ CODE PATTERNS
### Error Handling
```rust
// ❌ WRONG
let value = something.unwrap();
// ✅ CORRECT
let value = something?;
let value = something.ok_or_else(|| Error::NotFound)?;
```
### Self Usage
```rust
impl MyStruct {
fn new() -> Self { Self { } } // ✅ Not MyStruct
}
```
### Format Strings
```rust
format!("Hello {name}") // ✅ Not format!("{}", name)
```
### Derive Eq with PartialEq
```rust
#[derive(PartialEq, Eq)] // ✅ Always both
struct MyStruct { }
```
---
## 📦 KEY DEPENDENCIES
| Library | Version | Purpose |
|---------|---------|---------|
| axum | 0.7.5 | Web framework |
| reqwest | 0.12 | HTTP client |
| tokio | 1.41 | Async runtime |
| askama | 0.12 | HTML Templates |
---
## 📚 Documentation
For complete documentation, guides, and API references:
- **[docs.pragmatismo.com.br](https://docs.pragmatismo.com.br)** - Full online documentation
- **[BotBook](./botbook)** - Local comprehensive guide
- **[General Bots Repository](https://github.com/GeneralBots/BotServer)** - Main project repository
---
## 🔑 REMEMBER
- **ZERO WARNINGS** - Every clippy warning must be fixed
- **NO ALLOW IN CODE** - Never use #[allow()] in source files
- **NO DEAD CODE** - Delete unused code
- **NO UNWRAP/EXPECT** - Use ? operator
- **HTMX first** - Minimize JS, delegate to server
- **Local assets** - No CDN, all vendor files local
- **No business logic** - All logic in botserver
- **HTML responses** - Server returns fragments, not JSON
- **Version 6.2.0** - do not change without approval

View file

@ -1,3 +1,5 @@
fn main() {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let ui_path = std::path::Path::new(&manifest_dir).join("ui");
println!("cargo:rustc-env=BOTUI_UI_PATH={}", ui_path.display());
}

262
html3.html Normal file
View file

@ -0,0 +1,262 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard - Build V3</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700;800&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
mono: ['"JetBrains Mono"', 'monospace'],
sans: ['Inter', 'sans-serif'],
},
colors: {
brand: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d',
}
}
}
}
}
</script>
<style>
.app-icon {
background: linear-gradient(135deg, #4ade80 0%, #15803d 100%);
box-shadow:
inset 0px 2px 4px rgba(255,255,255,0.4),
inset 0px -2px 4px rgba(0,0,0,0.3),
0px 6px 12px rgba(0,0,0,0.15);
border: 1px solid #14532d;
border-bottom-width: 3px;
}
.workspace-bg {
background-color: #fafdfa;
}
.workspace-grid {
background-image: linear-gradient(to right, #f0fdf4 1px, transparent 1px), linear-gradient(to bottom, #f0fdf4 1px, transparent 1px);
background-size: 40px 40px;
}
/* Custom scrollbar for terminal */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #333;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
</style>
</head>
<body class="h-screen w-screen overflow-hidden flex flex-col bg-[var(--bg,#ffffff)] text-[var(--text,#1f2937)] font-sans selection:bg-brand-200">
<div class="flex-1 flex overflow-hidden relative">
<!-- LEFT SIDEBAR -->
<aside class="w-14 shrink-0 bg-[var(--bg-secondary,#ffffff)] border-r border-[var(--border-color,#f3f4f6)] flex flex-col items-center py-6 z-20 relative">
<div class="flex flex-col space-y-8 text-[var(--text-secondary,#6b7280)]">
<button class="hover:text-[var(--primary,#16a34a)] transition-colors"><i class="fa-solid fa-chevron-right"></i></button>
<button class="hover:text-[var(--primary,#16a34a)] transition-colors text-xl"><i class="fa-solid fa-house"></i></button>
<button class="hover:text-[var(--primary,#16a34a)] transition-colors text-xl"><i class="fa-solid fa-magnifying-glass"></i></button>
<button class="hover:text-[var(--primary,#16a34a)] transition-colors text-xl"><i class="fa-solid fa-border-all"></i></button>
<button class="hover:text-[var(--primary,#16a34a)] transition-colors text-xl"><i class="fa-regular fa-user"></i></button>
<button class="hover:text-[var(--primary,#16a34a)] transition-colors text-xl"><i class="fa-solid fa-layer-group"></i></button>
<button class="hover:text-[var(--primary,#16a34a)] transition-colors text-xl"><i class="fa-solid fa-gear"></i></button>
</div>
</aside>
<!-- MAIN CONTENT -->
<main class="flex-1 flex flex-col min-w-0 relative z-10">
<!-- TOP NAVIGATION PATH -->
<header class="h-12 shrink-0 bg-[var(--bg,#ffffff)] border-b border-[var(--border-color,#f3f4f6)] flex items-center px-6">
<div class="font-mono text-xs font-semibold tracking-wider flex space-x-3 items-center">
<span class="text-[var(--text-secondary,#9ca3af)]">// DASHBOARD</span>
<span class="text-[var(--text-muted,#d1d5db)]">&gt;</span>
<span class="text-[var(--text,#1f2937)]">// E-COMMERCE APP DEVELOPMENT</span>
</div>
</header>
<!-- STAGE NAVIGATION -->
<nav class="h-12 shrink-0 bg-[var(--bg,#ffffff)] border-b border-[var(--border-color,#f3f4f6)] flex items-center font-mono text-xs font-semibold z-10">
<div class="flex-1 flex justify-center border-r border-[var(--border-color,#f3f4f6)] py-3 hover:bg-[var(--bg-hover,#f9fafb)] cursor-pointer text-[var(--text-secondary,#9ca3af)] transition-colors">
// PLAN
</div>
<div class="flex-1 flex justify-center border-r border-[var(--border-color,#f3f4f6)] py-3 bg-[var(--primary-bg,#f0fdf4)] text-[var(--primary,#16a34a)] cursor-pointer border-b-2 border-b-[var(--primary,#22c55e)] transition-colors shadow-[inset_0_2px_4px_rgba(34,197,94,0.05)]">
// BUILD
</div>
<div class="flex-1 flex justify-center border-r border-[var(--border-color,#f3f4f6)] py-3 hover:bg-[var(--bg-hover,#f9fafb)] cursor-pointer text-[var(--text-secondary,#9ca3af)] transition-colors">
// REVIEW
</div>
<div class="flex-1 flex justify-center border-r border-[var(--border-color,#f3f4f6)] py-3 hover:bg-[var(--bg-hover,#f9fafb)] cursor-pointer text-[var(--text-secondary,#9ca3af)] transition-colors">
// DEPLOY
</div>
<div class="flex-1 flex justify-center py-3 hover:bg-[var(--bg-hover,#f9fafb)] cursor-pointer text-[var(--text-secondary,#9ca3af)] transition-colors">
// MONITOR
</div>
</nav>
<!-- WORKSPACE AREA -->
<div class="flex-1 relative overflow-hidden workspace-bg workspace-grid">
<!-- Subtly styled background lines mimicking the design's large cells -->
<svg class="absolute inset-0 w-full h-full pointer-events-none" preserveAspectRatio="none" viewBox="0 0 1000 800" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M-100,200 Q200,200 300,50 T300,-100" stroke="#dcfce7" stroke-width="24" stroke-linecap="round" fill="none" opacity="0.6"/>
<path d="M300,50 Q450,300 650,200 T1000,100" stroke="#dcfce7" stroke-width="28" stroke-linecap="round" fill="none" opacity="0.6"/>
<path d="M200,900 Q300,500 600,600 T1200,500" stroke="#dcfce7" stroke-width="20" stroke-linecap="round" fill="none" opacity="0.6"/>
<path d="M650,200 Q500,450 600,600" stroke="#dcfce7" stroke-width="26" stroke-linecap="round" fill="none" opacity="0.6"/>
<path d="M300,900 Q200,500 -100,600" stroke="#dcfce7" stroke-width="24" stroke-linecap="round" fill="none" opacity="0.6"/>
</svg>
<!-- Desktop Icons Grid -->
<div class="absolute top-10 left-8 flex flex-col space-y-7 z-10">
<!-- Mantis -->
<div class="flex flex-col items-center w-20 group cursor-pointer">
<div class="app-icon w-16 h-16 rounded-xl flex items-center justify-center text-white text-3xl group-hover:scale-105 transition-transform">
<i class="fa-solid fa-microchip drop-shadow-md"></i>
</div>
<span class="mt-2 text-xs font-mono font-medium text-gray-800 bg-white/70 px-1.5 py-0.5 rounded backdrop-blur-sm">Mantis</span>
</div>
<!-- Tasks -->
<div class="flex flex-col items-center w-20 group cursor-pointer">
<div class="app-icon w-16 h-16 rounded-xl flex items-center justify-center text-white text-3xl group-hover:scale-105 transition-transform">
<i class="fa-solid fa-clipboard-list drop-shadow-md"></i>
</div>
<span class="mt-2 text-xs font-mono font-medium text-gray-800 bg-white/70 px-1.5 py-0.5 rounded backdrop-blur-sm">Tasks</span>
</div>
<!-- Chat -->
<div class="flex flex-col items-center w-20 group cursor-pointer">
<div class="app-icon w-16 h-16 rounded-xl flex items-center justify-center text-white text-3xl group-hover:scale-105 transition-transform">
<i class="fa-solid fa-comment-dots drop-shadow-md"></i>
</div>
<span class="mt-2 text-xs font-mono font-medium text-gray-800 bg-white/70 px-1.5 py-0.5 rounded backdrop-blur-sm">Chat</span>
</div>
<!-- Terminal -->
<div class="flex flex-col items-center w-20 group cursor-pointer">
<div class="app-icon w-16 h-16 rounded-xl flex items-center justify-center text-white text-3xl group-hover:scale-105 transition-transform">
<i class="fa-solid fa-terminal drop-shadow-md"></i>
</div>
<span class="mt-2 text-xs font-mono font-medium text-gray-800 bg-white/70 px-1.5 py-0.5 rounded backdrop-blur-sm">Terminal</span>
</div>
<!-- Explorer -->
<div class="flex flex-col items-center w-20 group cursor-pointer">
<div class="app-icon w-16 h-16 rounded-xl flex items-center justify-center text-white text-3xl group-hover:scale-105 transition-transform">
<i class="fa-regular fa-folder-open drop-shadow-md"></i>
</div>
<span class="mt-2 text-xs font-mono font-medium text-gray-800 bg-white/70 px-1.5 py-0.5 rounded backdrop-blur-sm">Explorer</span>
</div>
<!-- Editor -->
<div class="flex flex-col items-center w-20 group cursor-pointer">
<div class="app-icon w-16 h-16 rounded-xl flex items-center justify-center text-white text-3xl group-hover:scale-105 transition-transform">
<i class="fa-solid fa-code drop-shadow-md"></i>
</div>
<span class="mt-2 text-xs font-mono font-medium text-gray-800 bg-white/70 px-1.5 py-0.5 rounded backdrop-blur-sm">Editor</span>
</div>
<!-- Browser -->
<div class="flex flex-col items-center w-20 group cursor-pointer">
<div class="app-icon w-16 h-16 rounded-xl flex items-center justify-center text-white text-3xl group-hover:scale-105 transition-transform">
<i class="fa-regular fa-compass drop-shadow-md"></i>
</div>
<span class="mt-2 text-xs font-mono font-medium text-gray-800 bg-white/70 px-1.5 py-0.5 rounded backdrop-blur-sm">Browser</span>
</div>
</div>
<!-- Floating Terminal Window -->
<div class="absolute bottom-12 left-40 w-[700px] bg-white rounded-lg shadow-2xl flex flex-col border border-gray-200 overflow-hidden z-20 hover:shadow-[0_25px_50px_rgba(0,0,0,0.15)] transition-shadow">
<!-- Window Header -->
<div class="h-10 bg-white/95 backdrop-blur flex items-center justify-between px-4 border-b border-gray-200 select-none cursor-move">
<div class="font-mono text-xs font-bold text-brand-600 tracking-wide flex items-center space-x-2">
<span>// TERMINAL</span>
</div>
<!-- Window Controls -->
<div class="flex space-x-3 text-gray-400">
<button class="hover:text-gray-600 transition-colors"><i class="fa-solid fa-minus"></i></button>
<button class="hover:text-gray-600 transition-colors"><i class="fa-regular fa-square"></i></button>
<button class="hover:text-red-500 transition-colors"><i class="fa-solid fa-xmark"></i></button>
</div>
</div>
<!-- Window Body -->
<div class="bg-[#1a1a1a] p-6 font-mono text-sm leading-relaxed overflow-y-auto h-[260px]">
<div class="text-gray-300 whitespace-pre font-medium"> - @types/node
- @types/react
- @types/react-dom
- postcss
- tailwindcss
- eslint
- eslint-config-next
... [Success] Created project at /home/ecommerceapp
<span class="text-brand-400"></span> Initializing git repository...
<span class="text-brand-400"></span> Installing Prisma...
<span class="text-white">npm</span> install prisma --save-dev
<span class="text-white">npx</span> prisma init --datasource-provider sqlite</div>
<div class="mt-1 flex items-center">
<span class="text-brand-400 mr-2">/home/ecommerceapp $</span>
<div class="w-2.5 h-4 bg-brand-400 animate-pulse inline-block"></div>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- BOTTOM TASKBAR -->
<footer class="h-14 shrink-0 bg-white/95 backdrop-blur-md border-t border-gray-200 flex items-center justify-between px-4 z-30 relative shadow-[0_-2px_10px_rgba(0,0,0,0.02)]">
<!-- Open Apps -->
<div class="flex items-center space-x-2 h-full pt-1">
<div class="h-10 w-12 flex items-center justify-center cursor-pointer hover:bg-gray-100 rounded border-b-2 border-transparent hover:border-brand-500 transition-all">
<div class="app-icon w-8 h-8 rounded-md flex items-center justify-center text-white text-xs shadow-sm">
<i class="fa-regular fa-folder-open"></i>
</div>
</div>
<div class="h-10 w-12 flex items-center justify-center cursor-pointer bg-brand-50 rounded border-b-2 border-brand-500 transition-all">
<div class="app-icon w-8 h-8 rounded-md flex items-center justify-center text-white text-xs shadow-sm">
<i class="fa-solid fa-terminal"></i>
</div>
</div>
<div class="h-10 w-12 flex items-center justify-center cursor-pointer hover:bg-gray-100 rounded border-b-2 border-transparent hover:border-brand-500 transition-all">
<div class="app-icon w-8 h-8 rounded-md flex items-center justify-center text-white text-xs shadow-sm">
<i class="fa-solid fa-comment-dots"></i>
</div>
</div>
</div>
<!-- System Tray -->
<div class="flex items-center space-x-6">
<div class="text-brand-400 text-xl opacity-80 cursor-help hover:text-brand-600 transition-colors">
<i class="fa-brands fa-envira"></i>
</div>
<div class="flex flex-col items-end font-mono text-[11px] text-gray-800 tracking-tight leading-[1.3] mr-2">
<span class="font-bold text-[13px]">21:20</span>
<span class="text-gray-500">01/01/2026</span>
</div>
</div>
</footer>
</body>
</html>

View file

@ -1,4 +1,3 @@
use log::info;
use std::net::SocketAddr;

File diff suppressed because it is too large Load diff

View file

@ -153,7 +153,7 @@
<script>
// Configuration
const CONFIG = {
serverUrl: window.BOTSERVER_URL || 'http://localhost:8088',
serverUrl: window.BOTSERVER_URL || 'http://localhost:8080',
maxMessages: 10, // Keep memory low
maxMsgLen: 100, // Truncate long messages
};

File diff suppressed because it is too large Load diff

73
ui/public/themes/dark.css Normal file
View file

@ -0,0 +1,73 @@
/* Dark Theme for General Bots */
:root {
--color-primary: #d4f505;
--color-secondary: #00d4aa;
--color-accent: #818cf8;
--color-bg: #0f172a;
--color-bg-secondary: #1e293b;
--color-bg-tertiary: #334155;
--color-text: #f1f5f9;
--color-text-secondary: #cbd5e1;
--color-text-muted: #64748b;
--color-border: #334155;
--color-border-light: #1e293b;
--color-success: #22c55e;
--color-warning: #f59e0b;
--color-error: #ef4444;
--color-info: #3b82f6;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.4), 0 1px 2px -1px rgb(0 0 0 / 0.4);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.4);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.5), 0 4px 6px -4px rgb(0 0 0 / 0.5);
--radius-sm: 0.25rem;
--radius: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
}
body {
background-color: var(--color-bg);
color: var(--color-text);
}
a {
color: var(--color-accent);
}
a:hover {
color: var(--color-primary);
}
.btn-primary {
background-color: var(--color-primary);
color: var(--color-bg);
}
.btn-primary:hover {
background-color: var(--color-secondary);
}
.card {
background-color: var(--color-bg-secondary);
border: 1px solid var(--color-border);
box-shadow: var(--shadow-sm);
}
input, textarea, select {
background-color: var(--color-bg-secondary);
border: 1px solid var(--color-border);
color: var(--color-text);
}
input:focus, textarea:focus, select:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(212, 245, 5, 0.1);
}

View file

@ -0,0 +1,73 @@
/* Light Theme for General Bots */
:root {
--color-primary: #d4f505;
--color-secondary: #00d4aa;
--color-accent: #6366f1;
--color-bg: #ffffff;
--color-bg-secondary: #f8fafc;
--color-bg-tertiary: #f1f5f9;
--color-text: #0f172a;
--color-text-secondary: #475569;
--color-text-muted: #94a3b8;
--color-border: #e2e8f0;
--color-border-light: #f1f5f9;
--color-success: #22c55e;
--color-warning: #f59e0b;
--color-error: #ef4444;
--color-info: #3b82f6;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--radius-sm: 0.25rem;
--radius: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
}
body {
background-color: var(--color-bg);
color: var(--color-text);
}
a {
color: var(--color-accent);
}
a:hover {
color: var(--color-primary);
}
.btn-primary {
background-color: var(--color-primary);
color: var(--color-text);
}
.btn-primary:hover {
background-color: var(--color-secondary);
}
.card {
background-color: var(--color-bg);
border: 1px solid var(--color-border);
box-shadow: var(--shadow-sm);
}
input, textarea, select {
background-color: var(--color-bg);
border: 1px solid var(--color-border);
color: var(--color-text);
}
input:focus, textarea:focus, select:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(212, 245, 5, 0.1);
}

View file

@ -0,0 +1,117 @@
/* Y2K Glow Theme for General Bots */
:root {
--color-primary: #ff00ff;
--color-secondary: #00ffff;
--color-accent: #ffff00;
--color-bg: #0a0a1a;
--color-bg-secondary: #1a0a2e;
--color-bg-tertiary: #2d1b4e;
--color-text: #00ff00;
--color-text-secondary: #ff00ff;
--color-text-muted: #00ffff;
--color-border: #ff00ff;
--color-border-light: #00ffff;
--color-success: #00ff00;
--color-warning: #ffff00;
--color-error: #ff0066;
--color-info: #00ffff;
--shadow-glow: 0 0 10px #ff00ff, 0 0 20px #ff00ff, 0 0 30px #ff00ff;
--shadow-sm: 0 0 5px rgba(255, 0, 255, 0.5);
--shadow: 0 0 10px rgba(255, 0, 255, 0.7);
--shadow-md: 0 0 15px rgba(255, 0, 255, 0.8);
--shadow-lg: 0 0 25px rgba(255, 0, 255, 0.9);
--radius-sm: 0.25rem;
--radius: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
}
body {
background-color: var(--color-bg);
color: var(--color-text);
text-shadow: 0 0 5px var(--color-text);
}
a {
color: var(--color-secondary);
text-shadow: 0 0 5px var(--color-secondary);
}
a:hover {
color: var(--color-primary);
text-shadow: 0 0 10px var(--color-primary), 0 0 20px var(--color-primary);
}
.btn-primary {
background: linear-gradient(45deg, var(--color-primary), var(--color-secondary));
color: var(--color-bg);
border: 2px solid var(--color-primary);
box-shadow: var(--shadow-glow);
text-shadow: none;
}
.btn-primary:hover {
background: linear-gradient(45deg, var(--color-secondary), var(--color-accent));
border-color: var(--color-secondary);
box-shadow: 0 0 15px var(--color-secondary), 0 0 30px var(--color-secondary);
}
.card {
background: linear-gradient(135deg, var(--color-bg-secondary), var(--color-bg-tertiary));
border: 2px solid var(--color-primary);
box-shadow: var(--shadow);
animation: glow 2s ease-in-out infinite alternate;
}
@keyframes glow {
from {
box-shadow: 0 0 5px var(--color-primary), 0 0 10px var(--color-primary);
}
to {
box-shadow: 0 0 10px var(--color-secondary), 0 0 20px var(--color-secondary);
}
}
input, textarea, select {
background: var(--color-bg-secondary);
border: 2px solid var(--color-border);
color: var(--color-text);
box-shadow: 0 0 5px var(--color-border);
}
input:focus, textarea:focus, select:focus {
outline: none;
border-color: var(--color-accent);
box-shadow: 0 0 10px var(--color-accent), 0 0 20px var(--color-accent), 0 0 30px var(--color-accent);
}
input::placeholder, textarea::placeholder {
color: var(--color-text-muted);
text-shadow: 0 0 3px var(--color-text-muted);
}
::-webkit-scrollbar {
width: 12px;
height: 12px;
}
::-webkit-scrollbar-track {
background: var(--color-bg);
}
::-webkit-scrollbar-thumb {
background: linear-gradient(var(--color-primary), var(--color-secondary));
border-radius: 6px;
box-shadow: 0 0 10px var(--color-primary);
}
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(var(--color-secondary), var(--color-accent));
}

View file

@ -172,7 +172,7 @@
<div class="activity-list" hx-get="/api/admin/dashboard/activity" hx-trigger="load" hx-swap="innerHTML">
<div class="activity-item">
<div class="activity-avatar">
<img src="/assets/avatars/default.svg" alt="User avatar">
<img src="/suite/assets/avatars/default.svg" alt="User avatar">
</div>
<div class="activity-content">
<div class="activity-text">
@ -198,7 +198,7 @@
</div>
<div class="activity-item">
<div class="activity-avatar">
<img src="/assets/avatars/default.svg" alt="User avatar">
<img src="/suite/assets/avatars/default.svg" alt="User avatar">
</div>
<div class="activity-content">
<div class="activity-text">
@ -222,7 +222,7 @@
</div>
<div class="activity-item">
<div class="activity-avatar">
<img src="/assets/avatars/default.svg" alt="User avatar">
<img src="/suite/assets/avatars/default.svg" alt="User avatar">
</div>
<div class="activity-content">
<div class="activity-text">
@ -274,7 +274,7 @@
<div class="member-list" hx-get="/api/admin/dashboard/members" hx-trigger="load" hx-swap="innerHTML">
<div class="member-item">
<div class="member-avatar">
<img src="/assets/avatars/default.svg" alt="User avatar">
<img src="/suite/assets/avatars/default.svg" alt="User avatar">
<span class="status-indicator online"></span>
</div>
<div class="member-info">
@ -285,7 +285,7 @@
</div>
<div class="member-item">
<div class="member-avatar">
<img src="/assets/avatars/default.svg" alt="User avatar">
<img src="/suite/assets/avatars/default.svg" alt="User avatar">
<span class="status-indicator online"></span>
</div>
<div class="member-info">
@ -296,7 +296,7 @@
</div>
<div class="member-item">
<div class="member-avatar">
<img src="/assets/avatars/default.svg" alt="User avatar">
<img src="/suite/assets/avatars/default.svg" alt="User avatar">
<span class="status-indicator away"></span>
</div>
<div class="member-info">
@ -307,7 +307,7 @@
</div>
<div class="member-item">
<div class="member-avatar">
<img src="/assets/avatars/default.svg" alt="User avatar">
<img src="/suite/assets/avatars/default.svg" alt="User avatar">
<span class="status-indicator offline"></span>
</div>
<div class="member-info">

View file

@ -2,7 +2,7 @@
<div class="wizard-container">
<div class="wizard-sidebar">
<div class="wizard-logo">
<img src="/assets/icons/gb-logo.svg" alt="General Bots" width="48" height="48">
<img src="/suite/assets/icons/gb-logo.svg" alt="General Bots" width="48" height="48">
</div>
<div class="wizard-steps">
<div class="wizard-step active" data-step="1">

View file

@ -1322,7 +1322,6 @@
"WebSocket connected for attendant:",
currentAttendantId,
);
reconnectAttempts = 0;
showToast(
"Connected to notification service",
"success",
@ -1367,6 +1366,7 @@
switch (msgType) {
case "connected":
console.log("WebSocket connected:", data.message);
reconnectAttempts = 0;
break;
case "new_conversation":
showToast("New conversation in queue", "info");

View file

@ -283,7 +283,7 @@
<body>
<div class="setup-container">
<div class="setup-header">
<div class="setup-logo">🤖</div>
<div class="setup-logo"><img src="/suite/assets/icons/gb-logo.svg" alt="General Bots" width="48" height="48"></div>
<h1 class="setup-title">Initial Setup</h1>
<p class="setup-subtitle">
Create the first administrator account for your General Bots installation

View file

@ -4,8 +4,8 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login - General Bots</title>
<script src="/js/vendor/htmx.min.js"></script>
<script src="/js/vendor/htmx-json-enc.js"></script>
<script src="/suite/js/vendor/htmx.min.js"></script>
<script src="/suite/js/vendor/htmx-json-enc.js"></script>
<style>
:root {
--primary: #3b82f6;
@ -75,6 +75,18 @@
box-shadow: 0 8px 32px rgba(59, 130, 246, 0.3);
}
.login-logo img {
width: 100%;
height: 100%;
object-fit: contain;
border-radius: 18px;
}
.login-logo:has(img[src]) {
background: transparent;
box-shadow: none;
}
.login-title {
font-size: 1.75rem;
font-weight: 700;
@ -585,9 +597,12 @@
<body>
<div class="login-container">
<div class="login-header">
<div class="login-logo">🤖</div>
<h1 class="login-title">Welcome Back</h1>
<p class="login-subtitle">
<div class="login-logo" id="login-logo">
<img id="login-logo-img" src="" alt="Logo" style="display:none; width:100%; height:100%; object-fit:contain;">
<span id="login-logo-default"><img src="/suite/assets/icons/gb-logo.svg" alt="General Bots" width="48" height="48"></span>
</div>
<h1 class="login-title" id="login-title">Welcome Back</h1>
<p class="login-subtitle" id="login-subtitle">
Sign in to your General Bots account
</p>
</div>
@ -1018,6 +1033,55 @@
</div>
<script>
// Load bot config and apply logo/title
async function loadBotConfig() {
try {
// Get bot name from URL path
const pathParts = window.location.pathname.split('/');
const botName = pathParts[1] || 'default';
// Fetch bot config
const response = await fetch(`/api/bot/config?bot_name=${botName}`);
if (response.ok) {
const config = await response.json();
// Apply logo if provided
const logo = config.theme_logo || config["theme-logo"] || "";
if (logo) {
const logoImg = document.getElementById("login-logo-img");
const logoDefault = document.getElementById("login-logo-default");
const logoContainer = document.getElementById("login-logo");
if (logoImg) {
logoImg.src = logo;
logoImg.style.display = "block";
}
if (logoDefault) {
logoDefault.style.display = "none";
}
}
// Apply title if provided
const title = config.theme_title || config["theme-title"] || "";
if (title) {
const titleEl = document.getElementById("login-title");
if (titleEl) {
titleEl.textContent = title;
}
const subtitleEl = document.getElementById("login-subtitle");
if (subtitleEl) {
subtitleEl.textContent = "Sign in to your account";
}
}
}
} catch (e) {
console.log("Could not load bot config:", e);
}
}
// Load bot config on page load
loadBotConfig();
// Password visibility toggle
function togglePassword() {
const passwordInput = document.getElementById("password");
@ -1264,12 +1328,18 @@
// Successful login - redirect
if (response.redirect || response.success) {
window.location.href = response.redirect || "/";
// Check for redirect parameter in URL
const urlParams = new URLSearchParams(window.location.search);
const redirectUrl = urlParams.get('redirect') || response.redirect;
window.location.href = redirectUrl ? redirectUrl : window.location.origin + "/#chat";
}
} catch (e) {
// If response is not JSON, check for redirect header
if (event.detail.xhr.status === 200) {
window.location.href = "/";
// Check for redirect parameter in URL
const urlParams = new URLSearchParams(window.location.search);
const redirectUrl = urlParams.get('redirect');
window.location.href = redirectUrl ? redirectUrl : window.location.origin + "/#chat";
}
}
} else {

View file

@ -557,7 +557,7 @@
<body>
<div class="register-container">
<div class="register-header">
<div class="register-logo">🤖</div>
<div class="register-logo"><img src="/suite/assets/icons/gb-logo.svg" alt="General Bots" width="48" height="48"></div>
<h1 class="register-title">Create Account</h1>
<p class="register-subtitle">
Join General Bots and start building

View file

@ -1,983 +0,0 @@
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BotUI Suite - Base Layout Preview</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
/* =============================================================================
SENTIENT THEME VARIABLES
============================================================================= */
:root {
--sentient-bg-primary: #0a0a0a;
--sentient-bg-secondary: #111111;
--sentient-bg-tertiary: #1a1a1a;
--sentient-bg-card: #141414;
--sentient-bg-hover: #1f1f1f;
--sentient-accent: #c5f82a;
--sentient-accent-dim: rgba(197, 248, 42, 0.15);
--sentient-accent-glow: rgba(197, 248, 42, 0.3);
--sentient-success: #22c55e;
--sentient-warning: #f59e0b;
--sentient-error: #ef4444;
--sentient-info: #3b82f6;
--sentient-text-primary: #ffffff;
--sentient-text-secondary: #a1a1a1;
--sentient-text-muted: #6b6b6b;
--sentient-border: #2a2a2a;
--sentient-border-hover: #3a3a3a;
--sentient-radius-sm: 6px;
--sentient-radius-md: 10px;
--sentient-radius-lg: 16px;
--sentient-font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--sentient-font-family);
background: var(--sentient-bg-primary);
color: var(--sentient-text-primary);
}
/* =============================================================================
LAYOUT
============================================================================= */
.suite-app {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.suite-topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
background: var(--sentient-bg-primary);
border-bottom: 1px solid var(--sentient-border);
height: 52px;
}
.topbar-left {
display: flex;
align-items: center;
gap: 16px;
}
.topbar-tabs {
display: flex;
gap: 2px;
}
.topbar-tab {
padding: 8px 16px;
background: transparent;
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-sm);
color: var(--sentient-text-secondary);
font-family: var(--sentient-font-family);
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.topbar-tab:first-child {
border-radius: var(--sentient-radius-sm) 0 0 var(--sentient-radius-sm);
}
.topbar-tab:last-child {
border-radius: 0 var(--sentient-radius-sm) var(--sentient-radius-sm) 0;
border-left: none;
}
.topbar-tab:hover {
background: var(--sentient-bg-tertiary);
color: var(--sentient-text-primary);
}
.topbar-tab.active {
background: var(--sentient-bg-tertiary);
border-color: var(--sentient-accent);
color: var(--sentient-accent);
}
.topbar-app-launcher {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 8px;
background: var(--sentient-bg-secondary);
border-radius: var(--sentient-radius-lg);
margin-left: 16px;
}
.app-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--sentient-bg-tertiary);
border: none;
border-radius: var(--sentient-radius-md);
color: var(--sentient-text-primary);
font-size: 18px;
cursor: pointer;
transition: all 0.2s ease;
}
.app-icon:hover {
background: var(--sentient-bg-hover);
transform: scale(1.05);
}
.app-icon.active {
background: var(--sentient-accent-dim);
color: var(--sentient-accent);
}
.topbar-right {
display: flex;
align-items: center;
gap: 12px;
}
.topbar-btn-primary {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
background: var(--sentient-accent);
border: none;
border-radius: var(--sentient-radius-sm);
color: #000;
font-family: var(--sentient-font-family);
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
.topbar-btn-primary:hover {
background: #d4ff4a;
box-shadow: 0 0 20px var(--sentient-accent-glow);
}
.topbar-btn-icon {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-sm);
color: var(--sentient-text-secondary);
font-size: 16px;
cursor: pointer;
transition: all 0.2s ease;
}
.topbar-btn-icon:hover {
background: var(--sentient-bg-tertiary);
color: var(--sentient-text-primary);
}
.suite-main {
display: flex;
flex: 1;
overflow: hidden;
}
.suite-content-panel {
flex: 1;
display: flex;
flex-direction: column;
overflow: auto;
padding: 20px 24px;
}
/* =============================================================================
AI PANEL
============================================================================= */
.suite-ai-panel {
width: 320px;
display: flex;
flex-direction: column;
background: var(--sentient-bg-secondary);
border-left: 1px solid var(--sentient-border);
}
.ai-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
border-bottom: 1px solid var(--sentient-border);
}
.ai-panel-title {
display: flex;
align-items: center;
gap: 12px;
}
.ai-avatar {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: var(--sentient-accent-dim);
border-radius: var(--sentient-radius-md);
font-size: 18px;
}
.ai-panel-title h3 {
font-size: 14px;
font-weight: 600;
margin: 0;
}
.ai-panel-title .ai-status {
font-size: 11px;
color: var(--sentient-text-muted);
margin: 2px 0 0 0;
}
.ai-panel-close {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
border-radius: var(--sentient-radius-sm);
color: var(--sentient-text-muted);
font-size: 16px;
cursor: pointer;
}
.ai-panel-close:hover {
background: var(--sentient-bg-tertiary);
color: var(--sentient-text-primary);
}
.ai-panel-messages {
flex: 1;
overflow-y: auto;
padding: 16px;
display: flex;
flex-direction: column;
gap: 16px;
}
.ai-message {
display: flex;
flex-direction: column;
gap: 8px;
}
.ai-message.user { align-items: flex-end; }
.ai-message.assistant { align-items: flex-start; }
.ai-message-bubble {
max-width: 90%;
padding: 12px 14px;
border-radius: var(--sentient-radius-md);
font-size: 13px;
line-height: 1.5;
}
.ai-message.user .ai-message-bubble {
background: var(--sentient-accent);
color: #000;
border-bottom-right-radius: 4px;
}
.ai-message.assistant .ai-message-bubble {
background: var(--sentient-bg-tertiary);
color: var(--sentient-text-primary);
border-bottom-left-radius: 4px;
}
.ai-message-action {
display: inline-block;
padding: 8px 12px;
background: var(--sentient-accent);
color: #000;
border-radius: var(--sentient-radius-sm);
font-size: 12px;
font-weight: 500;
cursor: pointer;
}
.ai-typing-indicator {
display: flex;
gap: 4px;
padding: 12px 14px;
background: var(--sentient-bg-tertiary);
border-radius: var(--sentient-radius-md);
width: fit-content;
}
.ai-typing-indicator span {
width: 8px;
height: 8px;
background: var(--sentient-text-muted);
border-radius: 50%;
animation: typing 1.4s infinite;
}
.ai-typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
.ai-typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
@keyframes typing {
0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
30% { transform: translateY(-4px); opacity: 1; }
}
.ai-quick-actions {
padding: 12px 16px;
border-top: 1px solid var(--sentient-border);
}
.quick-actions-label {
display: block;
font-size: 10px;
font-weight: 600;
color: var(--sentient-text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 10px;
}
.quick-actions-grid {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.quick-action-btn {
padding: 6px 10px;
background: var(--sentient-bg-tertiary);
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-sm);
color: var(--sentient-text-secondary);
font-family: var(--sentient-font-family);
font-size: 11px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.quick-action-btn:hover {
background: var(--sentient-bg-hover);
border-color: var(--sentient-accent);
color: var(--sentient-accent);
}
.ai-panel-input {
display: flex;
gap: 8px;
padding: 12px 16px;
border-top: 1px solid var(--sentient-border);
}
.ai-input {
flex: 1;
padding: 10px 14px;
background: var(--sentient-bg-tertiary);
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-md);
color: var(--sentient-text-primary);
font-family: var(--sentient-font-family);
font-size: 13px;
}
.ai-input::placeholder { color: var(--sentient-text-muted); }
.ai-input:focus { outline: none; border-color: var(--sentient-accent); }
.ai-send-btn {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--sentient-accent);
border: none;
border-radius: var(--sentient-radius-md);
color: #000;
font-size: 16px;
cursor: pointer;
}
.ai-send-btn:hover { background: #d4ff4a; }
/* =============================================================================
STAT CARDS
============================================================================= */
.stat-cards {
display: flex;
gap: 12px;
margin-bottom: 20px;
}
.stat-card {
flex: 1;
display: flex;
align-items: center;
gap: 12px;
padding: 16px;
background: var(--sentient-bg-card);
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-md);
}
.stat-card-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--sentient-bg-tertiary);
border-radius: var(--sentient-radius-sm);
font-size: 18px;
}
.stat-card-content { flex: 1; }
.stat-card-label {
font-size: 11px;
color: var(--sentient-text-muted);
text-transform: uppercase;
letter-spacing: 0.3px;
margin-bottom: 4px;
}
.stat-card-value {
font-size: 20px;
font-weight: 700;
}
.stat-card.highlight {
border-color: var(--sentient-accent);
}
.stat-card.highlight .stat-card-value {
color: var(--sentient-accent);
}
/* =============================================================================
APP HEADER
============================================================================= */
.app-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 20px;
}
.app-title-section h1 {
font-size: 22px;
font-weight: 700;
margin: 0 0 4px 0;
}
.app-title-section p {
font-size: 13px;
color: var(--sentient-text-muted);
margin: 0;
}
.app-actions {
display: flex;
gap: 10px;
}
.app-btn-primary {
display: flex;
align-items: center;
gap: 6px;
padding: 10px 16px;
background: var(--sentient-accent);
border: none;
border-radius: var(--sentient-radius-sm);
color: #000;
font-family: var(--sentient-font-family);
font-size: 13px;
font-weight: 600;
cursor: pointer;
}
.app-btn-primary:hover { background: #d4ff4a; }
.app-btn-secondary {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: var(--sentient-bg-tertiary);
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-sm);
color: var(--sentient-text-secondary);
font-size: 16px;
cursor: pointer;
}
.app-btn-secondary:hover {
background: var(--sentient-bg-hover);
color: var(--sentient-text-primary);
}
/* =============================================================================
DATA TABLE
============================================================================= */
.data-table-container {
flex: 1;
background: var(--sentient-bg-card);
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-lg);
overflow: hidden;
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table thead {
background: var(--sentient-bg-tertiary);
}
.data-table th {
padding: 12px 16px;
text-align: left;
font-size: 11px;
font-weight: 600;
color: var(--sentient-text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
border-bottom: 1px solid var(--sentient-border);
}
.data-table td {
padding: 14px 16px;
font-size: 13px;
color: var(--sentient-text-primary);
border-bottom: 1px solid var(--sentient-border);
}
.data-table tbody tr:hover {
background: var(--sentient-bg-tertiary);
}
.data-table tbody tr:last-child td {
border-bottom: none;
}
.status-badge {
display: inline-block;
padding: 4px 10px;
border-radius: 12px;
font-size: 11px;
font-weight: 600;
}
.status-badge.active {
background: rgba(34, 197, 94, 0.15);
color: var(--sentient-success);
}
.status-badge.pending {
background: rgba(245, 158, 11, 0.15);
color: var(--sentient-warning);
}
.status-badge.inactive {
background: rgba(239, 68, 68, 0.15);
color: var(--sentient-error);
}
.table-actions {
display: flex;
gap: 6px;
}
.table-action-btn {
padding: 6px 12px;
background: var(--sentient-bg-tertiary);
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-sm);
color: var(--sentient-text-secondary);
font-family: var(--sentient-font-family);
font-size: 12px;
cursor: pointer;
transition: all 0.2s ease;
}
.table-action-btn:hover {
background: var(--sentient-bg-hover);
color: var(--sentient-text-primary);
}
.table-action-btn.delete {
background: rgba(239, 68, 68, 0.1);
border-color: rgba(239, 68, 68, 0.3);
color: var(--sentient-error);
}
.table-action-btn.delete:hover {
background: rgba(239, 68, 68, 0.2);
}
.data-table-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
background: var(--sentient-bg-tertiary);
border-top: 1px solid var(--sentient-border);
}
.pagination-info {
font-size: 12px;
color: var(--sentient-text-muted);
}
.pagination-controls {
display: flex;
align-items: center;
gap: 4px;
}
.pagination-btn {
padding: 6px 12px;
background: var(--sentient-bg-card);
border: 1px solid var(--sentient-border);
border-radius: var(--sentient-radius-sm);
color: var(--sentient-text-secondary);
font-family: var(--sentient-font-family);
font-size: 12px;
cursor: pointer;
}
.pagination-btn:hover {
background: var(--sentient-bg-hover);
color: var(--sentient-text-primary);
}
.pagination-btn.active {
background: var(--sentient-accent);
border-color: var(--sentient-accent);
color: #000;
}
/* =============================================================================
SCROLLBAR
============================================================================= */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--sentient-bg-secondary); }
::-webkit-scrollbar-thumb { background: var(--sentient-bg-tertiary); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--sentient-border-hover); }
</style>
</head>
<body>
<div class="suite-app">
<!-- Top Header Bar -->
<header class="suite-topbar">
<div class="topbar-left">
<nav class="topbar-tabs">
<button class="topbar-tab active">Dashboard</button>
<button class="topbar-tab">Analytics</button>
</nav>
<div class="topbar-app-launcher">
<button class="app-icon" data-app="chat" title="Chat">💬</button>
<button class="app-icon active" data-app="files" title="Files">📁</button>
<button class="app-icon" data-app="terminal" title="Terminal">⌨️</button>
<button class="app-icon" data-app="tasks" title="Tasks"></button>
<button class="app-icon" data-app="calendar" title="Calendar">📅</button>
<button class="app-icon" data-app="docs" title="Docs">📄</button>
<button class="app-icon" data-app="settings" title="Settings">⚙️</button>
</div>
</div>
<div class="topbar-right">
<button class="topbar-btn-primary">✨ New Intent</button>
<button class="topbar-btn-icon" title="Settings">⚙️</button>
</div>
</header>
<!-- Main Content Area -->
<main class="suite-main">
<!-- Left: Content Panel -->
<section class="suite-content-panel">
<!-- Stat Cards -->
<div class="stat-cards">
<div class="stat-card highlight">
<div class="stat-card-icon">📊</div>
<div class="stat-card-content">
<div class="stat-card-label">Total Records</div>
<div class="stat-card-value">12,847</div>
</div>
</div>
<div class="stat-card">
<div class="stat-card-icon"></div>
<div class="stat-card-content">
<div class="stat-card-label">Active</div>
<div class="stat-card-value">8,234</div>
</div>
</div>
<div class="stat-card">
<div class="stat-card-icon"></div>
<div class="stat-card-content">
<div class="stat-card-label">Pending</div>
<div class="stat-card-value">2,156</div>
</div>
</div>
<div class="stat-card">
<div class="stat-card-icon">📈</div>
<div class="stat-card-content">
<div class="stat-card-label">Growth</div>
<div class="stat-card-value">+24%</div>
</div>
</div>
</div>
<!-- App Header -->
<div class="app-header">
<div class="app-title-section">
<h1>Files Manager</h1>
<p>Manage your documents and media files</p>
</div>
<div class="app-actions">
<button class="app-btn-primary">+ Upload File</button>
<button class="app-btn-secondary">🔍</button>
<button class="app-btn-secondary"></button>
</div>
</div>
<!-- Data Table -->
<div class="data-table-container">
<table class="data-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Size</th>
<th>Modified</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>project-report.pdf</td>
<td>PDF Document</td>
<td>2.4 MB</td>
<td>Dec 13, 2025</td>
<td><span class="status-badge active">Active</span></td>
<td>
<div class="table-actions">
<button class="table-action-btn">View</button>
<button class="table-action-btn">Edit</button>
<button class="table-action-btn delete">Delete</button>
</div>
</td>
</tr>
<tr>
<td>dashboard-mockup.fig</td>
<td>Figma File</td>
<td>8.1 MB</td>
<td>Dec 12, 2025</td>
<td><span class="status-badge pending">Pending</span></td>
<td>
<div class="table-actions">
<button class="table-action-btn">View</button>
<button class="table-action-btn">Edit</button>
<button class="table-action-btn delete">Delete</button>
</div>
</td>
</tr>
<tr>
<td>api-documentation.md</td>
<td>Markdown</td>
<td>156 KB</td>
<td>Dec 11, 2025</td>
<td><span class="status-badge active">Active</span></td>
<td>
<div class="table-actions">
<button class="table-action-btn">View</button>
<button class="table-action-btn">Edit</button>
<button class="table-action-btn delete">Delete</button>
</div>
</td>
</tr>
<tr>
<td>backup-2025-12.zip</td>
<td>Archive</td>
<td>45.2 MB</td>
<td>Dec 10, 2025</td>
<td><span class="status-badge inactive">Archived</span></td>
<td>
<div class="table-actions">
<button class="table-action-btn">View</button>
<button class="table-action-btn">Edit</button>
<button class="table-action-btn delete">Delete</button>
</div>
</td>
</tr>
<tr>
<td>user-analytics.csv</td>
<td>Spreadsheet</td>
<td>890 KB</td>
<td>Dec 9, 2025</td>
<td><span class="status-badge active">Active</span></td>
<td>
<div class="table-actions">
<button class="table-action-btn">View</button>
<button class="table-action-btn">Edit</button>
<button class="table-action-btn delete">Delete</button>
</div>
</td>
</tr>
</tbody>
</table>
<div class="data-table-footer">
<span class="pagination-info">Showing 1-5 of 847 files</span>
<div class="pagination-controls">
<button class="pagination-btn"></button>
<button class="pagination-btn active">1</button>
<button class="pagination-btn">2</button>
<button class="pagination-btn">3</button>
<button class="pagination-btn">...</button>
<button class="pagination-btn">170</button>
<button class="pagination-btn"></button>
</div>
</div>
</div>
</section>
<!-- Right: AI Assistant Panel -->
<aside class="suite-ai-panel">
<div class="ai-panel-header">
<div class="ai-panel-title">
<span class="ai-avatar">🤖</span>
<div>
<h3>AI Developer</h3>
<p class="ai-status">Desenvolvendo: CRM Deloitte</p>
</div>
</div>
<button class="ai-panel-close"></button>
</div>
<div class="ai-panel-messages" id="ai-messages">
<div class="ai-message assistant">
<div class="ai-message-bubble">Olá! Sou o AI Developer. Como posso ajudar você hoje?</div>
</div>
<div class="ai-message assistant">
<div class="ai-message-bubble">Você pode me pedir para modificar campos, alterar cores, adicionar validações ou qualquer outra mudança no sistema.</div>
</div>
<div class="ai-message user">
<div class="ai-message-bubble">Adicione um campo de telefone no formulário de cadastro</div>
</div>
<div class="ai-message assistant">
<div class="ai-message-bubble">Perfeito! Adicionei o campo de telefone com máscara automática e validação de formato brasileiro.</div>
<span class="ai-message-action">Ver alterações</span>
</div>
</div>
<div class="ai-quick-actions">
<span class="quick-actions-label">AÇÕES RÁPIDAS</span>
<div class="quick-actions-grid">
<button class="quick-action-btn">Adicionar campo</button>
<button class="quick-action-btn">Mudar cor</button>
<button class="quick-action-btn">Adicionar validação</button>
<button class="quick-action-btn">Exportar dados</button>
</div>
</div>
<div class="ai-panel-input">
<input type="text" class="ai-input" placeholder="Digite suas modificações..." id="ai-input">
<button class="ai-send-btn"></button>
</div>
</aside>
</main>
</div>
<script>
// Tab switching
document.querySelectorAll('.topbar-tab').forEach(tab => {
tab.addEventListener('click', function() {
document.querySelectorAll('.topbar-tab').forEach(t => t.classList.remove('active'));
this.classList.add('active');
});
});
// App icon switching
document.querySelectorAll('.app-icon').forEach(icon => {
icon.addEventListener('click', function() {
document.querySelectorAll('.app-icon').forEach(i => i.classList.remove('active'));
this.classList.add('active');
});
});
// Quick actions
document.querySelectorAll('.quick-action-btn').forEach(btn => {
btn.addEventListener('click', function() {
const action = this.textContent;
addMessage('user', action);
setTimeout(() => {
addMessage('assistant', `Ação "${action}" executada com sucesso!`);
}, 1000);
});
});
// Send message
document.querySelector('.ai-send-btn').addEventListener('click', sendMessage);
document.getElementById('ai-input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') sendMessage();
});
function sendMessage() {
const input = document.getElementById('ai-input');
const message = input.value.trim();
if (!message) return;
addMessage('user', message);
input.value = '';
setTimeout(() => {
addMessage('assistant', `Entendido! Processando: "${message}"`);
}, 1500);
}
function addMessage(type, content) {
const container = document.getElementById('ai-messages');
const div = document.createElement('div');
div.className = `ai-message ${type}`;
div.innerHTML = `<div class="ai-message-bubble">${content}</div>`;
container.appendChild(div);
container.scrollTop = container.scrollHeight;
}
</script>
</body>
</html>

View file

@ -1,98 +0,0 @@
<!-- =============================================================================
BOTUI SUITE - BASE LAYOUT
Sentient Theme with AI Assistant Panel
============================================================================= -->
<link rel="stylesheet" href="/themes/sentient/sentient.css">
<link rel="stylesheet" href="/suite/base-layout.css">
<div class="suite-app sentient-theme">
<!-- Top Header Bar -->
<header class="suite-topbar">
<!-- Left: Navigation Tabs -->
<div class="topbar-left">
<nav class="topbar-tabs">
<button class="topbar-tab active">Dashboard</button>
<button class="topbar-tab">Analytics</button>
</nav>
<!-- App Launcher -->
<div class="topbar-app-launcher">
<button class="app-icon" data-app="chat" title="Chat">
<span>💬</span>
</button>
<button class="app-icon" data-app="files" title="Files">
<span>📁</span>
</button>
<button class="app-icon" data-app="terminal" title="Terminal">
<span>⌨️</span>
</button>
<button class="app-icon" data-app="tasks" title="Tasks">
<span></span>
</button>
<button class="app-icon" data-app="calendar" title="Calendar">
<span>📅</span>
</button>
<button class="app-icon" data-app="docs" title="Docs">
<span>📄</span>
</button>
<button class="app-icon" data-app="settings" title="Settings">
<span>⚙️</span>
</button>
</div>
</div>
<!-- Right: Actions -->
<div class="topbar-right">
<button class="topbar-btn-primary">
<span></span> New Intent
</button>
<button class="topbar-btn-icon" title="Settings">⚙️</button>
</div>
</header>
<!-- Main Content Area -->
<main class="suite-main">
<!-- Left: Content Panel -->
<section class="suite-content-panel" id="suite-content">
<!-- App content goes here -->
</section>
<!-- Right: AI Assistant Panel -->
<aside class="suite-ai-panel" id="ai-panel">
<div class="ai-panel-header">
<div class="ai-panel-title">
<span class="ai-avatar">🤖</span>
<div>
<h3>AI Developer</h3>
<p class="ai-status">Desenvolvendo: CRM Deloitte</p>
</div>
</div>
<button class="ai-panel-close" onclick="toggleAIPanel()"></button>
</div>
<div class="ai-panel-messages" id="ai-messages">
<!-- Messages will be inserted here -->
</div>
<div class="ai-quick-actions">
<span class="quick-actions-label">AÇÕES RÁPIDAS</span>
<div class="quick-actions-grid">
<button class="quick-action-btn">Adicionar campo</button>
<button class="quick-action-btn">Mudar cor</button>
<button class="quick-action-btn">Adicionar validação</button>
<button class="quick-action-btn">Exportar dados</button>
</div>
</div>
<div class="ai-panel-input">
<input type="text" class="ai-input" placeholder="Digite suas modificações..." id="ai-input">
<button class="ai-send-btn" onclick="sendAIMessage()">
<span></span>
</button>
</div>
</aside>
</main>
</div>
<script src="/suite/base-layout.js"></script>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,19 @@
<div class="h-full flex flex-col bg-white overflow-hidden text-gray-800">
<div class="h-10 bg-gray-100 border-b border-gray-200 flex items-center px-4 space-x-2">
<button class="text-gray-400 hover:text-gray-600"><i class="fa-solid fa-arrow-left"></i></button>
<button class="text-gray-400 hover:text-gray-600"><i class="fa-solid fa-arrow-right"></i></button>
<button class="text-gray-400 hover:text-gray-600"><i class="fa-solid fa-rotate-right"></i></button>
<div class="flex-1 bg-white border border-gray-300 rounded px-3 py-1 flex items-center shadow-inner">
<i class="fa-solid fa-lock text-green-600 text-xs mr-2"></i>
<input type="text" class="flex-1 outline-none text-sm" value="https://generalbots.com" readonly>
</div>
<button class="text-gray-400 hover:text-gray-600"><i class="fa-solid fa-bars"></i></button>
</div>
<div class="flex-1 flex items-center justify-center bg-[#fafdfa]">
<div class="text-center text-gray-400">
<i class="fa-regular fa-compass text-5xl mb-4 text-brand-300"></i>
<h2 class="text-xl font-medium text-gray-600">Browser</h2>
<p class="mt-2 text-sm">Internet access starting soon...</p>
</div>
</div>
</div>

View file

@ -1,4 +1,4 @@
<link rel="stylesheet" href="calendar/calendar.css" />
<link rel="stylesheet" href="/suite/calendar/calendar.css" />
<!-- Calendar - Event Management -->
<div class="calendar-container" id="calendar-app">

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,18 @@
<link rel="stylesheet" href="chat/chat.css" />
<link rel="stylesheet" href="/suite/chat/chat.css?v=9" />
<link rel="stylesheet" href="/suite/css/markdown-message.css" />
<script src="/suite/js/vendor/marked.min.js"></script>
<div class="chat-layout" id="chat-app">
<!-- Connection Status -->
<div
class="connection-status connecting"
id="connectionStatus"
style="display: none"
>
<span class="connection-status-dot"></span>
<span class="connection-text">Connecting...</span>
</div>
<main id="messages"></main>
<footer>
@ -23,14 +35,6 @@
autofocus
autocomplete="off"
/>
<button
type="button"
id="voiceBtn"
title="Voice"
data-i18n-title="chat-voice"
>
🎤
</button>
<button
type="submit"
id="sendBtn"
@ -41,7 +45,24 @@
</button>
</form>
</footer>
<button class="scroll-to-bottom" id="scrollToBottom"></button>
<button
class="scroll-to-bottom"
id="scrollToBottom"
title="Scroll to bottom"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
</div>
<div class="entity-card-tooltip" id="entityCardTooltip">
@ -81,7 +102,7 @@
var WS_BASE_URL =
window.location.protocol === "https:" ? "wss://" : "ws://";
var WS_URL = WS_BASE_URL + window.location.host;
var WS_URL = WS_BASE_URL + window.location.host + "/ws";
var MessageType = {
EXTERNAL: 0,
@ -148,11 +169,14 @@
var currentSessionId = null;
var currentUserId = null;
var currentBotId = "default";
var currentBotName = "default";
var isStreaming = false;
var streamingMessageId = null;
var currentStreamingContent = "";
var reconnectAttempts = 0;
var maxReconnectAttempts = 5;
var disconnectNotified = false;
var isUserScrolling = false;
var mentionState = {
active: false,
@ -168,6 +192,63 @@
return div.innerHTML;
}
// Scroll handling
function scrollToBottom(animate) {
var messages = document.getElementById("messages");
if (messages) {
if (animate) {
messages.scrollTo({
top: messages.scrollHeight,
behavior: "smooth",
});
} else {
messages.scrollTop = messages.scrollHeight;
}
}
}
function updateScrollButton() {
var messages = document.getElementById("messages");
var scrollBtn = document.getElementById("scrollToBottom");
if (!messages || !scrollBtn) return;
var isNearBottom =
messages.scrollHeight -
messages.scrollTop -
messages.clientHeight <
100;
if (isNearBottom) {
scrollBtn.classList.remove("visible");
} else {
scrollBtn.classList.add("visible");
}
}
// Scroll-to-bottom button click
var scrollBtn = document.getElementById("scrollToBottom");
if (scrollBtn) {
scrollBtn.addEventListener("click", function () {
scrollToBottom(true);
isUserScrolling = false;
});
}
// Detect user scrolling
var messagesEl = document.getElementById("messages");
if (messagesEl) {
messagesEl.addEventListener("scroll", function () {
isUserScrolling = true;
updateScrollButton();
// Reset isUserScrolling after 2 seconds of no scrolling
clearTimeout(messagesEl.scrollTimeout);
messagesEl.scrollTimeout = setTimeout(function () {
isUserScrolling = false;
}, 2000);
});
}
function renderMentionInMessage(content) {
return content.replace(
/@(\w+):([^\s]+)/g,
@ -225,7 +306,13 @@
}
messages.appendChild(div);
messages.scrollTop = messages.scrollHeight;
// Auto-scroll to bottom unless user is manually scrolling
if (!isUserScrolling) {
scrollToBottom(true);
} else {
updateScrollButton();
}
setupMentionClickHandlers(div);
}
@ -670,9 +757,20 @@
if (isStreaming) {
finalizeStreaming();
} else {
addMessage("bot", data.content);
if (data.content && data.content.trim() !== "") {
addMessage("bot", data.content);
}
}
isStreaming = false;
// Render suggestions when message is complete
if (
data.suggestions &&
Array.isArray(data.suggestions) &&
data.suggestions.length > 0
) {
renderSuggestions(data.suggestions);
}
} else {
if (!isStreaming) {
isStreaming = true;
@ -690,22 +788,103 @@
}
}
function sendMessage() {
// Render suggestion buttons
function renderSuggestions(suggestions) {
var suggestionsEl = document.getElementById("suggestions");
if (!suggestionsEl) {
console.warn("Suggestions container not found");
return;
}
// Get the footer element
var footer = suggestionsEl.closest("footer");
// Clear existing suggestions
suggestionsEl.innerHTML = "";
console.log("Rendering " + suggestions.length + " suggestions");
// Add or remove CSS class based on whether suggestions are displayed
if (footer) {
if (suggestions.length > 0) {
footer.classList.add("has-suggestions");
} else {
footer.classList.remove("has-suggestions");
}
}
suggestions.forEach(function (suggestion) {
var chip = document.createElement("button");
chip.className = "suggestion-chip";
chip.textContent = suggestion.text || "Suggestion";
// Use window.sendMessage which is already exposed
chip.onclick = (function (sugg) {
return function () {
console.log("Suggestion clicked:", sugg);
// Check if there's an action to parse
if (sugg.action) {
try {
var action =
typeof sugg.action === "string"
? JSON.parse(sugg.action)
: sugg.action;
console.log("Parsed action:", action);
if (action.type === "invoke_tool") {
// Send the display text so it shows correctly in chat
// The backend will recognize this as a tool request
window.sendMessage(sugg.text);
} else if (action.type === "send_message") {
window.sendMessage(
action.message || sugg.text,
);
} else if (action.type === "select_context") {
window.sendMessage(action.context);
} else {
window.sendMessage(sugg.text);
}
} catch (e) {
console.error(
"Failed to parse action:",
e,
"falling back to text",
);
window.sendMessage(sugg.text);
}
} else {
// No action, just send the text
window.sendMessage(sugg.text);
}
};
})(suggestion);
suggestionsEl.appendChild(chip);
});
}
function sendMessage(messageContent) {
var input = document.getElementById("messageInput");
if (!input) {
console.error("Chat input not found");
return;
}
var content = input.value.trim();
// If no messageContent provided, read from input
var content = messageContent || input.value.trim();
if (!content) {
return;
}
hideMentionDropdown();
// If called from input field (no messageContent provided), clear input
if (!messageContent) {
hideMentionDropdown();
input.value = "";
input.focus();
}
addMessage("user", content);
input.value = "";
input.focus();
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(
@ -726,51 +905,340 @@
window.sendMessage = sendMessage;
// Expose session info for suggestion clicks
window.getChatSessionInfo = function () {
return {
ws: ws,
currentBotId: currentBotId,
currentUserId: currentUserId,
currentSessionId: currentSessionId,
currentBotName: currentBotName,
};
};
function connectWebSocket() {
if (ws) {
ws.close();
}
updateConnectionStatus("connecting");
var url =
WS_URL +
"/ws?session_id=" +
"?session_id=" +
currentSessionId +
"&user_id=" +
currentUserId;
currentUserId +
"&bot_name=" +
currentBotName;
console.log("Connecting WebSocket to:", url);
ws = new WebSocket(url);
// Add connection timeout to detect silent failures
var connectionTimeout = setTimeout(function () {
if (ws.readyState !== WebSocket.OPEN) {
console.error("WebSocket connection timeout");
ws.close();
}
}, 5000);
ws.onopen = function () {
console.log("WebSocket connected");
reconnectAttempts = 0;
clearTimeout(connectionTimeout);
console.log("WebSocket connected to:", url);
disconnectNotified = false;
updateConnectionStatus("connected");
};
ws.onmessage = function (event) {
try {
var data = JSON.parse(event.data);
if (data.type === "connected") return;
console.log("Chat WebSocket received:", data);
// Ignore connection confirmation
if (data.type === "connected") {
reconnectAttempts = 0;
return;
}
// Process system events (theme changes, etc)
if (data.event) {
if (data.event === "change_theme") {
applyThemeData(data.data || {});
}
return;
}
// Check if content contains theme change events (JSON strings)
if (data.content && typeof data.content === "string") {
try {
var contentObj = JSON.parse(data.content);
if (contentObj.event === "change_theme") {
applyThemeData(contentObj.data || {});
return;
}
} catch (e) {
// Content is not JSON, continue processing
}
}
// Only process bot responses
if (data.message_type === MessageType.BOT_RESPONSE) {
console.log("Processing bot response:", data);
processMessage(data);
} else {
console.log("Ignoring non-bot message:", data);
}
} catch (e) {
console.error("WS message error:", e);
}
};
ws.onclose = function () {
notify("Disconnected from chat server", "error");
ws.onclose = function (event) {
clearTimeout(connectionTimeout);
console.log("WebSocket closed:", event.code, event.reason);
updateConnectionStatus("disconnected");
if (!disconnectNotified) {
notify("Disconnected from chat server", "error");
disconnectNotified = true;
}
if (reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++;
updateConnectionStatus("connecting");
setTimeout(connectWebSocket, 1000 * reconnectAttempts);
} else {
console.error(
"Max reconnection attempts reached. Stopping reconnection.",
);
notify(
"Could not reconnect to chat server after multiple attempts",
"error",
);
}
};
ws.onerror = function (e) {
console.error("WebSocket error:", e);
updateConnectionStatus("disconnected");
};
}
// Apply theme data from WebSocket events
function getContrastYIQ(hexcolor) {
if (!hexcolor) return "#ffffff";
// Handle named colors and variables by letting the browser resolve them
var temp = document.createElement("div");
temp.style.color = hexcolor;
temp.style.display = "none";
document.body.appendChild(temp);
var style = window.getComputedStyle(temp).color;
document.body.removeChild(temp);
var rgb = style.match(/\d+/g);
if (!rgb || rgb.length < 3) return "#ffffff";
var r = parseInt(rgb[0]);
var g = parseInt(rgb[1]);
var b = parseInt(rgb[2]);
var yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq >= 128 ? "#000000" : "#ffffff";
}
function applyThemeData(themeData) {
console.log("Applying theme data:", themeData);
var color1 = themeData.color1 || themeData.data?.color1 || "black";
var color2 = themeData.color2 || themeData.data?.color2 || "white";
var logo = themeData.logo_url || themeData.data?.logo_url || "";
var title =
themeData.title ||
themeData.data?.title ||
window.__INITIAL_BOT_NAME__ ||
"Chat";
// Set CSS variables for colors on document element
document.documentElement.style.setProperty("--chat-color1", color1);
document.documentElement.style.setProperty("--chat-color2", color2);
document.documentElement.style.setProperty(
"--suggestion-color",
color1,
);
document.documentElement.style.setProperty(
"--suggestion-bg",
color2,
);
// Also set on root for better cascading
document.documentElement.style.setProperty("--color1", color1);
document.documentElement.style.setProperty("--color2", color2);
// Update suggestion button colors to match theme
document.documentElement.style.setProperty("--primary", color1);
document.documentElement.style.setProperty("--accent", color1);
document.documentElement.style.setProperty(
"--chat-fg1",
getContrastYIQ(color1),
);
document.documentElement.style.setProperty(
"--chat-fg2",
getContrastYIQ(color2),
);
console.log("Theme applied:", {
color1: color1,
color2: color2,
logo: logo,
title: title,
});
}
// Load bot config and apply colors/logo
function loadBotConfig() {
var botName = window.__INITIAL_BOT_NAME__ || "default";
fetch("/api/bot/config?bot_name=" + encodeURIComponent(botName))
.then(function (response) {
return response.json();
})
.then(function (config) {
if (!config) return;
// Get the theme manager's theme for this bot to check if user selected a different theme
var botId = botName.toLowerCase();
var botThemeKey = "gb-theme-" + botId;
var botTheme = window.ThemeManager
? // Get bot-specific theme from theme manager's mapping
(window.ThemeManager.getAvailableThemes &&
window.ThemeManager.getAvailableThemes().find(
(t) => t.id === botId,
)) ||
// Fallback to localStorage
localStorage.getItem(botThemeKey)
: localStorage.getItem(botThemeKey);
// Check if bot config has a theme-base setting
var configThemeBase =
config.theme_base || config["theme-base"] || "light";
// Only use bot config colors if:
// 1. No theme has been explicitly selected by user (localStorage empty or default)
// 2. AND the bot config's theme-base matches the current theme
var localStorageTheme = localStorage.getItem(botThemeKey);
var useBotConfigColors =
!localStorageTheme ||
localStorageTheme === "default" ||
localStorageTheme === configThemeBase;
// Apply colors from config (API returns snake_case)
var color1 =
config.theme_color1 ||
config["theme-color1"] ||
config["Theme Color"] ||
"#3b82f6";
var color2 =
config.theme_color2 ||
config["theme-color2"] ||
"#f5deb3";
var title =
config.theme_title || config["theme-title"] || botName;
var logo = config.theme_logo || config["theme-logo"] || "";
// Only set bot config colors if user hasn't selected a different theme
if (useBotConfigColors) {
document.documentElement.setAttribute(
"data-has-bot-colors",
"true",
);
document.documentElement.style.setProperty(
"--chat-color1",
color1,
);
document.documentElement.style.setProperty(
"--chat-color2",
color2,
);
document.documentElement.style.setProperty(
"--suggestion-color",
color1,
);
document.documentElement.style.setProperty(
"--suggestion-bg",
color2,
);
document.documentElement.style.setProperty(
"--color1",
color1,
);
document.documentElement.style.setProperty(
"--color2",
color2,
);
document.documentElement.style.setProperty(
"--primary",
color1,
);
document.documentElement.style.setProperty(
"--accent",
color1,
);
document.documentElement.style.setProperty(
"--chat-fg1",
getContrastYIQ(color1),
);
document.documentElement.style.setProperty(
"--chat-fg2",
getContrastYIQ(color2),
);
console.log("Bot config colors applied:", {
color1: color1,
color2: color2,
});
} else {
console.log(
"Bot config colors skipped - user selected custom theme:",
localStorageTheme,
);
}
// Update logo if provided
if (logo) {
var logoImg = document.querySelector(".logo-icon-img");
if (logoImg) {
logoImg.src = logo;
logoImg.alt = title || botName;
logoImg.style.display = "block";
}
// Hide the SVG logo when image logo is used
var logoSvg = document.querySelector(".logo-icon-svg");
if (logoSvg) {
logoSvg.style.display = "none";
}
}
console.log("Bot config loaded:", {
color1: color1,
color2: color2,
title: title,
logo: logo,
});
})
.catch(function (e) {
console.log("Could not load bot config:", e);
});
}
function initChat() {
var botName = "default";
// Load bot config first
loadBotConfig();
// Just proceed with chat initialization - no auth check
proceedWithChatInit();
}
function proceedWithChatInit() {
var botName = window.__INITIAL_BOT_NAME__ || "default";
fetch("/api/auth?bot_name=" + encodeURIComponent(botName))
.then(function (response) {
return response.json();
@ -779,20 +1247,61 @@
currentUserId = auth.user_id;
currentSessionId = auth.session_id;
currentBotId = auth.bot_id || "default";
currentBotName = botName;
console.log("Auth:", {
currentUserId: currentUserId,
currentSessionId: currentSessionId,
currentBotId: currentBotId,
currentBotName: currentBotName,
});
connectWebSocket();
})
.catch(function (e) {
console.error("Auth failed:", e);
notify("Failed to connect to chat server", "error");
setTimeout(initChat, 3000);
// Proceed with anonymous connection - WebSocket handler supports it
currentUserId = crypto.randomUUID
? crypto.randomUUID()
: Date.now().toString();
currentSessionId = crypto.randomUUID
? crypto.randomUUID()
: Date.now().toString();
currentBotId = botName;
currentBotName = botName;
console.log("Anonymous chat:", {
currentUserId: currentUserId,
currentSessionId: currentSessionId,
currentBotId: currentBotId,
currentBotName: currentBotName,
});
connectWebSocket();
});
}
function updateConnectionStatus(status) {
var statusEl = document.getElementById("connectionStatus");
if (!statusEl) return;
statusEl.className = "connection-status " + status;
var statusText = statusEl.querySelector(".connection-text");
if (statusText) {
switch (status) {
case "connected":
statusText.textContent = "Connected";
statusEl.style.display = "none";
break;
case "disconnected":
statusText.textContent = "Disconnected";
statusEl.style.display = "flex";
break;
case "connecting":
statusText.textContent = "Connecting...";
statusEl.style.display = "flex";
break;
}
}
}
function setupEventHandlers() {
var form = document.getElementById("chatForm");
var input = document.getElementById("messageInput");

File diff suppressed because it is too large Load diff

View file

@ -1085,9 +1085,27 @@ body {
.logo-icon {
width: 32px;
height: 20px;
height: 32px;
color: var(--text, var(--text-primary, #ffffff));
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
/* Theme logo image - when src is set, show as image */
.logo-icon.logo-icon-img[src:not=""]] {
display: block;
width: auto;
height: 40px;
object-fit: contain;
filter: none;
}
/* Hide SVG when logo image is shown */
.logo-icon.logo-icon-svg[style*="display: none"],
.logo-icon.logo-icon-svg.hidden {
display: none !important;
}
.logo-text {

View file

@ -472,14 +472,15 @@ body.no-animations .spinner {
}
.logo-icon {
width: 32px;
height: 32px;
width: 40px;
height: 40px;
background: linear-gradient(135deg, var(--primary), #8b5cf6);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
flex-shrink: 0;
}
/* ============================================ */

View file

@ -0,0 +1,604 @@
/* Chat Agent Mode — Z.ai toggle + OpenClaw multi-panel layout */
/* ============================================
AGENT / CHAT MODE TOGGLE (Z.ai style)
============================================ */
.chat-mode-toggle {
display: flex;
align-items: center;
gap: 2px;
background: var(--surface, #1a1a24);
border: 1px solid var(--border, #2a2a2a);
border-radius: 20px;
padding: 2px;
margin-right: 8px;
}
.chat-mode-btn {
padding: 5px 14px;
border: none;
border-radius: 18px;
font-family: 'Fira Code', monospace;
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
background: transparent;
color: var(--text-secondary, var(--text-muted));
letter-spacing: 0.3px;
}
.chat-mode-btn.active {
background: var(--accent);
color: var(--bg);
box-shadow: 0 2px 8px rgba(132, 214, 105, 0.3);
}
.chat-mode-btn:not(.active):hover {
color: var(--text, var(--bg));
background: var(--hover, rgba(255, 255, 255, 0.05));
}
/* ============================================
QUICK ACTION CHIPS (Z.ai style)
============================================ */
.quick-actions-container {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 12px;
justify-content: center;
animation: quickActionsIn 0.4s ease;
}
@keyframes quickActionsIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
.quick-action-chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
border: 1px solid var(--border, #2a2a2a);
border-radius: 24px;
background: var(--surface, #1a1a24);
color: var(--text, var(--bg));
font-family: 'Fira Code', monospace;
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
white-space: nowrap;
}
.quick-action-chip:hover {
border-color: var(--accent);
background: rgba(132, 214, 105, 0.08);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(132, 214, 105, 0.15);
}
.quick-action-chip:active {
transform: translateY(0);
}
.quick-action-icon {
font-size: 14px;
}
/* ============================================
AGENT MODE MULTI-PANEL LAYOUT
============================================ */
.chat-layout.agent-mode {
max-width: none;
padding: 0;
display: grid;
grid-template-columns: 48px 1fr 1fr;
grid-template-rows: 1fr auto auto;
gap: 0;
}
/* Agent Mode Left Sidebar */
.agent-sidebar {
display: none;
grid-row: 1 / -1;
grid-column: 1;
background: var(--surface);
border-right: 1px solid var(--border);
flex-direction: column;
z-index: 50;
}
.agent-mode .agent-sidebar {
display: flex;
}
.agent-sidebar-item {
width: 48px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
position: relative;
border-bottom: 1px solid var(--border);
background: transparent;
border-left: none;
border-right: none;
border-top: none;
color: var(--text-muted);
}
.agent-sidebar-item:hover {
background: var(--bg);
color: var(--text);
}
.agent-sidebar-item.active {
background: var(--bg);
border-left: 3px solid var(--accent);
color: var(--text);
}
.agent-sidebar-badge {
position: absolute;
top: 4px;
right: 4px;
min-width: 16px;
height: 16px;
padding: 0 4px;
border-radius: 8px;
background: var(--accent);
color: var(--bg);
font-size: 9px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Fira Code', monospace;
}
/* Chat Panel (in agent mode) */
.agent-mode #messages {
padding: 16px;
}
.agent-mode footer {
grid-column: 2 / -1;
padding: 8px 16px;
border-top: 1px solid var(--border);
}
/* ============================================
THOUGHT PROCESS BLOCK
============================================ */
.thought-process {
margin: 12px 0;
border: 1px solid var(--border, var(--border));
border-radius: 8px;
overflow: hidden;
background: var(--surface, #f8f9fa);
}
.thought-process-header {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 14px;
cursor: pointer;
font-family: 'Fira Code', monospace;
font-size: 12px;
font-weight: 600;
color: var(--text, var(--text));
background: var(--surface, var(--border));
transition: background 0.15s;
border: none;
width: 100%;
text-align: left;
}
.thought-process-header:hover {
background: var(--hover, #e8e9ea);
}
.thought-process-toggle {
transition: transform 0.2s;
font-size: 10px;
}
.thought-process.expanded .thought-process-toggle {
transform: rotate(90deg);
}
.thought-process-body {
display: none;
padding: 12px 14px;
font-size: 13px;
line-height: 1.6;
color: var(--text-secondary, var(--text-muted));
border-top: 1px solid var(--border, var(--border));
}
.thought-process.expanded .thought-process-body {
display: block;
}
/* ============================================
BROWSER PANEL
============================================ */
.agent-browser-panel {
display: none;
grid-column: 3;
grid-row: 1;
border-left: 1px solid var(--border);
flex-direction: column;
background: var(--bg);
}
.agent-mode .agent-browser-panel {
display: flex;
}
.browser-panel-header {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: var(--surface);
border-bottom: 1px solid var(--border);
font-family: 'Fira Code', monospace;
font-size: 12px;
font-weight: 600;
color: var(--text);
}
.browser-url-bar {
flex: 1;
padding: 4px 10px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 4px;
font-family: 'Fira Code', monospace;
font-size: 11px;
color: var(--text-muted);
}
.browser-panel-content {
flex: 1;
background: var(--bg);
}
.browser-panel-content iframe {
width: 100%;
height: 100%;
border: none;
}
.browser-panel-empty {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: var(--text-muted);
font-family: 'Fira Code', monospace;
font-size: 13px;
}
/* ============================================
TERMINAL PANEL
============================================ */
.agent-terminal-panel {
display: none;
grid-column: 2;
grid-row: 2;
border-top: 1px solid var(--border);
flex-direction: column;
max-height: 200px;
min-height: 120px;
}
.agent-mode .agent-terminal-panel {
display: flex;
}
.terminal-panel-header {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
background: #1e1e1e;
border-bottom: 1px solid #333;
font-family: 'Fira Code', monospace;
font-size: 11px;
font-weight: 600;
color: var(--accent);
}
.terminal-panel-content {
flex: 1;
overflow-y: auto;
background: #1e1e1e;
padding: 8px 12px;
font-family: 'Fira Code', monospace;
font-size: 12px;
line-height: 1.5;
color: #d4d4d4;
}
.terminal-line {
white-space: pre-wrap;
word-break: break-all;
}
.terminal-line.stderr {
color: #f87171;
}
.terminal-line.stdout {
color: #d4d4d4;
}
/* ============================================
AGENT INFO CARD
============================================ */
.agent-info-card {
display: none;
grid-column: 3;
grid-row: 2;
border-top: 1px solid var(--border);
border-left: 1px solid var(--border);
padding: 12px 16px;
background: var(--surface);
flex-direction: column;
gap: 8px;
}
.agent-mode .agent-info-card {
display: flex;
}
.agent-info-name {
display: flex;
align-items: center;
gap: 8px;
font-family: 'Fira Code', monospace;
font-size: 13px;
font-weight: 600;
color: var(--text);
}
.agent-info-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--accent);
}
.agent-level-badge {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-family: 'Fira Code', monospace;
font-size: 10px;
font-weight: 700;
letter-spacing: 0.5px;
text-transform: uppercase;
}
.badge-evolved {
background: var(--accent);
color: var(--bg);
}
.badge-bred {
background: #f59e0b;
color: var(--bg);
}
.badge-wild {
background: #ef4444;
color: var(--bg);
}
.agent-info-model {
font-family: 'Fira Code', monospace;
font-size: 11px;
color: var(--text-muted);
}
.agent-info-toggles {
display: flex;
gap: 8px;
align-items: center;
}
.agent-toggle {
display: flex;
align-items: center;
gap: 4px;
font-family: 'Fira Code', monospace;
font-size: 11px;
color: var(--text-muted);
}
.agent-toggle-switch {
width: 28px;
height: 16px;
border-radius: 8px;
background: #ccc;
position: relative;
cursor: pointer;
transition: background 0.2s;
border: none;
padding: 0;
}
.agent-toggle-switch.on {
background: var(--accent);
}
.agent-toggle-switch::after {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--bg);
transition: transform 0.2s;
}
.agent-toggle-switch.on::after {
transform: translateX(12px);
}
/* ============================================
STEP COUNTER BAR
============================================ */
.agent-step-bar {
display: none;
grid-column: 1 / -1;
grid-row: 3;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
background: var(--surface);
border-top: 1px solid var(--border);
}
.agent-mode .agent-step-bar {
display: flex;
}
.step-counter {
display: flex;
align-items: center;
gap: 12px;
font-family: 'Fira Code', monospace;
font-size: 13px;
color: var(--text);
}
.step-nav-btn {
width: 28px;
height: 28px;
border-radius: 50%;
border: 1px solid var(--border);
background: var(--bg);
color: var(--text-muted);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s;
font-size: 14px;
padding: 0;
}
.step-nav-btn:hover {
border-color: var(--accent);
color: var(--accent);
}
.step-action-btns {
display: flex;
gap: 6px;
}
.step-action-btn {
width: 36px;
height: 36px;
border-radius: 50%;
border: none;
background: var(--accent);
color: var(--bg);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s;
font-size: 16px;
padding: 0;
}
.step-action-btn:hover {
transform: scale(1.1);
box-shadow: 0 2px 8px rgba(132, 214, 105, 0.3);
}
/* ============================================
TODO LIST (OpenClaw style)
============================================ */
.agent-todo-list {
margin: 12px 0;
border: 1px solid var(--border, var(--border));
border-radius: 8px;
overflow: hidden;
}
.agent-todo-header {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 14px;
background: var(--surface, var(--border));
font-family: 'Fira Code', monospace;
font-size: 12px;
font-weight: 600;
color: var(--text, var(--text));
}
.agent-todo-count {
background: var(--accent);
color: var(--bg);
padding: 1px 6px;
border-radius: 10px;
font-size: 10px;
}
.agent-todo-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 14px;
border-top: 1px solid var(--border, var(--border));
font-size: 13px;
color: var(--text, var(--text));
transition: opacity 0.2s;
}
.agent-todo-item.done {
opacity: 0.5;
text-decoration: line-through;
}
.agent-todo-check {
width: 16px;
height: 16px;
border-radius: 50%;
border: 2px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.agent-todo-item.done .agent-todo-check {
background: var(--accent);
border-color: var(--accent);
color: var(--bg);
font-size: 10px;
}

View file

@ -0,0 +1,16 @@
/* Config Color Overrides */
/* Maps theme-color1 and theme-color2 from config.csv to actual theme variables */
:root {
/* Use --color1 and --color2 from config.csv, with fallback defaults */
--sentient-accent: var(--color1, #3b82f6);
--primary: var(--color1, #3b82f6);
--primary-hover: color-mix(in srgb, var(--color1, #3b82f6) 85%, black);
--primary-light: color-mix(in srgb, var(--color1, #3b82f6) 10%, transparent);
--chart-1: var(--color1, #3b82f6);
--chart-2: var(--color2, #f59e0b);
--ring: var(--color1, #3b82f6);
/* Background can use color2 for subtle tint */
/* --sentient-bg-primary stays white/light for text readability */
}

295
ui/suite/css/desktop.css Normal file
View file

@ -0,0 +1,295 @@
.app-icon {
background: var(--surface-hover, #ffffff);
border: 1px solid var(--border, #e5e7eb);
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.05);
/* removed border */
/* removed border bottom */
}
.workspace-bg {
background-color: var(--bg, #fafdfa);
}
.workspace-grid {
background-image:
linear-gradient(to right, var(--border, #f0fdf4) 1px, transparent 1px),
linear-gradient(to bottom, var(--border, #f0fdf4) 1px, transparent 1px);
background-size: 40px 40px;
}
/* Custom scrollbar for terminal */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--surface-active, #333);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--border-hover, #555);
}
/* Window Manager Core Styles (replacing missing Tailwind classes) */
.window-element {
position: absolute;
width: 700px;
height: 500px;
background-color: var(--surface, white);
border-radius: 8px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
display: flex;
flex-direction: column;
border: 1px solid var(--border, #e5e7eb);
overflow: hidden;
z-index: 100;
}
.window-header {
height: 40px;
background-color: var(--surface, #ffffff);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
border-bottom: 1px solid var(--border, #e5e7eb);
user-select: none;
cursor: move;
position: relative;
z-index: 10;
}
.window-header .font-mono {
font-family: "Fira Code", monospace;
font-size: 12px;
font-weight: 700;
color: var(--accent, #16a34a); /* brand-600 */
letter-spacing: 0.025em;
}
.window-header-controls {
display: flex;
gap: 12px;
color: var(--text-muted, #9ca3af);
}
.window-header button {
background: none;
border: none;
cursor: pointer;
color: inherit;
font-size: 14px;
}
.window-header .btn-minimize:hover,
.window-header .btn-maximize:hover {
color: var(--text, #4b5563);
}
.window-header .btn-close:hover {
color: var(--error, #ef4444);
}
.window-body {
position: relative;
flex: 1 1 0%;
overflow-y: auto;
background-color: var(--bg, #fafdfa);
padding: 16px;
}
.w-\[700px\] {
width: 700px;
}
.h-\[500px\] {
height: 500px;
}
.bg-white {
background-color: #fff;
}
.rounded-lg {
border-radius: 0.5rem;
}
.shadow-2xl {
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
.flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.border {
border-width: 1px;
border-style: solid;
}
.border-gray-200 {
border-color: #e5e7eb;
}
.overflow-hidden {
overflow: hidden;
}
.absolute {
position: absolute;
}
.h-10 {
height: 2.5rem;
}
.bg-white\/95 {
background-color: var(--surface, rgba(255, 255, 255, 0.95));
}
.backdrop-blur {
backdrop-filter: blur(8px);
}
.items-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.border-b {
border-bottom-width: 1px;
}
.select-none {
user-select: none;
}
.cursor-move {
cursor: move;
}
.font-mono {
font-family:
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
"Liberation Mono", "Courier New", monospace;
}
.text-xs {
font-size: 0.75rem;
line-height: 1rem;
}
.font-bold {
font-weight: 700;
}
.text-brand-600 {
color: var(--accent, #84d669);
}
.tracking-wide {
letter-spacing: 0.025em;
}
.space-x-3 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.75rem * var(--tw-space-x-reverse));
margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse)));
}
.text-gray-400 {
color: var(--text-muted, #9ca3af);
}
.hover\:text-gray-600:hover {
color: var(--text, #4b5563);
}
.hover\:text-red-500:hover {
color: var(--error, #ef4444);
}
.relative {
position: relative;
}
.flex-1 {
flex: 1 1 0%;
}
.overflow-y-auto {
overflow-y: auto;
}
.bg-\[\#fafdfa\] {
background-color: var(--bg, #fafdfa);
}
.window-header {
height: 40px;
background-color: var(--surface, #ffffff);
border-bottom: 1px solid var(--border, #e5e7eb);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
user-select: none;
cursor: move;
position: relative;
z-index: 10;
}
.window-header .font-mono {
font-family: "Fira Code", monospace;
font-size: 12px;
font-weight: 700;
color: var(--accent, #16a34a);
letter-spacing: 0.025em;
}
.window-header .flex {
display: flex;
gap: 12px;
color: var(--text-muted, #9ca3af);
}
.window-header button {
background: transparent;
border: none;
cursor: pointer;
transition: color 0.15s ease;
}
.window-header button:hover {
color: var(--text, #4b5563);
}
.window-header .btn-close:hover {
color: var(--error, #ef4444);
}
.window-content {
flex: 1;
overflow-y: auto;
position: relative;
background-color: var(--bg, #ffffff);
}
/* Hide background content when window is maximized */
body.window-maximized .sidebar,
body.window-maximized .toolbar,
body.window-maximized .sidebar-item,
body.window-maximized .desktop-icon,
body.window-maximized .panel-grid,
body.window-maximized .workspace-grid,
body.window-maximized .bg-grid,
body.window-maximized .bg-svg {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
}
/* Ensure maximized window fills the screen without minibar offset */
body.window-maximized .window-element {
z-index: 9998 !important; /* Lower than minibar's 9999 */
top: 0 !important; /* No minibar offset - start at top */
height: 100vh !important; /* Fill entire screen height */
width: 100vw !important; /* Fill entire screen width */
}
/* Ensure window body is opaque */
.window-body {
background-color: var(--bg, #fafdfa) !important;
opacity: 1 !important;
}
/* Ensure window element is fully opaque */
.window-element {
background-color: var(--surface, #ffffff) !important;
opacity: 1 !important;
}
/* Fix theme dropdown background - use surface color to adapt to theme */
/* This overrides hardcoded black background from other CSS files */
#themeDropdown,
select.theme-dropdown {
background: var(--surface) !important;
}

View file

@ -395,3 +395,155 @@
-webkit-line-clamp: 3;
}
}
/* ============================================ */
/* MARKDOWN MESSAGE STYLING */
/* ============================================ */
/* Lists in message content */
.message-content ul,
.message-content ol {
margin: 12px 0;
padding-left: 24px;
}
/* List items with proper spacing from border */
.message-content li {
margin: 8px 0;
line-height: 1.7;
}
/* Nested lists */
.message-content ul ul,
.message-content ol ol,
.message-content ul ol,
.message-content ol ul {
margin: 8px 0;
}
/* Bullet points */
.message-content ul li {
list-style-type: disc;
padding-left: 8px;
}
.message-content ul li::marker {
color: var(--chat-color1, var(--accent, var(--primary, #3b82f6)));
}
/* Nested bullets */
.message-content ul ul li {
list-style-type: circle;
}
.message-content ul ul ul li {
list-style-type: square;
}
/* Numbered lists */
.message-content ol li {
list-style-type: decimal;
}
/* Nested numbered lists */
.message-content ol ol li {
list-style-type: lower-alpha;
}
.message-content ol ol ol li {
list-style-type: lower-roman;
}
/* Lists in user messages */
.message.user .message-content ul li::marker,
.message.user .message-content ol li::marker {
color: rgba(255, 255, 255, 0.9);
}
/* Lists in bot messages */
.message.bot .message-content ul li::marker,
.message.bot .message-content ol li::marker {
color: var(--chat-color1, var(--accent, var(--primary, #3b82f6)));
}
/* Paragraphs in messages */
.message-content p {
margin: 8px 0;
line-height: 1.7;
}
/* First and last paragraph spacing */
.message-content p:first-child {
margin-top: 0;
}
.message-content p:last-child {
margin-bottom: 0;
}
/* Headings in messages */
.message-content h1,
.message-content h2,
.message-content h3,
.message-content h4,
.message-content h5,
.message-content h6 {
margin: 16px 0 8px 0;
font-weight: 600;
line-height: 1.3;
}
.message-content h1 { font-size: 1.5em; }
.message-content h2 { font-size: 1.3em; }
.message-content h3 { font-size: 1.15em; }
.message-content h4 { font-size: 1.05em; }
/* Code blocks */
.message-content pre {
margin: 12px 0;
padding: 12px;
background: rgba(0, 0, 0, 0.2);
border-radius: 8px;
overflow-x: auto;
font-size: 13px;
line-height: 1.5;
}
/* Inline code */
.message-content code {
padding: 2px 6px;
background: rgba(0, 0, 0, 0.15);
border-radius: 4px;
font-size: 0.9em;
}
.message.user .message-content code {
background: rgba(255, 255, 255, 0.2);
}
/* Blockquotes */
.message-content blockquote {
margin: 12px 0;
padding-left: 16px;
border-left: 3px solid var(--chat-color1, var(--accent, var(--primary, #3b82f6)));
font-style: italic;
}
/* Horizontal rules */
.message-content hr {
margin: 16px 0;
border: none;
border-top: 1px solid rgba(128, 128, 128, 0.3);
}
/* Links in messages */
.message-content a {
color: inherit;
text-decoration: underline;
text-decoration-color: rgba(128, 128, 128, 0.5);
transition: text-decoration-color 0.2s;
}
.message-content a:hover {
text-decoration-color: currentColor;
}

View file

@ -0,0 +1,241 @@
/* Markdown Message Styling - Better lists and spacing for chat messages */
/* Lists in message content */
.message-content ul,
.message-content ol {
margin: 16px 0 !important;
padding-left: 28px !important;
}
/* Extra space between list container edge and bullets */
.message-content ul li,
.message-content ol li {
margin-left: 0px !important;
}
/* List items with better spacing */
.message-content li {
margin: 10px 0;
line-height: 1.8;
position: relative;
padding-left: 6px;
}
/* Nested lists with visual hierarchy */
.message-content ul ul,
.message-content ol ol,
.message-content ul ol,
.message-content ol ul {
margin: 12px 0;
padding-left: 32px;
}
/* Bullet points with better visual weight */
.message-content ul li {
list-style-type: disc;
font-weight: 400;
}
.message-content ul li::marker {
color: var(--chat-color1, var(--accent, var(--primary, #3b82f6)));
font-size: 1.1em;
}
/* Nested bullets with distinct styles */
.message-content ul ul li {
list-style-type: circle;
}
.message-content ul ul li::marker {
font-size: 1em;
opacity: 0.85;
}
.message-content ul ul ul li {
list-style-type: square;
}
.message-content ul ul ul li::marker {
font-size: 0.95em;
opacity: 0.75;
}
/* Numbered lists with better styling */
.message-content ol li {
list-style-type: decimal;
font-weight: 500;
}
.message-content ol li::marker {
color: var(--chat-color1, var(--accent, var(--primary, #3b82f6)));
font-weight: 600;
}
/* Nested numbered lists with visual hierarchy */
.message-content ol ol li {
list-style-type: lower-alpha;
}
.message-content ol ol li::marker {
font-weight: 500;
opacity: 0.9;
}
.message-content ol ol ol li {
list-style-type: lower-roman;
}
.message-content ol ol ol li::marker {
font-weight: 400;
opacity: 0.85;
}
/* Lists in user messages (white text on colored background) */
.message.user .message-content ul li::marker,
.message.user .message-content ol li::marker {
color: rgba(255, 255, 255, 0.95);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.message.user .message-content ul ul li::marker,
.message.user .message-content ol ol li::marker {
color: rgba(255, 255, 255, 0.85);
}
/* Lists in bot messages with better contrast */
.message.bot .message-content ul li::marker,
.message.bot .message-content ol li::marker {
color: var(--chat-color1, var(--accent, var(--primary, #3b82f6)));
}
.message.bot .message-content ul ul li::marker,
.message.bot .message-content ol ol li::marker {
color: var(--chat-color1, var(--accent, var(--primary, #3b82f6)));
opacity: 0.8;
}
/* Paragraphs in messages */
.message-content p {
margin: 10px 0;
line-height: 1.75;
}
/* First and last paragraph spacing */
.message-content p:first-child {
margin-top: 0;
}
.message-content p:last-child {
margin-bottom: 0;
}
/* Lists with better visual separation from paragraphs */
.message-content ul + p,
.message-content ol + p,
.message-content p + ul,
.message-content p + ol {
margin-top: 14px;
}
/* Headings in messages */
.message-content h1,
.message-content h2,
.message-content h3,
.message-content h4,
.message-content h5,
.message-content h6 {
margin: 18px 0 10px 0;
font-weight: 600;
line-height: 1.3;
letter-spacing: -0.01em;
}
.message-content h1 { font-size: 1.5em; }
.message-content h2 { font-size: 1.3em; }
.message-content h3 { font-size: 1.15em; }
.message-content h4 { font-size: 1.05em; }
/* Headings in user messages */
.message.user .message-content h1,
.message.user .message-content h2,
.message.user .message-content h3 {
color: #ffffff;
}
/* Headings in bot messages */
.message.bot .message-content h1,
.message.bot .message-content h2,
.message.bot .message-content h3 {
color: #1a1a1a;
}
/* Code blocks */
.message-content pre {
margin: 12px 0;
padding: 14px;
background: rgba(0, 0, 0, 0.15);
border-radius: 8px;
overflow-x: auto;
font-size: 13px;
line-height: 1.6;
border: 1px solid rgba(0, 0, 0, 0.1);
}
/* Inline code */
.message-content code {
padding: 3px 7px;
background: rgba(0, 0, 0, 0.12);
border-radius: 5px;
font-size: 0.9em;
font-family: "Monaco", "Menlo", "Consolas", monospace;
letter-spacing: 0.02em;
}
.message.user .message-content code {
background: rgba(255, 255, 255, 0.25);
border: 1px solid rgba(255, 255, 255, 0.15);
}
.message.bot .message-content code {
background: rgba(0, 0, 0, 0.08);
border: 1px solid rgba(0, 0, 0, 0.1);
}
/* Blockquotes */
.message-content blockquote {
margin: 12px 0;
padding-left: 16px;
border-left: 3px solid var(--chat-color1, var(--accent, var(--primary, #3b82f6)));
font-style: italic;
}
/* Horizontal rules */
.message-content hr {
margin: 16px 0;
border: none;
border-top: 1px solid rgba(128, 128, 128, 0.3);
}
/* Links in messages */
.message-content a {
color: inherit;
text-decoration: underline;
text-decoration-color: rgba(128, 128, 128, 0.5);
transition: text-decoration-color 0.2s;
}
.message-content a:hover {
text-decoration-color: currentColor;
}
/* Strong/bold text */
.message-content strong,
.message-content b {
font-weight: 600;
}
/* Emphasis/italic text */
.message-content em,
.message-content i {
font-style: italic;
}

View file

@ -876,7 +876,7 @@
[data-theme="sentient"] input,
[data-theme="sentient"] textarea,
[data-theme="sentient"] select {
background: var(--input-bg);
background: var(--surface);
border: 1px solid var(--input-border);
color: var(--text);
border-radius: 8px;
@ -884,6 +884,12 @@
transition: all 0.2s ease;
}
/* Ensure theme dropdown uses surface color in all themes */
[data-theme="sentient"] select.theme-dropdown,
[data-theme="sentient"] #themeDropdown {
background: var(--surface) !important;
}
[data-theme="sentient"] input:focus,
[data-theme="sentient"] textarea:focus,
[data-theme="sentient"] select:focus {

9
ui/suite/css/vendor/all.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -12,6 +12,10 @@
<!-- Styles -->
<link rel="stylesheet" href="css/app.css" />
<!-- Config color overrides -->
<link rel="stylesheet" href="css/config-colors.css" />
<!-- Markdown message styling -->
<link rel="stylesheet" href="css/markdown-message.css" />
<!-- Local Libraries (no external CDN dependencies) -->
<script src="js/vendor/gsap.min.js"></script>
@ -47,10 +51,7 @@
<!-- Right: Theme selector, Apps menu and user avatar -->
<div class="header-right">
<!-- Theme dropdown selector -->
<div
id="themeSelectorContainer"
aria-label="Theme selector"
></div>
<!-- Apps menu button -->
<button
@ -156,34 +157,34 @@
<!-- Application initialization -->
<script>
// Initialize application
(function initApp() {
"use strict";
(function initApp() {
"use strict";
// Initialize ThemeManager
document.addEventListener("DOMContentLoaded", () => {
console.log("🚀 Initializing General Bots Desktop...");
// Initialize ThemeManager
document.addEventListener("DOMContentLoaded", () => {
console.log("🚀 Initializing General Bots Desktop...");
// Initialize theme system
if (window.ThemeManager) {
ThemeManager.init();
console.log("✓ Theme Manager initialized");
} else {
console.warn("⚠ ThemeManager not found");
// Initialize theme system
if (window.ThemeManager) {
ThemeManager.init();
console.log("✓ Theme Manager initialized");
} else {
console.warn("⚠ ThemeManager not found");
}
// Initialize apps menu
initAppsMenu();
// Hide loading overlay after initialization
setTimeout(() => {
const loadingOverlay =
document.getElementById("loadingOverlay");
if (loadingOverlay) {
loadingOverlay.classList.add("hidden");
console.log("✓ Application ready");
}
// Initialize apps menu
initAppsMenu();
// Hide loading overlay after initialization
setTimeout(() => {
const loadingOverlay =
document.getElementById("loadingOverlay");
if (loadingOverlay) {
loadingOverlay.classList.add("hidden");
console.log("✓ Application ready");
}
}, 500);
});
}, 500);
});
// Apps menu functionality
function initAppsMenu() {

733
ui/suite/desktop.html Normal file
View file

@ -0,0 +1,733 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>General Bots Desktop</title>
<!-- Link to the existing compiled CSS -->
<link rel="stylesheet" href="/suite/css/app.css" />
<link rel="stylesheet" href="/suite/css/base.css" />
<link rel="stylesheet" href="/suite/css/theme-sentient.css" />
<link rel="stylesheet" href="/suite/css/desktop.css" />
<!-- Local JS requirements per AGENTS.md / UI.md -->
<script src="/suite/js/vendor/htmx.min.js"></script>
<script src="/suite/js/vendor/marked.min.js"></script>
<script src="/suite/js/window-manager.js?v=2"></script>
<script src="/suite/js/theme-manager.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Fira Code", "Fira Sans", Arial, sans-serif;
background: var(--bg, #ffffff);
color: var(--text, #333333);
overflow: hidden;
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
display: flex;
}
/* Core Layout replicating BUILD V3 screenshot styling */
.build-container {
width: 100%;
height: 100%;
display: flex;
position: absolute;
inset: 0;
z-index: 1000;
background: var(--bg, #ffffff);
}
/* Left Sidebar */
.sidebar {
width: 51px;
height: 100%;
background: var(--bg-secondary, #f8f8f8);
border-right: 1px solid #d1d5db;
display: flex;
flex-direction: column;
z-index: 100;
}
.sidebar-item {
width: 51px;
height: 50px;
border-bottom: 1px solid var(--border-color, #f0f1f2);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
}
.sidebar-item:hover {
background: var(--bg, #ffffff);
}
.sidebar-item.active {
background: var(--bg, #ffffff);
border-left: 3px solid var(--primary, #84d669);
}
.sidebar-icon {
width: 30px;
height: 30px;
stroke: var(--text-secondary, #3b3b3b);
opacity: 0.6;
transition:
stroke 0.15s ease,
opacity 0.15s ease;
}
.sidebar-item:hover .sidebar-icon {
opacity: 1;
stroke: var(--text, #3b3b3b);
}
/* Main Content wrapper */
.main-wrapper {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Top Navigation Tabs - Removed (already in Vibe) */
/* Workspace (Where windows float) */
.workspace {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--bg, #ffffff);
position: relative;
}
/* The Panel Grid (Desktop Icons) */
.panel-section {
flex: 1;
padding: 26px 33px;
overflow-y: auto;
z-index: 10;
position: absolute;
inset: 0;
pointer-events: none;
}
/* Interactive Desktop Icons triggering HTMX */
.desktop-icons-container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 20px;
align-items: flex-start;
justify-content: flex-end;
width: auto;
pointer-events: auto;
position: absolute;
right: 33px;
top: 26px;
}
.desktop-icon {
display: flex;
flex-direction: column;
align-items: center;
width: 80px;
cursor: pointer;
position: relative;
gap: 8px;
}
.app-icon {
width: 64px;
height: 64px;
border-radius: 16px;
background: var(--surface-hover, #ffffff);
border: 1px solid var(--border, #e5e7eb);
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.15s ease;
}
.desktop-icon:hover .app-icon {
transform: scale(1.05);
border-color: var(--accent, #84d669);
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.1);
}
.app-icon svg {
width: 32px;
height: 32px;
stroke: var(--text, #374151);
transition: stroke 0.15s ease;
}
.desktop-icon:hover .app-icon svg {
stroke: var(--accent, #84d669);
}
.desktop-icon-label {
font-family: "Fira Code", monospace;
font-size: 12px;
font-weight: 600;
color: var(--text-secondary, #374151);
background: transparent;
backdrop-filter: blur(4px);
padding: 2px 8px;
border-radius: 4px;
text-align: center;
}
.bg-grid {
display: none;
}
.bg-svg {
display: none !important;
}
/* Bottom Taskbar */
.toolbar {
height: 50px;
background: var(--surface);
border-top: 1px solid var(--border);
display: flex;
align-items: center;
padding: 0 8px;
z-index: 100;
position: relative;
}
#taskbar-apps {
display: flex;
flex: 1;
height: 100%;
align-items: center;
gap: 0px;
}
.toolbar-time {
font-family: "Fira Code", monospace;
font-size: 14px;
color: var(--text-secondary, #3b3b3b);
text-align: right;
line-height: 1.4;
padding: 0 10px;
margin-left: auto;
}
/* Taskbar Items generated by WindowManager */
.taskbar-item {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
border-bottom: 2px solid transparent;
}
/* Fullscreen Mode Styles */
body.fullscreen .sidebar {
display: none !important;
}
body.fullscreen .toolbar {
display: none !important;
}
body.fullscreen .panel-section {
display: none !important;
}
body.fullscreen .workspace {
height: 100vh !important;
}
body.fullscreen .main-wrapper {
height: 100vh !important;
}
body.fullscreen .window-titlebar {
display: none !important;
}
body.fullscreen .window {
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
}
/* Hide window title bar and controls in fullscreen */
body.fullscreen .window > div:first-child {
display: none !important;
}
body.fullscreen .window > div:nth-child(2) {
display: none !important;
}
</style>
</head>
<body>
<!-- Minibar removed - login moved to taskbar -->
<div class="build-container">
<!-- Left Sidebar -->
<aside class="sidebar">
<div
class="sidebar-item active"
title="Home"
onclick="if(window.wm) window.wm.open('home', 'Home', '<div style=\'padding:20px;text-align:center;\'><h2>Welcome to General Bots Desktop</h2></div>');"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"
></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
</div>
<div
class="sidebar-item"
title="Search"
onclick="alert('Search coming soon');"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
</div>
<div
class="sidebar-item"
title="Terminal"
onclick="fetch('/suite/terminal/terminal.html').then(r=>r.text()).then(html=>{if(window.wm)window.wm.open('terminal','Terminal',html);});"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
</div>
<div
class="sidebar-item"
title="User"
onclick="alert('User profile coming soon');"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"
></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
</div>
<div
class="sidebar-item"
title="Apps"
onclick="if(window.wm) window.wm.open('apps', 'Applications', '<div style=\'padding:20px;\'><h3>Installed Applications</h3><p>Click desktop icons to launch apps.</p></div>');"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect x="3" y="3" width="7" height="7"></rect>
<rect x="14" y="3" width="7" height="7"></rect>
<rect x="14" y="14" width="7" height="7"></rect>
<rect x="3" y="14" width="7" height="7"></rect>
</svg>
</div>
<div
class="sidebar-item"
style="margin-top: auto"
title="Settings"
onclick="fetch('/suite/admin/organization-settings.html').then(r=>r.text()).then(html=>{if(window.wm)window.wm.open('settings','Settings',html);}).catch(e=>alert('Settings page not found'));"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="3"></circle>
<path
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"
></path>
</svg>
</div>
</aside>
<!-- Main Wrapper -->
<div class="main-wrapper">
<!-- Top Navigation Tabs - Removed (already in Vibe) -->
<!-- Workspace container where WindowManager operates -->
<div class="workspace" id="desktop-content">
<!-- Background Pattern -->
<div class="panel-section">
<div class="desktop-icons-container">
<div
class="desktop-icon"
data-app-id="vibe"
data-app-title="Vibe"
hx-get="/suite/partials/vibe.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"
/>
</svg>
</div>
<span class="desktop-icon-label">Vibe</span>
</div>
<div
class="desktop-icon"
data-app-id="tasks"
data-app-title="Tasks"
hx-get="/suite/tasks/task-window.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9 11l3 3L22 4" />
<path
d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"
/>
</svg>
</div>
<span class="desktop-icon-label">Tasks</span>
</div>
<div
class="desktop-icon"
data-app-id="chat"
data-app-title="Chat"
hx-get="/suite/partials/chat.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
/>
</svg>
</div>
<span class="desktop-icon-label">Chat</span>
</div>
<div
class="desktop-icon"
data-app-id="terminal"
data-app-title="Terminal"
hx-get="/suite/terminal/terminal.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="4 17 10 11 4 5" />
<line x1="12" y1="19" x2="20" y2="19" />
</svg>
</div>
<span class="desktop-icon-label">Terminal</span>
</div>
<div
class="desktop-icon"
data-app-id="drive"
data-app-title="Explorer"
hx-get="/suite/drive/drive.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"
/>
</svg>
</div>
<span class="desktop-icon-label">Explorer</span>
</div>
<div
class="desktop-icon"
data-app-id="editor"
data-app-title="Editor"
hx-get="/suite/editor.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="16 18 22 12 16 6" />
<polyline points="8 6 2 12 8 18" />
</svg>
</div>
<span class="desktop-icon-label">Editor</span>
</div>
<div
class="desktop-icon"
data-app-id="browser"
data-app-title="Browser"
hx-get="/suite/browser/browser.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10" />
<polygon
points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"
/>
</svg>
</div>
<span class="desktop-icon-label">Browser</span>
</div>
</div>
</div>
</div>
<!-- Bottom Taskbar -->
<footer class="toolbar" id="taskbar">
<div id="taskbar-apps">
<!-- Taskbar items populated automatically by window-manager.js -->
</div>
<div
class="toolbar-time"
style="display: flex; align-items: center; gap: 15px"
>
<div id="themeSelectorContainer"></div>
<button
id="loginBtn"
onclick="window.location.href='/suite/auth/login.html'"
style="
background: var(--primary, #84d669);
color: white;
border: none;
border-radius: 4px;
padding: 6px 12px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
font-family: &quot;Fira Code&quot;, monospace;
"
>
Sign In
</button>
<div style="text-align: right">
<div id="clock-time">00:00</div>
<div id="clock-date">01/01/2026</div>
</div>
</div>
</footer>
</div>
</div>
<!-- HTMX Intercepts and WindowManager Init as described in UI.md Phase 3 -->
<script>
// Check for fullscreen mode
(function() {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('fullscreen') === 'true') {
document.body.classList.add('fullscreen');
console.log('Fullscreen mode activated');
}
})();
document.addEventListener("DOMContentLoaded", async () => {
// Initialize WindowManager
if (typeof window.WindowManager !== "undefined") {
window.wm = window.WindowManager;
} else {
console.error(
"WindowManager class not loaded from window-manager.js",
);
}
// Initialize ThemeManager
if (typeof window.ThemeManager !== "undefined") {
window.ThemeManager.init();
}
// Auto-open Chat window maximized on desktop load
if (window.wm) {
try {
const response = await fetch(
"/suite/partials/chat.html",
);
if (response.ok) {
const htmlContent = await response.text();
window.wm.open("chat", "Chat", htmlContent);
// Maximize the chat window after opening
setTimeout(() => {
window.wm.toggleMaximize("chat");
}, 100);
}
} catch (err) {
console.error("Failed to auto-open chat:", err);
}
}
});
// Listen to HTMX afterRequest event
document.body.addEventListener("htmx:afterRequest", function (evt) {
const target = evt.detail.elt;
// Check if the click came from a desktop icon
if (target.classList.contains("desktop-icon")) {
const appId = target.getAttribute("data-app-id");
const title = target.getAttribute("data-app-title");
const htmlContent = evt.detail.xhr.response;
// Tell WindowManager to open it
if (window.wm) {
window.wm.open(appId, title, htmlContent);
}
}
// Ensure Theme dropdown is re-injected if wiped
if (window.ThemeManager) {
const container = document.getElementById(
"themeSelectorContainer",
);
if (container && !container.hasChildNodes()) {
// Quick and dirty way to re-init
window.ThemeManager.init();
}
}
});
// Update login button based on auth state
function updateLoginButton() {
var token =
localStorage.getItem("gb-access-token") ||
sessionStorage.getItem("gb-access-token");
var loginBtn = document.getElementById("loginBtn");
if (token && loginBtn) {
loginBtn.textContent = "Sign Out";
loginBtn.onclick = function () {
fetch("/api/auth/logout", { method: "POST" }).finally(
function () {
localStorage.removeItem("gb-access-token");
sessionStorage.removeItem("gb-access-token");
window.location.reload();
},
);
};
}
}
// Check login state on load
setTimeout(updateLoginButton, 500);
// Simple Clock implementation matching the screenshot bottom right corner
setInterval(() => {
const now = new Date();
document.getElementById("clock-time").textContent =
now.toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
});
document.getElementById("clock-date").textContent =
now.toLocaleDateString();
}, 1000);
</script>
</body>
</html>

View file

@ -0,0 +1,680 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>General Bots Desktop</title>
<!-- Link to the existing compiled CSS -->
<link rel="stylesheet" href="/suite/css/app.css" />
<link rel="stylesheet" href="/suite/css/base.css" />
<link rel="stylesheet" href="/suite/css/theme-sentient.css" />
<link rel="stylesheet" href="/suite/css/desktop.css" />
<!-- Local JS requirements per AGENTS.md / UI.md -->
<script src="/suite/js/vendor/htmx.min.js"></script>
<script src="/suite/js/vendor/marked.min.js"></script>
<script src="/suite/js/window-manager.js?v=2"></script>
<script src="/suite/js/theme-manager.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Fira Code", "Fira Sans", Arial, sans-serif;
background: var(--bg, #ffffff);
color: var(--text, #333333);
overflow: hidden;
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
display: flex;
}
/* Core Layout replicating BUILD V3 screenshot styling */
.build-container {
width: 100%;
height: 100%;
display: flex;
position: absolute;
inset: 0;
z-index: 1000;
background: var(--bg, #ffffff);
}
/* Left Sidebar */
.sidebar {
width: 51px;
height: 100%;
background: var(--bg-secondary, #f8f8f8);
border-right: 1px solid #d1d5db;
display: flex;
flex-direction: column;
z-index: 100;
}
.sidebar-item {
width: 51px;
height: 50px;
border-bottom: 1px solid var(--border-color, #f0f1f2);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
}
.sidebar-item:hover {
background: var(--bg, #ffffff);
}
.sidebar-item.active {
background: var(--bg, #ffffff);
border-left: 3px solid var(--primary, #84d669);
}
.sidebar-icon {
width: 30px;
height: 30px;
stroke: var(--text-secondary, #3b3b3b);
opacity: 0.6;
transition:
stroke 0.15s ease,
opacity 0.15s ease;
}
.sidebar-item:hover .sidebar-icon {
opacity: 1;
stroke: var(--text, #3b3b3b);
}
/* Main Content wrapper */
.main-wrapper {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Top Navigation Tabs - Removed (already in Vibe) */
/* Workspace (Where windows float) */
.workspace {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--bg, #ffffff);
position: relative;
}
/* The Panel Grid (Desktop Icons) */
.panel-section {
flex: 1;
padding: 26px 33px;
overflow-y: auto;
z-index: 10;
position: absolute;
inset: 0;
pointer-events: none;
}
/* Interactive Desktop Icons triggering HTMX */
.desktop-icons-container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 20px;
align-items: flex-start;
justify-content: flex-end;
width: auto;
pointer-events: auto;
position: absolute;
right: 33px;
top: 26px;
}
.desktop-icon {
display: flex;
flex-direction: column;
align-items: center;
width: 80px;
cursor: pointer;
position: relative;
gap: 8px;
}
.app-icon {
width: 64px;
height: 64px;
border-radius: 16px;
background: var(--surface-hover, #ffffff);
border: 1px solid var(--border, #e5e7eb);
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.15s ease;
}
.desktop-icon:hover .app-icon {
transform: scale(1.05);
border-color: var(--accent, #84d669);
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.1);
}
.app-icon svg {
width: 32px;
height: 32px;
stroke: var(--text, #374151);
transition: stroke 0.15s ease;
}
.desktop-icon:hover .app-icon svg {
stroke: var(--accent, #84d669);
}
.desktop-icon-label {
font-family: "Fira Code", monospace;
font-size: 12px;
font-weight: 600;
color: var(--text-secondary, #374151);
background: transparent;
backdrop-filter: blur(4px);
padding: 2px 8px;
border-radius: 4px;
text-align: center;
}
.bg-grid {
display: none;
}
.bg-svg {
display: none !important;
}
/* Bottom Taskbar */
.toolbar {
height: 50px;
background: var(--surface);
border-top: 1px solid var(--border);
display: flex;
align-items: center;
padding: 0 8px;
z-index: 100;
position: relative;
}
#taskbar-apps {
display: flex;
flex: 1;
height: 100%;
align-items: center;
gap: 0px;
}
.toolbar-time {
font-family: "Fira Code", monospace;
font-size: 14px;
color: var(--text-secondary, #3b3b3b);
text-align: right;
line-height: 1.4;
padding: 0 10px;
margin-left: auto;
}
/* Taskbar Items generated by WindowManager */
.taskbar-item {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
border-bottom: 2px solid transparent;
}
</head>
<body>
<!-- Minibar removed - login moved to taskbar -->
<div class="build-container">
<!-- Left Sidebar -->
<aside class="sidebar">
<div
class="sidebar-item active"
title="Home"
onclick="if(window.wm) window.wm.open('home', 'Home', '<div style=\'padding:20px;text-align:center;\'><h2>Welcome to General Bots Desktop</h2></div>');"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"
></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
</div>
<div
class="sidebar-item"
title="Search"
onclick="alert('Search coming soon');"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
</div>
<div
class="sidebar-item"
title="Terminal"
onclick="fetch('/suite/terminal/terminal.html').then(r=>r.text()).then(html=>{if(window.wm)window.wm.open('terminal','Terminal',html);});"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<polyline points="4 17 10 11 4 5"></polyline>
<line x1="12" y1="19" x2="20" y2="19"></line>
</svg>
</div>
<div
class="sidebar-item"
title="User"
onclick="alert('User profile coming soon');"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"
></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
</div>
<div
class="sidebar-item"
title="Apps"
onclick="if(window.wm) window.wm.open('apps', 'Applications', '<div style=\'padding:20px;\'><h3>Installed Applications</h3><p>Click desktop icons to launch apps.</p></div>');"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect x="3" y="3" width="7" height="7"></rect>
<rect x="14" y="3" width="7" height="7"></rect>
<rect x="14" y="14" width="7" height="7"></rect>
<rect x="3" y="14" width="7" height="7"></rect>
</svg>
</div>
<div
class="sidebar-item"
style="margin-top: auto"
title="Settings"
onclick="fetch('/suite/admin/organization-settings.html').then(r=>r.text()).then(html=>{if(window.wm)window.wm.open('settings','Settings',html);}).catch(e=>alert('Settings page not found'));"
>
<svg
class="sidebar-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="3"></circle>
<path
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"
></path>
</svg>
</div>
</aside>
<!-- Main Wrapper -->
<div class="main-wrapper">
<!-- Top Navigation Tabs - Removed (already in Vibe) -->
<!-- Workspace container where WindowManager operates -->
<div class="workspace" id="desktop-content">
<!-- Background Pattern -->
<div class="panel-section">
<div class="desktop-icons-container">
<div
class="desktop-icon"
data-app-id="vibe"
data-app-title="Vibe"
hx-get="/suite/partials/vibe.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"
/>
</svg>
</div>
<span class="desktop-icon-label">Vibe</span>
</div>
<div
class="desktop-icon"
data-app-id="tasks"
data-app-title="Tasks"
hx-get="/suite/tasks/task-window.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9 11l3 3L22 4" />
<path
d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"
/>
</svg>
</div>
<span class="desktop-icon-label">Tasks</span>
</div>
<div
class="desktop-icon"
data-app-id="chat"
data-app-title="Chat"
hx-get="/suite/partials/chat.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
/>
</svg>
</div>
<span class="desktop-icon-label">Chat</span>
</div>
<div
class="desktop-icon"
data-app-id="terminal"
data-app-title="Terminal"
hx-get="/suite/terminal/terminal.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="4 17 10 11 4 5" />
<line x1="12" y1="19" x2="20" y2="19" />
</svg>
</div>
<span class="desktop-icon-label">Terminal</span>
</div>
<div
class="desktop-icon"
data-app-id="drive"
data-app-title="Explorer"
hx-get="/suite/drive/drive.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"
/>
</svg>
</div>
<span class="desktop-icon-label">Explorer</span>
</div>
<div
class="desktop-icon"
data-app-id="editor"
data-app-title="Editor"
hx-get="/suite/editor.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="16 18 22 12 16 6" />
<polyline points="8 6 2 12 8 18" />
</svg>
</div>
<span class="desktop-icon-label">Editor</span>
</div>
<div
class="desktop-icon"
data-app-id="browser"
data-app-title="Browser"
hx-get="/suite/browser/browser.html"
hx-swap="none"
>
<div class="app-icon">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10" />
<polygon
points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"
/>
</svg>
</div>
<span class="desktop-icon-label">Browser</span>
</div>
</div>
</div>
</div>
<!-- Bottom Taskbar -->
<footer class="toolbar" id="taskbar">
<div id="taskbar-apps">
<!-- Taskbar items populated automatically by window-manager.js -->
</div>
<div
class="toolbar-time"
style="display: flex; align-items: center; gap: 15px"
>
<div id="themeSelectorContainer"></div>
<button
id="loginBtn"
onclick="window.location.href='/suite/auth/login.html'"
style="
background: var(--primary, #84d669);
color: white;
border: none;
border-radius: 4px;
padding: 6px 12px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
font-family: &quot;Fira Code&quot;, monospace;
"
>
Sign In
</button>
<div style="text-align: right">
<div id="clock-time">00:00</div>
<div id="clock-date">01/01/2026</div>
</div>
</div>
</footer>
</div>
</div>
<!-- HTMX Intercepts and WindowManager Init as described in UI.md Phase 3 -->
<script>
document.addEventListener("DOMContentLoaded", async () => {
// Initialize WindowManager
if (typeof window.WindowManager !== "undefined") {
window.wm = window.WindowManager;
} else {
console.error(
"WindowManager class not loaded from window-manager.js",
);
}
// Initialize ThemeManager
if (typeof window.ThemeManager !== "undefined") {
window.ThemeManager.init();
}
// Auto-open Chat window maximized on desktop load
if (window.wm) {
try {
const response = await fetch(
"/suite/partials/chat.html",
);
if (response.ok) {
const htmlContent = await response.text();
window.wm.open("chat", "Chat", htmlContent);
// Maximize the chat window after opening
setTimeout(() => {
window.wm.toggleMaximize("chat");
}, 100);
}
} catch (err) {
console.error("Failed to auto-open chat:", err);
}
}
});
// Listen to HTMX afterRequest event
document.body.addEventListener("htmx:afterRequest", function (evt) {
const target = evt.detail.elt;
// Check if the click came from a desktop icon
if (target.classList.contains("desktop-icon")) {
const appId = target.getAttribute("data-app-id");
const title = target.getAttribute("data-app-title");
const htmlContent = evt.detail.xhr.response;
// Tell WindowManager to open it
if (window.wm) {
window.wm.open(appId, title, htmlContent);
}
}
// Ensure Theme dropdown is re-injected if wiped
if (window.ThemeManager) {
const container = document.getElementById(
"themeSelectorContainer",
);
if (container && !container.hasChildNodes()) {
// Quick and dirty way to re-init
window.ThemeManager.init();
}
}
});
// Update login button based on auth state
function updateLoginButton() {
var token =
localStorage.getItem("gb-access-token") ||
sessionStorage.getItem("gb-access-token");
var loginBtn = document.getElementById("loginBtn");
if (token && loginBtn) {
loginBtn.textContent = "Sign Out";
loginBtn.onclick = function () {
fetch("/api/auth/logout", { method: "POST" }).finally(
function () {
localStorage.removeItem("gb-access-token");
sessionStorage.removeItem("gb-access-token");
window.location.reload();
},
);
};
}
}
// Check login state on load
setTimeout(updateLoginButton, 500);
// Simple Clock implementation matching the screenshot bottom right corner
setInterval(() => {
const now = new Date();
document.getElementById("clock-time").textContent =
now.toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
});
document.getElementById("clock-date").textContent =
now.toLocaleDateString();
}, 1000);
</script>
</body>
</html>

View file

@ -1,5 +1,5 @@
<!-- Drive - File Management v1.0 -->
<link rel="stylesheet" href="drive/drive.css" />
<link rel="stylesheet" href="/suite/drive/drive.css" />
<div class="drive-container" id="drive-app">
<!-- Sidebar -->
@ -348,4 +348,4 @@
<!-- Context Menu (dynamically populated by JS) -->
<div id="context-menu" class="context-menu hidden"></div>
<script src="drive/drive.js"></script>
<script src="/suite/drive/drive.js"></script>

View file

@ -17,7 +17,7 @@
<nav class="nav-section">
<div class="nav-item active"
hx-get="/api/drive/files?path=/"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
onclick="setActiveNav(this)">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@ -29,7 +29,7 @@
<div class="nav-item"
hx-get="/api/drive/files?filter=shared"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
onclick="setActiveNav(this)">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@ -43,7 +43,7 @@
<div class="nav-item"
hx-get="/api/drive/files?filter=recent"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
onclick="setActiveNav(this)">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@ -55,7 +55,7 @@
<div class="nav-item"
hx-get="/api/drive/files?filter=starred"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
onclick="setActiveNav(this)">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@ -66,7 +66,7 @@
<div class="nav-item"
hx-get="/api/drive/files?filter=trash"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
onclick="setActiveNav(this)">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@ -174,7 +174,7 @@
<select class="sort-dropdown" id="sort-dropdown"
hx-get="/api/drive/files"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
hx-include="[name='path']">
<option value="name">Name</option>
@ -264,7 +264,7 @@
hx-delete="/api/drive/files"
hx-include=".file-checkbox:checked"
hx-confirm="Move selected items to trash?"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="3 6 5 6 21 6"></polyline>
@ -322,7 +322,7 @@
<div class="upload-zone" id="upload-zone"
hx-post="/api/drive/upload"
hx-encoding="multipart/form-data"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML">
<input type="file" id="file-input" name="files" multiple hidden>
<input type="hidden" name="path" id="upload-path" value="/">
@ -352,7 +352,7 @@
<dialog class="modal" id="folder-modal">
<form class="modal-content"
hx-post="/api/drive/folder"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
hx-on::after-request="document.getElementById('folder-modal').close()">
<div class="modal-header">
@ -418,7 +418,7 @@
<dialog class="modal" id="copy-modal">
<form class="modal-content"
hx-post="/files/copy"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
hx-on::after-request="document.getElementById('copy-modal').close()">
<div class="modal-header">
@ -453,7 +453,7 @@
<dialog class="modal" id="move-modal">
<form class="modal-content"
hx-post="/files/move"
hx-target="#file-grid"
hx-target="closest .window-body #file-grid"
hx-swap="innerHTML"
hx-on::after-request="document.getElementById('move-modal').close()">
<div class="modal-header">
@ -562,7 +562,7 @@
</h3>
<p>Combine multiple documents into one</p>
<form hx-post="/docs/merge"
hx-target="#docs-result"
hx-target="closest .window-body #docs-result"
hx-swap="innerHTML"
hx-encoding="multipart/form-data">
<input type="file" name="files" multiple accept=".pdf,.docx,.doc,.txt" class="form-group" style="margin-bottom: 8px;">
@ -584,7 +584,7 @@
</h3>
<p>Convert between document formats</p>
<form hx-post="/docs/convert"
hx-target="#docs-result"
hx-target="closest .window-body #docs-result"
hx-swap="innerHTML"
hx-encoding="multipart/form-data">
<input type="file" name="file" accept=".pdf,.docx,.doc,.txt,.md,.html" class="form-group" style="margin-bottom: 8px;">
@ -612,7 +612,7 @@
</h3>
<p>Populate template with data</p>
<form hx-post="/docs/fill"
hx-target="#docs-result"
hx-target="closest .window-body #docs-result"
hx-swap="innerHTML"
hx-encoding="multipart/form-data">
<input type="file" name="template" accept=".docx,.doc" class="form-group" style="margin-bottom: 8px;">
@ -633,7 +633,7 @@
</h3>
<p>Export document in specified format</p>
<form hx-post="/docs/export"
hx-target="#docs-result"
hx-target="closest .window-body #docs-result"
hx-swap="innerHTML">
<input type="text" name="path" placeholder="File path (e.g., /documents/report.docx)" class="form-group" style="width: 100%; margin-bottom: 8px;">
<select name="format" class="sort-dropdown" style="width: 100%; margin-bottom: 8px;">
@ -657,7 +657,7 @@
</h3>
<p>Import document from URL or upload</p>
<form hx-post="/docs/import"
hx-target="#docs-result"
hx-target="closest .window-body #docs-result"
hx-swap="innerHTML"
hx-encoding="multipart/form-data">
<input type="url" name="url" placeholder="Document URL (optional)" class="form-group" style="width: 100%; margin-bottom: 8px;">

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -351,8 +351,8 @@
this.clearAuth();
this.emit("tokenExpired");
const currentPath = window.location.pathname;
if (!currentPath.startsWith("/auth/")) {
const currentPath = window.location.pathname + window.location.hash;
if (!window.location.pathname.startsWith("/auth/")) {
window.location.href =
"/auth/login.html?expired=1&redirect=" +
encodeURIComponent(currentPath);

View file

@ -47,12 +47,15 @@ function applyProductConfig(config) {
// Check if we have compiled_features info to filter even further
// This ensures we don't show apps that are enabled in config but not compiled in binary
if (config.compiled_features && Array.isArray(config.compiled_features)) {
const compiledSet = new Set(config.compiled_features.map(f => f.toLowerCase()));
effectiveApps = effectiveApps.filter(app =>
compiledSet.has(app.toLowerCase()) ||
app.toLowerCase() === 'settings' ||
app.toLowerCase() === 'auth' ||
app.toLowerCase() === 'admin' // Admin usually contains settings which is always there
const compiledSet = new Set(
config.compiled_features.map((f) => f.toLowerCase()),
);
effectiveApps = effectiveApps.filter(
(app) =>
compiledSet.has(app.toLowerCase()) ||
app.toLowerCase() === "settings" ||
app.toLowerCase() === "auth" ||
app.toLowerCase() === "admin", // Admin usually contains settings which is always there
);
// Also call a helper to hide UI elements for non-compiled features explicitly
@ -61,6 +64,33 @@ function applyProductConfig(config) {
}
filterAppsByConfig(effectiveApps);
// Check if there are any visible apps after filtering
const hasVisibleApps = effectiveApps.length > 0;
// Hide apps menu button if menu launcher is disabled or if there are no apps to show
if (config.menu_launcher_enabled === false || !hasVisibleApps) {
const appsButton = document.getElementById("appsButton");
if (appsButton) {
appsButton.style.display = "none";
}
const appsMenuContainer = document.querySelector(".apps-menu-container");
if (appsMenuContainer) {
appsMenuContainer.style.display = "none";
}
}
}
// Hide omnibox if search is disabled
if (config.search_enabled === false) {
const omnibox = document.getElementById("omnibox");
if (omnibox) {
omnibox.style.display = "none";
}
const headerCenter = document.querySelector(".header-center");
if (headerCenter) {
headerCenter.style.display = "none";
}
}
// Apply custom logo
@ -95,18 +125,22 @@ function applyProductConfig(config) {
// Hide UI elements that require features not compiled in the binary
function hideNonCompiledUI(compiledSet) {
// Hide elements with data-feature attribute that aren't in compiled set
document.querySelectorAll('[data-feature]').forEach(el => {
const feature = el.getAttribute('data-feature').toLowerCase();
document.querySelectorAll("[data-feature]").forEach((el) => {
const feature = el.getAttribute("data-feature").toLowerCase();
// Allow settings/admin as they are usually core
if (!compiledSet.has(feature) && feature !== 'settings' && feature !== 'admin') {
el.style.display = 'none';
el.classList.add('hidden-uncompiled');
if (
!compiledSet.has(feature) &&
feature !== "settings" &&
feature !== "admin"
) {
el.style.display = "none";
el.classList.add("hidden-uncompiled");
}
});
// Also look for specific sections that might map to features
// e.g. .feature-mail, .feature-meet classes
compiledSet.forEach(feature => {
compiledSet.forEach((feature) => {
// This loop defines what IS available.
// Logic should be inverse: find all feature- classes and hide if not in set
// But scanning all classes is expensive.

View file

@ -0,0 +1,302 @@
/**
* Chat Agent Mode handles toggling between Agent and Chat mode,
* multi-panel layout management, and WebSocket message routing
* for thought process, terminal output, browser preview, and step tracking.
*/
(function () {
"use strict";
var agentMode = false;
var currentStep = 0;
var totalSteps = 0;
var terminalLineCount = 0;
function initAgentMode() {
setupModeToggle();
setupToggleSwitches();
setupStepNavigation();
setupQuickActions();
setupSidebarItems();
}
function setupModeToggle() {
var agentBtn = document.getElementById("modeAgentBtn");
var chatBtn = document.getElementById("modeChatBtn");
if (!agentBtn || !chatBtn) return;
agentBtn.addEventListener("click", function () {
setMode("agent");
});
chatBtn.addEventListener("click", function () {
setMode("chat");
});
}
function setMode(mode) {
var chatApp = document.getElementById("chat-app");
var agentBtn = document.getElementById("modeAgentBtn");
var chatBtn = document.getElementById("modeChatBtn");
var quickActions = document.getElementById("quickActions");
if (!chatApp || !agentBtn || !chatBtn) return;
agentMode = mode === "agent";
agentBtn.classList.toggle("active", agentMode);
chatBtn.classList.toggle("active", !agentMode);
if (agentMode) {
chatApp.classList.add("agent-mode");
if (quickActions) quickActions.style.display = "none";
} else {
chatApp.classList.remove("agent-mode");
if (quickActions) quickActions.style.display = "";
}
}
function setupToggleSwitches() {
var planToggle = document.getElementById("togglePlan");
var yoloToggle = document.getElementById("toggleYolo");
if (planToggle) {
planToggle.addEventListener("click", function () {
this.classList.toggle("on");
emitModeChange();
});
}
if (yoloToggle) {
yoloToggle.addEventListener("click", function () {
this.classList.toggle("on");
emitModeChange();
});
}
}
function emitModeChange() {
var planOn = document.getElementById("togglePlan");
var yoloOn = document.getElementById("toggleYolo");
var mode = "plan";
if (yoloOn && yoloOn.classList.contains("on")) {
mode = "yolo";
}
if (window.ws && window.ws.readyState === WebSocket.OPEN) {
window.ws.send(JSON.stringify({
type: "toggle_mode",
mode: mode
}));
}
}
function setupStepNavigation() {
var prevBtn = document.getElementById("stepPrev");
var nextBtn = document.getElementById("stepNext");
if (prevBtn) {
prevBtn.addEventListener("click", function () {
if (currentStep > 1) {
currentStep--;
updateStepCounter();
}
});
}
if (nextBtn) {
nextBtn.addEventListener("click", function () {
if (currentStep < totalSteps) {
currentStep++;
updateStepCounter();
}
});
}
}
function updateStepCounter() {
var display = document.getElementById("stepCounterText");
if (display) {
display.textContent = currentStep + " / " + totalSteps;
}
}
function setupQuickActions() {
var chips = document.querySelectorAll(".quick-action-chip");
chips.forEach(function (chip) {
chip.addEventListener("click", function () {
var action = this.getAttribute("data-action");
var prompts = {
"full-stack": "Create a full-stack web application",
"writing": "Help me write ",
"data-insight": "Analyze data and provide insights",
"magic-design": "Design a beautiful UI for "
};
var input = document.getElementById("messageInput");
if (input && prompts[action]) {
input.value = prompts[action];
input.focus();
}
});
});
}
function setupSidebarItems() {
var items = document.querySelectorAll(".agent-sidebar-item");
items.forEach(function (item) {
item.addEventListener("click", function () {
items.forEach(function (i) { i.classList.remove("active"); });
this.classList.add("active");
});
});
}
/* ===========================================
Agent Mode WebSocket Message Handlers
=========================================== */
function handleAgentMessage(data) {
if (!agentMode) return;
switch (data.type) {
case "thought_process":
renderThoughtProcess(data.content);
break;
case "terminal_output":
appendTerminalLine(data.line, data.stream);
break;
case "browser_ready":
showBrowserPreview(data.url);
break;
case "step_progress":
currentStep = data.current;
totalSteps = data.total;
updateStepCounter();
break;
case "step_complete":
break;
case "todo_update":
renderTodoList(data.todos);
break;
case "agent_status":
updateAgentInfo(data);
break;
case "file_created":
incrementBadge("explorerBadge");
break;
}
}
function renderThoughtProcess(content) {
var messages = document.getElementById("messages");
if (!messages) return;
var block = document.createElement("div");
block.className = "thought-process";
block.innerHTML =
'<button class="thought-process-header">' +
'<span class="thought-process-toggle">▶</span>' +
'<span>Thought Process</span>' +
"</button>" +
'<div class="thought-process-body">' + escapeForHtml(content) + "</div>";
var header = block.querySelector(".thought-process-header");
header.addEventListener("click", function () {
block.classList.toggle("expanded");
});
messages.appendChild(block);
}
function appendTerminalLine(text, stream) {
var terminal = document.getElementById("terminalPanelContent");
if (!terminal) return;
var line = document.createElement("div");
line.className = "terminal-line " + (stream || "stdout");
line.textContent = text;
terminal.appendChild(line);
terminal.scrollTop = terminal.scrollHeight;
terminalLineCount++;
incrementBadge("terminalBadge");
}
function showBrowserPreview(url) {
var content = document.getElementById("browserPanelContent");
var urlBar = document.getElementById("browserUrlBar");
if (!content || !urlBar) return;
urlBar.value = url;
content.innerHTML = '<iframe src="' + url + '" sandbox="allow-scripts allow-same-origin"></iframe>';
}
function renderTodoList(todos) {
var messages = document.getElementById("messages");
if (!messages) return;
var existing = messages.querySelector(".agent-todo-list:last-child");
if (existing) existing.remove();
var list = document.createElement("div");
list.className = "agent-todo-list";
var headerHtml = '<div class="agent-todo-header">' +
'<span>📋 Todos</span>' +
'<span class="agent-todo-count">' + todos.length + "</span>" +
"</div>";
var itemsHtml = todos.map(function (todo) {
var doneClass = todo.done ? " done" : "";
var checkMark = todo.done ? "✓" : "";
return '<div class="agent-todo-item' + doneClass + '">' +
'<span class="agent-todo-check">' + checkMark + "</span>" +
'<span>' + escapeForHtml(todo.text) + "</span>" +
"</div>";
}).join("");
list.innerHTML = headerHtml + itemsHtml;
messages.appendChild(list);
}
function updateAgentInfo(data) {
var nameEl = document.getElementById("agentNameDisplay");
var levelEl = document.getElementById("agentLevelBadge");
var modelEl = document.getElementById("agentModelDisplay");
if (nameEl && data.name) nameEl.textContent = data.name;
if (levelEl && data.level) {
levelEl.textContent = data.level;
levelEl.className = "agent-level-badge badge-" + data.level.toLowerCase();
}
if (modelEl && data.model) {
modelEl.textContent = data.model + " — " + (data.usage || 0) + "%";
}
}
function incrementBadge(badgeId) {
var badge = document.getElementById(badgeId);
if (!badge) return;
var count = parseInt(badge.textContent, 10) || 0;
badge.textContent = count + 1;
badge.style.display = "";
}
function escapeForHtml(text) {
var div = document.createElement("div");
div.textContent = text || "";
return div.innerHTML;
}
/* ===========================================
Expose to global scope
=========================================== */
window.AgentMode = {
init: initAgentMode,
handleMessage: handleAgentMessage,
setMode: setMode,
isActive: function () { return agentMode; }
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initAgentMode);
} else {
initAgentMode();
}
})();

0
ui/suite/js/editor.js Normal file
View file

View file

@ -0,0 +1,190 @@
(function() {
'use strict';
const MAX_ERRORS = 50;
const REPORT_ENDPOINT = '/api/client-errors';
let errorQueue = [];
let isReporting = false;
function formatError(error, context = {}) {
return {
type: error.name || 'Error',
message: error.message || String(error),
stack: error.stack,
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: new Date().toISOString(),
context: context
};
}
async function reportErrors() {
if (isReporting || errorQueue.length === 0) return;
isReporting = true;
const errorsToReport = errorQueue.splice(0, MAX_ERRORS);
errorQueue = [];
try {
const response = await fetch(REPORT_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ errors: errorsToReport })
});
if (!response.ok) {
console.warn('[ErrorReporter] Failed to send errors:', response.status);
} else {
console.log('[ErrorReporter] Sent', errorsToReport.length, 'errors to server');
}
} catch (e) {
console.warn('[ErrorReporter] Failed to send errors:', e.message);
errorQueue.unshift(...errorsToReport);
} finally {
isReporting = false;
if (errorQueue.length > 0) {
setTimeout(reportErrors, 1000);
}
}
}
function queueError(errorData) {
errorQueue.push(errorData);
if (errorQueue.length >= 10) {
reportErrors();
}
}
window.addEventListener('error', (event) => {
const errorData = formatError(event.error || new Error(event.message), {
filename: event.filename,
lineno: event.lineno,
colno: event.colno
});
queueError(errorData);
});
window.addEventListener('unhandledrejection', (event) => {
const errorData = formatError(event.reason || new Error(String(event.reason)), {
type: 'unhandledRejection'
});
queueError(errorData);
});
window.ErrorReporter = {
report: function(error, context) {
queueError(formatError(error, context));
},
reportNetworkError: function(url, status, statusText) {
queueError({
type: 'NetworkError',
message: `Failed to load ${url}: ${status} ${statusText}`,
url: window.location.href,
timestamp: new Date().toISOString(),
context: { url, status, statusText }
});
},
flush: function() {
reportErrors();
}
};
if (document.readyState === 'complete') {
setTimeout(reportErrors, 1000);
} else {
window.addEventListener('load', () => {
setTimeout(reportErrors, 1000);
});
}
console.log('[ErrorReporter] Client-side error reporting initialized');
window.NavigationLogger = {
log: function(from, to, method) {
const navEvent = {
type: 'navigation',
from: from,
to: to,
method: method,
url: window.location.href,
timestamp: new Date().toISOString()
};
queueError({
name: 'Navigation',
message: `${method}: ${from} -> ${to}`,
stack: undefined
});
}
};
function initNavigationTracking() {
if (!document.body) {
setTimeout(initNavigationTracking, 50);
return;
}
if (document.body) {
document.body.addEventListener('click', function(e) {
const target = e.target.closest('[data-section]');
if (target) {
const section = target.getAttribute('data-section');
const currentHash = window.location.hash.slice(1) || '';
if (section !== currentHash) {
setTimeout(() => {
window.NavigationLogger.log(currentHash || 'home', section, 'click');
}, 100);
}
}
}, true);
}
window.addEventListener('hashchange', function(e) {
const oldURL = new URL(e.oldURL);
const newURL = new URL(e.newURL);
const fromHash = oldURL.hash.slice(1) || '';
const toHash = newURL.hash.slice(1) || '';
window.NavigationLogger.log(fromHash || 'home', toHash, 'hashchange');
});
console.log('[NavigationLogger] Navigation tracking initialized');
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initNavigationTracking);
} else {
initNavigationTracking();
}
// Intercept link onload/onerror events to catch CSS/image load failures
const originalCreateElement = document.createElement;
document.createElement = function(tagName) {
const element = originalCreateElement.call(document, tagName);
if (tagName.toLowerCase() === 'link') {
element.addEventListener('error', function() {
if (this.href && window.ErrorReporter && window.ErrorReporter.reportNetworkError) {
window.ErrorReporter.reportNetworkError(this.href, 'LOAD_FAILED', 'Resource failed to load');
}
});
}
return element;
};
window.addEventListener('load', () => {
setTimeout(() => {
const failedResources = performance.getEntriesByType('resource').filter(entry =>
entry.transferSize === 0 && entry.decodedBodySize > 0 && !entry.name.includes('anon') && entry.duration > 100
);
if (failedResources.length > 0) {
console.warn('[ErrorReporter] Detected potentially failed resources:', failedResources);
failedResources.forEach(resource => {
window.ErrorReporter.reportNetworkError(resource.name, 'FAILED', 'Resource load timeout/failure');
});
}
}, 5000);
});
})();

View file

@ -192,7 +192,6 @@
document.body.addEventListener("htmx:wsOpen", () => {
updateConnectionStatus("connected");
reconnectAttempts = 0;
});
document.body.addEventListener("htmx:wsClose", () => {
@ -203,7 +202,29 @@
// Handle WebSocket messages
function handleWebSocketMessage(message) {
switch (message.type) {
const messageType = message.type || message.event;
if (messageType === "connected") {
reconnectAttempts = 0;
}
// Debug logging
console.log("handleWebSocketMessage called with:", { messageType, message });
// Hide initial loading overlay when first bot message arrives
if (window.hideLoadingOverlay) {
setTimeout(window.hideLoadingOverlay, 300);
}
// Handle suggestions array from BotResponse
if (message.suggestions && Array.isArray(message.suggestions) && message.suggestions.length > 0) {
clearSuggestions();
message.suggestions.forEach(suggestion => {
addSuggestionButton(suggestion.text, suggestion.value || suggestion.text);
});
}
switch (messageType) {
case "message":
appendMessage(message);
break;
@ -216,11 +237,48 @@
case "suggestion":
addSuggestion(message.text);
break;
case "change_theme":
console.log("Processing change_theme event, not appending to chat");
if (message.data) {
ThemeManager.setThemeFromServer(message.data);
}
return; // Don't append theme events to chat
default:
console.log("Unknown message type:", message.type);
// Only append unknown message types to chat if they have text content
if (message.text || message.content) {
console.log("Unknown message type, treating as chat message:", messageType);
appendMessage(message);
} else {
console.log("Unknown message type:", messageType, message);
}
}
}
// Clear all suggestions
function clearSuggestions() {
const suggestionsEl = document.getElementById("suggestions");
if (suggestionsEl) {
suggestionsEl.innerHTML = '';
}
}
// Add suggestion button with value
function addSuggestionButton(text, value) {
const suggestionsEl = document.getElementById("suggestions");
if (!suggestionsEl) return;
const chip = document.createElement("button");
chip.className = "suggestion-chip";
chip.textContent = text;
chip.setAttribute("hx-post", "/api/sessions/current/message");
chip.setAttribute("hx-vals", JSON.stringify({ content: value }));
chip.setAttribute("hx-target", "#messages");
chip.setAttribute("hx-swap", "beforeend");
suggestionsEl.appendChild(chip);
htmx.process(chip);
}
// Append message to chat
function appendMessage(message) {
const messagesEl = document.getElementById("messages");

View file

@ -3,8 +3,13 @@
const DEFAULT_LOCALE = "en";
const STORAGE_KEY = "gb-locale";
const CACHE_VERSION = "v2";
const CACHE_TTL_MS = 3600000;
// IMPORTANT: Increment CACHE_VERSION when translation structure changes
// to invalidate all user caches and force fresh API fetches
// v2: Invalidated cache to fix placeholder translations after i18n embed fix
const MINIMAL_FALLBACK = {
"label-loading": "Loading...",
"status-error": "Error",
@ -36,7 +41,7 @@
}
function getCacheKey(locale) {
return `gb-i18n-cache-${locale}`;
return `gb-i18n-cache-${locale}}-${CACHE_VERSION}`;
}
function getCachedTranslations(locale) {
@ -44,7 +49,9 @@
const cached = localStorage.getItem(getCacheKey(locale));
if (cached) {
const { data, timestamp } = JSON.parse(cached);
if (Date.now() - timestamp < CACHE_TTL_MS) {
const age = Date.now() - timestamp;
console.log(`i18n: Cache check for ${locale}: age=${Math.round(age/1000)}s, valid=${age < CACHE_TTL_MS}, keys=${Object.keys(data || {}).length}`);
if (age < CACHE_TTL_MS) {
return data;
}
}
@ -70,6 +77,7 @@
async function fetchTranslations(locale) {
try {
console.log(`i18n: Fetching translations for locale: ${locale}`);
const response = await fetch(`/api/i18n/${locale}`, {
headers: { Accept: "application/json" },
});
@ -79,21 +87,25 @@
}
const result = await response.json();
console.log(`i18n: Loaded ${Object.keys(result.translations || {}).length} translations for ${locale}`);
return result.translations || {};
} catch (e) {
console.warn(`i18n: Failed to fetch translations for ${locale}`, e);
console.error(`i18n: Failed to fetch translations for ${locale}`, e);
return null;
}
}
async function loadTranslations(locale) {
console.log(`i18n: loadTranslations called for locale: ${locale}`);
const cached = getCachedTranslations(locale);
if (cached) {
console.log(`i18n: Using cached translations for ${locale}`);
translations = cached;
currentLocale = locale;
return true;
}
console.log(`i18n: Cache miss, fetching from API for ${locale}`);
const fetched = await fetchTranslations(locale);
if (fetched && Object.keys(fetched).length > 0) {
translations = fetched;
@ -107,6 +119,7 @@
return loadTranslations(DEFAULT_LOCALE);
}
console.warn(`i18n: No translations found, using minimal fallback`);
translations = MINIMAL_FALLBACK;
return false;
}
@ -114,6 +127,10 @@
function t(key, params) {
let text = translations[key] || MINIMAL_FALLBACK[key] || key;
if (!translations[key] && !MINIMAL_FALLBACK[key]) {
console.warn(`i18n: Missing translation key: ${key}`);
}
if (params && typeof params === "object") {
Object.keys(params).forEach((param) => {
text = text.replace(
@ -232,14 +249,18 @@
}
async function init() {
console.log("i18n: Initialization started");
if (isInitialized) {
console.log("i18n: Already initialized, skipping");
return;
}
const locale = detectBrowserLocale();
console.log(`i18n: Detected locale: ${locale}`);
await loadTranslations(locale);
isInitialized = true;
console.log(`i18n: Initialization complete, current locale: ${currentLocale}`);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", () => {
@ -276,6 +297,7 @@
localStorage.removeItem(key);
}
});
console.log("i18n: Cleared all translation caches");
}
window.i18n = {

View file

@ -210,10 +210,14 @@
return originalFetch
.call(window, input, init)
.then(function (response) {
var url = typeof input === "string" ? input : input.url;
if (response.status === 401) {
var url = typeof input === "string" ? input : input.url;
self.handleUnauthorized(url);
} else if (!response.ok && window.ErrorReporter && window.ErrorReporter.reportNetworkError) {
window.ErrorReporter.reportNetworkError(url, response.status, response.statusText);
}
return response;
});
};
@ -295,6 +299,12 @@
});
window.addEventListener("gb:auth:expired", function (event) {
// Check if current bot is public - if so, skip redirect
if (window.__BOT_IS_PUBLIC__ === true) {
console.log("[GBSecurity] Bot is public, skipping auth redirect");
return;
}
console.log(
"[GBSecurity] Auth expired, clearing tokens and redirecting",
);

File diff suppressed because it is too large Load diff

View file

@ -3,6 +3,27 @@ const ThemeManager = (() => {
let currentThemeId = "default";
let subscribers = [];
// Bot ID to theme mapping (configured via config.csv theme-base field)
const botThemeMap = {
// Default bot uses light theme with brown accents
default: "light",
// Cristo bot uses typewriter theme (classic typewriter style)
cristo: "typewriter",
// Salesianos bot uses light theme with blue accents
salesianos: "light",
};
// Detect current bot from URL path
function getCurrentBotId() {
const path = window.location.pathname;
// Match patterns like /bot/cristo, /cristo, etc.
const match = path.match(/(?:\/bot\/)?([a-z0-9-]+)/i);
if (match && match[1]) {
return match[1].toLowerCase();
}
return "default";
}
const themes = [
{ id: "default", name: "🎨 Default", file: "light.css" },
{ id: "light", name: "☀️ Light", file: "light.css" },
@ -46,7 +67,10 @@ const ThemeManager = (() => {
if (!theme.file) {
currentThemeId = "default";
localStorage.setItem("gb-theme", "default");
const botId = getCurrentBotId();
localStorage.setItem(`gb-theme-${botId}`, "default");
// Re-enable sentient theme for default
document.documentElement.setAttribute("data-theme", "sentient");
updateDropdown();
return;
}
@ -54,21 +78,217 @@ const ThemeManager = (() => {
const link = document.createElement("link");
link.id = "theme-css";
link.rel = "stylesheet";
link.href = `public/themes/${theme.file}`;
link.href = `/suite/public/themes/${theme.file}`;
link.onload = () => {
console.log("✓ Theme loaded:", theme.name);
currentThemeId = id;
localStorage.setItem("gb-theme", id);
updateDropdown();
subscribers.forEach((cb) => cb({ themeId: id, themeName: theme.name }));
const botId = getCurrentBotId();
localStorage.setItem(`gb-theme-${botId}`, id);
// Keep data-theme="sentient" on html so CSS selectors work
// The inline styles will override the colors
if (!document.documentElement.getAttribute("data-theme")) {
document.documentElement.setAttribute("data-theme", "sentient");
}
// Remove data-theme from body to prevent base.css theme rules from overriding
document.body.removeAttribute("data-theme");
// Small delay to ensure CSS variables are applied
setTimeout(() => {
// Get the theme's colors from CSS variables
const rootStyle = getComputedStyle(document.documentElement);
const primary =
rootStyle.getPropertyValue("--primary")?.trim() || "#3b82f6";
const background =
rootStyle.getPropertyValue("--background")?.trim() || "0 0% 100%";
const foreground =
rootStyle.getPropertyValue("--foreground")?.trim() || "222 47% 11%";
const card = rootStyle.getPropertyValue("--card")?.trim() || "0 0% 98%";
const border =
rootStyle.getPropertyValue("--border")?.trim() || "214 32% 91%";
// Convert HSL values to hex format for app compatibility
const hslToHex = (h, s, l) => {
l /= 100;
const a = (s * Math.min(l, 1 - l)) / 100;
const f = (n) => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color)
.toString(16)
.padStart(2, "0");
};
return `#${f(0)}${f(8)}${f(4)}`;
};
const parseHsl = (hslStr) => {
if (!hslStr) return null;
const match = hslStr
.trim()
.match(/([0-9.]+)\s+([0-9.]+)%\s+([0-9.]+)%/);
if (match) {
return [
parseFloat(match[1]),
parseFloat(match[2]),
parseFloat(match[3]),
];
}
return null;
};
const getContrastYIQ = (hexcolor) => {
if (!hexcolor) return "#ffffff";
hexcolor = hexcolor.replace("#", "");
if (hexcolor.length === 3) {
hexcolor = hexcolor
.split("")
.map((c) => c + c)
.join("");
}
if (hexcolor.length !== 6) return "#ffffff";
var r = parseInt(hexcolor.substr(0, 2), 16);
var g = parseInt(hexcolor.substr(2, 2), 16);
var b = parseInt(hexcolor.substr(4, 2), 16);
var yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq >= 128 ? "#000000" : "#ffffff";
};
const bgHsl = parseHsl(background);
const fgHsl = parseHsl(foreground);
const cardHsl = parseHsl(card);
const borderHsl = parseHsl(border);
let calculatedTextHex = "#ffffff";
if (bgHsl) {
const bgHex = hslToHex(...bgHsl);
document.documentElement.style.setProperty("--bg", bgHex);
document.documentElement.style.setProperty("--bg-secondary", bgHex);
document.documentElement.style.setProperty(
"--primary-bg",
`hsl(${background})`,
);
document.documentElement.style.setProperty("--header-bg", bgHex);
document.documentElement.style.setProperty("--glass-bg", bgHex);
document.documentElement.style.setProperty("--sidebar-bg", bgHex);
calculatedTextHex = getContrastYIQ(bgHex);
}
if (fgHsl) {
const textHex = hslToHex(...fgHsl);
document.documentElement.style.setProperty("--text", textHex);
document.documentElement.style.setProperty("--text-primary", textHex);
document.documentElement.style.setProperty(
"--text-secondary",
textHex,
);
document.documentElement.style.setProperty("--text-muted", textHex);
document.documentElement.style.setProperty(
"--primary-fg",
`hsl(${foreground})`,
);
} else if (bgHsl) {
document.documentElement.style.setProperty(
"--text",
calculatedTextHex,
);
document.documentElement.style.setProperty(
"--text-primary",
calculatedTextHex,
);
document.documentElement.style.setProperty(
"--text-secondary",
calculatedTextHex,
);
document.documentElement.style.setProperty(
"--text-muted",
calculatedTextHex,
);
}
if (cardHsl) {
const surfaceHex = hslToHex(...cardHsl);
document.documentElement.style.setProperty("--surface", surfaceHex);
document.documentElement.style.setProperty(
"--surface-hover",
surfaceHex,
);
document.documentElement.style.setProperty(
"--surface-active",
surfaceHex,
);
document.documentElement.style.setProperty("--card-bg", surfaceHex);
}
if (borderHsl) {
const borderHex = hslToHex(...borderHsl);
document.documentElement.style.setProperty("--border", borderHex);
document.documentElement.style.setProperty(
"--border-light",
borderHex,
);
}
// Check if config.csv already set the primary color, we shouldn't wipe it
// Only update color and suggestion variables if they aren't marked as bot-config
if (
document.documentElement.getAttribute("data-has-bot-colors") !==
"true"
) {
document.documentElement.style.setProperty(
"--chat-color1",
`hsl(${primary})`,
);
document.documentElement.style.setProperty(
"--chat-color2",
`hsl(${card})`,
);
document.documentElement.style.setProperty(
"--suggestion-color",
`hsl(${primary})`,
);
document.documentElement.style.setProperty(
"--suggestion-bg",
`hsl(${card})`,
);
document.documentElement.style.setProperty(
"--color1",
`hsl(${primary})`,
);
document.documentElement.style.setProperty(
"--color2",
`hsl(${card})`,
);
}
console.log("✓ Theme colors applied:", {
bg: background,
primary: primary,
});
updateDropdown();
// Fix theme dropdown background to use surface color
const themeDropdown = document.getElementById("themeDropdown");
if (themeDropdown) {
const surfaceColor = getComputedStyle(document.documentElement)
.getPropertyValue("--surface")
.trim();
if (surfaceColor) {
themeDropdown.style.setProperty(
"background",
surfaceColor,
"important",
);
}
}
subscribers.forEach((cb) => cb({ themeId: id, themeName: theme.name }));
}, 50);
};
link.onerror = () => console.error("✗ Failed:", theme.name);
document.head.appendChild(link);
}
function updateDropdown() {
const dd = document.getElementById("themeDropdown");
if (dd) dd.value = currentThemeId;
const select = document.getElementById("themeDropdown");
if (select) select.value = currentThemeId;
}
function createDropdown() {
@ -87,33 +307,96 @@ const ThemeManager = (() => {
}
function init() {
let saved = localStorage.getItem("gb-theme") || "default";
// Ensure data-theme is set on html element so CSS selectors work
if (!document.documentElement.getAttribute("data-theme")) {
document.documentElement.setAttribute("data-theme", "sentient");
}
// First, load saved bot theme from config.csv (if available)
loadSavedTheme();
// Then load the UI theme (CSS theme)
// Priority: 1) localStorage user preference, 2) bot-specific theme, 3) default
const botId = getCurrentBotId();
let saved = localStorage.getItem(`gb-theme-${botId}`);
if (!saved || !themes.find((t) => t.id === saved)) {
// No user preference, try bot-specific theme
saved = botThemeMap[botId] || "light";
// Save to localStorage so it persists
localStorage.setItem(`gb-theme-${botId}`, saved);
}
if (!themes.find((t) => t.id === saved)) saved = "default";
currentThemeId = saved;
loadTheme(saved);
// Dropdown injection restored for the window manager
const container = document.getElementById("themeSelectorContainer");
if (container) container.appendChild(createDropdown());
if (container) {
container.innerHTML = "";
container.appendChild(createDropdown());
}
console.log("✓ Theme Manager initialized");
}
function setThemeFromServer(data) {
// Save theme to localStorage for persistence across page loads
const botId = getCurrentBotId();
localStorage.setItem(`gb-theme-data-${botId}`, JSON.stringify(data));
// Load base theme if specified
if (data.theme_base) {
loadTheme(data.theme_base);
}
if (data.logo_url) {
document
.querySelectorAll(".logo-icon, .assistant-avatar")
.forEach((el) => {
el.style.backgroundImage = `url("${data.logo_url}")`;
});
// For img elements - set src and show, hide SVG
const logoImg = document.querySelector(".logo-icon-img");
const logoSvg = document.querySelector(".logo-icon-svg");
if (logoImg && logoSvg) {
logoImg.src = data.logo_url;
logoImg.alt = data.title || "Logo";
logoImg.style.display = "block";
logoSvg.style.display = "none";
}
// For elements that use background image
document.querySelectorAll(".assistant-avatar").forEach((el) => {
el.style.backgroundImage = `url("${data.logo_url}")`;
el.style.backgroundSize = "contain";
el.style.backgroundRepeat = "no-repeat";
el.style.backgroundPosition = "center";
});
}
if (data.color1) {
document.documentElement.style.setProperty("--color1", data.color1);
}
if (data.color2) {
document.documentElement.style.setProperty("--color2", data.color2);
}
if (data.title) document.title = data.title;
if (data.logo_text) {
document.querySelectorAll(".logo-text").forEach((el) => {
document.querySelectorAll(".logo span, .logo-text").forEach((el) => {
el.textContent = data.logo_text;
});
}
}
// Load saved theme from localStorage on page load
function loadSavedTheme() {
const botId = getCurrentBotId();
const savedTheme = localStorage.getItem(`gb-theme-data-${botId}`);
if (savedTheme) {
try {
const data = JSON.parse(savedTheme);
setThemeFromServer(data);
console.log(`✓ Theme loaded from localStorage for ${botId}`);
} catch (e) {
console.warn("Failed to load saved theme:", e);
}
}
}
function applyCustomizations() {
// Called by modules if needed
}
@ -126,6 +409,7 @@ const ThemeManager = (() => {
init,
loadTheme,
setThemeFromServer,
loadSavedTheme,
applyCustomizations,
subscribe,
getAvailableThemes: () => themes,

83
ui/suite/js/vendor/tailwindcss.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.de",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["Array","Boolescher Wert","Klasse","Konstante","Konstruktor","Enumeration","Enumerationsmember","Ereignis","Feld","Datei","Funktion","Schnittstelle","Schl\xFCssel","Methode","Modul","Namespace","NULL","Zahl","Objekt","Operator","Paket","Eigenschaft","Zeichenfolge","Struktur","Typparameter","Variable","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.de.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.es",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["matriz","booleano","clase","constante","constructor","enumeraci\xF3n","miembro de la enumeraci\xF3n","evento","campo","archivo","funci\xF3n","interfaz","clave","m\xE9todo","m\xF3dulo","espacio de nombres","NULL","n\xFAmero","objeto","operador","paquete","propiedad","cadena","estructura","par\xE1metro de tipo","variable","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.es.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.fr",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["tableau","bool\xE9en","classe","constante","constructeur","\xE9num\xE9ration","membre d'\xE9num\xE9ration","\xE9v\xE9nement","champ","fichier","fonction","interface","cl\xE9","m\xE9thode","module","espace de noms","NULL","nombre","objet","op\xE9rateur","package","propri\xE9t\xE9","cha\xEEne","struct","param\xE8tre de type","variable","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.fr.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.it",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["matrice","valore booleano","classe","costante","costruttore","enumerazione","membro di enumerazione","evento","campo","file","funzione","interfaccia","chiave","metodo","modulo","spazio dei nomi","Null","numero","oggetto","operatore","pacchetto","propriet\xE0","stringa","struct","parametro di tipo","variabile","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.it.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.ja",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["\u914D\u5217","\u30D6\u30FC\u30EB\u5024","\u30AF\u30E9\u30B9","\u5B9A\u6570","\u30B3\u30F3\u30B9\u30C8\u30E9\u30AF\u30BF\u30FC","\u5217\u6319\u578B","\u5217\u6319\u578B\u30E1\u30F3\u30D0\u30FC","\u30A4\u30D9\u30F3\u30C8","\u30D5\u30A3\u30FC\u30EB\u30C9","\u30D5\u30A1\u30A4\u30EB","\u95A2\u6570","\u30A4\u30F3\u30BF\u30FC\u30D5\u30A7\u30A4\u30B9","\u30AD\u30FC","\u30E1\u30BD\u30C3\u30C9","\u30E2\u30B8\u30E5\u30FC\u30EB","\u540D\u524D\u7A7A\u9593","NULL","\u6570\u5024","\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8","\u6F14\u7B97\u5B50","\u30D1\u30C3\u30B1\u30FC\u30B8","\u30D7\u30ED\u30D1\u30C6\u30A3","\u6587\u5B57\u5217","\u69CB\u9020\u4F53","\u578B\u30D1\u30E9\u30E1\u30FC\u30BF\u30FC","\u5909\u6570","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.ja.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["array","boolean","class","constant","constructor","enumeration","enumeration member","event","field","file","function","interface","key","method","module","namespace","null","number","object","operator","package","property","string","struct","type parameter","variable","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.ko",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["\uBC30\uC5F4","\uBD80\uC6B8","\uD074\uB798\uC2A4","\uC0C1\uC218","\uC0DD\uC131\uC790","\uC5F4\uAC70\uD615","\uC5F4\uAC70\uD615 \uBA64\uBC84","\uC774\uBCA4\uD2B8","\uD544\uB4DC","\uD30C\uC77C","\uD568\uC218","\uC778\uD130\uD398\uC774\uC2A4","\uD0A4","\uBA54\uC11C\uB4DC","\uBAA8\uB4C8","\uB124\uC784\uC2A4\uD398\uC774\uC2A4","Null","\uC22B\uC790","\uAC1C\uCCB4","\uC5F0\uC0B0\uC790","\uD328\uD0A4\uC9C0","\uC18D\uC131","\uBB38\uC790\uC5F4","\uAD6C\uC870\uCCB4","\uD615\uC2DD \uB9E4\uAC1C \uBCC0\uC218","\uBCC0\uC218","{0}({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.ko.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.ru",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["\u043C\u0430\u0441\u0441\u0438\u0432","\u043B\u043E\u0433\u0438\u0447\u0435\u0441\u043A\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435","\u043A\u043B\u0430\u0441\u0441","\u043A\u043E\u043D\u0441\u0442\u0430\u043D\u0442\u0430","\u043A\u043E\u043D\u0441\u0442\u0440\u0443\u043A\u0442\u043E\u0440","\u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u0435","\u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u044F","\u0441\u043E\u0431\u044B\u0442\u0438\u0435","\u043F\u043E\u043B\u0435","\u0444\u0430\u0439\u043B","\u0444\u0443\u043D\u043A\u0446\u0438\u044F","\u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441","\u043A\u043B\u044E\u0447","\u043C\u0435\u0442\u043E\u0434","\u043C\u043E\u0434\u0443\u043B\u044C","\u043F\u0440\u043E\u0441\u0442\u0440\u0430\u043D\u0441\u0442\u0432\u043E \u0438\u043C\u0435\u043D","NULL","\u0447\u0438\u0441\u043B\u043E","\u043E\u0431\u044A\u0435\u043A\u0442","\u043E\u043F\u0435\u0440\u0430\u0442\u043E\u0440","\u043F\u0430\u043A\u0435\u0442","\u0441\u0432\u043E\u0439\u0441\u0442\u0432\u043E","\u0441\u0442\u0440\u043E\u043A\u0430","\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430","\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u0442\u0438\u043F\u0430","\u041F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.ru.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.zh-cn",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["\u6570\u7EC4","\u5E03\u5C14\u503C","\u7C7B","\u5E38\u6570","\u6784\u9020\u51FD\u6570","\u679A\u4E3E","\u679A\u4E3E\u6210\u5458","\u4E8B\u4EF6","\u5B57\u6BB5","\u6587\u4EF6","\u51FD\u6570","\u63A5\u53E3","\u952E","\u65B9\u6CD5","\u6A21\u5757","\u547D\u540D\u7A7A\u95F4","Null","\u6570\u5B57","\u5BF9\u8C61","\u8FD0\u7B97\u7B26","\u5305","\u5C5E\u6027","\u5B57\u7B26\u4E32","\u7ED3\u6784","\u7C7B\u578B\u53C2\u6570","\u53D8\u91CF","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.zh-cn.js.map

View file

@ -0,0 +1,8 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/define("vs/base/common/worker/simpleWorker.nls.zh-tw",{"vs/base/common/platform":["_"],"vs/editor/common/languages":["\u9663\u5217","\u5E03\u6797\u503C","\u985E\u5225","\u5E38\u6578","\u5EFA\u69CB\u51FD\u5F0F","\u5217\u8209","\u5217\u8209\u6210\u54E1","\u4E8B\u4EF6","\u6B04\u4F4D","\u6A94\u6848","\u51FD\u5F0F","\u4ECB\u9762","\u7D22\u5F15\u9375","\u65B9\u6CD5","\u6A21\u7D44","\u547D\u540D\u7A7A\u9593","null","\u6578\u5B57","\u7269\u4EF6","\u904B\u7B97\u5B50","\u5957\u4EF6","\u5C6C\u6027","\u5B57\u4E32","\u7D50\u69CB","\u578B\u5225\u53C3\u6578","\u8B8A\u6578","{0} ({1})"]});
//# sourceMappingURL=../../../../../min-maps/vs/base/common/worker/simpleWorker.nls.zh-tw.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/apex/apex", ["require","require"],(require)=>{
var moduleExports=(()=>{var i=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var d=(e,t)=>{for(var s in t)i(e,s,{get:t[s],enumerable:!0})},g=(e,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of c(t))!l.call(e,o)&&o!==s&&i(e,o,{get:()=>t[o],enumerable:!(a=r(t,o))||a.enumerable});return e};var p=e=>g(i({},"__esModule",{value:!0}),e);var h={};d(h,{conf:()=>m,language:()=>b});var m={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"<",close:">"}],folding:{markers:{start:new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:<editor-fold\\b))"),end:new RegExp("^\\s*//\\s*(?:(?:#?endregion\\b)|(?:</editor-fold>))")}}},u=["abstract","activate","and","any","array","as","asc","assert","autonomous","begin","bigdecimal","blob","boolean","break","bulk","by","case","cast","catch","char","class","collect","commit","const","continue","convertcurrency","decimal","default","delete","desc","do","double","else","end","enum","exception","exit","export","extends","false","final","finally","float","for","from","future","get","global","goto","group","having","hint","if","implements","import","in","inner","insert","instanceof","int","interface","into","join","last_90_days","last_month","last_n_days","last_week","like","limit","list","long","loop","map","merge","native","new","next_90_days","next_month","next_n_days","next_week","not","null","nulls","number","object","of","on","or","outer","override","package","parallel","pragma","private","protected","public","retrieve","return","returning","rollback","savepoint","search","select","set","short","sort","stat","static","strictfp","super","switch","synchronized","system","testmethod","then","this","this_month","this_week","throw","throws","today","tolabel","tomorrow","transaction","transient","trigger","true","try","type","undelete","update","upsert","using","virtual","void","volatile","webservice","when","where","while","yesterday"],f=e=>e.charAt(0).toUpperCase()+e.substr(1),n=[];u.forEach(e=>{n.push(e),n.push(e.toUpperCase()),n.push(f(e))});var b={defaultToken:"",tokenPostfix:".apex",keywords:n,operators:["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%","<<",">>",">>>","+=","-=","*=","/=","&=","|=","^=","%=","<<=",">>=",">>>="],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,digits:/\d+(_+\d+)*/,octaldigits:/[0-7]+(_+[0-7]+)*/,binarydigits:/[0-1]+(_+[0-1]+)*/,hexdigits:/[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,tokenizer:{root:[[/[a-z_$][\w$]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],[/[A-Z][\w\$]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"type.identifier"}}],{include:"@whitespace"},[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/@\s*[a-zA-Z_\$][\w\$]*/,"annotation"],[/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/,"number.float"],[/(@digits)[fFdD]/,"number.float"],[/(@digits)[lL]?/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/"/,"string",'@string."'],[/'/,"string","@string.'"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@apexdoc"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],apexdoc:[[/[^\/*]+/,"comment.doc"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"']+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}]]}};return p(h);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/azcli/azcli", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var r=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var c=(t,e)=>{for(var o in e)s(t,o,{get:e[o],enumerable:!0})},k=(t,e,o,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of r(e))!l.call(t,n)&&n!==o&&s(t,n,{get:()=>e[n],enumerable:!(a=i(e,n))||a.enumerable});return t};var p=t=>k(s({},"__esModule",{value:!0}),t);var d={};c(d,{conf:()=>f,language:()=>g});var f={comments:{lineComment:"#"}},g={defaultToken:"keyword",ignoreCase:!0,tokenPostfix:".azcli",str:/[^#\s]/,tokenizer:{root:[{include:"@comment"},[/\s-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":{token:"key.identifier",next:"@type"}}}],[/^-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":{token:"key.identifier",next:"@type"}}}]],type:[{include:"@comment"},[/-+@str*\s*/,{cases:{"@eos":{token:"key.identifier",next:"@popall"},"@default":"key.identifier"}}],[/@str+\s*/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}]],comment:[[/#.*$/,{cases:{"@eos":{token:"comment",next:"@popall"}}}]]}};return p(d);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/bat/bat", ["require","require"],(require)=>{
var moduleExports=(()=>{var n=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var i=Object.prototype.hasOwnProperty;var g=(o,e)=>{for(var t in e)n(o,t,{get:e[t],enumerable:!0})},c=(o,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of l(e))!i.call(o,s)&&s!==t&&n(o,s,{get:()=>e[s],enumerable:!(a=r(e,s))||a.enumerable});return o};var p=o=>c(n({},"__esModule",{value:!0}),o);var k={};g(k,{conf:()=>d,language:()=>m});var d={comments:{lineComment:"REM"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],surroundingPairs:[{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],folding:{markers:{start:new RegExp("^\\s*(::\\s*|REM\\s+)#region"),end:new RegExp("^\\s*(::\\s*|REM\\s+)#endregion")}}},m={defaultToken:"",ignoreCase:!0,tokenPostfix:".bat",brackets:[{token:"delimiter.bracket",open:"{",close:"}"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"delimiter.square",open:"[",close:"]"}],keywords:/call|defined|echo|errorlevel|exist|for|goto|if|pause|set|shift|start|title|not|pushd|popd/,symbols:/[=><!~?&|+\-*\/\^;\.,]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/^(\s*)(rem(?:\s.*|))$/,["","comment"]],[/(\@?)(@keywords)(?!\w)/,[{token:"keyword"},{token:"keyword.$2"}]],[/[ \t\r\n]+/,""],[/setlocal(?!\w)/,"keyword.tag-setlocal"],[/endlocal(?!\w)/,"keyword.tag-setlocal"],[/[a-zA-Z_]\w*/,""],[/:\w*/,"metatag"],[/%[^%]+%/,"variable"],[/%%[\w]+(?!\w)/,"variable"],[/[{}()\[\]]/,"@brackets"],[/@symbols/,"delimiter"],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F_]*[0-9a-fA-F]/,"number.hex"],[/\d+/,"number"],[/[;,.]/,"delimiter"],[/"/,"string",'@string."'],[/'/,"string","@string.'"]],string:[[/[^\\"'%]+/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/%[\w ]+%/,"variable"],[/%%[\w]+(?!\w)/,"variable"],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}],[/$/,"string","@popall"]]}};return p(k);})();
return moduleExports;
});

View file

@ -0,0 +1,11 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/bicep/bicep", ["require","require"],(require)=>{
var moduleExports=(()=>{var r=Object.defineProperty;var s=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var a=Object.prototype.hasOwnProperty;var g=(e,n)=>{for(var o in n)r(e,o,{get:n[o],enumerable:!0})},l=(e,n,o,i)=>{if(n&&typeof n=="object"||typeof n=="function")for(let t of c(n))!a.call(e,t)&&t!==o&&r(e,t,{get:()=>n[t],enumerable:!(i=s(n,t))||i.enumerable});return e};var m=e=>l(r({},"__esModule",{value:!0}),e);var y={};g(y,{conf:()=>$,language:()=>w});var p=e=>`\\b${e}\\b`,k="[_a-zA-Z]",x="[_a-zA-Z0-9]",u=p(`${k}${x}*`),d=["targetScope","resource","module","param","var","output","for","in","if","existing"],b=["true","false","null"],f="[ \\t\\r\\n]",C="[0-9]+",$={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"'",close:"'"},{open:"'''",close:"'''"}],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"'",close:"'",notIn:["string","comment"]},{open:"'''",close:"'''",notIn:["string","comment"]}],autoCloseBefore:`:.,=}])'
`,indentationRules:{increaseIndentPattern:new RegExp("^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$"),decreaseIndentPattern:new RegExp("^((?!.*?\\/\\*).*\\*/)?\\s*[\\}\\]].*$")}},w={defaultToken:"",tokenPostfix:".bicep",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],symbols:/[=><!~?:&|+\-*/^%]+/,keywords:d,namedLiterals:b,escapes:"\\\\(u{[0-9A-Fa-f]+}|n|r|t|\\\\|'|\\${)",tokenizer:{root:[{include:"@expression"},{include:"@whitespace"}],stringVerbatim:[{regex:"(|'|'')[^']",action:{token:"string"}},{regex:"'''",action:{token:"string.quote",next:"@pop"}}],stringLiteral:[{regex:"\\${",action:{token:"delimiter.bracket",next:"@bracketCounting"}},{regex:"[^\\\\'$]+",action:{token:"string"}},{regex:"@escapes",action:{token:"string.escape"}},{regex:"\\\\.",action:{token:"string.escape.invalid"}},{regex:"'",action:{token:"string",next:"@pop"}}],bracketCounting:[{regex:"{",action:{token:"delimiter.bracket",next:"@bracketCounting"}},{regex:"}",action:{token:"delimiter.bracket",next:"@pop"}},{include:"expression"}],comment:[{regex:"[^\\*]+",action:{token:"comment"}},{regex:"\\*\\/",action:{token:"comment",next:"@pop"}},{regex:"[\\/*]",action:{token:"comment"}}],whitespace:[{regex:f},{regex:"\\/\\*",action:{token:"comment",next:"@comment"}},{regex:"\\/\\/.*$",action:{token:"comment"}}],expression:[{regex:"'''",action:{token:"string.quote",next:"@stringVerbatim"}},{regex:"'",action:{token:"string.quote",next:"@stringLiteral"}},{regex:C,action:{token:"number"}},{regex:u,action:{cases:{"@keywords":{token:"keyword"},"@namedLiterals":{token:"keyword"},"@default":{token:"identifier"}}}}]}};return m(y);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/cameligo/cameligo", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var c=(o,e)=>{for(var n in e)s(o,n,{get:e[n],enumerable:!0})},m=(o,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of a(e))!l.call(o,t)&&t!==n&&s(o,t,{get:()=>e[t],enumerable:!(r=i(e,t))||r.enumerable});return o};var p=o=>m(s({},"__esModule",{value:!0}),o);var u={};c(u,{conf:()=>d,language:()=>g});var d={comments:{lineComment:"//",blockComment:["(*","*)"]},brackets:[["{","}"],["[","]"],["(",")"],["<",">"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'},{open:"(*",close:"*)"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'},{open:"(*",close:"*)"}]},g={defaultToken:"",tokenPostfix:".cameligo",ignoreCase:!0,brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],keywords:["abs","assert","block","Bytes","case","Crypto","Current","else","failwith","false","for","fun","if","in","let","let%entry","let%init","List","list","Map","map","match","match%nat","mod","not","operation","Operation","of","record","Set","set","sender","skip","source","String","then","to","true","type","with"],typeKeywords:["int","unit","string","tz","nat","bool"],operators:["=",">","<","<=",">=","<>",":",":=","and","mod","or","+","-","*","/","@","&","^","%","->","<-","&&","||"],symbols:/[=><:@\^&|+\-*\/\^%]+/,tokenizer:{root:[[/[a-zA-Z_][\w]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],{include:"@whitespace"},[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float"],[/\$[0-9a-fA-F]{1,16}/,"number.hex"],[/\d+/,"number"],[/[;,.]/,"delimiter"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/'/,"string","@string"],[/'[^\\']'/,"string"],[/'/,"string.invalid"],[/\#\d+/,"string"]],comment:[[/[^\(\*]+/,"comment"],[/\*\)/,"comment","@pop"],[/\(\*/,"comment"]],string:[[/[^\\']+/,"string"],[/\\./,"string.escape.invalid"],[/'/,{token:"string.quote",bracket:"@close",next:"@pop"}]],whitespace:[[/[ \t\r\n]+/,"white"],[/\(\*/,"comment","@comment"],[/\/\/.*$/,"comment"]]}};return p(u);})();
return moduleExports;
});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/coffee/coffee", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var a=Object.prototype.hasOwnProperty;var l=(n,e)=>{for(var t in e)s(n,t,{get:e[t],enumerable:!0})},p=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of g(e))!a.call(n,r)&&r!==t&&s(n,r,{get:()=>e[r],enumerable:!(o=i(e,r))||o.enumerable});return n};var c=n=>p(s({},"__esModule",{value:!0}),n);var m={};l(m,{conf:()=>d,language:()=>x});var d={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\@\#%\^\&\*\(\)\=\$\-\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{blockComment:["###","###"],lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*#region\\b"),end:new RegExp("^\\s*#endregion\\b")}}},x={defaultToken:"",ignoreCase:!0,tokenPostfix:".coffee",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],regEx:/\/(?!\/\/)(?:[^\/\\]|\\.)*\/[igm]*/,keywords:["and","or","is","isnt","not","on","yes","@","no","off","true","false","null","this","new","delete","typeof","in","instanceof","return","throw","break","continue","debugger","if","else","switch","for","while","do","try","catch","finally","class","extends","super","undefined","then","unless","until","loop","of","by","when"],symbols:/[=><!~?&%|+\-*\/\^\.,\:]+/,escapes:/\\(?:[abfnrtv\\"'$]|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/\@[a-zA-Z_]\w*/,"variable.predefined"],[/[a-zA-Z_]\w*/,{cases:{this:"variable.predefined","@keywords":{token:"keyword.$0"},"@default":""}}],[/[ \t\r\n]+/,""],[/###/,"comment","@comment"],[/#.*$/,"comment"],["///",{token:"regexp",next:"@hereregexp"}],[/^(\s*)(@regEx)/,["","regexp"]],[/(\()(\s*)(@regEx)/,["@brackets","","regexp"]],[/(\,)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\=)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\:)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\[)(\s*)(@regEx)/,["@brackets","","regexp"]],[/(\!)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\&)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\|)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\?)(\s*)(@regEx)/,["delimiter","","regexp"]],[/(\{)(\s*)(@regEx)/,["@brackets","","regexp"]],[/(\;)(\s*)(@regEx)/,["","","regexp"]],[/}/,{cases:{"$S2==interpolatedstring":{token:"string",next:"@pop"},"@default":"@brackets"}}],[/[{}()\[\]]/,"@brackets"],[/@symbols/,"delimiter"],[/\d+[eE]([\-+]?\d+)?/,"number.float"],[/\d+\.\d+([eE][\-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F]+/,"number.hex"],[/0[0-7]+(?!\d)/,"number.octal"],[/\d+/,"number"],[/[,.]/,"delimiter"],[/"""/,"string",'@herestring."""'],[/'''/,"string","@herestring.'''"],[/"/,{cases:{"@eos":"string","@default":{token:"string",next:'@string."'}}}],[/'/,{cases:{"@eos":"string","@default":{token:"string",next:"@string.'"}}}]],string:[[/[^"'\#\\]+/,"string"],[/@escapes/,"string.escape"],[/\./,"string.escape.invalid"],[/\./,"string.escape.invalid"],[/#{/,{cases:{'$S2=="':{token:"string",next:"root.interpolatedstring"},"@default":"string"}}],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}],[/#/,"string"]],herestring:[[/("""|''')/,{cases:{"$1==$S2":{token:"string",next:"@pop"},"@default":"string"}}],[/[^#\\'"]+/,"string"],[/['"]+/,"string"],[/@escapes/,"string.escape"],[/\./,"string.escape.invalid"],[/#{/,{token:"string.quote",next:"root.interpolatedstring"}],[/#/,"string"]],comment:[[/[^#]+/,"comment"],[/###/,"comment","@pop"],[/#/,"comment"]],hereregexp:[[/[^\\\/#]+/,"regexp"],[/\\./,"regexp"],[/#.*$/,"comment"],["///[igm]*",{token:"regexp",next:"@pop"}],[/\//,"regexp"]]}};return c(m);})();
return moduleExports;
});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/csharp/csharp", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var l=(t,e)=>{for(var o in e)s(t,o,{get:e[o],enumerable:!0})},p=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of a(e))!c.call(t,n)&&n!==o&&s(t,n,{get:()=>e[n],enumerable:!(i=r(e,n))||i.enumerable});return t};var g=t=>p(s({},"__esModule",{value:!0}),t);var u={};l(u,{conf:()=>d,language:()=>m});var d={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"'",close:"'",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"<",close:">"},{open:"'",close:"'"},{open:'"',close:'"'}],folding:{markers:{start:new RegExp("^\\s*#region\\b"),end:new RegExp("^\\s*#endregion\\b")}}},m={defaultToken:"",tokenPostfix:".cs",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],keywords:["extern","alias","using","bool","decimal","sbyte","byte","short","ushort","int","uint","long","ulong","char","float","double","object","dynamic","string","assembly","is","as","ref","out","this","base","new","typeof","void","checked","unchecked","default","delegate","var","const","if","else","switch","case","while","do","for","foreach","in","break","continue","goto","return","throw","try","catch","finally","lock","yield","from","let","where","join","on","equals","into","orderby","ascending","descending","select","group","by","namespace","partial","class","field","event","method","param","public","protected","internal","private","abstract","sealed","static","struct","readonly","volatile","virtual","override","params","get","set","add","remove","operator","true","false","implicit","explicit","interface","enum","null","async","await","fixed","sizeof","stackalloc","unsafe","nameof","when"],namespaceFollows:["namespace","using"],parenFollows:["if","for","while","switch","foreach","using","catch","when"],operators:["=","??","||","&&","|","^","&","==","!=","<=",">=","<<","+","-","*","/","%","!","~","++","--","+=","-=","*=","/=","%=","&=","|=","^=","<<=",">>=",">>","=>"],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/\@?[a-zA-Z_]\w*/,{cases:{"@namespaceFollows":{token:"keyword.$0",next:"@namespace"},"@keywords":{token:"keyword.$0",next:"@qualified"},"@default":{token:"identifier",next:"@qualified"}}}],{include:"@whitespace"},[/}/,{cases:{"$S2==interpolatedstring":{token:"string.quote",next:"@pop"},"$S2==litinterpstring":{token:"string.quote",next:"@pop"},"@default":"@brackets"}}],[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/[0-9_]*\.[0-9_]+([eE][\-+]?\d+)?[fFdD]?/,"number.float"],[/0[xX][0-9a-fA-F_]+/,"number.hex"],[/0[bB][01_]+/,"number.hex"],[/[0-9_]+/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,{token:"string.quote",next:"@string"}],[/\$\@"/,{token:"string.quote",next:"@litinterpstring"}],[/\@"/,{token:"string.quote",next:"@litstring"}],[/\$"/,{token:"string.quote",next:"@interpolatedstring"}],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],qualified:[[/[a-zA-Z_][\w]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],[/\./,"delimiter"],["","","@pop"]],namespace:[{include:"@whitespace"},[/[A-Z]\w*/,"namespace"],[/[\.=]/,"delimiter"],["","","@pop"]],comment:[[/[^\/*]+/,"comment"],["\\*/","comment","@pop"],[/[\/*]/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,{token:"string.quote",next:"@pop"}]],litstring:[[/[^"]+/,"string"],[/""/,"string.escape"],[/"/,{token:"string.quote",next:"@pop"}]],litinterpstring:[[/[^"{]+/,"string"],[/""/,"string.escape"],[/{{/,"string.escape"],[/}}/,"string.escape"],[/{/,{token:"string.quote",next:"root.litinterpstring"}],[/"/,{token:"string.quote",next:"@pop"}]],interpolatedstring:[[/[^\\"{]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/{{/,"string.escape"],[/}}/,"string.escape"],[/{/,{token:"string.quote",next:"root.interpolatedstring"}],[/"/,{token:"string.quote",next:"@pop"}]],whitespace:[[/^[ \t\v\f]*#((r)|(load))(?=\s)/,"directive.csx"],[/^[ \t\v\f]*#\w.*$/,"namespace.cpp"],[/[ \t\v\f\r\n]+/,""],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]]}};return g(u);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/csp/csp", ["require","require"],(require)=>{
var moduleExports=(()=>{var o=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var a=(r,t)=>{for(var s in t)o(r,s,{get:t[s],enumerable:!0})},c=(r,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of u(t))!g.call(r,e)&&e!==s&&o(r,e,{get:()=>t[e],enumerable:!(n=i(t,e))||n.enumerable});return r};var q=r=>c(o({},"__esModule",{value:!0}),r);var p={};a(p,{conf:()=>f,language:()=>l});var f={brackets:[],autoClosingPairs:[],surroundingPairs:[]},l={keywords:[],typeKeywords:[],tokenPostfix:".csp",operators:[],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/child-src/,"string.quote"],[/connect-src/,"string.quote"],[/default-src/,"string.quote"],[/font-src/,"string.quote"],[/frame-src/,"string.quote"],[/img-src/,"string.quote"],[/manifest-src/,"string.quote"],[/media-src/,"string.quote"],[/object-src/,"string.quote"],[/script-src/,"string.quote"],[/style-src/,"string.quote"],[/worker-src/,"string.quote"],[/base-uri/,"string.quote"],[/plugin-types/,"string.quote"],[/sandbox/,"string.quote"],[/disown-opener/,"string.quote"],[/form-action/,"string.quote"],[/frame-ancestors/,"string.quote"],[/report-uri/,"string.quote"],[/report-to/,"string.quote"],[/upgrade-insecure-requests/,"string.quote"],[/block-all-mixed-content/,"string.quote"],[/require-sri-for/,"string.quote"],[/reflected-xss/,"string.quote"],[/referrer/,"string.quote"],[/policy-uri/,"string.quote"],[/'self'/,"string.quote"],[/'unsafe-inline'/,"string.quote"],[/'unsafe-eval'/,"string.quote"],[/'strict-dynamic'/,"string.quote"],[/'unsafe-hashed-attributes'/,"string.quote"]]}};return q(p);})();
return moduleExports;
});

View file

@ -0,0 +1,12 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/css/css", ["require","require"],(require)=>{
var moduleExports=(()=>{var r=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var s=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var m=(t,e)=>{for(var o in e)r(t,o,{get:e[o],enumerable:!0})},c=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of s(e))!l.call(t,n)&&n!==o&&r(t,n,{get:()=>e[n],enumerable:!(i=a(e,n))||i.enumerable});return t};var d=t=>c(r({},"__esModule",{value:!0}),t);var k={};m(k,{conf:()=>u,language:()=>p});var u={wordPattern:/(#?-?\d*\.\d\w*%?)|((::|[@#.!:])?[\w-?]+%?)|::|[@#.!:]/g,comments:{blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\/"),end:new RegExp("^\\s*\\/\\*\\s*#endregion\\b.*\\*\\/")}}},p={defaultToken:"",tokenPostfix:".css",ws:`[
\r\f]*`,identifier:"-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",brackets:[{open:"{",close:"}",token:"delimiter.bracket"},{open:"[",close:"]",token:"delimiter.bracket"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],tokenizer:{root:[{include:"@selector"}],selector:[{include:"@comments"},{include:"@import"},{include:"@strings"},["[@](keyframes|-webkit-keyframes|-moz-keyframes|-o-keyframes)",{token:"keyword",next:"@keyframedeclaration"}],["[@](page|content|font-face|-moz-document)",{token:"keyword"}],["[@](charset|namespace)",{token:"keyword",next:"@declarationbody"}],["(url-prefix)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],["(url)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],{include:"@selectorname"},["[\\*]","tag"],["[>\\+,]","delimiter"],["\\[",{token:"delimiter.bracket",next:"@selectorattribute"}],["{",{token:"delimiter.bracket",next:"@selectorbody"}]],selectorbody:[{include:"@comments"},["[*_]?@identifier@ws:(?=(\\s|\\d|[^{;}]*[;}]))","attribute.name","@rulevalue"],["}",{token:"delimiter.bracket",next:"@pop"}]],selectorname:[["(\\.|#(?=[^{])|%|(@identifier)|:)+","tag"]],selectorattribute:[{include:"@term"},["]",{token:"delimiter.bracket",next:"@pop"}]],term:[{include:"@comments"},["(url-prefix)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],["(url)(\\()",["attribute.value",{token:"delimiter.parenthesis",next:"@urldeclaration"}]],{include:"@functioninvocation"},{include:"@numbers"},{include:"@name"},{include:"@strings"},["([<>=\\+\\-\\*\\/\\^\\|\\~,])","delimiter"],[",","delimiter"]],rulevalue:[{include:"@comments"},{include:"@strings"},{include:"@term"},["!important","keyword"],[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],warndebug:[["[@](warn|debug)",{token:"keyword",next:"@declarationbody"}]],import:[["[@](import)",{token:"keyword",next:"@declarationbody"}]],urldeclaration:[{include:"@strings"},[`[^)\r
]+`,"string"],["\\)",{token:"delimiter.parenthesis",next:"@pop"}]],parenthizedterm:[{include:"@term"},["\\)",{token:"delimiter.parenthesis",next:"@pop"}]],declarationbody:[{include:"@term"},[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[/[^*/]+/,"comment"],[/./,"comment"]],name:[["@identifier","attribute.value"]],numbers:[["-?(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?",{token:"attribute.value.number",next:"@units"}],["#[0-9a-fA-F_]+(?!\\w)","attribute.value.hex"]],units:[["(em|ex|ch|rem|fr|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?","attribute.value.unit","@pop"]],keyframedeclaration:[["@identifier","attribute.value"],["{",{token:"delimiter.bracket",switchTo:"@keyframebody"}]],keyframebody:[{include:"@term"},["{",{token:"delimiter.bracket",next:"@selectorbody"}],["}",{token:"delimiter.bracket",next:"@pop"}]],functioninvocation:[["@identifier\\(",{token:"attribute.value",next:"@functionarguments"}]],functionarguments:[["\\$@identifier@ws:","attribute.name"],["[,]","delimiter"],{include:"@term"},["\\)",{token:"attribute.value",next:"@pop"}]],strings:[['~?"',{token:"string",next:"@stringenddoublequote"}],["~?'",{token:"string",next:"@stringendquote"}]],stringenddoublequote:[["\\\\.","string"],['"',{token:"string",next:"@pop"}],[/[^\\"]+/,"string"],[".","string"]],stringendquote:[["\\\\.","string"],["'",{token:"string",next:"@pop"}],[/[^\\']+/,"string"],[".","string"]]}};return d(k);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/cypher/cypher", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var c=(i,e)=>{for(var n in e)s(i,n,{get:e[n],enumerable:!0})},g=(i,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of a(e))!l.call(i,t)&&t!==n&&s(i,t,{get:()=>e[t],enumerable:!(o=r(e,t))||o.enumerable});return i};var p=i=>g(s({},"__esModule",{value:!0}),i);var u={};c(u,{conf:()=>d,language:()=>m});var d={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"`",close:"`"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"`",close:"`"}]},m={defaultToken:"",tokenPostfix:".cypher",ignoreCase:!0,brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.bracket"},{open:"(",close:")",token:"delimiter.parenthesis"}],keywords:["ALL","AND","AS","ASC","ASCENDING","BY","CALL","CASE","CONTAINS","CREATE","DELETE","DESC","DESCENDING","DETACH","DISTINCT","ELSE","END","ENDS","EXISTS","IN","IS","LIMIT","MANDATORY","MATCH","MERGE","NOT","ON","ON","OPTIONAL","OR","ORDER","REMOVE","RETURN","SET","SKIP","STARTS","THEN","UNION","UNWIND","WHEN","WHERE","WITH","XOR","YIELD"],builtinLiterals:["true","TRUE","false","FALSE","null","NULL"],builtinFunctions:["abs","acos","asin","atan","atan2","avg","ceil","coalesce","collect","cos","cot","count","degrees","e","endNode","exists","exp","floor","head","id","keys","labels","last","left","length","log","log10","lTrim","max","min","nodes","percentileCont","percentileDisc","pi","properties","radians","rand","range","relationships","replace","reverse","right","round","rTrim","sign","sin","size","split","sqrt","startNode","stDev","stDevP","substring","sum","tail","tan","timestamp","toBoolean","toFloat","toInteger","toLower","toString","toUpper","trim","type"],operators:["+","-","*","/","%","^","=","<>","<",">","<=",">=","->","<-","-->","<--"],escapes:/\\(?:[tbnrf\\"'`]|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,digits:/\d+/,octaldigits:/[0-7]+/,hexdigits:/[0-9a-fA-F]+/,tokenizer:{root:[[/[{}[\]()]/,"@brackets"],{include:"common"}],common:[{include:"@whitespace"},{include:"@numbers"},{include:"@strings"},[/:[a-zA-Z_][\w]*/,"type.identifier"],[/[a-zA-Z_][\w]*(?=\()/,{cases:{"@builtinFunctions":"predefined.function"}}],[/[a-zA-Z_$][\w$]*/,{cases:{"@keywords":"keyword","@builtinLiterals":"predefined.literal","@default":"identifier"}}],[/`/,"identifier.escape","@identifierBacktick"],[/[;,.:|]/,"delimiter"],[/[<>=%+\-*/^]+/,{cases:{"@operators":"delimiter","@default":""}}]],numbers:[[/-?(@digits)[eE](-?(@digits))?/,"number.float"],[/-?(@digits)?\.(@digits)([eE]-?(@digits))?/,"number.float"],[/-?0x(@hexdigits)/,"number.hex"],[/-?0(@octaldigits)/,"number.octal"],[/-?(@digits)/,"number"]],strings:[[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/"/,"string","@stringDouble"],[/'/,"string","@stringSingle"]],whitespace:[[/[ \t\r\n]+/,"white"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/\/\/.*/,"comment"],[/[^/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[/*]/,"comment"]],stringDouble:[[/[^\\"]+/,"string"],[/@escapes/,"string"],[/\\./,"string.invalid"],[/"/,"string","@pop"]],stringSingle:[[/[^\\']+/,"string"],[/@escapes/,"string"],[/\\./,"string.invalid"],[/'/,"string","@pop"]],identifierBacktick:[[/[^\\`]+/,"identifier.escape"],[/@escapes/,"identifier.escape"],[/\\./,"identifier.escape.invalid"],[/`/,"identifier.escape","@pop"]]}};return p(u);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/dart/dart", ["require","require"],(require)=>{
var moduleExports=(()=>{var r=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var a=Object.prototype.hasOwnProperty;var p=(n,e)=>{for(var t in e)r(n,t,{get:e[t],enumerable:!0})},g=(n,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of c(e))!a.call(n,o)&&o!==t&&r(n,o,{get:()=>e[o],enumerable:!(s=i(e,o))||s.enumerable});return n};var l=n=>g(r({},"__esModule",{value:!0}),n);var x={};p(x,{conf:()=>d,language:()=>m});var d={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"'",close:"'",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string"]},{open:"`",close:"`",notIn:["string","comment"]},{open:"/**",close:" */",notIn:["string"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"<",close:">"},{open:"'",close:"'"},{open:"(",close:")"},{open:'"',close:'"'},{open:"`",close:"`"}],folding:{markers:{start:/^\s*\s*#?region\b/,end:/^\s*\s*#?endregion\b/}}},m={defaultToken:"invalid",tokenPostfix:".dart",keywords:["abstract","dynamic","implements","show","as","else","import","static","assert","enum","in","super","async","export","interface","switch","await","extends","is","sync","break","external","library","this","case","factory","mixin","throw","catch","false","new","true","class","final","null","try","const","finally","on","typedef","continue","for","operator","var","covariant","Function","part","void","default","get","rethrow","while","deferred","hide","return","with","do","if","set","yield"],typeKeywords:["int","double","String","bool"],operators:["+","-","*","/","~/","%","++","--","==","!=",">","<",">=","<=","=","-=","/=","%=",">>=","^=","+=","*=","~/=","<<=","&=","!=","||","&&","&","|","^","~","<<",">>","!",">>>","??","?",":","|="],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,digits:/\d+(_+\d+)*/,octaldigits:/[0-7]+(_+[0-7]+)*/,binarydigits:/[0-1]+(_+[0-1]+)*/,hexdigits:/[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,regexpctl:/[(){}\[\]\$\^|\-*+?\.]/,regexpesc:/\\(?:[bBdDfnrstvwWn0\\\/]|@regexpctl|c[A-Z]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})/,tokenizer:{root:[[/[{}]/,"delimiter.bracket"],{include:"common"}],common:[[/[a-z_$][\w$]*/,{cases:{"@typeKeywords":"type.identifier","@keywords":"keyword","@default":"identifier"}}],[/[A-Z_$][\w\$]*/,"type.identifier"],{include:"@whitespace"},[/\/(?=([^\\\/]|\\.)+\/([gimsuy]*)(\s*)(\.|;|,|\)|\]|\}|$))/,{token:"regexp",bracket:"@open",next:"@regexp"}],[/@[a-zA-Z]+/,"annotation"],[/[()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/!(?=([^=]|$))/,"delimiter"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/(@digits)[eE]([\-+]?(@digits))?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?/,"number.float"],[/0[xX](@hexdigits)n?/,"number.hex"],[/0[oO]?(@octaldigits)n?/,"number.octal"],[/0[bB](@binarydigits)n?/,"number.binary"],[/(@digits)n?/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string_double"],[/'/,"string","@string_single"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@jsdoc"],[/\/\*/,"comment","@comment"],[/\/\/\/.*$/,"comment.doc"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],jsdoc:[[/[^\/*]+/,"comment.doc"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],regexp:[[/(\{)(\d+(?:,\d*)?)(\})/,["regexp.escape.control","regexp.escape.control","regexp.escape.control"]],[/(\[)(\^?)(?=(?:[^\]\\\/]|\\.)+)/,["regexp.escape.control",{token:"regexp.escape.control",next:"@regexrange"}]],[/(\()(\?:|\?=|\?!)/,["regexp.escape.control","regexp.escape.control"]],[/[()]/,"regexp.escape.control"],[/@regexpctl/,"regexp.escape.control"],[/[^\\\/]/,"regexp"],[/@regexpesc/,"regexp.escape"],[/\\\./,"regexp.invalid"],[/(\/)([gimsuy]*)/,[{token:"regexp",bracket:"@close",next:"@pop"},"keyword.other"]]],regexrange:[[/-/,"regexp.escape.control"],[/\^/,"regexp.invalid"],[/@regexpesc/,"regexp.escape"],[/[^\]]/,"regexp"],[/\]/,{token:"regexp.escape.control",next:"@pop",bracket:"@close"}]],string_double:[[/[^\\"\$]+/,"string"],[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"],[/\$\w+/,"identifier"]],string_single:[[/[^\\'\$]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/'/,"string","@pop"],[/\$\w+/,"identifier"]]}};return l(x);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/dockerfile/dockerfile", ["require","require"],(require)=>{
var moduleExports=(()=>{var a=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var r=Object.getOwnPropertyNames;var i=Object.prototype.hasOwnProperty;var p=(o,e)=>{for(var s in e)a(o,s,{get:e[s],enumerable:!0})},g=(o,e,s,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of r(e))!i.call(o,n)&&n!==s&&a(o,n,{get:()=>e[n],enumerable:!(t=l(e,n))||t.enumerable});return o};var c=o=>g(a({},"__esModule",{value:!0}),o);var k={};p(k,{conf:()=>u,language:()=>d});var u={brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},d={defaultToken:"",tokenPostfix:".dockerfile",variable:/\${?[\w]+}?/,tokenizer:{root:[{include:"@whitespace"},{include:"@comment"},[/(ONBUILD)(\s+)/,["keyword",""]],[/(ENV)(\s+)([\w]+)/,["keyword","",{token:"variable",next:"@arguments"}]],[/(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|ARG|VOLUME|LABEL|USER|WORKDIR|COPY|CMD|STOPSIGNAL|SHELL|HEALTHCHECK|ENTRYPOINT)/,{token:"keyword",next:"@arguments"}]],arguments:[{include:"@whitespace"},{include:"@strings"},[/(@variable)/,{cases:{"@eos":{token:"variable",next:"@popall"},"@default":"variable"}}],[/\\/,{cases:{"@eos":"","@default":""}}],[/./,{cases:{"@eos":{token:"",next:"@popall"},"@default":""}}]],whitespace:[[/\s+/,{cases:{"@eos":{token:"",next:"@popall"},"@default":""}}]],comment:[[/(^#.*$)/,"comment","@popall"]],strings:[[/\\'$/,"","@popall"],[/\\'/,""],[/'$/,"string","@popall"],[/'/,"string","@stringBody"],[/"$/,"string","@popall"],[/"/,"string","@dblStringBody"]],stringBody:[[/[^\\\$']/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/\\./,"string.escape"],[/'$/,"string","@popall"],[/'/,"string","@pop"],[/(@variable)/,"variable"],[/\\$/,"string"],[/$/,"string","@popall"]],dblStringBody:[[/[^\\\$"]/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/\\./,"string.escape"],[/"$/,"string","@popall"],[/"/,"string","@pop"],[/(@variable)/,"variable"],[/\\$/,"string"],[/$/,"string","@popall"]]}};return c(k);})();
return moduleExports;
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/flow9/flow9", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var c=(o,e)=>{for(var t in e)s(o,t,{get:e[t],enumerable:!0})},m=(o,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of a(e))!l.call(o,n)&&n!==t&&s(o,n,{get:()=>e[n],enumerable:!(i=r(e,n))||i.enumerable});return o};var p=o=>m(s({},"__esModule",{value:!0}),o);var u={};c(u,{conf:()=>g,language:()=>f});var g={comments:{blockComment:["/*","*/"],lineComment:"//"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string"]},{open:"[",close:"]",notIn:["string"]},{open:"(",close:")",notIn:["string"]},{open:'"',close:'"',notIn:["string"]},{open:"'",close:"'",notIn:["string"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"<",close:">"}]},f={defaultToken:"",tokenPostfix:".flow",keywords:["import","require","export","forbid","native","if","else","cast","unsafe","switch","default"],types:["io","mutable","bool","int","double","string","flow","void","ref","true","false","with"],operators:["=",">","<","<=",">=","==","!","!=",":=","::=","&&","||","+","-","*","/","@","&","%",":","->","\\","$","??","^"],symbols:/[@$=><!~?:&|+\-*\\\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/[a-zA-Z_]\w*/,{cases:{"@keywords":"keyword","@types":"type","@default":"identifier"}}],{include:"@whitespace"},[/[{}()\[\]]/,"delimiter"],[/[<>](?!@symbols)/,"delimiter"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/((0(x|X)[0-9a-fA-F]*)|(([0-9]+\.?[0-9]*)|(\.[0-9]+))((e|E)(\+|-)?[0-9]+)?)/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]]}};return p(u);})();
return moduleExports;
});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/fsharp/fsharp", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var c=(n,e)=>{for(var o in e)s(n,o,{get:e[o],enumerable:!0})},g=(n,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of a(e))!l.call(n,t)&&t!==o&&s(n,t,{get:()=>e[t],enumerable:!(i=r(e,t))||i.enumerable});return n};var f=n=>g(s({},"__esModule",{value:!0}),n);var d={};c(d,{conf:()=>m,language:()=>u});var m={comments:{lineComment:"//",blockComment:["(*","*)"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*//\\s*#region\\b|^\\s*\\(\\*\\s*#region(.*)\\*\\)"),end:new RegExp("^\\s*//\\s*#endregion\\b|^\\s*\\(\\*\\s*#endregion\\s*\\*\\)")}}},u={defaultToken:"",tokenPostfix:".fs",keywords:["abstract","and","atomic","as","assert","asr","base","begin","break","checked","component","const","constraint","constructor","continue","class","default","delegate","do","done","downcast","downto","elif","else","end","exception","eager","event","external","extern","false","finally","for","fun","function","fixed","functor","global","if","in","include","inherit","inline","interface","internal","land","lor","lsl","lsr","lxor","lazy","let","match","member","mod","module","mutable","namespace","method","mixin","new","not","null","of","open","or","object","override","private","parallel","process","protected","pure","public","rec","return","static","sealed","struct","sig","then","to","true","tailcall","trait","try","type","upcast","use","val","void","virtual","volatile","when","while","with","yield"],symbols:/[=><!~?:&|+\-*\^%;\.,\/]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,integersuffix:/[uU]?[yslnLI]?/,floatsuffix:/[fFmM]?/,tokenizer:{root:[[/[a-zA-Z_]\w*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],{include:"@whitespace"},[/\[<.*>\]/,"annotation"],[/^#(if|else|endif)/,"keyword"],[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,"delimiter"],[/\d*\d+[eE]([\-+]?\d+)?(@floatsuffix)/,"number.float"],[/\d*\.\d+([eE][\-+]?\d+)?(@floatsuffix)/,"number.float"],[/0x[0-9a-fA-F]+LF/,"number.float"],[/0x[0-9a-fA-F]+(@integersuffix)/,"number.hex"],[/0b[0-1]+(@integersuffix)/,"number.bin"],[/\d+(@integersuffix)/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"""/,"string",'@string."""'],[/"/,"string",'@string."'],[/\@"/,{token:"string.quote",next:"@litstring"}],[/'[^\\']'B?/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\(\*(?!\))/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^*(]+/,"comment"],[/\*\)/,"comment","@pop"],[/\*/,"comment"],[/\(\*\)/,"comment"],[/\(/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/("""|"B?)/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}]],litstring:[[/[^"]+/,"string"],[/""/,"string.escape"],[/"/,{token:"string.quote",next:"@pop"}]]}};return f(d);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/go/go", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var m=(n,e)=>{for(var t in e)s(n,t,{get:e[t],enumerable:!0})},l=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of a(e))!c.call(n,o)&&o!==t&&s(n,o,{get:()=>e[o],enumerable:!(r=i(e,o))||r.enumerable});return n};var g=n=>l(s({},"__esModule",{value:!0}),n);var d={};m(d,{conf:()=>p,language:()=>u});var p={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"`",close:"`",notIn:["string"]},{open:'"',close:'"',notIn:["string"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"`",close:"`"},{open:'"',close:'"'},{open:"'",close:"'"}]},u={defaultToken:"",tokenPostfix:".go",keywords:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var","bool","true","false","uint8","uint16","uint32","uint64","int8","int16","int32","int64","float32","float64","complex64","complex128","byte","rune","uint","int","uintptr","string","nil"],operators:["+","-","*","/","%","&","|","^","<<",">>","&^","+=","-=","*=","/=","%=","&=","|=","^=","<<=",">>=","&^=","&&","||","<-","++","--","==","<",">","=","!","!=","<=",">=",":=","...","(",")","","]","{","}",",",";",".",":"],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/[a-zA-Z_]\w*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],{include:"@whitespace"},[/\[\[.*\]\]/,"annotation"],[/^\s*#\w+/,"keyword"],[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/\d*\d+[eE]([\-+]?\d+)?/,"number.float"],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F']*[0-9a-fA-F]/,"number.hex"],[/0[0-7']*[0-7]/,"number.octal"],[/0[bB][0-1']*[0-1]/,"number.binary"],[/\d[\d']*/,"number"],[/\d/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"],[/`/,"string","@rawstring"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@doccomment"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],doccomment:[[/[^\/*]+/,"comment.doc"],[/\/\*/,"comment.doc.invalid"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],rawstring:[[/[^\`]/,"string"],[/`/,"string","@pop"]]}};return g(d);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/graphql/graphql", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var c=(n,e)=>{for(var t in e)s(n,t,{get:e[t],enumerable:!0})},d=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of i(e))!l.call(n,o)&&o!==t&&s(n,o,{get:()=>e[o],enumerable:!(r=a(e,o))||r.enumerable});return n};var p=n=>d(s({},"__esModule",{value:!0}),n);var u={};c(u,{conf:()=>g,language:()=>I});var g={comments:{lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"""',close:'"""',notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"""',close:'"""'},{open:'"',close:'"'}],folding:{offSide:!0}},I={defaultToken:"invalid",tokenPostfix:".gql",keywords:["null","true","false","query","mutation","subscription","extend","schema","directive","scalar","type","interface","union","enum","input","implements","fragment","on"],typeKeywords:["Int","Float","String","Boolean","ID"],directiveLocations:["SCHEMA","SCALAR","OBJECT","FIELD_DEFINITION","ARGUMENT_DEFINITION","INTERFACE","UNION","ENUM","ENUM_VALUE","INPUT_OBJECT","INPUT_FIELD_DEFINITION","QUERY","MUTATION","SUBSCRIPTION","FIELD","FRAGMENT_DEFINITION","FRAGMENT_SPREAD","INLINE_FRAGMENT","VARIABLE_DEFINITION"],operators:["=","!","?",":","&","|"],symbols:/[=!?:&|]+/,escapes:/\\(?:["\\\/bfnrt]|u[0-9A-Fa-f]{4})/,tokenizer:{root:[[/[a-z_][\w$]*/,{cases:{"@keywords":"keyword","@default":"key.identifier"}}],[/[$][\w$]*/,{cases:{"@keywords":"keyword","@default":"argument.identifier"}}],[/[A-Z][\w\$]*/,{cases:{"@typeKeywords":"keyword","@default":"type.identifier"}}],{include:"@whitespace"},[/[{}()\[\]]/,"@brackets"],[/@symbols/,{cases:{"@operators":"operator","@default":""}}],[/@\s*[a-zA-Z_\$][\w\$]*/,{token:"annotation",log:"annotation token: $0"}],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float"],[/0[xX][0-9a-fA-F]+/,"number.hex"],[/\d+/,"number"],[/[;,.]/,"delimiter"],[/"""/,{token:"string",next:"@mlstring",nextEmbedded:"markdown"}],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,{token:"string.quote",bracket:"@open",next:"@string"}]],mlstring:[[/[^"]+/,"string"],['"""',{token:"string",next:"@pop",nextEmbedded:"@pop"}]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,{token:"string.quote",bracket:"@close",next:"@pop"}]],whitespace:[[/[ \t\r\n]+/,""],[/#.*$/,"comment"]]}};return p(u);})();
return moduleExports;
});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/hcl/hcl", ["require","require"],(require)=>{
var moduleExports=(()=>{var r=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var l=(t,e)=>{for(var o in e)r(t,o,{get:e[o],enumerable:!0})},d=(t,e,o,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of i(e))!c.call(t,s)&&s!==o&&r(t,s,{get:()=>e[s],enumerable:!(n=a(e,s))||n.enumerable});return t};var m=t=>d(r({},"__esModule",{value:!0}),t);var f={};l(f,{conf:()=>p,language:()=>g});var p={comments:{lineComment:"#",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"',notIn:["string"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}]},g={defaultToken:"",tokenPostfix:".hcl",keywords:["var","local","path","for_each","any","string","number","bool","true","false","null","if ","else ","endif ","for ","in","endfor"],operators:["=",">=","<=","==","!=","+","-","*","/","%","&&","||","!","<",">","?","...",":"],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,terraformFunctions:/(abs|ceil|floor|log|max|min|pow|signum|chomp|format|formatlist|indent|join|lower|regex|regexall|replace|split|strrev|substr|title|trimspace|upper|chunklist|coalesce|coalescelist|compact|concat|contains|distinct|element|flatten|index|keys|length|list|lookup|map|matchkeys|merge|range|reverse|setintersection|setproduct|setunion|slice|sort|transpose|values|zipmap|base64decode|base64encode|base64gzip|csvdecode|jsondecode|jsonencode|urlencode|yamldecode|yamlencode|abspath|dirname|pathexpand|basename|file|fileexists|fileset|filebase64|templatefile|formatdate|timeadd|timestamp|base64sha256|base64sha512|bcrypt|filebase64sha256|filebase64sha512|filemd5|filemd1|filesha256|filesha512|md5|rsadecrypt|sha1|sha256|sha512|uuid|uuidv5|cidrhost|cidrnetmask|cidrsubnet|tobool|tolist|tomap|tonumber|toset|tostring)/,terraformMainBlocks:/(module|data|terraform|resource|provider|variable|output|locals)/,tokenizer:{root:[[/^@terraformMainBlocks([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)(\{)/,["type","","string","","string","","@brackets"]],[/(\w+[ \t]+)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)(\{)/,["identifier","","string","","string","","@brackets"]],[/(\w+[ \t]+)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)(=)(\{)/,["identifier","","string","","operator","","@brackets"]],{include:"@terraform"}],terraform:[[/@terraformFunctions(\()/,["type","@brackets"]],[/[a-zA-Z_]\w*-*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"variable"}}],{include:"@whitespace"},{include:"@heredoc"},[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"operator","@default":""}}],[/\d*\d+[eE]([\-+]?\d+)?/,"number.float"],[/\d*\.\d+([eE][\-+]?\d+)?/,"number.float"],[/\d[\d']*/,"number"],[/\d/,"number"],[/[;,.]/,"delimiter"],[/"/,"string","@string"],[/'/,"invalid"]],heredoc:[[/<<[-]*\s*["]?([\w\-]+)["]?/,{token:"string.heredoc.delimiter",next:"@heredocBody.$1"}]],heredocBody:[[/([\w\-]+)$/,{cases:{"$1==$S2":[{token:"string.heredoc.delimiter",next:"@popall"}],"@default":"string.heredoc"}}],[/./,"string.heredoc"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"],[/#.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],string:[[/\$\{/,{token:"delimiter",next:"@stringExpression"}],[/[^\\"\$]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@popall"]],stringInsideExpression:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],stringExpression:[[/\}/,{token:"delimiter",next:"@pop"}],[/"/,"string","@stringInsideExpression"],{include:"@terraform"}]}};return m(f);})();
return moduleExports;
});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/ini/ini", ["require","require"],(require)=>{
var moduleExports=(()=>{var t=Object.defineProperty;var i=Object.getOwnPropertyDescriptor;var r=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var c=(n,e)=>{for(var s in e)t(n,s,{get:e[s],enumerable:!0})},l=(n,e,s,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of r(e))!g.call(n,o)&&o!==s&&t(n,o,{get:()=>e[o],enumerable:!(a=i(e,o))||a.enumerable});return n};var p=n=>l(t({},"__esModule",{value:!0}),n);var f={};c(f,{conf:()=>u,language:()=>m});var u={comments:{lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},m={defaultToken:"",tokenPostfix:".ini",escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/^\[[^\]]*\]/,"metatag"],[/(^\w+)(\s*)(\=)/,["key","","delimiter"]],{include:"@whitespace"},[/\d+/,"number"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/"/,"string",'@string."'],[/'/,"string","@string.'"]],whitespace:[[/[ \t\r\n]+/,""],[/^\s*[#;].*$/,"comment"]],string:[[/[^\\"']+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":"string"}}]]}};return p(f);})();
return moduleExports;
});

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/java/java", ["require","require"],(require)=>{
var moduleExports=(()=>{var s=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var r=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var l=(t,e)=>{for(var o in e)s(t,o,{get:e[o],enumerable:!0})},d=(t,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of r(e))!c.call(t,n)&&n!==o&&s(t,n,{get:()=>e[n],enumerable:!(i=a(e,n))||i.enumerable});return t};var g=t=>d(s({},"__esModule",{value:!0}),t);var f={};l(f,{conf:()=>m,language:()=>p});var m={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"<",close:">"}],folding:{markers:{start:new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:<editor-fold\\b))"),end:new RegExp("^\\s*//\\s*(?:(?:#?endregion\\b)|(?:</editor-fold>))")}}},p={defaultToken:"",tokenPostfix:".java",keywords:["abstract","continue","for","new","switch","assert","default","goto","package","synchronized","boolean","do","if","private","this","break","double","implements","protected","throw","byte","else","import","public","throws","case","enum","instanceof","return","transient","catch","extends","int","short","try","char","final","interface","static","void","class","finally","long","strictfp","volatile","const","float","native","super","while","true","false","yield","record","sealed","non-sealed","permits"],operators:["=",">","<","!","~","?",":","==","<=",">=","!=","&&","||","++","--","+","-","*","/","&","|","^","%","<<",">>",">>>","+=","-=","*=","/=","&=","|=","^=","%=","<<=",">>=",">>>="],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,digits:/\d+(_+\d+)*/,octaldigits:/[0-7]+(_+[0-7]+)*/,binarydigits:/[0-1]+(_+[0-1]+)*/,hexdigits:/[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,tokenizer:{root:[["non-sealed","keyword.non-sealed"],[/[a-zA-Z_$][\w$]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],{include:"@whitespace"},[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/@\s*[a-zA-Z_\$][\w\$]*/,"annotation"],[/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/,"number.float"],[/0[xX](@hexdigits)[Ll]?/,"number.hex"],[/0(@octaldigits)[Ll]?/,"number.octal"],[/0[bB](@binarydigits)[Ll]?/,"number.binary"],[/(@digits)[fFdD]/,"number.float"],[/(@digits)[lL]?/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"""/,"string","@multistring"],[/"/,"string","@string"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@javadoc"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],javadoc:[[/[^\/*]+/,"comment.doc"],[/\/\*/,"comment.doc.invalid"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],multistring:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"""/,"string","@pop"],[/./,"string"]]}};return g(f);})();
return moduleExports;
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/kotlin/kotlin", ["require","require"],(require)=>{
var moduleExports=(()=>{var o=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var r=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var l=(n,e)=>{for(var i in e)o(n,i,{get:e[i],enumerable:!0})},d=(n,e,i,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of r(e))!c.call(n,t)&&t!==i&&o(n,t,{get:()=>e[t],enumerable:!(s=a(e,t))||s.enumerable});return n};var g=n=>d(o({},"__esModule",{value:!0}),n);var f={};l(f,{conf:()=>m,language:()=>p});var m={wordPattern:/(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"},{open:"<",close:">"}],folding:{markers:{start:new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:<editor-fold\\b))"),end:new RegExp("^\\s*//\\s*(?:(?:#?endregion\\b)|(?:</editor-fold>))")}}},p={defaultToken:"",tokenPostfix:".kt",keywords:["as","as?","break","class","continue","do","else","false","for","fun","if","in","!in","interface","is","!is","null","object","package","return","super","this","throw","true","try","typealias","val","var","when","while","by","catch","constructor","delegate","dynamic","field","file","finally","get","import","init","param","property","receiver","set","setparam","where","actual","abstract","annotation","companion","const","crossinline","data","enum","expect","external","final","infix","inline","inner","internal","lateinit","noinline","open","operator","out","override","private","protected","public","reified","sealed","suspend","tailrec","vararg","field","it"],operators:["+","-","*","/","%","=","+=","-=","*=","/=","%=","++","--","&&","||","!","==","!=","===","!==",">","<","<=",">=","[","]","!!","?.","?:","::","..",":","?","->","@",";","$","_"],symbols:/[=><!~?:&|+\-*\/\^%]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,digits:/\d+(_+\d+)*/,octaldigits:/[0-7]+(_+[0-7]+)*/,binarydigits:/[0-1]+(_+[0-1]+)*/,hexdigits:/[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,tokenizer:{root:[[/[A-Z][\w\$]*/,"type.identifier"],[/[a-zA-Z_$][\w$]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":"identifier"}}],{include:"@whitespace"},[/[{}()\[\]]/,"@brackets"],[/[<>](?!@symbols)/,"@brackets"],[/@symbols/,{cases:{"@operators":"delimiter","@default":""}}],[/@\s*[a-zA-Z_\$][\w\$]*/,"annotation"],[/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/,"number.float"],[/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/,"number.float"],[/0[xX](@hexdigits)[Ll]?/,"number.hex"],[/0(@octaldigits)[Ll]?/,"number.octal"],[/0[bB](@binarydigits)[Ll]?/,"number.binary"],[/(@digits)[fFdD]/,"number.float"],[/(@digits)[lL]?/,"number"],[/[;,.]/,"delimiter"],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"""/,"string","@multistring"],[/"/,"string","@string"],[/'[^\\']'/,"string"],[/(')(@escapes)(')/,["string","string.escape","string"]],[/'/,"string.invalid"]],whitespace:[[/[ \t\r\n]+/,""],[/\/\*\*(?!\/)/,"comment.doc","@javadoc"],[/\/\*/,"comment","@comment"],[/\/\/.*$/,"comment"]],comment:[[/[^\/*]+/,"comment"],[/\/\*/,"comment","@comment"],[/\*\//,"comment","@pop"],[/[\/*]/,"comment"]],javadoc:[[/[^\/*]+/,"comment.doc"],[/\/\*/,"comment.doc","@push"],[/\/\*/,"comment.doc.invalid"],[/\*\//,"comment.doc","@pop"],[/[\/*]/,"comment.doc"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],multistring:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"""/,"string","@pop"],[/./,"string"]]}};return g(f);})();
return moduleExports;
});

View file

@ -0,0 +1,11 @@
"use strict";/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.45.0(5e5af013f8d295555a7210df0d5f2cea0bf5dd56)
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/less/less", ["require","require"],(require)=>{
var moduleExports=(()=>{var r=Object.defineProperty;var s=Object.getOwnPropertyDescriptor;var a=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var d=(t,e)=>{for(var i in e)r(t,i,{get:e[i],enumerable:!0})},u=(t,e,i,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of a(e))!l.call(t,n)&&n!==i&&r(t,n,{get:()=>e[n],enumerable:!(o=s(e,n))||o.enumerable});return t};var c=t=>u(r({},"__esModule",{value:!0}),t);var p={};d(p,{conf:()=>m,language:()=>g});var m={wordPattern:/(#?-?\d*\.\d\w*%?)|([@#!.:]?[\w-?]+%?)|[@#!.]/g,comments:{blockComment:["/*","*/"],lineComment:"//"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\/"),end:new RegExp("^\\s*\\/\\*\\s*#endregion\\b.*\\*\\/")}}},g={defaultToken:"",tokenPostfix:".less",identifier:"-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",identifierPlus:"-?-?([a-zA-Z:.]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-:.]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.bracket"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],tokenizer:{root:[{include:"@nestedJSBegin"},["[ \\t\\r\\n]+",""],{include:"@comments"},{include:"@keyword"},{include:"@strings"},{include:"@numbers"},["[*_]?[a-zA-Z\\-\\s]+(?=:.*(;|(\\\\$)))","attribute.name","@attribute"],["url(\\-prefix)?\\(",{token:"tag",next:"@urldeclaration"}],["[{}()\\[\\]]","@brackets"],["[,:;]","delimiter"],["#@identifierPlus","tag.id"],["&","tag"],["\\.@identifierPlus(?=\\()","tag.class","@attribute"],["\\.@identifierPlus","tag.class"],["@identifierPlus","tag"],{include:"@operators"},["@(@identifier(?=[:,\\)]))","variable","@attribute"],["@(@identifier)","variable"],["@","key","@atRules"]],nestedJSBegin:[["``","delimiter.backtick"],["`",{token:"delimiter.backtick",next:"@nestedJSEnd",nextEmbedded:"text/javascript"}]],nestedJSEnd:[["`",{token:"delimiter.backtick",next:"@pop",nextEmbedded:"@pop"}]],operators:[["[<>=\\+\\-\\*\\/\\^\\|\\~]","operator"]],keyword:[["(@[\\s]*import|![\\s]*important|true|false|when|iscolor|isnumber|isstring|iskeyword|isurl|ispixel|ispercentage|isem|hue|saturation|lightness|alpha|lighten|darken|saturate|desaturate|fadein|fadeout|fade|spin|mix|round|ceil|floor|percentage)\\b","keyword"]],urldeclaration:[{include:"@strings"},[`[^)\r
]+`,"string"],["\\)",{token:"tag",next:"@pop"}]],attribute:[{include:"@nestedJSBegin"},{include:"@comments"},{include:"@strings"},{include:"@numbers"},{include:"@keyword"},["[a-zA-Z\\-]+(?=\\()","attribute.value","@attribute"],[">","operator","@pop"],["@identifier","attribute.value"],{include:"@operators"},["@(@identifier)","variable"],["[)\\}]","@brackets","@pop"],["[{}()\\[\\]>]","@brackets"],["[;]","delimiter","@pop"],["[,=:]","delimiter"],["\\s",""],[".","attribute.value"]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[".","comment"]],numbers:[["(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?",{token:"attribute.value.number",next:"@units"}],["#[0-9a-fA-F_]+(?!\\w)","attribute.value.hex"]],units:[["(em|ex|ch|rem|fr|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?","attribute.value.unit","@pop"]],strings:[['~?"',{token:"string.delimiter",next:"@stringsEndDoubleQuote"}],["~?'",{token:"string.delimiter",next:"@stringsEndQuote"}]],stringsEndDoubleQuote:[['\\\\"',"string"],['"',{token:"string.delimiter",next:"@popall"}],[".","string"]],stringsEndQuote:[["\\\\'","string"],["'",{token:"string.delimiter",next:"@popall"}],[".","string"]],atRules:[{include:"@comments"},{include:"@strings"},["[()]","delimiter"],["[\\{;]","delimiter","@pop"],[".","key"]]}};return c(p);})();
return moduleExports;
});

Some files were not shown because too many files have changed in this diff Show more