mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
- Rename dynamic routes from [slug].astro to [...slug].astro for multi-segment paths - Replace deprecated entry.slug with entry.id across all components and utils - Fix TypeScript implicit any types in TemplateFilters and prompt-templates - Add proper type narrowing for feature.note in pricing page - Remove unused marked import from FAQCard - Delete invalid placeholder content files - Add shared-landing-ui dependency and integrate StepsSection/PricingSection - Update tailwind config with shared-landing-ui content paths - Add global.css with Indigo/Violet dark theme variables 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
225 lines
6.5 KiB
Text
225 lines
6.5 KiB
Text
---
|
|
import { getCollection } from 'astro:content';
|
|
import type { CollectionEntry } from 'astro:content';
|
|
import Layout from '@layouts/Layout.astro';
|
|
import { getRelatedFeatures } from '@/utils/features';
|
|
import { t } from '../../i18n';
|
|
import { localizePath } from '../../i18n';
|
|
import FeatureCard from '@components/features/FeatureCard.astro';
|
|
|
|
export async function getStaticPaths() {
|
|
const allFeatures = await getCollection('features');
|
|
return allFeatures.map(feature => ({
|
|
params: { slug: feature.id },
|
|
props: { feature },
|
|
}));
|
|
}
|
|
|
|
interface Props {
|
|
feature: CollectionEntry<'features'>;
|
|
}
|
|
|
|
const { feature } = Astro.props;
|
|
const { Content } = await feature.render();
|
|
const { title, description, icon, category, benefits, useCases, available, comingSoon } = feature.data;
|
|
|
|
const relatedFeatures = await getRelatedFeatures(feature, 3);
|
|
---
|
|
|
|
<Layout title={title} description={description}>
|
|
<article class="min-h-screen bg-dark-bg">
|
|
<!-- Hero Section -->
|
|
<div class="relative py-24 overflow-hidden">
|
|
<div class="absolute inset-0 bg-gradient-to-br from-primary-900/20 via-dark-surface to-secondary-900/20"></div>
|
|
|
|
<div class="relative z-10 container mx-auto px-4">
|
|
<div class="max-w-4xl mx-auto">
|
|
<!-- Back Button -->
|
|
<a
|
|
href={localizePath('/features')}
|
|
class="inline-flex items-center gap-2 text-primary hover:text-primary-400 transition-colors mb-8"
|
|
>
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
|
</svg>
|
|
<span>{t('features.back_to_features')}</span>
|
|
</a>
|
|
|
|
<!-- Icon & Category -->
|
|
<div class="flex items-center gap-4 mb-6">
|
|
<span class="text-6xl">{icon}</span>
|
|
<span class="px-3 py-1 bg-primary/20 text-primary text-sm font-medium rounded-full capitalize">
|
|
{t(`features.categories.${category}`)}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Title -->
|
|
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6">
|
|
{title}
|
|
</h1>
|
|
|
|
<!-- Description -->
|
|
<p class="text-xl text-gray-300 mb-8">
|
|
{description}
|
|
</p>
|
|
|
|
<!-- Status Badges -->
|
|
<div class="flex flex-wrap gap-3">
|
|
{available && (
|
|
<span class="px-4 py-2 bg-success/20 text-success border border-success/30 rounded-lg font-medium">
|
|
✓ {t('features.available_now')}
|
|
</span>
|
|
)}
|
|
{comingSoon && (
|
|
<span class="px-4 py-2 bg-secondary/20 text-secondary border border-secondary/30 rounded-lg font-medium">
|
|
🚀 {t('features.coming_soon')}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Benefits Section -->
|
|
{benefits && benefits.length > 0 && (
|
|
<section class="py-16 bg-dark-surface">
|
|
<div class="container mx-auto px-4">
|
|
<div class="max-w-4xl mx-auto">
|
|
<h2 class="text-3xl font-bold text-white mb-8">{t('features.key_benefits')}</h2>
|
|
<div class="grid md:grid-cols-2 gap-4">
|
|
{benefits.map(benefit => (
|
|
<div class="flex items-start gap-3 p-4 bg-dark-elevated border border-dark-border rounded-lg">
|
|
<svg class="w-6 h-6 text-primary mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
|
</svg>
|
|
<span class="text-gray-300">{benefit}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)}
|
|
|
|
<!-- Content -->
|
|
<section class="py-16">
|
|
<div class="container mx-auto px-4">
|
|
<div class="max-w-4xl mx-auto">
|
|
<div class="prose prose-invert prose-primary prose-lg max-w-none">
|
|
<Content />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Use Cases -->
|
|
{useCases && useCases.length > 0 && (
|
|
<section class="py-16 bg-dark-surface">
|
|
<div class="container mx-auto px-4">
|
|
<div class="max-w-4xl mx-auto">
|
|
<h2 class="text-3xl font-bold text-white mb-8">{t('features.use_cases')}</h2>
|
|
<div class="grid md:grid-cols-2 gap-6">
|
|
{useCases.map(useCase => (
|
|
<div class="p-6 bg-dark-elevated border border-dark-border rounded-xl">
|
|
<div class="flex items-start gap-3">
|
|
<span class="text-2xl">💡</span>
|
|
<p class="text-gray-300 flex-1">{useCase}</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)}
|
|
|
|
<!-- CTA -->
|
|
<section class="py-16">
|
|
<div class="container mx-auto px-4">
|
|
<div class="max-w-4xl mx-auto text-center p-12 bg-gradient-to-br from-primary/20 to-secondary/20 border border-primary/30 rounded-2xl">
|
|
<h2 class="text-3xl font-bold text-white mb-4">
|
|
{t('features.try_feature')}
|
|
</h2>
|
|
<p class="text-gray-300 mb-8 max-w-2xl mx-auto">
|
|
{t('features.try_feature_subtitle')}
|
|
</p>
|
|
<a
|
|
href="#"
|
|
class="inline-block px-8 py-4 bg-gradient-to-r from-primary-600 to-secondary-600 hover:from-primary-700 hover:to-secondary-700 text-white rounded-lg font-semibold text-lg transition-all duration-300 shadow-lg shadow-primary/50 hover:shadow-primary/70 hover:scale-105"
|
|
>
|
|
{t('features.get_started')}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Related Features -->
|
|
{relatedFeatures.length > 0 && (
|
|
<section class="py-16 bg-dark-surface">
|
|
<div class="container mx-auto px-4">
|
|
<h2 class="text-3xl font-bold text-white mb-8">{t('features.related_features')}</h2>
|
|
<div class="grid md:grid-cols-3 gap-8">
|
|
{relatedFeatures.map(relatedFeature => (
|
|
<FeatureCard feature={relatedFeature} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)}
|
|
</article>
|
|
</Layout>
|
|
|
|
<style is:global>
|
|
/* Feature Page Styles - same as blog */
|
|
.prose {
|
|
@apply text-gray-300;
|
|
}
|
|
|
|
.prose h2 {
|
|
@apply text-3xl font-bold text-white mt-12 mb-6;
|
|
}
|
|
|
|
.prose h3 {
|
|
@apply text-2xl font-semibold text-white mt-8 mb-4;
|
|
}
|
|
|
|
.prose p {
|
|
@apply mb-6 leading-relaxed;
|
|
}
|
|
|
|
.prose ul, .prose ol {
|
|
@apply mb-6 space-y-2;
|
|
}
|
|
|
|
.prose li {
|
|
@apply text-gray-300;
|
|
}
|
|
|
|
.prose a {
|
|
@apply text-primary hover:text-primary-400 transition-colors underline;
|
|
}
|
|
|
|
.prose strong {
|
|
@apply text-white font-semibold;
|
|
}
|
|
|
|
.prose code {
|
|
@apply bg-dark-elevated px-2 py-1 rounded text-primary-300 text-sm;
|
|
}
|
|
|
|
.prose pre {
|
|
@apply bg-dark-elevated border border-dark-border rounded-xl p-4 overflow-x-auto mb-6;
|
|
}
|
|
|
|
.prose table {
|
|
@apply w-full mb-6;
|
|
}
|
|
|
|
.prose th {
|
|
@apply bg-dark-elevated text-white font-semibold p-3 text-left;
|
|
}
|
|
|
|
.prose td {
|
|
@apply border-t border-dark-border p-3;
|
|
}
|
|
</style>
|