Customization Guide
Customize Litestore themes, layouts, and functionality
Customization Overview
Litestore is built with customization in mind. From themes and layouts to custom integrations and business logic, you can adapt Litestore to fit your specific needs.
Theme Customization
Tailwind CSS Configuration
Customize colors, fonts, and spacing:
// tailwind.config.js
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./app/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
colors: {
brand: {
primary: '#your-brand-color',
secondary: '#your-secondary-color',
accent: '#your-accent-color',
},
litestore: {
'creator': '#6366f1',
'social': '#ec4899',
'ai': '#06b6d4',
}
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
display: ['Cal Sans', 'Inter', 'system-ui', 'sans-serif'],
},
spacing: {
'18': '4.5rem',
'88': '22rem',
},
animation: {
'fade-in': 'fadeIn 0.5s ease-in-out',
'slide-up': 'slideUp 0.3s ease-out',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
},
},
},
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
],
}CSS Variables
Use CSS custom properties for dynamic theming:
/* styles/globals.css */
:root {
--color-brand-primary: #your-brand-color;
--color-brand-secondary: #your-secondary-color;
--color-text-primary: #1f2937;
--color-text-secondary: #6b7280;
--color-bg-primary: #ffffff;
--color-bg-secondary: #f9fafb;
--font-family-primary: 'Inter', system-ui, sans-serif;
--font-family-display: 'Cal Sans', 'Inter', system-ui, sans-serif;
--border-radius-sm: 0.25rem;
--border-radius-md: 0.375rem;
--border-radius-lg: 0.5rem;
}
[data-theme="dark"] {
--color-text-primary: #f9fafb;
--color-text-secondary: #d1d5db;
--color-bg-primary: #111827;
--color-bg-secondary: #1f2937;
}
/* Component styles */
.btn-primary {
background-color: var(--color-brand-primary);
color: white;
border-radius: var(--border-radius-md);
font-family: var(--font-family-primary);
}Theme Provider
Create a theme provider for dynamic theme switching:
// components/theme-provider.tsx
'use client';
import { createContext, useContext, useEffect, useState } from 'react';
type Theme = 'light' | 'dark' | 'system';
interface ThemeContextType {
theme: Theme;
setTheme: (theme: Theme) => void;
resolvedTheme: 'light' | 'dark';
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>('system');
const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light');
useEffect(() => {
const root = window.document.documentElement;
root.classList.remove('light', 'dark');
let systemTheme: 'light' | 'dark' = 'light';
if (typeof window !== 'undefined') {
systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
const resolved = theme === 'system' ? systemTheme : theme;
root.classList.add(resolved);
setResolvedTheme(resolved);
}, [theme]);
return (
<ThemeContext.Provider value={{ theme, setTheme, resolvedTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}Layout Customization
Custom Header
Create a branded header component:
// components/layout/header.tsx
import Link from 'next/link';
import { useSession } from '@/hooks/use-session';
import { Logo } from '@/components/logo';
import { UserMenu } from '@/components/user-menu';
export function Header() {
const { user } = useSession();
return (
<header className="sticky top-0 z-50 bg-white border-b border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center">
<Link href="/" className="flex items-center space-x-2">
<Logo className="h-8 w-8" />
<span className="text-xl font-bold text-gray-900">Your Brand</span>
</Link>
</div>
<nav className="hidden md:flex space-x-8">
<Link href="/products" className="text-gray-600 hover:text-gray-900">
Products
</Link>
<Link href="/creators" className="text-gray-600 hover:text-gray-900">
Creators
</Link>
<Link href="/about" className="text-gray-600 hover:text-gray-900">
About
</Link>
</nav>
<div className="flex items-center space-x-4">
{user ? (
<UserMenu user={user} />
) : (
<div className="space-x-4">
<Link href="/auth/sign-in" className="text-gray-600 hover:text-gray-900">
Sign In
</Link>
<Link href="/auth/sign-up" className="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700">
Get Started
</Link>
</div>
)}
</div>
</div>
</div>
</header>
);
}Custom Footer
Create a comprehensive footer:
// components/layout/footer.tsx
import Link from 'next/link';
const footerLinks = {
product: [
{ name: 'Features', href: '/features' },
{ name: 'Pricing', href: '/pricing' },
{ name: 'API', href: '/docs/api' },
{ name: 'Status', href: '/status' },
],
creators: [
{ name: 'Join as Creator', href: '/creators/join' },
{ name: 'Creator Dashboard', href: '/dashboard/creator' },
{ name: 'Commission Calculator', href: '/creators/calculator' },
{ name: 'Success Stories', href: '/creators/stories' },
],
company: [
{ name: 'About', href: '/about' },
{ name: 'Blog', href: '/blog' },
{ name: 'Careers', href: '/careers' },
{ name: 'Contact', href: '/contact' },
],
legal: [
{ name: 'Privacy', href: '/legal/privacy' },
{ name: 'Terms', href: '/legal/terms' },
{ name: 'Cookies', href: '/legal/cookies' },
{ name: 'GDPR', href: '/legal/gdpr' },
],
};
export function Footer() {
return (
<footer className="bg-gray-50 border-t border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
<div>
<h3 className="text-sm font-semibold text-gray-900 tracking-wider uppercase">
Product
</h3>
<ul className="mt-4 space-y-4">
{footerLinks.product.map((link) => (
<li key={link.name}>
<Link href={link.href} className="text-gray-600 hover:text-gray-900">
{link.name}
</Link>
</li>
))}
</ul>
</div>
<div>
<h3 className="text-sm font-semibold text-gray-900 tracking-wider uppercase">
Creators
</h3>
<ul className="mt-4 space-y-4">
{footerLinks.creators.map((link) => (
<li key={link.name}>
<Link href={link.href} className="text-gray-600 hover:text-gray-900">
{link.name}
</Link>
</li>
))}
</ul>
</div>
<div>
<h3 className="text-sm font-semibold text-gray-900 tracking-wider uppercase">
Company
</h3>
<ul className="mt-4 space-y-4">
{footerLinks.company.map((link) => (
<li key={link.name}>
<Link href={link.href} className="text-gray-600 hover:text-gray-900">
{link.name}
</Link>
</li>
))}
</ul>
</div>
<div>
<h3 className="text-sm font-semibold text-gray-900 tracking-wider uppercase">
Legal
</h3>
<ul className="mt-4 space-y-4">
{footerLinks.legal.map((link) => (
<li key={link.name}>
<Link href={link.href} className="text-gray-600 hover:text-gray-900">
{link.name}
</Link>
</li>
))}
</ul>
</div>
</div>
<div className="mt-8 pt-8 border-t border-gray-200">
<div className="flex flex-col md:flex-row justify-between items-center">
<div className="flex items-center space-x-4">
<Logo className="h-8 w-8" />
<span className="text-gray-900 font-semibold">Your Brand</span>
</div>
<p className="mt-4 md:mt-0 text-gray-600 text-sm">
© 2024 Your Brand. All rights reserved.
</p>
</div>
</div>
</div>
</footer>
);
}Component Customization
Custom Product Card
Create branded product display components:
// components/product/product-card.tsx
import Image from 'next/image';
import Link from 'next/link';
import { Heart, ShoppingCart, Star } from 'lucide-react';
interface ProductCardProps {
product: {
id: string;
name: string;
price: number;
originalPrice?: number;
rating: number;
reviewCount: number;
image: string;
badge?: string;
creator?: {
name: string;
avatar: string;
};
};
}
export function ProductCard({ product }: ProductCardProps) {
const discount = product.originalPrice
? Math.round(((product.originalPrice - product.price) / product.originalPrice) * 100)
: 0;
return (
<div className="group bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200 overflow-hidden">
<div className="relative">
<Link href={`/products/${product.id}`}>
<div className="aspect-square relative overflow-hidden">
<Image
src={product.image}
alt={product.name}
fill
className="object-cover group-hover:scale-105 transition-transform duration-200"
/>
</div>
</Link>
{/* Badges */}
<div className="absolute top-2 left-2 flex flex-col gap-1">
{product.badge && (
<span className="bg-red-500 text-white text-xs px-2 py-1 rounded">
{product.badge}
</span>
)}
{discount > 0 && (
<span className="bg-green-500 text-white text-xs px-2 py-1 rounded">
-{discount}%
</span>
)}
</div>
{/* Wishlist */}
<button className="absolute top-2 right-2 p-2 bg-white/80 hover:bg-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity">
<Heart className="h-4 w-4 text-gray-600" />
</button>
</div>
<div className="p-4">
{/* Creator */}
{product.creator && (
<div className="flex items-center gap-2 mb-2">
<Image
src={product.creator.avatar}
alt={product.creator.name}
width={20}
height={20}
className="rounded-full"
/>
<span className="text-sm text-gray-600">{product.creator.name}</span>
</div>
)}
{/* Product Name */}
<Link href={`/products/${product.id}`}>
<h3 className="font-medium text-gray-900 hover:text-blue-600 line-clamp-2">
{product.name}
</h3>
</Link>
{/* Rating */}
<div className="flex items-center gap-1 mt-1">
<div className="flex">
{[...Array(5)].map((_, i) => (
<Star
key={i}
className={`h-4 w-4 ${
i < Math.floor(product.rating)
? 'text-yellow-400 fill-current'
: 'text-gray-300'
}`}
/>
))}
</div>
<span className="text-sm text-gray-600">
{product.rating} ({product.reviewCount})
</span>
</div>
{/* Price */}
<div className="flex items-center justify-between mt-2">
<div className="flex items-center gap-2">
<span className="text-lg font-semibold text-gray-900">
${product.price}
</span>
{product.originalPrice && (
<span className="text-sm text-gray-500 line-through">
${product.originalPrice}
</span>
)}
</div>
<button className="p-2 bg-blue-600 text-white rounded-full hover:bg-blue-700">
<ShoppingCart className="h-4 w-4" />
</button>
</div>
</div>
</div>
);
}Custom Creator Profile
Create branded creator profile components:
// components/creator/creator-profile.tsx
import Image from 'next/image';
import Link from 'next/link';
import { MapPin, Link as LinkIcon, Users, Star } from 'lucide-react';
interface CreatorProfileProps {
creator: {
id: string;
name: string;
bio: string;
avatar: string;
coverImage?: string;
location?: string;
website?: string;
socialMedia: {
instagram?: string;
tiktok?: string;
youtube?: string;
};
stats: {
followers: number;
contentCount: number;
avgRating: number;
totalEarnings: number;
};
verified: boolean;
niche: string[];
};
}
export function CreatorProfile({ creator }: CreatorProfileProps) {
return (
<div className="bg-white rounded-lg shadow-sm overflow-hidden">
{/* Cover Image */}
{creator.coverImage && (
<div className="h-32 relative">
<Image
src={creator.coverImage}
alt="Cover"
fill
className="object-cover"
/>
</div>
)}
<div className="p-6">
{/* Avatar and Basic Info */}
<div className="flex items-start gap-4">
<div className="relative">
<Image
src={creator.avatar}
alt={creator.name}
width={80}
height={80}
className="rounded-full border-4 border-white -mt-10 relative z-10"
/>
{creator.verified && (
<div className="absolute -bottom-1 -right-1 bg-blue-500 text-white rounded-full p-1">
<Star className="h-3 w-3 fill-current" />
</div>
)}
</div>
<div className="flex-1">
<div className="flex items-center gap-2">
<h1 className="text-2xl font-bold text-gray-900">{creator.name}</h1>
{creator.verified && (
<span className="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded-full">
Verified
</span>
)}
</div>
<p className="text-gray-600 mt-1">{creator.bio}</p>
{/* Location and Website */}
<div className="flex items-center gap-4 mt-2 text-sm text-gray-500">
{creator.location && (
<div className="flex items-center gap-1">
<MapPin className="h-4 w-4" />
{creator.location}
</div>
)}
{creator.website && (
<a
href={creator.website}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1 hover:text-blue-600"
>
<LinkIcon className="h-4 w-4" />
Website
</a>
)}
</div>
{/* Social Media */}
<div className="flex gap-3 mt-3">
{creator.socialMedia.instagram && (
<a
href={`https://instagram.com/${creator.socialMedia.instagram}`}
target="_blank"
rel="noopener noreferrer"
className="text-pink-600 hover:text-pink-700"
>
Instagram
</a>
)}
{creator.socialMedia.tiktok && (
<a
href={`https://tiktok.com/@${creator.socialMedia.tiktok}`}
target="_blank"
rel="noopener noreferrer"
className="text-black hover:text-gray-700"
>
TikTok
</a>
)}
{creator.socialMedia.youtube && (
<a
href={`https://youtube.com/@${creator.socialMedia.youtube}`}
target="_blank"
rel="noopener noreferrer"
className="text-red-600 hover:text-red-700"
>
YouTube
</a>
)}
</div>
</div>
</div>
{/* Stats */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-6">
<div className="text-center">
<div className="text-2xl font-bold text-gray-900">
{creator.stats.followers.toLocaleString()}
</div>
<div className="text-sm text-gray-600">Followers</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-gray-900">
{creator.stats.contentCount}
</div>
<div className="text-sm text-gray-600">Content</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-gray-900">
{creator.stats.avgRating.toFixed(1)}
</div>
<div className="text-sm text-gray-600">Rating</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-gray-900">
${creator.stats.totalEarnings.toLocaleString()}
</div>
<div className="text-sm text-gray-600">Earned</div>
</div>
</div>
{/* Niche Tags */}
<div className="flex flex-wrap gap-2 mt-6">
{creator.niche.map((tag) => (
<span
key={tag}
className="bg-gray-100 text-gray-800 text-sm px-3 py-1 rounded-full"
>
{tag}
</span>
))}
</div>
{/* Action Buttons */}
<div className="flex gap-3 mt-6">
<Link
href={`/creators/${creator.id}/content`}
className="flex-1 bg-blue-600 text-white text-center py-2 px-4 rounded-lg hover:bg-blue-700"
>
View Content
</Link>
<button className="flex-1 border border-gray-300 text-gray-700 py-2 px-4 rounded-lg hover:bg-gray-50">
Follow
</button>
</div>
</div>
</div>
);
}Business Logic Customization
Custom Commission Rules
Implement custom commission calculations:
// lib/commission.ts
export interface CommissionRule {
type: 'percentage' | 'flat' | 'tiered';
baseRate: number;
tiers?: Array<{
min: number;
max?: number;
rate: number;
}>;
conditions?: {
productCategory?: string[];
creatorTier?: 'new' | 'established' | 'premium';
timeLimit?: number; // days
};
}
export function calculateCommission(
orderAmount: number,
rule: CommissionRule,
creator: Creator,
product: Product
): number {
let rate = rule.baseRate;
// Apply tiered rates
if (rule.tiers) {
const applicableTier = rule.tiers.find(
tier => orderAmount >= tier.min && (!tier.max || orderAmount <= tier.max)
);
if (applicableTier) {
rate = applicableTier.rate;
}
}
// Apply conditions
if (rule.conditions) {
if (rule.conditions.productCategory &&
!rule.conditions.productCategory.includes(product.category)) {
rate *= 0.8; // 20% reduction for non-matching categories
}
if (rule.conditions.creatorTier) {
switch (rule.conditions.creatorTier) {
case 'new':
if (creator.stats.contentCount > 50) rate *= 0.9;
break;
case 'established':
if (creator.stats.contentCount <= 50) rate *= 0.9;
break;
case 'premium':
if (creator.stats.avgRating < 4.5) rate *= 0.9;
break;
}
}
}
return orderAmount * (rate / 100);
}Custom AI Prompts
Customize AI behavior for your brand:
// config/ai-prompts.ts
export const aiPrompts = {
productDescription: {
systemPrompt: `You are a product description writer for {{brandName}}.
Write engaging, SEO-optimized descriptions that highlight key features and benefits.
Use a {{brandVoice}} tone. Keep descriptions between 100-200 words.`,
userPrompt: `Write a compelling product description for:
Product: {{productName}}
Key Features: {{features}}
Target Audience: {{audience}}
Unique Selling Points: {{sellingPoints}}`
},
contentModeration: {
systemPrompt: `You are a content moderator for {{brandName}}.
Review creator content for brand alignment, quality, and community guidelines.
Be fair but firm. Consider context and intent.`,
criteria: {
brandAlignment: 0.8,
quality: 0.7,
spam: 0.9,
toxicity: 0.95
}
},
categorySuggestions: {
systemPrompt: `You are a product categorization expert for {{brandName}}.
Suggest the most appropriate categories and tags for products.
Consider user search behavior and brand taxonomy.`,
examples: [
"Wireless earbuds → Audio, Electronics, Wireless",
"Organic skincare → Beauty, Skincare, Organic, Wellness"
]
}
};Custom Email Templates
Create branded email templates:
// templates/emails/creator-approved.tsx
import { Html } from '@react-email/html';
import { Head } from '@react-email/head';
import { Body } from '@react-email/body';
import { Container } from '@react-email/container';
import { Section } from '@react-email/section';
import { Text } from '@react-email/text';
import { Button } from '@react-email/button';
interface CreatorApprovedEmailProps {
creatorName: string;
contentTitle: string;
commission: number;
dashboardUrl: string;
}
export function CreatorApprovedEmail({
creatorName,
contentTitle,
commission,
dashboardUrl
}: CreatorApprovedEmailProps) {
return (
<Html>
<Head />
<Body style={main}>
<Container style={container}>
<Section style={header}>
<Text style={brand}>Your Brand</Text>
</Section>
<Section style={content}>
<Text style={heading}>Content Approved! 🎉</Text>
<Text style={paragraph}>
Hi {creatorName},
</Text>
<Text style={paragraph}>
Great news! Your content "{contentTitle}" has been approved and is now live.
You've earned ${commission} in commission so far from this piece.
</Text>
<Text style={paragraph}>
Keep creating amazing content and watch your earnings grow!
</Text>
<Button style={button} href={dashboardUrl}>
View Dashboard
</Button>
</Section>
<Section style={footer}>
<Text style={footerText}>
Questions? Reply to this email or contact our creator support team.
</Text>
</Section>
</Container>
</Body>
</Html>
);
}
const main = {
backgroundColor: '#f6f9fc',
fontFamily: 'Inter, system-ui, sans-serif',
};
const container = {
margin: '0 auto',
padding: '20px 0 48px',
maxWidth: '600px',
};
const header = {
backgroundColor: '#ffffff',
padding: '24px',
borderRadius: '8px 8px 0 0',
};
const brand = {
fontSize: '24px',
fontWeight: 'bold',
color: '#1f2937',
};
const content = {
backgroundColor: '#ffffff',
padding: '24px',
};
const heading = {
fontSize: '24px',
fontWeight: 'bold',
color: '#1f2937',
margin: '0 0 16px 0',
};
const paragraph = {
fontSize: '16px',
lineHeight: '24px',
color: '#4b5563',
margin: '0 0 16px 0',
};
const button = {
backgroundColor: '#3b82f6',
color: '#ffffff',
padding: '12px 24px',
borderRadius: '6px',
textDecoration: 'none',
display: 'inline-block',
};
const footer = {
backgroundColor: '#f9fafb',
padding: '24px',
borderRadius: '0 0 8px 8px',
};
const footerText = {
fontSize: '14px',
color: '#6b7280',
textAlign: 'center' as const,
};Plugin System
Custom Plugins
Create reusable plugins for common customizations:
// plugins/shipping-calculator.ts
import { LitestorePlugin } from '@/types/plugin';
export class ShippingCalculatorPlugin implements LitestorePlugin {
name = 'shipping-calculator';
version = '1.0.0';
async init(app: LitestoreApp) {
// Register shipping calculation hook
app.hooks.on('order.calculateShipping', this.calculateShipping.bind(this));
// Add admin settings
app.admin.addSetting({
key: 'shipping.enabled',
type: 'boolean',
default: true,
label: 'Enable shipping calculator'
});
}
async calculateShipping(order: Order): Promise<ShippingRate[]> {
// Custom shipping logic
const rates: ShippingRate[] = [];
// Standard shipping
if (order.subtotal > 50) {
rates.push({
method: 'standard',
cost: 0,
estimatedDays: 5
});
} else {
rates.push({
method: 'standard',
cost: 5.99,
estimatedDays: 5
});
}
// Express shipping
rates.push({
method: 'express',
cost: 12.99,
estimatedDays: 2
});
return rates;
}
}Plugin Configuration
// config/plugins.ts
export const plugins = [
new ShippingCalculatorPlugin(),
new CustomPaymentGatewayPlugin(),
new AdvancedAnalyticsPlugin(),
new MultiLanguagePlugin(),
];
// Register plugins
export async function registerPlugins(app: LitestoreApp) {
for (const plugin of plugins) {
await app.registerPlugin(plugin);
}
}Advanced Customizations
Custom Database Models
Extend the database schema:
// prisma/schema.prisma
model CustomProductField {
id String @id @default(cuid())
productId String
fieldName String
fieldType String // 'text', 'number', 'boolean', 'select'
fieldValue String?
options String? // JSON string for select options
product Product @relation(fields: [productId], references: [id])
@@index([productId])
}Custom API Endpoints
Add custom API routes:
// app/api/custom/analytics/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { prisma } from '@/lib/db';
export async function GET(request: NextRequest) {
const session = await getServerSession();
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { searchParams } = new URL(request.url);
const timeframe = searchParams.get('timeframe') || '30d';
// Custom analytics logic
const analytics = await calculateCustomAnalytics(session.user.id, timeframe);
return NextResponse.json(analytics);
}
async function calculateCustomAnalytics(userId: string, timeframe: string) {
// Implement custom analytics calculations
const startDate = new Date();
startDate.setDate(startDate.getDate() - parseInt(timeframe));
const orders = await prisma.order.findMany({
where: {
userId,
createdAt: { gte: startDate }
},
include: {
items: {
include: {
product: true
}
}
}
});
// Custom calculations
const totalSpent = orders.reduce((sum, order) => sum + order.total, 0);
const favoriteCategory = calculateFavoriteCategory(orders);
const spendingTrend = calculateSpendingTrend(orders);
return {
totalSpent,
favoriteCategory,
spendingTrend,
orderCount: orders.length
};
}Custom Admin Panels
Create custom admin interfaces:
// app/admin/custom-analytics/page.tsx
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { CustomAnalyticsChart } from '@/components/admin/custom-analytics-chart';
export default function CustomAnalyticsPage() {
return (
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold">Custom Analytics</h1>
<p className="text-muted-foreground">
Advanced analytics tailored to your business needs
</p>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Custom Metric 1</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">1,234</div>
<p className="text-xs text-muted-foreground">+20.1% from last month</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Custom Metric 2</CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">567</div>
<p className="text-xs text-muted-foreground">+10.5% from last month</p>
</CardContent>
</Card>
</div>
<Card>
<CardHeader>
<CardTitle>Custom Analytics Chart</CardTitle>
</CardHeader>
<CardContent>
<CustomAnalyticsChart />
</CardContent>
</Card>
</div>
);
}Migration Strategies
Data Migration
Migrate from existing platforms:
// scripts/migrate-data.ts
import { PrismaClient } from '@prisma/client';
import { migrateFromShopify } from '@/lib/migrations/shopify';
import { migrateFromWooCommerce } from '@/lib/migrations/woocommerce';
const prisma = new PrismaClient();
async function migrateData() {
console.log('Starting data migration...');
// Migrate products
await migrateFromShopify.products();
await migrateFromWooCommerce.products();
// Migrate customers
await migrateFromShopify.customers();
await migrateFromWooCommerce.customers();
// Migrate orders
await migrateFromShopify.orders();
await migrateFromWooCommerce.orders();
console.log('Data migration completed!');
}
migrateData()
.catch(console.error)
.finally(() => prisma.$disconnect());Feature Flags
Gradually roll out custom features:
// config/feature-flags.ts
export const featureFlags = {
customShipping: {
enabled: process.env.NODE_ENV === 'production',
percentage: 50, // Enable for 50% of users
userIds: ['user-123', 'user-456'] // Specific users
},
advancedAnalytics: {
enabled: true,
premiumOnly: true
},
customThemes: {
enabled: false // Coming soon
}
};
// Usage
export function isFeatureEnabled(feature: keyof typeof featureFlags, userId?: string): boolean {
const flag = featureFlags[feature];
if (!flag.enabled) return false;
if (flag.premiumOnly && !isPremiumUser(userId)) return false;
if (flag.percentage && Math.random() * 100 > flag.percentage) return false;
if (flag.userIds && userId && !flag.userIds.includes(userId)) return false;
return true;
}Best Practice
Start with small customizations and gradually expand. Always test thoroughly and consider backward compatibility for future updates.