Introduce variant capabilities
All checks were successful
Build and deploy updated apps / Build & deploy (push) Successful in 2m11s

This commit is contained in:
Dominik Milacher 2025-06-14 23:28:00 +02:00
parent f3f668f20e
commit cf76334c38
14 changed files with 54 additions and 26 deletions

View File

@ -26,7 +26,7 @@
<div class="flex justify-end"> <div class="flex justify-end">
<div class="flex flex-row gap-4 "> <div class="flex flex-row gap-4 ">
<UButton <UButton
to="/contact" :to="variantPath('contact')"
size="md" size="md"
color="primary" color="primary"
variant="outline" variant="outline"
@ -36,7 +36,7 @@
</UButton> </UButton>
<UButton <UButton
to="/book" :to="variantPath('book')"
size="md" size="md"
color="primary" color="primary"
variant="solid" variant="solid"
@ -57,4 +57,5 @@ import type {Apartment} from '@/composables/useApartments'
const {t, tm, rt} = useI18n() const {t, tm, rt} = useI18n()
defineProps<{ apartment: Apartment }>() defineProps<{ apartment: Apartment }>()
const { variantPath } = useVariantPath()
</script> </script>

View File

@ -37,7 +37,7 @@
<div class="flex flex-col gap-4 "> <div class="flex flex-col gap-4 ">
<UButton <UButton
to="/contact" :to="variantPath('contact')"
size="md" size="md"
color="primary" color="primary"
variant="solid" variant="solid"
@ -47,7 +47,7 @@
</UButton> </UButton>
<UButton <UButton
to="/book" :to="variantPath('book')"
size="md" size="md"
color="primary" color="primary"
variant="solid" variant="solid"
@ -63,9 +63,9 @@
<div class="pt-4 text-center text-sm text-neutral-600 flex flex-col py-4"> <div class="pt-4 text-center text-sm text-neutral-600 flex flex-col py-4">
<span>&copy; {{ year }} Panoramablick Saalbach</span> <span>&copy; {{ year }} Panoramablick Saalbach</span>
<div> <div>
<NuxtLink to="/legal#imprint" :external="true" class="underline ml-2">Impressum</NuxtLink> <NuxtLink :to="variantPath('legal', 'imprint')" :external="true" class="underline ml-2">Impressum</NuxtLink>
<NuxtLink to="/legal#privacy" :external="true" class="underline ml-2">Datenschutz</NuxtLink> <NuxtLink :to="variantPath('legal', 'privacy')" :external="true" class="underline ml-2">Datenschutz</NuxtLink>
<NuxtLink to="/legal#accessability" :external="true" class="underline ml-2">Barrierefreiheit</NuxtLink> <NuxtLink :to="variantPath('legal', 'accessability')" :external="true" class="underline ml-2">Barrierefreiheit</NuxtLink>
</div> </div>
</div> </div>
</AppStripe> </AppStripe>
@ -75,4 +75,5 @@
<script setup lang="ts"> <script setup lang="ts">
const {t, tm, rt} = useI18n() const {t, tm, rt} = useI18n()
const year = new Date().getFullYear() const year = new Date().getFullYear()
const { variantPath } = useVariantPath()
</script> </script>

View File

@ -3,20 +3,20 @@
<AppStripe> <AppStripe>
<nav class="mx-auto py-4 flex items-center justify-between"> <nav class="mx-auto py-4 flex items-center justify-between">
<!-- your logo / home link --> <!-- your logo / home link -->
<NuxtLink to="/" class="text-xl font-semibold"> <NuxtLink :to="variantPath('/')" class="text-xl font-semibold">
{{ t('header.home') }} {{ t('header.home') }}
</NuxtLink> </NuxtLink>
<!-- nav links --> <!-- nav links -->
<ul class="flex space-x-6"> <ul class="flex space-x-6">
<li> <li>
<NuxtLink to="/apartments">{{ t('header.apartments') }}</NuxtLink> <NuxtLink :to="variantPath('apartments')">{{ t('header.apartments') }}</NuxtLink>
</li> </li>
<li> <li>
<NuxtLink to="/book">{{ t('header.book') }}</NuxtLink> <NuxtLink :to="variantPath('book')">{{ t('header.book') }}</NuxtLink>
</li> </li>
<li> <li>
<NuxtLink to="/contact">{{ t('header.contact') }}</NuxtLink> <NuxtLink :to="variantPath('contact')">{{ t('header.contact') }}</NuxtLink>
</li> </li>
<AppLocaleSwitcher/> <AppLocaleSwitcher/>
</ul> </ul>
@ -27,4 +27,5 @@
<script setup lang="ts"> <script setup lang="ts">
const {t, tm, rt} = useI18n() const {t, tm, rt} = useI18n()
const { variantPath } = useVariantPath()
</script> </script>

View File

@ -1,9 +1,9 @@
{ {
"header": { "header": {
"home": "Landhaus Panoramablick", "home": "Landhaus Panoramablick",
"apartments": "Apartments & Preise", "apartments": "Apartments & Rates",
"book": "Buchen", "book": "Book",
"contact": "Kontakt" "contact": "Contact"
}, },
"footer": { "footer": {
"questions": "Fragen oder Wünsche?", "questions": "Fragen oder Wünsche?",

View File

@ -26,9 +26,11 @@ export default defineNuxtConfig({
hotelId: "test" hotelId: "test"
} }
}, },
generate: { websites: {
routes: [ defaultVariant: 'sumu',
'/legal' variants: [
{ code: 'su', name: 'Summer' },
{ code: 'wi', name: 'Winter' }
] ]
} }
}) })

View File

@ -36,7 +36,7 @@
<p class="text-neutral-700 mb-4 max-w-prose"> <p class="text-neutral-700 mb-4 max-w-prose">
{{ t('contact.online-1') }} {{ t('contact.online-1') }}
<UButton to="/book" variant="outline" trailing-icon="i-heroicons-arrow-right">{{ <UButton :to="variantPath('book')" variant="outline" trailing-icon="i-heroicons-arrow-right">{{
t('contact.online-2') t('contact.online-2')
}} }}
</UButton> </UButton>
@ -97,6 +97,7 @@
<script setup lang="ts"> <script setup lang="ts">
/*TODO form should contain link to privacy statement?*/ /*TODO form should contain link to privacy statement?*/
const {t, tm, rt} = useI18n() const {t, tm, rt} = useI18n()
const { variantPath } = useVariantPath()
import * as v from 'valibot' import * as v from 'valibot'
import type {FormSubmitEvent} from '@nuxt/ui' import type {FormSubmitEvent} from '@nuxt/ui'

View File

@ -27,13 +27,13 @@
</div> </div>
<div class="mt-8 flex gap-4"> <div class="mt-8 flex gap-4">
<UButton to="/apartments" color="primary" variant="solid" size="xl" <UButton :to="variantPath('apartments')" color="primary" variant="solid" size="xl"
trailing-icon="i-heroicons-arrow-right">{{ t('button.apartments') }} trailing-icon="i-heroicons-arrow-right">{{ t('button.apartments') }}
</UButton> </UButton>
<UButton to="/book" color="secondary" variant="solid" size="xl" trailing-icon="i-heroicons-globe-alt"> <UButton :to="variantPath('book')" color="secondary" variant="solid" size="xl" trailing-icon="i-heroicons-globe-alt">
{{ t('button.book') }} {{ t('button.book') }}
</UButton> </UButton>
<UButton to="/contact" color="secondary" variant="solid" size="xl" trailing-icon="i-heroicons-envelope"> <UButton :to="variantPath('contact')" color="secondary" variant="solid" size="xl" trailing-icon="i-heroicons-envelope">
{{ t('button.contact') }} {{ t('button.contact') }}
</UButton> </UButton>
</div> </div>
@ -53,7 +53,7 @@
<!-- Right: Text Content --> <!-- Right: Text Content -->
<AppTitleText i18n-key="landing.highlight"> <AppTitleText i18n-key="landing.highlight">
<UButton :external="true" to="/contact#hosts" color="primary" variant="solid" size="xl" <UButton :external="true" :to="variantPath('contact', 'hosts')" color="primary" variant="solid" size="xl"
trailing-icon="i-heroicons-arrow-right"> trailing-icon="i-heroicons-arrow-right">
{{ {{
t('button.hosts') t('button.hosts')
@ -98,7 +98,7 @@
<AppTitleText i18n-key="landing.apartments"> <AppTitleText i18n-key="landing.apartments">
<div class="flex flex-wrap gap-4 justify-center"> <div class="flex flex-wrap gap-4 justify-center">
<a v-for="apartment in tm('apartments.list')" :href="`/apartments#${rt(apartment.id)}`" <a v-for="apartment in tm('apartments.list')" :href="variantPath('apartments', rt(apartment.id))"
class="relative group block w-60 h-80 overflow-hidden"> class="relative group block w-60 h-80 overflow-hidden">
<img :src="rt(apartment.thumbnail)" alt="Image 1" <img :src="rt(apartment.thumbnail)" alt="Image 1"
class="w-full h-full object-cover transition-transform duration-300 ease-out group-hover:scale-110"/> class="w-full h-full object-cover transition-transform duration-300 ease-out group-hover:scale-110"/>
@ -131,4 +131,5 @@ const images = [
] ]
const {t, tm, rt} = useI18n() const {t, tm, rt} = useI18n()
const { variantPath } = useVariantPath()
</script> </script>

View File

@ -1,4 +1,4 @@
import { defineNuxtModule, createResolver, addComponentsDir } from '@nuxt/kit' import { defineNuxtModule, createResolver, addComponentsDir, addImportsDir } from '@nuxt/kit'
// Module options TypeScript interface definition // Module options TypeScript interface definition
export interface ModuleOptions {} export interface ModuleOptions {}
@ -8,7 +8,13 @@ export default defineNuxtModule<ModuleOptions>({
name: 'websites', name: 'websites',
configKey: 'websites', configKey: 'websites',
}, },
defaults: {}, defaults: {
defaultVariant: "su",
variants: [
{ code: 'su', name: 'Summer' },
{ code: 'wi', name: 'Winter' }
]
},
setup(_options, _nuxt) { setup(_options, _nuxt) {
const resolver = createResolver(import.meta.url) const resolver = createResolver(import.meta.url)
addComponentsDir({ addComponentsDir({
@ -17,5 +23,6 @@ export default defineNuxtModule<ModuleOptions>({
prefix: '', prefix: '',
global: true, global: true,
}) })
}, addImportsDir(resolver.resolve('./runtime/composables'))
}
}) })

View File

@ -0,0 +1,14 @@
export function useVariantPath() {
const localePath = useLocalePath()
const route = useRoute()
function variantPath(page: string, anchor?: string) {
let base = [localePath('/'), route.params.variant ?? '', page].filter(Boolean).join('/')
base = base.replace(/\/{2,}/g, '/')
base = base.replace(/\/+$/, '')
base = base ? base : '/'
return anchor ? `${base}#${anchor}` : base
}
return { variantPath }
}