feat: some nice animations for settings areas missing it & fix update video

This commit is contained in:
2026-08-21 17:38:11 +09:30
parent f0247428a0
commit 12833f9270
8 changed files with 348 additions and 64 deletions
+117 -38
View File
@@ -1,5 +1,6 @@
import browser from "webextension-polyfill";
import stringToHTML from "@/seqta/utils/stringToHTML";
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
import loadingSpinner from "./loading-spinner.html?raw";
import loadingOverlay from "./loading-overlay.html?raw";
import { startLoadingCanvas } from "./loadingCanvas";
@@ -9,32 +10,46 @@ import {
} from "./loadingVariants";
let stopCanvas: (() => void) | null = null;
let unbindThemeGuard: (() => void) | null = null;
let activeLoading: {
host: HTMLElement;
shadow: ShadowRoot;
variant: LoadingVariant;
} | null = null;
const THEME_GUARD_KEYS = [
"selectedTheme",
"selectedColor",
"DarkMode",
"adaptiveThemeColour",
"selectedFont",
] as const;
const LOADING_PALETTE = {
line: "rgba(255, 255, 255, 0.08)",
lineAccent: "rgba(255, 255, 255, 0.15)",
lineBlue: "rgba(96, 165, 250, 0.42)",
grid: "rgba(255, 255, 255, 0.028)",
text: "#f4f4f5",
} as const;
const loadingStyles = /* css */ `
.bkloading {
--bk-line-color: rgba(255, 255, 255, 0.08);
--bk-line-accent: rgba(255, 255, 255, 0.15);
--bk-line-blue: rgba(96, 165, 250, 0.42);
--bk-grid-color: rgba(255, 255, 255, 0.028);
:host {
--bk-line-color: ${LOADING_PALETTE.line};
--bk-line-accent: ${LOADING_PALETTE.lineAccent};
--bk-line-blue: ${LOADING_PALETTE.lineBlue};
--bk-grid-color: ${LOADING_PALETTE.grid};
--bk-spin-outer: 1s;
--bk-spin-inner: 3s;
--bk-spin-small: 3s;
--bk-stage-name: bkloading-stage-in;
--bk-stage-duration: 0.85s;
position: absolute;
inset: 0;
z-index: 1000000;
overflow: hidden;
contain: strict;
color: #f4f4f5;
background:
radial-gradient(ellipse 70% 45% at 50% 95%, rgba(37, 99, 235, 0.12), transparent 62%),
linear-gradient(180deg, #010101 0%, #040404 50%, #080808 100%);
color: ${LOADING_PALETTE.text};
opacity: 1;
transition: opacity 0.85s cubic-bezier(0.4, 0, 0.2, 1);
}
.bkloading.closeLoading {
:host(.closeLoading) {
opacity: 0;
pointer-events: none;
}
@@ -184,24 +199,80 @@ function overlayWithSpinner(): string {
);
}
function applyVariantTheme(root: HTMLElement, variant: LoadingVariant) {
const { theme } = variant;
root.dataset.variant = variant.id;
root.style.background = theme.background;
root.style.setProperty("--bk-spin-outer", theme.spinOuter);
root.style.setProperty("--bk-spin-inner", theme.spinInner);
root.style.setProperty("--bk-spin-small", theme.spinSmall);
root.style.setProperty("--bk-stage-name", theme.stageName);
root.style.setProperty("--bk-stage-duration", theme.stageDuration);
function applyHostShell(host: HTMLElement) {
const shell = [
["position", "fixed"],
["inset", "0"],
["z-index", "1000000"],
["display", "block"],
["overflow", "hidden"],
["contain", "strict"],
["visibility", "visible"],
["pointer-events", "auto"],
["color", LOADING_PALETTE.text],
["--bk-line-color", LOADING_PALETTE.line],
["--bk-line-accent", LOADING_PALETTE.lineAccent],
["--bk-line-blue", LOADING_PALETTE.lineBlue],
["--bk-grid-color", LOADING_PALETTE.grid],
] as const;
const vignette = root.querySelector(".bkloading__vignette") as HTMLElement | null;
for (const [prop, value] of shell) {
host.style.setProperty(prop, value, "important");
}
}
function applyVariantTheme(
host: HTMLElement,
shadow: ShadowRoot,
variant: LoadingVariant,
) {
const { theme } = variant;
host.dataset.variant = variant.id;
applyHostShell(host);
host.style.setProperty("background", theme.background, "important");
host.style.setProperty("--bk-spin-outer", theme.spinOuter, "important");
host.style.setProperty("--bk-spin-inner", theme.spinInner, "important");
host.style.setProperty("--bk-spin-small", theme.spinSmall, "important");
host.style.setProperty("--bk-stage-name", theme.stageName, "important");
host.style.setProperty("--bk-stage-duration", theme.stageDuration, "important");
const vignette = shadow.querySelector(".bkloading__vignette") as HTMLElement | null;
if (vignette) vignette.style.opacity = String(theme.vignetteOpacity);
}
function startCanvasForRoot(root: HTMLElement, variant: LoadingVariant) {
function refreshActiveLoadingTheme() {
if (!activeLoading || activeLoading.host.classList.contains("closeLoading")) return;
applyVariantTheme(activeLoading.host, activeLoading.shadow, activeLoading.variant);
}
function bindLoadingThemeGuard() {
const onThemeChange = () => refreshActiveLoadingTheme();
for (const key of THEME_GUARD_KEYS) {
settingsState.register(key, onThemeChange);
}
const observer = new MutationObserver(onThemeChange);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ["style", "class", "data-city-state"],
});
return () => {
for (const key of THEME_GUARD_KEYS) {
settingsState.unregister(key, onThemeChange);
}
observer.disconnect();
};
}
function startCanvasForRoot(
host: HTMLElement,
shadow: ShadowRoot,
variant: LoadingVariant,
) {
stopCanvas?.();
const canvas = root.querySelector(".bkloading__canvas") as HTMLCanvasElement | null;
stopCanvas = canvas ? startLoadingCanvas(canvas, root, variant) : null;
const canvas = shadow.querySelector(".bkloading__canvas") as HTMLCanvasElement | null;
stopCanvas = canvas ? startLoadingCanvas(canvas, host, variant) : null;
}
export function AppendLoadingSymbol(givenID: string, position: string) {
@@ -216,23 +287,31 @@ export function AppendLoadingSymbol(givenID: string, position: string) {
export function stopLoadingAnimation() {
stopCanvas?.();
stopCanvas = null;
unbindThemeGuard?.();
unbindThemeGuard = null;
activeLoading = null;
}
export default function loading() {
stopLoadingAnimation();
const variant = pickLoadingVariant();
const host = document.createElement("div");
host.id = "loading";
host.className = "bkloading";
const loadinghtml = stringToHTML(/* html */ `
<div class="bkloading" id="loading" data-variant="${variant.id}">
<style>${loadingStyles}</style>
${overlayWithSpinner()}
<div class="bkloading__version">v${browser.runtime.getManifest().version}</div>
</div>`);
const shadow = host.attachShadow({ mode: "open" });
shadow.innerHTML = `
<style>${loadingStyles}</style>
${overlayWithSpinner()}
<div class="bkloading__version">v${browser.runtime.getManifest().version}</div>
`;
const root = loadinghtml.firstChild as HTMLElement;
document.documentElement.append(root);
document.documentElement.append(host);
applyVariantTheme(root, variant);
startCanvasForRoot(root, variant);
applyVariantTheme(host, shadow, variant);
startCanvasForRoot(host, shadow, variant);
activeLoading = { host, shadow, variant };
unbindThemeGuard = bindLoadingThemeGuard();
}