Timeline styling

This commit is contained in:
Ruben van de Ven 2024-06-22 15:15:17 +02:00
parent f8a506bb77
commit 1590fa5615
3 changed files with 147 additions and 20 deletions

View file

@ -1,6 +1,7 @@
<script lang="ts">
import parsed_transits from "/data/parsed_transits.json";
import { draw, slide, fade } from "svelte/transition";
import { draw, slide, fade, scale } from "svelte/transition";
import typewriter from "./lib/typewriter";
import { fps } from "@sveu/browser";
import LibrariesSvg from "./LibrariesSvg.svelte";
@ -261,30 +262,51 @@
<!-- {#if currentScene?.rendered_elements.indexOf("timeline") >= 0} -->
<div id="timeline">
{#if $current_item}
<div id="current">
<h2>{$current_item.title}</h2>
</div>
{/if}
<div id="events">
{#each $events as e}
<div class="entry" in:slide={{ duration: 200 }}>
<!-- {m['Title (Complete)']} -->
<span class="date"
>{e.date.toLocaleDateString("en-UK", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
})}</span
>
<div class="text">
<span class="title">{e.title}</span>
<span class="description">{e.description}</span>
<span class="date" in:typewriter={{ delay: 1000, speed: 10 }}>
<h3>
{e.date.toLocaleDateString("en-UK", {
year: "numeric",
month: "long",
day: "numeric",
})}
</h3>
<span class="weekday">
{e.date.toLocaleDateString("en-UK", {
weekday: "long",
})}
</span>
<span class="time">
{e.date.toLocaleTimeString("en-UK", {
hour: "numeric",
minute: "numeric",
})}
</span>
</span>
<div class="divider">
<div
class="dot"
in:scale={{ delay: 500, duration: 600 }}
></div>
<div class="connector"><!-- transition in css: --></div>
</div>
<div class="text" in:typewriter={{ delay: 1500, speed: 10 }}>
<h3>{e.title}</h3>
<p>{e.description}</p>
</div>
</div>
{/each}
</div>
{#if $current_item}
<div id="current">
<h2>{$current_item.title}</h2>
<p>{[$current_item.Date, $current_item.Publisher, $current_item.Place].filter((e) => e).join(', ')}</p>
</div>
{/if}
</div>
<!-- {/if} -->
@ -303,6 +325,58 @@
position: absolute;
bottom: 20px;
left: 20px;
#events{
position: relative;
// max-height: 200px;
}
.entry {
display: flex;
flex-direction: row;
.date {
width: 180px;
}
.divider {
display: flex;
flex-direction: column;
--divider-width: 15px;
--connector-width: 2px;
margin-right: 10px;
transform: translateY(calc(20px));
.dot {
height: var(--divider-width);
width: var(--divider-width);
background-color: rgb(79 70 229);
border-radius: calc(var(--divider-width) / 2);
// border: solid 5px black;
flex-grow: 0;
}
.connector {
flex-grow: 1;
border-left: solid var(--connector-width) rgb(203 213 225);
transition: flex-grow 1s ease-in-out;
margin-top: 5px;
margin-bottom: 5px;
margin-left: calc(
(var(--divider-width) - var(--connector-width)) / 2
);
}
}
&:last-child .divider .connector {
flex-grow: 0;
height: 0;
}
.text {
h3 {
}
p {
}
}
}
}
#fps {
position: absolute;
@ -355,7 +429,4 @@
opacity: 0;
} */
#events {
max-height: 50px;
}
</style>

View file

@ -22,6 +22,7 @@ export type Item = {
_original: Object
}
export function importItem(orig: Object, locations: Map<string, Location>): Item {
// Barcode
// Request Date

55
src/lib/typewriter.js Normal file
View file

@ -0,0 +1,55 @@
// Written by Weiming Wu
// https://weimingwu.medium.com/a-better-typewriter-transition-in-svelte-528e9610ec2e
export default function typewriter(node, { delay = 0, speed = 50 }) {
const textNodes = getAllTextNodes(node);
if (!textNodes.length) {
throw new Error(`This transition only works on elements with text nodes`);
}
let totalLength = 0;
const ranges = textNodes.map(textNode => {
const range = [totalLength, totalLength + textNode.textContent.length];
totalLength += textNode.textContent.length;
const text = textNode.textContent;
textNode.textContent = '';
return { textNode, range, text };
});
let currentRangeIndex = 0;
function getCurrentRange(i) {
while (ranges[currentRangeIndex].range[1] < i && currentRangeIndex < ranges.length) {
const { textNode, text } = ranges[currentRangeIndex];
textNode.textContent = text; // finish typing up the last node
currentRangeIndex++;
}
return ranges[currentRangeIndex];
}
const duration = totalLength * speed;
return {
delay,
duration,
tick: t => {
const progress = ~~(totalLength * t);
const { textNode, range, text } = getCurrentRange(progress);
const [start, end] = range;
const textLength = ((progress - start) / (end - start)) * text.length;
textNode.textContent = text.slice(0, textLength);
},
};
}
function getAllTextNodes(node) {
if (node.nodeType === 3) {
return [node];
} else if (node.hasChildNodes()) {
let list = [];
for (let child of node.childNodes) {
getAllTextNodes(child).forEach(textNode => list.push(textNode));
}
return list;
}
return [];
}