Build static Next.js sites with Redux state management, Tailwind CSS styling, TypeScript safety, and mobile-first responsive design. All content driven by Redux slices, optimized for static export.
Build static Next.js 16 sites with Redux-driven content, Tailwind CSS styling, and TypeScript type safety. Perfect for portfolios, documentation sites, and content-heavy static applications.
ALL static text and images MUST be driven by Redux state, never hardcoded in components. Each section has its own Redux slice in `lib/slices/`. Components consume state using typed hooks from `@/lib/hooks`.
When creating components:
Example component pattern:
```typescript
'use client';
import { useAppSelector } from '@/lib/hooks';
export default function SectionName() {
const data = useAppSelector((state) => state.sliceName);
return (
<section id="section-id" className="border-t-2 border-zinc-300 bg-white dark:border-zinc-700 dark:bg-black">
<div className="mx-auto max-w-6xl px-6 py-20">
{/* Render data from Redux */}
</div>
</section>
);
}
```
For each content section, create a Redux slice in `lib/slices/`:
Example slice structure:
```typescript
import { createSlice } from '@reduxjs/toolkit';
export interface SectionState {
title: string;
items: Array<{ id: string; name: string; description: string }>;
}
const initialState: SectionState = {
title: 'Section Title',
items: [],
};
export const sectionSlice = createSlice({
name: 'section',
initialState,
reducers: {},
});
export default sectionSlice.reducer;
```
Register slice in `lib/store.ts`.
Follow these strict styling rules:
**Mobile-First Responsive Design:**
**Dark Mode Support:**
**Standard Section Pattern:**
```tsx
<section className="border-t-2 border-zinc-300 bg-white dark:border-zinc-700 dark:bg-black">
<div className="mx-auto max-w-6xl px-6 py-20">
<div className="space-y-8">
{/* Content with consistent spacing */}
</div>
</div>
</section>
```
**Responsive Layout Pattern:**
```tsx
<div className="flex flex-col items-center gap-4 sm:flex-row sm:items-start">
<div className="flex-shrink-0 sm:mr-4">{/* Logo/Image */}</div>
<div className="flex-1 text-center sm:text-left">{/* Content */}</div>
</div>
```
Example:
```tsx
import Image from 'next/image';
<Image
src="/images/logo.png"
alt="Company Logo"
width={72}
height={72}
className="h-full w-full rounded-lg object-contain"
/>
```
Ensure proper SSG setup:
Maintain this structure:
```
app/
├── layout.tsx # Root layout with Redux provider
├── page.tsx # Home page
└── globals.css # Global Tailwind styles
components/ # React components
lib/
├── store.ts # Redux store configuration
├── hooks.ts # Typed Redux hooks (useAppSelector, useAppDispatch)
└── slices/ # Redux slices (one per section)
public/
└── images/ # Image files
```
Follow these key rules:
Run `npm run lint` before committing and fix all warnings/errors.
When adding new content:
1. **NEVER hardcode** in components
2. Update or create appropriate Redux slice in `lib/slices/`
3. Define TypeScript interfaces for new data structures
4. Add slice to store if new
5. Use `useAppSelector` in component to consume state
6. Apply Tailwind styling following mobile-first pattern
7. Ensure dark mode support
8. Test responsive behavior on mobile and desktop
9. Run ESLint and fix issues
1. Create slice `lib/slices/testimonialsSlice.ts`:
```typescript
import { createSlice } from '@reduxjs/toolkit';
export interface Testimonial {
id: string;
author: string;
quote: string;
avatar: string;
}
interface TestimonialsState {
title: string;
items: Testimonial[];
}
const initialState: TestimonialsState = {
title: 'What People Say',
items: [
{ id: '1', author: 'Jane Doe', quote: 'Amazing!', avatar: '/images/jane.jpg' },
],
};
export const testimonialsSlice = createSlice({
name: 'testimonials',
initialState,
reducers: {},
});
export default testimonialsSlice.reducer;
```
2. Add to `lib/store.ts`:
```typescript
import testimonialsReducer from './slices/testimonialsSlice';
export const store = configureStore({
reducer: {
testimonials: testimonialsReducer,
// ... other slices
},
});
```
3. Create component `components/Testimonials.tsx`:
```typescript
'use client';
import Image from 'next/image';
import { useAppSelector } from '@/lib/hooks';
export default function Testimonials() {
const { title, items } = useAppSelector((state) => state.testimonials);
return (
<section className="border-t-2 border-zinc-300 bg-white dark:border-zinc-700 dark:bg-black">
<div className="mx-auto max-w-6xl px-6 py-20">
<h2 className="text-3xl font-bold text-zinc-900 dark:text-zinc-100 mb-8">
{title}
</h2>
<div className="space-y-8">
{items.map((testimonial) => (
<div key={testimonial.id} className="flex flex-col items-center gap-4 sm:flex-row sm:items-start">
<Image
src={testimonial.avatar}
alt={testimonial.author}
width={64}
height={64}
className="rounded-full"
/>
<div className="flex-1 text-center sm:text-left">
<p className="text-zinc-700 dark:text-zinc-300">{testimonial.quote}</p>
<p className="mt-2 font-semibold text-zinc-900 dark:text-zinc-100">
{testimonial.author}
</p>
</div>
</div>
))}
</div>
</div>
</section>
);
}
```
4. Add to `app/page.tsx`:
```typescript
import Testimonials from '@/components/Testimonials';
export default function Home() {
return (
<>
{/* Other sections */}
<Testimonials />
</>
);
}
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/nextjs-redux-tailwind-static-site-pattern/raw