|
1 | 1 | <script lang="ts"> |
2 | 2 | import { page } from "$app/state" |
| 3 | + import Carousel from "$lib/components/Carousel.svelte" |
| 4 | + import Dice3D from "$lib/components/Dice3D.svelte" |
3 | 5 | import { generateRandomSequence } from "$lib/dice" |
| 6 | + import { locale } from "$lib/stores/locale" |
4 | 7 | import emblaCarouselSvelte from "embla-carousel-svelte" |
5 | | - import Dice3D from "$lib/components/Dice3D.svelte" |
6 | | -
|
7 | | - import Carousel from "$lib/components/Carousel.svelte" |
8 | 8 | import { onMount } from "svelte" |
| 9 | + import { fade } from "svelte/transition" |
9 | 10 |
|
10 | 11 | emblaCarouselSvelte.globalOptions = { |
11 | 12 | loop: true, |
|
15 | 16 | let sequence: number[] = $state([]) |
16 | 17 | let isRolling = $state(false) |
17 | 18 |
|
| 19 | + function toggleLanguage() { |
| 20 | + $locale = $locale === "de" ? "en" : "de" |
| 21 | + } |
| 22 | +
|
18 | 23 | // On change to isRolling, set a new sequence |
19 | 24 | $effect(() => { |
20 | 25 | if (isRolling) { |
|
40 | 45 | history.pushState("", document.title, window.location.pathname + window.location.search) |
41 | 46 | return hashSequence |
42 | 47 | } |
| 48 | +
|
| 49 | + // Track scroll position |
| 50 | + let scrollY = $state(0) |
| 51 | + let innerHeight = $state(0) |
| 52 | + let showBackToTop = $derived(scrollY > innerHeight) |
| 53 | +
|
43 | 54 | onMount(() => { |
44 | 55 | sequence = initialiseSequence() |
45 | 56 | }) |
| 57 | +
|
| 58 | + // Add function to scroll back to top |
| 59 | + function scrollToTop() { |
| 60 | + window.scrollTo({ |
| 61 | + top: 0, |
| 62 | + behavior: "smooth" |
| 63 | + }) |
| 64 | + } |
| 65 | +
|
| 66 | + // Reference to the main element |
| 67 | + let mainElement: HTMLElement |
| 68 | +
|
| 69 | + // Add function to scroll to main content |
| 70 | + function scrollToMain() { |
| 71 | + mainElement?.scrollIntoView({ |
| 72 | + behavior: "smooth" |
| 73 | + }) |
| 74 | + } |
46 | 75 | </script> |
47 | 76 |
|
48 | | -<!-- Center column backdrop --> |
49 | | -<div |
50 | | - class="absolute inset-0 top-4 bottom-4 left-1/2 z-[-1] w-md -translate-x-1/2 border-4 border-sky-800 bg-amber-50" |
51 | | -></div> |
| 77 | +<svelte:window bind:scrollY bind:innerHeight /> |
| 78 | + |
| 79 | +<header class="h-screen w-full p-4 md:p-16"> |
| 80 | + <div |
| 81 | + class="relative flex h-full w-full flex-col items-center justify-evenly bg-sky-800 px-8 text-center text-amber-50 ring-4 ring-sky-800 ring-offset-4 ring-offset-amber-50" |
| 82 | + > |
| 83 | + <!-- Language toggle button --> |
| 84 | + <button |
| 85 | + class="relative flex h-26 w-26 cursor-pointer items-center justify-center rounded-full bg-amber-50 text-4xl text-sky-800 uppercase hover:bg-amber-100 focus:outline-none" |
| 86 | + onclick={toggleLanguage} |
| 87 | + aria-label={$locale === "de" ? "Sprache umschalten" : "Toggle language"} |
| 88 | + > |
| 89 | + {$locale} |
| 90 | + </button> |
| 91 | + |
| 92 | + {#if $locale === "de"} |
| 93 | + <div lang="de" class="max-w-[75ch]"> |
| 94 | + <h1 class="text-3xl md:text-6xl">Ein Dramenautomat von 1829 digital aufbereitet</h1> |
| 95 | + <p class="pt-8 md:text-xl"> |
| 96 | + Der 1829 von Georg Nikolaus Bärmann veröffentlichte <a |
| 97 | + class="underline" |
| 98 | + target="_blank" |
| 99 | + href="https://de.wikisource.org/wiki/Neunhundert_neun_und_neunzig_und_noch_etliche_Almanachs-Lustspiele_durch_den_W%C3%BCrfel" |
| 100 | + ><em>Würfelalmanach</em></a |
| 101 | + > |
| 102 | + ist ein spielerisches System zur Erzeugung von Einaktern per Würfelwurf. Diese kurzen Dramen |
| 103 | + waren auf der Bühne und im privaten Kreis beliebt, und Bärmanns Buch ermöglichte die Erstellung |
| 104 | + von 4×10<sup>155</sup> Variationen aus 1.200 Textfragmenten. Diese Webanwendung bringt den |
| 105 | + Almanach in digitaler Form zurück und lädt dazu ein, eine frühe Form algorithmischen Erzählens |
| 106 | + interaktiv zu erkunden. |
| 107 | + </p> |
| 108 | + </div> |
| 109 | + {:else} |
| 110 | + <div lang="en" class="max-w-[75ch]"> |
| 111 | + <h1 class="text-3xl md:text-6xl">A literary automaton from 1829, reborn online</h1> |
| 112 | + <p class="pt-8 md:text-xl"> |
| 113 | + The <a |
| 114 | + class="underline" |
| 115 | + target="_blank" |
| 116 | + href="https://de.wikisource.org/wiki/Neunhundert_neun_und_neunzig_und_noch_etliche_Almanachs-Lustspiele_durch_den_W%C3%BCrfel" |
| 117 | + ><em>Würfelalmanach</em></a |
| 118 | + >, published by Georg Nikolaus Bärmann in 1829, is a playful system for generating one-act |
| 119 | + plays by rolling dice. These short dramas were popular on stage and in private gatherings, |
| 120 | + and Bärmann's book offered a way to create 4×10<sup>155</sup> possible variations from 1,200 |
| 121 | + text fragments. This web app recreates the experience, letting you explore an early example |
| 122 | + of algorithmic storytelling in an interactive way. |
| 123 | + </p> |
| 124 | + </div> |
| 125 | + {/if} |
| 126 | + |
| 127 | + <!-- Scroll to main button --> |
| 128 | + <button |
| 129 | + onclick={scrollToMain} |
| 130 | + class="pulse-animation flex h-26 w-26 cursor-pointer items-center justify-center rounded-full bg-amber-50 text-2xl text-sky-800 transition-colors hover:bg-amber-100 focus:outline-none" |
| 131 | + aria-label="Scroll to content" |
| 132 | + > |
| 133 | + START |
| 134 | + </button> |
| 135 | + </div> |
| 136 | +</header> |
| 137 | + |
| 138 | +<main class="overflow-x-hidden p-4" bind:this={mainElement}> |
| 139 | + <!-- Center column backdrop --> |
| 140 | + <div |
| 141 | + class="absolute inset-0 bottom-4 left-1/2 z-[-1] w-[430px] -translate-x-1/2 border-4 border-sky-800 bg-amber-50" |
| 142 | + style="top: calc(100vh + 2em);" |
| 143 | + ></div> |
52 | 144 |
|
53 | | -<header class="mx-auto flex w-md flex-col items-center"> |
54 | | - <h1 class="m-4 pt-10 text-center text-2xl font-bold"> |
| 145 | + <h2 class="m-4 pt-10 text-center text-2xl font-bold"> |
55 | 146 | Neunhundert neun und neunzig <br /> <small>und noch etliche</small> <br /> Almanachs-Lustspiele |
56 | 147 | <br /> <small>durch den Würfel</small> |
57 | | - </h1> |
| 148 | + </h2> |
58 | 149 |
|
59 | | - <div class="flex justify-center" title="Würfeln"> |
60 | | - <div class="m-5 flex items-center justify-center rounded-full bg-sky-800 p-3" title="Würfeln"> |
| 150 | + <div class="flex justify-center"> |
| 151 | + <div class="m-5 flex items-center justify-center rounded-full bg-sky-800 p-3"> |
61 | 152 | <Dice3D bind:isRolling /> |
62 | 153 | </div> |
63 | 154 | </div> |
64 | | -</header> |
65 | | - |
66 | | -<main class="p-4"> |
67 | 155 | <!-- Display all six versions side by side --> |
68 | | - <div class="versions flex flex-col gap-10"> |
| 156 | + <div class="versions flex flex-col gap-10" lang="de"> |
69 | 157 | {#each Array.from(new Array(200), (_x, i) => i + 1) as index} |
70 | 158 | <div class="flex flex-col items-center"> |
71 | 159 | <h2 class="text-center text-xl font-bold" id={index.toString()}>{index}</h2> |
|
79 | 167 | {/each} |
80 | 168 | </div> |
81 | 169 | </main> |
| 170 | + |
| 171 | +<!-- Back to top button with conditional visibility --> |
| 172 | +{#if showBackToTop} |
| 173 | + <button |
| 174 | + onclick={scrollToTop} |
| 175 | + transition:fade={{ duration: 300 }} |
| 176 | + class="fixed right-6 bottom-6 flex h-18 w-18 cursor-pointer items-center justify-center rounded-full bg-sky-800 text-white shadow-lg transition-all hover:bg-sky-700 focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 focus:outline-none" |
| 177 | + aria-label={$locale === "de" ? "Zurück nach oben" : "Back to top"} |
| 178 | + title={$locale === "de" ? "Zurück nach oben" : "Back to top"} |
| 179 | + > |
| 180 | + <svg |
| 181 | + xmlns="http://www.w3.org/2000/svg" |
| 182 | + class="h-6 w-6" |
| 183 | + fill="none" |
| 184 | + viewBox="0 0 24 24" |
| 185 | + stroke="currentColor" |
| 186 | + > |
| 187 | + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" /> |
| 188 | + </svg> |
| 189 | + </button> |
| 190 | +{/if} |
| 191 | + |
| 192 | +<style> |
| 193 | + @keyframes pulse { |
| 194 | + 0% { |
| 195 | + transform: scale(1); |
| 196 | + } |
| 197 | +
|
| 198 | + 70% { |
| 199 | + transform: scale(1.11); |
| 200 | + } |
| 201 | +
|
| 202 | + 100% { |
| 203 | + transform: scale(1); |
| 204 | + } |
| 205 | + } |
| 206 | +
|
| 207 | + .pulse-animation { |
| 208 | + animation: pulse 2s infinite; |
| 209 | + } |
| 210 | +</style> |
0 commit comments