2024-06-29 20:23:56 +02:00
|
|
|
<script lang="ts">
|
2024-07-23 13:42:13 +02:00
|
|
|
import { onMount } from "svelte";
|
2024-07-21 11:42:48 +02:00
|
|
|
|
2024-07-29 10:46:10 +02:00
|
|
|
import type { Optional } from "$lib/types/generic";
|
|
|
|
|
|
|
|
import Skeleton from "$components/misc/Skeleton.svelte";
|
|
|
|
|
2024-06-29 20:23:56 +02:00
|
|
|
export let version: string;
|
2024-07-31 15:28:48 +02:00
|
|
|
export let title: string = "";
|
|
|
|
export let date: string = "";
|
|
|
|
export let banner: Optional<{ file: string; alt: string }> = undefined;
|
|
|
|
export let skeleton = false;
|
2024-07-17 11:07:25 +02:00
|
|
|
|
2024-07-21 11:42:48 +02:00
|
|
|
let bannerLoaded = false;
|
|
|
|
|
2024-07-17 11:07:25 +02:00
|
|
|
const formatDate = (dateString: string) => {
|
|
|
|
const date = new Date(dateString);
|
2024-07-31 15:28:48 +02:00
|
|
|
const months = ["January", "February", "March", "April", "May",
|
|
|
|
"June", "July", "August", "September", "October",
|
|
|
|
"November", "December"];
|
2024-07-17 11:07:25 +02:00
|
|
|
|
|
|
|
return [
|
2024-09-09 22:35:12 +02:00
|
|
|
months[date.getMonth()],
|
|
|
|
date.getDate() + ",",
|
|
|
|
date.getFullYear(),
|
2024-07-31 15:28:48 +02:00
|
|
|
].join(" ");
|
|
|
|
};
|
2024-07-23 13:42:13 +02:00
|
|
|
|
|
|
|
onMount(() => {
|
|
|
|
const to_focus: HTMLElement | null =
|
|
|
|
document.querySelector("[data-first-focus]");
|
|
|
|
to_focus?.focus();
|
|
|
|
});
|
2024-06-29 20:23:56 +02:00
|
|
|
</script>
|
2024-07-17 09:32:07 +02:00
|
|
|
|
2024-07-29 10:46:10 +02:00
|
|
|
<main id="changelog-parent">
|
2024-07-31 15:28:48 +02:00
|
|
|
<div id="changelog-header" class:no-padding={!banner && !skeleton}>
|
2024-07-17 10:04:53 +02:00
|
|
|
<div class="changelog-info">
|
2024-07-23 14:18:18 +02:00
|
|
|
<div
|
|
|
|
class="changelog-version"
|
|
|
|
data-first-focus
|
|
|
|
data-focus-ring-hidden
|
|
|
|
tabindex="-1"
|
2024-07-31 15:28:48 +02:00
|
|
|
>
|
|
|
|
{version}
|
|
|
|
</div>
|
|
|
|
<div class="changelog-date">
|
|
|
|
{#if skeleton}
|
|
|
|
<Skeleton width="8em" height="16px" />
|
|
|
|
{:else}
|
|
|
|
{formatDate(date)}
|
|
|
|
{/if}
|
|
|
|
</div>
|
2024-07-17 10:04:53 +02:00
|
|
|
</div>
|
2024-07-31 15:28:48 +02:00
|
|
|
{#if skeleton}
|
|
|
|
<Skeleton width="100%" height="27.59px" />
|
|
|
|
{:else}
|
|
|
|
<h1 class="changelog-title">{title}</h1>
|
|
|
|
{/if}
|
2024-07-17 10:04:53 +02:00
|
|
|
</div>
|
2024-07-17 09:32:07 +02:00
|
|
|
<div class="changelog-content">
|
|
|
|
{#if banner}
|
|
|
|
<img
|
|
|
|
src={`/update-banners/${banner.file}`}
|
|
|
|
alt={banner.alt}
|
2024-07-21 11:42:48 +02:00
|
|
|
class:loading={!bannerLoaded}
|
|
|
|
on:load={() => bannerLoaded = true}
|
2024-07-17 09:32:07 +02:00
|
|
|
class="changelog-banner"
|
|
|
|
/>
|
2024-07-21 11:42:48 +02:00
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
<Skeleton class="big changelog-banner" hidden={bannerLoaded} />
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
{#if skeleton}
|
|
|
|
<Skeleton class="big changelog-banner" width="100%" />
|
2024-07-17 09:32:07 +02:00
|
|
|
{/if}
|
2024-08-06 10:29:15 +02:00
|
|
|
<div class="changelog-body long-text-noto">
|
2024-07-31 15:28:48 +02:00
|
|
|
{#if skeleton}
|
|
|
|
{#each { length: 3 + Math.random() * 5 } as _}
|
|
|
|
<p>
|
|
|
|
<Skeleton
|
|
|
|
width="100%"
|
|
|
|
height={Math.random() * 84 + 16 + "px"}
|
|
|
|
/>
|
|
|
|
</p>
|
|
|
|
{/each}
|
|
|
|
{:else}
|
|
|
|
<slot></slot>
|
|
|
|
{/if}
|
2024-07-17 09:32:07 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</main>
|
|
|
|
|
2024-07-29 10:46:10 +02:00
|
|
|
<style>
|
2024-07-31 15:28:48 +02:00
|
|
|
#changelog-parent {
|
2024-07-29 10:46:10 +02:00
|
|
|
overflow-x: hidden;
|
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
#changelog-header {
|
2024-07-29 10:46:10 +02:00
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
align-items: start;
|
|
|
|
gap: calc(var(--padding) / 2);
|
|
|
|
padding-bottom: 1em; /* match default <p> padding */
|
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
#changelog-header.no-padding {
|
2024-07-29 10:46:10 +02:00
|
|
|
padding-bottom: 0;
|
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
.changelog-info {
|
2024-07-29 10:46:10 +02:00
|
|
|
display: flex;
|
|
|
|
flex-direction: row;
|
|
|
|
align-items: center;
|
|
|
|
gap: 14px;
|
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
.changelog-version {
|
2024-07-29 10:46:10 +02:00
|
|
|
padding: 3px 8px;
|
|
|
|
border-radius: 6px;
|
|
|
|
background-color: var(--secondary);
|
|
|
|
color: var(--primary);
|
|
|
|
font-size: 18px;
|
|
|
|
font-weight: 500;
|
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
.changelog-date {
|
2024-07-29 10:46:10 +02:00
|
|
|
font-size: 13px;
|
|
|
|
font-weight: 500;
|
|
|
|
color: var(--gray);
|
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
.changelog-title {
|
2024-07-29 10:46:10 +02:00
|
|
|
padding: 0;
|
|
|
|
line-height: 1.2;
|
|
|
|
font-size: 23px;
|
|
|
|
user-select: text;
|
2024-07-31 15:28:48 +02:00
|
|
|
-webkit-user-select: text;
|
2024-07-29 10:46:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
:global(.changelog-banner) {
|
|
|
|
display: block;
|
|
|
|
object-fit: cover;
|
|
|
|
max-height: 320pt;
|
|
|
|
min-height: 210pt;
|
|
|
|
width: 100%;
|
|
|
|
aspect-ratio: 16/9;
|
|
|
|
border-radius: var(--padding);
|
2024-10-01 17:15:57 +02:00
|
|
|
pointer-events: all;
|
2024-07-29 10:46:10 +02:00
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
.changelog-banner.loading {
|
2024-07-29 10:46:10 +02:00
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
.changelog-content {
|
2024-07-29 10:46:10 +02:00
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
align-items: center;
|
|
|
|
}
|
|
|
|
|
2024-07-31 15:28:48 +02:00
|
|
|
.changelog-body {
|
2024-07-29 10:46:10 +02:00
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
</style>
|