feat: mobile-friendly UI overhaul
- Bottom navigation bar on mobile instead of sidebar - Sheet-style modals (slide up from bottom) on small screens - Larger touch targets for shopping list checkboxes - Stacked ingredient form inputs for mobile usability - Responsive header buttons with short labels on small screens - Safe-area support for notched phones - Reduced padding on mobile for better space usage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="theme-color" content="#09090b" />
|
||||
<title>Mealplanner</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
|
||||
<!-- Authenticated app -->
|
||||
<div v-else class="flex h-screen bg-zinc-950 overflow-hidden">
|
||||
<!-- Sidebar -->
|
||||
<!-- Desktop Sidebar (hidden on mobile) -->
|
||||
<aside
|
||||
class="flex flex-col bg-zinc-900 border-r border-zinc-800 transition-all duration-300 z-20"
|
||||
class="hidden md:flex flex-col bg-zinc-900 border-r border-zinc-800 transition-all duration-300 z-20"
|
||||
:class="sidebarOpen ? 'w-56' : 'w-14'"
|
||||
>
|
||||
<!-- Logo / toggle -->
|
||||
@@ -79,7 +79,7 @@
|
||||
: 'text-zinc-400 hover:text-zinc-100 hover:bg-zinc-800'"
|
||||
:title="!sidebarOpen ? item.label : undefined"
|
||||
>
|
||||
<span class="flex-shrink-0 w-5 h-5" v-html="item.icon" />
|
||||
<span class="flex-shrink-0 w-5 h-5 [&>svg]:w-5 [&>svg]:h-5" v-html="item.icon" />
|
||||
<Transition name="fade-text">
|
||||
<span v-if="sidebarOpen" class="text-sm font-medium whitespace-nowrap overflow-hidden">{{ item.label }}</span>
|
||||
</Transition>
|
||||
@@ -122,47 +122,39 @@
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Mobile overlay -->
|
||||
<div
|
||||
v-if="sidebarOpen && isMobile"
|
||||
class="fixed inset-0 z-10 bg-black/50"
|
||||
@click="sidebarOpen = false"
|
||||
/>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="flex-1 overflow-y-auto">
|
||||
<div class="p-6 max-w-7xl mx-auto">
|
||||
<main class="flex-1 overflow-y-auto pb-20 md:pb-0">
|
||||
<div class="p-4 md:p-6 max-w-7xl mx-auto">
|
||||
<RouterView />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Mobile bottom navigation -->
|
||||
<nav class="md:hidden fixed bottom-0 inset-x-0 z-30 bg-zinc-900 border-t border-zinc-800 safe-bottom">
|
||||
<div class="flex items-stretch">
|
||||
<RouterLink
|
||||
v-for="item in navItems"
|
||||
:key="item.to"
|
||||
:to="item.to"
|
||||
class="flex-1 flex flex-col items-center gap-1 py-3 transition-colors"
|
||||
:class="isActiveRoute(item.to)
|
||||
? 'text-accent'
|
||||
: 'text-zinc-500 active:text-zinc-300'"
|
||||
>
|
||||
<span class="w-6 h-6" v-html="item.icon" />
|
||||
<span class="text-[10px] font-medium">{{ item.shortLabel }}</span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { isAuthenticated, isLoading, authError, currentUser, login, logout } from './auth'
|
||||
|
||||
const sidebarOpen = ref(true)
|
||||
const windowWidth = ref(window.innerWidth)
|
||||
|
||||
function onResize(): void {
|
||||
windowWidth.value = window.innerWidth
|
||||
if (window.innerWidth < 768) {
|
||||
sidebarOpen.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', onResize)
|
||||
if (window.innerWidth < 768) sidebarOpen.value = false
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', onResize)
|
||||
})
|
||||
|
||||
const isMobile = computed(() => windowWidth.value < 768)
|
||||
const sidebarOpen = ref(window.innerWidth >= 768)
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
@@ -175,7 +167,8 @@ const navItems = [
|
||||
{
|
||||
to: '/',
|
||||
label: 'Wochenplan',
|
||||
icon: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-5 h-5">
|
||||
shortLabel: 'Plan',
|
||||
icon: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-full h-full">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>`,
|
||||
@@ -183,7 +176,8 @@ const navItems = [
|
||||
{
|
||||
to: '/shopping',
|
||||
label: 'Einkaufsliste',
|
||||
icon: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-5 h-5">
|
||||
shortLabel: 'Einkauf',
|
||||
icon: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-full h-full">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||
</svg>`,
|
||||
@@ -191,7 +185,8 @@ const navItems = [
|
||||
{
|
||||
to: '/recipes',
|
||||
label: 'Rezepte',
|
||||
icon: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-5 h-5">
|
||||
shortLabel: 'Rezepte',
|
||||
icon: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-full h-full">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0118 18a8.966 8.966 0 00-6 2.292m0-14.25v14.25" />
|
||||
</svg>`,
|
||||
@@ -199,7 +194,8 @@ const navItems = [
|
||||
{
|
||||
to: '/settings',
|
||||
label: 'Einstellungen',
|
||||
icon: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-5 h-5">
|
||||
shortLabel: 'Mehr',
|
||||
icon: `<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" class="w-full h-full">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
@@ -212,6 +208,9 @@ const navItems = [
|
||||
html, body {
|
||||
background-color: #09090b;
|
||||
}
|
||||
.safe-bottom {
|
||||
padding-bottom: env(safe-area-inset-bottom, 0px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<!-- Backdrop -->
|
||||
<Teleport to="body">
|
||||
<div
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm"
|
||||
class="fixed inset-0 z-50 flex items-end md:items-center justify-center md:p-4 bg-black/70 backdrop-blur-sm"
|
||||
@click.self="$emit('close')"
|
||||
>
|
||||
<div class="relative w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-zinc-900 border border-zinc-800 rounded-2xl shadow-2xl">
|
||||
<div class="relative w-full max-w-2xl h-full md:h-auto md:max-h-[90vh] overflow-y-auto bg-zinc-900 md:border md:border-zinc-800 md:rounded-2xl shadow-2xl">
|
||||
<!-- Close button -->
|
||||
<button
|
||||
@click="$emit('close')"
|
||||
@@ -32,7 +32,7 @@
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="p-6">
|
||||
<div class="p-4 md:p-6">
|
||||
<h2 class="text-2xl font-bold text-zinc-100 mb-4">{{ recipe.title }}</h2>
|
||||
|
||||
<!-- Ingredients -->
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center gap-3 py-2 px-3 rounded-lg hover:bg-zinc-800/50 transition-colors group cursor-pointer"
|
||||
class="flex items-center gap-3 py-3 px-3 rounded-lg hover:bg-zinc-800/50 active:bg-zinc-800/70 transition-colors group cursor-pointer select-none"
|
||||
@click="$emit('toggle', item.name)"
|
||||
>
|
||||
<!-- Checkbox -->
|
||||
<div
|
||||
class="flex-shrink-0 w-5 h-5 rounded border-2 flex items-center justify-center transition-all"
|
||||
class="flex-shrink-0 w-6 h-6 rounded border-2 flex items-center justify-center transition-all"
|
||||
:class="item.isChecked
|
||||
? 'bg-accent border-accent'
|
||||
: 'border-zinc-600 group-hover:border-zinc-400'"
|
||||
>
|
||||
<svg v-if="item.isChecked" class="w-3 h-3 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<svg v-if="item.isChecked" class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<!-- Amount + unit -->
|
||||
<span
|
||||
class="text-sm tabular-nums transition-colors"
|
||||
class="text-sm tabular-nums transition-colors whitespace-nowrap"
|
||||
:class="item.isChecked ? 'text-zinc-700' : 'text-zinc-400'"
|
||||
>{{ item.totalAmount != null ? item.totalAmount : '' }} {{ item.unit ?? '' }}</span>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<div
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm"
|
||||
class="fixed inset-0 z-50 flex items-end md:items-center justify-center md:p-4 bg-black/70 backdrop-blur-sm"
|
||||
@click.self="$emit('close')"
|
||||
>
|
||||
<div class="w-full max-w-lg bg-zinc-900 border border-zinc-800 rounded-2xl shadow-2xl">
|
||||
<div class="w-full max-w-lg max-h-[85vh] md:max-h-none bg-zinc-900 md:border md:border-zinc-800 rounded-t-2xl md:rounded-2xl shadow-2xl flex flex-col">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b border-zinc-800">
|
||||
<h2 class="text-lg font-semibold text-zinc-100">Rezept austauschen</h2>
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Recipe list -->
|
||||
<div class="px-6 pb-4 max-h-80 overflow-y-auto space-y-1">
|
||||
<div class="px-4 md:px-6 pb-4 flex-1 overflow-y-auto space-y-1">
|
||||
<div v-if="!filtered.length" class="text-center py-8 text-zinc-500 text-sm">
|
||||
Keine Rezepte gefunden.
|
||||
</div>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-2xl font-bold text-zinc-100">Meine Rezepte</h1>
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<h1 class="text-xl md:text-2xl font-bold text-zinc-100">Meine Rezepte</h1>
|
||||
<button
|
||||
@click="openCreate"
|
||||
class="flex items-center gap-2 px-4 py-2 rounded-lg bg-accent hover:bg-accent-hover text-white text-sm font-medium transition-colors"
|
||||
class="flex-shrink-0 flex items-center gap-2 px-3 md:px-4 py-2 rounded-lg bg-accent hover:bg-accent-hover text-white text-sm font-medium transition-colors"
|
||||
>
|
||||
<!-- Plus icon -->
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
Neues Rezept
|
||||
<span class="hidden sm:inline">Neues Rezept</span>
|
||||
<span class="sm:hidden">Neu</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -115,10 +115,10 @@
|
||||
<Teleport to="body">
|
||||
<div
|
||||
v-if="showForm"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/70 backdrop-blur-sm"
|
||||
class="fixed inset-0 z-50 flex items-end md:items-center justify-center md:p-4 bg-black/70 backdrop-blur-sm"
|
||||
@click.self="closeForm"
|
||||
>
|
||||
<div class="w-full max-w-2xl max-h-[90vh] overflow-y-auto bg-zinc-900 border border-zinc-800 rounded-2xl shadow-2xl">
|
||||
<div class="w-full max-w-2xl h-full md:h-auto md:max-h-[90vh] overflow-y-auto bg-zinc-900 md:border md:border-zinc-800 md:rounded-2xl shadow-2xl">
|
||||
<!-- Form header -->
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b border-zinc-800 sticky top-0 bg-zinc-900 z-10">
|
||||
<h2 class="text-lg font-semibold text-zinc-100">
|
||||
@@ -134,7 +134,7 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="handleSubmit" class="p-6 space-y-5">
|
||||
<form @submit.prevent="handleSubmit" class="p-4 md:p-6 space-y-5">
|
||||
<!-- Title -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-zinc-300 mb-1.5">Titel *</label>
|
||||
@@ -185,52 +185,56 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="(ing, idx) in form.ingredients"
|
||||
:key="idx"
|
||||
class="flex gap-2 items-start"
|
||||
class="bg-zinc-800/30 rounded-lg p-3 space-y-2"
|
||||
>
|
||||
<input
|
||||
v-model="ing.name"
|
||||
type="text"
|
||||
placeholder="Name"
|
||||
class="flex-1 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 placeholder-zinc-500 focus:outline-none focus:border-accent text-sm"
|
||||
/>
|
||||
<input
|
||||
v-model.number="ing.amount"
|
||||
type="number"
|
||||
placeholder="Menge"
|
||||
min="0"
|
||||
step="any"
|
||||
class="w-20 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 placeholder-zinc-500 focus:outline-none focus:border-accent text-sm"
|
||||
/>
|
||||
<input
|
||||
v-model="ing.unit"
|
||||
type="text"
|
||||
placeholder="Einheit"
|
||||
class="w-20 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 placeholder-zinc-500 focus:outline-none focus:border-accent text-sm"
|
||||
/>
|
||||
<select
|
||||
v-model="ing.category"
|
||||
class="w-32 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 focus:outline-none focus:border-accent text-sm"
|
||||
>
|
||||
<option value="Gemüse">Gemüse</option>
|
||||
<option value="Fleisch">Fleisch</option>
|
||||
<option value="Milchprodukte">Milchprodukte</option>
|
||||
<option value="Gewürze">Gewürze</option>
|
||||
<option value="Sonstiges">Sonstiges</option>
|
||||
</select>
|
||||
<button
|
||||
type="button"
|
||||
@click="removeIngredient(idx)"
|
||||
class="p-2 text-zinc-500 hover:text-error transition-colors"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
v-model="ing.name"
|
||||
type="text"
|
||||
placeholder="Name"
|
||||
class="flex-1 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 placeholder-zinc-500 focus:outline-none focus:border-accent text-sm"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@click="removeIngredient(idx)"
|
||||
class="p-2 text-zinc-500 hover:text-error transition-colors flex-shrink-0"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
v-model.number="ing.amount"
|
||||
type="number"
|
||||
placeholder="Menge"
|
||||
min="0"
|
||||
step="any"
|
||||
class="w-24 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 placeholder-zinc-500 focus:outline-none focus:border-accent text-sm"
|
||||
/>
|
||||
<input
|
||||
v-model="ing.unit"
|
||||
type="text"
|
||||
placeholder="Einheit"
|
||||
class="w-24 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 placeholder-zinc-500 focus:outline-none focus:border-accent text-sm"
|
||||
/>
|
||||
<select
|
||||
v-model="ing.category"
|
||||
class="flex-1 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 text-zinc-100 focus:outline-none focus:border-accent text-sm"
|
||||
>
|
||||
<option value="Gemüse">Gemüse</option>
|
||||
<option value="Fleisch">Fleisch</option>
|
||||
<option value="Milchprodukte">Milchprodukte</option>
|
||||
<option value="Gewürze">Gewürze</option>
|
||||
<option value="Sonstiges">Sonstiges</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-zinc-100">Wochenplan</h1>
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="min-w-0">
|
||||
<h1 class="text-xl md:text-2xl font-bold text-zinc-100">Wochenplan</h1>
|
||||
<p v-if="store.currentPlan" class="text-zinc-500 text-sm mt-0.5">
|
||||
{{ formatWeek(store.currentPlan.weekStart) }}
|
||||
</p>
|
||||
@@ -11,7 +11,7 @@
|
||||
<button
|
||||
@click="handleGenerate"
|
||||
:disabled="store.generating"
|
||||
class="flex items-center gap-2 px-4 py-2 rounded-lg bg-accent hover:bg-accent-hover disabled:opacity-60 disabled:cursor-not-allowed text-white text-sm font-medium transition-colors"
|
||||
class="flex-shrink-0 flex items-center gap-2 px-3 md:px-4 py-2 rounded-lg bg-accent hover:bg-accent-hover disabled:opacity-60 disabled:cursor-not-allowed text-white text-sm font-medium transition-colors"
|
||||
>
|
||||
<svg v-if="store.generating" class="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
@@ -24,7 +24,8 @@
|
||||
<circle cx="15.5" cy="15.5" r="1.5" fill="currentColor" />
|
||||
<circle cx="12" cy="12" r="1.5" fill="currentColor" />
|
||||
</svg>
|
||||
{{ store.generating ? 'Generiere...' : 'Neue Woche generieren' }}
|
||||
<span class="hidden sm:inline">{{ store.generating ? 'Generiere...' : 'Neue Woche generieren' }}</span>
|
||||
<span class="sm:hidden">{{ store.generating ? '...' : 'Neu' }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user