feat(anime): open Anime Browser in player modal

- Add the Ctrl+Alt+A shortcut and dedicated overlay modal
- Share queue, sources, and watch history while isolating browser state
This commit is contained in:
2026-08-15 21:44:52 -07:00
parent cc43d3007a
commit 7a1450ddb7
51 changed files with 921 additions and 180 deletions
+24 -4
View File
@@ -22,13 +22,25 @@ import type {
AnimeBrowserSource,
} from '../types/anime-browser';
declare global {
interface Window {
animeBrowserAPI: AnimeBrowserAPI;
const embeddedInOverlay =
new URLSearchParams(window.location.search).get('embedded') === 'overlay-modal';
if (embeddedInOverlay) document.documentElement.dataset.embedded = 'overlay-modal';
function resolveAnimeBrowserAPI(): AnimeBrowserAPI {
const local = (window as Window & { animeBrowserAPI?: AnimeBrowserAPI }).animeBrowserAPI;
if (local) return local;
try {
const parent = (window.parent as Window & { animeBrowserAPI?: AnimeBrowserAPI })
.animeBrowserAPI;
if (parent) return parent;
} catch {
// The embedded document is expected to be same-origin. Fall through to a
// direct error if Chromium blocks that relationship unexpectedly.
}
throw new Error('Anime Browser API is unavailable.');
}
const api = window.animeBrowserAPI;
const api = resolveAnimeBrowserAPI();
const searchForm = el<HTMLFormElement>('search-form');
const searchInput = el<HTMLInputElement>('search-input');
@@ -82,6 +94,14 @@ function setStatus(message: string, tone: 'info' | 'ok' | 'error' = 'info'): voi
const detailPanel = createDetailPanel({ api, setStatus });
if (embeddedInOverlay) {
document.addEventListener('keydown', (event) => {
if (event.key !== 'Escape' || event.defaultPrevented || detailPanel.isOpen()) return;
event.preventDefault();
window.parent.postMessage('subminer:anime-browser-close', '*');
});
}
const BRIDGE_LABELS: Record<AnimeBrowserBridgeState['stage'], string> = {
idle: 'Starting the extension bridge',
locating: 'Looking up the extension bridge release',
+5 -1
View File
@@ -89,7 +89,11 @@ export function createDetailPanel({ api, setStatus }: DetailPanelOptions) {
detailBack.addEventListener('click', close);
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && !detail.classList.contains('hidden')) close();
if (event.key === 'Escape' && !detail.classList.contains('hidden')) {
event.preventDefault();
event.stopImmediatePropagation();
close();
}
});
return {
+17
View File
@@ -52,6 +52,23 @@ body {
overflow: hidden;
}
html[data-embedded='overlay-modal'] .topbar {
gap: 12px;
padding: 10px 14px;
}
html[data-embedded='overlay-modal'] .brand-block {
display: none;
}
html[data-embedded='overlay-modal'] .bridge-banner {
padding-inline: 14px;
}
html[data-embedded='overlay-modal'] .statusbar {
padding-inline: 14px;
}
body {
display: flex;
flex-direction: column;