Consolidate and upload changes from recent work

This commit is contained in:
aronmal 2023-12-08 17:52:06 +01:00
parent 05a69bf274
commit da2e46aab2
Signed by: aronmal
GPG key ID: 816B7707426FC612
20 changed files with 1844 additions and 1566 deletions

200
src/components/Asset.tsx Normal file
View file

@ -0,0 +1,200 @@
import {
faMagnifyingGlassMinus,
faMagnifyingGlassPlus,
faSlidersSimple,
faVolume,
faVolumeSlash,
faXmark,
} from "@fortawesome/pro-regular-svg-icons";
import {
Match,
Setter,
Show,
Switch,
createEffect,
createSignal,
} from "solid-js";
import { FontAwesomeIcon } from "./FontAwesomeIcon";
interface Asset {
src: string;
}
function AssetHandler() {
const [moving, setMoving] = createSignal(false);
const [active, setActive] = createSignal("");
const [zoomLevel, setZoomLevel] = createSignal(0);
const zoomAmount = () => 1 + zoomLevel() * 0.5;
const [x, setX] = createSignal(0);
const [y, setY] = createSignal(0);
function FullscreenView() {
const [muted, setMuted] = createSignal(true);
const [controlls, setControlls] = createSignal(false);
const [clientX, setClientX] = createSignal(0);
const [clientY, setClientY] = createSignal(0);
const [ref, setRef] = createSignal<HTMLElement | null>(null);
const handleMouseMove = (event: MouseEvent) => {
const { clientX, clientY } = event;
setClientX(clientX);
setClientY(clientY);
};
createEffect(() => {
const thisRef = ref();
if (!thisRef) return;
const rectA = thisRef.getBoundingClientRect();
const origSizeW = rectA.width / zoomAmount();
const origSizeH = rectA.height / zoomAmount();
const rectW = wrapperRef.getBoundingClientRect();
const hori = rectW.width - origSizeW + origSizeW / zoomAmount();
const verti = rectW.height - origSizeH + origSizeH / zoomAmount();
const xP = (clientX() - hori / 2) / (rectW.width - hori);
const yP = (clientY() - verti / 2) / (rectW.height - verti);
setX((xP > 0 ? (xP < 1 ? xP : 1) : 0) * origSizeW);
setY((yP > 0 ? (yP < 1 ? yP : 1) : 0) * origSizeH);
const moving =
clientX() > (rectW.width - origSizeW) / 2 &&
clientX() < rectW.width - (rectW.width - origSizeW) / 2 &&
clientY() > (rectW.height - origSizeH) / 2 &&
clientY() < rectW.height - (rectW.height - origSizeH) / 2;
setMoving(moving);
});
let wrapperRef: HTMLDivElement;
createEffect(() => {
if (active()) return;
setZoomLevel(0);
setMuted(true);
setControlls(false);
});
return (
<div
ref={wrapperRef!}
onMouseMove={handleMouseMove}
classList={{ "fullscreen-asset": true, active: !!active() }}
>
<Asset
src={active()}
volume={!muted()}
controlls={controlls()}
setRef={setRef}
/>
<div class="controlls">
<button onClick={() => setActive("")} title="Close">
<FontAwesomeIcon icon={faXmark} />
</button>
<Show when={active().startsWith("/videos")}>
<button
onClick={() => setMuted((e) => !e)}
style={{ "border-style": controlls() ? "dashed" : "" }}
title={muted() ? "Unmute" : "Mute"}
>
<FontAwesomeIcon icon={!muted() ? faVolume : faVolumeSlash} />
</button>
<button
onClick={() => setControlls((e) => !e)}
style={{ "border-style": controlls() ? "inset" : "" }}
title="Show controlls"
>
<FontAwesomeIcon icon={faSlidersSimple} />
</button>
</Show>
<button
onClick={() => setZoomLevel((e) => e + 1)}
disabled={zoomLevel() === 4}
title="Zoom +"
>
<FontAwesomeIcon icon={faMagnifyingGlassPlus} />
</button>
<button
onClick={() => setZoomLevel((e) => e - 1)}
disabled={zoomLevel() === 0}
title="Zoom -"
>
<FontAwesomeIcon icon={faMagnifyingGlassMinus} />
</button>
</div>
</div>
);
}
function Asset(
props: Asset & {
class?: string;
volume?: boolean;
controlls?: boolean;
setRef?: Setter<HTMLElement | null>;
},
) {
let imgRef: HTMLImageElement;
let videoRef: HTMLVideoElement;
const shouldZoom = () => active() === props.src && !!zoomLevel();
return (
<Switch>
<Match when={props.src.startsWith("/images")}>
<img
ref={imgRef!}
style={
shouldZoom()
? {
"--zoom": zoomAmount(),
"--x": x() + "px",
"--y": y() + "px",
}
: {}
}
onMouseEnter={() => props.setRef && props.setRef(imgRef)}
classList={{
[props.class ?? ""]: !!props.class,
zoomed: shouldZoom(),
move: moving(),
}}
onClick={() => setActive(props.src)}
src={props.src}
alt={props.src}
/>
</Match>
<Match when={props.src.startsWith("/videos")}>
<video
ref={videoRef!}
onMouseEnter={() => props.setRef && props.setRef(videoRef)}
style={
shouldZoom()
? {
"--zoom": zoomAmount(),
"--x": x() + "px",
"--y": y() + "px",
}
: {}
}
classList={{
[props.class ?? ""]: !!props.class,
zoomed: shouldZoom(),
move: moving(),
active: !props.setRef && active() === props.src,
}}
onClick={() => setActive(props.src)}
width="auto"
height="auto"
autoplay
muted={!props.volume}
loop
controls={props.controlls}
>
<source src={props.src} type="video/mp4" />
</video>
</Match>
</Switch>
);
}
return { FullscreenView, Asset };
}
export default AssetHandler;

