Skip to content

Commit 6fa3198

Browse files
committed
feat: mobile AI panel optimization — maximize chat area & streamline controls
- Hide quick actions, search providers, AI text, model badge on mobile by default - Add mobile options toggle (grid) for quick actions, independent of search - Merge model selector into chat input bar as compact gradient icon button - Restyle search toggle as icon-only (28px), solid green when enabled - Separate search and grid toggle behaviors — each controls own section - Search toggle directly shows/hides provider bar via ai-mobile-show class - Fix mobile dark mode toggle with icon/label sync on init and change - Sync QAB theme icon/label on theme change - ~60% header height reduction on mobile
1 parent 279b82e commit 6fa3198

File tree

8 files changed

+337
-2
lines changed

8 files changed

+337
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ TextAgent has undergone significant evolution since its inception. What started
543543

544544
| Date | Commits | Feature / Update |
545545
|------|---------|-----------------:|
546+
| **2026-03-30** | | 📱 **Mobile AI Panel Optimization** — maximized chat area on mobile (≤767px) by hiding secondary UI elements by default; removed duplicate model badge and "AI Assistant" text from header; search toggle restyled as compact icon-only button (turns solid green when enabled); model selector merged into chat input bar as compact gradient icon; quick actions and search providers now independently toggleable via separate grid and globe buttons; mobile dark mode toggle fixed with icon/label sync; ~60% header height reduction on mobile |
546547
| **2026-03-30** | | 📂 **File Import Expansion** — added 15 new file extensions to the import pipeline: `.txt`, `.text`, `.log`, `.rst`, `.ini`, `.conf`, `.cfg`, `.env`, `.properties` as plain text; `.yaml`/`.yml` wrapped in yaml code block; `.toml` wrapped in toml code block; `.tsv` parsed as tab-separated Markdown table; updated file input `accept` attribute with all new extensions and MIME types; updated dropzone label and error toast; total supported extensions now 25 |
547548
| **2026-03-29** | | 🔑 **Secure Session Editing** — cryptographic Edit Key (`ek`) system for collaborative editing of shared documents; 24-char random edit key hashed via SHA-256 and stored as `ekHash` in Firestore; write-token encrypted with edit key via AES-GCM stored as `eWt`; editor links (`&ek=<token>`) grant write access without exposing raw write-tokens; verification in both compact (`#s=`) and secure (`#id=&secure=1`) share paths; edit mode bypasses form/quiz access gate; auto-save preserves `ekHash`/`eWt` fields; "Editor Link" section in share result modal with purple badge; "Copy All Links" includes editor link; email/download credentials include editor link; Firestore rules updated for new fields |
548549
| **2026-03-29** | | 🚀 **21× Cloud Context Window** — raised cloud AI worker context limits from 6K to 128K chars for Groq (Llama 3.3 70B) and OpenRouter (GPT-5.4, Claude, Qwen 35B); Gemini raised from 32K to 128K (4×); chat history per-message doubled from 4K to 8K chars; Gemini worker migrated to shared `ai-worker-common.js` (eliminated ~80 lines of duplicate system prompts); local Qwen workers deliberately kept at 32K chars — Qwen 3.5 hybrid GDN architecture degrades beyond 25-50K tokens for small (0.8B-4B) models; existing degenerate output circuit breaker and `presence_penalty: 2.0` safety nets preserved |
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Mobile AI Panel Optimization — Maximize Chat Area & Remove Duplicate UI
2+
3+
- Hid quick action chips (Summarize, Expand, etc.) by default on mobile (≤767px) to maximize chat area
4+
- Hid search provider bar by default on mobile — shown independently via search toggle
5+
- Hid "AI Assistant" text from panel header on mobile — only sparkle icon remains
6+
- Hid duplicate model badge from header on mobile — model info available via inline model button
7+
- Added mobile-only grid toggle button (⊞) in header to expand/collapse quick action chips
8+
- Added compact inline model button (gradient icon) inside the chat input bar on mobile, replacing the full-width model selector row
9+
- Made search toggle icon-only on mobile (28×28px), turns solid green (#10b981) when enabled
10+
- Separated search toggle and grid toggle behaviors — each controls its own section independently
11+
- Search toggle shows/hides provider pills without affecting quick actions
12+
- Grid toggle shows/hides quick actions without affecting provider bar
13+
- Mobile model icon syncs with desktop model selection via `updateModelUI()`
14+
- Compact welcome message and input area styles for mobile
15+
- Hidden welcome tips on mobile for space savings
16+
- Fixed mobile dark mode toggle: added click handler for `mobile-theme-toggle` that delegates to desktop toggle
17+
- Synced mobile theme toggle icon/label on init and on theme change
18+
- Synced QAB theme icon/label on theme change
19+
- Fixed: empty CSS ruleset lint warning at line 1529
20+
21+
---
22+
23+
## Summary
24+
Optimized the AI Assistant panel for mobile devices by hiding non-essential UI elements by default, merging the model selector into the chat input bar, and separating toggle controls so each button independently manages its own section. Also fixed the mobile dark mode toggle.
25+
26+
---
27+
28+
## 1. Mobile Header Cleanup
29+
**Files:** `css/ai-panel.css`, `js/modal-templates.js`
30+
**What:** On mobile (≤767px), the "AI Assistant" text and model badge are hidden from the panel header via `display: none`. The search toggle is restyled as a compact 28×28px icon-only button that turns solid green when enabled, removing the slider and "Search" text.
31+
**Impact:** Header height reduced by ~60%, leaving only essential controls (sparkle icon, search toggle, grid toggle, clear, close) for a cleaner mobile experience.
32+
33+
## 2. Mobile Options Toggle
34+
**Files:** `css/ai-panel.css`, `js/modal-templates.js`, `js/ai-assistant.js`
35+
**What:** Added a new `.ai-mobile-options-toggle` button (grid icon) in the header controls. Clicking it toggles the `.ai-mobile-expanded` class on the panel, which shows/hides `.ai-quick-actions`. This button ONLY controls quick action chips — it does not affect the search provider bar.
36+
**Impact:** Users can access quick actions on demand without them consuming vertical space by default.
37+
38+
## 3. Independent Search Toggle on Mobile
39+
**Files:** `css/ai-panel.css`, `js/ai-chat.js`
40+
**What:** The search toggle's `change` handler now adds/removes the `.ai-mobile-show` class on the provider bar, which overrides the mobile `display: none !important` rule. The CSS rule `.ai-search-provider-bar.ai-mobile-show` no longer requires the `.ai-mobile-expanded` parent.
41+
**Impact:** Clicking the search globe independently shows/hides the provider pills (DDG, Brave, Serper, etc.) without also showing quick action chips.
42+
43+
## 4. Model Selector Merged into Chat Bar
44+
**Files:** `css/ai-panel.css`, `js/modal-templates.js`, `js/ai-assistant.js`
45+
**What:** The full-width `.ai-model-btn` is hidden on mobile via `display: none`. A new `.ai-mobile-model-btn` (30×30px gradient icon) is placed inside `.ai-input-wrapper` and triggers the existing model dropdown. The icon syncs via `updateModelUI()`.
46+
**Impact:** Saves ~45px vertical space by eliminating the separate model selector row on mobile.
47+
48+
## 5. Mobile Dark Mode Toggle Fix
49+
**Files:** `js/app-init.js`, `js/app-core.js`
50+
**What:** Added click event listener for `mobile-theme-toggle` that delegates to `M.themeToggle.click()` and closes the mobile menu. Added icon/label sync for both the mobile toggle and QAB theme button on init and on every theme change.
51+
**Impact:** Dark mode toggle now works from the mobile menu, with icon/label correctly reflecting the current theme state.
52+
53+
---
54+
55+
## Files Changed (6 total)
56+
57+
| File | Lines Changed | Type |
58+
|------|:---:|------|
59+
| `css/ai-panel.css` | +210 −0 | Mobile responsive overrides, compact controls, toggle styles |
60+
| `js/ai-assistant.js` | +23 −0 | Mobile toggle handlers, model icon sync |
61+
| `js/ai-chat.js` | +11 −2 | Search toggle mobile class sync |
62+
| `js/modal-templates.js` | +4 −0 | Mobile toggle button, inline model button in template |
63+
| `js/app-init.js` | +19 −0 | Mobile theme toggle handler, theme sync |
64+
| `js/app-core.js` | +7 −0 | Mobile theme toggle init sync |

css/ai-panel.css

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,16 @@
14131413
}
14141414

