basicstack.org/pages/infrastructure/index.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

154 lines
3.7 KiB
Vue
Raw 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 class="infra-page">
<div class="page-header">
<div class="container">
<h1>Infrastructure</h1>
<p>How BasicStack is hosted, secured, monitored, and maintained</p>
</div>
</div>
<div class="container page-body">
<div v-if="grouped && Object.keys(grouped).length > 0">
<section
v-for="(items, category) in grouped"
:key="category"
class="category-section"
>
<h2 class="category-title">{{ categoryLabels[category] ?? category }}</h2>
<div class="infra-grid">
<NuxtLink
v-for="item in items"
:key="item.id"
:to="item.slug ? `/infrastructure/${item.slug}` : '#'"
class="infra-card card"
>
<h3>{{ item.title }}</h3>
<p v-if="item.summary" class="item-summary">{{ item.summary }}</p>
<span class="read-more">Read more </span>
</NuxtLink>
</div>
</section>
</div>
<div v-else class="empty">
<p>Infrastructure documentation coming soon.</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const { getInfrastructure } = useDirectus()
const { data: infrastructure } = await useAsyncData('infrastructure', () => getInfrastructure())
const categoryLabels: Record<string, string> = {
hosting: 'Hosting',
security: 'Security & Encryption',
monitoring: 'Monitoring',
backup: 'Backup',
disaster_recovery: 'Disaster Recovery',
}
const categoryOrder = ['hosting', 'security', 'monitoring', 'backup', 'disaster_recovery']
const grouped = computed(() => {
if (!infrastructure.value) return {}
const groups: Record<string, typeof infrastructure.value> = {}
for (const item of infrastructure.value) {
if (!groups[item.category]) groups[item.category] = []
groups[item.category].push(item)
}
const ordered: Record<string, typeof infrastructure.value> = {}
for (const cat of categoryOrder) {
if (groups[cat]) ordered[cat] = groups[cat]
}
for (const cat of Object.keys(groups)) {
if (!ordered[cat]) ordered[cat] = groups[cat]
}
return ordered
})
useSeoMeta({
title: 'Infrastructure BasicStack',
description: 'Learn about how BasicStack infrastructure is hosted, secured, and maintained on Hetzner Cloud.',
})
</script>
<style scoped>
.page-header {
background: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
padding: var(--space-2xl) 0;
}
.page-header p {
color: var(--color-text-muted);
margin: var(--space-sm) 0 0;
}
.page-body {
padding: var(--space-2xl) var(--space-lg);
}
.category-section {
margin-bottom: var(--space-3xl);
}
.category-title {
font-size: 1.25rem;
margin-bottom: var(--space-lg);
color: var(--color-text-muted);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
font-size: 0.875rem;
}
.infra-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: var(--space-lg);
}
.infra-card {
text-decoration: none;
color: inherit;
transition: box-shadow 0.2s;
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.infra-card:hover {
box-shadow: var(--shadow-md);
text-decoration: none;
}
.infra-card h3 {
font-size: 1.0625rem;
margin: 0;
}
.item-summary {
color: var(--color-text-muted);
font-size: 0.9375rem;
margin: 0;
flex: 1;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.read-more {
font-size: 0.875rem;
color: var(--color-primary);
margin-top: auto;
}
.empty {
text-align: center;
padding: var(--space-3xl) 0;
color: var(--color-text-muted);
}
</style>