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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.10.0] - 2025-09-13

### Added
- Tiled View (MVP): view two sessions side‑by‑side with independent terminals and sockets.
- Resizable splitter between panes with persistent split position.
- Per‑pane session picker and close controls; layout and assignments persist in localStorage.

### Changed
- Settings font size now applies to all visible panes in tiled view.

### Notes
- Client‑side only; no server/CLI changes required. Default remains single‑pane; toggle via new tile button in the top bar.

## [2.9.0] - 2025-09-13

### Added
- Theme toggle in Settings with persistence (Dark/Light).
- Early theme application to avoid flash of incorrect theme on load.

### Changed
- Default theme set to Dark; Light can be selected in Settings.

### Notes
- UI-only change; no server/CLI APIs modified.

## [2.8.0] - 2025-09-13

### Added
Expand Down Expand Up @@ -133,14 +158,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Startup logs show configured aliases.
- README updated with alias usage examples.
## [2.9.0] - 2025-09-13

### Added
- Theme toggle in Settings with persistence (Dark/Light).
- Early theme application to avoid flash of incorrect theme on load.

### Changed
- Default theme set to Dark; Light can be selected in Settings.

### Notes
- UI-only change; no server/CLI APIs modified.
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "claude-code-web",
"version": "2.9.0",
"version": "2.10.0",
"description": "Web-based interface for Claude Code CLI accessible via browser",
"main": "src/server.js",
"bin": {
Expand Down
23 changes: 22 additions & 1 deletion src/public/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ClaudeCodeWebInterface {
this.sessionTimer = null;
this.sessionTimerInterval = null;

this.paneManager = null;
this.init();
}

Expand Down Expand Up @@ -72,6 +73,8 @@ class ClaudeCodeWebInterface {
this.setupTerminal();
this.setupUI();
this.setupPlanDetector();
// Pane manager after UI exists
this.paneManager = new PaneManager(this);
this.loadSettings();
this.applyAliasesToUI();
this.disablePullToRefresh();
Expand Down Expand Up @@ -109,6 +112,7 @@ class ClaudeCodeWebInterface {

window.addEventListener('resize', () => {
this.fitTerminal();
if (this.paneManager?.enabled) this.paneManager.panes.forEach(p => p.fit());
});

window.addEventListener('beforeunload', () => {
Expand Down Expand Up @@ -151,7 +155,7 @@ class ClaudeCodeWebInterface {

// Plan modal title
const planTitle = document.querySelector('#planModal .modal-header h2');
if (planTitle) planTitle.innerHTML = `<span class="icon" aria-hidden="true">${window.icons?.clipboard?.(18) || ''}</span> ${this.getAlias('claude')}'s Plan`;
if (planTitle) planTitle.innerHTML = `<span class=\"icon\" aria-hidden=\"true\">${window.icons?.clipboard?.(18) || ''}</span> ${this.getAlias('claude')}'s Plan`;
}

detectMobile() {
Expand Down Expand Up @@ -432,6 +436,19 @@ class ClaudeCodeWebInterface {
if (settingsBtn) settingsBtn.addEventListener('click', () => this.showSettings());
if (retryBtn) retryBtn.addEventListener('click', () => this.reconnect());

// Tile view toggle
const tileToggle = document.getElementById('tileViewToggle');
if (tileToggle) {
tileToggle.addEventListener('click', () => {
if (!this.paneManager) return;
if (this.paneManager.enabled) {
this.paneManager.disable();
} else {
this.paneManager.enable();
}
});
}

// Mobile menu event listeners
if (closeMenuBtn) closeMenuBtn.addEventListener('click', () => this.closeMobileMenu());
if (settingsBtnMobile) {
Expand Down Expand Up @@ -947,6 +964,8 @@ class ClaudeCodeWebInterface {
message.plan,
message.limits
);
// Also refresh pane session selectors when sessions list changes
if (this.paneManager) this.paneManager.refreshSessionSelects();
break;

default:
Expand Down Expand Up @@ -1155,6 +1174,7 @@ class ClaudeCodeWebInterface {
}

this.terminal.options.fontSize = settings.fontSize;
if (this.paneManager?.panes) this.paneManager.panes.forEach(p => { if (p.terminal) p.terminal.options.fontSize = settings.fontSize; p.fit();});

this.fitTerminal();
}
Expand Down Expand Up @@ -2248,5 +2268,6 @@ document.head.appendChild(style);

document.addEventListener('DOMContentLoaded', () => {
const app = new ClaudeCodeWebInterface();
window.app = app;
app.startHeartbeat();
});
42 changes: 39 additions & 3 deletions src/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,21 @@
<!-- Overflow tabs will be listed here -->
</div>
</div>
<button class="tab-settings" id="settingsBtn" title="Settings">
<div class="tab-actions">
<button class="tab-tile" id="tileViewToggle" title="Toggle Tile View">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="8" height="8"/>
<rect x="13" y="3" width="8" height="8"/>
<rect x="3" y="13" width="18" height="8"/>
</svg>
</button>
<button class="tab-settings" id="settingsBtn" title="Settings">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"/>
<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"/>
</svg>
</button>
</button>
</div>
</div>


Expand All @@ -130,7 +139,7 @@ <h2><span class="icon" aria-hidden="true"><svg width="18" height="18" viewBox="0
</div>

<main class="main">
<div class="terminal-container" id="terminalContainer">
<div class="terminal-container" id="terminalContainer" data-view="single">
<div class="terminal-wrapper">
<div id="terminal"></div>
</div>
Expand Down Expand Up @@ -158,6 +167,32 @@ <h3>Connection Error</h3>
</div>
</div>
</div>
<!-- Tiled Panes Container (hidden by default) -->
<div class="tiles-container" id="tilesContainer" style="display:none;">
<div class="tile-grid" id="tileGrid">
<div class="tile-pane" data-index="0">
<div class="tile-toolbar">
<select class="tile-session-select" data-index="0"></select>
<div class="spacer"></div>
<button class="tile-close" data-index="0" title="Close Pane">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div class="tile-terminal" id="tileTerminal0"></div>
</div>
<div class="resizer" id="tileResizer" title="Drag to resize"></div>
<div class="tile-pane" data-index="1">
<div class="tile-toolbar">
<select class="tile-session-select" data-index="1"></select>
<div class="spacer"></div>
<button class="tile-close" data-index="1" title="Close Pane">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div class="tile-terminal" id="tileTerminal1"></div>
</div>
</div>
</div>
</main>

<div class="settings-modal" id="settingsModal">
Expand Down Expand Up @@ -329,6 +364,7 @@ <h2>Sessions</h2>
<script src="auth.js"></script>
<script src="plan-detector.js"></script>
<script src="session-manager.js"></script>
<script src="panes.js"></script>
<script src="icons.js"></script>
<script src="app.js"></script>

Expand Down
Loading