14151415
/* --- Responsive --- */
1416+
/* --- Mobile options toggle button (visible only on mobile) --- */
1417+
.ai-mobile-options-toggle {
1418+
display: none; /* hidden on desktop */
1419+
}
1420+
1421+
/* --- Mobile inline model button (visible only on mobile) --- */
1422+
.ai-mobile-model-btn {
1423+
display: none; /* hidden on desktop */
1424+
}
1425+
14161426
@media (max-width: 767px) {
14171427
.ai-panel {
14181428
width: 100%;
@@ -1431,6 +1441,206 @@
14311441
.ai-resize-divider {
14321442
display: none;
14331443
}
1444+
1445+
/* --- Hide options by default on mobile for more chat space --- */
1446+
.ai-quick-actions {
1447+
display: none;
1448+
padding: 8px 12px;
1449+
gap: 4px;
1450+
}
1451+
1452+
.ai-search-provider-bar {
1453+
display: none !important;
1454+
}
1455+
1456+
.ai-status-bar {
1457+
padding: 4px 12px;
1458+
font-size: 11px;
1459+
}
1460+
1461+
/* Compact header on mobile */
1462+
.ai-panel-header {
1463+
padding: 8px 12px;
1464+
}
1465+
1466+
/* Hide "AI Assistant" text and model badge — duplicates on mobile */
1467+
.ai-panel-title span,
1468+
.ai-panel-title .ai-badge {
1469+
display: none;
1470+
}
1471+
1472+
/* Keep the sparkle icon visible */
1473+
.ai-panel-title i.bi-stars {
1474+
display: inline;
1475+
font-size: 16px;
1476+
}
1477+
1478+
/* Compact search toggle on mobile — icon-only, green when active */
1479+
.ai-search-toggle {
1480+
padding: 4px;
1481+
border-radius: 8px;
1482+
border: 1px solid var(--border-color);
1483+
gap: 0;
1484+
width: 28px;
1485+
height: 28px;
1486+
justify-content: center;
1487+
}
1488+
1489+
.ai-search-toggle .ai-search-slider,
1490+
.ai-search-toggle .ai-search-label {
1491+
display: none;
1492+
}
1493+
1494+
.ai-search-toggle i {
1495+
font-size: 14px;
1496+
}
1497+
1498+
.ai-search-toggle:has(input:checked) {
1499+
background: #10b981;
1500+
border-color: #10b981;
1501+
}
1502+
1503+
.ai-search-toggle:has(input:checked) i {
1504+
color: #fff;
1505+
}
1506+
1507+
/* Compact welcome message on mobile */
1508+
.ai-welcome-message {
1509+
padding: 18px 14px;
1510+
}
1511+
1512+
.ai-welcome-icon {
1513+
font-size: 32px;
1514+
margin-bottom: 6px;
1515+
}
1516+
1517+
.ai-welcome-message h5 {
1518+
font-size: 15px;
1519+
margin-bottom: 4px;
1520+
}
1521+
1522+
.ai-welcome-message p {
1523+
font-size: 12px;
1524+
margin-bottom: 10px;
1525+
}
1526+
1527+
.ai-welcome-tips {
1528+
display: none;
1529+
}
1530+
1531+
/* Compact input area on mobile */
1532+
.ai-input-area {
1533+
padding: 8px 10px;
1534+
}
1535+
1536+
/* --- Merge model selector into chat bar on mobile --- */
1537+
.ai-model-selector {
1538+
position: absolute;
1539+
left: 0;
1540+
bottom: 100%;
1541+
right: 0;
1542+
margin-bottom: 0;
1543+
z-index: 10;
1544+
}
1545+
1546+
/* Hide the full-width model button on mobile — replaced by inline icon */
1547+
.ai-model-btn {
1548+
display: none;
1549+
}
1550+
1551+
/* Show the dropdown when opened (positioned above the input) */
1552+
.ai-model-selector.open .ai-model-dropdown {
1553+
position: fixed;
1554+
bottom: 56px;
1555+
left: 8px;
1556+
right: 8px;
1557+
margin-bottom: 0;
1558+
border-radius: 12px;
1559+
max-height: 45vh;
1560+
}
1561+
1562+
/* Make input wrapper relative for positioning */
1563+
.ai-input-area {
1564+
position: relative;
1565+
}
1566+
1567+
/* Show compact inline model button on mobile */
1568+
.ai-mobile-model-btn {
1569+
display: flex;
1570+
align-items: center;
1571+
justify-content: center;
1572+
width: 30px;
1573+
height: 30px;
1574+
border-radius: 8px;
1575+
border: none;
1576+
background: linear-gradient(135deg, #667eea, #764ba2);
1577+
color: #fff;
1578+
font-size: 13px;
1579+
cursor: pointer;
1580+
transition: all 0.2s;
1581+
flex-shrink: 0;
1582+
}
1583+
1584+
.ai-mobile-model-btn:hover,
1585+
.ai-mobile-model-btn:active {
1586+
transform: scale(1.05);
1587+
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.35);
1588+
}
1589+
1590+
/* Show the mobile toggle button */
1591+
.ai-mobile-options-toggle {
1592+
display: inline-flex;
1593+
align-items: center;
1594+
justify-content: center;
1595+
width: 28px;
1596+
height: 28px;
1597+
border-radius: 8px;
1598+
border: 1px solid var(--border-color);
1599+
background: var(--button-bg);
1600+
color: var(--text-color);
1601+
font-size: 13px;
1602+
cursor: pointer;
1603+
transition: all 0.2s;
1604+
opacity: 0.7;
1605+
flex-shrink: 0;
1606+
}
1607+
1608+
.ai-mobile-options-toggle:hover,
1609+
.ai-mobile-options-toggle.active {
1610+
opacity: 1;
1611+
border-color: #667eea;
1612+
color: #667eea;
1613+
background: rgba(102, 126, 234, 0.08);
1614+
}
1615+
1616+
.ai-mobile-options-toggle .bi-chevron-up {
1617+
transition: transform 0.2s;
1618+
}
1619+
1620+
.ai-mobile-options-toggle.active .bi-chevron-up {
1621+
transform: rotate(180deg);
1622+
}
1623+
1624+
/* When options are expanded on mobile */
1625+
.ai-panel.ai-mobile-expanded .ai-quick-actions {
1626+
display: flex;
1627+
}
1628+
1629+
/* Search provider bar shows independently when search toggle is ON */
1630+
.ai-search-provider-bar.ai-mobile-show {
1631+
display: block !important;
1632+
}
1633+
1634+
/* Smaller quick action chips on mobile */
1635+
.ai-action-chip {
1636+
padding: 4px 9px;
1637+
font-size: 11px;
1638+
border-radius: 12px;
1639+
}
1640+
1641+
.ai-action-chip i {
1642+
font-size: 11px;
1643+
}
14341644
}
14351645

14361646
/* --- AI Status Indicator (in-panel) --- */

js/ai-assistant.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@
173173
if (aiModelLabel) aiModelLabel.textContent = cfg.label;
174174
if (aiModelBtnIcon) { aiModelBtnIcon.className = cfg.icon; }
175175
if (aiModelBadge) aiModelBadge.textContent = cfg.badge;
176+
// Sync mobile inline model icon
177+
const mobileIcon = document.getElementById('ai-mobile-model-icon');
178+
if (mobileIcon) mobileIcon.className = cfg.icon;
176179
}
177180
}
178181

