feat: implement frontend-backend configuration linkage
- Create public config API for frontend consumption - Add configuration fetching to homepage - Implement module show/hide logic based on config - Add support for Services items filtering - Add support for Products featured products and pricing display - Add support for News display count, categories, and sort order - Fix table name from 'configs' to 'siteConfig' in API route - Update type definitions for proper TypeScript support
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { useInView } from 'framer-motion';
|
||||
import { useRef } from 'react';
|
||||
import { useRef, useMemo } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -10,10 +10,27 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { ArrowRight, Check, TrendingUp } from 'lucide-react';
|
||||
import { PRODUCTS } from '@/lib/constants';
|
||||
|
||||
export function ProductsSection() {
|
||||
interface ProductsConfig {
|
||||
enabled?: boolean;
|
||||
showPricing?: boolean;
|
||||
featuredProducts?: string[];
|
||||
}
|
||||
|
||||
interface ProductsSectionProps {
|
||||
config?: ProductsConfig;
|
||||
}
|
||||
|
||||
export function ProductsSection({ config }: ProductsSectionProps) {
|
||||
const ref = useRef(null);
|
||||
const isInView = useInView(ref, { once: true, margin: '-100px' });
|
||||
|
||||
const filteredProducts = useMemo(() => {
|
||||
if (!config?.featuredProducts || config.featuredProducts.length === 0) {
|
||||
return PRODUCTS;
|
||||
}
|
||||
return PRODUCTS.filter(product => config.featuredProducts?.includes(product.id));
|
||||
}, [config]);
|
||||
|
||||
return (
|
||||
<section id="products" role="region" aria-labelledby="products-heading" className="py-24 bg-[#F5F7FA] relative overflow-hidden" ref={ref}>
|
||||
<div className="absolute top-1/2 left-0 w-[400px] h-[400px] bg-[rgba(79,70,229,0.03)] rounded-full blur-3xl" />
|
||||
@@ -34,7 +51,7 @@ export function ProductsSection() {
|
||||
</motion.div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{PRODUCTS.map((product, idx) => (
|
||||
{filteredProducts.map((product, idx) => (
|
||||
<motion.div
|
||||
key={product.id}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
@@ -84,6 +101,19 @@ export function ProductsSection() {
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{config?.showPricing && product.pricing && (
|
||||
<div className="mb-4 p-3 bg-[#F5F7FA] rounded-lg">
|
||||
<p className="text-sm font-medium text-[#1C1C1C] mb-2">价格方案</p>
|
||||
<div className="space-y-1">
|
||||
{Object.entries(product.pricing).map(([key, value]) => (
|
||||
<p key={key} className="text-xs text-[#5C5C5C]">
|
||||
{value}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button variant="outline" className="w-full mt-auto group-hover:bg-[#A01830] group-hover:text-white group-hover:border-[#A01830] transition-colors">
|
||||
了解详情
|
||||
<ArrowRight className="ml-2 w-4 h-4" />
|
||||
|
||||
Reference in New Issue
Block a user