View file

@ -4,17 +4,15 @@ import { A } from "solid-start";
function DeviceTile(props: { href?: string; name: string; src: string }) {
return (
<A href={props.href ?? "/soon"}>
<div class="raster">
<h3>{props.name}</h3>
<Show when={props.src.startsWith("/images")}>
<img src={props.src} alt={props.name} />
</Show>
<Show when={props.src.startsWith("/videos")}>
<video width="auto" height="auto" autoplay muted loop>
<source src={props.src} type="video/mp4" />
</video>
</Show>
</div>
<h3>{props.name}</h3>
<Show when={props.src.startsWith("/images")}>
<img src={props.src} alt={props.name} />
</Show>
<Show when={props.src.startsWith("/videos")}>
<video width="auto" height="auto" autoplay muted loop>
<source src={props.src} type="video/mp4" />
</video>
</Show>
</A>
);
}

View file

@ -43,7 +43,7 @@ function R(props: {
target={type() === "external" ? "_blank" : ""}
rel={type() === "external" ? "noreferrer noopener" : ""}
id={props.id}
class={props.class}
classList={{ reference: true, [props.class ?? ""]: !!props.class }}
>
<Show when={type() === "id"}>
<FontAwesomeIcon class="left" icon={types["id"]} />

View file

@ -1,6 +1,8 @@
import {
faBars,
faBookOpen,
faCircleHalfStroke,
faGavel,
faGlobe,
faXmark,
} from "@fortawesome/pro-regular-svg-icons";
@ -75,7 +77,7 @@ function Navbar() {
<A href="/de/overview#historie">Historie</A>
</li>
<li>
<A href="/de/overview#geräte">Geräte Liste</A>
<A href="/de/overview#geraete">Geräte Liste</A>
</li>
</ol>
@ -83,6 +85,10 @@ function Navbar() {
<FontAwesomeIcon icon={faBookOpen} /> Hersteller
</A>
<A href="/de/imprint">
<FontAwesomeIcon icon={faGavel} /> Impressum
</A>
<button onClick={() => setLightMode((e) => !e)}>
{lightMode() ? "Dark Mode " : "Light Mode "}
<FontAwesomeIcon icon={faCircleHalfStroke} />
@ -99,14 +105,9 @@ function Navbar() {
</button>
</div>
<div
id="sidenavbar"
style={{ visibility: menu() ? "hidden" : "visible" }}
>
<button onClick={() => navigate(-1)}>Zurück</button>
<button onClick={() => navigate("/de/overview")}>Start</button>
<button onClick={() => setMenu(true)}>Menu</button>
</div>
<button class="menu" title="Menu" onClick={() => setMenu(true)}>
<FontAwesomeIcon icon={faBars} />
</button>
</>
);
}

View file

@ -1,6 +1,8 @@
import {
faBars,
faBookOpen,
faCircleHalfStroke,
faGavel,
faGlobe,
faXmark,
} from "@fortawesome/pro-regular-svg-icons";
@ -75,7 +77,7 @@ function Navbar() {
<A href="/en/overview#historie">History</A>
</li>
<li>
<A href="/en/overview#geräte">Device list</A>
<A href="/en/overview#geraete">Device list</A>
</li>
</ol>
@ -83,6 +85,10 @@ function Navbar() {
<FontAwesomeIcon icon={faBookOpen} /> Manufacturers
</A>
<A href="/de/imprint">
<FontAwesomeIcon icon={faGavel} /> Legal Notice (DE)
</A>
<button onClick={() => setLightMode((e) => !e)}>
{lightMode() ? "Dark Mode " : "Light Mode "}
<FontAwesomeIcon icon={faCircleHalfStroke} />
@ -99,14 +105,9 @@ function Navbar() {
</button>
</div>
<div
id="sidenavbar"
style={{ visibility: menu() ? "hidden" : "visible" }}
>
<button onClick={() => navigate(-1)}>Back</button>
<button onClick={() => navigate("/en/overview")}>Start</button>
<button onClick={() => setMenu(true)}>Menu</button>
</div>
<button class="menu" title="Menu" onClick={() => setMenu(true)}>
<FontAwesomeIcon icon={faBars} />
</button>
</>
);
}