@@ -379,6 +382,26 @@
379382
if (aiPanelCloseBtn) aiPanelCloseBtn.addEventListener('click', closeAiPanel);
380383
// Overlay is pass-through — panel closes via the X button only
381384

385+
// --- Mobile Options Toggle (show/hide quick actions ONLY) ---
386+
const aiMobileOptionsToggle = document.getElementById('ai-mobile-options-toggle');
387+
if (aiMobileOptionsToggle) {
388+
aiMobileOptionsToggle.addEventListener('click', () => {
389+
const isExpanded = aiPanel.classList.toggle('ai-mobile-expanded');
390+
aiMobileOptionsToggle.classList.toggle('active', isExpanded);
391+
aiMobileOptionsToggle.title = isExpanded ? 'Hide quick actions' : 'Show quick actions';
392+
});
393+
}
394+
395+
// --- Mobile Inline Model Button (opens model dropdown on mobile) ---
396+
const aiMobileModelBtn = document.getElementById('ai-mobile-model-btn');
397+
const aiMobileModelIcon = document.getElementById('ai-mobile-model-icon');
398+
if (aiMobileModelBtn && aiModelSelector) {
399+
aiMobileModelBtn.addEventListener('click', (e) => {
400+
e.stopPropagation();
401+
aiModelSelector.classList.toggle('open');
402+
});
403+
}
404+
382405
// --- AI Panel Resize (drag left edge) ---
383406
const aiResizeDivider = document.getElementById('ai-resize-divider');
384407

js/ai-chat.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,10 @@
887887
if (!searchToggle || !M.webSearch) return;
888888

889889
searchToggle.checked = M.webSearch.isSearchEnabled();
890-
if (searchToggle.checked && providerBar) providerBar.style.display = '';
890+
if (searchToggle.checked && providerBar) {
891+
providerBar.style.display = '';
892+
providerBar.classList.add('ai-mobile-show');
893+
}
891894

892895
// Sync checkbox state from saved providers
893896
function syncPillState() {
@@ -903,7 +906,11 @@
903906

904907
searchToggle.addEventListener('change', function () {
905908
M.webSearch.setSearchEnabled(searchToggle.checked);
906-
if (providerBar) providerBar.style.display = searchToggle.checked ? '' : 'none';
909+
if (providerBar) {
910+
providerBar.style.display = searchToggle.checked ? '' : 'none';
911+
// On mobile, CSS uses !important to hide — use class to override
912+
providerBar.classList.toggle('ai-mobile-show', searchToggle.checked);
913+
}
907914
});
908915

909916
// Checkbox toggle handler

js/app-core.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@
7878
? '<i class="bi bi-sun"></i>'
7979
: '<i class="bi bi-moon"></i>';
8080

81+
// Sync mobile theme toggle icon + label on init
82+
if (M.mobileThemeToggle) {
83+
var mi = M.mobileThemeToggle.querySelector('i');
84+
if (mi) mi.className = initialTheme === 'dark' ? 'bi bi-sun-fill me-2' : 'bi bi-moon me-2';
85+
M.mobileThemeToggle.lastChild.textContent = initialTheme === 'dark' ? ' Light Mode' : ' Dark Mode';
86+
}
87+
8188
// --- Mermaid Initialization ---
8289
M.initMermaid = async function () {
8390
const mermaidLib = await window.getMermaid();

0 commit comments

Comments
 (0)