Skip to content

fix: update docs graphics + style, improve dev_setup page#183

Merged
Aiosa merged 1 commit into
masterfrom
release/v3
Jun 14, 2026
Merged

fix: update docs graphics + style, improve dev_setup page#183
Aiosa merged 1 commit into
masterfrom
release/v3

Conversation

@Aiosa

@Aiosa Aiosa commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced glassmorphism design theme with light and dark mode support
    • Added session import/export capabilities for better workflow management
    • Redesigned developer setup interface with improved split-view layout and session sidebar
    • Enabled inline session renaming
  • Style

    • Enhanced UI with frosted glass effects and backdrop filters across navigation, sidebar, modals, and cards
    • Added smooth animations and improved visual hierarchy

@Aiosa Aiosa merged commit aab0c0e into master Jun 14, 2026
1 of 3 checks passed
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 689da1d5-322c-4771-9e7b-34a15f34c1ee

📥 Commits

Reviewing files that changed from the base of the PR and between c0684e6 and 49a6c8a.

⛔ Files ignored due to path filters (2)
  • docs/site/static/img/logo.png is excluded by !**/*.png
  • docs/site/static/img/xopat-banner.png is excluded by !**/*.png
📒 Files selected for processing (2)
  • docs/site/src/css/custom.css
  • server/templates/dev-setup.html

📝 Walkthrough

Walkthrough

The PR adds a glassmorphism CSS theme to the docs site (animated blob backdrop, frosted glass for navbar/sidebar/cards, light/dark variables, motion and backdrop-filter fallbacks) and rewrites dev-setup.html with a split sidebar/editor layout, normalized tab state model with normalizeTab()/nextId(), inline session renaming, and full import/export functionality including multi-session bundle support.

Changes

Docs Site Glassmorphism Theme

Layer / File(s) Summary
Light and dark CSS variable definitions
docs/site/src/css/custom.css
Defines all --glass-* custom properties for light mode and overrides them under [data-theme='dark'].
Glassmorphism styling, animation, and fallbacks
docs/site/src/css/custom.css
Applies frosted glass via backdrop-filter to navbar, sidebar, TOC, dropdowns, cards, and search modal; adds animated radial-gradient blob backdrop on body::before; disables animation under prefers-reduced-motion; raises opacity via @supports fallback when backdrop-filter is absent.

Dev Setup Session Manager Rewrite

