Migre le projet vers Blazor WebAssembly en .NET 10
This commit is contained in:
BIN
ChessCubing.App/wwwroot/icon-192.png
Normal file
BIN
ChessCubing.App/wwwroot/icon-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
45
ChessCubing.App/wwwroot/index.html
Normal file
45
ChessCubing.App/wwwroot/index.html
Normal file
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||
<meta name="theme-color" content="#140700" />
|
||||
<meta name="application-name" content="ChessCubing Arena" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="ChessCubing" />
|
||||
<meta name="description" content="Application officielle ChessCubing Arena en Blazor .NET 10." />
|
||||
<title>ChessCubing Arena</title>
|
||||
<base href="/" />
|
||||
<link rel="preload" id="webassembly" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="shortcut icon" href="favicon.png" />
|
||||
<link rel="apple-touch-icon" href="logo.png" />
|
||||
<link rel="manifest" href="site.webmanifest" />
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<link href="ChessCubing.App.styles.css" rel="stylesheet" />
|
||||
<script src="js/chesscubing-interop.js"></script>
|
||||
<script type="importmap"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<div style="min-height: 100dvh; display: grid; place-items: center; padding: 2rem; color: #f5f7fb;">
|
||||
<div style="text-align: center;">
|
||||
<strong style="display: block; margin-bottom: 0.75rem;">ChessCubing Arena</strong>
|
||||
<span>Chargement de l'application Blazor...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
Une erreur inattendue est survenue.
|
||||
<a href="." class="reload">Recharger</a>
|
||||
<span class="dismiss">x</span>
|
||||
</div>
|
||||
<script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
200
ChessCubing.App/wwwroot/js/chesscubing-interop.js
Normal file
200
ChessCubing.App/wwwroot/js/chesscubing-interop.js
Normal file
@@ -0,0 +1,200 @@
|
||||
(() => {
|
||||
const assetTokenStorageKey = "chesscubing-arena-asset-token";
|
||||
let viewportStarted = false;
|
||||
let audioContext = null;
|
||||
|
||||
function syncViewportHeight() {
|
||||
const visibleHeight = window.visualViewport?.height ?? window.innerHeight;
|
||||
const viewportTopOffset = window.visualViewport?.offsetTop ?? 0;
|
||||
const viewportHeight = Math.max(
|
||||
visibleHeight + viewportTopOffset,
|
||||
window.innerHeight,
|
||||
document.documentElement.clientHeight,
|
||||
);
|
||||
|
||||
document.documentElement.style.setProperty("--app-visible-height", `${Math.round(visibleHeight)}px`);
|
||||
document.documentElement.style.setProperty("--app-viewport-top", `${Math.round(viewportTopOffset)}px`);
|
||||
document.documentElement.style.setProperty("--app-viewport-height", `${Math.round(viewportHeight)}px`);
|
||||
}
|
||||
|
||||
function startViewport() {
|
||||
if (viewportStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewportStarted = true;
|
||||
syncViewportHeight();
|
||||
window.addEventListener("load", syncViewportHeight);
|
||||
window.addEventListener("resize", syncViewportHeight);
|
||||
window.addEventListener("scroll", syncViewportHeight, { passive: true });
|
||||
window.addEventListener("pageshow", syncViewportHeight);
|
||||
window.addEventListener("orientationchange", syncViewportHeight);
|
||||
window.visualViewport?.addEventListener("resize", syncViewportHeight);
|
||||
window.visualViewport?.addEventListener("scroll", syncViewportHeight);
|
||||
window.setTimeout(syncViewportHeight, 0);
|
||||
window.setTimeout(syncViewportHeight, 150);
|
||||
window.setTimeout(syncViewportHeight, 400);
|
||||
window.requestAnimationFrame(() => window.requestAnimationFrame(syncViewportHeight));
|
||||
}
|
||||
|
||||
function getAudioContext() {
|
||||
const AudioContextClass = window.AudioContext || window.webkitAudioContext;
|
||||
if (!AudioContextClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!audioContext) {
|
||||
try {
|
||||
audioContext = new AudioContextClass();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return audioContext;
|
||||
}
|
||||
|
||||
function primeAudio() {
|
||||
const context = getAudioContext();
|
||||
if (!context || context.state === "running") {
|
||||
return;
|
||||
}
|
||||
|
||||
context.resume().catch(() => undefined);
|
||||
}
|
||||
|
||||
function playCubePhaseAlert() {
|
||||
primeAudio();
|
||||
const context = getAudioContext();
|
||||
if (!context || context.state !== "running") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const pattern = [
|
||||
{ frequency: 740, offset: 0, duration: 0.12, gain: 0.035 },
|
||||
{ frequency: 988, offset: 0.18, duration: 0.12, gain: 0.04 },
|
||||
{ frequency: 1318, offset: 0.36, duration: 0.2, gain: 0.05 },
|
||||
];
|
||||
const startAt = context.currentTime + 0.02;
|
||||
|
||||
pattern.forEach(({ frequency, offset, duration, gain }) => {
|
||||
const oscillator = context.createOscillator();
|
||||
const envelope = context.createGain();
|
||||
const toneStartAt = startAt + offset;
|
||||
|
||||
oscillator.type = "triangle";
|
||||
oscillator.frequency.setValueAtTime(frequency, toneStartAt);
|
||||
envelope.gain.setValueAtTime(0.0001, toneStartAt);
|
||||
envelope.gain.exponentialRampToValueAtTime(gain, toneStartAt + 0.02);
|
||||
envelope.gain.exponentialRampToValueAtTime(0.0001, toneStartAt + duration);
|
||||
|
||||
oscillator.connect(envelope);
|
||||
envelope.connect(context.destination);
|
||||
oscillator.start(toneStartAt);
|
||||
oscillator.stop(toneStartAt + duration + 0.03);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
window.chesscubingPage = {
|
||||
setBodyState(page, bodyClass) {
|
||||
if (page) {
|
||||
document.body.dataset.page = page;
|
||||
} else {
|
||||
delete document.body.dataset.page;
|
||||
}
|
||||
|
||||
document.body.className = bodyClass || "";
|
||||
},
|
||||
};
|
||||
|
||||
window.chesscubingViewport = {
|
||||
start: startViewport,
|
||||
};
|
||||
|
||||
window.chesscubingStorage = {
|
||||
getMatchState(storageKey, windowNameKey) {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(storageKey);
|
||||
if (raw) {
|
||||
return raw;
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
|
||||
try {
|
||||
if (!window.name || !window.name.startsWith(windowNameKey)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return window.name.slice(windowNameKey.length);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
setMatchState(storageKey, windowNameKey, value) {
|
||||
try {
|
||||
window.name = `${windowNameKey}${value}`;
|
||||
} catch {
|
||||
}
|
||||
|
||||
try {
|
||||
window.localStorage.setItem(storageKey, value);
|
||||
} catch {
|
||||
}
|
||||
},
|
||||
|
||||
clearMatchState(storageKey) {
|
||||
try {
|
||||
window.localStorage.removeItem(storageKey);
|
||||
} catch {
|
||||
}
|
||||
|
||||
try {
|
||||
window.name = "";
|
||||
} catch {
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
window.chesscubingAudio = {
|
||||
prime: primeAudio,
|
||||
playCubePhaseAlert,
|
||||
};
|
||||
|
||||
window.chesscubingBrowser = {
|
||||
async forceRefresh(path) {
|
||||
const refreshToken = `${Date.now()}`;
|
||||
|
||||
try {
|
||||
window.sessionStorage.setItem(assetTokenStorageKey, refreshToken);
|
||||
} catch {
|
||||
}
|
||||
|
||||
if ("caches" in window) {
|
||||
try {
|
||||
const cacheKeys = await window.caches.keys();
|
||||
await Promise.all(cacheKeys.map((cacheKey) => window.caches.delete(cacheKey)));
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
if ("serviceWorker" in navigator) {
|
||||
try {
|
||||
const registrations = await navigator.serviceWorker.getRegistrations();
|
||||
await Promise.all(registrations.map((registration) => registration.update().catch(() => undefined)));
|
||||
await Promise.all(registrations.map((registration) => registration.unregister().catch(() => undefined)));
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
const targetUrl = new URL(path, window.location.href);
|
||||
targetUrl.searchParams.set("refresh", refreshToken);
|
||||
window.location.replace(targetUrl.toString());
|
||||
},
|
||||
};
|
||||
|
||||
startViewport();
|
||||
})();
|
||||
Reference in New Issue
Block a user