refactor: $app/stores → $app/state, legacy stores → runes
Codemod-driven migration of 55 .svelte files from the deprecated $app/stores module to the rune-based $app/state ($page.x → page.x, no auto-subscription wrapper). Two custom writable() stores converted to .svelte.ts factory functions matching the existing theme store pattern, with consumers updated to use .value getters and the explicit .set() method. UserHeader.svelte's login link now guards page.url.search behind the browser flag — search-param access throws during prerender, and this defensive change unblocks future prerender adoption on any page that includes the header.
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
import { enhance } from '$app/forms';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import Heart from '@lucide/svelte/icons/heart';
|
||||
|
||||
let { recipeId, isFavorite = $bindable(false), isLoggedIn = false } = $props<{ recipeId: string, isFavorite?: boolean, isLoggedIn?: boolean }>();
|
||||
|
||||
const recipeLang = $derived($page.url.pathname.split('/')[1] || 'rezepte');
|
||||
const recipeLang = $derived(page.url.pathname.split('/')[1] || 'rezepte');
|
||||
|
||||
let isLoading = $state(false);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { recipeTranslationStore } from '$lib/stores/recipeTranslation';
|
||||
import { languageStore } from '$lib/stores/language';
|
||||
import { page } from '$app/state';
|
||||
import { recipeTranslationStore } from '$lib/stores/recipeTranslation.svelte';
|
||||
import { languageStore } from '$lib/stores/language.svelte';
|
||||
import { convertFitnessPath } from '$lib/js/fitnessI18n';
|
||||
import { convertCospendPath } from '$lib/js/cospendI18n';
|
||||
import { onMount } from 'svelte';
|
||||
@@ -10,7 +10,7 @@
|
||||
let { lang = undefined }: { lang?: 'de' | 'en' | 'la' } = $props();
|
||||
|
||||
// Use prop for display if provided (SSR-safe), otherwise fall back to store
|
||||
const displayLang = $derived(lang ?? $languageStore);
|
||||
const displayLang = $derived(lang ?? languageStore.value);
|
||||
|
||||
let currentPath = $state('');
|
||||
let langButton: HTMLButtonElement;
|
||||
@@ -33,14 +33,14 @@
|
||||
};
|
||||
|
||||
// Whether the current page is a faith route (show LA option)
|
||||
const faithPath = $derived(currentPath || $page.url.pathname);
|
||||
const faithPath = $derived(currentPath || page.url.pathname);
|
||||
const isFaithRoute = $derived(
|
||||
faithPath.startsWith('/glaube') || faithPath.startsWith('/faith') || faithPath.startsWith('/fides')
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
// Update current language and path when page changes (reactive to browser navigation)
|
||||
const path = $page.url.pathname;
|
||||
const path = page.url.pathname;
|
||||
currentPath = path;
|
||||
|
||||
if (path.startsWith('/recipes') || path.startsWith('/faith')) {
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
// Compute target paths for each language (used as href for no-JS)
|
||||
function computeTargetPath(targetLang: 'de' | 'en' | 'la'): string {
|
||||
const path = currentPath || $page.url.pathname;
|
||||
const path = currentPath || page.url.pathname;
|
||||
|
||||
if (path.startsWith('/glaube') || path.startsWith('/faith') || path.startsWith('/fides')) {
|
||||
return convertFaithPath(path, targetLang);
|
||||
@@ -102,7 +102,7 @@
|
||||
}
|
||||
|
||||
// Use translated recipe slugs from page data when available (works during SSR)
|
||||
const pageData = $page.data;
|
||||
const pageData = page.data;
|
||||
if (targetLang === 'en' && path.startsWith('/rezepte')) {
|
||||
if (pageData?.englishShortName) {
|
||||
return `/recipes/${pageData.englishShortName}`;
|
||||
@@ -171,7 +171,7 @@
|
||||
}
|
||||
|
||||
// If we have recipe translation data from store, use the correct short names
|
||||
const recipeData = $recipeTranslationStore;
|
||||
const recipeData = recipeTranslationStore.value;
|
||||
if (recipeData) {
|
||||
if (lang === 'en' && recipeData.englishShortName) {
|
||||
await goto(`/recipes/${recipeData.englishShortName}`);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { goto } from '$app/navigation';
|
||||
import ErrorView from './ErrorView.svelte';
|
||||
import { getErrorTitle, getErrorDescription, errorLabels, pick } from '$lib/js/errorStrings';
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
let { sectionHref, sectionLabel, isEnglish: isEnglishProp, extraActions }: Props = $props();
|
||||
|
||||
let status = $derived($page.status);
|
||||
let error = $derived($page.error as any);
|
||||
let status = $derived(page.status);
|
||||
let error = $derived(page.error as any);
|
||||
let bibleQuote = $derived(error?.bibleQuote);
|
||||
let detectedEnglish = $derived(error?.lang === 'en');
|
||||
let isEnglish = $derived(isEnglishProp ?? detectedEnglish);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from '$app/paths';
|
||||
import { onMount } from "svelte";
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { browser } from '$app/environment';
|
||||
import LogIn from '@lucide/svelte/icons/log-in';
|
||||
|
||||
let { user, recipeLang = 'rezepte', lang = 'de' } = $props();
|
||||
@@ -157,7 +158,7 @@
|
||||
<li><a href={resolve('/[recipeLang=recipeLang]/administration', { recipeLang })}>Administration</a></li>
|
||||
{/if}
|
||||
<li><a href="https://sso.bocken.org/if/user/#/settings" >Einstellungen</a></li>
|
||||
<li><a href={`${resolve('/logout')}?callbackUrl=${encodeURIComponent(getLogoutCallbackUrl($page.url.pathname))}`}>Log Out</a></li>
|
||||
<li><a href={`${resolve('/logout')}?callbackUrl=${encodeURIComponent(getLogoutCallbackUrl(page.url.pathname))}`}>Log Out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -165,7 +166,7 @@
|
||||
{:else}
|
||||
<a
|
||||
class="entry login-link"
|
||||
href={`${resolve('/login')}?callbackUrl=${encodeURIComponent($page.url.pathname + $page.url.search)}`}
|
||||
href={`${resolve('/login')}?callbackUrl=${encodeURIComponent(page.url.pathname + (browser ? page.url.search : ''))}`}
|
||||
aria-label={lang === 'de' ? 'Anmelden' : 'Login'}
|
||||
title={lang === 'de' ? 'Anmelden' : 'Login'}
|
||||
>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import ProfilePicture from './ProfilePicture.svelte';
|
||||
import { formatCurrency } from '$lib/utils/formatters';
|
||||
import { detectCospendLang, locale, t } from '$lib/js/cospendI18n';
|
||||
|
||||
const lang = $derived(detectCospendLang($page.url.pathname));
|
||||
const lang = $derived(detectCospendLang(page.url.pathname));
|
||||
const loc = $derived(locale(lang));
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import ProfilePicture from './ProfilePicture.svelte';
|
||||
import { formatCurrency as formatCurrencyUtil } from '$lib/utils/formatters';
|
||||
import { detectCospendLang, locale, t } from '$lib/js/cospendI18n';
|
||||
|
||||
const lang = $derived(detectCospendLang($page.url.pathname));
|
||||
const lang = $derived(detectCospendLang(page.url.pathname));
|
||||
const loc = $derived(locale(lang));
|
||||
|
||||
let { initialBalance = null, initialDebtData = null } = $props<{ initialBalance?: any, initialDebtData?: any }>();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { resolve } from '$app/paths';
|
||||
import { onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import ProfilePicture from './ProfilePicture.svelte';
|
||||
import EditButton from '$lib/components/EditButton.svelte';
|
||||
import { getCategoryEmoji } from '$lib/utils/categories';
|
||||
@@ -13,9 +13,9 @@
|
||||
let { paymentId, onclose, onpaymentDeleted } = $props();
|
||||
|
||||
// Get session from page store
|
||||
let session = $derived($page.data?.session);
|
||||
let session = $derived(page.data?.session);
|
||||
|
||||
const lang = $derived(detectCospendLang($page.url.pathname));
|
||||
const lang = $derived(detectCospendLang(page.url.pathname));
|
||||
const root = $derived(cospendRoot(lang));
|
||||
const loc = $derived(locale(lang));
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script>
|
||||
import ProfilePicture from './ProfilePicture.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { detectCospendLang, t } from '$lib/js/cospendI18n';
|
||||
|
||||
const lang = $derived(detectCospendLang($page.url.pathname));
|
||||
const lang = $derived(detectCospendLang(page.url.pathname));
|
||||
|
||||
let {
|
||||
splitMethod = $bindable('equal'),
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script>
|
||||
import { resolve } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { getEnrichedExerciseById } from '$lib/data/exercisedb';
|
||||
import { detectFitnessLang, fitnessSlugs } from '$lib/js/fitnessI18n';
|
||||
|
||||
let { exerciseId, plain = false } = $props();
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
const exercise = $derived(getEnrichedExerciseById(exerciseId, lang));
|
||||
const sl = $derived(fitnessSlugs(lang));
|
||||
</script>
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
import PersonStanding from '@lucide/svelte/icons/person-standing';
|
||||
import Shapes from '@lucide/svelte/icons/shapes';
|
||||
import Weight from '@lucide/svelte/icons/weight';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { detectFitnessLang, t } from '$lib/js/fitnessI18n';
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
const isEn = $derived(lang === 'en');
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { resolve } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { browser } from '$app/environment';
|
||||
import { untrack } from 'svelte';
|
||||
import Heart from '@lucide/svelte/icons/heart';
|
||||
@@ -50,7 +50,7 @@
|
||||
initialResults = undefined,
|
||||
} = $props();
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
const s = $derived(fitnessSlugs(lang));
|
||||
const isEn = $derived(lang === 'en');
|
||||
const btnLabel = $derived(confirmLabel ?? t('log_food', lang));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { detectFitnessLang } from '$lib/js/fitnessI18n';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import Beef from '@lucide/svelte/icons/beef';
|
||||
import Droplet from '@lucide/svelte/icons/droplet';
|
||||
import Wheat from '@lucide/svelte/icons/wheat';
|
||||
@@ -31,7 +31,7 @@
|
||||
showDetailRows = true,
|
||||
} = $props();
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
const isEn = $derived(lang === 'en');
|
||||
|
||||
const macroPercent = $derived.by(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { onMount } from 'svelte';
|
||||
import { detectFitnessLang } from '$lib/js/fitnessI18n';
|
||||
import frontSvgRaw from '$lib/assets/muscle-front.svg?raw';
|
||||
@@ -13,7 +13,7 @@
|
||||
/** @type {{ data?: { totals?: Record<string, MuscleTotals> } | null }} */
|
||||
let { data } = $props();
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
const isEn = $derived(lang === 'en');
|
||||
/** @type {Record<string, MuscleTotals>} */
|
||||
const totals = $derived(data?.totals ?? {});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { resolve } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { getExerciseById, getExerciseMetrics } from '$lib/data/exercises';
|
||||
import Clock from '@lucide/svelte/icons/clock';
|
||||
import Weight from '@lucide/svelte/icons/weight';
|
||||
@@ -10,7 +10,7 @@
|
||||
import Flame from '@lucide/svelte/icons/flame';
|
||||
import { detectFitnessLang, fitnessSlugs } from '$lib/js/fitnessI18n';
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
const sl = $derived(fitnessSlugs(lang));
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
import Square from '@lucide/svelte/icons/square';
|
||||
import { METRIC_LABELS } from '$lib/data/exercises';
|
||||
import RestTimer from './RestTimer.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { detectFitnessLang, t } from '$lib/js/fitnessI18n';
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
|
||||
/**
|
||||
* @type {{
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import { getExerciseById } from '$lib/data/exercises';
|
||||
import EllipsisVertical from '@lucide/svelte/icons/ellipsis-vertical';
|
||||
import MapPin from '@lucide/svelte/icons/map-pin';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { detectFitnessLang, t } from '$lib/js/fitnessI18n';
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
|
||||
/**
|
||||
* @type {{
|
||||
|
||||
@@ -4,10 +4,10 @@ import Play from '@lucide/svelte/icons/play';
|
||||
import Pause from '@lucide/svelte/icons/pause';
|
||||
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
||||
import SyncIndicator from '$lib/components/fitness/SyncIndicator.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import { detectFitnessLang, t } from '$lib/js/fitnessI18n';
|
||||
|
||||
const lang = $derived(detectFitnessLang($page.url.pathname));
|
||||
const lang = $derived(detectFitnessLang(page.url.pathname));
|
||||
|
||||
let { href, elapsed = '0:00', paused = false, syncStatus = 'idle', onPauseToggle,
|
||||
restSeconds = 0, restTotal = 0, onRestAdjust = null, onRestSkip = null } = $props();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { browser } from '$app/environment';
|
||||
import { enhance } from '$app/forms';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
|
||||
let { item, multiplier = 1, yeastId = 0, lang = 'de' } = $props();
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
: 'Zwischen Frischhefe und Trockenhefe wechseln');
|
||||
|
||||
// Get all current URL parameters to preserve state
|
||||
const currentParams = $derived(browser ? new URLSearchParams(window.location.search) : $page.url.searchParams);
|
||||
const currentParams = $derived(browser ? new URLSearchParams(window.location.search) : page.url.searchParams);
|
||||
|
||||
/** @param {Event} event */
|
||||
function toggleHefe(event) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { onMount } from 'svelte';
|
||||
import { onNavigate } from "$app/navigation";
|
||||
import { browser } from '$app/environment';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import HefeSwapper from './HefeSwapper.svelte';
|
||||
import NutritionSummary from './NutritionSummary.svelte';
|
||||
import AddToFoodLogButton from './AddToFoodLogButton.svelte';
|
||||
@@ -272,7 +272,7 @@ const yeastIds = $derived.by(() => {
|
||||
});
|
||||
|
||||
// Get all current URL parameters to preserve state in multiplier forms
|
||||
const currentParams = $derived(browser ? new URLSearchParams(window.location.search) : $page.url.searchParams);
|
||||
const currentParams = $derived(browser ? new URLSearchParams(window.location.search) : page.url.searchParams);
|
||||
|
||||
// Progressive enhancement - use JS if available
|
||||
onMount(() => {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
export type Language = 'de' | 'en';
|
||||
|
||||
function createLanguage() {
|
||||
let value = $state<Language>('de');
|
||||
|
||||
return {
|
||||
get value() { return value; },
|
||||
set: (v: Language) => { value = v; }
|
||||
};
|
||||
}
|
||||
|
||||
export const languageStore = createLanguage();
|
||||
@@ -1,27 +0,0 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
type Language = 'de' | 'en';
|
||||
|
||||
function createLanguageStore() {
|
||||
const { subscribe, set } = writable<Language>('de');
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set,
|
||||
init: () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const path = window.location.pathname;
|
||||
if (path.startsWith('/recipes') || path.startsWith('/faith')) {
|
||||
set('en');
|
||||
} else if (path.startsWith('/rezepte') || path.startsWith('/glaube')) {
|
||||
set('de');
|
||||
} else {
|
||||
const preferredLanguage = localStorage.getItem('preferredLanguage');
|
||||
set(preferredLanguage === 'en' ? 'en' : 'de');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const languageStore = createLanguageStore();
|
||||
@@ -0,0 +1,16 @@
|
||||
export interface RecipeTranslationData {
|
||||
germanShortName: string;
|
||||
englishShortName?: string;
|
||||
hasEnglishTranslation: boolean;
|
||||
}
|
||||
|
||||
function createRecipeTranslation() {
|
||||
let value = $state<RecipeTranslationData | null>(null);
|
||||
|
||||
return {
|
||||
get value() { return value; },
|
||||
set: (v: RecipeTranslationData | null) => { value = v; }
|
||||
};
|
||||
}
|
||||
|
||||
export const recipeTranslationStore = createRecipeTranslation();
|
||||
@@ -1,9 +0,0 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
interface RecipeTranslationData {
|
||||
germanShortName: string;
|
||||
englishShortName?: string;
|
||||
hasEnglishTranslation: boolean;
|
||||
}
|
||||
|
||||
export const recipeTranslationStore = writable<RecipeTranslationData | null>(null);
|
||||
Reference in New Issue
Block a user