feat: implement video_protocol.rs, commands.rs, wire up main.rs, and index.html
- video_protocol.rs: tutdock:// custom protocol with HTTP Range support for video streaming, subtitle/font serving with path traversal protection - commands.rs: all 26 Tauri command handlers as thin wrappers - main.rs: full Tauri bootstrap with state management, window restore, async font caching, and ffmpeg discovery - index.html: complete HTML markup extracted from Python app - lib.rs: updated with all module declarations and AppPaths struct
This commit is contained in:
261
src/index.html
261
src/index.html
@@ -1,14 +1,251 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>TutorialDock</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="zoomRoot">
|
||||
<div class="app"></div>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>TutorialDock</title>
|
||||
<link rel="stylesheet" href="tutdock://localhost/fonts.css">
|
||||
<link rel="stylesheet" href="tutdock://localhost/fa.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="zoomRoot">
|
||||
<div class="app">
|
||||
<div class="topbar">
|
||||
<div class="brand">
|
||||
<div class="appIcon" aria-hidden="true"><div class="appIconGlow"></div><i class="fa-solid fa-graduation-cap"></i></div>
|
||||
<div class="brandText">
|
||||
<div class="appName">TutorialDock</div>
|
||||
<div class="tagline">Watch local tutorials, resume instantly, and actually finish them.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<div class="actionGroup">
|
||||
<label class="switch" data-tooltip="On Top" data-tooltip-desc="Keep this window above others (global)">
|
||||
<input type="checkbox" id="onTopChk">
|
||||
<span class="track"><span class="knob"></span></span>
|
||||
<span>On top</span>
|
||||
</label>
|
||||
|
||||
<label class="switch" data-tooltip="Autoplay" data-tooltip-desc="Autoplay next/prev (saved per folder)">
|
||||
<input type="checkbox" id="autoplayChk">
|
||||
<span class="track"><span class="knob"></span></span>
|
||||
<span>Autoplay</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="actionDivider"></div>
|
||||
|
||||
<div class="actionGroup">
|
||||
<div class="zoomControl" data-tooltip="UI Zoom" data-tooltip-desc="Adjust the interface zoom level">
|
||||
<button class="zoomBtn" id="zoomOutBtn"><i class="fa-solid fa-minus"></i></button>
|
||||
<span class="zoomValue" id="zoomResetBtn">100%</span>
|
||||
<button class="zoomBtn" id="zoomInBtn"><i class="fa-solid fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actionDivider"></div>
|
||||
|
||||
<div class="actionGroup">
|
||||
<div class="splitBtn primary">
|
||||
<button class="btn primary" id="chooseBtn" data-tooltip="Open Folder" data-tooltip-desc="Browse and select a folder containing videos"><i class="fa-solid fa-folder-open"></i> Open folder</button>
|
||||
<button class="btn drop" id="chooseDropBtn" data-tooltip="Recent Folders" data-tooltip-desc="Open a recently used folder"><i class="fa-solid fa-chevron-down"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actionDivider"></div>
|
||||
|
||||
<div class="actionGroup">
|
||||
<button class="toolbarBtn" id="resetProgBtn" data-tooltip="Reset Progress" data-tooltip-desc="Reset DONE / NOW progress for this folder (keeps notes, volume, etc.)"><i class="fa-solid fa-clock-rotate-left"></i></button>
|
||||
<button class="toolbarBtn" id="refreshBtn" data-tooltip="Reload" data-tooltip-desc="Reload the current folder"><i class="fa-solid fa-arrows-rotate"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/main.ts"></script>
|
||||
</body>
|
||||
|
||||
<div class="dropdownPortal" id="recentMenu"></div>
|
||||
|
||||
<div class="content" id="contentGrid">
|
||||
<div class="panel">
|
||||
<div class="panelHeader">
|
||||
<div style="min-width:0;">
|
||||
<div class="nowTitle" id="nowTitle">No video loaded</div>
|
||||
<div class="nowSub" id="nowSub">-</div>
|
||||
</div>
|
||||
|
||||
<div class="progressPill" data-tooltip="Overall Progress" data-tooltip-desc="Folder completion (time-based, using cached durations when available)">
|
||||
<div class="progressLabel">Overall</div>
|
||||
<div class="progressBar"><div id="overallBar"></div></div>
|
||||
<div class="progressPct" id="overallPct">-</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="videoWrap">
|
||||
<video id="player" preload="metadata"></video>
|
||||
<div class="videoOverlay" id="videoOverlay">
|
||||
<div class="overlayIcon" id="overlayIcon">
|
||||
<i class="fa-solid fa-play" id="overlayIconI"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<div class="controlsRow">
|
||||
<div class="group">
|
||||
<button class="iconBtn" id="prevBtn" data-tooltip="Previous" data-tooltip-desc="Go to previous video"><i class="fa-solid fa-backward-step"></i></button>
|
||||
|
||||
<button class="iconBtn primary" id="playPauseBtn" data-tooltip="Play/Pause" data-tooltip-desc="Toggle video playback">
|
||||
<i class="fa-solid fa-play" id="ppIcon"></i>
|
||||
</button>
|
||||
|
||||
<button class="iconBtn" id="nextBtn" data-tooltip="Next" data-tooltip-desc="Go to next video"><i class="fa-solid fa-forward-step"></i></button>
|
||||
|
||||
<div class="timeChip" data-tooltip="Time" data-tooltip-desc="Current position / Total duration">
|
||||
<div class="timeDot"></div>
|
||||
<div><span id="timeNow">00:00</span> <span style="color:rgba(165,172,196,.65)">/</span> <span id="timeDur">00:00</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="group">
|
||||
<div class="subsBox">
|
||||
<button class="iconBtn" id="subsBtn" data-tooltip="Subtitles" data-tooltip-desc="Load or select subtitles"><i class="fa-regular fa-closed-captioning"></i></button>
|
||||
<div class="subsMenu" id="subsMenu" role="menu"></div>
|
||||
</div>
|
||||
|
||||
<div class="miniCtl" data-tooltip="Volume" data-tooltip-desc="Adjust volume (saved per folder)">
|
||||
<i class="fa-solid fa-volume-high"></i>
|
||||
<div class="volWrap">
|
||||
<div class="volTrack">
|
||||
<div class="volFill" id="volFill"></div>
|
||||
</div>
|
||||
<input type="range" id="volSlider" class="vol" min="0" max="1" step="0.01" value="1">
|
||||
</div>
|
||||
<div class="volTooltip" id="volTooltip">100%</div>
|
||||
</div>
|
||||
|
||||
<div class="miniCtl" data-tooltip="Speed" data-tooltip-desc="Playback speed (saved per folder)">
|
||||
<svg id="speedIcon" width="14" height="14" viewBox="0 0 24 24" style="overflow:visible; color:var(--iconStrong);">
|
||||
<path d="M12 22C6.5 22 2 17.5 2 12S6.5 2 12 2s10 4.5 10 10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity=".5"/>
|
||||
<path d="M12 22c5.5 0 10-4.5 10-10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity=".3"/>
|
||||
<g transform="rotate(0, 12, 13)">
|
||||
<line x1="12" y1="13" x2="12" y2="5" stroke="rgba(255,255,255,.85)" stroke-width="2.5" stroke-linecap="round"/>
|
||||
</g>
|
||||
<circle cx="12" cy="13" r="2" fill="currentColor" opacity=".7"/>
|
||||
</svg>
|
||||
<div class="speedBox">
|
||||
<button class="speedBtn" id="speedBtn" aria-label="Playback speed">
|
||||
<span id="speedBtnText">1.0x</span>
|
||||
<span class="speedCaret" aria-hidden="true"><i class="fa-solid fa-chevron-up"></i></span>
|
||||
</button>
|
||||
<div class="speedMenu" id="speedMenu" role="menu" aria-label="Speed menu"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="iconBtn" id="fsBtn" data-tooltip="Fullscreen" data-tooltip-desc="Toggle fullscreen mode"><i class="fa-solid fa-expand"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="seekWrap">
|
||||
<div class="seekTrack">
|
||||
<div class="seekFill" id="seekFill"></div>
|
||||
</div>
|
||||
<input type="range" id="seek" class="seek" min="0" max="1000" step="1" value="0" aria-label="Seek">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dock" id="dockGrid">
|
||||
<div class="dockPane">
|
||||
<div class="dockInner">
|
||||
<div class="dockHeader" id="notesHeader" data-tooltip="Notes" data-tooltip-desc="Your notes are automatically saved for each video file. Write timestamps, TODOs, or reminders.">
|
||||
<div class="dockTitle"><i class="fa-solid fa-note-sticky"></i> Notes</div>
|
||||
</div>
|
||||
<div class="notesArea">
|
||||
<textarea class="notes" id="notesBox" placeholder="Write timestamps, TODOs, reminders…"></textarea>
|
||||
<div class="notesSaved" id="notesSaved"><i class="fa-solid fa-check"></i> Saved</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dockDividerWrap">
|
||||
<div class="dockDivider" id="dockDivider" data-tooltip="Resize" data-tooltip-desc="Drag to resize panels"></div>
|
||||
</div>
|
||||
|
||||
<div class="dockPane">
|
||||
<div class="dockInner">
|
||||
<div class="dockHeader" id="infoHeader" data-tooltip="Info" data-tooltip-desc="Metadata and progress info for the current folder and video. Updates automatically.">
|
||||
<div class="dockTitle"><i class="fa-solid fa-circle-info"></i> Info</div>
|
||||
</div>
|
||||
<div class="infoGrid" id="infoGrid">
|
||||
<div class="kv">
|
||||
<div class="k">Folder</div><div class="v" id="infoFolder">-</div>
|
||||
<div class="k">Next up</div><div class="v" id="infoNext">-</div>
|
||||
<div class="k">Structure</div><div class="v mono" id="infoStruct">-</div>
|
||||
</div>
|
||||
|
||||
<div class="kv">
|
||||
<div class="k">Title</div><div class="v" id="infoTitle">-</div>
|
||||
<div class="k">Relpath</div><div class="v mono" id="infoRel">-</div>
|
||||
<div class="k">Position</div><div class="v mono" id="infoPos">-</div>
|
||||
</div>
|
||||
|
||||
<div class="kv">
|
||||
<div class="k">File</div><div class="v mono" id="infoFileBits">-</div>
|
||||
<div class="k">Video</div><div class="v mono" id="infoVidBits">-</div>
|
||||
<div class="k">Audio</div><div class="v mono" id="infoAudBits">-</div>
|
||||
<div class="k">Subtitles</div><div class="v mono" id="infoSubsBits">-</div>
|
||||
</div>
|
||||
|
||||
<div class="kv">
|
||||
<div class="k">Finished</div><div class="v mono" id="infoFinished">-</div>
|
||||
<div class="k">Remaining</div><div class="v mono" id="infoRemaining">-</div>
|
||||
<div class="k">ETA</div><div class="v mono" id="infoEta">-</div>
|
||||
</div>
|
||||
|
||||
<div class="kv">
|
||||
<div class="k">Volume</div><div class="v mono" id="infoVolume">-</div>
|
||||
<div class="k">Speed</div><div class="v mono" id="infoSpeed">-</div>
|
||||
<div class="k">Durations</div><div class="v mono" id="infoKnown">-</div>
|
||||
</div>
|
||||
|
||||
<div class="kv">
|
||||
<div class="k">Top folders</div><div class="v mono" id="infoTop">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="dividerWrap">
|
||||
<div class="divider" id="divider" data-tooltip="Resize" data-tooltip-desc="Drag to resize panels"></div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panelHeader" style="align-items:center;">
|
||||
<div class="playlistHeader" id="plistHeader" data-tooltip="Playlist" data-tooltip-desc="Drag items to reorder. The blue line shows where it will drop."><i class="fa-solid fa-list"></i> Playlist</div>
|
||||
<div style="flex:1 1 auto;"></div>
|
||||
</div>
|
||||
<div class="listWrap">
|
||||
<div class="list" id="list"></div>
|
||||
<div class="listScrollbar" id="listScrollbar"><div class="listScrollbarThumb" id="listScrollbarThumb"></div></div>
|
||||
</div>
|
||||
<div class="empty" id="emptyHint" style="display:none;">
|
||||
No videos found (searched recursively).<br/>Native playback is happiest with MP4 (H.264/AAC) or WebM.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="toast" aria-live="polite">
|
||||
<div class="toastInner">
|
||||
<div class="toastIcon"><i class="fa-solid fa-circle-info"></i></div>
|
||||
<div class="toastMsg" id="toastMsg">-</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tooltip" id="fancyTooltip"><div class="tooltip-title"></div><div class="tooltip-desc"></div></div>
|
||||
|
||||
<script type="module" src="/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user