cobalt/web/src/components/changelog/ChangelogEntry.svelte

166 lines
4.2 KiB
Svelte
Raw Normal View History

2024-06-29 20:23:56 +02:00
<script lang="ts">
import { onMount } from "svelte";
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;
export let title: string = "";
export let date: string = "";
export let banner: Optional<{ file: string; alt: string }> = undefined;
export let skeleton = false;
let bannerLoaded = false;
const formatDate = (dateString: string) => {
const date = new Date(dateString);
const months = ["January", "February", "March", "April", "May",
"June", "July", "August", "September", "October",
"November", "December"];
return [
months[date.getMonth()],
date.getDate() + ",",
date.getFullYear(),
].join(" ");
};
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">
<div id="changelog-header" class:no-padding={!banner && !skeleton}>
<div class="changelog-info">
<div
class="changelog-version"
data-first-focus
data-focus-ring-hidden
tabindex="-1"
>
{version}
</div>
<div class="changelog-date">
{#if skeleton}
<Skeleton width="8em" height="16px" />
{:else}
{formatDate(date)}
{/if}
</div>
</div>
{#if skeleton}
<Skeleton width="100%" height="27.59px" />
{:else}
<h1 class="changelog-title">{title}</h1>
{/if}
</div>
2024-07-17 09:32:07 +02:00
<div class="changelog-content">
{#if banner}
<img
src={`/update-banners/${banner.file}`}
alt={banner.alt}
class:loading={!bannerLoaded}
on:load={() => bannerLoaded = true}
2024-07-17 09:32:07 +02:00
class="changelog-banner"
/>
<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}
<div class="changelog-body long-text-noto">
{#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>
#changelog-parent {
2024-07-29 10:46:10 +02:00
overflow-x: hidden;
}
#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 */
}
#changelog-header.no-padding {
2024-07-29 10:46:10 +02:00
padding-bottom: 0;
}
.changelog-info {
2024-07-29 10:46:10 +02:00
display: flex;
flex-direction: row;
align-items: center;
gap: 14px;
}
.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;
}
.changelog-date {
2024-07-29 10:46:10 +02:00
font-size: 13px;
font-weight: 500;
color: var(--gray);
}
.changelog-title {
2024-07-29 10:46:10 +02:00
padding: 0;
line-height: 1.2;
font-size: 23px;
user-select: text;
-webkit-user-select: text;
2024-07-29 10:46:10 +02:00
}
:global(.changelog-banner) {
display: block;
object-fit: cover;
max-height: 350pt;
min-height: 180pt;
2024-07-29 10:46:10 +02:00
width: 100%;
aspect-ratio: 16/9;
border-radius: var(--padding);
pointer-events: all;
2024-07-29 10:46:10 +02:00
}
.changelog-banner.loading {
2024-07-29 10:46:10 +02:00
display: none;
}
.changelog-content {
2024-07-29 10:46:10 +02:00
display: flex;
flex-direction: column;
align-items: center;
}
.changelog-body {
2024-07-29 10:46:10 +02:00
width: 100%;
}
</style>