Layer / File(s) Summary
HTML layout restructure and DOM/event wiring
server/templates/dev-setup.html
Reorganizes page into a left Sessions sidebar (#tab-list, Import/Export controls) and a dedicated editor panel. Adds bundleType/_nextId to app state, captures #active-tab-name and #import-file-input DOM references, wires rename and file-import events, and introduces nextId()/getActiveTab() helpers.
Tab state normalization and loadState
server/templates/dev-setup.html
Introduces normalizeTab() to coerce raw stored objects into {id, name, content} with generated IDs. Updates loadState() to normalize stored tabs, restore activeTabId by best-effort index when IDs don't match, and fall back to createDefaultState() when no valid tabs exist.
Session lifecycle and content sync
server/templates/dev-setup.html
Updates resetDefaults() confirmation text, makes addTab() use nextId() with default JSON content, revises closeTab() last-tab alert and delete gating. Modifies updateActiveTabContent() to use getActiveTab() and loadActiveContent() to sync #active-tab-name with the active tab name.
Import/export helpers and renderTabs rewrite
server/templates/dev-setup.html
Adds safeFileName() and download() utilities. Implements exportTab/exportActive/exportAll (export-all emits a {type, version, tabs} bundle). Adds handleImportFiles() supporting bundled multi-session and single-session imports with raw-text fallback. Rewrites renderTabs() to render #tab-list sidebar entries with export icon buttons and conditional close controls.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hop hop, the glass is clear,
Blobs drift and blur with frosted cheer.
Sessions stack with tidy IDs,
Export a bundle? With the greatest of ease!
Import, rename, the sidebar gleams —
A rabbit built this more than it seems.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/v3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a glassmorphism theme to the documentation site and refactors the developer visualization setup page to feature a sidebar-based session manager with import/export capabilities and inline renaming. Feedback on these changes highlights a potential TypeError crash during state loading when invalid tabs are filtered out, a performance bottleneck caused by animating background-position on the backdrop blobs, and a redundant saveState() call in the file import finalization logic.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +481 to +490
const tabs = Array.isArray(data && data.tabs) ? data.tabs : [];
this.tabs = tabs
.map((t, i) => this.normalizeTab(t, `Config ${i + 1}`))
.filter(Boolean);
if (this.tabs.length) {
// Stored activeTabId no longer matches regenerated ids; restore by index.
const idx = tabs.findIndex(t => t && t.id === (data && data.activeTabId));
this.activeTabId = this.tabs[idx >= 0 ? idx : 0].id;
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There is a potential out-of-bounds/TypeError crash here when loading the stored state if any of the stored tabs are invalid and get filtered out.

The Issue:

  1. this.tabs is populated by mapping and filtering the raw tabs array:
    this.tabs = tabs
        .map((t, i) => this.normalizeTab(t, `Config \${i + 1}`))
        .filter(Boolean);
    If any tab is invalid (e.g., missing content), it is filtered out, making this.tabs.length smaller than tabs.length.
  2. idx is found using the raw tabs array:
    const idx = tabs.findIndex(t => t && t.id === (data && data.activeTabId));
  3. Then, this.activeTabId is set by accessing this.tabs[idx]:
    this.activeTabId = this.tabs[idx >= 0 ? idx : 0].id;
    If idx is greater than or equal to the length of the filtered this.tabs array, this.tabs[idx] will be undefined, throwing a TypeError: Cannot read properties of undefined (reading 'id') and crashing the page initialization.

Solution:

We should resolve the active tab using object references during the iteration/normalization process rather than relying on raw array indices. This ensures we always get the correct normalized tab and completely avoids out-of-bounds errors.

                    const tabs = Array.isArray(data && data.tabs) ? data.tabs : [];
                    let activeIdx = tabs.findIndex(t => t && t.id === (data && data.activeTabId));
                    if (activeIdx < 0) activeIdx = 0;
                    const rawActiveTab = tabs[activeIdx];

                    this.tabs = [];
                    let activeTab = null;
                    tabs.forEach((t, i) => {
                        const normalized = this.normalizeTab(t, "Config " + (i + 1));
                        if (normalized) {
                            this.tabs.push(normalized);
                            if (t === rawActiveTab) {
                                activeTab = normalized;
                            }
                        }
                    });

                    if (this.tabs.length) {
                        this.activeTabId = (activeTab || this.tabs[0]).id;
                        return;
                    }

Comment on lines +85 to +92
/* Slow, barely-there drift; disabled for reduced-motion users (below). */
animation: glass-blob-drift 38s ease-in-out infinite alternate;
}

@keyframes glass-blob-drift {
from { background-position: 0% 0%, 0% 0%, 0% 0%, 0% 0%; }
to { background-position: 6% 4%, -5% 3%, 4% -4%, 0% 0%; }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Animating background-position (especially with multiple large radial-gradient layers and background-attachment: fixed) is highly inefficient because it cannot be GPU-accelerated. This forces the browser to perform expensive CPU-bound repaint operations on every frame.

When combined with the heavy backdrop-filter: blur(...) used on elements like .navbar, .theme-doc-sidebar-container, and .table-of-contents, this will cause significant rendering lag, high CPU/GPU utilization, and increased battery consumption (particularly on high-DPI screens or mobile devices).

Recommendation:
To achieve a smooth, GPU-accelerated drifting effect, consider using separate pseudo-elements (or absolute-positioned container divs) for the blobs and animating them using transform: translate() or transform: rotate().

Comment on lines +674 to +679
const finalize = () => {
if (--pending > 0) return;
this.saveState();
if (firstNewId !== null) this.switchTab(firstNewId);
else this.renderTabs();
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In finalize, calling this.saveState() right before this.switchTab(firstNewId) is redundant.

this.switchTab internally calls this.updateActiveTabContent(this.editor.value) and this.saveState(). Calling it twice in immediate succession causes redundant localStorage writes and duplicate DOM updates (updating the #save-status text).

We can optimize this by only calling saveState and renderTabs when we are not switching tabs.

Suggested change
const finalize = () => {
if (--pending > 0) return;
this.saveState();
if (firstNewId !== null) this.switchTab(firstNewId);
else this.renderTabs();
};
const finalize = () => {
if (--pending > 0) return;
if (firstNewId !== null) {
this.switchTab(firstNewId);
} else {
this.saveState();
this.renderTabs();
}
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant