feat(ui): install shadcn Card; sweep card patterns site-wide
Add the shadcn-vue Card primitive (Card / CardHeader / CardTitle / CardDescription / CardContent / CardFooter) at src/components/ui/card. Replace ~20 hand-rolled "rounded-lg border border-border bg-card …" patterns across nine views with <Card>: - ConceptView (slow-farming pillars) - VisionValuesView (philosophy + pillars + team) - GalleryView (image figure cards) - EventsView (program cards) - SymposiumView (included items + apply steps) - LongStaysView (path cards) - OpportunitiesView (group cards + apply explainers) - AccommodationView (rooms + cabins + exterior items) - ReservationsView (kind cards + contact card) - MarketplaceView (category cards) - HomeView (featured events) For image-bearing cards (events / rooms), use Card + CardContent so the image stays flush at the top of the card and the inner padding lives on the content slot. For clickable cards, the RouterLink wraps the Card so the whole card is the link target. Variants where the card sits on a tinted section (philosophy items on bg-card section, cabins on bg-card section) override Card's default bg-card with bg-background via the class prop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4fcbc22d1c
commit
4cb0fa14a2
18 changed files with 265 additions and 197 deletions
21
src/components/ui/card/Card.vue
Normal file
21
src/components/ui/card/Card.vue
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'rounded-lg border bg-card text-card-foreground shadow-sm',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
14
src/components/ui/card/CardContent.vue
Normal file
14
src/components/ui/card/CardContent.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('p-6 pt-0', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
14
src/components/ui/card/CardDescription.vue
Normal file
14
src/components/ui/card/CardDescription.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p :class="cn('text-sm text-muted-foreground', props.class)">
|
||||
<slot />
|
||||
</p>
|
||||
</template>
|
||||
14
src/components/ui/card/CardFooter.vue
Normal file
14
src/components/ui/card/CardFooter.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex items-center p-6 pt-0', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
14
src/components/ui/card/CardHeader.vue
Normal file
14
src/components/ui/card/CardHeader.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex flex-col gap-y-1.5 p-6', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
18
src/components/ui/card/CardTitle.vue
Normal file
18
src/components/ui/card/CardTitle.vue
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes["class"]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h3
|
||||
:class="
|
||||
cn('text-2xl font-semibold leading-none tracking-tight', props.class)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
</h3>
|
||||
</template>
|
||||
6
src/components/ui/card/index.ts
Normal file
6
src/components/ui/card/index.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export { default as Card } from "./Card.vue"
|
||||
export { default as CardContent } from "./CardContent.vue"
|
||||
export { default as CardDescription } from "./CardDescription.vue"
|
||||
export { default as CardFooter } from "./CardFooter.vue"
|
||||
export { default as CardHeader } from "./CardHeader.vue"
|
||||
export { default as CardTitle } from "./CardTitle.vue"
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
|
||||
const { t, tm, rt } = useI18n()
|
||||
|
||||
|
|
@ -82,41 +83,39 @@ const exteriorItems = tm('accommodation.exterior.items') as string[]
|
|||
<p class="mt-3 text-muted-foreground">{{ t('accommodation.rooms.subtitle') }}</p>
|
||||
</div>
|
||||
<ul class="mt-8 grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<li
|
||||
v-for="room in rooms"
|
||||
:key="room.key"
|
||||
class="overflow-hidden rounded-lg border border-border bg-card"
|
||||
>
|
||||
<img
|
||||
:src="room.image"
|
||||
alt=""
|
||||
class="aspect-[4/3] w-full object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div class="p-5">
|
||||
<div class="flex items-baseline justify-between gap-3">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`accommodation.rooms.${room.key}.name`) }}
|
||||
</h3>
|
||||
<span
|
||||
class="rounded-full px-2 py-0.5 text-[10px] uppercase tracking-wider"
|
||||
:class="
|
||||
room.open
|
||||
? 'bg-primary/10 text-primary'
|
||||
: 'border border-border text-muted-foreground'
|
||||
"
|
||||
>
|
||||
{{
|
||||
room.open
|
||||
? t('accommodation.statusOpen')
|
||||
: t('accommodation.statusComingSoon')
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`accommodation.rooms.${room.key}.summary`) }}
|
||||
</p>
|
||||
</div>
|
||||
<li v-for="room in rooms" :key="room.key">
|
||||
<Card class="overflow-hidden">
|
||||
<img
|
||||
:src="room.image"
|
||||
alt=""
|
||||
class="aspect-[4/3] w-full object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
<CardContent class="p-5 pt-5">
|
||||
<div class="flex items-baseline justify-between gap-3">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`accommodation.rooms.${room.key}.name`) }}
|
||||
</h3>
|
||||
<span
|
||||
class="rounded-full px-2 py-0.5 text-[10px] uppercase tracking-wider"
|
||||
:class="
|
||||
room.open
|
||||
? 'bg-primary/10 text-primary'
|
||||
: 'border border-border text-muted-foreground'
|
||||
"
|
||||
>
|
||||
{{
|
||||
room.open
|
||||
? t('accommodation.statusOpen')
|
||||
: t('accommodation.statusComingSoon')
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`accommodation.rooms.${room.key}.summary`) }}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
|
@ -131,27 +130,25 @@ const exteriorItems = tm('accommodation.exterior.items') as string[]
|
|||
<p class="mt-3 text-muted-foreground">{{ t('accommodation.cabins.subtitle') }}</p>
|
||||
</div>
|
||||
<ul class="mt-8 grid gap-6 md:grid-cols-3">
|
||||
<li
|
||||
v-for="cabin in cabins"
|
||||
:key="cabin.key"
|
||||
class="overflow-hidden rounded-lg border border-border bg-background"
|
||||
>
|
||||
<img
|
||||
:src="cabin.image"
|
||||
alt=""
|
||||
class="aspect-[4/3] w-full object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div class="flex items-baseline justify-between gap-3 p-5">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`accommodation.cabins.${cabin.key}`) }}
|
||||
</h3>
|
||||
<span
|
||||
class="rounded-full border border-border px-2 py-0.5 text-[10px] uppercase tracking-wider text-muted-foreground"
|
||||
>
|
||||
{{ t('accommodation.statusComingSoon') }}
|
||||
</span>
|
||||
</div>
|
||||
<li v-for="cabin in cabins" :key="cabin.key">
|
||||
<Card class="overflow-hidden bg-background">
|
||||
<img
|
||||
:src="cabin.image"
|
||||
alt=""
|
||||
class="aspect-[4/3] w-full object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div class="flex items-baseline justify-between gap-3 p-5">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`accommodation.cabins.${cabin.key}`) }}
|
||||
</h3>
|
||||
<span
|
||||
class="rounded-full border border-border px-2 py-0.5 text-[10px] uppercase tracking-wider text-muted-foreground"
|
||||
>
|
||||
{{ t('accommodation.statusComingSoon') }}
|
||||
</span>
|
||||
</div>
|
||||
</Card>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -166,12 +163,10 @@ const exteriorItems = tm('accommodation.exterior.items') as string[]
|
|||
<p class="mt-3 text-muted-foreground">{{ t('accommodation.exterior.subtitle') }}</p>
|
||||
</div>
|
||||
<ul class="mt-8 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<li
|
||||
v-for="(item, i) in exteriorItems"
|
||||
:key="i"
|
||||
class="rounded-lg border border-dashed border-border bg-secondary/20 p-5 text-sm text-foreground/85"
|
||||
>
|
||||
{{ rt(item) }}
|
||||
<li v-for="(item, i) in exteriorItems" :key="i">
|
||||
<Card class="border-dashed bg-secondary/20 p-5 text-sm text-foreground/85">
|
||||
{{ rt(item) }}
|
||||
</Card>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Card } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -96,18 +97,14 @@ const pillars = [
|
|||
<p class="mt-3 text-muted-foreground">{{ t('concept.slowFarming.body') }}</p>
|
||||
</div>
|
||||
<div class="mt-8 grid gap-6 md:grid-cols-3">
|
||||
<article
|
||||
v-for="p in pillars"
|
||||
:key="p.key"
|
||||
class="rounded-lg border border-border bg-card p-6"
|
||||
>
|
||||
<Card v-for="p in pillars" :key="p.key" class="p-6">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`concept.slowFarming.${p.key}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`concept.slowFarming.${p.key}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -64,28 +65,30 @@ const events = [
|
|||
<component
|
||||
:is="e.to ? 'RouterLink' : 'article'"
|
||||
v-bind="e.to ? { to: e.to } : {}"
|
||||
class="group block h-full overflow-hidden rounded-lg border border-border bg-card transition hover:shadow-md"
|
||||
class="group block h-full"
|
||||
>
|
||||
<img
|
||||
:src="e.image"
|
||||
alt=""
|
||||
class="aspect-[4/3] w-full object-cover transition group-hover:scale-[1.02]"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div class="p-5">
|
||||
<p class="text-xs uppercase tracking-wider text-accent">
|
||||
{{ t(`events.${e.key}.date`) }}
|
||||
</p>
|
||||
<h2 class="mt-1 font-serif text-xl font-semibold">
|
||||
{{ t(`events.${e.key}.title`) }}
|
||||
</h2>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
{{ t(`events.${e.key}.location`) }}
|
||||
</p>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`events.${e.key}.description`) }}
|
||||
</p>
|
||||
</div>
|
||||
<Card class="h-full overflow-hidden transition hover:shadow-md">
|
||||
<img
|
||||
:src="e.image"
|
||||
alt=""
|
||||
class="aspect-[4/3] w-full object-cover transition group-hover:scale-[1.02]"
|
||||
loading="lazy"
|
||||
/>
|
||||
<CardContent class="p-5 pt-5">
|
||||
<p class="text-xs uppercase tracking-wider text-accent">
|
||||
{{ t(`events.${e.key}.date`) }}
|
||||
</p>
|
||||
<h2 class="mt-1 font-serif text-xl font-semibold">
|
||||
{{ t(`events.${e.key}.title`) }}
|
||||
</h2>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
{{ t(`events.${e.key}.location`) }}
|
||||
</p>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`events.${e.key}.description`) }}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</component>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Card } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -47,24 +48,22 @@ const items = [
|
|||
|
||||
<section class="mx-auto max-w-7xl px-4 py-16 lg:px-6">
|
||||
<ul class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<li
|
||||
v-for="item in items"
|
||||
:key="item.key"
|
||||
class="group overflow-hidden rounded-lg border border-border bg-card"
|
||||
>
|
||||
<figure>
|
||||
<img
|
||||
:src="item.src"
|
||||
:alt="t(`gallery.captions.${item.key}`)"
|
||||
class="aspect-square w-full object-cover transition group-hover:scale-[1.02]"
|
||||
loading="lazy"
|
||||
/>
|
||||
<figcaption
|
||||
class="border-t border-border px-4 py-3 font-serif text-sm text-foreground/85"
|
||||
>
|
||||
{{ t(`gallery.captions.${item.key}`) }}
|
||||
</figcaption>
|
||||
</figure>
|
||||
<li v-for="item in items" :key="item.key" class="group">
|
||||
<Card class="overflow-hidden">
|
||||
<figure>
|
||||
<img
|
||||
:src="item.src"
|
||||
:alt="t(`gallery.captions.${item.key}`)"
|
||||
class="aspect-square w-full object-cover transition group-hover:scale-[1.02]"
|
||||
loading="lazy"
|
||||
/>
|
||||
<figcaption
|
||||
class="border-t border-border px-4 py-3 font-serif text-sm text-foreground/85"
|
||||
>
|
||||
{{ t(`gallery.captions.${item.key}`) }}
|
||||
</figcaption>
|
||||
</figure>
|
||||
</Card>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import cosmicStag from '@/assets/cosmic-stag.avif'
|
||||
import heroLandscape from '@/assets/hero-landscape.webp'
|
||||
import sectionTile from '@/assets/section-tile.webp'
|
||||
|
|
@ -192,25 +193,27 @@ const featuredEvents = [
|
|||
v-for="e in featuredEvents"
|
||||
:key="e.key"
|
||||
:to="e.to"
|
||||
class="group overflow-hidden rounded-lg border border-border bg-card transition hover:shadow-md"
|
||||
class="group block"
|
||||
>
|
||||
<img
|
||||
:src="e.image"
|
||||
alt=""
|
||||
class="aspect-[4/3] w-full object-cover transition group-hover:scale-[1.02]"
|
||||
loading="lazy"
|
||||
/>
|
||||
<div class="p-5">
|
||||
<p class="text-xs uppercase tracking-wider text-accent">
|
||||
{{ t(`events.${e.key}.date`) }}
|
||||
</p>
|
||||
<h3 class="mt-2 font-display text-lg uppercase tracking-wider">
|
||||
{{ t(`events.${e.key}.title`) }}
|
||||
</h3>
|
||||
<p class="mt-1 text-xs text-foreground/70">
|
||||
{{ t(`events.${e.key}.location`) }}
|
||||
</p>
|
||||
</div>
|
||||
<Card class="overflow-hidden transition hover:shadow-md">
|
||||
<img
|
||||
:src="e.image"
|
||||
alt=""
|
||||
class="aspect-[4/3] w-full object-cover transition group-hover:scale-[1.02]"
|
||||
loading="lazy"
|
||||
/>
|
||||
<CardContent class="p-5 pt-5">
|
||||
<p class="text-xs uppercase tracking-wider text-accent">
|
||||
{{ t(`events.${e.key}.date`) }}
|
||||
</p>
|
||||
<h3 class="mt-2 font-display text-lg uppercase tracking-wider">
|
||||
{{ t(`events.${e.key}.title`) }}
|
||||
</h3>
|
||||
<p class="mt-1 text-xs text-foreground/70">
|
||||
{{ t(`events.${e.key}.location`) }}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="mt-10 text-center">
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -31,18 +32,14 @@ const paths = ['exchange', 'rental', 'partial', 'funded'] as const
|
|||
{{ t('longStays.pathsTitle') }}
|
||||
</h2>
|
||||
<div class="mt-8 grid gap-6 md:grid-cols-2">
|
||||
<article
|
||||
v-for="key in paths"
|
||||
:key="key"
|
||||
class="rounded-lg border border-border bg-card p-6"
|
||||
>
|
||||
<Card v-for="key in paths" :key="key" class="p-6">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`longStays.paths.${key}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-base leading-relaxed text-foreground/85">
|
||||
{{ t(`longStays.paths.${key}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -28,18 +29,14 @@ const categories = ['fresh', 'pantry', 'craft'] as const
|
|||
{{ t('marketplace.categoriesTitle') }}
|
||||
</h2>
|
||||
<div class="mt-8 grid gap-6 md:grid-cols-3">
|
||||
<article
|
||||
v-for="key in categories"
|
||||
:key="key"
|
||||
class="rounded-lg border border-dashed border-border bg-card p-6"
|
||||
>
|
||||
<Card v-for="key in categories" :key="key" class="border-dashed p-6">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`marketplace.categories.${key}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-base leading-relaxed text-foreground/85">
|
||||
{{ t(`marketplace.categories.${key}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -43,17 +44,15 @@ const applyKeys = ['model', 'window', 'open'] as const
|
|||
<p class="mt-3 text-muted-foreground">{{ t('opportunities.groupsSubtitle') }}</p>
|
||||
</div>
|
||||
<ul class="mt-8 grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<li
|
||||
v-for="key in groups"
|
||||
:key="key"
|
||||
class="rounded-lg border border-border bg-card p-6"
|
||||
>
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`opportunities.groups.${key}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`opportunities.groups.${key}Positions`) }}
|
||||
</p>
|
||||
<li v-for="key in groups" :key="key">
|
||||
<Card class="p-6">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`opportunities.groups.${key}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`opportunities.groups.${key}Positions`) }}
|
||||
</p>
|
||||
</Card>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
|
@ -65,18 +64,14 @@ const applyKeys = ['model', 'window', 'open'] as const
|
|||
{{ t('opportunities.applyTitle') }}
|
||||
</h2>
|
||||
<div class="mt-8 grid gap-6 md:grid-cols-3">
|
||||
<article
|
||||
v-for="key in applyKeys"
|
||||
:key="key"
|
||||
class="rounded-lg border border-border bg-card p-6"
|
||||
>
|
||||
<Card v-for="key in applyKeys" :key="key" class="p-6">
|
||||
<h3 class="font-serif text-lg font-semibold">
|
||||
{{ t(`opportunities.apply.${key}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`opportunities.apply.${key}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
<div class="mt-10 flex flex-wrap items-center gap-3">
|
||||
<Button as-child>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -31,18 +32,14 @@ const kinds = ['weekend', 'retreat', 'gathering', 'residency'] as const
|
|||
{{ t('reservations.kindsTitle') }}
|
||||
</h2>
|
||||
<div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<article
|
||||
v-for="key in kinds"
|
||||
:key="key"
|
||||
class="rounded-lg border border-border bg-card p-6"
|
||||
>
|
||||
<Card v-for="key in kinds" :key="key" class="p-6">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t(`reservations.kinds.${key}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`reservations.kinds.${key}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -87,7 +84,7 @@ const kinds = ['weekend', 'retreat', 'gathering', 'residency'] as const
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="rounded-lg border border-border bg-card p-6 lg:col-span-2">
|
||||
<Card class="p-6 lg:col-span-2">
|
||||
<h3 class="font-serif text-xl font-semibold">
|
||||
{{ t('reservations.contactCard.title') }}
|
||||
</h3>
|
||||
|
|
@ -118,7 +115,7 @@ const kinds = ['weekend', 'retreat', 'gathering', 'residency'] as const
|
|||
<dd class="mt-1">{{ t('reservations.contactCard.openingValue') }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</aside>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -56,18 +57,14 @@ const applySteps = ['stepOne', 'stepTwo', 'stepThree'] as const
|
|||
{{ t('symposium.includedTitle') }}
|
||||
</h2>
|
||||
<div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<article
|
||||
v-for="key in included"
|
||||
:key="key"
|
||||
class="rounded-lg border border-border bg-background p-6"
|
||||
>
|
||||
<Card v-for="key in included" :key="key" class="bg-background p-6">
|
||||
<h3 class="font-serif text-lg font-semibold">
|
||||
{{ t(`symposium.included.${key}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`symposium.included.${key}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -89,17 +86,15 @@ const applySteps = ['stepOne', 'stepTwo', 'stepThree'] as const
|
|||
{{ t('symposium.applyTitle') }}
|
||||
</h2>
|
||||
<ol class="mt-8 grid gap-6 md:grid-cols-3">
|
||||
<li
|
||||
v-for="step in applySteps"
|
||||
:key="step"
|
||||
class="rounded-lg border border-border bg-card p-6"
|
||||
>
|
||||
<h3 class="font-serif text-lg font-semibold">
|
||||
{{ t(`symposium.apply.${step}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`symposium.apply.${step}Body`) }}
|
||||
</p>
|
||||
<li v-for="step in applySteps" :key="step">
|
||||
<Card class="p-6">
|
||||
<h3 class="font-serif text-lg font-semibold">
|
||||
{{ t(`symposium.apply.${step}Title`) }}
|
||||
</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`symposium.apply.${step}Body`) }}
|
||||
</p>
|
||||
</Card>
|
||||
</li>
|
||||
</ol>
|
||||
<div class="mt-10 flex flex-wrap items-center gap-3">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { Card } from '@/components/ui/card'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -55,11 +56,7 @@ const team = ['patrick', 'coco', 'charlie'] as const
|
|||
<p class="mt-3 text-muted-foreground">{{ t('vision.philosophySubtitle') }}</p>
|
||||
</div>
|
||||
<div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-5">
|
||||
<article
|
||||
v-for="(p, i) in philosophy"
|
||||
:key="p"
|
||||
class="rounded-lg border border-border bg-background p-5"
|
||||
>
|
||||
<Card v-for="(p, i) in philosophy" :key="p" class="bg-background p-5">
|
||||
<div class="font-serif text-2xl text-accent">{{ i + 1 }}</div>
|
||||
<h3 class="mt-2 font-serif text-lg font-semibold">
|
||||
{{ t(`vision.philosophy.${p}Title`) }}
|
||||
|
|
@ -67,7 +64,7 @@ const team = ['patrick', 'coco', 'charlie'] as const
|
|||
<p class="mt-2 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`vision.philosophy.${p}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -81,16 +78,12 @@ const team = ['patrick', 'coco', 'charlie'] as const
|
|||
<p class="mt-3 text-muted-foreground">{{ t('vision.pillarsSubtitle') }}</p>
|
||||
</div>
|
||||
<div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||
<article
|
||||
v-for="p in pillars"
|
||||
:key="p"
|
||||
class="rounded-lg border border-border bg-card p-6"
|
||||
>
|
||||
<Card v-for="p in pillars" :key="p" class="p-6">
|
||||
<h3 class="font-serif text-xl font-semibold">{{ t(`vision.pillars.${p}Title`) }}</h3>
|
||||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`vision.pillars.${p}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -101,11 +94,7 @@ const team = ['patrick', 'coco', 'charlie'] as const
|
|||
{{ t('vision.teamTitle') }}
|
||||
</h2>
|
||||
<div class="mt-8 grid gap-6 md:grid-cols-3">
|
||||
<article
|
||||
v-for="m in team"
|
||||
:key="m"
|
||||
class="rounded-lg border border-border bg-card p-6"
|
||||
>
|
||||
<Card v-for="m in team" :key="m" class="p-6">
|
||||
<h3 class="font-serif text-xl font-semibold">{{ t(`vision.team.${m}Name`) }}</h3>
|
||||
<p class="mt-1 text-xs uppercase tracking-wider text-accent">
|
||||
{{ t(`vision.team.${m}Role`) }}
|
||||
|
|
@ -113,7 +102,7 @@ const team = ['patrick', 'coco', 'charlie'] as const
|
|||
<p class="mt-3 text-sm leading-relaxed text-foreground/85">
|
||||
{{ t(`vision.team.${m}Body`) }}
|
||||
</p>
|
||||
</article>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue