[web-ext]: add-audio-mode-and-revamp-popup-and-options#79
Open
DarhkVoyd wants to merge 3 commits into
Open
Conversation
DarhkVoyd
force-pushed
the
claude/exciting-keller-a18866
branch
from
May 14, 2026 21:37
f2054cb to
dfa60f6
Compare
DarhkVoyd
force-pushed
the
claude/exciting-keller-a18866
branch
from
May 17, 2026 21:32
d039cdb to
b3e383c
Compare
| if (currentCustomImageUrl) { | ||
| // Wrap in double quotes; CSS.escape() is for identifiers (class | ||
| // names/selectors) and would mangle the URL's : ; / + = characters. | ||
| const escapedUrl = currentCustomImageUrl.replace(/"/g, '\\"'); |
DarhkVoyd
force-pushed
the
claude/exciting-keller-a18866
branch
from
June 21, 2026 11:48
0074568 to
3aa7a07
Compare
clean up wait wait feat: Segments — multi-segment playback sequencer (#102) Replaces the single loop-segment system with a fully extensible Segments engine. Users can define multiple time-range markers on any video and configure exactly how they play back. Core capabilities - Multiple segments per video, each shown as a colored pentagon marker pair on the YouTube progress bar - Per-segment loop count (0 = infinite) and playback rate override - Per-iteration rate overrides: [1.0, 1.5] plays 1× first, 1.5× second - Advanced Sequence editor: compose steps with any custom segment order; duplicates allowed — [seg3, seg3, seg1] plays seg3 twice then seg1 - Segment merge: hold adjacent markers within 1.5% for 500 ms → merge with pulse animation Save tiers - Last-used: auto-updated volatile slot, never requires explicit save - Default slot: one-click quick save - Named configs: unlimited, each with an optional keyboard shortcut for instant activation (e.g. Ctrl+1) Keyboard shortcuts - Z — load last-used config / toggle off (replaces toggleLoopSegment) - Shift+Z — always start a fresh slate (full video, infinite loop) - Q / E — set start / end of the active segment (one containing playhead) - Shift+Q / Shift+E — nudge with acceleration (unchanged) - Named config combos — user-assignable per saved config New modules (SOLID boundaries) - utils/segments/types.ts — data types only - utils/segments/factories.ts — pure config factory functions - utils/segments/engine.ts — playback state machine, no DOM - utils/segments/markers.tsx — DOM marker controller, N colored pairs - utils/storage/segmentStore.ts — IndexedDB CRUD + transparent migration - components/SegmentButton.tsx — control bar button - components/SegmentPanel.tsx — below-video panel (simple + advanced) - components/Segments.tsx — coordinator; public API for watch.tsx Migration Existing SavedLoopSegment records are transparently converted to a single-segment SegmentConfig on first access. IndexedDB bumped to v4 with a new `segment_data` object store. Backward compat All existing preference keys (toggleLoopSegment, setLoopSegmentBegin, setLoopSegmentEnd, nudgeLoopSegment.*) are preserved unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> segment fixes marker update changes updates
DarhkVoyd
force-pushed
the
claude/exciting-keller-a18866
branch
from
June 21, 2026 11:49
3aa7a07 to
1774554
Compare
remove
DarhkVoyd
force-pushed
the
claude/exciting-keller-a18866
branch
from
June 21, 2026 11:50
1774554 to
9e63c09
Compare
Comment on lines
+24
to
+31
| import { | ||
| setSidebarVisible, | ||
| setCommentsVisible, | ||
| setEndCardsVisible, | ||
| resetSidebar, | ||
| resetComments, | ||
| resetEndCards, | ||
| } from "../../primitives/watch"; |
| "Show or hide the right-side recommendations", | ||
| !sidebarEl || sidebarEl.style.display !== "none", | ||
| async (next) => { | ||
| const { setSidebarVisible, resetSidebar } = await import( |
| import { useToast } from "../../../components/feedback/ToastProvider"; | ||
| import { useCapabilityCache } from "../../../hooks/useCapabilityCache"; | ||
| import { setExtensionIcon } from "../../../utils/browser"; | ||
| import { ThemePreference } from "../../../utils/theme"; |
| @@ -0,0 +1,249 @@ | |||
| import React, { useEffect, useState } from "react"; | |||
| import { Link } from "react-router-dom"; | |||
Comment on lines
+21
to
+26
| import { | ||
| BUILT_IN_PRESETS, | ||
| type Profile, | ||
| type ProfilePrimitiveConfig, | ||
| type ThumbnailMode, | ||
| } from "../../../data/profiles.data"; |
Comment on lines
+19
to
+22
| import { | ||
| getCustomProfiles, | ||
| setActiveProfileId, | ||
| } from "../../utils/storage/profileStore"; |
| withStore, | ||
| } from "./indexedDb"; | ||
| import type { VideoSegmentData, SegmentConfig, SegmentAutoLoadPin } from "../segments/types"; | ||
| import { createFreshConfig } from "../segments/factories"; |
Colocate docs UI under app/docs, consolidate site config into constants/site.ts, flatten route data files, and remove the old website/lib layer. update
DarhkVoyd
force-pushed
the
claude/exciting-keller-a18866
branch
from
June 23, 2026 06:15
cea95b3 to
111c312
Compare
| @@ -0,0 +1,27 @@ | |||
| import type { Metadata } from "next"; | |||
| import DocsPageHeader from "./components/DocsPageHeader"; | |||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
This PR introduces Audio Mode for the YouTube watch page, then revamps the popup and options page on top of a new shared component library and theme system.
Bshortcut that hides the video and plays audio-only, with three screen modes (Black, Visualizer, Custom Image). Includes a full custom UI overlay with title, channel, play/pause, progress bar, volume, mode switcher, per-video pin, and explicit close button. Persists across SPA navigation. Per-video pins stored inchrome.storage.local. Visualizer sensitivity is configurable. Auto-disables during ads.chrome.storage.local.prefers-color-scheme.options/tosrc/shared/so popup, options, and any future surface share primitives, form, feedback (Popup → ActionPopup → ConfirmPopup), layout, hooks, and utils.src/shared/features.ts) is a single source of truth for feature metadata + "What's New" feed; popup renders from it.web-ext/CLAUDE.md) document the new layout, theming, features-registry contract, and storage split.Why is this change necessary?
The original popup was a static welcome screen; the options page was a single monolithic file with hardcoded colors and limited components, and the watch page had no audio-only mode for users who want to listen without the visuals (office use, multitasking, NSFW visuals, etc.).
Putting popup + options on a shared, themable foundation also unblocks future surfaces — every primitive (Popup → ActionPopup → ConfirmPopup, Toast +
useToast(), ConfirmProvider +useConfirm(), Select, Slider, FilePicker, etc.) is now reusable, and adding a feature requires only an entry insrc/shared/features.tsfor it to appear in the popup.How was this change implemented?
web-ext/src/content_scripts/components/AudioMode/)#movie_playeratz-[9000+], with a class on the player that hides YouTube's chrome (.ytp-chrome-bottom, gradients, end-screen cards) viaweb-ext/src/content_scripts/index.csswhile active.createMediaElementSource(video)reroutes audio through Web Audio. Keepsource → destinationconnected at all times so audio plays in every screen mode; the analyser is an optional side-branch attached only when the visualizer runs.sqrtperceptual curve and a configurable sensitivity multiplier.userWantsAudioMode) persists across SPA navigations; per-video pins override.chrome.storage.syncfor preferences,chrome.storage.localfor per-video pins and uploaded background images (which exceedsync's 8KB per-item cap).web-ext/src/shared/theme.css)--color-bg,--color-surface,--color-fg,--color-accent, plus tonal pairs for success/info/warning/danger).web-ext/scripts/build.jsexposes them as semantic utilities (tw-bg-surface,tw-text-fg, etc.).useTheme()resolves the user's preference and writesdata-themeon<html>; re-applies on OS preference changes when "system" is selected.web-ext/src/shared/)options/components/and reorganized intoprimitives/,form/,feedback/,layout/,hooks/,utils/.Fieldwrapper for consistent label/description/error layout.Popup(portal + focus trap + backdrop) →ActionPopup(title + body + footer actions) →ConfirmPopup(configures actions for the confirm pattern) →useConfirm()for an imperativeawait confirm({…})API.web-ext/src/options/)chrome.storage.local).SectionNavusesIntersectionObserverto highlight the section in view; sticky positioning required removingoverflow-x-hiddenfrom<main>(any non-visibleoverflow ancestor silently becomes the sticky's scroll container).getStorage()deep-mergesDEFAULT_STOREinto existingchrome.storage.syncdata so installs get new keys (audio mode, theme, visualizer sensitivity) without manual migration.web-ext/src/popup/)options_pending_routetochrome.storage.local;options/App.tsxreads and consumes it on mount.web-ext/src/shared/features.ts)FEATURESandWHATS_NEWarrays with a maintainer-rules header. Popup renders from this; future surfaces (search, onboarding) can too.Screenshots / Visual Changes
NA (please grab while testing — the diff is large enough that screenshots would be helpful in the PR description before merging).
Related Issues
NA
Additional Considerations
getStorage()(web-ext/src/background/store.ts) means existing users won't lose their settings or hit "undefined" errors when the new keys (ui.theme,audioMode.*,audioMode.visualizerSensitivity) appear. The strategy is recursive merge of defaults into stored data with stored values taking precedence.createMediaElementSource(video)permanently reroutes the video's audio throughAudioContext. Once attached, audio plays only ifsource → destinationis connected. We keep that connection at all times and treat the analyser as an optional branch — switching out of visualizer mode no longer kills audio (this was an early bug that the new structure prevents).web-ext/scripts/build.js: addeddarkMode: ["class", '[data-theme="dark"]']and atheme.extend.colorsblock that maps semantic names to the CSS variables. No effect on production behavior, but reviewers should be aware.web-ext/CLAUDE.mdand the header ofweb-ext/src/shared/features.tsboth document that any new user-facing feature should be added toFEATURES(andWHATS_NEW) so the popup picks it up automatically.options/components/{Card,Input,Keybinding,Navbar,Switch,Tooltip}.tsxandpopup/components/Navbar.tsxare deleted in favor of the shared library; the previousoptions/store.tsx,options/hooks/,options/utils/moved toshared/.🤖 Generated with Claude Code