basicstack.org/pages/infrastructure/[slug].vue
Paperclip CTO a7bd527793 Initial commit: Move basicstack.org frontend to Forgejo
Migrate the Nuxt 3 + Vue 3 SSR frontend application for basicstack.org to our self-hosted Forgejo instance. This repository will serve as the source for all future development and deployment of the basicstack.org website.

The application includes:
- Nuxt 3 + Vue 3 SSR setup
- Directus CMS integration
- Tailwind CSS styling
- Kubernetes deployment manifests
- Docker containerization

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-28 12:32:23 +00:00

86 lines
1.9 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div v-if="item" class="infra-detail">
<div class="page-header">
<div class="container">
<NuxtLink to="/infrastructure" class="breadcrumb"> Infrastructure</NuxtLink>
<span class="badge badge-primary">{{ categoryLabels[item.category] ?? item.category }}</span>
<h1>{{ item.title }}</h1>
<p v-if="item.summary" class="summary">{{ item.summary }}</p>
</div>
</div>
<div class="container page-body">
<div class="prose" v-html="item.content" />
</div>
</div>
<div v-else class="not-found container">
<h1>Not found</h1>
<NuxtLink to="/infrastructure" class="btn btn-primary">Back to Infrastructure</NuxtLink>
</div>
</template>
<script setup lang="ts">
const route = useRoute()
const { getInfrastructureItem } = useDirectus()
const { data: item } = await useAsyncData(`infra-${route.params.slug}`, () =>
getInfrastructureItem(route.params.slug as string)
)
const categoryLabels: Record<string, string> = {
hosting: 'Hosting',
security: 'Security',
monitoring: 'Monitoring',
backup: 'Backup',
disaster_recovery: 'Disaster Recovery',
}
if (item.value) {
useSeoMeta({
title: `${item.value.title} BasicStack`,
description: item.value.summary ?? undefined,
})
}
</script>
<style scoped>
.page-header {
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
padding: var(--space-2xl) 0;
}
.breadcrumb {
color: var(--color-text-muted);
font-size: 0.875rem;
display: block;
margin-bottom: var(--space-lg);
}
.page-header .badge {
display: inline-block;
margin-bottom: var(--space-md);
}
.page-header h1 {
margin-bottom: var(--space-sm);
}
.summary {
color: var(--color-text-muted);
font-size: 1.0625rem;
margin: 0;
max-width: 65ch;
}
.page-body {
padding: var(--space-2xl) var(--space-lg);
max-width: 768px;
}
.not-found {
padding: var(--space-3xl) var(--space-lg);
text-align: center;
}
</style>