Compare commits
98 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b01a02d396 | |||
| 6db01bf6c6 | |||
| 9a84dfad28 | |||
| 054e57e074 | |||
| befa48edfb | |||
| 027a7aa8e2 | |||
| a4e641a1d5 | |||
| 61d90da409 | |||
| 84b7cb63f9 | |||
| e2f1efef8c | |||
| 48d773c0b3 | |||
| 3e81991e8b | |||
| b26d3ef4a5 | |||
| dd6e1aa2bc | |||
| 0c2dd80f30 | |||
| 6bbfa2989e | |||
| d13c82b7c8 | |||
| 7279104bbc | |||
| aef91abc1c | |||
| 7a06f954fb | |||
| 8075f9701c | |||
| 4a2c28e252 | |||
| 76ec8f9bb5 | |||
| a570d7bd11 | |||
| 9444d3892c | |||
| afb13cb397 | |||
| 7c1deca8ae | |||
| bfc8f4da77 | |||
| 8bfe97e92e | |||
| e89e87d2b2 | |||
| 76e8df36ee | |||
| 09bb9ee55d | |||
| 6d07aa4bdd | |||
| 2f53b65aeb | |||
| 6afeeb311f | |||
| 756da22dd5 | |||
| 093f417ff7 | |||
| 84684c6687 | |||
| a7991dd3dc | |||
| 138ad31a32 | |||
| 4987a15858 | |||
| 785187868e | |||
| 68bb516ec2 | |||
| ea8003e213 | |||
| a3747a794f | |||
| e5796fa64c | |||
| a8bff4e1a7 | |||
| f0aba607e9 | |||
| cbbcc58ad7 | |||
| 9b417bf4f2 | |||
| 8bb8f9d96a | |||
| ccee337522 | |||
| a29255c848 | |||
| 4f654dd95d | |||
| 8732738622 | |||
| 8611472d4e | |||
| fb66708cdc | |||
| be802201fd | |||
| 4164b75c89 | |||
| 2bb7959666 | |||
| b68fc0aa85 | |||
| 161012c6a6 | |||
| af78f31565 | |||
| a8bc5530b0 | |||
| 123787378f | |||
|
|
1bf9510c7d | ||
|
|
6b1dcc9d3f | ||
|
|
607ad076d9 | ||
| 661edc09fa | |||
| 1a1de27fd7 | |||
| 924f7660a0 | |||
| e286d64ce3 | |||
| 07da8a4e88 | |||
| f5ab1799a6 | |||
| 95f856b080 | |||
| a1a30adb2c | |||
| cdf8bea155 | |||
| 1ad929e3ff | |||
| 802219d8cd | |||
| 414d277ae1 | |||
| abdd2ff615 | |||
| 77374ae638 | |||
| e0504f3703 | |||
| 91a750127c | |||
| 5618ed4367 | |||
| 5e10222a94 | |||
| 375b457f48 | |||
| e135ebf2e6 | |||
| b69ea06ad3 | |||
| bd49ee3892 | |||
| 34d55825bc | |||
| 27e839f22a | |||
| db0f0c1178 | |||
| f4dcae288a | |||
| bb8b35d885 | |||
| 497d0dd18c | |||
| 22fa29b3ec | |||
| 12c1e3210f |
206 changed files with 77280 additions and 11029 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
name: GBCI
|
name: BotUI CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -6,18 +6,37 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_BUILD_JOBS: 6
|
||||||
|
CARGO_NET_RETRY: 10
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: gbo
|
runs-on: gbo
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Disable SSL verification (temporary)
|
- name: Disable SSL verification
|
||||||
run: git config --global http.sslVerify false
|
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
|
# Clone botui separately
|
||||||
run: git clone --depth 1 https://github.com/GeneralBots/botlib.git ../botlib
|
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
|
- name: Cache Cargo registry
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
|
@ -25,34 +44,54 @@ jobs:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
~/.cargo/git
|
~/.cargo/git
|
||||||
target
|
~/.cache/sccache
|
||||||
key: ${{ runner.os }}-cargo-botui-${{ hashFiles('**/Cargo.lock') }}
|
workspace/target
|
||||||
|
key: ${{ runner.os }}-cargo-v2-debug-ui-${{ hashFiles('**/Cargo.lock') }}
|
||||||
restore-keys: |
|
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
|
- name: Install Rust
|
||||||
run: |
|
run: |
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
|
||||||
echo "/root/.cargo/bin" >> $GITHUB_PATH
|
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
|
- name: Setup environment
|
||||||
|
run: sudo cp /opt/gbo/bin/system/.env . 2>/dev/null || true
|
||||||
|
|
||||||
|
- name: Build BotUI
|
||||||
|
working-directory: workspace
|
||||||
run: |
|
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
|
- name: Save build log
|
||||||
run: /root/.cargo/bin/cargo build --locked --release
|
if: always()
|
||||||
|
|
||||||
- name: Prepare release artifacts
|
|
||||||
run: |
|
run: |
|
||||||
sudo mkdir -p /opt/gbo/releases/botui/linux-x86_64
|
sudo mkdir -p /opt/gbo/logs
|
||||||
sudo cp ./target/release/botui /opt/gbo/releases/botui/linux-x86_64/ || true
|
sudo cp /tmp/build.log /opt/gbo/logs/botui-$(date +%Y%m%d-%H%M%S).log || true
|
||||||
sudo chmod -R 755 /opt/gbo/releases/botui/
|
|
||||||
|
|
||||||
- name: Deploy and restart local service
|
- name: Deploy
|
||||||
|
working-directory: workspace
|
||||||
run: |
|
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 cp target/release/botui /opt/gbo/bin/system/
|
||||||
sudo chmod +x /opt/gbo/bin/botui
|
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
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "botui"
|
name = "botui"
|
||||||
version = "6.1.0"
|
version = "6.1.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "General Bots UI - Pure web interface"
|
description = "General Bots UI - Pure web interface"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|
@ -13,8 +13,10 @@ workspace = true
|
||||||
features = ["http-client"]
|
features = ["http-client"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["ui-server", "chat", "drive", "tasks"]
|
default = ["ui-server", "chat", "drive", "tasks", "admin"]
|
||||||
ui-server = []
|
ui-server = []
|
||||||
|
embed-ui = ["rust-embed"]
|
||||||
|
|
||||||
|
|
||||||
# App Features
|
# App Features
|
||||||
chat = []
|
chat = []
|
||||||
|
|
@ -56,8 +58,10 @@ anyhow = { workspace = true }
|
||||||
axum = { workspace = true }
|
axum = { workspace = true }
|
||||||
futures-util = { workspace = true }
|
futures-util = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
mime_guess.workspace = true
|
||||||
native-tls = { workspace = true }
|
native-tls = { workspace = true }
|
||||||
reqwest = { workspace = true, features = ["json"] }
|
reqwest = { workspace = true, features = ["json"] }
|
||||||
|
rust-embed = { workspace = true, optional = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
|
|
|
||||||
278
PROMPT.md
278
PROMPT.md
|
|
@ -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
317
README.md
|
|
@ -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
|
||||||
|
|
||||||

|
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
|
```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:
|
- `BOTUI_PORT` - Server port (default: 9000)
|
||||||
```bash
|
|
||||||
npm run dev
|
---
|
||||||
|
|
||||||
|
## 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
|
||||||
4
build.rs
4
build.rs
|
|
@ -1,3 +1,5 @@
|
||||||
|
|
||||||
fn main() {
|
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
262
html3.html
Normal 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)]">></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>
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -153,7 +153,7 @@
|
||||||
<script>
|
<script>
|
||||||
// Configuration
|
// Configuration
|
||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
serverUrl: window.BOTSERVER_URL || 'http://localhost:8088',
|
serverUrl: window.BOTSERVER_URL || 'http://localhost:8080',
|
||||||
maxMessages: 10, // Keep memory low
|
maxMessages: 10, // Keep memory low
|
||||||
maxMsgLen: 100, // Truncate long messages
|
maxMsgLen: 100, // Truncate long messages
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="pt-br">
|
<html lang="pt-br">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>General Bots</title>
|
<title>General Bots</title>
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
<script>
|
<script>
|
||||||
// BotServer URL - configurable via window.BOTSERVER_URL or defaults to same origin port 8088
|
// BotServer URL - configurable via window.BOTSERVER_URL or defaults to same origin port 9000
|
||||||
const BOTSERVER_URL =
|
const BOTSERVER_URL =
|
||||||
window.BOTSERVER_URL || "https://localhost:8088";
|
window.BOTSERVER_URL || "http://localhost:9000";
|
||||||
const BOTSERVER_WS_URL = BOTSERVER_URL.replace(
|
const BOTSERVER_WS_URL = BOTSERVER_URL.replace(
|
||||||
"https://",
|
"https://",
|
||||||
"wss://",
|
"wss://",
|
||||||
|
|
@ -37,17 +38,14 @@
|
||||||
--glass: rgba(0, 0, 0, 0.02);
|
--glass: rgba(0, 0, 0, 0.02);
|
||||||
--shadow: rgba(0, 0, 0, 0.05);
|
--shadow: rgba(0, 0, 0, 0.05);
|
||||||
--logo-url: url("https://pragmatismo.com.br/icons/general-bots.svg");
|
--logo-url: url("https://pragmatismo.com.br/icons/general-bots.svg");
|
||||||
--gradient-1: linear-gradient(
|
--gradient-1: linear-gradient(135deg,
|
||||||
135deg,
|
|
||||||
rgba(0, 102, 255, 0.05) 0%,
|
rgba(0, 102, 255, 0.05) 0%,
|
||||||
rgba(0, 102, 255, 0) 100%
|
rgba(0, 102, 255, 0) 100%);
|
||||||
);
|
--gradient-2: linear-gradient(45deg,
|
||||||
--gradient-2: linear-gradient(
|
|
||||||
45deg,
|
|
||||||
rgba(0, 0, 0, 0.02) 0%,
|
rgba(0, 0, 0, 0.02) 0%,
|
||||||
rgba(0, 0, 0, 0) 100%
|
rgba(0, 0, 0, 0) 100%);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="dark"] {
|
[data-theme="dark"] {
|
||||||
--bg: #1a1a1a;
|
--bg: #1a1a1a;
|
||||||
--fg: #ffffff;
|
--fg: #ffffff;
|
||||||
|
|
@ -55,22 +53,20 @@
|
||||||
--accent: #ffffff;
|
--accent: #ffffff;
|
||||||
--glass: rgba(255, 255, 255, 0.05);
|
--glass: rgba(255, 255, 255, 0.05);
|
||||||
--shadow: rgba(0, 0, 0, 0.5);
|
--shadow: rgba(0, 0, 0, 0.5);
|
||||||
--gradient-1: linear-gradient(
|
--gradient-1: linear-gradient(135deg,
|
||||||
135deg,
|
|
||||||
rgba(255, 255, 255, 0.08) 0%,
|
rgba(255, 255, 255, 0.08) 0%,
|
||||||
rgba(255, 255, 255, 0) 100%
|
rgba(255, 255, 255, 0) 100%);
|
||||||
);
|
--gradient-2: linear-gradient(45deg,
|
||||||
--gradient-2: linear-gradient(
|
|
||||||
45deg,
|
|
||||||
rgba(255, 255, 255, 0.03) 0%,
|
rgba(255, 255, 255, 0.03) 0%,
|
||||||
rgba(255, 255, 255, 0) 100%
|
rgba(255, 255, 255, 0) 100%);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter", sans-serif;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
|
|
@ -84,6 +80,7 @@
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
body::before {
|
body::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
@ -92,6 +89,7 @@
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.float-menu {
|
.float-menu {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 20px;
|
left: 20px;
|
||||||
|
|
@ -101,6 +99,7 @@
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.float-logo {
|
.float-logo {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
@ -112,11 +111,13 @@
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
[data-theme="dark"] .float-logo {
|
|
||||||
}
|
[data-theme="dark"] .float-logo {}
|
||||||
|
|
||||||
.float-logo:hover {
|
.float-logo:hover {
|
||||||
transform: scale(1.1) rotate(5deg);
|
transform: scale(1.1) rotate(5deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-button {
|
.menu-button {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
@ -132,11 +133,13 @@
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-button:hover {
|
.menu-button:hover {
|
||||||
transform: scale(1.1) rotate(-5deg);
|
transform: scale(1.1) rotate(-5deg);
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: -320px;
|
left: -320px;
|
||||||
|
|
@ -152,9 +155,11 @@
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
box-shadow: 4px 0 20px var(--shadow);
|
box-shadow: 4px 0 20px var(--shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar.open {
|
.sidebar.open {
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header {
|
.sidebar-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -162,18 +167,21 @@
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-logo {
|
.sidebar-logo {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
background: var(--logo-url) center/contain no-repeat;
|
background: var(--logo-url) center/contain no-repeat;
|
||||||
filter: var(--logo-filter, none);
|
filter: var(--logo-filter, none);
|
||||||
}
|
}
|
||||||
[data-theme="dark"] .sidebar-logo {
|
|
||||||
}
|
[data-theme="dark"] .sidebar-logo {}
|
||||||
|
|
||||||
.sidebar-title {
|
.sidebar-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-button {
|
.sidebar-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
|
|
@ -188,14 +196,17 @@
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-button:hover {
|
.sidebar-button:hover {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
transform: translateX(4px) scale(1.02);
|
transform: translateX(4px) scale(1.02);
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-section {
|
.history-section {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-title {
|
.history-title {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
|
@ -203,6 +214,7 @@
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-item {
|
.history-item {
|
||||||
padding: 10px 14px;
|
padding: 10px 14px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
|
|
@ -212,11 +224,13 @@
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-item:hover {
|
.history-item:hover {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
transform: translateX(4px) scale(1.02);
|
transform: translateX(4px) scale(1.02);
|
||||||
}
|
}
|
||||||
|
|
||||||
#messages {
|
#messages {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
@ -227,16 +241,19 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-container {
|
.message-container {
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(10px);
|
transform: translateY(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-message {
|
.user-message {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-message-content {
|
.user-message-content {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
|
|
@ -249,6 +266,7 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-message-content::before {
|
.user-message-content::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -257,11 +275,13 @@
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assistant-message {
|
.assistant-message {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assistant-avatar {
|
.assistant-avatar {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
|
@ -271,8 +291,9 @@
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
filter: var(--logo-filter, none);
|
filter: var(--logo-filter, none);
|
||||||
}
|
}
|
||||||
[data-theme="dark"] .assistant-avatar {
|
|
||||||
}
|
[data-theme="dark"] .assistant-avatar {}
|
||||||
|
|
||||||
.assistant-message-content {
|
.assistant-message-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
@ -285,6 +306,7 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assistant-message-content::before {
|
.assistant-message-content::before {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -293,6 +315,7 @@
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thinking-indicator {
|
.thinking-indicator {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
@ -300,10 +323,12 @@
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.typing-dots {
|
.typing-dots {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.typing-dot {
|
.typing-dot {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
|
|
@ -311,24 +336,30 @@
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: bounce 1.4s infinite;
|
animation: bounce 1.4s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.typing-dot:nth-child(1) {
|
.typing-dot:nth-child(1) {
|
||||||
animation-delay: -0.32s;
|
animation-delay: -0.32s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.typing-dot:nth-child(2) {
|
.typing-dot:nth-child(2) {
|
||||||
animation-delay: -0.16s;
|
animation-delay: -0.16s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes bounce {
|
@keyframes bounce {
|
||||||
|
|
||||||
0%,
|
0%,
|
||||||
80%,
|
80%,
|
||||||
100% {
|
100% {
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
40% {
|
40% {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
@ -341,6 +372,7 @@
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.suggestions-container {
|
.suggestions-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
@ -350,6 +382,7 @@
|
||||||
max-width: 680px;
|
max-width: 680px;
|
||||||
margin: 0 auto 8px;
|
margin: 0 auto 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.suggestion-button {
|
.suggestion-button {
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
|
@ -361,11 +394,13 @@
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.suggestion-button:hover {
|
.suggestion-button:hover {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-container {
|
.input-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|
@ -373,6 +408,7 @@
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#messageInput {
|
#messageInput {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|
@ -386,13 +422,16 @@
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
#messageInput:focus {
|
#messageInput:focus {
|
||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
box-shadow: 0 0 0 3px rgba(0, 102, 255, 0.1);
|
box-shadow: 0 0 0 3px rgba(0, 102, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#messageInput::placeholder {
|
#messageInput::placeholder {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sendBtn,
|
#sendBtn,
|
||||||
#voiceBtn {
|
#voiceBtn {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
|
|
@ -409,28 +448,35 @@
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sendBtn:hover,
|
#sendBtn:hover,
|
||||||
#voiceBtn:hover {
|
#voiceBtn:hover {
|
||||||
transform: scale(1.08) rotate(5deg);
|
transform: scale(1.08) rotate(5deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#sendBtn:active,
|
#sendBtn:active,
|
||||||
#voiceBtn:active {
|
#voiceBtn:active {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
#voiceBtn.recording {
|
#voiceBtn.recording {
|
||||||
animation: pulse 1.5s infinite;
|
animation: pulse 1.5s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
|
|
||||||
0%,
|
0%,
|
||||||
100% {
|
100% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.flash-overlay {
|
.flash-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
|
@ -439,6 +485,7 @@
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-to-bottom {
|
.scroll-to-bottom {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 80px;
|
bottom: 80px;
|
||||||
|
|
@ -457,12 +504,15 @@
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
z-index: 90;
|
z-index: 90;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-to-bottom.visible {
|
.scroll-to-bottom.visible {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-to-bottom:hover {
|
.scroll-to-bottom:hover {
|
||||||
transform: scale(1.1) rotate(180deg);
|
transform: scale(1.1) rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning-message {
|
.warning-message {
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
|
|
@ -472,6 +522,7 @@
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.continue-button {
|
.continue-button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
|
|
@ -484,11 +535,13 @@
|
||||||
background: var(--glass);
|
background: var(--glass);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.continue-button:hover {
|
.continue-button:hover {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-indicator {
|
.context-indicator {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 130px;
|
bottom: 130px;
|
||||||
|
|
@ -504,9 +557,11 @@
|
||||||
display: none;
|
display: none;
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-indicator.visible {
|
.context-indicator.visible {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-progress {
|
.context-progress {
|
||||||
height: 3px;
|
height: 3px;
|
||||||
background: var(--glass);
|
background: var(--glass);
|
||||||
|
|
@ -514,12 +569,14 @@
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-progress-bar {
|
.context-progress-bar {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: var(--accent);
|
background: var(--accent);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
transition: width 0.3s;
|
transition: width 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.connection-status {
|
.connection-status {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
|
|
@ -530,42 +587,52 @@
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.connection-status.connecting {
|
.connection-status.connecting {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
animation: ping 1.5s infinite;
|
animation: ping 1.5s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.connection-status.connected {
|
.connection-status.connected {
|
||||||
background: var(--accent);
|
background: var(--accent);
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.connection-status.disconnected {
|
.connection-status.disconnected {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes ping {
|
@keyframes ping {
|
||||||
|
|
||||||
0%,
|
0%,
|
||||||
100% {
|
100% {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
transform: scale(0.8);
|
transform: scale(0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
transform: scale(1.2);
|
transform: scale(1.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content p {
|
.markdown-content p {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content ul,
|
.markdown-content ul,
|
||||||
.markdown-content ol {
|
.markdown-content ol {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content li {
|
.markdown-content li {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content code {
|
.markdown-content code {
|
||||||
background: var(--glass);
|
background: var(--glass);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
|
@ -573,6 +640,7 @@
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content pre {
|
.markdown-content pre {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
|
@ -581,10 +649,12 @@
|
||||||
background: var(--glass);
|
background: var(--glass);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content pre code {
|
.markdown-content pre code {
|
||||||
background: none;
|
background: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content h1,
|
.markdown-content h1,
|
||||||
.markdown-content h2,
|
.markdown-content h2,
|
||||||
.markdown-content h3 {
|
.markdown-content h3 {
|
||||||
|
|
@ -592,30 +662,37 @@
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content h1 {
|
.markdown-content h1 {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content h2 {
|
.markdown-content h2 {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content h3 {
|
.markdown-content h3 {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content table {
|
.markdown-content table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content table th,
|
.markdown-content table th,
|
||||||
.markdown-content table td {
|
.markdown-content table td {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content table th {
|
.markdown-content table th {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: var(--glass);
|
background: var(--glass);
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content blockquote {
|
.markdown-content blockquote {
|
||||||
border-left: 2px solid var(--accent);
|
border-left: 2px solid var(--accent);
|
||||||
padding-left: 14px;
|
padding-left: 14px;
|
||||||
|
|
@ -623,53 +700,65 @@
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content a {
|
.markdown-content a {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-content a:hover {
|
.markdown-content a:hover {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background: var(--border);
|
background: var(--border);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--fg);
|
background: var(--fg);
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
left: -100%;
|
left: -100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#messages {
|
#messages {
|
||||||
padding: 20px 16px 140px;
|
padding: 20px 16px 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.float-menu {
|
.float-menu {
|
||||||
left: 12px;
|
left: 12px;
|
||||||
top: 12px;
|
top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.float-logo,
|
.float-logo,
|
||||||
.menu-button {
|
.menu-button {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroll-to-bottom {
|
.scroll-to-bottom {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
bottom: 70px;
|
bottom: 70px;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-indicator {
|
.context-indicator {
|
||||||
bottom: 120px;
|
bottom: 120px;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
|
|
@ -678,23 +767,17 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="connection-status connecting" id="connectionStatus"></div>
|
<div class="connection-status connecting" id="connectionStatus"></div>
|
||||||
<div class="flash-overlay" id="flashOverlay"></div>
|
<div class="flash-overlay" id="flashOverlay"></div>
|
||||||
<div class="float-menu">
|
|
||||||
<div class="float-logo" id="floatLogo" title="Menu"></div>
|
|
||||||
<div class="menu-button" id="themeBtn" title="Theme">⚙</div>
|
|
||||||
</div>
|
|
||||||
<div class="sidebar" id="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<div class="sidebar-logo"></div>
|
<div class="sidebar-logo"></div>
|
||||||
<div class="sidebar-title" id="sidebarTitle">General Bots</div>
|
<div class="sidebar-title" id="sidebarTitle">General Bots</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button class="sidebar-button" id="voiceToggle" onclick="toggleVoiceMode()">
|
||||||
class="sidebar-button"
|
|
||||||
id="voiceToggle"
|
|
||||||
onclick="toggleVoiceMode()"
|
|
||||||
>
|
|
||||||
🎤 Voice Mode
|
🎤 Voice Mode
|
||||||
</button>
|
</button>
|
||||||
<div class="history-section">
|
<div class="history-section">
|
||||||
|
|
@ -706,12 +789,7 @@
|
||||||
<footer>
|
<footer>
|
||||||
<div class="suggestions-container" id="suggestions"></div>
|
<div class="suggestions-container" id="suggestions"></div>
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input
|
<input id="messageInput" type="text" placeholder="Message..." autofocus />
|
||||||
id="messageInput"
|
|
||||||
type="text"
|
|
||||||
placeholder="Message..."
|
|
||||||
autofocus
|
|
||||||
/>
|
|
||||||
<button id="voiceBtn" title="Voice">🎤</button>
|
<button id="voiceBtn" title="Voice">🎤</button>
|
||||||
<button id="sendBtn" title="Send">↑</button>
|
<button id="sendBtn" title="Send">↑</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -721,11 +799,7 @@
|
||||||
<div>Context</div>
|
<div>Context</div>
|
||||||
<div id="contextPercentage">0%</div>
|
<div id="contextPercentage">0%</div>
|
||||||
<div class="context-progress">
|
<div class="context-progress">
|
||||||
<div
|
<div class="context-progress-bar" id="contextProgressBar" style="width: 0%"></div>
|
||||||
class="context-progress-bar"
|
|
||||||
id="contextProgressBar"
|
|
||||||
style="width: 0%"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -770,9 +844,8 @@
|
||||||
document.getElementById("connectionStatus"),
|
document.getElementById("connectionStatus"),
|
||||||
flashOverlay = document.getElementById("flashOverlay"),
|
flashOverlay = document.getElementById("flashOverlay"),
|
||||||
suggestionsContainer = document.getElementById("suggestions"),
|
suggestionsContainer = document.getElementById("suggestions"),
|
||||||
floatLogo = document.getElementById("floatLogo"),
|
|
||||||
sidebar = document.getElementById("sidebar"),
|
sidebar = document.getElementById("sidebar"),
|
||||||
themeBtn = document.getElementById("themeBtn"),
|
|
||||||
scrollToBottomBtn = document.getElementById("scrollToBottom"),
|
scrollToBottomBtn = document.getElementById("scrollToBottom"),
|
||||||
contextIndicator = document.getElementById("contextIndicator"),
|
contextIndicator = document.getElementById("contextIndicator"),
|
||||||
contextPercentage =
|
contextPercentage =
|
||||||
|
|
@ -782,7 +855,7 @@
|
||||||
sidebarTitle = document.getElementById("sidebarTitle");
|
sidebarTitle = document.getElementById("sidebarTitle");
|
||||||
marked.setOptions({ breaks: true, gfm: true });
|
marked.setOptions({ breaks: true, gfm: true });
|
||||||
|
|
||||||
floatLogo.addEventListener("click", toggleSidebar);
|
|
||||||
|
|
||||||
function toggleSidebar() {
|
function toggleSidebar() {
|
||||||
sidebar.classList.toggle("open");
|
sidebar.classList.toggle("open");
|
||||||
|
|
@ -800,8 +873,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateThemeButton() {
|
function updateThemeButton() {
|
||||||
const icons = { auto: "⚙", dark: "🌙", light: "☀️" };
|
// Theme button removed for non-logged users
|
||||||
themeBtn.textContent = icons[currentTheme] || "⚙";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyTheme() {
|
function applyTheme() {
|
||||||
|
|
@ -847,13 +919,12 @@
|
||||||
input.focus();
|
input.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
themeBtn.addEventListener("click", toggleTheme);
|
|
||||||
|
|
||||||
document.addEventListener("click", function (e) {
|
document.addEventListener("click", function (e) {
|
||||||
if (
|
if (
|
||||||
sidebar.classList.contains("open") &&
|
sidebar.classList.contains("open") &&
|
||||||
!sidebar.contains(e.target) &&
|
!sidebar.contains(e.target)
|
||||||
!floatLogo.contains(e.target)
|
|
||||||
) {
|
) {
|
||||||
sidebar.classList.remove("open");
|
sidebar.classList.remove("open");
|
||||||
}
|
}
|
||||||
|
|
@ -1030,6 +1101,7 @@
|
||||||
const r = JSON.parse(e.data);
|
const r = JSON.parse(e.data);
|
||||||
if (r.type === "connected") {
|
if (r.type === "connected") {
|
||||||
console.log("WebSocket welcome message:", r);
|
console.log("WebSocket welcome message:", r);
|
||||||
|
reconnectAttempts = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (r.bot_id) {
|
if (r.bot_id) {
|
||||||
|
|
@ -1083,7 +1155,6 @@
|
||||||
ws.readyState,
|
ws.readyState,
|
||||||
);
|
);
|
||||||
updateConnectionStatus("connected");
|
updateConnectionStatus("connected");
|
||||||
reconnectAttempts = 0;
|
|
||||||
hasReceivedInitialMessage = false;
|
hasReceivedInitialMessage = false;
|
||||||
};
|
};
|
||||||
ws.onclose = function (e) {
|
ws.onclose = function (e) {
|
||||||
|
|
@ -1127,8 +1198,10 @@
|
||||||
streamingMessageId = null;
|
streamingMessageId = null;
|
||||||
currentStreamingContent = "";
|
currentStreamingContent = "";
|
||||||
} else {
|
} else {
|
||||||
|
if (r.content && r.content.trim() !== "") {
|
||||||
addMessage("assistant", r.content, false);
|
addMessage("assistant", r.content, false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isStreaming) {
|
if (!isStreaming) {
|
||||||
isStreaming = true;
|
isStreaming = true;
|
||||||
|
|
@ -1715,4 +1788,5 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
73
ui/public/themes/dark.css
Normal file
73
ui/public/themes/dark.css
Normal 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);
|
||||||
|
}
|
||||||
73
ui/public/themes/light.css
Normal file
73
ui/public/themes/light.css
Normal 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);
|
||||||
|
}
|
||||||
117
ui/public/themes/y2kglow.css
Normal file
117
ui/public/themes/y2kglow.css
Normal 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));
|
||||||
|
}
|
||||||
|
|
@ -172,7 +172,7 @@
|
||||||
<div class="activity-list" hx-get="/api/admin/dashboard/activity" hx-trigger="load" hx-swap="innerHTML">
|
<div class="activity-list" hx-get="/api/admin/dashboard/activity" hx-trigger="load" hx-swap="innerHTML">
|
||||||
<div class="activity-item">
|
<div class="activity-item">
|
||||||
<div class="activity-avatar">
|
<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>
|
||||||
<div class="activity-content">
|
<div class="activity-content">
|
||||||
<div class="activity-text">
|
<div class="activity-text">
|
||||||
|
|
@ -198,7 +198,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="activity-item">
|
<div class="activity-item">
|
||||||
<div class="activity-avatar">
|
<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>
|
||||||
<div class="activity-content">
|
<div class="activity-content">
|
||||||
<div class="activity-text">
|
<div class="activity-text">
|
||||||
|
|
@ -222,7 +222,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="activity-item">
|
<div class="activity-item">
|
||||||
<div class="activity-avatar">
|
<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>
|
||||||
<div class="activity-content">
|
<div class="activity-content">
|
||||||
<div class="activity-text">
|
<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-list" hx-get="/api/admin/dashboard/members" hx-trigger="load" hx-swap="innerHTML">
|
||||||
<div class="member-item">
|
<div class="member-item">
|
||||||
<div class="member-avatar">
|
<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>
|
<span class="status-indicator online"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="member-info">
|
<div class="member-info">
|
||||||
|
|
@ -285,7 +285,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="member-item">
|
<div class="member-item">
|
||||||
<div class="member-avatar">
|
<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>
|
<span class="status-indicator online"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="member-info">
|
<div class="member-info">
|
||||||
|
|
@ -296,7 +296,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="member-item">
|
<div class="member-item">
|
||||||
<div class="member-avatar">
|
<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>
|
<span class="status-indicator away"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="member-info">
|
<div class="member-info">
|
||||||
|
|
@ -307,7 +307,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="member-item">
|
<div class="member-item">
|
||||||
<div class="member-avatar">
|
<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>
|
<span class="status-indicator offline"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="member-info">
|
<div class="member-info">
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="wizard-container">
|
<div class="wizard-container">
|
||||||
<div class="wizard-sidebar">
|
<div class="wizard-sidebar">
|
||||||
<div class="wizard-logo">
|
<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>
|
||||||
<div class="wizard-steps">
|
<div class="wizard-steps">
|
||||||
<div class="wizard-step active" data-step="1">
|
<div class="wizard-step active" data-step="1">
|
||||||
|
|
|
||||||
|
|
@ -1322,7 +1322,6 @@
|
||||||
"WebSocket connected for attendant:",
|
"WebSocket connected for attendant:",
|
||||||
currentAttendantId,
|
currentAttendantId,
|
||||||
);
|
);
|
||||||
reconnectAttempts = 0;
|
|
||||||
showToast(
|
showToast(
|
||||||
"Connected to notification service",
|
"Connected to notification service",
|
||||||
"success",
|
"success",
|
||||||
|
|
@ -1367,6 +1366,7 @@
|
||||||
switch (msgType) {
|
switch (msgType) {
|
||||||
case "connected":
|
case "connected":
|
||||||
console.log("WebSocket connected:", data.message);
|
console.log("WebSocket connected:", data.message);
|
||||||
|
reconnectAttempts = 0;
|
||||||
break;
|
break;
|
||||||
case "new_conversation":
|
case "new_conversation":
|
||||||
showToast("New conversation in queue", "info");
|
showToast("New conversation in queue", "info");
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="setup-container">
|
<div class="setup-container">
|
||||||
<div class="setup-header">
|
<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>
|
<h1 class="setup-title">Initial Setup</h1>
|
||||||
<p class="setup-subtitle">
|
<p class="setup-subtitle">
|
||||||
Create the first administrator account for your General Bots installation
|
Create the first administrator account for your General Bots installation
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Login - General Bots</title>
|
<title>Login - General Bots</title>
|
||||||
<script src="/js/vendor/htmx.min.js"></script>
|
<script src="/suite/js/vendor/htmx.min.js"></script>
|
||||||
<script src="/js/vendor/htmx-json-enc.js"></script>
|
<script src="/suite/js/vendor/htmx-json-enc.js"></script>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--primary: #3b82f6;
|
--primary: #3b82f6;
|
||||||
|
|
@ -75,6 +75,18 @@
|
||||||
box-shadow: 0 8px 32px rgba(59, 130, 246, 0.3);
|
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 {
|
.login-title {
|
||||||
font-size: 1.75rem;
|
font-size: 1.75rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|
@ -585,9 +597,12 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="login-container">
|
<div class="login-container">
|
||||||
<div class="login-header">
|
<div class="login-header">
|
||||||
<div class="login-logo">🤖</div>
|
<div class="login-logo" id="login-logo">
|
||||||
<h1 class="login-title">Welcome Back</h1>
|
<img id="login-logo-img" src="" alt="Logo" style="display:none; width:100%; height:100%; object-fit:contain;">
|
||||||
<p class="login-subtitle">
|
<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
|
Sign in to your General Bots account
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1018,6 +1033,55 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<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
|
// Password visibility toggle
|
||||||
function togglePassword() {
|
function togglePassword() {
|
||||||
const passwordInput = document.getElementById("password");
|
const passwordInput = document.getElementById("password");
|
||||||
|
|
@ -1264,12 +1328,18 @@
|
||||||
|
|
||||||
// Successful login - redirect
|
// Successful login - redirect
|
||||||
if (response.redirect || response.success) {
|
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) {
|
} catch (e) {
|
||||||
// If response is not JSON, check for redirect header
|
// If response is not JSON, check for redirect header
|
||||||
if (event.detail.xhr.status === 200) {
|
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 {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -557,7 +557,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="register-container">
|
<div class="register-container">
|
||||||
<div class="register-header">
|
<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>
|
<h1 class="register-title">Create Account</h1>
|
||||||
<p class="register-subtitle">
|
<p class="register-subtitle">
|
||||||
Join General Bots and start building
|
Join General Bots and start building
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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>
|
|
||||||
1573
ui/suite/base.html
1573
ui/suite/base.html
File diff suppressed because it is too large
Load diff
19
ui/suite/browser/browser.html
Normal file
19
ui/suite/browser/browser.html
Normal 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>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<link rel="stylesheet" href="calendar/calendar.css" />
|
<link rel="stylesheet" href="/suite/calendar/calendar.css" />
|
||||||
|
|
||||||
<!-- Calendar - Event Management -->
|
<!-- Calendar - Event Management -->
|
||||||
<div class="calendar-container" id="calendar-app">
|
<div class="calendar-container" id="calendar-app">
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -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">
|
<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>
|
<main id="messages"></main>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
|
|
@ -23,14 +35,6 @@
|
||||||
autofocus
|
autofocus
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
/>
|
/>
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
id="voiceBtn"
|
|
||||||
title="Voice"
|
|
||||||
data-i18n-title="chat-voice"
|
|
||||||
>
|
|
||||||
🎤
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
id="sendBtn"
|
id="sendBtn"
|
||||||
|
|
@ -41,7 +45,24 @@
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</footer>
|
</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>
|
||||||
|
|
||||||
<div class="entity-card-tooltip" id="entityCardTooltip">
|
<div class="entity-card-tooltip" id="entityCardTooltip">
|
||||||
|
|
@ -81,7 +102,7 @@
|
||||||
|
|
||||||
var WS_BASE_URL =
|
var WS_BASE_URL =
|
||||||
window.location.protocol === "https:" ? "wss://" : "ws://";
|
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 = {
|
var MessageType = {
|
||||||
EXTERNAL: 0,
|
EXTERNAL: 0,
|
||||||
|
|
@ -148,11 +169,14 @@
|
||||||
var currentSessionId = null;
|
var currentSessionId = null;
|
||||||
var currentUserId = null;
|
var currentUserId = null;
|
||||||
var currentBotId = "default";
|
var currentBotId = "default";
|
||||||
|
var currentBotName = "default";
|
||||||
var isStreaming = false;
|
var isStreaming = false;
|
||||||
var streamingMessageId = null;
|
var streamingMessageId = null;
|
||||||
var currentStreamingContent = "";
|
var currentStreamingContent = "";
|
||||||
var reconnectAttempts = 0;
|
var reconnectAttempts = 0;
|
||||||
var maxReconnectAttempts = 5;
|
var maxReconnectAttempts = 5;
|
||||||
|
var disconnectNotified = false;
|
||||||
|
var isUserScrolling = false;
|
||||||
|
|
||||||
var mentionState = {
|
var mentionState = {
|
||||||
active: false,
|
active: false,
|
||||||
|
|
@ -168,6 +192,63 @@
|
||||||
return div.innerHTML;
|
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) {
|
function renderMentionInMessage(content) {
|
||||||
return content.replace(
|
return content.replace(
|
||||||
/@(\w+):([^\s]+)/g,
|
/@(\w+):([^\s]+)/g,
|
||||||
|
|
@ -225,7 +306,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
messages.appendChild(div);
|
messages.appendChild(div);
|
||||||
messages.scrollTop = messages.scrollHeight;
|
|
||||||
|
// Auto-scroll to bottom unless user is manually scrolling
|
||||||
|
if (!isUserScrolling) {
|
||||||
|
scrollToBottom(true);
|
||||||
|
} else {
|
||||||
|
updateScrollButton();
|
||||||
|
}
|
||||||
|
|
||||||
setupMentionClickHandlers(div);
|
setupMentionClickHandlers(div);
|
||||||
}
|
}
|
||||||
|
|
@ -670,9 +757,20 @@
|
||||||
if (isStreaming) {
|
if (isStreaming) {
|
||||||
finalizeStreaming();
|
finalizeStreaming();
|
||||||
} else {
|
} else {
|
||||||
|
if (data.content && data.content.trim() !== "") {
|
||||||
addMessage("bot", data.content);
|
addMessage("bot", data.content);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
isStreaming = false;
|
isStreaming = false;
|
||||||
|
|
||||||
|
// Render suggestions when message is complete
|
||||||
|
if (
|
||||||
|
data.suggestions &&
|
||||||
|
Array.isArray(data.suggestions) &&
|
||||||
|
data.suggestions.length > 0
|
||||||
|
) {
|
||||||
|
renderSuggestions(data.suggestions);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isStreaming) {
|
if (!isStreaming) {
|
||||||
isStreaming = true;
|
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");
|
var input = document.getElementById("messageInput");
|
||||||
if (!input) {
|
if (!input) {
|
||||||
console.error("Chat input not found");
|
console.error("Chat input not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var content = input.value.trim();
|
// If no messageContent provided, read from input
|
||||||
|
var content = messageContent || input.value.trim();
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If called from input field (no messageContent provided), clear input
|
||||||
|
if (!messageContent) {
|
||||||
hideMentionDropdown();
|
hideMentionDropdown();
|
||||||
addMessage("user", content);
|
|
||||||
input.value = "";
|
input.value = "";
|
||||||
input.focus();
|
input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
addMessage("user", content);
|
||||||
|
|
||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send(
|
ws.send(
|
||||||
|
|
@ -726,51 +905,340 @@
|
||||||
|
|
||||||
window.sendMessage = sendMessage;
|
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() {
|
function connectWebSocket() {
|
||||||
if (ws) {
|
if (ws) {
|
||||||
ws.close();
|
ws.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateConnectionStatus("connecting");
|
||||||
|
|
||||||
var url =
|
var url =
|
||||||
WS_URL +
|
WS_URL +
|
||||||
"/ws?session_id=" +
|
"?session_id=" +
|
||||||
currentSessionId +
|
currentSessionId +
|
||||||
"&user_id=" +
|
"&user_id=" +
|
||||||
currentUserId;
|
currentUserId +
|
||||||
|
"&bot_name=" +
|
||||||
|
currentBotName;
|
||||||
|
|
||||||
|
console.log("Connecting WebSocket to:", url);
|
||||||
ws = new WebSocket(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 () {
|
ws.onopen = function () {
|
||||||
console.log("WebSocket connected");
|
clearTimeout(connectionTimeout);
|
||||||
reconnectAttempts = 0;
|
console.log("WebSocket connected to:", url);
|
||||||
|
disconnectNotified = false;
|
||||||
|
updateConnectionStatus("connected");
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onmessage = function (event) {
|
ws.onmessage = function (event) {
|
||||||
try {
|
try {
|
||||||
var data = JSON.parse(event.data);
|
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) {
|
if (data.message_type === MessageType.BOT_RESPONSE) {
|
||||||
|
console.log("Processing bot response:", data);
|
||||||
processMessage(data);
|
processMessage(data);
|
||||||
|
} else {
|
||||||
|
console.log("Ignoring non-bot message:", data);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("WS message error:", e);
|
console.error("WS message error:", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onclose = function () {
|
ws.onclose = function (event) {
|
||||||
|
clearTimeout(connectionTimeout);
|
||||||
|
console.log("WebSocket closed:", event.code, event.reason);
|
||||||
|
updateConnectionStatus("disconnected");
|
||||||
|
if (!disconnectNotified) {
|
||||||
notify("Disconnected from chat server", "error");
|
notify("Disconnected from chat server", "error");
|
||||||
|
disconnectNotified = true;
|
||||||
|
}
|
||||||
if (reconnectAttempts < maxReconnectAttempts) {
|
if (reconnectAttempts < maxReconnectAttempts) {
|
||||||
reconnectAttempts++;
|
reconnectAttempts++;
|
||||||
|
updateConnectionStatus("connecting");
|
||||||
setTimeout(connectWebSocket, 1000 * reconnectAttempts);
|
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) {
|
ws.onerror = function (e) {
|
||||||
console.error("WebSocket error:", 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() {
|
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))
|
fetch("/api/auth?bot_name=" + encodeURIComponent(botName))
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
return response.json();
|
return response.json();
|
||||||
|
|
@ -779,18 +1247,59 @@
|
||||||
currentUserId = auth.user_id;
|
currentUserId = auth.user_id;
|
||||||
currentSessionId = auth.session_id;
|
currentSessionId = auth.session_id;
|
||||||
currentBotId = auth.bot_id || "default";
|
currentBotId = auth.bot_id || "default";
|
||||||
|
currentBotName = botName;
|
||||||
console.log("Auth:", {
|
console.log("Auth:", {
|
||||||
currentUserId: currentUserId,
|
currentUserId: currentUserId,
|
||||||
currentSessionId: currentSessionId,
|
currentSessionId: currentSessionId,
|
||||||
currentBotId: currentBotId,
|
currentBotId: currentBotId,
|
||||||
|
currentBotName: currentBotName,
|
||||||
});
|
});
|
||||||
connectWebSocket();
|
connectWebSocket();
|
||||||
})
|
})
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
console.error("Auth failed:", e);
|
console.error("Auth failed:", e);
|
||||||
notify("Failed to connect to chat server", "error");
|
// Proceed with anonymous connection - WebSocket handler supports it
|
||||||
setTimeout(initChat, 3000);
|
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() {
|
function setupEventHandlers() {
|
||||||
|
|
|
||||||
|
|
@ -48,16 +48,14 @@
|
||||||
⏩
|
⏩
|
||||||
</button>
|
</button>
|
||||||
<div class="progress-container">
|
<div class="progress-container">
|
||||||
<input type="range" class="progress-bar" id="progress-bar"
|
<input type="range" class="progress-bar" id="progress-bar" min="0" max="100" value="0"
|
||||||
min="0" max="100" value="0"
|
|
||||||
oninput="seekTo(this.value)">
|
oninput="seekTo(this.value)">
|
||||||
<span class="time-display" id="time-display">0:00 / 0:00</span>
|
<span class="time-display" id="time-display">0:00 / 0:00</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="control-btn" onclick="toggleMute()" id="mute-btn" title="Mute">
|
<button class="control-btn" onclick="toggleMute()" id="mute-btn" title="Mute">
|
||||||
🔊
|
🔊
|
||||||
</button>
|
</button>
|
||||||
<input type="range" class="volume-slider" id="volume-slider"
|
<input type="range" class="volume-slider" id="volume-slider" min="0" max="100" value="100"
|
||||||
min="0" max="100" value="100"
|
|
||||||
oninput="setVolume(this.value)">
|
oninput="setVolume(this.value)">
|
||||||
<button class="control-btn" onclick="toggleLoop()" id="loop-btn" title="Loop">
|
<button class="control-btn" onclick="toggleLoop()" id="loop-btn" title="Loop">
|
||||||
🔁
|
🔁
|
||||||
|
|
@ -82,8 +80,7 @@
|
||||||
▶️
|
▶️
|
||||||
</button>
|
</button>
|
||||||
<div class="slide-nav">
|
<div class="slide-nav">
|
||||||
<input type="number" id="slide-input" min="1" value="1"
|
<input type="number" id="slide-input" min="1" value="1" onchange="goToSlide(this.value)">
|
||||||
onchange="goToSlide(this.value)">
|
|
||||||
</div>
|
</div>
|
||||||
<button class="control-btn" onclick="zoomIn()" title="Zoom In">
|
<button class="control-btn" onclick="zoomIn()" title="Zoom In">
|
||||||
🔍+
|
🔍+
|
||||||
|
|
@ -126,12 +123,7 @@
|
||||||
<button class="control-btn" onclick="toggleWordWrap()" title="Word Wrap">
|
<button class="control-btn" onclick="toggleWordWrap()" title="Word Wrap">
|
||||||
↩️
|
↩️
|
||||||
</button>
|
</button>
|
||||||
<select class="theme-select" id="theme-select" onchange="setCodeTheme(this.value)">
|
|
||||||
<option value="dark">Dark</option>
|
|
||||||
<option value="light">Light</option>
|
|
||||||
<option value="monokai">Monokai</option>
|
|
||||||
<option value="github">GitHub</option>
|
|
||||||
</select>
|
|
||||||
<button class="control-btn" onclick="copyCode()" title="Copy">
|
<button class="control-btn" onclick="copyCode()" title="Copy">
|
||||||
📋
|
📋
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -148,7 +140,7 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background: rgba(0, 0, 0, 0.9);
|
background: rgba(0, 0, 0, 0.8);
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -161,8 +153,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; }
|
from {
|
||||||
to { opacity: 1; }
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Container */
|
/* Container */
|
||||||
|
|
@ -171,7 +168,7 @@
|
||||||
max-width: 1400px;
|
max-width: 1400px;
|
||||||
height: 90%;
|
height: 90%;
|
||||||
max-height: 900px;
|
max-height: 900px;
|
||||||
background: #1a1a1a;
|
background: var(--bg, #1a1a1a);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -193,8 +190,8 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px 20px;
|
padding: 12px 20px;
|
||||||
background: #252525;
|
background: var(--surface, #252525);
|
||||||
border-bottom: 1px solid #333;
|
border-bottom: 1px solid var(--border, #333);
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-title-section {
|
.projector-title-section {
|
||||||
|
|
@ -208,7 +205,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-title {
|
.projector-title {
|
||||||
color: #fff;
|
color: var(--text, #fff);
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
|
|
@ -225,7 +222,7 @@
|
||||||
.projector-btn {
|
.projector-btn {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: #aaa;
|
color: var(--text-muted, #aaa);
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
@ -234,13 +231,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-btn:hover {
|
.projector-btn:hover {
|
||||||
background: #333;
|
background: var(--surface-hover, #333);
|
||||||
color: #fff;
|
color: var(--text, #fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-btn.close-btn:hover {
|
.projector-btn.close-btn:hover {
|
||||||
background: #e74c3c;
|
background: var(--error, #e74c3c);
|
||||||
color: #fff;
|
color: var(--text, #fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Content Area */
|
/* Content Area */
|
||||||
|
|
@ -251,7 +248,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #000;
|
background: var(--bg, #000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loading */
|
/* Loading */
|
||||||
|
|
@ -260,7 +257,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
color: #888;
|
color: var(--text-muted, #888);
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-loading.hidden {
|
.projector-loading.hidden {
|
||||||
|
|
@ -270,14 +267,16 @@
|
||||||
.loading-spinner {
|
.loading-spinner {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border: 3px solid #333;
|
border: 3px solid var(--surface-hover, #333);
|
||||||
border-top-color: #667eea;
|
border-top-color: var(--accent, #667eea);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: spin 1s linear infinite;
|
animation: spin 1s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to { transform: rotate(360deg); }
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Video Player */
|
/* Video Player */
|
||||||
|
|
@ -322,7 +321,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
background: #1e1e1e;
|
background: var(--bg, #1e1e1e);
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,7 +330,7 @@
|
||||||
font-family: 'Fira Code', 'Monaco', 'Consolas', monospace;
|
font-family: 'Fira Code', 'Monaco', 'Consolas', monospace;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: #d4d4d4;
|
color: var(--text, #d4d4d4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-code.line-numbers pre {
|
.projector-code.line-numbers pre {
|
||||||
|
|
@ -344,7 +343,7 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
color: #666;
|
color: var(--text-muted, #666);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -358,7 +357,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide-container {
|
.slide-container {
|
||||||
background: #fff;
|
background: var(--bg, #fff);
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||||
aspect-ratio: 16/9;
|
aspect-ratio: 16/9;
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
|
|
@ -380,7 +379,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
background: #fff;
|
background: var(--bg, #fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Markdown Viewer */
|
/* Markdown Viewer */
|
||||||
|
|
@ -389,20 +388,20 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
background: #fff;
|
background: var(--bg, #fff);
|
||||||
color: #333;
|
color: var(--text, #333);
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-markdown h1,
|
.projector-markdown h1,
|
||||||
.projector-markdown h2,
|
.projector-markdown h2,
|
||||||
.projector-markdown h3 {
|
.projector-markdown h3 {
|
||||||
color: #1a1a1a;
|
color: var(--text, #1a1a1a);
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-markdown code {
|
.projector-markdown code {
|
||||||
background: #f0f0f0;
|
background: var(--surface, #f0f0f0);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
|
@ -417,8 +416,8 @@
|
||||||
/* Controls */
|
/* Controls */
|
||||||
.projector-controls {
|
.projector-controls {
|
||||||
padding: 12px 20px;
|
padding: 12px 20px;
|
||||||
background: #252525;
|
background: var(--surface, #252525);
|
||||||
border-top: 1px solid #333;
|
border-top: 1px solid var(--border, #333);
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-controls,
|
.media-controls,
|
||||||
|
|
@ -439,9 +438,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-btn {
|
.control-btn {
|
||||||
background: #333;
|
background: var(--surface-hover, #333);
|
||||||
border: none;
|
border: none;
|
||||||
color: #fff;
|
color: var(--text, #fff);
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
@ -450,11 +449,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-btn:hover {
|
.control-btn:hover {
|
||||||
background: #444;
|
background: var(--surface-active, #444);
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-btn.active {
|
.control-btn.active {
|
||||||
background: #667eea;
|
background: var(--accent, #667eea);
|
||||||
}
|
}
|
||||||
|
|
||||||
.play-btn {
|
.play-btn {
|
||||||
|
|
@ -476,7 +475,7 @@
|
||||||
height: 6px;
|
height: 6px;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
background: #444;
|
background: var(--surface-active, #444);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
@ -485,7 +484,7 @@
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background: #667eea;
|
background: var(--accent, #667eea);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
@ -493,14 +492,14 @@
|
||||||
.progress-bar::-moz-range-thumb {
|
.progress-bar::-moz-range-thumb {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background: #667eea;
|
background: var(--accent, #667eea);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-display {
|
.time-display {
|
||||||
color: #888;
|
color: var(--text-muted, #888);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
@ -512,7 +511,7 @@
|
||||||
height: 4px;
|
height: 4px;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
background: #444;
|
background: var(--surface-active, #444);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
@ -521,7 +520,7 @@
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
background: #fff;
|
background: var(--bg, #fff);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
@ -529,8 +528,8 @@
|
||||||
/* Speed/Theme Select */
|
/* Speed/Theme Select */
|
||||||
.speed-select,
|
.speed-select,
|
||||||
.theme-select {
|
.theme-select {
|
||||||
background: #333;
|
background: var(--surface-hover, #333);
|
||||||
color: #fff;
|
color: var(--text, #fff);
|
||||||
border: none;
|
border: none;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|
@ -542,15 +541,15 @@
|
||||||
.image-info,
|
.image-info,
|
||||||
.code-info,
|
.code-info,
|
||||||
.zoom-level {
|
.zoom-level {
|
||||||
color: #888;
|
color: var(--text-muted, #888);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide-nav input {
|
.slide-nav input {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
background: #333;
|
background: var(--surface-hover, #333);
|
||||||
border: none;
|
border: none;
|
||||||
color: #fff;
|
color: var(--text, #fff);
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -562,7 +561,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
color: #e74c3c;
|
color: var(--error, #e74c3c);
|
||||||
}
|
}
|
||||||
|
|
||||||
.projector-error-icon {
|
.projector-error-icon {
|
||||||
|
|
@ -571,7 +570,7 @@
|
||||||
|
|
||||||
.projector-error-message {
|
.projector-error-message {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #888;
|
color: var(--text-muted, #888);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive */
|
/* Responsive */
|
||||||
|
|
@ -959,12 +958,12 @@ function loadGeneric(container, data) {
|
||||||
const wrapper = document.createElement('div');
|
const wrapper = document.createElement('div');
|
||||||
wrapper.style.textAlign = 'center';
|
wrapper.style.textAlign = 'center';
|
||||||
wrapper.style.padding = '40px';
|
wrapper.style.padding = '40px';
|
||||||
wrapper.style.color = '#888';
|
wrapper.style.color = 'var(--text-muted, #888)';
|
||||||
|
|
||||||
wrapper.innerHTML = `
|
wrapper.innerHTML = `
|
||||||
<div style="font-size: 64px; margin-bottom: 20px;">📁</div>
|
<div style="font-size: 64px; margin-bottom: 20px;">📁</div>
|
||||||
<div style="font-size: 18px; margin-bottom: 10px;">Cannot preview this file type</div>
|
<div style="font-size: 18px; margin-bottom: 10px;">Cannot preview this file type</div>
|
||||||
<a href="${data.source_url}" download style="color: #667eea; text-decoration: none;">
|
<a href="${data.source_url}" download style="color: var(--accent, #667eea); text-decoration: none;">
|
||||||
⬇️ Download File
|
⬇️ Download File
|
||||||
</a>
|
</a>
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -1085,9 +1085,27 @@ body {
|
||||||
|
|
||||||
.logo-icon {
|
.logo-icon {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 20px;
|
height: 32px;
|
||||||
color: var(--text, var(--text-primary, #ffffff));
|
color: var(--text, var(--text-primary, #ffffff));
|
||||||
flex-shrink: 0;
|
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 {
|
.logo-text {
|
||||||
|
|
|
||||||
|
|
@ -472,14 +472,15 @@ body.no-animations .spinner {
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo-icon {
|
.logo-icon {
|
||||||
width: 32px;
|
width: 40px;
|
||||||
height: 32px;
|
height: 40px;
|
||||||
background: linear-gradient(135deg, var(--primary), #8b5cf6);
|
background: linear-gradient(135deg, var(--primary), #8b5cf6);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================ */
|
/* ============================================ */
|
||||||
|
|
|
||||||
604
ui/suite/css/chat-agent-mode.css
Normal file
604
ui/suite/css/chat-agent-mode.css
Normal 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;
|
||||||
|
}
|
||||||
16
ui/suite/css/config-colors.css
Normal file
16
ui/suite/css/config-colors.css
Normal 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
295
ui/suite/css/desktop.css
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -395,3 +395,155 @@
|
||||||
-webkit-line-clamp: 3;
|
-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;
|
||||||
|
}
|
||||||
|
|
|
||||||
241
ui/suite/css/markdown-message.css
Normal file
241
ui/suite/css/markdown-message.css
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -876,7 +876,7 @@
|
||||||
[data-theme="sentient"] input,
|
[data-theme="sentient"] input,
|
||||||
[data-theme="sentient"] textarea,
|
[data-theme="sentient"] textarea,
|
||||||
[data-theme="sentient"] select {
|
[data-theme="sentient"] select {
|
||||||
background: var(--input-bg);
|
background: var(--surface);
|
||||||
border: 1px solid var(--input-border);
|
border: 1px solid var(--input-border);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
@ -884,6 +884,12 @@
|
||||||
transition: all 0.2s ease;
|
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"] input:focus,
|
||||||
[data-theme="sentient"] textarea:focus,
|
[data-theme="sentient"] textarea:focus,
|
||||||
[data-theme="sentient"] select:focus {
|
[data-theme="sentient"] select:focus {
|
||||||
|
|
|
||||||
9
ui/suite/css/vendor/all.min.css
vendored
Normal file
9
ui/suite/css/vendor/all.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
ui/suite/css/webfonts/fa-brands-400.woff2
Normal file
BIN
ui/suite/css/webfonts/fa-brands-400.woff2
Normal file
Binary file not shown.
BIN
ui/suite/css/webfonts/fa-regular-400.woff2
Normal file
BIN
ui/suite/css/webfonts/fa-regular-400.woff2
Normal file
Binary file not shown.
BIN
ui/suite/css/webfonts/fa-solid-900.woff2
Normal file
BIN
ui/suite/css/webfonts/fa-solid-900.woff2
Normal file
Binary file not shown.
|
|
@ -12,6 +12,10 @@
|
||||||
|
|
||||||
<!-- Styles -->
|
<!-- Styles -->
|
||||||
<link rel="stylesheet" href="css/app.css" />
|
<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) -->
|
<!-- Local Libraries (no external CDN dependencies) -->
|
||||||
<script src="js/vendor/gsap.min.js"></script>
|
<script src="js/vendor/gsap.min.js"></script>
|
||||||
|
|
@ -47,10 +51,7 @@
|
||||||
<!-- Right: Theme selector, Apps menu and user avatar -->
|
<!-- Right: Theme selector, Apps menu and user avatar -->
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<!-- Theme dropdown selector -->
|
<!-- Theme dropdown selector -->
|
||||||
<div
|
|
||||||
id="themeSelectorContainer"
|
|
||||||
aria-label="Theme selector"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<!-- Apps menu button -->
|
<!-- Apps menu button -->
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
733
ui/suite/desktop.html
Normal file
733
ui/suite/desktop.html
Normal 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: "Fira Code", 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>
|
||||||
680
ui/suite/desktop.html.backup
Normal file
680
ui/suite/desktop.html.backup
Normal 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: "Fira Code", 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>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<!-- Drive - File Management v1.0 -->
|
<!-- 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">
|
<div class="drive-container" id="drive-app">
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
|
|
@ -348,4 +348,4 @@
|
||||||
<!-- Context Menu (dynamically populated by JS) -->
|
<!-- Context Menu (dynamically populated by JS) -->
|
||||||
<div id="context-menu" class="context-menu hidden"></div>
|
<div id="context-menu" class="context-menu hidden"></div>
|
||||||
|
|
||||||
<script src="drive/drive.js"></script>
|
<script src="/suite/drive/drive.js"></script>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<nav class="nav-section">
|
<nav class="nav-section">
|
||||||
<div class="nav-item active"
|
<div class="nav-item active"
|
||||||
hx-get="/api/drive/files?path=/"
|
hx-get="/api/drive/files?path=/"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
onclick="setActiveNav(this)">
|
onclick="setActiveNav(this)">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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"
|
<div class="nav-item"
|
||||||
hx-get="/api/drive/files?filter=shared"
|
hx-get="/api/drive/files?filter=shared"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
onclick="setActiveNav(this)">
|
onclick="setActiveNav(this)">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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"
|
<div class="nav-item"
|
||||||
hx-get="/api/drive/files?filter=recent"
|
hx-get="/api/drive/files?filter=recent"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
onclick="setActiveNav(this)">
|
onclick="setActiveNav(this)">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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"
|
<div class="nav-item"
|
||||||
hx-get="/api/drive/files?filter=starred"
|
hx-get="/api/drive/files?filter=starred"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
onclick="setActiveNav(this)">
|
onclick="setActiveNav(this)">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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"
|
<div class="nav-item"
|
||||||
hx-get="/api/drive/files?filter=trash"
|
hx-get="/api/drive/files?filter=trash"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
onclick="setActiveNav(this)">
|
onclick="setActiveNav(this)">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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"
|
<select class="sort-dropdown" id="sort-dropdown"
|
||||||
hx-get="/api/drive/files"
|
hx-get="/api/drive/files"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-include="[name='path']">
|
hx-include="[name='path']">
|
||||||
<option value="name">Name</option>
|
<option value="name">Name</option>
|
||||||
|
|
@ -264,7 +264,7 @@
|
||||||
hx-delete="/api/drive/files"
|
hx-delete="/api/drive/files"
|
||||||
hx-include=".file-checkbox:checked"
|
hx-include=".file-checkbox:checked"
|
||||||
hx-confirm="Move selected items to trash?"
|
hx-confirm="Move selected items to trash?"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML">
|
hx-swap="innerHTML">
|
||||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
<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>
|
<polyline points="3 6 5 6 21 6"></polyline>
|
||||||
|
|
@ -322,7 +322,7 @@
|
||||||
<div class="upload-zone" id="upload-zone"
|
<div class="upload-zone" id="upload-zone"
|
||||||
hx-post="/api/drive/upload"
|
hx-post="/api/drive/upload"
|
||||||
hx-encoding="multipart/form-data"
|
hx-encoding="multipart/form-data"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML">
|
hx-swap="innerHTML">
|
||||||
<input type="file" id="file-input" name="files" multiple hidden>
|
<input type="file" id="file-input" name="files" multiple hidden>
|
||||||
<input type="hidden" name="path" id="upload-path" value="/">
|
<input type="hidden" name="path" id="upload-path" value="/">
|
||||||
|
|
@ -352,7 +352,7 @@
|
||||||
<dialog class="modal" id="folder-modal">
|
<dialog class="modal" id="folder-modal">
|
||||||
<form class="modal-content"
|
<form class="modal-content"
|
||||||
hx-post="/api/drive/folder"
|
hx-post="/api/drive/folder"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-on::after-request="document.getElementById('folder-modal').close()">
|
hx-on::after-request="document.getElementById('folder-modal').close()">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
@ -418,7 +418,7 @@
|
||||||
<dialog class="modal" id="copy-modal">
|
<dialog class="modal" id="copy-modal">
|
||||||
<form class="modal-content"
|
<form class="modal-content"
|
||||||
hx-post="/files/copy"
|
hx-post="/files/copy"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-on::after-request="document.getElementById('copy-modal').close()">
|
hx-on::after-request="document.getElementById('copy-modal').close()">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
@ -453,7 +453,7 @@
|
||||||
<dialog class="modal" id="move-modal">
|
<dialog class="modal" id="move-modal">
|
||||||
<form class="modal-content"
|
<form class="modal-content"
|
||||||
hx-post="/files/move"
|
hx-post="/files/move"
|
||||||
hx-target="#file-grid"
|
hx-target="closest .window-body #file-grid"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-on::after-request="document.getElementById('move-modal').close()">
|
hx-on::after-request="document.getElementById('move-modal').close()">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
|
@ -562,7 +562,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
<p>Combine multiple documents into one</p>
|
<p>Combine multiple documents into one</p>
|
||||||
<form hx-post="/docs/merge"
|
<form hx-post="/docs/merge"
|
||||||
hx-target="#docs-result"
|
hx-target="closest .window-body #docs-result"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-encoding="multipart/form-data">
|
hx-encoding="multipart/form-data">
|
||||||
<input type="file" name="files" multiple accept=".pdf,.docx,.doc,.txt" class="form-group" style="margin-bottom: 8px;">
|
<input type="file" name="files" multiple accept=".pdf,.docx,.doc,.txt" class="form-group" style="margin-bottom: 8px;">
|
||||||
|
|
@ -584,7 +584,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
<p>Convert between document formats</p>
|
<p>Convert between document formats</p>
|
||||||
<form hx-post="/docs/convert"
|
<form hx-post="/docs/convert"
|
||||||
hx-target="#docs-result"
|
hx-target="closest .window-body #docs-result"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-encoding="multipart/form-data">
|
hx-encoding="multipart/form-data">
|
||||||
<input type="file" name="file" accept=".pdf,.docx,.doc,.txt,.md,.html" class="form-group" style="margin-bottom: 8px;">
|
<input type="file" name="file" accept=".pdf,.docx,.doc,.txt,.md,.html" class="form-group" style="margin-bottom: 8px;">
|
||||||
|
|
@ -612,7 +612,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
<p>Populate template with data</p>
|
<p>Populate template with data</p>
|
||||||
<form hx-post="/docs/fill"
|
<form hx-post="/docs/fill"
|
||||||
hx-target="#docs-result"
|
hx-target="closest .window-body #docs-result"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-encoding="multipart/form-data">
|
hx-encoding="multipart/form-data">
|
||||||
<input type="file" name="template" accept=".docx,.doc" class="form-group" style="margin-bottom: 8px;">
|
<input type="file" name="template" accept=".docx,.doc" class="form-group" style="margin-bottom: 8px;">
|
||||||
|
|
@ -633,7 +633,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
<p>Export document in specified format</p>
|
<p>Export document in specified format</p>
|
||||||
<form hx-post="/docs/export"
|
<form hx-post="/docs/export"
|
||||||
hx-target="#docs-result"
|
hx-target="closest .window-body #docs-result"
|
||||||
hx-swap="innerHTML">
|
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;">
|
<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;">
|
<select name="format" class="sort-dropdown" style="width: 100%; margin-bottom: 8px;">
|
||||||
|
|
@ -657,7 +657,7 @@
|
||||||
</h3>
|
</h3>
|
||||||
<p>Import document from URL or upload</p>
|
<p>Import document from URL or upload</p>
|
||||||
<form hx-post="/docs/import"
|
<form hx-post="/docs/import"
|
||||||
hx-target="#docs-result"
|
hx-target="closest .window-body #docs-result"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-encoding="multipart/form-data">
|
hx-encoding="multipart/form-data">
|
||||||
<input type="url" name="url" placeholder="Document URL (optional)" class="form-group" style="width: 100%; margin-bottom: 8px;">
|
<input type="url" name="url" placeholder="Document URL (optional)" class="form-group" style="width: 100%; margin-bottom: 8px;">
|
||||||
|
|
|
||||||
1094
ui/suite/home.html
1094
ui/suite/home.html
File diff suppressed because it is too large
Load diff
1391
ui/suite/index.html
1391
ui/suite/index.html
File diff suppressed because it is too large
Load diff
|
|
@ -351,8 +351,8 @@
|
||||||
this.clearAuth();
|
this.clearAuth();
|
||||||
this.emit("tokenExpired");
|
this.emit("tokenExpired");
|
||||||
|
|
||||||
const currentPath = window.location.pathname;
|
const currentPath = window.location.pathname + window.location.hash;
|
||||||
if (!currentPath.startsWith("/auth/")) {
|
if (!window.location.pathname.startsWith("/auth/")) {
|
||||||
window.location.href =
|
window.location.href =
|
||||||
"/auth/login.html?expired=1&redirect=" +
|
"/auth/login.html?expired=1&redirect=" +
|
||||||
encodeURIComponent(currentPath);
|
encodeURIComponent(currentPath);
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,15 @@ function applyProductConfig(config) {
|
||||||
// Check if we have compiled_features info to filter even further
|
// 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
|
// 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)) {
|
if (config.compiled_features && Array.isArray(config.compiled_features)) {
|
||||||
const compiledSet = new Set(config.compiled_features.map(f => f.toLowerCase()));
|
const compiledSet = new Set(
|
||||||
effectiveApps = effectiveApps.filter(app =>
|
config.compiled_features.map((f) => f.toLowerCase()),
|
||||||
|
);
|
||||||
|
effectiveApps = effectiveApps.filter(
|
||||||
|
(app) =>
|
||||||
compiledSet.has(app.toLowerCase()) ||
|
compiledSet.has(app.toLowerCase()) ||
|
||||||
app.toLowerCase() === 'settings' ||
|
app.toLowerCase() === "settings" ||
|
||||||
app.toLowerCase() === 'auth' ||
|
app.toLowerCase() === "auth" ||
|
||||||
app.toLowerCase() === 'admin' // Admin usually contains settings which is always there
|
app.toLowerCase() === "admin", // Admin usually contains settings which is always there
|
||||||
);
|
);
|
||||||
|
|
||||||
// Also call a helper to hide UI elements for non-compiled features explicitly
|
// Also call a helper to hide UI elements for non-compiled features explicitly
|
||||||
|
|
@ -61,6 +64,33 @@ function applyProductConfig(config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
filterAppsByConfig(effectiveApps);
|
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
|
// Apply custom logo
|
||||||
|
|
@ -95,18 +125,22 @@ function applyProductConfig(config) {
|
||||||
// Hide UI elements that require features not compiled in the binary
|
// Hide UI elements that require features not compiled in the binary
|
||||||
function hideNonCompiledUI(compiledSet) {
|
function hideNonCompiledUI(compiledSet) {
|
||||||
// Hide elements with data-feature attribute that aren't in compiled set
|
// Hide elements with data-feature attribute that aren't in compiled set
|
||||||
document.querySelectorAll('[data-feature]').forEach(el => {
|
document.querySelectorAll("[data-feature]").forEach((el) => {
|
||||||
const feature = el.getAttribute('data-feature').toLowerCase();
|
const feature = el.getAttribute("data-feature").toLowerCase();
|
||||||
// Allow settings/admin as they are usually core
|
// Allow settings/admin as they are usually core
|
||||||
if (!compiledSet.has(feature) && feature !== 'settings' && feature !== 'admin') {
|
if (
|
||||||
el.style.display = 'none';
|
!compiledSet.has(feature) &&
|
||||||
el.classList.add('hidden-uncompiled');
|
feature !== "settings" &&
|
||||||
|
feature !== "admin"
|
||||||
|
) {
|
||||||
|
el.style.display = "none";
|
||||||
|
el.classList.add("hidden-uncompiled");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also look for specific sections that might map to features
|
// Also look for specific sections that might map to features
|
||||||
// e.g. .feature-mail, .feature-meet classes
|
// e.g. .feature-mail, .feature-meet classes
|
||||||
compiledSet.forEach(feature => {
|
compiledSet.forEach((feature) => {
|
||||||
// This loop defines what IS available.
|
// This loop defines what IS available.
|
||||||
// Logic should be inverse: find all feature- classes and hide if not in set
|
// Logic should be inverse: find all feature- classes and hide if not in set
|
||||||
// But scanning all classes is expensive.
|
// But scanning all classes is expensive.
|
||||||
|
|
|
||||||
302
ui/suite/js/chat-agent-mode.js
Normal file
302
ui/suite/js/chat-agent-mode.js
Normal 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
0
ui/suite/js/editor.js
Normal file
190
ui/suite/js/error-reporter.js
Normal file
190
ui/suite/js/error-reporter.js
Normal 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);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
@ -192,7 +192,6 @@
|
||||||
|
|
||||||
document.body.addEventListener("htmx:wsOpen", () => {
|
document.body.addEventListener("htmx:wsOpen", () => {
|
||||||
updateConnectionStatus("connected");
|
updateConnectionStatus("connected");
|
||||||
reconnectAttempts = 0;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.addEventListener("htmx:wsClose", () => {
|
document.body.addEventListener("htmx:wsClose", () => {
|
||||||
|
|
@ -203,7 +202,29 @@
|
||||||
|
|
||||||
// Handle WebSocket messages
|
// Handle WebSocket messages
|
||||||
function handleWebSocketMessage(message) {
|
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":
|
case "message":
|
||||||
appendMessage(message);
|
appendMessage(message);
|
||||||
break;
|
break;
|
||||||
|
|
@ -216,9 +237,46 @@
|
||||||
case "suggestion":
|
case "suggestion":
|
||||||
addSuggestion(message.text);
|
addSuggestion(message.text);
|
||||||
break;
|
break;
|
||||||
default:
|
case "change_theme":
|
||||||
console.log("Unknown message type:", message.type);
|
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:
|
||||||
|
// 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
|
// Append message to chat
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,13 @@
|
||||||
|
|
||||||
const DEFAULT_LOCALE = "en";
|
const DEFAULT_LOCALE = "en";
|
||||||
const STORAGE_KEY = "gb-locale";
|
const STORAGE_KEY = "gb-locale";
|
||||||
|
const CACHE_VERSION = "v2";
|
||||||
const CACHE_TTL_MS = 3600000;
|
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 = {
|
const MINIMAL_FALLBACK = {
|
||||||
"label-loading": "Loading...",
|
"label-loading": "Loading...",
|
||||||
"status-error": "Error",
|
"status-error": "Error",
|
||||||
|
|
@ -36,7 +41,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCacheKey(locale) {
|
function getCacheKey(locale) {
|
||||||
return `gb-i18n-cache-${locale}`;
|
return `gb-i18n-cache-${locale}}-${CACHE_VERSION}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCachedTranslations(locale) {
|
function getCachedTranslations(locale) {
|
||||||
|
|
@ -44,7 +49,9 @@
|
||||||
const cached = localStorage.getItem(getCacheKey(locale));
|
const cached = localStorage.getItem(getCacheKey(locale));
|
||||||
if (cached) {
|
if (cached) {
|
||||||
const { data, timestamp } = JSON.parse(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;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -70,6 +77,7 @@
|
||||||
|
|
||||||
async function fetchTranslations(locale) {
|
async function fetchTranslations(locale) {
|
||||||
try {
|
try {
|
||||||
|
console.log(`i18n: Fetching translations for locale: ${locale}`);
|
||||||
const response = await fetch(`/api/i18n/${locale}`, {
|
const response = await fetch(`/api/i18n/${locale}`, {
|
||||||
headers: { Accept: "application/json" },
|
headers: { Accept: "application/json" },
|
||||||
});
|
});
|
||||||
|
|
@ -79,21 +87,25 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
console.log(`i18n: Loaded ${Object.keys(result.translations || {}).length} translations for ${locale}`);
|
||||||
return result.translations || {};
|
return result.translations || {};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(`i18n: Failed to fetch translations for ${locale}`, e);
|
console.error(`i18n: Failed to fetch translations for ${locale}`, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadTranslations(locale) {
|
async function loadTranslations(locale) {
|
||||||
|
console.log(`i18n: loadTranslations called for locale: ${locale}`);
|
||||||
const cached = getCachedTranslations(locale);
|
const cached = getCachedTranslations(locale);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
|
console.log(`i18n: Using cached translations for ${locale}`);
|
||||||
translations = cached;
|
translations = cached;
|
||||||
currentLocale = locale;
|
currentLocale = locale;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`i18n: Cache miss, fetching from API for ${locale}`);
|
||||||
const fetched = await fetchTranslations(locale);
|
const fetched = await fetchTranslations(locale);
|
||||||
if (fetched && Object.keys(fetched).length > 0) {
|
if (fetched && Object.keys(fetched).length > 0) {
|
||||||
translations = fetched;
|
translations = fetched;
|
||||||
|
|
@ -107,6 +119,7 @@
|
||||||
return loadTranslations(DEFAULT_LOCALE);
|
return loadTranslations(DEFAULT_LOCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.warn(`i18n: No translations found, using minimal fallback`);
|
||||||
translations = MINIMAL_FALLBACK;
|
translations = MINIMAL_FALLBACK;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -114,6 +127,10 @@
|
||||||
function t(key, params) {
|
function t(key, params) {
|
||||||
let text = translations[key] || MINIMAL_FALLBACK[key] || key;
|
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") {
|
if (params && typeof params === "object") {
|
||||||
Object.keys(params).forEach((param) => {
|
Object.keys(params).forEach((param) => {
|
||||||
text = text.replace(
|
text = text.replace(
|
||||||
|
|
@ -232,14 +249,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
|
console.log("i18n: Initialization started");
|
||||||
if (isInitialized) {
|
if (isInitialized) {
|
||||||
|
console.log("i18n: Already initialized, skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const locale = detectBrowserLocale();
|
const locale = detectBrowserLocale();
|
||||||
|
console.log(`i18n: Detected locale: ${locale}`);
|
||||||
await loadTranslations(locale);
|
await loadTranslations(locale);
|
||||||
|
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
|
console.log(`i18n: Initialization complete, current locale: ${currentLocale}`);
|
||||||
|
|
||||||
if (document.readyState === "loading") {
|
if (document.readyState === "loading") {
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
@ -276,6 +297,7 @@
|
||||||
localStorage.removeItem(key);
|
localStorage.removeItem(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
console.log("i18n: Cleared all translation caches");
|
||||||
}
|
}
|
||||||
|
|
||||||
window.i18n = {
|
window.i18n = {
|
||||||
|
|
|
||||||
|
|
@ -210,10 +210,14 @@
|
||||||
return originalFetch
|
return originalFetch
|
||||||
.call(window, input, init)
|
.call(window, input, init)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
if (response.status === 401) {
|
|
||||||
var url = typeof input === "string" ? input : input.url;
|
var url = typeof input === "string" ? input : input.url;
|
||||||
|
|
||||||
|
if (response.status === 401) {
|
||||||
self.handleUnauthorized(url);
|
self.handleUnauthorized(url);
|
||||||
|
} else if (!response.ok && window.ErrorReporter && window.ErrorReporter.reportNetworkError) {
|
||||||
|
window.ErrorReporter.reportNetworkError(url, response.status, response.statusText);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -295,6 +299,12 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("gb:auth:expired", function (event) {
|
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(
|
console.log(
|
||||||
"[GBSecurity] Auth expired, clearing tokens and redirecting",
|
"[GBSecurity] Auth expired, clearing tokens and redirecting",
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ window.Suite = {
|
||||||
description: "",
|
description: "",
|
||||||
actions: [],
|
actions: [],
|
||||||
searchable: true,
|
searchable: true,
|
||||||
...config
|
...config,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Trigger UI update if Omnibox is initialized
|
// Trigger UI update if Omnibox is initialized
|
||||||
if (typeof Omnibox !== 'undefined' && Omnibox.isActive) {
|
if (typeof Omnibox !== "undefined" && Omnibox.isActive) {
|
||||||
Omnibox.updateActions();
|
Omnibox.updateActions();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -36,7 +36,7 @@ window.Suite = {
|
||||||
getContextActions(contextId) {
|
getContextActions(contextId) {
|
||||||
const app = this.apps.get(contextId);
|
const app = this.apps.get(contextId);
|
||||||
return app ? app.actions : null;
|
return app ? app.actions : null;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
@ -55,18 +55,23 @@ const Omnibox = {
|
||||||
this.backdrop = document.getElementById("omniboxBackdrop");
|
this.backdrop = document.getElementById("omniboxBackdrop");
|
||||||
this.results = document.getElementById("omniboxResults");
|
this.results = document.getElementById("omniboxResults");
|
||||||
this.chat = document.getElementById("omniboxChat");
|
this.chat = document.getElementById("omniboxChat");
|
||||||
this.chatMessages = document.getElementById(
|
this.chatMessages = document.getElementById("omniboxChatMessages");
|
||||||
"omniboxChatMessages",
|
this.chatInput = document.getElementById("omniboxChatInput");
|
||||||
);
|
this.modeToggle = document.getElementById("omniboxModeToggle");
|
||||||
this.chatInput =
|
|
||||||
document.getElementById("omniboxChatInput");
|
|
||||||
this.modeToggle =
|
|
||||||
document.getElementById("omniboxModeToggle");
|
|
||||||
|
|
||||||
|
// Only bind events if all required elements exist
|
||||||
|
if (this.input && this.backdrop) {
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
bindEvents() {
|
bindEvents() {
|
||||||
|
// Defensive: ensure elements exist before binding
|
||||||
|
if (!this.input || !this.backdrop) {
|
||||||
|
console.warn("[Omnibox] Required elements not found, skipping event binding");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Input focus/blur
|
// Input focus/blur
|
||||||
this.input.addEventListener("focus", () => this.open());
|
this.input.addEventListener("focus", () => this.open());
|
||||||
this.backdrop.addEventListener("click", () => this.close());
|
this.backdrop.addEventListener("click", () => this.close());
|
||||||
|
|
@ -77,9 +82,7 @@ const Omnibox = {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Keyboard navigation
|
// Keyboard navigation
|
||||||
this.input.addEventListener("keydown", (e) =>
|
this.input.addEventListener("keydown", (e) => this.handleKeydown(e));
|
||||||
this.handleKeydown(e),
|
|
||||||
);
|
|
||||||
this.chatInput?.addEventListener("keydown", (e) => {
|
this.chatInput?.addEventListener("keydown", (e) => {
|
||||||
if (e.key === "Enter" && !e.shiftKey) {
|
if (e.key === "Enter" && !e.shiftKey) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -94,12 +97,8 @@ const Omnibox = {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Action buttons
|
// Action buttons
|
||||||
document
|
document.querySelectorAll(".omnibox-action").forEach((btn) => {
|
||||||
.querySelectorAll(".omnibox-action")
|
btn.addEventListener("click", () => this.handleAction(btn));
|
||||||
.forEach((btn) => {
|
|
||||||
btn.addEventListener("click", () =>
|
|
||||||
this.handleAction(btn),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Send button
|
// Send button
|
||||||
|
|
@ -115,9 +114,7 @@ const Omnibox = {
|
||||||
// Expand button
|
// Expand button
|
||||||
document
|
document
|
||||||
.getElementById("omniboxExpandBtn")
|
.getElementById("omniboxExpandBtn")
|
||||||
?.addEventListener("click", () =>
|
?.addEventListener("click", () => this.expandToFullChat());
|
||||||
this.expandToFullChat(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Global shortcut (Cmd+K / Ctrl+K)
|
// Global shortcut (Cmd+K / Ctrl+K)
|
||||||
document.addEventListener("keydown", (e) => {
|
document.addEventListener("keydown", (e) => {
|
||||||
|
|
@ -159,17 +156,11 @@ const Omnibox = {
|
||||||
|
|
||||||
if (e.key === "ArrowDown") {
|
if (e.key === "ArrowDown") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.selectedIndex = Math.min(
|
this.selectedIndex = Math.min(this.selectedIndex + 1, actions.length - 1);
|
||||||
this.selectedIndex + 1,
|
|
||||||
actions.length - 1,
|
|
||||||
);
|
|
||||||
this.updateSelection(actions);
|
this.updateSelection(actions);
|
||||||
} else if (e.key === "ArrowUp") {
|
} else if (e.key === "ArrowUp") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.selectedIndex = Math.max(
|
this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
|
||||||
this.selectedIndex - 1,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
this.updateSelection(actions);
|
this.updateSelection(actions);
|
||||||
} else if (e.key === "Enter") {
|
} else if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -185,17 +176,13 @@ const Omnibox = {
|
||||||
|
|
||||||
updateSelection(actions) {
|
updateSelection(actions) {
|
||||||
actions.forEach((a, i) => {
|
actions.forEach((a, i) => {
|
||||||
a.classList.toggle(
|
a.classList.toggle("selected", i === this.selectedIndex);
|
||||||
"selected",
|
|
||||||
i === this.selectedIndex,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateActions() {
|
updateActions() {
|
||||||
const currentApp = this.getCurrentApp();
|
const currentApp = this.getCurrentApp();
|
||||||
const actionsContainer =
|
const actionsContainer = document.getElementById("omniboxActions");
|
||||||
document.getElementById("omniboxActions");
|
|
||||||
|
|
||||||
const contextActions = {
|
const contextActions = {
|
||||||
chat: [
|
chat: [
|
||||||
|
|
@ -362,12 +349,8 @@ const Omnibox = {
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
// Rebind events
|
// Rebind events
|
||||||
actionsContainer
|
actionsContainer.querySelectorAll(".omnibox-action").forEach((btn) => {
|
||||||
.querySelectorAll(".omnibox-action")
|
btn.addEventListener("click", () => this.handleAction(btn));
|
||||||
.forEach((btn) => {
|
|
||||||
btn.addEventListener("click", () =>
|
|
||||||
this.handleAction(btn),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.selectedIndex = 0;
|
this.selectedIndex = 0;
|
||||||
|
|
@ -398,9 +381,7 @@ const Omnibox = {
|
||||||
|
|
||||||
navigateTo(target) {
|
navigateTo(target) {
|
||||||
this.close();
|
this.close();
|
||||||
const link = document.querySelector(
|
const link = document.querySelector(`a[data-section="${target}"]`);
|
||||||
`a[data-section="${target}"]`,
|
|
||||||
);
|
|
||||||
if (link) {
|
if (link) {
|
||||||
link.click();
|
link.click();
|
||||||
}
|
}
|
||||||
|
|
@ -436,32 +417,24 @@ const Omnibox = {
|
||||||
},
|
},
|
||||||
|
|
||||||
showDefaultActions() {
|
showDefaultActions() {
|
||||||
document.getElementById(
|
document.getElementById("searchResultsSection").style.display = "none";
|
||||||
"searchResultsSection",
|
|
||||||
).style.display = "none";
|
|
||||||
this.updateActions();
|
this.updateActions();
|
||||||
},
|
},
|
||||||
|
|
||||||
searchContent(query) {
|
searchContent(query) {
|
||||||
// Show search results section
|
// Show search results section
|
||||||
const resultsSection = document.getElementById(
|
const resultsSection = document.getElementById("searchResultsSection");
|
||||||
"searchResultsSection",
|
const resultsList = document.getElementById("searchResultsList");
|
||||||
);
|
|
||||||
const resultsList =
|
|
||||||
document.getElementById("searchResultsList");
|
|
||||||
|
|
||||||
resultsSection.style.display = "block";
|
resultsSection.style.display = "block";
|
||||||
|
|
||||||
// Update first action to be "Ask about: query"
|
// Update first action to be "Ask about: query"
|
||||||
const actionsContainer =
|
const actionsContainer = document.getElementById("omniboxActions");
|
||||||
document.getElementById("omniboxActions");
|
const firstAction = actionsContainer.querySelector(".omnibox-action");
|
||||||
const firstAction =
|
|
||||||
actionsContainer.querySelector(".omnibox-action");
|
|
||||||
if (firstAction) {
|
if (firstAction) {
|
||||||
firstAction.dataset.action = "chat";
|
firstAction.dataset.action = "chat";
|
||||||
firstAction.dataset.query = query;
|
firstAction.dataset.query = query;
|
||||||
firstAction.querySelector(".action-icon").textContent =
|
firstAction.querySelector(".action-icon").textContent = "💬";
|
||||||
"💬";
|
|
||||||
firstAction.querySelector(".action-text").textContent =
|
firstAction.querySelector(".action-text").textContent =
|
||||||
`Ask: "${query.substring(0, 30)}${query.length > 30 ? "..." : ""}"`;
|
`Ask: "${query.substring(0, 30)}${query.length > 30 ? "..." : ""}"`;
|
||||||
}
|
}
|
||||||
|
|
@ -485,12 +458,8 @@ const Omnibox = {
|
||||||
'<div class="no-results">No results found. Try asking the bot!</div>';
|
'<div class="no-results">No results found. Try asking the bot!</div>';
|
||||||
|
|
||||||
// Bind click events
|
// Bind click events
|
||||||
resultsList
|
resultsList.querySelectorAll(".omnibox-result").forEach((btn) => {
|
||||||
.querySelectorAll(".omnibox-result")
|
btn.addEventListener("click", () => this.navigateTo(btn.dataset.target));
|
||||||
.forEach((btn) => {
|
|
||||||
btn.addEventListener("click", () =>
|
|
||||||
this.navigateTo(btn.dataset.target),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -581,17 +550,16 @@ const Omnibox = {
|
||||||
title: "Settings",
|
title: "Settings",
|
||||||
description: "App settings",
|
description: "App settings",
|
||||||
},
|
},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Add plugin apps
|
// Add plugin apps
|
||||||
const pluginApps = window.Suite.getAllApps()
|
const pluginApps = window.Suite.getAllApps()
|
||||||
.filter(app => app.searchable)
|
.filter((app) => app.searchable)
|
||||||
.map(app => ({
|
.map((app) => ({
|
||||||
target: app.id,
|
target: app.id,
|
||||||
icon: app.icon || "📦",
|
icon: app.icon || "📦",
|
||||||
title: app.title || app.id,
|
title: app.title || app.id,
|
||||||
description: app.description || "App plugin"
|
description: app.description || "App plugin",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const allItems = items.concat(pluginApps);
|
const allItems = items.concat(pluginApps);
|
||||||
|
|
@ -641,9 +609,7 @@ const Omnibox = {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.addMessage(
|
this.addMessage(
|
||||||
data.reply ||
|
data.reply || data.message || "I received your message.",
|
||||||
data.message ||
|
|
||||||
"I received your message.",
|
|
||||||
"bot",
|
"bot",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -660,10 +626,7 @@ const Omnibox = {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.removeTypingIndicator(typingId);
|
this.removeTypingIndicator(typingId);
|
||||||
// Fallback response when API is not available
|
// Fallback response when API is not available
|
||||||
this.addMessage(
|
this.addMessage(this.getFallbackResponse(message), "bot");
|
||||||
this.getFallbackResponse(message),
|
|
||||||
"bot",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -697,8 +660,7 @@ const Omnibox = {
|
||||||
<div class="message-content">${this.escapeHtml(text)}</div>
|
<div class="message-content">${this.escapeHtml(text)}</div>
|
||||||
`;
|
`;
|
||||||
this.chatMessages.appendChild(msgDiv);
|
this.chatMessages.appendChild(msgDiv);
|
||||||
this.chatMessages.scrollTop =
|
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
|
||||||
this.chatMessages.scrollHeight;
|
|
||||||
|
|
||||||
this.chatHistory.push({ role: sender, content: text });
|
this.chatHistory.push({ role: sender, content: text });
|
||||||
},
|
},
|
||||||
|
|
@ -715,8 +677,7 @@ const Omnibox = {
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
this.chatMessages.appendChild(typingDiv);
|
this.chatMessages.appendChild(typingDiv);
|
||||||
this.chatMessages.scrollTop =
|
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
|
||||||
this.chatMessages.scrollHeight;
|
|
||||||
return id;
|
return id;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -727,18 +688,13 @@ const Omnibox = {
|
||||||
|
|
||||||
handleBotAction(action) {
|
handleBotAction(action) {
|
||||||
if (action.navigate) {
|
if (action.navigate) {
|
||||||
setTimeout(
|
setTimeout(() => this.navigateTo(action.navigate), 1000);
|
||||||
() => this.navigateTo(action.navigate),
|
|
||||||
1000,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
expandToFullChat() {
|
expandToFullChat() {
|
||||||
this.close();
|
this.close();
|
||||||
const chatLink = document.querySelector(
|
const chatLink = document.querySelector('a[data-section="chat"]');
|
||||||
'a[data-section="chat"]',
|
|
||||||
);
|
|
||||||
if (chatLink) chatLink.click();
|
if (chatLink) chatLink.click();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -751,17 +707,69 @@ const Omnibox = {
|
||||||
|
|
||||||
// Initialize Omnibox when DOM is ready
|
// Initialize Omnibox when DOM is ready
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
// Detect bot name from pathname (e.g., /bot/cristo -> bot_name = "cristo", /edu -> bot_name = "edu")
|
||||||
|
const detectBotFromPath = () => {
|
||||||
|
const pathname = window.location.pathname;
|
||||||
|
// Remove leading/trailing slashes and split
|
||||||
|
const segments = pathname.replace(/^\/|\/$/g, "").split("/");
|
||||||
|
|
||||||
|
// Handle /bot/{bot_name} pattern
|
||||||
|
if (segments[0] === "bot" && segments[1]) {
|
||||||
|
return segments[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// For other patterns, use first segment if it's not a known route
|
||||||
|
const firstSegment = segments[0];
|
||||||
|
const knownRoutes = ["suite", "auth", "api", "static", "public", "bot"];
|
||||||
|
if (firstSegment && !knownRoutes.includes(firstSegment)) {
|
||||||
|
return firstSegment;
|
||||||
|
}
|
||||||
|
return "default";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set global bot name
|
||||||
|
window.__INITIAL_BOT_NAME__ = detectBotFromPath();
|
||||||
|
console.log(`🤖 Bot detected from path: ${window.__INITIAL_BOT_NAME__}`);
|
||||||
|
|
||||||
|
// Check if bot is public to skip authentication
|
||||||
|
const checkBotPublicStatus = async () => {
|
||||||
|
try {
|
||||||
|
const botName = window.__INITIAL_BOT_NAME__;
|
||||||
|
if (!botName || botName === "default") return;
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/bot/config?bot_name=${encodeURIComponent(botName)}`,
|
||||||
|
);
|
||||||
|
if (response.ok) {
|
||||||
|
const config = await response.json();
|
||||||
|
if (config.public === true) {
|
||||||
|
window.__BOT_IS_PUBLIC__ = true;
|
||||||
|
console.log(
|
||||||
|
`✅ Bot '${botName}' is public - authentication not required`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Failed to check bot public status:", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Omnibox.init();
|
Omnibox.init();
|
||||||
console.log("🚀 Initializing General Bots with HTMX...");
|
console.log("🚀 Initializing General Bots with HTMX...");
|
||||||
|
|
||||||
// Hide loading overlay
|
// Check bot public status early
|
||||||
setTimeout(() => {
|
checkBotPublicStatus();
|
||||||
const loadingOverlay =
|
|
||||||
document.getElementById("loadingOverlay");
|
// Provide a global function to hide the loading overlay
|
||||||
if (loadingOverlay) {
|
window.hideLoadingOverlay = function() {
|
||||||
|
const loadingOverlay = document.getElementById("loadingOverlay");
|
||||||
|
if (loadingOverlay && !loadingOverlay.classList.contains("hidden")) {
|
||||||
loadingOverlay.classList.add("hidden");
|
loadingOverlay.classList.add("hidden");
|
||||||
}
|
}
|
||||||
}, 500);
|
};
|
||||||
|
|
||||||
|
// Failsafe: hide after 10 seconds if no message arrives
|
||||||
|
setTimeout(window.hideLoadingOverlay, 10000);
|
||||||
|
|
||||||
// Simple apps menu handling
|
// Simple apps menu handling
|
||||||
const appsBtn = document.getElementById("appsButton");
|
const appsBtn = document.getElementById("appsButton");
|
||||||
|
|
@ -775,15 +783,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
const isOpen = appsDropdown.classList.toggle("show");
|
const isOpen = appsDropdown.classList.toggle("show");
|
||||||
appsBtn.setAttribute("aria-expanded", isOpen);
|
appsBtn.setAttribute("aria-expanded", isOpen);
|
||||||
// Close settings panel
|
// Close settings panel
|
||||||
if (settingsPanel)
|
if (settingsPanel) settingsPanel.classList.remove("show");
|
||||||
settingsPanel.classList.remove("show");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("click", (e) => {
|
document.addEventListener("click", (e) => {
|
||||||
if (
|
if (!appsDropdown.contains(e.target) && !appsBtn.contains(e.target)) {
|
||||||
!appsDropdown.contains(e.target) &&
|
|
||||||
!appsBtn.contains(e.target)
|
|
||||||
) {
|
|
||||||
appsDropdown.classList.remove("show");
|
appsDropdown.classList.remove("show");
|
||||||
appsBtn.setAttribute("aria-expanded", "false");
|
appsBtn.setAttribute("aria-expanded", "false");
|
||||||
}
|
}
|
||||||
|
|
@ -813,8 +817,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
// Theme selection handling
|
// Theme selection handling
|
||||||
const themeOptions = document.querySelectorAll(".theme-option");
|
const themeOptions = document.querySelectorAll(".theme-option");
|
||||||
const savedTheme =
|
const savedTheme = localStorage.getItem("gb-theme") || "sentient";
|
||||||
localStorage.getItem("gb-theme") || "sentient";
|
|
||||||
|
|
||||||
// Apply saved theme
|
// Apply saved theme
|
||||||
document.body.setAttribute("data-theme", savedTheme);
|
document.body.setAttribute("data-theme", savedTheme);
|
||||||
|
|
@ -827,9 +830,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
const theme = option.getAttribute("data-theme");
|
const theme = option.getAttribute("data-theme");
|
||||||
document.body.setAttribute("data-theme", theme);
|
document.body.setAttribute("data-theme", theme);
|
||||||
localStorage.setItem("gb-theme", theme);
|
localStorage.setItem("gb-theme", theme);
|
||||||
themeOptions.forEach((o) =>
|
themeOptions.forEach((o) => o.classList.remove("active"));
|
||||||
o.classList.remove("active"),
|
|
||||||
);
|
|
||||||
option.classList.add("active");
|
option.classList.add("active");
|
||||||
|
|
||||||
// Update theme-color meta tag
|
// Update theme-color meta tag
|
||||||
|
|
@ -841,14 +842,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
orange: "#f97316",
|
orange: "#f97316",
|
||||||
sentient: "#d4f505",
|
sentient: "#d4f505",
|
||||||
};
|
};
|
||||||
const metaTheme = document.querySelector(
|
const metaTheme = document.querySelector('meta[name="theme-color"]');
|
||||||
'meta[name="theme-color"]',
|
|
||||||
);
|
|
||||||
if (metaTheme) {
|
if (metaTheme) {
|
||||||
metaTheme.setAttribute(
|
metaTheme.setAttribute("content", themeColors[theme] || "#d4f505");
|
||||||
"content",
|
|
||||||
themeColors[theme] || "#d4f505",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -959,17 +955,13 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
// Validate target exists before triggering HTMX load
|
// Validate target exists before triggering HTMX load
|
||||||
if (!mainContent) {
|
if (!mainContent) {
|
||||||
console.warn(
|
console.warn("handleHashChange: #main-content not found, skipping load");
|
||||||
"handleHashChange: #main-content not found, skipping load",
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if main-content is in the DOM
|
// Check if main-content is in the DOM
|
||||||
if (!document.body.contains(mainContent)) {
|
if (!document.body.contains(mainContent)) {
|
||||||
console.warn(
|
console.warn("handleHashChange: #main-content not in DOM, skipping load");
|
||||||
"handleHashChange: #main-content not in DOM, skipping load",
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -984,8 +976,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
// Debounce the load to prevent rapid double-requests
|
// Debounce the load to prevent rapid double-requests
|
||||||
pendingLoadTimeout = setTimeout(() => {
|
pendingLoadTimeout = setTimeout(() => {
|
||||||
// Re-check if section changed during debounce
|
// Re-check if section changed during debounce
|
||||||
const currentHash =
|
const currentHash = window.location.hash.slice(1) || "chat";
|
||||||
window.location.hash.slice(1) || "chat";
|
|
||||||
if (currentLoadedSection === currentHash) {
|
if (currentLoadedSection === currentHash) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1005,10 +996,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
swap: "innerHTML",
|
swap: "innerHTML",
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(
|
console.warn("handleHashChange: HTMX ajax error:", e);
|
||||||
"handleHashChange: HTMX ajax error:",
|
|
||||||
e,
|
|
||||||
);
|
|
||||||
currentLoadedSection = null;
|
currentLoadedSection = null;
|
||||||
isLoadingSection = false;
|
isLoadingSection = false;
|
||||||
}
|
}
|
||||||
|
|
@ -1019,10 +1007,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
// Listen for HTMX swaps to track loaded sections and prevent duplicates
|
// Listen for HTMX swaps to track loaded sections and prevent duplicates
|
||||||
document.body.addEventListener("htmx:afterSwap", (event) => {
|
document.body.addEventListener("htmx:afterSwap", (event) => {
|
||||||
if (
|
if (event.detail.target && event.detail.target.id === "main-content") {
|
||||||
event.detail.target &&
|
|
||||||
event.detail.target.id === "main-content"
|
|
||||||
) {
|
|
||||||
const hash = window.location.hash.slice(1) || "chat";
|
const hash = window.location.hash.slice(1) || "chat";
|
||||||
currentLoadedSection = hash;
|
currentLoadedSection = hash;
|
||||||
isLoadingSection = false;
|
isLoadingSection = false;
|
||||||
|
|
@ -1031,27 +1016,18 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
// Reset tracking on swap errors
|
// Reset tracking on swap errors
|
||||||
document.body.addEventListener("htmx:swapError", (event) => {
|
document.body.addEventListener("htmx:swapError", (event) => {
|
||||||
if (
|
if (event.detail.target && event.detail.target.id === "main-content") {
|
||||||
event.detail.target &&
|
|
||||||
event.detail.target.id === "main-content"
|
|
||||||
) {
|
|
||||||
isLoadingSection = false;
|
isLoadingSection = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also listen for response errors
|
// Also listen for response errors
|
||||||
document.body.addEventListener(
|
document.body.addEventListener("htmx:responseError", (event) => {
|
||||||
"htmx:responseError",
|
if (event.detail.target && event.detail.target.id === "main-content") {
|
||||||
(event) => {
|
|
||||||
if (
|
|
||||||
event.detail.target &&
|
|
||||||
event.detail.target.id === "main-content"
|
|
||||||
) {
|
|
||||||
isLoadingSection = false;
|
isLoadingSection = false;
|
||||||
currentLoadedSection = null;
|
currentLoadedSection = null;
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// Load initial content based on hash or default to chat
|
// Load initial content based on hash or default to chat
|
||||||
window.addEventListener("hashchange", handleHashChange);
|
window.addEventListener("hashchange", handleHashChange);
|
||||||
|
|
@ -1065,7 +1041,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.readyState === "complete") {
|
// Skip SPA initialization on auth pages (login, register, etc.) and desktop
|
||||||
|
if (window.location.pathname.startsWith("/auth/")) {
|
||||||
|
console.log("[SPA] Skipping initialization on auth page");
|
||||||
|
} else if (document.getElementById('desktop-content')) {
|
||||||
|
console.log("[SPA] Skipping initialization on desktop page");
|
||||||
|
} else if (document.readyState === "complete") {
|
||||||
setTimeout(initialLoad, 50);
|
setTimeout(initialLoad, 50);
|
||||||
} else {
|
} else {
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
|
|
@ -1082,17 +1063,13 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
const list = document.getElementById("notificationsList");
|
const list = document.getElementById("notificationsList");
|
||||||
const btn = document.getElementById("notificationsBtn");
|
const btn = document.getElementById("notificationsBtn");
|
||||||
const panel = document.getElementById("notificationsPanel");
|
const panel = document.getElementById("notificationsPanel");
|
||||||
const clearBtn = document.getElementById(
|
const clearBtn = document.getElementById("clearNotificationsBtn");
|
||||||
"clearNotificationsBtn",
|
|
||||||
);
|
|
||||||
|
|
||||||
function updateBadge() {
|
function updateBadge() {
|
||||||
if (badge) {
|
if (badge) {
|
||||||
if (notifications.length > 0) {
|
if (notifications.length > 0) {
|
||||||
badge.textContent =
|
badge.textContent =
|
||||||
notifications.length > 99
|
notifications.length > 99 ? "99+" : notifications.length;
|
||||||
? "99+"
|
|
||||||
: notifications.length;
|
|
||||||
badge.style.display = "flex";
|
badge.style.display = "flex";
|
||||||
} else {
|
} else {
|
||||||
badge.style.display = "none";
|
badge.style.display = "none";
|
||||||
|
|
@ -1172,10 +1149,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("click", (e) => {
|
document.addEventListener("click", (e) => {
|
||||||
if (
|
if (!panel.contains(e.target) && !btn.contains(e.target)) {
|
||||||
!panel.contains(e.target) &&
|
|
||||||
!btn.contains(e.target)
|
|
||||||
) {
|
|
||||||
panel.classList.remove("show");
|
panel.classList.remove("show");
|
||||||
btn.setAttribute("aria-expanded", "false");
|
btn.setAttribute("aria-expanded", "false");
|
||||||
}
|
}
|
||||||
|
|
@ -1241,9 +1215,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
? "🔴"
|
? "🔴"
|
||||||
: "🟡",
|
: "🟡",
|
||||||
title:
|
title:
|
||||||
"Connection " +
|
"Connection " + status.charAt(0).toUpperCase() + status.slice(1),
|
||||||
status.charAt(0).toUpperCase() +
|
|
||||||
status.slice(1),
|
|
||||||
message: message || "",
|
message: message || "",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -1256,8 +1228,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
if (e.altKey && !e.ctrlKey && !e.shiftKey) {
|
if (e.altKey && !e.ctrlKey && !e.shiftKey) {
|
||||||
const num = parseInt(e.key);
|
const num = parseInt(e.key);
|
||||||
if (num >= 1 && num <= 9) {
|
if (num >= 1 && num <= 9) {
|
||||||
const items =
|
const items = document.querySelectorAll(".app-item");
|
||||||
document.querySelectorAll(".app-item");
|
|
||||||
if (items[num - 1]) {
|
if (items[num - 1]) {
|
||||||
items[num - 1].click();
|
items[num - 1].click();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -1281,21 +1252,18 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
const userName = document.getElementById("userName");
|
const userName = document.getElementById("userName");
|
||||||
const userEmail = document.getElementById("userEmail");
|
const userEmail = document.getElementById("userEmail");
|
||||||
const userAvatar = document.getElementById("userAvatar");
|
const userAvatar = document.getElementById("userAvatar");
|
||||||
const userAvatarLarge =
|
const userAvatarLarge = document.getElementById("userAvatarLarge");
|
||||||
document.getElementById("userAvatarLarge");
|
|
||||||
const authAction = document.getElementById("authAction");
|
const authAction = document.getElementById("authAction");
|
||||||
const authText = document.getElementById("authText");
|
const authText = document.getElementById("authText");
|
||||||
const authIcon = document.getElementById("authIcon");
|
const authIcon = document.getElementById("authIcon");
|
||||||
|
const settingsBtn = document.getElementById("settingsBtn");
|
||||||
|
const appsButton = document.getElementById("appsButton");
|
||||||
|
const notificationsBtn = document.getElementById("notificationsBtn");
|
||||||
|
|
||||||
const displayName =
|
const displayName =
|
||||||
user.display_name ||
|
user.display_name || user.first_name || user.username || "User";
|
||||||
user.first_name ||
|
|
||||||
user.username ||
|
|
||||||
"User";
|
|
||||||
const email = user.email || "";
|
const email = user.email || "";
|
||||||
const initial = (
|
const initial = (displayName.charAt(0) || "U").toUpperCase();
|
||||||
displayName.charAt(0) || "U"
|
|
||||||
).toUpperCase();
|
|
||||||
|
|
||||||
console.log("Updating user UI:", displayName, email);
|
console.log("Updating user UI:", displayName, email);
|
||||||
|
|
||||||
|
|
@ -1328,14 +1296,35 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
authIcon.innerHTML =
|
authIcon.innerHTML =
|
||||||
'<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line>';
|
'<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settingsBtn) settingsBtn.style.display = "";
|
||||||
|
if (appsButton) appsButton.style.display = "";
|
||||||
|
if (notificationsBtn) notificationsBtn.style.display = "";
|
||||||
|
|
||||||
|
// Show omnibox (search bar) when signed in
|
||||||
|
const omnibox = document.getElementById("omnibox");
|
||||||
|
if (omnibox) omnibox.style.display = "";
|
||||||
|
|
||||||
|
// Show Drive, Tasks, CRM, and Calendar navigation when signed in (all instances)
|
||||||
|
const driveTabs = document.querySelectorAll('[data-section="drive"]');
|
||||||
|
const tasksTabs = document.querySelectorAll('[data-section="tasks"]');
|
||||||
|
const crmTabs = document.querySelectorAll('[data-section="crm"]');
|
||||||
|
const calendarTabs = document.querySelectorAll('[data-section="calendar"]');
|
||||||
|
|
||||||
|
driveTabs.forEach(tab => tab.style.display = "");
|
||||||
|
tasksTabs.forEach(tab => tab.style.display = "");
|
||||||
|
crmTabs.forEach(tab => tab.style.display = "");
|
||||||
|
calendarTabs.forEach(tab => tab.style.display = "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadUserProfile() {
|
function loadUserProfile() {
|
||||||
var token =
|
var token =
|
||||||
localStorage.getItem("gb-access-token") ||
|
localStorage.getItem("gb-access-token") ||
|
||||||
sessionStorage.getItem("gb-access-token");
|
sessionStorage.getItem("gb-access-token");
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
console.log("No auth token found");
|
console.log("No auth token found - user is signed out");
|
||||||
|
updateSignedOutUI();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1348,22 +1337,75 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
headers: { Authorization: "Bearer " + token },
|
headers: { Authorization: "Bearer " + token },
|
||||||
})
|
})
|
||||||
.then(function (res) {
|
.then(function (res) {
|
||||||
if (!res.ok) throw new Error("Not authenticated");
|
if (!res.ok) {
|
||||||
|
console.log("User not authenticated");
|
||||||
|
updateSignedOutUI();
|
||||||
|
throw new Error("Not authenticated");
|
||||||
|
}
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.then(function (user) {
|
.then(function (user) {
|
||||||
console.log("User profile loaded:", user);
|
console.log("User profile loaded:", user);
|
||||||
updateUserUI(user);
|
updateUserUI(user);
|
||||||
localStorage.setItem(
|
localStorage.setItem("gb-user-data", JSON.stringify(user));
|
||||||
"gb-user-data",
|
|
||||||
JSON.stringify(user),
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
console.log("Failed to load user profile:", err);
|
console.log("Failed to load user profile:", err);
|
||||||
|
updateSignedOutUI();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSignedOutUI() {
|
||||||
|
const userName = document.getElementById("userName");
|
||||||
|
const userEmail = document.getElementById("userEmail");
|
||||||
|
const userAvatar = document.getElementById("userAvatar");
|
||||||
|
const userAvatarLarge = document.getElementById("userAvatarLarge");
|
||||||
|
const authAction = document.getElementById("authAction");
|
||||||
|
const authText = document.getElementById("authText");
|
||||||
|
const authIcon = document.getElementById("authIcon");
|
||||||
|
const settingsBtn = document.getElementById("settingsBtn");
|
||||||
|
const appsButton = document.getElementById("appsButton");
|
||||||
|
const notificationsBtn = document.getElementById("notificationsBtn");
|
||||||
|
|
||||||
|
if (userName) userName.textContent = "User";
|
||||||
|
if (userEmail) userEmail.textContent = "user@example.com";
|
||||||
|
if (userAvatar) {
|
||||||
|
const avatarSpan = userAvatar.querySelector("span");
|
||||||
|
if (avatarSpan) avatarSpan.textContent = "U";
|
||||||
|
}
|
||||||
|
if (userAvatarLarge) userAvatarLarge.textContent = "U";
|
||||||
|
|
||||||
|
if (authAction) {
|
||||||
|
authAction.href = "/auth/login.html";
|
||||||
|
authAction.removeAttribute("onclick");
|
||||||
|
authAction.style.color = "var(--primary)";
|
||||||
|
}
|
||||||
|
if (authText) authText.textContent = "Sign in";
|
||||||
|
if (authIcon) {
|
||||||
|
authIcon.innerHTML =
|
||||||
|
'<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 21 12"></polyline><line x1="15" y1="12" x2="3" y2="12"></line>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settingsBtn) settingsBtn.style.display = "none";
|
||||||
|
if (appsButton) appsButton.style.display = "none";
|
||||||
|
if (notificationsBtn) notificationsBtn.style.display = "none";
|
||||||
|
|
||||||
|
// Hide omnibox (search bar) when signed out
|
||||||
|
const omnibox = document.getElementById("omnibox");
|
||||||
|
if (omnibox) omnibox.style.display = "none";
|
||||||
|
|
||||||
|
// Hide Drive, Tasks, CRM, and Calendar navigation when signed out (all instances)
|
||||||
|
const driveTabs = document.querySelectorAll('[data-section="drive"]');
|
||||||
|
const tasksTabs = document.querySelectorAll('[data-section="tasks"]');
|
||||||
|
const crmTabs = document.querySelectorAll('[data-section="crm"]');
|
||||||
|
const calendarTabs = document.querySelectorAll('[data-section="calendar"]');
|
||||||
|
|
||||||
|
driveTabs.forEach(tab => tab.style.display = "none");
|
||||||
|
tasksTabs.forEach(tab => tab.style.display = "none");
|
||||||
|
crmTabs.forEach(tab => tab.style.display = "none");
|
||||||
|
calendarTabs.forEach(tab => tab.style.display = "none");
|
||||||
|
}
|
||||||
|
|
||||||
// Try to load cached user first
|
// Try to load cached user first
|
||||||
var cachedUser = localStorage.getItem("gb-user-data");
|
var cachedUser = localStorage.getItem("gb-user-data");
|
||||||
if (cachedUser) {
|
if (cachedUser) {
|
||||||
|
|
@ -1377,10 +1419,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
// Always fetch fresh user data
|
// Always fetch fresh user data
|
||||||
if (document.readyState === "loading") {
|
if (document.readyState === "loading") {
|
||||||
document.addEventListener(
|
document.addEventListener("DOMContentLoaded", loadUserProfile);
|
||||||
"DOMContentLoaded",
|
|
||||||
loadUserProfile,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
loadUserProfile();
|
loadUserProfile();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,27 @@ const ThemeManager = (() => {
|
||||||
let currentThemeId = "default";
|
let currentThemeId = "default";
|
||||||
let subscribers = [];
|
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 = [
|
const themes = [
|
||||||
{ id: "default", name: "🎨 Default", file: "light.css" },
|
{ id: "default", name: "🎨 Default", file: "light.css" },
|
||||||
{ id: "light", name: "☀️ Light", file: "light.css" },
|
{ id: "light", name: "☀️ Light", file: "light.css" },
|
||||||
|
|
@ -46,7 +67,10 @@ const ThemeManager = (() => {
|
||||||
|
|
||||||
if (!theme.file) {
|
if (!theme.file) {
|
||||||
currentThemeId = "default";
|
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();
|
updateDropdown();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -54,21 +78,217 @@ const ThemeManager = (() => {
|
||||||
const link = document.createElement("link");
|
const link = document.createElement("link");
|
||||||
link.id = "theme-css";
|
link.id = "theme-css";
|
||||||
link.rel = "stylesheet";
|
link.rel = "stylesheet";
|
||||||
link.href = `public/themes/${theme.file}`;
|
link.href = `/suite/public/themes/${theme.file}`;
|
||||||
link.onload = () => {
|
link.onload = () => {
|
||||||
console.log("✓ Theme loaded:", theme.name);
|
console.log("✓ Theme loaded:", theme.name);
|
||||||
currentThemeId = id;
|
currentThemeId = id;
|
||||||
localStorage.setItem("gb-theme", id);
|
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();
|
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 }));
|
subscribers.forEach((cb) => cb({ themeId: id, themeName: theme.name }));
|
||||||
|
}, 50);
|
||||||
};
|
};
|
||||||
link.onerror = () => console.error("✗ Failed:", theme.name);
|
link.onerror = () => console.error("✗ Failed:", theme.name);
|
||||||
document.head.appendChild(link);
|
document.head.appendChild(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDropdown() {
|
function updateDropdown() {
|
||||||
const dd = document.getElementById("themeDropdown");
|
const select = document.getElementById("themeDropdown");
|
||||||
if (dd) dd.value = currentThemeId;
|
if (select) select.value = currentThemeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDropdown() {
|
function createDropdown() {
|
||||||
|
|
@ -87,33 +307,96 @@ const ThemeManager = (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
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";
|
if (!themes.find((t) => t.id === saved)) saved = "default";
|
||||||
currentThemeId = saved;
|
currentThemeId = saved;
|
||||||
loadTheme(saved);
|
loadTheme(saved);
|
||||||
|
|
||||||
|
// Dropdown injection restored for the window manager
|
||||||
const container = document.getElementById("themeSelectorContainer");
|
const container = document.getElementById("themeSelectorContainer");
|
||||||
if (container) container.appendChild(createDropdown());
|
if (container) {
|
||||||
|
container.innerHTML = "";
|
||||||
|
container.appendChild(createDropdown());
|
||||||
|
}
|
||||||
|
|
||||||
console.log("✓ Theme Manager initialized");
|
console.log("✓ Theme Manager initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
function setThemeFromServer(data) {
|
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) {
|
if (data.logo_url) {
|
||||||
document
|
// For img elements - set src and show, hide SVG
|
||||||
.querySelectorAll(".logo-icon, .assistant-avatar")
|
const logoImg = document.querySelector(".logo-icon-img");
|
||||||
.forEach((el) => {
|
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.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.title) document.title = data.title;
|
||||||
if (data.logo_text) {
|
if (data.logo_text) {
|
||||||
document.querySelectorAll(".logo-text").forEach((el) => {
|
document.querySelectorAll(".logo span, .logo-text").forEach((el) => {
|
||||||
el.textContent = data.logo_text;
|
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() {
|
function applyCustomizations() {
|
||||||
// Called by modules if needed
|
// Called by modules if needed
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +409,7 @@ const ThemeManager = (() => {
|
||||||
init,
|
init,
|
||||||
loadTheme,
|
loadTheme,
|
||||||
setThemeFromServer,
|
setThemeFromServer,
|
||||||
|
loadSavedTheme,
|
||||||
applyCustomizations,
|
applyCustomizations,
|
||||||
subscribe,
|
subscribe,
|
||||||
getAvailableThemes: () => themes,
|
getAvailableThemes: () => themes,
|
||||||
|
|
|
||||||
83
ui/suite/js/vendor/tailwindcss.js
vendored
Normal file
83
ui/suite/js/vendor/tailwindcss.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
ui/suite/js/vendor/vs/vs/base/browser/ui/codicons/codicon/codicon.ttf
vendored
Normal file
BIN
ui/suite/js/vendor/vs/vs/base/browser/ui/codicons/codicon/codicon.ttf
vendored
Normal file
Binary file not shown.
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.de.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.de.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.es.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.es.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.fr.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.fr.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.it.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.it.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.ja.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.ja.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.ko.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.ko.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.ru.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.ru.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.zh-cn.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.zh-cn.js
vendored
Normal 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
|
||||||
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.zh-tw.js
vendored
Normal file
8
ui/suite/js/vendor/vs/vs/base/common/worker/simpleWorker.nls.zh-tw.js
vendored
Normal 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
|
||||||
27
ui/suite/js/vendor/vs/vs/base/worker/workerMain.js
vendored
Normal file
27
ui/suite/js/vendor/vs/vs/base/worker/workerMain.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/abap/abap.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/abap/abap.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/apex/apex.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/apex/apex.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/azcli/azcli.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/azcli/azcli.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/bat/bat.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/bat/bat.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
11
ui/suite/js/vendor/vs/vs/basic-languages/bicep/bicep.js
vendored
Normal file
11
ui/suite/js/vendor/vs/vs/basic-languages/bicep/bicep.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/cameligo/cameligo.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/cameligo/cameligo.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/clojure/clojure.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/clojure/clojure.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/coffee/coffee.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/coffee/coffee.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/cpp/cpp.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/cpp/cpp.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/csharp/csharp.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/csharp/csharp.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/csp/csp.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/csp/csp.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
12
ui/suite/js/vendor/vs/vs/basic-languages/css/css.js
vendored
Normal file
12
ui/suite/js/vendor/vs/vs/basic-languages/css/css.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/cypher/cypher.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/cypher/cypher.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/dart/dart.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/dart/dart.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/dockerfile/dockerfile.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/dockerfile/dockerfile.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/ecl/ecl.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/ecl/ecl.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/elixir/elixir.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/elixir/elixir.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/flow9/flow9.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/flow9/flow9.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
12
ui/suite/js/vendor/vs/vs/basic-languages/freemarker2/freemarker2.js
vendored
Normal file
12
ui/suite/js/vendor/vs/vs/basic-languages/freemarker2/freemarker2.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/fsharp/fsharp.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/fsharp/fsharp.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/go/go.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/go/go.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/graphql/graphql.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/graphql/graphql.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/handlebars/handlebars.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/handlebars/handlebars.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/hcl/hcl.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/hcl/hcl.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/html/html.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/html/html.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/ini/ini.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/ini/ini.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/java/java.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/java/java.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
10
ui/suite/js/vendor/vs/vs/basic-languages/javascript/javascript.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/javascript/javascript.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/julia/julia.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/julia/julia.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
ui/suite/js/vendor/vs/vs/basic-languages/kotlin/kotlin.js
vendored
Normal file
10
ui/suite/js/vendor/vs/vs/basic-languages/kotlin/kotlin.js
vendored
Normal 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;
|
||||||
|
});
|
||||||
11
ui/suite/js/vendor/vs/vs/basic-languages/less/less.js
vendored
Normal file
11
ui/suite/js/vendor/vs/vs/basic-languages/less/less.js
vendored
Normal 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
Loading…
Add table
Reference in a new issue