mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 21:41:09 +02:00
feat(landing): add devlog section to ManaCore landing page
- Add devlog content collection with schema for development reports - Create devlog index page with card-based post listing - Create devlog detail page with prose styling for markdown content - Add first devlog entry: Production Launch (2026-01-23) - Add devlog link to navbar navigation - Add i18n translations for devlog in all languages (de, en, it, fr, es) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b8a84edfe0
commit
2596cb7540
6 changed files with 632 additions and 0 deletions
|
|
@ -21,6 +21,7 @@ const navLinks = [
|
|||
{ href: getLocalizedRoute('/apps', lang), label: t('nav.apps') },
|
||||
{ href: getLocalizedRoute('/pricing', lang), label: t('nav.pricing') },
|
||||
{ href: getLocalizedRoute('/clients', lang), label: t('nav.references') },
|
||||
{ href: getLocalizedRoute('/devlog', lang), label: t('nav.devlog') },
|
||||
{ href: getLocalizedRoute('/privacy', lang), label: t('nav.privacy') },
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -142,6 +142,21 @@ const contextCollection = defineCollection({
|
|||
}),
|
||||
});
|
||||
|
||||
const devlogCollection = defineCollection({
|
||||
type: 'content',
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
date: z.date(),
|
||||
author: z.string().default('Till Schneider'),
|
||||
category: z.enum(['release', 'infrastructure', 'feature', 'bugfix', 'update']),
|
||||
tags: z.array(z.string()).optional(),
|
||||
featured: z.boolean().default(false),
|
||||
commits: z.number().optional(),
|
||||
readTime: z.number().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = {
|
||||
apps: appsCollection,
|
||||
branchen: targetGroupsCollection,
|
||||
|
|
@ -150,4 +165,5 @@ export const collections = {
|
|||
clients: clientsCollection,
|
||||
mission: missionCollection,
|
||||
context: contextCollection,
|
||||
devlog: devlogCollection,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,169 @@
|
|||
---
|
||||
title: 'Production Launch: 6 Apps Live auf mana.how'
|
||||
description: 'Mac Mini Server Setup, Contacts App Deployment, Monitoring Stack und Landing Pages - ein produktiver Tag mit 26 Commits'
|
||||
date: 2026-01-23
|
||||
author: 'Till Schneider'
|
||||
category: 'release'
|
||||
tags: ['deployment', 'docker', 'monitoring', 'mac-mini', 'contacts', 'infrastructure']
|
||||
featured: true
|
||||
commits: 26
|
||||
readTime: 8
|
||||
---
|
||||
|
||||
Heute war ein sehr produktiver Tag mit Fokus auf die **Produktivstellung der ManaCore Apps auf dem Mac Mini Server**. Die wichtigsten Errungenschaften:
|
||||
|
||||
- **6 Apps live** auf https://mana.how (Auth, Dashboard, Chat, Todo, Calendar, Clock)
|
||||
- **Contacts App** vollständig deployed (Backend + Web)
|
||||
- **Monitoring Stack** eingerichtet (Prometheus, Grafana, Umami Analytics)
|
||||
- **Notification System** für Health Checks (Telegram + Email)
|
||||
- **Shared Landing UI** für einheitliche Landing Pages
|
||||
|
||||
---
|
||||
|
||||
## Mac Mini Server Setup & Management
|
||||
|
||||
### Auto-Start System
|
||||
|
||||
Einrichtung eines vollständigen Auto-Start-Systems für den Mac Mini Server:
|
||||
|
||||
- **LaunchAgent** für automatischen Start beim Boot
|
||||
- **Management Scripts:**
|
||||
- `start-manacore.sh` - Startet alle Docker Container
|
||||
- `stop-manacore.sh` - Stoppt alle Container
|
||||
- `health-check.sh` - Prüft alle Services
|
||||
- `update-images.sh` - Aktualisiert Docker Images
|
||||
|
||||
### Notification System
|
||||
|
||||
Implementierung eines Benachrichtigungssystems:
|
||||
|
||||
- **Telegram Bot** für sofortige Alerts
|
||||
- **Email Backup** via Gmail SMTP (msmtp)
|
||||
- Automatische Benachrichtigung bei Service-Ausfällen
|
||||
|
||||
---
|
||||
|
||||
## Contacts App Deployment
|
||||
|
||||
### Docker Images erstellt
|
||||
|
||||
Erstellung der Docker-Konfiguration für Contacts:
|
||||
|
||||
- `apps/contacts/apps/backend/Dockerfile` (Port 3015)
|
||||
- `apps/contacts/apps/web/Dockerfile` (Port 5184)
|
||||
- `docker-entrypoint.sh` für automatische DB-Migrationen
|
||||
- CI Workflow Updates für Image-Builds
|
||||
|
||||
### MinIO Object Storage
|
||||
|
||||
Einrichtung von MinIO für S3-kompatiblen Object Storage:
|
||||
|
||||
- MinIO Container in docker-compose.macmini.yml
|
||||
- `contacts-photos` Bucket für Kontaktbilder
|
||||
- S3 Environment Variables konfiguriert
|
||||
|
||||
**Live URLs:**
|
||||
|
||||
- https://contacts.mana.how (Web App)
|
||||
- https://contacts-api.mana.how (Backend API)
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Analytics Stack
|
||||
|
||||
Vollständiger Monitoring Stack eingerichtet:
|
||||
|
||||
| Service | Port | Beschreibung |
|
||||
| --------------------- | ---- | ------------------ |
|
||||
| **Prometheus** | 9090 | Metriken-Sammlung |
|
||||
| **Grafana** | 3100 | grafana.mana.how |
|
||||
| **Node Exporter** | 9100 | System-Metriken |
|
||||
| **cAdvisor** | 8080 | Container-Metriken |
|
||||
| **Postgres Exporter** | 9187 | Datenbank-Metriken |
|
||||
| **Redis Exporter** | 9121 | Cache-Metriken |
|
||||
| **Umami** | 3200 | analytics.mana.how |
|
||||
|
||||
### Umami Analytics Integration
|
||||
|
||||
Integration von Umami Web Analytics in alle Apps:
|
||||
|
||||
- Unique Website IDs für jede App
|
||||
- Tracking Script in allen Web Apps und Landing Pages
|
||||
- URL geändert zu stats.mana.how
|
||||
|
||||
---
|
||||
|
||||
## Landing Pages & Shared Components
|
||||
|
||||
### Shared Landing UI
|
||||
|
||||
Neues Package `@manacore/shared-landing-ui` mit wiederverwendbaren Astro-Komponenten:
|
||||
|
||||
- `Hero.astro` - Hero Section
|
||||
- `Features.astro` - Feature Grid
|
||||
- `Pricing.astro` - Preistabellen
|
||||
- `CTA.astro` - Call-to-Action
|
||||
- `Footer.astro` - Footer
|
||||
- `Layout.astro` - Base Layout
|
||||
|
||||
### Zentrales Pricing System
|
||||
|
||||
Einheitliches Pricing für alle Mana Apps:
|
||||
|
||||
| Plan | Preis | Features |
|
||||
| ---- | ----------- | ------------------------------- |
|
||||
| Free | 0€ | Basis-Features, limitiert |
|
||||
| Pro | 4,99€/Monat | Alle Features, unbegrenzt |
|
||||
| Team | 9,99€/Monat | Team-Features, Priority Support |
|
||||
|
||||
---
|
||||
|
||||
## Infrastruktur-Übersicht
|
||||
|
||||
### Aktive Services auf Mac Mini
|
||||
|
||||
| Service | Container | Port | Status |
|
||||
| ---------------- | ------------------- | --------- | ------ |
|
||||
| PostgreSQL | manacore-postgres | 5432 | ✅ |
|
||||
| Redis | manacore-redis | 6379 | ✅ |
|
||||
| MinIO | manacore-minio | 9000/9001 | ✅ |
|
||||
| Auth | mana-core-auth | 3001 | ✅ |
|
||||
| Dashboard | manacore-web | 5173 | ✅ |
|
||||
| Chat Backend | chat-backend | 3002 | ✅ |
|
||||
| Chat Web | chat-web | 3000 | ✅ |
|
||||
| Todo Backend | todo-backend | 3018 | ✅ |
|
||||
| Todo Web | todo-web | 5188 | ✅ |
|
||||
| Calendar Backend | calendar-backend | 3016 | ✅ |
|
||||
| Calendar Web | calendar-web | 5186 | ✅ |
|
||||
| Clock Backend | clock-backend | 3017 | ✅ |
|
||||
| Clock Web | clock-web | 5187 | ✅ |
|
||||
| Contacts Backend | contacts-backend | 3015 | ✅ |
|
||||
| Contacts Web | contacts-web | 5184 | ✅ |
|
||||
| Prometheus | manacore-prometheus | 9090 | ✅ |
|
||||
| Grafana | manacore-grafana | 3100 | ✅ |
|
||||
| Umami | manacore-umami | 3200 | ✅ |
|
||||
|
||||
### Live URLs
|
||||
|
||||
| App | Web | API |
|
||||
| --------- | ------------------------- | ----------------------------- |
|
||||
| Dashboard | https://mana.how | - |
|
||||
| Auth | - | https://auth.mana.how |
|
||||
| Chat | https://chat.mana.how | https://chat-api.mana.how |
|
||||
| Todo | https://todo.mana.how | https://todo-api.mana.how |
|
||||
| Calendar | https://calendar.mana.how | https://calendar-api.mana.how |
|
||||
| Clock | https://clock.mana.how | https://clock-api.mana.how |
|
||||
| Contacts | https://contacts.mana.how | https://contacts-api.mana.how |
|
||||
| Grafana | https://grafana.mana.how | - |
|
||||
| Analytics | https://stats.mana.how | - |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. **DNS konfigurieren** für mana.how Domain
|
||||
2. **SSL Zertifikate** einrichten (Caddy/Let's Encrypt)
|
||||
3. **Grafana Dashboards** erstellen
|
||||
4. **Backup-Strategie** implementieren
|
||||
5. **Mobile Apps** testen mit neuen APIs
|
||||
6. **Landing Pages** auf Cloudflare Pages deployen
|
||||
|
|
@ -34,6 +34,7 @@ export const ui = {
|
|||
'nav.forWhom': 'Für wen?',
|
||||
'nav.references': 'Referenzen',
|
||||
'nav.privacy': 'Datenschutz',
|
||||
'nav.devlog': 'Devlog',
|
||||
|
||||
// Buttons
|
||||
'button.startFree': 'Kostenlos testen',
|
||||
|
|
@ -113,6 +114,7 @@ export const ui = {
|
|||
'nav.forWhom': 'For whom?',
|
||||
'nav.references': 'References',
|
||||
'nav.privacy': 'Privacy',
|
||||
'nav.devlog': 'Devlog',
|
||||
|
||||
// Buttons
|
||||
'button.startFree': 'Start for free',
|
||||
|
|
@ -191,6 +193,7 @@ export const ui = {
|
|||
'nav.forWhom': 'Per chi?',
|
||||
'nav.references': 'Referenze',
|
||||
'nav.privacy': 'Privacy',
|
||||
'nav.devlog': 'Devlog',
|
||||
|
||||
// Buttons
|
||||
'button.startFree': 'Prova gratuita',
|
||||
|
|
@ -272,6 +275,7 @@ export const ui = {
|
|||
'nav.forWhom': 'Pour qui?',
|
||||
'nav.references': 'Références',
|
||||
'nav.privacy': 'Confidentialité',
|
||||
'nav.devlog': 'Devlog',
|
||||
|
||||
// Buttons
|
||||
'button.startFree': 'Essai gratuit',
|
||||
|
|
@ -355,6 +359,7 @@ export const ui = {
|
|||
'nav.forWhom': '¿Para quién?',
|
||||
'nav.references': 'Referencias',
|
||||
'nav.privacy': 'Privacidad',
|
||||
'nav.devlog': 'Devlog',
|
||||
|
||||
// Buttons
|
||||
'button.startFree': 'Prueba gratuita',
|
||||
|
|
|
|||
236
apps/manacore/apps/landing/src/pages/devlog/[slug].astro
Normal file
236
apps/manacore/apps/landing/src/pages/devlog/[slug].astro
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
---
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
import Navbar from '../../components/navigation/Navbar.astro';
|
||||
import Footer from '../../components/navigation/Footer.astro';
|
||||
import Section from '../../components/content/Section.astro';
|
||||
import Container from '../../components/layout/Container.astro';
|
||||
import Heading from '../../components/typography/Heading.astro';
|
||||
import Text from '../../components/typography/Text.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('devlog');
|
||||
return posts.map((post) => ({
|
||||
params: { slug: post.slug },
|
||||
props: { post },
|
||||
}));
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
const { Content } = await post.render();
|
||||
|
||||
const categoryColors: Record<string, { bg: string; text: string; border: string }> = {
|
||||
release: {
|
||||
bg: 'from-green-500/10 to-emerald-500/10',
|
||||
text: 'text-green-500',
|
||||
border: 'border-green-500/30',
|
||||
},
|
||||
infrastructure: {
|
||||
bg: 'from-blue-500/10 to-cyan-500/10',
|
||||
text: 'text-blue-500',
|
||||
border: 'border-blue-500/30',
|
||||
},
|
||||
feature: {
|
||||
bg: 'from-purple-500/10 to-pink-500/10',
|
||||
text: 'text-purple-500',
|
||||
border: 'border-purple-500/30',
|
||||
},
|
||||
bugfix: {
|
||||
bg: 'from-orange-500/10 to-amber-500/10',
|
||||
text: 'text-orange-500',
|
||||
border: 'border-orange-500/30',
|
||||
},
|
||||
update: {
|
||||
bg: 'from-gray-500/10 to-slate-500/10',
|
||||
text: 'text-gray-400',
|
||||
border: 'border-gray-500/30',
|
||||
},
|
||||
};
|
||||
|
||||
const categoryLabels: Record<string, string> = {
|
||||
release: 'Release',
|
||||
infrastructure: 'Infrastructure',
|
||||
feature: 'Feature',
|
||||
bugfix: 'Bugfix',
|
||||
update: 'Update',
|
||||
};
|
||||
|
||||
const colors = categoryColors[post.data.category] || categoryColors.update;
|
||||
|
||||
const formatDate = (date: Date) => {
|
||||
return new Intl.DateTimeFormat('de-DE', {
|
||||
weekday: 'long',
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
}).format(date);
|
||||
};
|
||||
---
|
||||
|
||||
<Layout title={`${post.data.title} - ManaCore Devlog`} description={post.data.description}>
|
||||
<div
|
||||
class="bg-gradient-to-b from-blue-50/30 via-white to-blue-50/30 dark:from-gray-900 dark:via-gray-900 dark:to-gray-900 min-h-screen"
|
||||
>
|
||||
<Navbar />
|
||||
|
||||
<!-- Hero Section -->
|
||||
<div class="relative pt-24 pb-12">
|
||||
<div class="absolute inset-0">
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-b from-blue-50/50 to-transparent dark:from-gray-900 dark:to-transparent"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="absolute top-0 right-0 w-96 h-96 bg-mana-blue/10 dark:bg-mana-blue/5 rounded-full blur-3xl"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-0 left-0 w-96 h-96 bg-purple-500/10 dark:bg-purple-500/5 rounded-full blur-3xl"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Container class="relative z-10">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- Back link -->
|
||||
<a
|
||||
href="/devlog"
|
||||
class="inline-flex items-center gap-2 text-gray-500 hover:text-mana-blue transition-colors mb-8"
|
||||
>
|
||||
<Icon name="mdi:arrow-left" class="w-4 h-4" />
|
||||
<Text size="sm">Zurück zum Devlog</Text>
|
||||
</a>
|
||||
|
||||
<!-- Meta info -->
|
||||
<div class="flex flex-wrap items-center gap-4 mb-6">
|
||||
<!-- Date -->
|
||||
<div class="flex items-center gap-2 text-gray-500 dark:text-gray-400">
|
||||
<Icon name="mdi:calendar" class="w-5 h-5" />
|
||||
<Text size="base">{formatDate(post.data.date)}</Text>
|
||||
</div>
|
||||
|
||||
<!-- Category Badge -->
|
||||
<span
|
||||
class={`inline-flex items-center px-4 py-1.5 rounded-full text-sm font-medium bg-gradient-to-r ${colors.bg} ${colors.text} border ${colors.border}`}
|
||||
>
|
||||
{categoryLabels[post.data.category]}
|
||||
</span>
|
||||
|
||||
<!-- Commits -->
|
||||
{
|
||||
post.data.commits && (
|
||||
<div class="flex items-center gap-2 text-gray-500 dark:text-gray-400">
|
||||
<Icon name="mdi:source-commit" class="w-5 h-5" />
|
||||
<Text size="base">{post.data.commits} Commits</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<!-- Read Time -->
|
||||
{
|
||||
post.data.readTime && (
|
||||
<div class="flex items-center gap-2 text-gray-500 dark:text-gray-400">
|
||||
<Icon name="mdi:clock-outline" class="w-5 h-5" />
|
||||
<Text size="base">{post.data.readTime} min Lesezeit</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<Heading as="h1" size="1" class="mb-6">
|
||||
{post.data.title}
|
||||
</Heading>
|
||||
|
||||
<!-- Description -->
|
||||
<Text size="xl" class="text-gray-600 dark:text-gray-400 mb-8">
|
||||
{post.data.description}
|
||||
</Text>
|
||||
|
||||
<!-- Author -->
|
||||
<div class="flex items-center gap-3 pb-8 border-b border-gray-200 dark:border-gray-700">
|
||||
<div
|
||||
class="w-10 h-10 bg-gradient-to-br from-mana-blue to-blue-600 rounded-full flex items-center justify-center text-white font-bold"
|
||||
>
|
||||
{post.data.author.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<Text weight="semibold">{post.data.author}</Text>
|
||||
<Text size="sm" class="text-gray-500">Autor</Text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<Section spacing="large" class="relative">
|
||||
<Container class="relative z-10">
|
||||
<article
|
||||
class="max-w-4xl mx-auto prose prose-lg dark:prose-invert prose-headings:text-gray-900 dark:prose-headings:text-white prose-p:text-gray-600 dark:prose-p:text-gray-300 prose-a:text-mana-blue prose-a:no-underline hover:prose-a:underline prose-strong:text-gray-900 dark:prose-strong:text-white prose-code:text-mana-blue prose-code:bg-gray-100 dark:prose-code:bg-gray-800 prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded prose-pre:bg-gray-900 prose-pre:border prose-pre:border-gray-700 prose-table:border-collapse prose-th:bg-gray-100 dark:prose-th:bg-gray-800 prose-th:border prose-th:border-gray-300 dark:prose-th:border-gray-600 prose-th:px-4 prose-th:py-2 prose-td:border prose-td:border-gray-300 dark:prose-td:border-gray-600 prose-td:px-4 prose-td:py-2 prose-hr:border-gray-200 dark:prose-hr:border-gray-700"
|
||||
>
|
||||
<Content />
|
||||
</article>
|
||||
|
||||
<!-- Tags -->
|
||||
{
|
||||
post.data.tags && post.data.tags.length > 0 && (
|
||||
<div class="max-w-4xl mx-auto mt-12 pt-8 border-t border-gray-200 dark:border-gray-700">
|
||||
<Text size="sm" weight="semibold" class="mb-4 text-gray-500">
|
||||
Tags
|
||||
</Text>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{post.data.tags.map((tag: string) => (
|
||||
<span class="px-3 py-1.5 text-sm rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 border border-gray-200 dark:border-gray-700">
|
||||
#{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<!-- Navigation -->
|
||||
<div class="max-w-4xl mx-auto mt-12 pt-8 border-t border-gray-200 dark:border-gray-700">
|
||||
<a
|
||||
href="/devlog"
|
||||
class="inline-flex items-center gap-2 px-6 py-3 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-mana-blue transition-colors"
|
||||
>
|
||||
<Icon name="mdi:arrow-left" class="w-5 h-5" />
|
||||
<Text weight="semibold">Alle Devlog Einträge</Text>
|
||||
</a>
|
||||
</div>
|
||||
</Container>
|
||||
</Section>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
/* Additional prose customizations */
|
||||
:global(.prose h2) {
|
||||
margin-top: 2.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px solid rgba(156, 163, 175, 0.2);
|
||||
}
|
||||
|
||||
:global(.prose h3) {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
:global(.prose table) {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:global(.prose ul) {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
:global(.prose li::marker) {
|
||||
color: #3b82f6;
|
||||
}
|
||||
</style>
|
||||
205
apps/manacore/apps/landing/src/pages/devlog/index.astro
Normal file
205
apps/manacore/apps/landing/src/pages/devlog/index.astro
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
---
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
import Navbar from '../../components/navigation/Navbar.astro';
|
||||
import Footer from '../../components/navigation/Footer.astro';
|
||||
import Section from '../../components/content/Section.astro';
|
||||
import Container from '../../components/layout/Container.astro';
|
||||
import Heading from '../../components/typography/Heading.astro';
|
||||
import Text from '../../components/typography/Text.astro';
|
||||
import HeroSection from '../../components/content/HeroSection.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { Icon } from 'astro-icon/components';
|
||||
|
||||
const posts = await getCollection('devlog');
|
||||
const sortedPosts = posts.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
||||
|
||||
const categoryColors: Record<string, { bg: string; text: string; border: string }> = {
|
||||
release: {
|
||||
bg: 'from-green-500/10 to-emerald-500/10',
|
||||
text: 'text-green-500',
|
||||
border: 'border-green-500/30',
|
||||
},
|
||||
infrastructure: {
|
||||
bg: 'from-blue-500/10 to-cyan-500/10',
|
||||
text: 'text-blue-500',
|
||||
border: 'border-blue-500/30',
|
||||
},
|
||||
feature: {
|
||||
bg: 'from-purple-500/10 to-pink-500/10',
|
||||
text: 'text-purple-500',
|
||||
border: 'border-purple-500/30',
|
||||
},
|
||||
bugfix: {
|
||||
bg: 'from-orange-500/10 to-amber-500/10',
|
||||
text: 'text-orange-500',
|
||||
border: 'border-orange-500/30',
|
||||
},
|
||||
update: {
|
||||
bg: 'from-gray-500/10 to-slate-500/10',
|
||||
text: 'text-gray-400',
|
||||
border: 'border-gray-500/30',
|
||||
},
|
||||
};
|
||||
|
||||
const categoryLabels: Record<string, string> = {
|
||||
release: 'Release',
|
||||
infrastructure: 'Infrastructure',
|
||||
feature: 'Feature',
|
||||
bugfix: 'Bugfix',
|
||||
update: 'Update',
|
||||
};
|
||||
|
||||
const formatDate = (date: Date) => {
|
||||
return new Intl.DateTimeFormat('de-DE', {
|
||||
day: '2-digit',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
}).format(date);
|
||||
};
|
||||
---
|
||||
|
||||
<Layout title="Devlog - ManaCore Entwicklungstagebuch">
|
||||
<div
|
||||
class="bg-gradient-to-b from-blue-50/30 via-white to-blue-50/30 dark:from-gray-900 dark:via-gray-900 dark:to-gray-900"
|
||||
>
|
||||
<Navbar />
|
||||
|
||||
<!-- Hero Section -->
|
||||
<div class="relative">
|
||||
<div class="absolute inset-0 -bottom-32">
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-b from-blue-50/50 to-transparent dark:from-gray-900 dark:to-transparent"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="absolute top-0 right-0 w-96 h-96 bg-mana-blue/10 dark:bg-mana-blue/5 rounded-full blur-3xl"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-0 left-0 w-96 h-96 bg-purple-500/10 dark:bg-purple-500/5 rounded-full blur-3xl"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<HeroSection
|
||||
title="Devlog"
|
||||
subtitle="Einblicke in die Entwicklung von ManaCore. Hier dokumentieren wir Features, Releases und technische Entscheidungen."
|
||||
background="none"
|
||||
minHeight="small"
|
||||
spacing="small"
|
||||
containerClass="py-16 relative z-10"
|
||||
centered={true}
|
||||
debug={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Posts Grid -->
|
||||
<Section spacing="xlarge" class="relative">
|
||||
<div class="absolute inset-0 -top-32 -bottom-32"></div>
|
||||
<div
|
||||
class="absolute top-0 left-1/4 w-96 h-96 bg-blue-500/15 dark:bg-blue-500/5 rounded-full blur-3xl"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="absolute bottom-0 right-1/4 w-96 h-96 bg-purple-500/15 dark:bg-purple-500/5 rounded-full blur-3xl"
|
||||
>
|
||||
</div>
|
||||
|
||||
<Container class="relative z-10">
|
||||
<div class="max-w-4xl mx-auto space-y-8">
|
||||
{
|
||||
sortedPosts.map((post) => {
|
||||
const colors = categoryColors[post.data.category] || categoryColors.update;
|
||||
return (
|
||||
<article class="group relative">
|
||||
<div
|
||||
class={`absolute -inset-0.5 bg-gradient-to-r ${colors.bg} rounded-2xl opacity-0 group-hover:opacity-100 transition-opacity duration-300 blur`}
|
||||
/>
|
||||
<a
|
||||
href={`/devlog/${post.slug}`}
|
||||
class="block relative bg-white/90 backdrop-blur-sm dark:bg-gray-800/90 rounded-2xl p-8 border border-gray-200 dark:border-gray-700 group-hover:border-mana-blue/50 transition-all duration-300"
|
||||
>
|
||||
<div class="flex flex-wrap items-center gap-3 mb-4">
|
||||
<div class="flex items-center gap-2 text-gray-500 dark:text-gray-400">
|
||||
<Icon name="mdi:calendar" class="w-4 h-4" />
|
||||
<Text size="sm">{formatDate(post.data.date)}</Text>
|
||||
</div>
|
||||
|
||||
<span
|
||||
class={`inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-gradient-to-r ${colors.bg} ${colors.text} border ${colors.border}`}
|
||||
>
|
||||
{categoryLabels[post.data.category]}
|
||||
</span>
|
||||
|
||||
{post.data.commits && (
|
||||
<div class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
|
||||
<Icon name="mdi:source-commit" class="w-4 h-4" />
|
||||
<Text size="sm">{post.data.commits} Commits</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{post.data.readTime && (
|
||||
<div class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
|
||||
<Icon name="mdi:clock-outline" class="w-4 h-4" />
|
||||
<Text size="sm">{post.data.readTime} min</Text>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Heading
|
||||
as="h2"
|
||||
size="4"
|
||||
class="mb-3 group-hover:text-mana-blue transition-colors"
|
||||
>
|
||||
{post.data.title}
|
||||
</Heading>
|
||||
|
||||
<Text size="base" class="text-gray-600 dark:text-gray-400 mb-4">
|
||||
{post.data.description}
|
||||
</Text>
|
||||
|
||||
{post.data.tags && post.data.tags.length > 0 && (
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{post.data.tags.map((tag: string) => (
|
||||
<span class="px-2 py-1 text-xs rounded-md bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400">
|
||||
#{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="mt-6 flex items-center text-mana-blue opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<Text size="sm" weight="semibold">
|
||||
Weiterlesen
|
||||
</Text>
|
||||
<Icon
|
||||
name="mdi:arrow-right"
|
||||
class="w-4 h-4 ml-2 group-hover:translate-x-1 transition-transform"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
</article>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
{
|
||||
sortedPosts.length === 0 && (
|
||||
<div class="text-center py-16">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-gray-500/10 to-slate-500/10 rounded-2xl mb-4">
|
||||
<Icon name="mdi:file-document-outline" class="w-8 h-8 text-gray-500" />
|
||||
</div>
|
||||
<Heading as="h2" size="4" class="mb-2">
|
||||
Noch keine Einträge
|
||||
</Heading>
|
||||
<Text class="text-gray-500">Hier erscheinen bald Entwicklungsberichte.</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</Container>
|
||||
</Section>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
</Layout>
|
||||
Loading…
Add table
Add a link
Reference in a new issue