css: consolidate stylesheets into single source of truth

Merge nordtheme.css tokens and utility classes into app.css, import
app.css once in root layout, delete redundant files (nordtheme.css,
form.css, rosenkranz.css), move domain CSS to layouts, fix broken
shake keyframe in action_button.css, and scope form styles to the
two pages that need them. 10 CSS files → 6, 41 redundant imports removed.
This commit is contained in:
2026-02-15 22:26:22 +01:00
parent 0a13df19f5
commit e38879d8be
47 changed files with 209 additions and 553 deletions
+124 -50
View File
@@ -109,6 +109,35 @@
--color-warning: var(--nord13);
--color-error: var(--nord11);
--color-info: var(--nord10);
/* Shared transitions & shadows */
--transition-fast: 100ms;
--transition-normal: 200ms;
--shadow-sm: 0 0 0.4em 0.05em rgba(0,0,0,0.2);
--shadow-md: 0 0 0.5em 0.1em rgba(0,0,0,0.3);
--shadow-lg: 0 0 1em 0.1em rgba(0,0,0,0.4);
--shadow-hover: 0.1em 0.1em 0.5em 0.1em rgba(0,0,0,0.3);
--radius-pill: 1000px;
--radius-card: 20px;
--radius-sm: 0.3rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
/* Spacing scale */
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 1.5rem;
--space-xl: 2rem;
--space-2xl: 3rem;
/* Font size scale */
--text-sm: 0.85rem;
--text-base: 1rem;
--text-lg: 1.1rem;
--text-xl: 1.5rem;
--text-2xl: 2rem;
--text-3xl: 3rem;
}
/* ============================================
@@ -208,65 +237,110 @@ a:focus-visible {
color: var(--color-link-hover);
}
/* ============================================
FORM STYLES
GLOBAL UTILITY CLASSES
============================================ */
form {
background-color: var(--color-bg-secondary);
display: flex;
flex-direction: column;
max-width: 600px;
gap: 0.5em;
margin-inline: auto;
justify-content: center;
align-items: center;
padding-block: 2rem;
margin-block: 2rem;
}
form label {
font-size: 1.2em;
}
form input {
display: block;
font-size: 1.2rem;
}
form:not(.search) button {
background-color: var(--color-accent);
color: var(--color-text-on-accent);
/* Pill-shaped element base */
.g-pill {
border-radius: var(--radius-pill);
border: none;
padding: 0.5em 1em;
font-size: 1.3em;
border-radius: 1000px;
margin-top: 1em;
transition: 100ms;
cursor: pointer;
display: inline-block;
text-decoration: none;
transition: var(--transition-fast);
}
form:not(.search) button:hover,
form:not(.search) button:focus-visible {
background-color: var(--color-accent-hover);
scale: 1.1;
/* Interactive hover/focus effects */
.g-interactive {
transition: var(--transition-fast);
}
.g-interactive:hover,
.g-interactive:focus-visible {
transform: scale(1.05);
box-shadow: var(--shadow-hover);
}
.g-interactive:focus {
scale: 0.9;
}
form:not(.search) button:active {
background-color: var(--color-accent-active);
/* Light background button (with dark mode) */
.g-btn-light {
background-color: var(--nord5);
color: var(--nord0);
box-shadow: var(--shadow-sm);
}
form p {
max-width: 400px;
margin-top: 0;
}
form h4 {
margin-bottom: 0;
}
@media screen and (max-width: 600px) {
form {
margin-top: 0;
@media (prefers-color-scheme: dark) {
.g-btn-light {
background-color: var(--nord0);
color: white;
}
}
/* Dark background button */
.g-btn-dark,
.g-btn-dark:visited,
.g-btn-dark:link {
background-color: var(--nord0);
color: var(--nord6);
box-shadow: var(--shadow-lg);
}
.g-btn-dark:hover,
.g-btn-dark:focus-visible {
background-color: var(--nord1);
color: var(--nord6);
}
/* Icon badge (circular icon container) */
.g-icon-badge {
font-family: "Noto Color Emoji", emoji, sans-serif;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
text-decoration: none;
transition: var(--transition-fast);
box-shadow: var(--shadow-lg);
}
.g-icon-badge:hover,
.g-icon-badge:focus-visible {
transform: scale(1.1);
box-shadow: var(--shadow-hover);
}
/* Tag/chip styling */
.g-tag,
.g-tag:visited,
.g-tag:link {
font-size: 1.1rem;
padding: 0.25em 1em;
border-radius: var(--radius-pill);
background-color: var(--nord5);
color: var(--nord0);
text-decoration: none;
cursor: pointer;
transition: var(--transition-fast);
box-shadow: var(--shadow-sm);
border: none;
display: inline-block;
}
.g-tag:hover,
.g-tag:focus-visible {
transform: scale(1.05);
background-color: var(--nord8);
box-shadow: var(--shadow-hover);
color: var(--nord0);
}
@media (prefers-color-scheme: dark) {
.g-tag,
.g-tag:visited,
.g-tag:link {
background-color: var(--nord0);
color: white;
}
.g-tag:hover,
.g-tag:focus-visible {
color: var(--nord0);
}
}
-1
View File
@@ -2,7 +2,6 @@
import type { Snippet } from 'svelte';
let { href, ariaLabel = undefined, children } = $props<{ href: string, ariaLabel?: string, children?: Snippet }>();
import "$lib/css/nordtheme.css"
import "$lib/css/action_button.css"
</script>
-1
View File
@@ -1,5 +1,4 @@
<script lang="ts">
import "$lib/css/nordtheme.css"
import { onMount } from "svelte";
import { page } from '$app/stores';
import Symbol from "./Symbol.svelte"
-1
View File
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
let {
value = $bindable(''),
-1
View File
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
</script>
<style>
:root{
-1
View File
@@ -1,6 +1,5 @@
<script lang="ts">
let { tag, ref } = $props<{ tag: string, ref: string }>();
import '$lib/css/nordtheme.css'
</script>
<style>
a{
-1
View File
@@ -1,5 +1,4 @@
<script lang="ts">
import "$lib/css/nordtheme.css";
import "$lib/css/shake.css";
import "$lib/css/icon.css";
import { onMount } from "svelte";
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
import TagChip from '$lib/components/recipes/TagChip.svelte';
let {
@@ -5,7 +5,6 @@ import Cross from '$lib/assets/icons/Cross.svelte'
import Plus from '$lib/assets/icons/Plus.svelte'
import Check from '$lib/assets/icons/Check.svelte'
import '$lib/css/nordtheme.css'
import "$lib/css/action_button.css"
import { do_on_key } from '$lib/components/recipes/do_on_key.js'
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
import Toggle from '$lib/components/Toggle.svelte';
let {
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
import CategoryFilter from './CategoryFilter.svelte';
import TagFilter from './TagFilter.svelte';
import IconFilter from './IconFilter.svelte';
-1
View File
@@ -1,5 +1,4 @@
<script lang="ts">
import '$lib/css/nordtheme.css';
import "$lib/css/shake.css"
let { icon, ...restProps } = $props<{ icon: string, [key: string]: any }>();
</script>
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
import TagChip from '$lib/components/recipes/TagChip.svelte';
let {
@@ -1,6 +1,5 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import '$lib/css/nordtheme.css';
import Recipes from '$lib/components/recipes/Recipes.svelte';
import Search from './Search.svelte';
@@ -4,8 +4,6 @@ import { onNavigate } from "$app/navigation";
import { browser } from '$app/environment';
import { page } from '$app/stores';
import HefeSwapper from './HefeSwapper.svelte';
import '$lib/css/recipe-links.css';
let { data } = $props();
// Helper function to multiply numbers in ingredient amounts
@@ -1,5 +1,4 @@
<script>
import '$lib/css/recipe-links.css';
let { data } = $props();
let multiplier = $state(data.multiplier || 1);
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
let {
useAndLogic = true,
@@ -1,6 +1,5 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import "$lib/css/nordtheme.css"
let { title = '', children } = $props<{ title?: string, children?: Snippet }>();
</script>
<style>
-1
View File
@@ -1,7 +1,6 @@
<script>
import {onMount} from "svelte";
import { browser } from '$app/environment';
import "$lib/css/nordtheme.css";
import FilterPanel from './FilterPanel.svelte';
import { getCategories } from '$lib/js/categories';
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
import TagChip from '$lib/components/recipes/TagChip.svelte';
let {
@@ -1,6 +1,5 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import '$lib/css/nordtheme.css';
import Recipes from '$lib/components/recipes/Recipes.svelte';
import Search from './Search.svelte';
@@ -1,5 +1,4 @@
<script lang=ts>
import "$lib/css/nordtheme.css"
import { season } from '$lib/js/season_store.js'
import {onMount} from "svelte";
import {do_on_key} from "./do_on_key";
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
let {
tag = '',
@@ -1,5 +1,4 @@
<script>
import "$lib/css/nordtheme.css";
import TagChip from '$lib/components/recipes/TagChip.svelte';
let {
+2 -30
View File
@@ -1,3 +1,5 @@
@import "./shake.css";
:root{
--angle: 15deg;
}
@@ -26,33 +28,3 @@
transition: 50ms;
scale: 0.8 0.8;
}
@keyframes shake{
0%{
transform: rotate(0)
scale(1,1);
}
25%{
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
transform: rotate(--angle)
scale(1.2,1.2)
;
}
50%{
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
transform: rotate(calc(-1 * --angle))
scale(1.2,1.2);
}
74%{
box-shadow: 0em 0em 1em 0.2em rgba(0, 0, 0, 0.6);
transform: rotate(--angle)
scale(1.2, 1.2);
}
100%{
transform: rotate(0)
scale(1.2, 1.2);
}
}
-51
View File
@@ -1,51 +0,0 @@
form{
background-color: var(--nord5);
display: flex;
flex-direction: column;
max-width: 600px;
gap: 0.5em;
margin-inline: auto;
justify-content: center;
align-items: center;
padding-block: 2rem;
margin-block: 2rem;
}
@media (prefers-color-scheme: dark){
form{
background-color: var(--accent-dark);
}
}
form label{
font-size: 1.2em;
}
form input{
display: block;
font-size: 1.2rem;
}
form button{
background-color: var(--red);
color: white;
border: none;
padding: 0.5em 1em;
font-size: 1.3em;
border-radius: 1000px;
margin-top: 1em;
transition: 100ms;
}
form button:hover,
form button:focus-visible
{
scale: 1.1;
}
form p{
max-width: 400px;
margin-top: 0;
}
form h4{
margin-bottom:0;
}
@media screen and (max-width: 600px){
form{
margin-top: 0;
}
}
-178
View File
@@ -1,178 +0,0 @@
:root{
--nord0: #2E3440;
--nord1: #3B4252;
--nord2: #434C5E;
--nord3: #4C566A;
--nord4: #D8DEE9;
--nord5: #E5E9F0;
--nord6: #ECEFF4;
--nord7: #8FBCBB;
--nord8: #88C0D0;
--nord9: #81A1C1;
--nord10: #5E81AC;
--nord11: #BF616A;
--nord12: #D08770;
--nord13: #EBCB8B;
--nord14: #A3BE8C;
--nord15: #B48EAD;
--lightblue: var(--nord9);
--blue: var(--nord10);
--red: var(--nord11);
--orange: var(--nord12);
--yellow: var(--nord13);
--green: var(--nord14);
--purple: var(--nord15);
--nord6-dark: #292c31;
--accent-dark: #1f1f21;
--background-dark: #21201b;
--font-default-dark: #ffffff;
/* Shared transitions & shadows */
--transition-fast: 100ms;
--transition-normal: 200ms;
--shadow-sm: 0 0 0.4em 0.05em rgba(0,0,0,0.2);
--shadow-md: 0 0 0.5em 0.1em rgba(0,0,0,0.3);
--shadow-lg: 0 0 1em 0.1em rgba(0,0,0,0.4);
--shadow-hover: 0.1em 0.1em 0.5em 0.1em rgba(0,0,0,0.3);
--radius-pill: 1000px;
--radius-card: 20px;
--radius-sm: 0.3rem;
}
a:not(:visited){
color: var(--blue);
}
a:visited{
color: var(--purple);
}
@media (prefers-color-scheme: dark) {
a:not(:visited){
color: var(--nord8);
}
}
*{
box-sizing: border-box;
font-family: Helvetica, Arial, "Noto Sans", sans-serif
}
body{
margin:0;
padding:0;
background-color: #fbf9f3;
overflow-x: hidden;
}
@media (prefers-color-scheme: dark) {
body{
color: white;
background-color: var(--background-dark);
}
}
/* ========================================
Global Utility Classes
Use these in components to avoid CSS duplication
======================================== */
/* Pill-shaped element base */
.g-pill {
border-radius: var(--radius-pill);
border: none;
cursor: pointer;
display: inline-block;
text-decoration: none;
transition: var(--transition-fast);
}
/* Interactive hover/focus effects */
.g-interactive {
transition: var(--transition-fast);
}
.g-interactive:hover,
.g-interactive:focus-visible {
transform: scale(1.05);
box-shadow: var(--shadow-hover);
}
.g-interactive:focus {
scale: 0.9;
}
/* Light background button (with dark mode) */
.g-btn-light {
background-color: var(--nord5);
color: var(--nord0);
box-shadow: var(--shadow-sm);
}
@media (prefers-color-scheme: dark) {
.g-btn-light {
background-color: var(--nord0);
color: white;
}
}
/* Dark background button */
.g-btn-dark,
.g-btn-dark:visited,
.g-btn-dark:link {
background-color: var(--nord0);
color: var(--nord6);
box-shadow: var(--shadow-lg);
}
.g-btn-dark:hover,
.g-btn-dark:focus-visible {
background-color: var(--nord1);
color: var(--nord6);
}
/* Icon badge (circular icon container) */
.g-icon-badge {
font-family: "Noto Color Emoji", emoji, sans-serif;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
text-decoration: none;
transition: var(--transition-fast);
box-shadow: var(--shadow-lg);
}
.g-icon-badge:hover,
.g-icon-badge:focus-visible {
transform: scale(1.1);
box-shadow: var(--shadow-hover);
}
/* Tag/chip styling */
.g-tag,
.g-tag:visited,
.g-tag:link {
font-size: 1.1rem;
padding: 0.25em 1em;
border-radius: var(--radius-pill);
background-color: var(--nord5);
color: var(--nord0);
text-decoration: none;
cursor: pointer;
transition: var(--transition-fast);
box-shadow: var(--shadow-sm);
border: none;
display: inline-block;
}
.g-tag:hover,
.g-tag:focus-visible {
transform: scale(1.05);
background-color: var(--nord8);
box-shadow: var(--shadow-hover);
color: var(--nord0);
}
@media (prefers-color-scheme: dark) {
.g-tag,
.g-tag:visited,
.g-tag:link {
background-color: var(--nord0);
color: white;
}
.g-tag:hover,
.g-tag:focus-visible {
color: var(--nord0);
}
}
-198
View File
@@ -1,198 +0,0 @@
@font-face {
font-family: 'LibertineMinimal';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(/fonts/LinLibertine_minimal.woff2) format('woff2'),
url(/fonts/LinLibertine_minimal.ttf) format('truetype');
}
.sbeads{
fill: var(--nord10);
}
.chain{
stroke:black;
stroke-width: 0.7;
stroke-miterlimit: 4;
stroke: gray;
fill: none;
}
.sbeads circle.hitbox{
r: 3.2px;
stroke-width:0;
}
#start1 circle{
cx:15.559271px;
cy: 20.881956px;
}
#start2 circle{
cx:21.633902px;
cy:20.367514px;
}
#start3 circle{
cx:27.96961px;
cy:21.178484px;
}
#lbead5 circle{
cx:118.50725px;
cy:59.477211px;
}
#lbead4 circle{
cx:126.81134px;
cy:15.751753px;
}
#lbead1 circle{
cx:7.6719489px;
cy:25.364584px;
}
#lbead2 circle{
cx:36.798512px;
cy:23.486462px;
}
#lbead3 circle{
cx:84.105789px;
cy:3.0456686px;
}
#lbead6 circle{
cx:72.185097px;
cy:64.006859px;
}
#start1:hover .msg,
#start2:hover .msg,
#start3:hover .msg,
#secret1:hover .msg,
#secret2:hover .msg,
#secret3:hover .msg,
#secret4:hover .msg,
#secret5:hover .msg,
#lbeads .beforedecades:hover .msg,
#lbeads .afterdecade:hover .msg,
#cross:hover .msg
{
display:block;
}
#start1:hover .sbeads circle:not(.hitbox),
#start2:hover .sbeads circle:not(.hitbox),
#start3:hover .sbeads circle:not(.hitbox),
#secret1:hover .sbeads circle,
#secret2:hover .sbeads circle,
#secret3:hover .sbeads circle,
#secret4:hover .sbeads circle,
#secret5:hover .sbeads circle
{
fill: var(--nord11);
r: 1.5px;
}
#lbead1:hover .lbead,
#lbead2:hover .lbead,
#lbead3:hover .lbead,
#lbead4:hover .lbead,
#lbead5:hover .lbead,
#lbead6:hover .lbead{
r: 2.8px;
fill: var(--nord11);
}
#cross:hover .symbol{
fill: var(--nord11);
stroke: var(--nord11);
stroke-width: 0.25;
}
#lbeads.msg{
display:block;
}
.sbeads circle{
r: 1.25px;
}
.msg .diff{
fill: var(--nord11);
}
.msg .b{
font-family: crosses;
font-weight: bold;
}
.msg .title{
fill: var(--nord10);
font-weight: bold;
font-size: 5px;
}
.msg{
font-size: 4px;
stroke: none;
fill: var(--nord4);
display:none;
}
text{
font-family: LibertineMinimal;
}
#lbeads circle.hitbox{
r:5px;
stroke:none;
stroke-width:0;
}
.lbead{
fill: var(--nord12);
r: 2.65px;
}
.hitbox{
opacity:0;
stroke-width: 2;
fill: red;
stroke: red;
}
#coin circle{
r: 2.7px;
fill:darkgray;
}
#coin text{
fill:var(--nord0);
font-size: 4.259px;
line-height:1.25;
font-family: crosses;
}
#cross .symbol{
font-family: crosses;
fill: var(--nord4);
font-size: 17.3637px;
line-height: 1.25;
stroke-width:0.434093
}
table{
width: 100%;
border-collapse: collapse;
}
td{
text-align:center;
border-left: 1px solid;
border-right: 1px solid;
border-color: var(--nord2);
padding-left: 5px;
padding-right: 5px;
}
tr :last-child{
border-right: none;
}
tr :first-child{
border-left: 0px solid;
}
thead td{
color: var(--nord4);
border-bottom-width: 3px;
border-bottom-color: var(--nord10);
border-bottom-style: dotted;
font-size: 110%;
font-weight: bold;
}
.table{
width:100%;
overflow-x: auto;
}
-1
View File
@@ -1,5 +1,4 @@
<script lang="ts">
import "$lib/css/nordtheme.css";
import LinksGrid from "$lib/components/LinksGrid.svelte";
import { onMount } from 'svelte';
let { data } = $props();
+37 -3
View File
@@ -1,6 +1,40 @@
<script>
import "$lib/css/form.css"
</script>
<style>
form {
background-color: var(--color-bg-secondary);
display: flex;
flex-direction: column;
max-width: 600px;
gap: 0.5em;
margin-inline: auto;
justify-content: center;
align-items: center;
padding-block: 2rem;
margin-block: 2rem;
}
form label { font-size: 1.2em; }
form input { display: block; font-size: 1.2rem; }
form button {
background-color: var(--color-accent);
color: var(--color-text-on-accent);
border: none;
padding: 0.5em 1em;
font-size: 1.3em;
border-radius: 1000px;
margin-top: 1em;
transition: 100ms;
cursor: pointer;
}
form button:hover, form button:focus-visible {
background-color: var(--color-accent-hover);
scale: 1.1;
}
form button:active { background-color: var(--color-accent-active); }
form p { max-width: 400px; margin-top: 0; }
form h4 { margin-bottom: 0; }
@media screen and (max-width: 600px) {
form { margin-top: 0; }
}
</style>
<form action="?/register" method=POST>
<h1>Registrieren</h1>
+36 -1
View File
@@ -3,9 +3,44 @@
export let data
let password;
const admin = data.user?.access.includes('admin') ?? false
import "$lib/css/form.css"
</script>
<style>
form {
background-color: var(--color-bg-secondary);
display: flex;
flex-direction: column;
max-width: 600px;
gap: 0.5em;
margin-inline: auto;
justify-content: center;
align-items: center;
padding-block: 2rem;
margin-block: 2rem;
}
form label { font-size: 1.2em; }
form input { display: block; font-size: 1.2rem; }
form button {
background-color: var(--color-accent);
color: var(--color-text-on-accent);
border: none;
padding: 0.5em 1em;
font-size: 1.3em;
border-radius: 1000px;
margin-top: 1em;
transition: 100ms;
cursor: pointer;
}
form button:hover, form button:focus-visible {
background-color: var(--color-accent-hover);
scale: 1.1;
}
form button:active { background-color: var(--color-accent-active); }
form p { max-width: 400px; margin-top: 0; }
form h4 { margin-bottom: 0; }
@media screen and (max-width: 600px) {
form { margin-top: 0; }
}
input:invalid + div{
display: none;
}
+1
View File
@@ -1,4 +1,5 @@
<script>
import '../app.css';
let { children } = $props();
</script>
@@ -1,4 +1,5 @@
<script>
import '$lib/css/christ.css';
import { page } from '$app/stores';
import Header from '$lib/components/Header.svelte'
import UserHeader from '$lib/components/UserHeader.svelte';
@@ -2,8 +2,6 @@
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import { createLanguageContext } from "$lib/contexts/languageContext.js";
import "$lib/css/christ.css";
import "$lib/css/nordtheme.css";
import Gebet from "./Gebet.svelte";
import LanguageToggle from "$lib/components/faith/LanguageToggle.svelte";
import SearchInput from "$lib/components/SearchInput.svelte";
@@ -1,8 +1,6 @@
<script>
import { onMount } from 'svelte';
import { createLanguageContext } from "$lib/contexts/languageContext.js";
import "$lib/css/christ.css";
import "$lib/css/nordtheme.css";
import LanguageToggle from "$lib/components/faith/LanguageToggle.svelte";
import Kreuzzeichen from "$lib/components/faith/prayers/Kreuzzeichen.svelte";
import GloriaPatri from "$lib/components/faith/prayers/GloriaPatri.svelte";
@@ -3,7 +3,6 @@ import { onMount, tick } from "svelte";
import { createLanguageContext } from "$lib/contexts/languageContext.js";
import { createPip } from "$lib/js/pip.svelte";
import PipImage from "$lib/components/faith/PipImage.svelte";
import "$lib/css/christ.css";
import "$lib/css/action_button.css";
import Kreuzzeichen from "$lib/components/faith/prayers/Kreuzzeichen.svelte";
import Credo from "$lib/components/faith/prayers/Credo.svelte";
@@ -75,6 +74,7 @@ let currentMysteryDescriptions = $derived(data.mysteryDescriptions[selectedMyste
// Function to switch mysteries
function selectMystery(mysteryType) {
selectedMystery = mysteryType;
lastMysteryTarget = 'before';
}
// Build URLs preserving full state (for no-JS fallback)
@@ -163,6 +163,7 @@ $effect(() => {
let mysteryImageContainer;
let mysteryScrollRaf = null;
let lastMysteryTarget = 'before';
function scrollMysteryImage(targetY, duration = 1200) {
if (!mysteryImageContainer) return;
@@ -193,14 +194,17 @@ $effect(() => {
// Edge pads (before/after): scroll flush so previous image hides behind the header
const offset = isEdge ? 0 : rem * IMAGE_COL_HEADER_OFFSET;
const target = Math.max(0, targetEl.offsetTop - offset);
if (isEdge) {
// Snap instantly when jumping to top/bottom
// Smooth-scroll the last image away when naturally transitioning from decade 5 to 'after'
const isNaturalEnd = targetName === 'after' && lastMysteryTarget === 5;
if (isEdge && !isNaturalEnd) {
// Snap instantly when jumping to top/bottom (not a natural scroll)
if (mysteryScrollRaf) cancelAnimationFrame(mysteryScrollRaf);
mysteryScrollRaf = null;
mysteryImageContainer.scrollTop = target;
} else {
scrollMysteryImage(target);
}
lastMysteryTarget = targetName;
}
});
@@ -1,4 +1,5 @@
<script>
import '$lib/css/recipe-links.css';
import { page } from '$app/stores';
import Header from '$lib/components/Header.svelte'
import UserHeader from '$lib/components/UserHeader.svelte';
@@ -3,7 +3,6 @@
export const multiplier = writable(0);
import type { PageData } from './$types';
import "$lib/css/nordtheme.css"
import EditButton from '$lib/components/EditButton.svelte';
import InstructionsPage from '$lib/components/recipes/InstructionsPage.svelte';
import IngredientsPage from '$lib/components/recipes/IngredientsPage.svelte';
@@ -10,7 +10,6 @@
import CreateStepList from '$lib/components/recipes/CreateStepList.svelte';
import Toggle from '$lib/components/Toggle.svelte';
import '$lib/css/action_button.css';
import '$lib/css/nordtheme.css';
let { data, form }: { data: PageData; form: ActionData } = $props();
@@ -1,6 +1,5 @@
<script lang="ts">
import type { PageData } from './$types';
import '$lib/css/nordtheme.css';
import Recipes from '$lib/components/recipes/Recipes.svelte';
import Card from '$lib/components/recipes/Card.svelte';
@@ -1,6 +1,5 @@
<script lang="ts">
import type { PageData } from './$types';
import '$lib/css/nordtheme.css';
let { data } = $props<{ data: PageData }>();
@@ -1,6 +1,5 @@
<script lang="ts">
import type { PageData } from './$types';
import "$lib/css/nordtheme.css";
let { data } = $props<{ data: PageData }>();
import TagCloud from '$lib/components/TagCloud.svelte';
import TagBall from '$lib/components/TagBall.svelte';
@@ -15,7 +15,6 @@
import { season } from '$lib/js/season_store';
import { portions } from '$lib/js/portions_store';
import '$lib/css/action_button.css';
import '$lib/css/nordtheme.css';
let { data, form }: { data: PageData; form: ActionData } = $props();
@@ -1,6 +1,5 @@
<script lang="ts">
import type { PageData } from './$types';
import '$lib/css/nordtheme.css';
import Recipes from '$lib/components/recipes/Recipes.svelte';
import Card from '$lib/components/recipes/Card.svelte';
import Search from '$lib/components/recipes/Search.svelte';
@@ -1,6 +1,5 @@
<script lang="ts">
import type { PageData } from './$types';
import '$lib/css/nordtheme.css';
import Recipes from '$lib/components/recipes/Recipes.svelte';
import MediaScroller from '$lib/components/recipes/MediaScroller.svelte';
import SeasonLayout from '$lib/components/recipes/SeasonLayout.svelte'
@@ -1,6 +1,5 @@
<script lang="ts">
import type { PageData } from './$types';
import '$lib/css/nordtheme.css';
import Recipes from '$lib/components/recipes/Recipes.svelte';
import MediaScroller from '$lib/components/recipes/MediaScroller.svelte';
import SeasonLayout from '$lib/components/recipes/SeasonLayout.svelte'
@@ -1,7 +1,6 @@
<script lang="ts">
import type { PageData } from './$types';
let { data } = $props<{ data: PageData }>();
import "$lib/css/nordtheme.css";
import TagCloud from '$lib/components/TagCloud.svelte';
import TagBall from '$lib/components/TagBall.svelte';