mirror of
https://codeberg.org/PLG-Development/PLG-MuDiCS
synced 2026-07-06 00:47:09 +00:00
21cb07a465
Co-authored-by: E44 <129310925+programmer-44@users.noreply.github.com> Reviewed-on: https://codeberg.org/PLG-Development/PLG-MuDiCS/pulls/58
311 lines
7.6 KiB
Plaintext
311 lines
7.6 KiB
Plaintext
package pkg
|
|
|
|
import "strings"
|
|
|
|
templ basicTemplate() {
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>PLG MuDiCS Display</title>
|
|
<style>
|
|
:root {
|
|
--background-color: black;
|
|
--foreground-color: oklch(92.3% 0.003 48.717);
|
|
--font-size: 5rem;
|
|
}
|
|
|
|
body {
|
|
display: flex;
|
|
justify-content: center;
|
|
/* centers horizontally */
|
|
align-items: center;
|
|
/* centers vertically */
|
|
width: 100vw;
|
|
/* Viewport width */
|
|
height: 100vh;
|
|
/* Viewport height */
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
background-color: var(--background-color);
|
|
color: var(--foreground-color);
|
|
font-family: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
|
cursor: none;
|
|
}
|
|
|
|
video,
|
|
img {
|
|
width: 100vw;
|
|
/* Viewport width */
|
|
height: 100vh;
|
|
/* Viewport height */
|
|
object-fit: contain;
|
|
}
|
|
|
|
p,
|
|
li {
|
|
font-size: var(--font-size);
|
|
line-height: 1.2;
|
|
text-wrap: balance;
|
|
max-width: 90vw;
|
|
word-break: break-word;
|
|
margin: 0 0 calc(var(--font-size) * 0.4) 0;
|
|
}
|
|
|
|
ul,
|
|
ol {
|
|
padding-left: calc(var(--font-size)*1.5);
|
|
}
|
|
</style>
|
|
</head>
|
|
<bod>
|
|
{ children... }
|
|
</bod>
|
|
</html>
|
|
}
|
|
|
|
templ videoTemplate(path string) {
|
|
@basicTemplate() {
|
|
<video autoplay>
|
|
<source src={ "file://" + path } type="video/mp4"/>
|
|
</video>
|
|
}
|
|
}
|
|
|
|
templ htmlTemplate(html string) {
|
|
@basicTemplate() {
|
|
@templ.Raw(html)
|
|
}
|
|
}
|
|
|
|
templ imageTemplate(path string) {
|
|
@basicTemplate() {
|
|
<img src={ "file://" + path }/>
|
|
}
|
|
}
|
|
|
|
templ deviceInfoTemplate(ip string, mac string, showQR bool) {
|
|
@basicTemplate() {
|
|
<div style="width: 100vw; height: 100vh; display: flex; flex-direction: row; justify-content: space-between;">
|
|
<div
|
|
style="display: flex; flex-direction: column; gap: 1rem; justify-content: end; padding: 2rem; font-size: 4rem;"
|
|
>
|
|
{ ip }
|
|
<span style="text-transform: uppercase;">{ mac }</span>
|
|
</div>
|
|
if showQR {
|
|
<div style="display: flex; justify-content: end; align-items: end; padding: 2rem;">
|
|
<div style="padding: 1rem; background-color: var(--foreground-color); border-radius: 1rem;">
|
|
<img
|
|
style="height: 30vh; width: auto; image-rendering: pixelated; image-rendering: crisp-edges;"
|
|
src={ "/qr?data=http://" + ip + ":8080" }
|
|
alt="QR-Code"
|
|
/>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
<style>
|
|
:root {
|
|
--splash-bg: transparent !important;
|
|
--splash-fade-out-state: paused !important;
|
|
--background-color: oklch(21.6% 0.006 56.043);
|
|
}
|
|
</style>
|
|
}
|
|
}
|
|
|
|
templ pdfTemplate(path string, serverOrigin string) {
|
|
@basicTemplate() {
|
|
<base href={ serverOrigin + "/" }/>
|
|
|
|
<div
|
|
id="pdf"
|
|
data-src={ "api/file/" + strings.Split(path, "/.local/share/plg-mudics/display")[1] }
|
|
data-lib="static/pdfjs/pdf.min.mjs"
|
|
data-worker="static/pdfjs/pdf.worker.min.mjs"
|
|
></div>
|
|
|
|
<style>
|
|
html,body,#pdf {
|
|
margin:0;
|
|
width:100%;
|
|
height:100%;
|
|
overflow:hidden;
|
|
background:#000;
|
|
}
|
|
#pdf {
|
|
display:grid;
|
|
place-items:center;
|
|
}
|
|
#pdf canvas {
|
|
grid-area:1/1;
|
|
display:block;
|
|
}
|
|
</style>
|
|
|
|
<script type="module">
|
|
const host=document.querySelector("#pdf");
|
|
const resolve=x=>new URL(x,document.baseURI).href;
|
|
|
|
const P=await import(resolve(host.dataset.lib));
|
|
P.GlobalWorkerOptions.workerSrc=resolve(host.dataset.worker);
|
|
|
|
const pdf=await P.getDocument({
|
|
url:resolve(host.dataset.src),
|
|
useWasm:false
|
|
}).promise;
|
|
|
|
const cache=new Map();
|
|
let currentPage=1;
|
|
let wantedPage=1;
|
|
let requestNumber=0;
|
|
|
|
function renderPage(number) {
|
|
if(cache.has(number)) return cache.get(number);
|
|
|
|
const promise=(async()=>{
|
|
const page=await pdf.getPage(number);
|
|
const original=page.getViewport({scale:1});
|
|
const scale=Math.min(
|
|
innerWidth/original.width,
|
|
innerHeight/original.height
|
|
);
|
|
|
|
// Use 1 on old hardware. Raise to 1.5 for sharper output.
|
|
const pixelRatio=1;
|
|
const viewport=page.getViewport({
|
|
scale:scale*pixelRatio
|
|
});
|
|
|
|
const canvas=document.createElement("canvas");
|
|
canvas.width=Math.ceil(viewport.width);
|
|
canvas.height=Math.ceil(viewport.height);
|
|
canvas.style.width=`${viewport.width/pixelRatio}px`;
|
|
canvas.style.height=`${viewport.height/pixelRatio}px`;
|
|
|
|
const task=page.render({
|
|
canvasContext:canvas.getContext("2d"),
|
|
viewport
|
|
});
|
|
|
|
await task.promise;
|
|
return canvas;
|
|
})().catch(error=>{
|
|
cache.delete(number);
|
|
throw error;
|
|
});
|
|
|
|
cache.set(number,promise);
|
|
return promise;
|
|
}
|
|
|
|
async function show(number) {
|
|
wantedPage=Math.max(1,Math.min(pdf.numPages,number));
|
|
const request=++requestNumber;
|
|
const canvas=await renderPage(wantedPage);
|
|
|
|
// Ignore an obsolete result after multiple fast key presses.
|
|
if(request!==requestNumber) return;
|
|
|
|
// The new canvas is already completely rendered.
|
|
host.replaceChildren(canvas);
|
|
currentPage=wantedPage;
|
|
|
|
pruneCache();
|
|
preloadNeighbours();
|
|
}
|
|
|
|
function preloadNeighbours() {
|
|
const page=currentPage;
|
|
|
|
requestIdleCallback(async()=>{
|
|
if(page+1<=pdf.numPages) {
|
|
await renderPage(page+1);
|
|
}
|
|
if(page-1>=1) {
|
|
await renderPage(page-1);
|
|
}
|
|
},{timeout:250});
|
|
}
|
|
|
|
function pruneCache() {
|
|
const keep=new Set([
|
|
currentPage-1,
|
|
currentPage,
|
|
currentPage+1
|
|
]);
|
|
|
|
for(const [number,promise] of cache) {
|
|
if(keep.has(number)) continue;
|
|
|
|
cache.delete(number);
|
|
promise.then(canvas=>{
|
|
if(!canvas.isConnected) {
|
|
canvas.width=0;
|
|
canvas.height=0;
|
|
}
|
|
}).catch(()=>{});
|
|
}
|
|
}
|
|
|
|
addEventListener("keydown",event=>{
|
|
if(event.key==="ArrowRight") {
|
|
event.preventDefault();
|
|
show(wantedPage+1);
|
|
} else if(event.key==="ArrowLeft") {
|
|
event.preventDefault();
|
|
show(wantedPage-1);
|
|
}
|
|
});
|
|
|
|
addEventListener("resize",()=>{
|
|
cache.clear();
|
|
show(currentPage);
|
|
});
|
|
|
|
window.pdfViewer={
|
|
page:()=>currentPage,
|
|
count:()=>pdf.numPages,
|
|
show
|
|
};
|
|
|
|
await show(1);
|
|
</script>
|
|
}
|
|
}
|
|
|
|
templ startScreenTemplate(splashScreenHtml string, ip string, mac string, qrPath string) {
|
|
@basicTemplate() {
|
|
<div style="width: 100vw; height: 100vh; display: flex; flex-direction: row; justify-content: space-between;">
|
|
<div
|
|
style="display: flex; flex-direction: column; gap: 1rem; justify-content: end; padding: 2rem; font-size: 4rem;"
|
|
>
|
|
{ ip }
|
|
<span style="text-transform: uppercase;">{ mac }</span>
|
|
</div>
|
|
if qrPath != "" {
|
|
<div style="display: flex; justify-content: end; align-items: end; padding: 2rem;">
|
|
<div style="padding: 1rem; background-color: var(--foreground-color); border-radius: 1rem;">
|
|
<img
|
|
style="height: 30vh; width: auto; image-rendering: pixelated; image-rendering: crisp-edges;"
|
|
src={ "file://" + qrPath }
|
|
alt="QR-Code"
|
|
/>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
@templ.Raw(splashScreenHtml)
|
|
<style>
|
|
:root {
|
|
--splash-bg: transparent !important;
|
|
--splash-fade-out-state: paused !important;
|
|
--background-color: oklch(21.6% 0.006 56.043);
|
|
}
|
|
</style>
|
|
}
|
|
}
|