Files
NebulaBrowser/ui/pages/bigpicture.html
T
Andrew Zambazos d6f15c5dce Add Big Picture mode and multi-target build
Introduce a Big Picture mode and support building two app targets. CMakeLists was refactored to add a helper (add_nebula_app_target) and now registers NebulaBrowser and NebulaBigPicture executables, moving UI/assets post-build copying into the helper. A new app/main_bigpicture.cpp entry was added and RunNebula now accepts LaunchOptions (AppMode) with a new LaunchOptions struct. NebulaController was extended heavily to manage a BigPicture browser role: creation, enter/exit mode, layout logic, cursor injection/removal, remote input handlers (mouse move/click/wheel/text), and state syncing. Cef/browser_client updated for the new BigPicture role and message filtering. Platform API gained MoveCursorToBrowserPoint with platform stubs/Win implementation. Big-picture UI files (CSS/JS/HTML) were also updated to support the new mode.
2026-05-18 22:07:41 +12:00

529 lines
24 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nebula - Big Picture Mode</title>
<link rel="icon" href="../assets/images/branding/Nebula-Icon.svg" type="image/svg+xml">
<link rel="stylesheet" href="../css/bigpicture.css">
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/remixicon@3/fonts/remixicon.css" rel="stylesheet">
</head>
<body>
<!-- Audio feedback for navigation -->
<audio id="navSound" preload="auto">
<source src="data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQ==" type="audio/wav">
</audio>
<audio id="selectSound" preload="auto">
<source src="data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQ==" type="audio/wav">
</audio>
<!-- Main container with ambient background -->
<div class="bp-container">
<!-- Animated background -->
<div class="bp-background">
<div class="bg-gradient"></div>
<div class="bg-particles"></div>
<div class="bg-glow"></div>
</div>
<div id="browser-stage-frame" class="browser-stage-frame hidden" aria-hidden="true"></div>
<div id="virtual-cursor" class="virtual-cursor hidden" aria-hidden="true">
<div class="virtual-cursor-dot"></div>
</div>
<!-- Top header bar -->
<header class="bp-header">
<div class="header-left">
<img src="../assets/images/branding/Nebula-Icon.svg" alt="Nebula" class="bp-logo">
<span class="bp-title">Nebula</span>
</div>
<div class="header-center">
<div class="clock-widget">
<span id="bp-time" class="time">--:--</span>
<span id="bp-date" class="date">---</span>
</div>
</div>
<div class="header-right">
<div class="status-icons">
<span id="bp-controller-status" class="status-icon controller-status disconnected" title="Controller disconnected">
<span class="material-symbols-outlined">sports_esports</span>
</span>
<span id="bp-wifi" class="status-icon" title="Connected">
<span class="material-symbols-outlined">wifi</span>
</span>
<span id="bp-battery" class="status-icon" title="Battery">
<span class="material-symbols-outlined">battery_full</span>
</span>
</div>
<button id="exitBigPicture" class="bp-exit-btn" data-focusable tabindex="0">
<span class="material-symbols-outlined">close</span>
<span class="btn-label">Exit</span>
</button>
</div>
</header>
<!-- Main navigation area -->
<main class="bp-main">
<!-- Left sidebar navigation -->
<nav class="bp-sidebar">
<div class="nav-items">
<button class="nav-item active" data-section="home" data-focusable tabindex="0">
<span class="material-symbols-outlined">home</span>
<span class="nav-label">Home</span>
</button>
<button class="nav-item" data-section="browse" data-focusable tabindex="0">
<span class="material-symbols-outlined">language</span>
<span class="nav-label">Browse</span>
</button>
<button class="nav-item" data-section="bookmarks" data-focusable tabindex="0">
<span class="material-symbols-outlined">bookmarks</span>
<span class="nav-label">Bookmarks</span>
</button>
<button class="nav-item" data-section="history" data-focusable tabindex="0">
<span class="material-symbols-outlined">history</span>
<span class="nav-label">History</span>
</button>
<button class="nav-item" data-section="downloads" data-focusable tabindex="0">
<span class="material-symbols-outlined">download</span>
<span class="nav-label">Downloads</span>
</button>
</div>
<div class="nav-footer">
<button class="nav-item" data-section="settings" data-focusable tabindex="0">
<span class="material-symbols-outlined">settings</span>
<span class="nav-label">Settings</span>
</button>
</div>
</nav>
<!-- Content area -->
<div class="bp-content">
<!-- Webview container for browsing -->
<div id="webview-container" class="webview-container hidden"></div>
<!-- Home section -->
<section id="section-home" class="bp-section active">
<div class="section-header">
<h1 class="section-title">
<span id="greeting-text">Welcome back</span>
</h1>
<p class="section-subtitle">What would you like to browse today?</p>
</div>
<!-- Search card -->
<div class="search-card" data-focusable tabindex="0">
<div class="search-icon">
<span class="material-symbols-outlined">search</span>
</div>
<input type="text" id="bp-search" class="search-input" placeholder="Search the web or enter URL..." autocomplete="off">
<div class="search-hint">
<span class="key-hint">A</span> Search
</div>
</div>
<!-- Quick access grid -->
<div class="quick-access">
<h2 class="subsection-title">Quick Access</h2>
<div class="tile-grid" id="quickAccessGrid">
<!-- Tiles will be populated dynamically -->
</div>
</div>
</section>
<!-- Browse section (for webview) -->
<section id="section-browse" class="bp-section">
<!-- Webview container is outside sections -->
</section>
<!-- Bookmarks section -->
<section id="section-bookmarks" class="bp-section">
<div class="section-header">
<h1 class="section-title">Bookmarks</h1>
<p class="section-subtitle">Your saved websites</p>
</div>
<div class="section-actions">
<button class="action-btn" id="addBookmarkBtn" data-focusable tabindex="0">
<span class="material-symbols-outlined">bookmark_add</span>
<span>Add Bookmark</span>
</button>
<button class="action-btn" id="addCurrentBookmarkBtn" data-focusable tabindex="0">
<span class="material-symbols-outlined">bookmark</span>
<span>Add Current Page</span>
</button>
</div>
<div class="tile-grid large" id="bookmarksGrid">
<!-- Bookmarks will be populated dynamically -->
</div>
</section>
<!-- History section -->
<section id="section-history" class="bp-section">
<div class="section-header">
<h1 class="section-title">History</h1>
<p class="section-subtitle">Recently visited sites from this profile</p>
</div>
<div class="section-actions">
<button class="action-btn danger" id="bp-clear-history" data-focusable tabindex="0">
<span class="material-symbols-outlined">delete</span>
<span>Clear History</span>
</button>
</div>
<div class="list-container" id="historyList">
<div class="empty-state">
<span class="material-symbols-outlined">history</span>
<p>No browsing history</p>
</div>
</div>
</section>
<!-- Downloads section -->
<section id="section-downloads" class="bp-section">
<div class="section-header">
<h1 class="section-title">Downloads</h1>
<p class="section-subtitle">Your downloaded files</p>
</div>
<div class="list-container" id="downloadsList">
<div class="empty-state">
<span class="material-symbols-outlined">folder_open</span>
<p>No recent downloads</p>
</div>
</div>
</section>
<!-- NeBot AI section -->
<section id="section-nebot" class="bp-section">
<div class="section-header">
<h1 class="section-title">NeBot AI Assistant</h1>
<p class="section-subtitle">Your AI-powered browsing companion</p>
</div>
<div class="nebot-launch">
<div class="nebot-card" data-focusable tabindex="0" id="launchNebot">
<div class="nebot-icon">
<span class="material-symbols-outlined">smart_toy</span>
</div>
<div class="nebot-info">
<h3>Start Conversation</h3>
<p>Ask questions, get summaries, and more</p>
</div>
<div class="nebot-action">
<span class="key-hint">A</span>
</div>
</div>
</div>
</section>
<!-- Settings section -->
<section id="section-settings" class="bp-section">
<div class="section-header">
<h1 class="section-title">Settings</h1>
<p class="section-subtitle">Configure your browser</p>
</div>
<!-- Settings categories navigation -->
<div class="settings-tabs">
<button class="settings-tab active" data-settings-tab="themes" data-focusable tabindex="0">
<span class="material-symbols-outlined">palette</span>
<span>Themes</span>
</button>
<button class="settings-tab" data-settings-tab="display" data-focusable tabindex="0">
<span class="material-symbols-outlined">display_settings</span>
<span>Display</span>
</button>
<button class="settings-tab" data-settings-tab="privacy" data-focusable tabindex="0">
<span class="material-symbols-outlined">shield</span>
<span>Privacy</span>
</button>
<button class="settings-tab" data-settings-tab="about" data-focusable tabindex="0">
<span class="material-symbols-outlined">info</span>
<span>About</span>
</button>
</div>
<!-- Settings panels -->
<div class="settings-panels">
<!-- Themes Panel -->
<div class="settings-panel active" id="settings-panel-themes">
<h2 class="settings-panel-title">Theme Presets</h2>
<div class="theme-grid" id="bp-theme-grid">
<button class="theme-card" data-theme="default" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #121418, #1B1035);"></div>
<span class="theme-name">Default</span>
</button>
<button class="theme-card" data-theme="ocean" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #1a365d, #2c5282);"></div>
<span class="theme-name">Ocean</span>
</button>
<button class="theme-card" data-theme="forest" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #1a202c, #2d3748);"></div>
<span class="theme-name">Forest</span>
</button>
<button class="theme-card" data-theme="sunset" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #744210, #c05621);"></div>
<span class="theme-name">Sunset</span>
</button>
<button class="theme-card" data-theme="cyberpunk" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #0a0a0a, #2a0a3a);"></div>
<span class="theme-name">Cyberpunk</span>
</button>
<button class="theme-card" data-theme="midnight-rose" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #1c1820, #3d3046);"></div>
<span class="theme-name">Midnight Rose</span>
</button>
<button class="theme-card" data-theme="arctic-ice" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #f0f8ff, #d1e7ff);"></div>
<span class="theme-name">Arctic Ice</span>
</button>
<button class="theme-card" data-theme="cherry-blossom" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #fff5f8, #ffd4db);"></div>
<span class="theme-name">Cherry Blossom</span>
</button>
<button class="theme-card" data-theme="cosmic-purple" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #0f0524, #2d1b69);"></div>
<span class="theme-name">Cosmic Purple</span>
</button>
<button class="theme-card" data-theme="emerald-dream" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #0d2818, #2d5a44);"></div>
<span class="theme-name">Emerald Dream</span>
</button>
<button class="theme-card" data-theme="mocha-coffee" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #3c2414, #5d3a26);"></div>
<span class="theme-name">Mocha Coffee</span>
</button>
<button class="theme-card" data-theme="lavender-fields" data-focusable tabindex="0">
<div class="theme-preview" style="background: linear-gradient(145deg, #f8f4ff, #e6d8ff);"></div>
<span class="theme-name">Lavender Fields</span>
</button>
</div>
</div>
<!-- Display Panel -->
<div class="settings-panel" id="settings-panel-display">
<h2 class="settings-panel-title">Display Settings</h2>
<div class="settings-option">
<div class="option-info">
<span class="material-symbols-outlined">zoom_in</span>
<div class="option-text">
<span class="option-label">Display Scale</span>
<span class="option-description">Adjust the default zoom level</span>
</div>
</div>
<div class="option-control">
<button class="scale-btn" id="bp-scale-down" data-focusable tabindex="0">
<span class="material-symbols-outlined">remove</span>
</button>
<span class="scale-value" id="bp-scale-value">100%</span>
<button class="scale-btn" id="bp-scale-up" data-focusable tabindex="0">
<span class="material-symbols-outlined">add</span>
</button>
</div>
</div>
<div class="settings-option">
<div class="option-info">
<span class="material-symbols-outlined">desktop_windows</span>
<div class="option-text">
<span class="option-label">Exit Big Picture Mode</span>
<span class="option-description">Return to standard desktop interface</span>
</div>
</div>
<div class="option-control">
<button class="action-button" id="bp-exit-desktop" data-focusable tabindex="0">
<span class="material-symbols-outlined">logout</span>
<span>Exit</span>
</button>
</div>
</div>
</div>
<!-- Privacy Panel -->
<div class="settings-panel" id="settings-panel-privacy">
<h2 class="settings-panel-title">Privacy & Data</h2>
<div class="settings-option">
<div class="option-info">
<span class="material-symbols-outlined">delete_sweep</span>
<div class="option-text">
<span class="option-label">Clear Browsing Data</span>
<span class="option-description">Delete cookies, cache, and site data</span>
</div>
</div>
<div class="option-control">
<button class="action-button danger" id="bp-clear-data" data-focusable tabindex="0">
<span class="material-symbols-outlined">delete</span>
<span>Clear All</span>
</button>
</div>
</div>
<div class="settings-option">
<div class="option-info">
<span class="material-symbols-outlined">history</span>
<div class="option-text">
<span class="option-label">Clear History</span>
<span class="option-description">Delete browsing history</span>
</div>
</div>
<div class="option-control">
<button class="action-button" id="bp-clear-history-settings" data-focusable tabindex="0">
<span class="material-symbols-outlined">delete</span>
<span>Clear</span>
</button>
</div>
</div>
<div class="settings-option">
<div class="option-info">
<span class="material-symbols-outlined">search_off</span>
<div class="option-text">
<span class="option-label">Clear Search History</span>
<span class="option-description">Delete search query history</span>
</div>
</div>
<div class="option-control">
<button class="action-button" id="bp-clear-search" data-focusable tabindex="0">
<span class="material-symbols-outlined">delete</span>
<span>Clear</span>
</button>
</div>
</div>
</div>
<!-- About Panel -->
<div class="settings-panel" id="settings-panel-about">
<h2 class="settings-panel-title">About Nebula Browser</h2>
<div class="about-info">
<div class="about-logo">
<img src="../assets/images/branding/Nebula-Icon.svg" alt="Nebula" class="about-logo-img">
<div class="about-title">
<h3>Nebula Browser</h3>
<span id="bp-version">Version loading...</span>
</div>
</div>
<div class="about-details">
<div class="about-row">
<span class="about-label">CEF</span>
<span class="about-value" id="bp-cef-version">--</span>
</div>
<div class="about-row">
<span class="about-label">Chromium</span>
<span class="about-value" id="bp-chromium-version">--</span>
</div>
<div class="about-row">
<span class="about-label">Node.js</span>
<span class="about-value" id="bp-node-version">--</span>
</div>
<div class="about-row">
<span class="about-label">Platform</span>
<span class="about-value" id="bp-platform">--</span>
</div>
</div>
<div class="about-actions">
<button class="action-button" id="bp-github-link" data-focusable tabindex="0">
<span class="ri-github-fill" style="font-size: 20px;"></span>
<span>GitHub</span>
</button>
<button class="action-button" id="bp-copy-diagnostics" data-focusable tabindex="0">
<span class="material-symbols-outlined">content_copy</span>
<span>Copy Info</span>
</button>
</div>
</div>
</div>
</div>
</section>
</div>
</main>
<!-- Bottom controller hints -->
<footer class="bp-footer">
<div class="controller-hints" id="controller-hints">
<div class="hint">
<span class="controller-btn dpad">
<span class="material-symbols-outlined">gamepad</span>
</span>
<span id="hint-navigate">Navigate</span>
</div>
<div class="hint">
<span class="controller-btn a-btn">A</span>
<span id="hint-a">Select</span>
</div>
<div class="hint">
<span class="controller-btn b-btn">B</span>
<span id="hint-b">Back</span>
</div>
<div class="hint">
<span class="controller-btn y-btn">Y</span>
<span id="hint-y">Search</span>
</div>
<div class="hint">
<span class="controller-btn menu-btn"></span>
<span id="hint-menu">Menu</span>
</div>
</div>
</footer>
<!-- On-screen keyboard (for controller input) -->
<div id="osk-overlay" class="osk-overlay hidden">
<div class="osk-container">
<div class="osk-title">
<span class="material-symbols-outlined">keyboard</span>
<span id="osk-label">Enter text</span>
</div>
<div class="osk-header">
<div class="osk-input-wrapper">
<input type="text" id="osk-input" class="osk-text-input" placeholder="Your text appears here..." readonly>
<span id="osk-cursor" class="osk-cursor"></span>
<span id="osk-text-measure" class="osk-text-measure"></span>
</div>
<button class="osk-close" data-focusable tabindex="0">
<span class="material-symbols-outlined">close</span>
</button>
</div>
<div class="osk-keyboard" id="osk-keyboard">
<!-- Keyboard rows will be generated by JS -->
</div>
<div class="osk-actions">
<button class="osk-action-btn" id="osk-space" data-focusable tabindex="0">
<span class="btn-hint">Y</span> Space
</button>
<button class="osk-action-btn" id="osk-backspace" data-focusable tabindex="0">
<span class="btn-hint">X</span>
<span class="material-symbols-outlined">backspace</span>
</button>
<button class="osk-action-btn" id="osk-clear" data-focusable tabindex="0">
<span class="btn-hint">LB</span> Clear
</button>
<button class="osk-action-btn primary" id="osk-submit" data-focusable tabindex="0">
<span class="btn-hint">RB</span> Go
</button>
</div>
<div class="osk-hints">
<span><b>A</b> Type</span>
<span><b>X</b> Backspace</span>
<span><b>Y</b> Space</span>
<span><b>B</b> Close</span>
<span><b>LB</b> Clear All</span>
<span><b>RB</b> Submit</span>
</div>
</div>
</div>
<!-- Context menu -->
<div id="context-menu" class="context-menu hidden">
<button class="context-item" data-action="open" data-focusable tabindex="0">
<span class="material-symbols-outlined">open_in_new</span>
<span>Open</span>
</button>
<button class="context-item" data-action="edit" data-focusable tabindex="0">
<span class="material-symbols-outlined">edit</span>
<span>Edit</span>
</button>
<button class="context-item" data-action="delete" data-focusable tabindex="0">
<span class="material-symbols-outlined">delete</span>
<span>Delete</span>
</button>
</div>
</div>
<script src="../js/bigpicture.js"></script>
</body>
</html>