From 847b27577b0c1eff175f52ad8093288f74875c31 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 20 May 2026 20:43:16 +0000 Subject: [PATCH 01/12] feat: add community Points of Interest showcase Adds a localised /community-poi overview and detail route so the community can present in-game build projects with status, goal vs. current state, builders, image gallery and Litematica schematic downloads. Each POI is a markdown file under content/community-poi with a typed schema; pages, composables and section components follow the existing types/composables/sections house pattern. https://claude.ai/code/session_01TWED5ZjQD6uv434RqTBaY2 --- .../community-poi/CommunityPoiCard.vue | 120 +++++++++++ .../community-poi/CommunityPoiGallery.vue | 198 ++++++++++++++++++ .../community-poi/CommunityPoiGoalState.vue | 47 +++++ .../community-poi/CommunityPoiGrid.vue | 30 +++ .../community-poi/CommunityPoiMeta.vue | 111 ++++++++++ .../community-poi/CommunityPoiProgressBar.vue | 49 +++++ .../CommunityPoiSchematicList.vue | 77 +++++++ .../community-poi/CommunityPoiStatusBadge.vue | 46 ++++ components/features/navigation/navItems.ts | 1 + composables/useCommunityPoi.ts | 162 ++++++++++++++ content.config.ts | 117 ++++++++--- content/community-poi/de/end-portal-ruine.md | 72 +++++++ content/community-poi/de/spawn-leuchtturm.md | 69 ++++++ .../community-poi/de/wuestenstadt-saqar.md | 61 ++++++ content/community-poi/en/desert-city-saqar.md | 61 ++++++ content/community-poi/en/end-portal-ruin.md | 72 +++++++ content/community-poi/en/spawn-lighthouse.md | 69 ++++++ i18n/locales/de.json | 65 +++++- i18n/locales/en.json | 65 +++++- pages/community-poi/[...slug].vue | 149 +++++++++++++ pages/community-poi/index.vue | 67 ++++++ types/community-poi.ts | 81 +++++++ utils/content/nuxtContentAdapter.ts | 19 ++ utils/content/repository.ts | 12 ++ 24 files changed, 1787 insertions(+), 33 deletions(-) create mode 100644 components/features/community-poi/CommunityPoiCard.vue create mode 100644 components/features/community-poi/CommunityPoiGallery.vue create mode 100644 components/features/community-poi/CommunityPoiGoalState.vue create mode 100644 components/features/community-poi/CommunityPoiGrid.vue create mode 100644 components/features/community-poi/CommunityPoiMeta.vue create mode 100644 components/features/community-poi/CommunityPoiProgressBar.vue create mode 100644 components/features/community-poi/CommunityPoiSchematicList.vue create mode 100644 components/features/community-poi/CommunityPoiStatusBadge.vue create mode 100644 composables/useCommunityPoi.ts create mode 100644 content/community-poi/de/end-portal-ruine.md create mode 100644 content/community-poi/de/spawn-leuchtturm.md create mode 100644 content/community-poi/de/wuestenstadt-saqar.md create mode 100644 content/community-poi/en/desert-city-saqar.md create mode 100644 content/community-poi/en/end-portal-ruin.md create mode 100644 content/community-poi/en/spawn-lighthouse.md create mode 100644 pages/community-poi/[...slug].vue create mode 100644 pages/community-poi/index.vue create mode 100644 types/community-poi.ts diff --git a/components/features/community-poi/CommunityPoiCard.vue b/components/features/community-poi/CommunityPoiCard.vue new file mode 100644 index 0000000..1df4900 --- /dev/null +++ b/components/features/community-poi/CommunityPoiCard.vue @@ -0,0 +1,120 @@ + + + diff --git a/components/features/community-poi/CommunityPoiGallery.vue b/components/features/community-poi/CommunityPoiGallery.vue new file mode 100644 index 0000000..ccd38ad --- /dev/null +++ b/components/features/community-poi/CommunityPoiGallery.vue @@ -0,0 +1,198 @@ + + + diff --git a/components/features/community-poi/CommunityPoiGoalState.vue b/components/features/community-poi/CommunityPoiGoalState.vue new file mode 100644 index 0000000..b4cee0d --- /dev/null +++ b/components/features/community-poi/CommunityPoiGoalState.vue @@ -0,0 +1,47 @@ + + + diff --git a/components/features/community-poi/CommunityPoiGrid.vue b/components/features/community-poi/CommunityPoiGrid.vue new file mode 100644 index 0000000..75f2a1f --- /dev/null +++ b/components/features/community-poi/CommunityPoiGrid.vue @@ -0,0 +1,30 @@ + + + diff --git a/components/features/community-poi/CommunityPoiMeta.vue b/components/features/community-poi/CommunityPoiMeta.vue new file mode 100644 index 0000000..1e123be --- /dev/null +++ b/components/features/community-poi/CommunityPoiMeta.vue @@ -0,0 +1,111 @@ + + + diff --git a/components/features/community-poi/CommunityPoiProgressBar.vue b/components/features/community-poi/CommunityPoiProgressBar.vue new file mode 100644 index 0000000..78fbddc --- /dev/null +++ b/components/features/community-poi/CommunityPoiProgressBar.vue @@ -0,0 +1,49 @@ + + + diff --git a/components/features/community-poi/CommunityPoiSchematicList.vue b/components/features/community-poi/CommunityPoiSchematicList.vue new file mode 100644 index 0000000..a4419bc --- /dev/null +++ b/components/features/community-poi/CommunityPoiSchematicList.vue @@ -0,0 +1,77 @@ + + + diff --git a/components/features/community-poi/CommunityPoiStatusBadge.vue b/components/features/community-poi/CommunityPoiStatusBadge.vue new file mode 100644 index 0000000..aa77ff7 --- /dev/null +++ b/components/features/community-poi/CommunityPoiStatusBadge.vue @@ -0,0 +1,46 @@ + + + diff --git a/components/features/navigation/navItems.ts b/components/features/navigation/navItems.ts index 3f43eb3..4753725 100644 --- a/components/features/navigation/navItems.ts +++ b/components/features/navigation/navItems.ts @@ -21,6 +21,7 @@ export const navConfig: NavConfigEntry[] = [ { type: 'link', textKey: 'navigation.overview', routeName: 'index', icon: ['fas', 'home'] }, { type: 'link', textKey: 'navigation.blog', routeName: 'blog', icon: ['fas', 'file-alt'] }, { type: 'link', textKey: 'navigation.team', routeName: 'team', icon: ['fas', 'users'] }, + { type: 'link', textKey: 'navigation.community_poi', routeName: 'community-poi', icon: ['fas', 'location-dot'] }, { type: 'group', textKey: 'navigation.more', diff --git a/composables/useCommunityPoi.ts b/composables/useCommunityPoi.ts new file mode 100644 index 0000000..e6c2584 --- /dev/null +++ b/composables/useCommunityPoi.ts @@ -0,0 +1,162 @@ +import { createError } from '#imports' +import type { LocaleObject } from 'vue-i18n-routing' +import { useContentRepository } from '~/composables/useContentRepository' +import type { Locale } from '~/utils/content/collections' +import { + COMMUNITY_POI_STATUS_ORDER, + type CommunityPoi, + type CommunityPoiAlternateHeader, + type CommunityPoiStatus +} from '~/types/community-poi' + +const updatedTimestamp = (entry: CommunityPoi): number => { + const raw = entry.updatedAt ?? entry.startedAt + if (!raw) return 0 + const parsed = raw instanceof Date ? raw : new Date(raw) + return Number.isNaN(parsed.getTime()) ? 0 : parsed.getTime() +} + +const slugFromUrl = (url: string): string | undefined => { + try { + const path = url.includes('://') ? new URL(url).pathname : url + return path.split('/').filter(Boolean).at(-1) + } catch { + return url.split('/').filter(Boolean).at(-1) + } +} + +const localeCodeFromHreflang = ( + hreflang: string, + available: LocaleObject[] +): string | undefined => { + const match = available.find((l) => l.code === hreflang || l.iso === hreflang || hreflang.split('-')[0] === l.code) + return match?.code +} + +const normalizeLocales = (list: unknown[]): LocaleObject[] => list + .filter((locale): locale is LocaleObject => Boolean(locale && typeof locale === 'object' && 'code' in (locale as Record))) + .map((locale) => locale as LocaleObject) + +/** + * Loads the community POI overview for the active locale and orders entries + * by status (active projects first), then by most recent update so the page + * shows the freshest community work at the top. + */ +export function useCommunityPoiOverview() { + const { locale } = useI18n() + const repo = useContentRepository() + const activeLocale = computed(() => (locale?.value || 'de') as Locale) + + const { data: pois } = useAsyncData( + () => `community-poi-list-${activeLocale.value}`, + () => repo.listCommunityPois(activeLocale.value), + { watch: [activeLocale] } + ) + + const sorted = computed(() => { + const list = pois.value || [] + return [...list].sort((a, b) => { + const sa = COMMUNITY_POI_STATUS_ORDER[a.status as CommunityPoiStatus] ?? 99 + const sb = COMMUNITY_POI_STATUS_ORDER[b.status as CommunityPoiStatus] ?? 99 + if (sa !== sb) return sa - sb + return updatedTimestamp(b) - updatedTimestamp(a) + }) + }) + + const total = computed(() => sorted.value.length) + + return { pois: sorted, total } +} + +/** + * Loads a single community POI by its catch-all slug param and publishes + * the translated slugs for every available locale, so the i18n language + * switcher resolves to the correct localized URL. + */ +export async function useCommunityPoiDetail() { + const { locale, locales } = useI18n() + const route = useRoute() + const repo = useContentRepository() + const activeLocale = computed(() => (locale?.value || 'de') as Locale) + const availableLocales = computed(() => { + const list = (locales.value || []) as unknown[] + return normalizeLocales(list) + }) + + const setI18nParams = useSetI18nParams() + + const slugSegments = computed(() => { + const params = route.params as Record + const p = params?.slug + if (Array.isArray(p) && p.length) return p.map(String) + if (typeof p === 'string' && p.length > 0) return [p] + const parts = (route.path || '').split('/').filter(Boolean) + const idx = parts.indexOf('community-poi') + if (idx !== -1) return parts.slice(idx + 1) + return [] + }) + + const slug = computed(() => slugSegments.value.at(-1)) + + const { data: poi } = await useAsyncData( + () => `community-poi-${route.path}-${activeLocale.value}`, + async () => { + if (!slug.value) return null + return repo.getCommunityPoiBySlug(activeLocale.value, slug.value) + }, + { watch: [activeLocale, slug] } + ) + + if (slug.value && !poi.value) { + throw createError({ + statusCode: 404, + statusMessage: 'Community POI not found', + fatal: true + }) + } + + const publishLocaleParams = (localeSlugs: Record) => { + const params: Record = {} + for (const [code, value] of Object.entries(localeSlugs)) { + if (value) params[code] = { slug: [value] } + } + if (Object.keys(params).length) setI18nParams(params) + } + + watch([poi, +locale, +locales], async () => { + if (!poi.value) return + const localeSlugs: Record = {} + if (poi.value.slug) localeSlugs[locale.value] = poi.value.slug + + if (poi.value.alternates && Array.isArray(poi.value.alternates)) { + for (const alt of poi.value.alternates as CommunityPoiAlternateHeader[]) { + if (!alt?.hreflang || !alt?.href) continue + const code = localeCodeFromHreflang(alt.hreflang, availableLocales.value) + const altSlug = slugFromUrl(alt.href) + if (code && altSlug) localeSlugs[code] = altSlug + } + publishLocaleParams(localeSlugs) + return + } + + const translationKey = poi.value.translationKey + if (!translationKey) { + publishLocaleParams(localeSlugs) + return + } + + const otherLocales = availableLocales.value.filter((l) => l.code !== locale.value) + for (const other of otherLocales) { + const translated = await repo.getCommunityPoiByTranslationKey( + other.code as Locale, + translationKey + ) + if (translated?.slug) localeSlugs[other.code] = translated.slug + } + publishLocaleParams(localeSlugs) + }, { immediate: true }) + + return { poi } +} diff --git a/content.config.ts b/content.config.ts index e219d4e..a7da664 100644 --- a/content.config.ts +++ b/content.config.ts @@ -7,8 +7,7 @@ import { } from './utils/content/collections' import {asSitemapCollection} from "@nuxtjs/sitemap/content"; -const blogSchema = withI18nMeta( - z.object({ +const blogSchema = withI18nMeta(z.object({ title: z.string(), alternativeTitle: z.string().optional(), description: z.string(), @@ -30,18 +29,15 @@ const blogSchema = withI18nMeta( type: z.string(), children: z.any() }) - }) -) + })) const carouselSchema = z.object({ key: z.string().optional(), slides: z - .array( - z.object({ + .array(z.object({ title: z.string(), image: z.string() - }) - ) + })) .default([]) }) @@ -58,8 +54,7 @@ const timelineSchema = z .object({ key: z.string().optional(), events: z - .array( - z + .array(z .object({ id: z.union([z.string(), z.number()]), title: z.string(), @@ -68,10 +63,13 @@ const timelineSchema = z href: z.string().optional(), icon: z.string().optional(), side: z.enum(['left', 'right']).optional(), - colorVariant: z.enum(['brand', 'accent', 'neutral', 'orange', 'purple']).optional() + colorVariant: z.enum(['brand', +'accent', +'neutral', +'orange', +'purple']).optional() }) - .passthrough() - ) + .passthrough()) .default([]) }) .passthrough() @@ -80,8 +78,7 @@ const teamSchema = z .object({ key: z.string().optional(), members: z - .array( - z + .array(z .object({ id: z.union([z.string(), z.number()]), name: z.string(), @@ -106,8 +103,7 @@ const teamSchema = z // OpenCollective (the donation-funded Lite rank). applyVia: z.enum(['discord', 'opencollective']).optional() }) - .passthrough() - ) + .passthrough()) .default([]) }) .passthrough() @@ -118,16 +114,14 @@ const serverConceptSchema = z title: z.string(), subtitle: z.string().optional(), points: z - .array( - z + .array(z .object({ id: z.union([z.string(), z.number()]), icon: z.string().optional(), title: z.string(), text: z.string() }) - .passthrough() - ) + .passthrough()) .default([]) }) .passthrough() @@ -136,8 +130,7 @@ const sponsorsSchema = z .object({ key: z.string().optional(), sponsors: z - .array( - z + .array(z .object({ name: z.string(), url: z.string().url(), @@ -146,8 +139,7 @@ const sponsorsSchema = z logo: z.string().optional(), icon: z.string().optional() }) - .passthrough() - ) + .passthrough()) .default([]) }) .passthrough() @@ -160,17 +152,75 @@ const faqSchema = z }) .passthrough() +const communityPoiSchema = withI18nMeta(z.object({ + slug: z.string(), + title: z.string(), + summary: z.string(), + status: z.enum([ + 'planning', + 'in-progress', + 'paused', + 'completed' + ]), + progress: z.number().min(0).max(100).default(0), + goal: z.string().optional(), + currentState: z.string().optional(), + location: z.string().optional(), + coordinates: z + .object({ + x: z.number(), + y: z.number().optional(), + z: z.number(), + dimension: z.enum([ + 'overworld', + 'nether', + 'end' + ]).optional() + }) + .optional(), + builders: z + .array(z.object({ + name: z.string(), + mcName: z.string().optional(), + link: z.string().url().optional() + })) + .optional(), + thumbnail: z.string().optional(), + thumbnailAlt: z.string().optional(), + gallery: z + .array(z.object({ + src: z.string(), + alt: z.string(), + caption: z.string().optional(), + width: z.number().int().positive().optional(), + height: z.number().int().positive().optional() + })) + .optional(), + schematics: z + .array(z.object({ + url: z.string(), + name: z.string(), + format: z.enum([ + 'litematic', + 'schem', + 'schematic', + 'nbt' + ]).optional(), + version: z.string().optional(), + sizeLabel: z.string().optional() + })) + .optional(), + startedAt: z.coerce.date().optional(), + updatedAt: z.coerce.date().optional() + })) + export default defineContentConfig({ collections: { - ...defineLocalizedCollections('blog', (locale) => - asSitemapCollection( - asSchemaOrgCollection({ + ...defineLocalizedCollections('blog', (locale) => asSitemapCollection(asSchemaOrgCollection({ type: 'page', source: `blog/${locale}/**/*.md`, schema: blogSchema - }) - ) - ), + }))), ...defineLocalizedCollections('home_carousel', (locale) => ({ type: 'data', source: `carousel/${locale}/home.json`, @@ -211,6 +261,11 @@ export default defineContentConfig({ source: `team-faq/${locale}/*.md`, schema: faqSchema })), + ...defineLocalizedCollections('community_poi', (locale) => asSitemapCollection(asSchemaOrgCollection({ + type: 'page', + source: `community-poi/${locale}/**/*.md`, + schema: communityPoiSchema + }))), authors: defineCollection({ type: 'page', source: 'authors/**/*.md', diff --git a/content/community-poi/de/end-portal-ruine.md b/content/community-poi/de/end-portal-ruine.md new file mode 100644 index 0000000..4659adf --- /dev/null +++ b/content/community-poi/de/end-portal-ruine.md @@ -0,0 +1,72 @@ +--- +slug: 'end-portal-ruine' +translationKey: 'end-portal-ruin' +title: 'End-Portal-Ruine' +summary: 'Eine verwitterte, halb von Wurzeln überwucherte Tempelruine rund um das aktivierte End-Portal – fertig gebaut und für alle besuchbar.' +status: 'completed' +progress: 100 +goal: 'Eine atmosphärische Ruine als würdige Kulisse für den Sprung in den End. Inkl. zugewachsener Pfade, verfallener Statuen und Beleuchtung mit Seelenfeuer.' +currentState: 'Fertig. Portal ist aktiviert, Pfade beleuchtet, kleine Info-Tafel am Eingang erklärt die Story.' +location: 'Wald-Biom, nördlich vom Spawn' +coordinates: + x: -340 + y: 62 + z: -1120 + dimension: 'overworld' +builders: + - name: 'Ravi' + mcName: 'ravi_builds' + - name: 'Nora' + mcName: 'NoraBuilds' +thumbnail: '/community-poi/end-portal-ruine/cover.webp' +thumbnailAlt: 'Tempelruine mit aktivem End-Portal, Wurzeln und Seelenfeuer-Beleuchtung' +gallery: + - src: '/community-poi/end-portal-ruine/gallery-1.webp' + alt: 'Außenansicht der Ruine mit überwachsenen Säulen' + caption: 'Außenansicht' + width: 1600 + height: 900 + - src: '/community-poi/end-portal-ruine/gallery-2.webp' + alt: 'Aktiviertes End-Portal im Innersten der Ruine' + caption: 'Das aktivierte Portal' + width: 1600 + height: 900 + - src: '/community-poi/end-portal-ruine/gallery-3.webp' + alt: 'Pfade mit Seelenfeuer-Lampen zwischen Wurzeln' + caption: 'Nachts mit Seelenfeuer' + width: 1600 + height: 900 + - src: '/community-poi/end-portal-ruine/gallery-4.webp' + alt: 'Verfallene Statue am Eingang der Ruine' + caption: 'Statue am Eingang' + width: 1600 + height: 900 +schematics: + - url: '/community-poi/end-portal-ruine/ruine-komplett.litematic' + name: 'End-Portal-Ruine (komplett)' + format: 'litematic' + version: '1.20.4' + sizeLabel: 'ca. 40 × 18 × 40' + - url: '/community-poi/end-portal-ruine/ruine-statue.litematic' + name: 'Eingangs-Statue' + format: 'litematic' + version: '1.20.4' + sizeLabel: '6 × 9 × 4' +startedAt: '2025-03-04' +updatedAt: '2025-08-18' +alternates: + - hreflang: 'de' + href: 'https://onelitefeather.net/de/community-poi/end-portal-ruine' + - hreflang: 'en' + href: 'https://onelitefeather.net/en/community-poi/end-portal-ruin' + - hreflang: 'x-default' + href: 'https://onelitefeather.net/en/community-poi/end-portal-ruin' +--- + +## Worum geht's? + +Die End-Portal-Ruine ist Anlaufpunkt für jeden, der den Sprung in den End wagen will. Sie steht auf einer kleinen Anhöhe im Wald nördlich vom Spawn und ist über einen Pfad mit Schildern beschildert. + +## Story + +Eine längst vergessene Kultur hat hier einen Tempel gebaut – der Wald hat sich das Gebäude längst zurückgeholt. Im Innersten wartet das aktivierte Portal auf alle, die mutig genug sind, hindurchzuspringen. diff --git a/content/community-poi/de/spawn-leuchtturm.md b/content/community-poi/de/spawn-leuchtturm.md new file mode 100644 index 0000000..aec02a7 --- /dev/null +++ b/content/community-poi/de/spawn-leuchtturm.md @@ -0,0 +1,69 @@ +--- +slug: 'spawn-leuchtturm' +translationKey: 'spawn-lighthouse' +title: 'Leuchtturm am Spawn' +summary: 'Ein 80 Blöcke hoher Leuchtturm aus Quarz und Prismarin direkt am Hauptspawn – als weithin sichtbarer Orientierungspunkt für Neulinge.' +status: 'in-progress' +progress: 65 +goal: 'Vollständiger Leuchtturm mit drehender Laterne, Beacon-Beam und begehbarer Aussichtsplattform auf 70 Blöcken Höhe. Im Inneren eine Wendeltreppe sowie eine kleine Galerie für Server-Meilensteine.' +currentState: 'Sockel und unteres Drittel stehen, Wendeltreppe bis 30 Blöcken eingebaut. Aktuell wird die mittlere Etage mit den Galeriefenstern verkleidet.' +location: 'Spawn, östlicher Hafen' +coordinates: + x: 120 + y: 65 + z: -480 + dimension: 'overworld' +builders: + - name: 'Lina' + mcName: 'LinaBuilds' + - name: 'Mika' + mcName: 'mika_mc' +thumbnail: '/community-poi/spawn-leuchtturm/cover.webp' +thumbnailAlt: 'Aufnahme des Leuchtturms am Spawn vor blauem Himmel' +gallery: + - src: '/community-poi/spawn-leuchtturm/gallery-1.webp' + alt: 'Sockel des Leuchtturms aus Quarz mit Prismarin-Rändern' + caption: 'Sockel und Eingang' + width: 1600 + height: 900 + - src: '/community-poi/spawn-leuchtturm/gallery-2.webp' + alt: 'Wendeltreppe im Inneren des Leuchtturms' + caption: 'Wendeltreppe im ersten Drittel' + width: 1600 + height: 900 + - src: '/community-poi/spawn-leuchtturm/gallery-3.webp' + alt: 'Blick von der noch unfertigen Aussichtsplattform aufs Meer' + caption: 'Aussicht vom oberen Drittel' + width: 1600 + height: 900 +schematics: + - url: '/community-poi/spawn-leuchtturm/leuchtturm-sockel.litematic' + name: 'Leuchtturm – Sockel & Eingang' + format: 'litematic' + version: '1.20.4' + sizeLabel: 'ca. 30 × 30 × 15' + - url: '/community-poi/spawn-leuchtturm/leuchtturm-treppe.litematic' + name: 'Wendeltreppen-Modul' + format: 'litematic' + version: '1.20.4' + sizeLabel: 'ca. 8 × 8 × 30' +startedAt: '2025-09-12' +updatedAt: '2026-05-10' +alternates: + - hreflang: 'de' + href: 'https://onelitefeather.net/de/community-poi/spawn-leuchtturm' + - hreflang: 'en' + href: 'https://onelitefeather.net/en/community-poi/spawn-lighthouse' + - hreflang: 'x-default' + href: 'https://onelitefeather.net/en/community-poi/spawn-lighthouse' +--- + +## Worum geht's? + +Der Leuchtturm am Spawn ist als gemeinsames Community-Projekt gestartet, bei dem alle Mitspieler:innen mitbauen dürfen. Ziel ist ein weithin sichtbarer Orientierungspunkt mit Atmosphäre – kein riesiges Bauwerk, sondern bewusst auf 80 Blöcke begrenzt, damit er aus dem nahen Hafen heraus noch wirkt. + +## Wie kannst du mithelfen? + +- Materialien sammeln: Quarz, Prismarin und Meereslaternen +- Innenausbau der Galerie: Texte und Banner für die Meilensteine +- Lade dir die Schematic herunter und übe den Aufbau auf deinem Plot diff --git a/content/community-poi/de/wuestenstadt-saqar.md b/content/community-poi/de/wuestenstadt-saqar.md new file mode 100644 index 0000000..299af31 --- /dev/null +++ b/content/community-poi/de/wuestenstadt-saqar.md @@ -0,0 +1,61 @@ +--- +slug: 'wuestenstadt-saqar' +translationKey: 'desert-city-saqar' +title: 'Wüstenstadt Saqar' +summary: 'Eine geplante Wüstenstadt mit Marktplatz, Karawanserei und Oase – als zentraler Knotenpunkt im Wüsten-Biom.' +status: 'planning' +progress: 15 +goal: 'Lebendige Wüstenstadt mit ca. 25 Gebäuden im arabisch inspirierten Stil: Marktplatz mit Brunnen, Karawanserei, Moscheen-Ruine, Palmenoase mit Wasserkanälen und Stadtmauer mit Toren.' +currentState: 'Konzeptphase: Layout der Stadtmauer und des Marktplatzes ist gesteckt, erste Test-Häuser im Süden errichtet, um den Stil zu validieren.' +location: 'Wüsten-Biom, ca. 1500 Blöcke östlich vom Spawn' +coordinates: + x: 1840 + y: 70 + z: 220 + dimension: 'overworld' +builders: + - name: 'Saskia' + mcName: 'sandkorn' + - name: 'Joel' + mcName: 'joelbuilds' + - name: 'Tariq' + mcName: 'tariq_mc' +thumbnail: '/community-poi/wuestenstadt-saqar/cover.webp' +thumbnailAlt: 'Konzeptzeichnung der Wüstenstadt Saqar mit Marktplatz und Brunnen' +gallery: + - src: '/community-poi/wuestenstadt-saqar/gallery-1.webp' + alt: 'Steckung der Stadtmauer in der Wüste mit gelben Wollblöcken' + caption: 'Planungsphase mit Wollblöcken' + width: 1600 + height: 900 + - src: '/community-poi/wuestenstadt-saqar/gallery-2.webp' + alt: 'Erstes Testhaus aus Sandstein und Akazienholz' + caption: 'Erster Testbau im Süden' + width: 1600 + height: 900 +schematics: + - url: '/community-poi/wuestenstadt-saqar/saqar-testhaus.litematic' + name: 'Testhaus Sandstein' + format: 'litematic' + version: '1.20.4' + sizeLabel: '12 × 9 × 12' +startedAt: '2026-02-01' +updatedAt: '2026-05-04' +alternates: + - hreflang: 'de' + href: 'https://onelitefeather.net/de/community-poi/wuestenstadt-saqar' + - hreflang: 'en' + href: 'https://onelitefeather.net/en/community-poi/desert-city-saqar' + - hreflang: 'x-default' + href: 'https://onelitefeather.net/en/community-poi/desert-city-saqar' +--- + +## Worum geht's? + +Saqar soll der zentrale Anlaufpunkt im Wüsten-Biom werden – mit Atmosphäre, Geschichte und Platz für Community-Events wie Marktstände und Karawanen-Rollenspiele. Das Projekt steht ganz am Anfang; jede Stilidee, jeder Beitrag zählt. + +## Wie kannst du mithelfen? + +- Beim Materialfarming für Sandstein, Akazienholz und Terrakotta +- Beim Bauen einzelner Häuser nach Stil-Guide +- Mit Ideen für Story-Elemente und Quests rund um die Stadt diff --git a/content/community-poi/en/desert-city-saqar.md b/content/community-poi/en/desert-city-saqar.md new file mode 100644 index 0000000..6237a9b --- /dev/null +++ b/content/community-poi/en/desert-city-saqar.md @@ -0,0 +1,61 @@ +--- +slug: 'desert-city-saqar' +translationKey: 'desert-city-saqar' +title: 'Desert city Saqar' +summary: 'A planned desert city with marketplace, caravanserai and oasis — a central hub in the desert biome.' +status: 'planning' +progress: 15 +goal: 'A lively desert city with around 25 buildings in an Arabic-inspired style: marketplace with fountain, caravanserai, mosque ruin, palm oasis with water channels and a city wall with gates.' +currentState: 'Concept phase: city wall and marketplace layout are pegged out, first test houses built in the south to validate the style.' +location: 'Desert biome, ~1500 blocks east of spawn' +coordinates: + x: 1840 + y: 70 + z: 220 + dimension: 'overworld' +builders: + - name: 'Saskia' + mcName: 'sandkorn' + - name: 'Joel' + mcName: 'joelbuilds' + - name: 'Tariq' + mcName: 'tariq_mc' +thumbnail: '/community-poi/wuestenstadt-saqar/cover.webp' +thumbnailAlt: 'Concept sketch of desert city Saqar with marketplace and fountain' +gallery: + - src: '/community-poi/wuestenstadt-saqar/gallery-1.webp' + alt: 'City wall layout pegged out in the desert with yellow wool blocks' + caption: 'Planning phase with wool markers' + width: 1600 + height: 900 + - src: '/community-poi/wuestenstadt-saqar/gallery-2.webp' + alt: 'First test house built from sandstone and acacia wood' + caption: 'First test build in the south' + width: 1600 + height: 900 +schematics: + - url: '/community-poi/wuestenstadt-saqar/saqar-testhaus.litematic' + name: 'Sandstone test house' + format: 'litematic' + version: '1.20.4' + sizeLabel: '12 × 9 × 12' +startedAt: '2026-02-01' +updatedAt: '2026-05-04' +alternates: + - hreflang: 'de' + href: 'https://onelitefeather.net/de/community-poi/wuestenstadt-saqar' + - hreflang: 'en' + href: 'https://onelitefeather.net/en/community-poi/desert-city-saqar' + - hreflang: 'x-default' + href: 'https://onelitefeather.net/en/community-poi/desert-city-saqar' +--- + +## What is this? + +Saqar is meant to be the central hub of the desert biome — with atmosphere, lore, and space for community events like market stalls and caravan role-play. The project is just kicking off, so every style idea and contribution counts. + +## How can you help? + +- Farming materials: sandstone, acacia wood and terracotta +- Building individual houses following the style guide +- Pitching ideas for story elements and quests set around the city diff --git a/content/community-poi/en/end-portal-ruin.md b/content/community-poi/en/end-portal-ruin.md new file mode 100644 index 0000000..89d4dac --- /dev/null +++ b/content/community-poi/en/end-portal-ruin.md @@ -0,0 +1,72 @@ +--- +slug: 'end-portal-ruin' +translationKey: 'end-portal-ruin' +title: 'End portal ruin' +summary: 'A weathered temple ruin, half overgrown by roots, surrounding an activated End portal — finished and open to everyone.' +status: 'completed' +progress: 100 +goal: 'An atmospheric ruin as a fitting backdrop for the jump into the End. Includes overgrown paths, decaying statues and soul-fire lighting.' +currentState: 'Done. The portal is activated, paths are lit, and a small info plaque at the entrance explains the lore.' +location: 'Forest biome, north of spawn' +coordinates: + x: -340 + y: 62 + z: -1120 + dimension: 'overworld' +builders: + - name: 'Ravi' + mcName: 'ravi_builds' + - name: 'Nora' + mcName: 'NoraBuilds' +thumbnail: '/community-poi/end-portal-ruine/cover.webp' +thumbnailAlt: 'Temple ruin with an active End portal, roots and soul-fire lighting' +gallery: + - src: '/community-poi/end-portal-ruine/gallery-1.webp' + alt: 'Exterior view of the ruin with overgrown columns' + caption: 'Exterior view' + width: 1600 + height: 900 + - src: '/community-poi/end-portal-ruine/gallery-2.webp' + alt: 'Active End portal at the centre of the ruin' + caption: 'The activated portal' + width: 1600 + height: 900 + - src: '/community-poi/end-portal-ruine/gallery-3.webp' + alt: 'Paths lit by soul-fire lanterns between tree roots' + caption: 'At night with soul fire' + width: 1600 + height: 900 + - src: '/community-poi/end-portal-ruine/gallery-4.webp' + alt: 'Decaying statue at the entrance of the ruin' + caption: 'Entrance statue' + width: 1600 + height: 900 +schematics: + - url: '/community-poi/end-portal-ruine/ruine-komplett.litematic' + name: 'End portal ruin (complete)' + format: 'litematic' + version: '1.20.4' + sizeLabel: 'approx. 40 × 18 × 40' + - url: '/community-poi/end-portal-ruine/ruine-statue.litematic' + name: 'Entrance statue' + format: 'litematic' + version: '1.20.4' + sizeLabel: '6 × 9 × 4' +startedAt: '2025-03-04' +updatedAt: '2025-08-18' +alternates: + - hreflang: 'de' + href: 'https://onelitefeather.net/de/community-poi/end-portal-ruine' + - hreflang: 'en' + href: 'https://onelitefeather.net/en/community-poi/end-portal-ruin' + - hreflang: 'x-default' + href: 'https://onelitefeather.net/en/community-poi/end-portal-ruin' +--- + +## What is this? + +The End portal ruin is the place to go for anyone willing to take the leap into the End. It sits on a small hill in the forest north of spawn and is signposted along a path with markers. + +## Lore + +A long-forgotten culture built a temple here — the forest has long since taken the building back. Deep inside, the activated portal waits for anyone brave enough to jump through. diff --git a/content/community-poi/en/spawn-lighthouse.md b/content/community-poi/en/spawn-lighthouse.md new file mode 100644 index 0000000..2d7ff24 --- /dev/null +++ b/content/community-poi/en/spawn-lighthouse.md @@ -0,0 +1,69 @@ +--- +slug: 'spawn-lighthouse' +translationKey: 'spawn-lighthouse' +title: 'Spawn lighthouse' +summary: 'An 80-block tall lighthouse in quartz and prismarine right at the main spawn — a landmark to orient newcomers from far away.' +status: 'in-progress' +progress: 65 +goal: 'A full lighthouse with a rotating lantern, beacon beam and walkable viewing platform at 70 blocks height. Inside: a spiral staircase plus a small gallery showcasing server milestones.' +currentState: 'Base and lower third are complete, spiral staircase built up to block 30. We are currently cladding the middle floor with the gallery windows.' +location: 'Spawn, eastern harbour' +coordinates: + x: 120 + y: 65 + z: -480 + dimension: 'overworld' +builders: + - name: 'Lina' + mcName: 'LinaBuilds' + - name: 'Mika' + mcName: 'mika_mc' +thumbnail: '/community-poi/spawn-leuchtturm/cover.webp' +thumbnailAlt: 'Photo of the spawn lighthouse in front of a blue sky' +gallery: + - src: '/community-poi/spawn-leuchtturm/gallery-1.webp' + alt: 'Lighthouse base built from quartz with prismarine edges' + caption: 'Base and entrance' + width: 1600 + height: 900 + - src: '/community-poi/spawn-leuchtturm/gallery-2.webp' + alt: 'Spiral staircase inside the lighthouse' + caption: 'Spiral staircase in the lower third' + width: 1600 + height: 900 + - src: '/community-poi/spawn-leuchtturm/gallery-3.webp' + alt: 'View of the sea from the unfinished viewing platform' + caption: 'View from the upper third' + width: 1600 + height: 900 +schematics: + - url: '/community-poi/spawn-leuchtturm/leuchtturm-sockel.litematic' + name: 'Lighthouse – base & entrance' + format: 'litematic' + version: '1.20.4' + sizeLabel: 'approx. 30 × 30 × 15' + - url: '/community-poi/spawn-leuchtturm/leuchtturm-treppe.litematic' + name: 'Spiral staircase module' + format: 'litematic' + version: '1.20.4' + sizeLabel: 'approx. 8 × 8 × 30' +startedAt: '2025-09-12' +updatedAt: '2026-05-10' +alternates: + - hreflang: 'de' + href: 'https://onelitefeather.net/de/community-poi/spawn-leuchtturm' + - hreflang: 'en' + href: 'https://onelitefeather.net/en/community-poi/spawn-lighthouse' + - hreflang: 'x-default' + href: 'https://onelitefeather.net/en/community-poi/spawn-lighthouse' +--- + +## What is this? + +The spawn lighthouse is a shared community project: everyone is welcome to help build. The goal is a recognisable landmark with atmosphere — not an enormous structure, but capped at 80 blocks on purpose so it still reads well from the nearby harbour. + +## How can you help? + +- Gather materials: quartz, prismarine, sea lanterns +- Interior decoration of the gallery: texts and banners for milestones +- Grab the schematic and rehearse the build on your plot first diff --git a/i18n/locales/de.json b/i18n/locales/de.json index bfc4584..bb455e7 100644 --- a/i18n/locales/de.json +++ b/i18n/locales/de.json @@ -16,7 +16,8 @@ "change_language": "Sprache ändern", "more": "Mehr", "status": "Status", - "roadmap": "Roadmap" + "roadmap": "Roadmap", + "community_poi": "Community-POIs" }, "carousel": { "prev": "Zurück", @@ -212,5 +213,67 @@ "message_404": "Die gesuchte Seite existiert nicht oder wurde möglicherweise an eine neue Adresse verschoben.", "title_generic": "Etwas ist schiefgelaufen", "message_generic": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuche es gleich noch einmal." + }, + "community_poi": { + "overview": { + "title": "Community Points of Interest", + "description": "Bauprojekte aus unserer Community: Vom Konzept über laufende Baustellen bis zur fertigen Sehenswürdigkeit – mit Fortschritt, Galerie und Litematica-Schematics zum Nachbauen.", + "count": "{count} POIs", + "empty": "Aktuell sind noch keine Community-POIs veröffentlicht. Schau bald wieder rein – oder reiche dein Projekt ein!" + }, + "status": { + "planning": "In Planung", + "in-progress": "Im Bau", + "paused": "Pausiert", + "completed": "Fertig" + }, + "progress": { + "label": "Fortschritt", + "value_text": "{value} Prozent fertiggestellt", + "aria": "Aktueller Baufortschritt" + }, + "goal_state": { + "aria": "Ziel und aktueller Zustand", + "goal": "Ziel", + "current": "Aktueller Zustand" + }, + "meta": { + "aria": "Projekt-Metadaten", + "location": "Ort im Spiel", + "coordinates": "Koordinaten", + "builders": "Beteiligte Builder", + "started": "Begonnen", + "updated": "Zuletzt aktualisiert" + }, + "dimension": { + "overworld": "Oberwelt", + "nether": "Nether", + "end": "End" + }, + "gallery": { + "title": "Bildergalerie", + "aria": "Bildergalerie zum Projekt", + "open_at": "Bild {current} von {total} öffnen", + "prev": "Vorheriges Bild", + "next": "Nächstes Bild", + "close": "Galerie schließen" + }, + "schematics": { + "title": "Litematica-Schematics", + "aria": "Verfügbare Schematics zum Download", + "download": "Herunterladen", + "opens_external": "(öffnet eine externe Seite)", + "hint": "Schematic mit dem Litematica-Mod in Minecraft laden, um den Bau Block für Block nachzubauen." + }, + "card": { + "by": "von", + "builders_more": "{first} + {count} weitere", + "open_detail": "Details zu {title} öffnen", + "gallery_count_sr": "Bilder in der Galerie", + "schematic_count_sr": "Verfügbare Schematics" + }, + "detail": { + "back": "Zur POI-Übersicht" + } } } diff --git a/i18n/locales/en.json b/i18n/locales/en.json index d0501b5..12188fc 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -16,7 +16,8 @@ "change_language": "Change language", "more": "More", "status": "Status", - "roadmap": "Roadmap" + "roadmap": "Roadmap", + "community_poi": "Community POIs" }, "carousel": { "prev": "Previous", @@ -212,5 +213,67 @@ "message_404": "The page you are looking for doesn’t exist or may have moved to a new address.", "title_generic": "Something went wrong", "message_generic": "An unexpected error occurred. Please try again in a moment." + }, + "community_poi": { + "overview": { + "title": "Community Points of Interest", + "description": "Building projects from our community: from concept to active build site to finished landmark — with progress, image galleries and Litematica schematics to rebuild them yourself.", + "count": "{count} POIs", + "empty": "No community POIs published yet. Check back soon — or submit your own project!" + }, + "status": { + "planning": "Planned", + "in-progress": "In progress", + "paused": "Paused", + "completed": "Completed" + }, + "progress": { + "label": "Progress", + "value_text": "{value} percent complete", + "aria": "Current build progress" + }, + "goal_state": { + "aria": "Goal and current state", + "goal": "Goal", + "current": "Current state" + }, + "meta": { + "aria": "Project metadata", + "location": "In-game location", + "coordinates": "Coordinates", + "builders": "Builders involved", + "started": "Started", + "updated": "Last updated" + }, + "dimension": { + "overworld": "Overworld", + "nether": "Nether", + "end": "End" + }, + "gallery": { + "title": "Image gallery", + "aria": "Project image gallery", + "open_at": "Open image {current} of {total}", + "prev": "Previous image", + "next": "Next image", + "close": "Close gallery" + }, + "schematics": { + "title": "Litematica schematics", + "aria": "Available schematic downloads", + "download": "Download", + "opens_external": "(opens an external site)", + "hint": "Load the schematic with the Litematica mod in Minecraft to rebuild the project block by block." + }, + "card": { + "by": "by", + "builders_more": "{first} + {count} more", + "open_detail": "Open details for {title}", + "gallery_count_sr": "Images in gallery", + "schematic_count_sr": "Available schematics" + }, + "detail": { + "back": "Back to POI overview" + } } } diff --git a/pages/community-poi/[...slug].vue b/pages/community-poi/[...slug].vue new file mode 100644 index 0000000..9a859fe --- /dev/null +++ b/pages/community-poi/[...slug].vue @@ -0,0 +1,149 @@ + + + diff --git a/pages/community-poi/index.vue b/pages/community-poi/index.vue new file mode 100644 index 0000000..d658761 --- /dev/null +++ b/pages/community-poi/index.vue @@ -0,0 +1,67 @@ + + + diff --git a/types/community-poi.ts b/types/community-poi.ts new file mode 100644 index 0000000..b746679 --- /dev/null +++ b/types/community-poi.ts @@ -0,0 +1,81 @@ +import type { + CommunityPoiDeCollectionItem, + CommunityPoiEnCollectionItem +} from '@nuxt/content' + +export const COMMUNITY_POI_STATUSES = [ + 'planning', + 'in-progress', + 'paused', + 'completed' +] as const +export type CommunityPoiStatus = (typeof COMMUNITY_POI_STATUSES)[number] + +// Status order used for sorting on the overview page (in-progress first +// because that's where the community can still help; completed last). +export const COMMUNITY_POI_STATUS_ORDER: Record = { + 'in-progress': 0, + planning: 1, + paused: 2, + completed: 3 +} + +export interface CommunityPoiBuilder { + name: string + mcName?: string + link?: string +} + +export interface CommunityPoiImage { + src: string + alt: string + caption?: string + width?: number + height?: number +} + +export interface CommunityPoiSchematic { + url: string + name: string + format?: 'litematic' | 'schem' | 'schematic' | 'nbt' + version?: string + sizeLabel?: string +} + +export interface CommunityPoiCoordinates { + x: number + y?: number + z: number + dimension?: 'overworld' | 'nether' | 'end' +} + +export interface CommunityPoiAlternateHeader { + hreflang: string + href: string +} + +export type CommunityPoi = ( + | CommunityPoiDeCollectionItem + | CommunityPoiEnCollectionItem +) & { + slug: string + translationKey?: string + title: string + summary: string + status: CommunityPoiStatus + progress: number + goal?: string + currentState?: string + builders?: CommunityPoiBuilder[] + location?: string + coordinates?: CommunityPoiCoordinates + thumbnail?: string + thumbnailAlt?: string + gallery?: CommunityPoiImage[] + schematics?: CommunityPoiSchematic[] + startedAt?: string | Date + updatedAt?: string | Date + canonical?: string + alternates?: CommunityPoiAlternateHeader[] + head?: Record +} diff --git a/utils/content/nuxtContentAdapter.ts b/utils/content/nuxtContentAdapter.ts index acb1b20..ff7dc8b 100644 --- a/utils/content/nuxtContentAdapter.ts +++ b/utils/content/nuxtContentAdapter.ts @@ -10,6 +10,7 @@ import type { HomeCarouselDocument } from '~/types/home' import type { SponsorsDocument } from '~/types/sponsoring' +import type { CommunityPoi } from '~/types/community-poi' // The `authors` collection is declared in `content.config.ts`, so its types // are generated by @nuxt/content — no module augmentation needed here. @@ -24,6 +25,7 @@ const sponsorsKey = (locale: Locale) => `sponsors_${locale}` as 'sponsors_de' | const serverConceptKey = (locale: Locale) => `server_concept_${locale}` as 'server_concept_de' | 'server_concept_en' const serverConnectKey = (locale: Locale) => `server_connect_${locale}` as 'server_connect_de' | 'server_connect_en' const homeCarouselKey = (locale: Locale) => `home_carousel_${locale}` as 'home_carousel_de' | 'home_carousel_en' +const communityPoiKey = (locale: Locale) => `community_poi_${locale}` as 'community_poi_de' | 'community_poi_en' /** * The @nuxt/content-backed {@link ContentRepository} implementation. Every @@ -92,6 +94,23 @@ export function createNuxtContentAdapter(): ContentRepository { getSponsorsDocument(locale) { return queryCollection(sponsorsKey(locale)) .first() as Promise + }, + + listCommunityPois(locale) { + return queryCollection(communityPoiKey(locale)) + .all() as Promise + }, + + getCommunityPoiBySlug(locale, slug) { + return queryCollection(communityPoiKey(locale)) + .where('slug', '=', slug) + .first() as Promise + }, + + getCommunityPoiByTranslationKey(locale, translationKey) { + return queryCollection(communityPoiKey(locale)) + .where('translationKey', '=', translationKey) + .first() as Promise } } } diff --git a/utils/content/repository.ts b/utils/content/repository.ts index 64786e3..bddbbcf 100644 --- a/utils/content/repository.ts +++ b/utils/content/repository.ts @@ -8,6 +8,7 @@ import type { HomeCarouselDocument } from '~/types/home' import type { SponsorsDocument } from '~/types/sponsoring' +import type { CommunityPoi } from '~/types/community-poi' /** * Provider-agnostic content access layer. @@ -54,4 +55,15 @@ export interface ContentRepository { // --- Sponsoring ----------------------------------------------------------- getSponsorsDocument(locale: Locale): Promise + + // --- Community POI -------------------------------------------------------- + /** All community POIs for a locale (unfiltered, unsorted — caller decides). */ + listCommunityPois(locale: Locale): Promise + /** Single POI by its `slug` frontmatter field, or null. */ + getCommunityPoiBySlug(locale: Locale, slug: string): Promise + /** Single POI in `locale` sharing the given `translationKey`, or null. */ + getCommunityPoiByTranslationKey( + locale: Locale, + translationKey: string + ): Promise } From e66b34336b4528c7048e869cecd19461351a3f9c Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 20 May 2026 21:04:51 +0000 Subject: [PATCH 02/12] feat: feature POIs in carousel, add categories, lore and Litematica setup guide Builds on the community POI showcase with the cross-linking and authorship cues we were missing: - Carousel now picks up POIs flagged `featured: true` and renders them via a new `poi` slide type that deep-links to the detail page. - POIs gain a `category` (team / community / collab) with a coloured badge on card and detail, so visitors can tell at a glance who built what. - Optional `lore` frontmatter renders as a styled callout for POIs with a backstory; POIs without one simply skip the section. - Each schematic can carry an `origin`, `facing` and `setupNotes` so the placement guide shows up directly next to the download button, paired with a reusable Litematica install / usage FAQ accordion. https://claude.ai/code/session_01TWED5ZjQD6uv434RqTBaY2 --- .../community-poi/CommunityPoiCard.vue | 4 +- .../CommunityPoiCategoryBadge.vue | 39 +++++++ .../CommunityPoiLitematicaHelp.vue | 63 ++++++++++ .../community-poi/CommunityPoiLore.vue | 29 +++++ .../CommunityPoiSchematicList.vue | 37 ++++++ .../features/home/carousel/Carousel.vue | 22 ++-- .../home/carousel/items/CarouselItemPoi.vue | 108 ++++++++++++++++++ composables/useCarousel.ts | 23 +++- composables/useHomeContent.ts | 43 ++++++- content.config.ts | 22 +++- content/community-poi/de/end-portal-ruine.md | 18 +++ content/community-poi/de/spawn-leuchtturm.md | 16 +++ .../community-poi/de/wuestenstadt-saqar.md | 7 ++ content/community-poi/en/desert-city-saqar.md | 7 ++ content/community-poi/en/end-portal-ruin.md | 18 +++ content/community-poi/en/spawn-lighthouse.md | 16 +++ i18n/locales/de.json | 57 ++++++++- i18n/locales/en.json | 57 ++++++++- pages/community-poi/[...slug].vue | 9 +- types/carousel.ts | 27 ++++- types/community-poi.ts | 24 ++++ 21 files changed, 629 insertions(+), 17 deletions(-) create mode 100644 components/features/community-poi/CommunityPoiCategoryBadge.vue create mode 100644 components/features/community-poi/CommunityPoiLitematicaHelp.vue create mode 100644 components/features/community-poi/CommunityPoiLore.vue create mode 100644 components/features/home/carousel/items/CarouselItemPoi.vue diff --git a/components/features/community-poi/CommunityPoiCard.vue b/components/features/community-poi/CommunityPoiCard.vue index 1df4900..64d32b0 100644 --- a/components/features/community-poi/CommunityPoiCard.vue +++ b/components/features/community-poi/CommunityPoiCard.vue @@ -1,6 +1,7 @@ + + diff --git a/components/features/community-poi/CommunityPoiLitematicaHelp.vue b/components/features/community-poi/CommunityPoiLitematicaHelp.vue new file mode 100644 index 0000000..1c1226a --- /dev/null +++ b/components/features/community-poi/CommunityPoiLitematicaHelp.vue @@ -0,0 +1,63 @@ + + + diff --git a/components/features/community-poi/CommunityPoiLore.vue b/components/features/community-poi/CommunityPoiLore.vue new file mode 100644 index 0000000..61f1f07 --- /dev/null +++ b/components/features/community-poi/CommunityPoiLore.vue @@ -0,0 +1,29 @@ + + + diff --git a/components/features/community-poi/CommunityPoiSchematicList.vue b/components/features/community-poi/CommunityPoiSchematicList.vue index a4419bc..67cb29e 100644 --- a/components/features/community-poi/CommunityPoiSchematicList.vue +++ b/components/features/community-poi/CommunityPoiSchematicList.vue @@ -28,6 +28,16 @@ const downloadClass = [ 'focus-visible:ring-[var(--color-brand-secondary,#6366f1)] focus-visible:ring-offset-2', 'focus-visible:ring-offset-white dark:focus-visible:ring-offset-neutral-900' ].join(' ') + +const setupClass = [ + 'mt-3 rounded-md bg-neutral-50 p-3 text-xs', 'text-neutral-700 dark:bg-neutral-800/60 dark:text-neutral-300' +].join(' ') + +const setupTitleClass = [ + 'font-semibold uppercase tracking-wide text-[10px]', 'text-neutral-500 dark:text-neutral-400' +].join(' ') + +const facingLabel = (facing?: CommunityPoiSchematic['facing']) => facing ? t(`community_poi.facing.${facing}`) : ''