This guide covers the complete implementation of the Minimal DAO landing page, from initial setup to production deployment.
# Clone the repository
git clone https://github.com/MinimalTechSolutions/app.git
cd app
# Install dependencies
npm install
# Create environment file
cp .env.example .env.localEdit .env.local:
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_CONTACT_EMAIL=byteminimal@gmail.comPlace all required images in /public/images/:
public/images/
βββ logo/
β βββ minimal-wide-logo-trans.png (main logo)
β βββ minimal-icon.png (favicon source)
βββ hero/
β βββ minimal-wallpaper00.png (hero background)
βββ services/
β βββ minimal-mobile-dev.png
β βββ minimal-web-dev.png
β βββ minimal-iot-dev.png
βββ og-image.png (1200x630 for social sharing)
Use favicon.io or RealFaviconGenerator:
public/
βββ favicon.ico
βββ favicon-16x16.png
βββ favicon-32x32.png
βββ apple-touch-icon.png
npm run devVisit http://localhost:3000 to see your site!
Edit src/app/globals.css:
:root {
/* Update these values to match your brand */
--color-background: #FFFFFF;
--color-foreground: #000000;
--color-accent: #000000;
}Update fonts in src/app/layout.tsx:
// Replace with your preferred fonts
import { YourDisplayFont, YourBodyFont } from 'next/font/google'
const displayFont = YourDisplayFont({
subsets: ['latin'],
variable: '--font-display',
})Edit src/components/sections/Hero.tsx:
- Update heading text
- Modify subheading
- Change CTA button text and links
Edit src/components/sections/PricingCards.tsx:
- Update pricing tiers
- Modify features lists
- Change prices and CTAs
Edit src/components/sections/Services.tsx:
- Update service titles and descriptions
- Replace service images
- Modify service icons
Edit src/lib/constants.ts:
export const NAVIGATION_LINKS = [
{ name: 'Your Link', href: '/your-route' },
// Add/remove as needed
]Update src/lib/constants.ts:
export const CONTACT_INFO = {
email: 'your-email@example.com',
address: {
street: 'Your Street',
city: 'Your City',
// ...
},
}Create a new page at src/app/your-page/page.tsx:
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Your Page Title',
description: 'Your page description',
}
export default function YourPage() {
return (
<div className="container-custom py-20">
<h1>Your Page Content</h1>
</div>
)
}Example Button component at src/components/ui/Button.tsx:
import { ButtonHTMLAttributes } from 'react'
import { cn } from '@/lib/utils'
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary'
size?: 'sm' | 'md' | 'lg'
}
export function Button({
variant = 'primary',
size = 'md',
className,
children,
...props
}: ButtonProps) {
return (
<button
className={cn(
'font-medium transition-all duration-300',
variant === 'primary' && 'btn-primary',
variant === 'secondary' && 'btn-secondary',
className
)}
{...props}
>
{children}
</button>
)
}Create scroll-reveal animation:
// src/components/animations/ScrollReveal.tsx
'use client'
import { useEffect, useRef, useState } from 'react'
export function ScrollReveal({ children, className = '' }) {
const [isVisible, setIsVisible] = useState(false)
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true)
observer.disconnect()
}
},
{ threshold: 0.1 }
)
if (ref.current) observer.observe(ref.current)
return () => observer.disconnect()
}, [])
return (
<div
ref={ref}
className={`transition-all duration-1000 ${
isVisible
? 'opacity-100 translate-y-0'
: 'opacity-0 translate-y-10'
} ${className}`}
>
{children}
</div>
)
}// src/components/ContactForm.tsx
'use client'
import { useState } from 'react'
export function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
})
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle')
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setStatus('loading')
try {
// Implement your form submission logic
const response = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
})
if (response.ok) {
setStatus('success')
setFormData({ name: '', email: '', message: '' })
} else {
setStatus('error')
}
} catch (error) {
setStatus('error')
}
}
return (
<form onSubmit={handleSubmit} className="space-y-6">
<div>
<label htmlFor="name" className="block text-sm font-medium mb-2">
Name
</label>
<input
type="text"
id="name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
required
className="w-full px-4 py-3 border border-minimal-gray-300 focus:border-minimal-black focus:ring-2 focus:ring-minimal-black focus:ring-offset-2 transition-all"
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium mb-2">
Email
</label>
<input
type="email"
id="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
required
className="w-full px-4 py-3 border border-minimal-gray-300 focus:border-minimal-black focus:ring-2 focus:ring-minimal-black focus:ring-offset-2 transition-all"
/>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium mb-2">
Message
</label>
<textarea
id="message"
rows={5}
value={formData.message}
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
required
className="w-full px-4 py-3 border border-minimal-gray-300 focus:border-minimal-black focus:ring-2 focus:ring-minimal-black focus:ring-offset-2 transition-all"
/>
</div>
<button
type="submit"
disabled={status === 'loading'}
className="btn-primary w-full disabled:opacity-50"
>
{status === 'loading' ? 'Sending...' : 'Send Message'}
</button>
{status === 'success' && (
<p className="text-green-600">Message sent successfully!</p>
)}
{status === 'error' && (
<p className="text-red-600">Failed to send message. Please try again.</p>
)}
</form>
)
}- All pages load without errors
- Navigation works correctly
- All links go to correct destinations
- Images load and are properly sized
- Forms submit successfully
- Mobile responsive on all screen sizes
- Animations play smoothly
- No console errors
Test on:
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
- Mobile Safari (iOS)
- Chrome Mobile (Android)
Run Lighthouse audit:
npm run build
npm start
# Open DevTools > Lighthouse > Run AuditTarget scores:
- Performance: 95+
- Accessibility: 100
- Best Practices: 100
- SEO: 100
Use tools:
- WAVE Extension
- axe DevTools
- Keyboard navigation test
- Screen reader test
- All content finalized
- Images optimized
- Environment variables set
- Meta tags configured
- Analytics set up
- Error tracking configured
- Performance targets met
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
# Production deployment
vercel --prod- Test live site
- Submit sitemap to Google
- Monitor analytics
- Check error logs
- Test from different locations
- Vercel Analytics
- Google Search Console
- Error tracking (Sentry)
- Uptime monitoring
Weekly:
- Check analytics
- Review errors
- Monitor performance
Monthly:
- Update dependencies
- Content updates
- SEO optimization
Quarterly:
- Major feature updates
- Design improvements
- Security audit
// Ensure images are in public directory
// Use proper path: /images/your-image.png
<Image src="/images/your-image.png" ... /># Clear cache and rebuild
rm -rf .next
npm run build# Run type check
npm run type-check
# Fix common issues in tsconfig.json# Restart dev server
# Check Tailwind config
# Verify class names- Figma - Design
- Squoosh - Image optimization
- PageSpeed Insights - Performance
- Documentation Issues: Check this guide and README.md
- Technical Problems: Create GitHub issue
- General Questions: Email byteminimal@gmail.com
- Community: Join our discussions
Happy Building! π