Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions templates/blog/nextjs-monolith/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"root": true,
"extends": "next/core-web-vitals"
}
72 changes: 72 additions & 0 deletions templates/blog/nextjs-monolith/app/articles/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Link from 'next/link';

export default function ArticlesPage() {
const articles = [
{ slug: 'getting-started-with-nextjs-14', title: 'Getting Started with Next.js 14: A Complete Guide', excerpt: 'Learn how to build modern web applications with Next.js 14 App Router and Server Components.', author: 'Jane Smith', date: 'Jun 15, 2024', readTime: '8 min', category: 'Tutorial' },
{ slug: 'tailwind-css-best-practices', title: 'Tailwind CSS Best Practices for Large Projects', excerpt: 'Discover patterns and strategies for maintaining clean Tailwind CSS in enterprise applications.', author: 'Alex Chen', date: 'Jun 12, 2024', readTime: '6 min', category: 'CSS' },
{ slug: 'typescript-generics-explained', title: 'TypeScript Generics Explained Simply', excerpt: 'A practical guide to understanding and using TypeScript generics in your everyday code.', author: 'Maria Garcia', date: 'Jun 10, 2024', readTime: '10 min', category: 'TypeScript' },
{ slug: 'react-server-components', title: 'Understanding React Server Components', excerpt: 'Deep dive into how React Server Components work and when to use them.', author: 'David Park', date: 'Jun 8, 2024', readTime: '7 min', category: 'React' },
{ slug: 'building-design-systems', title: 'Building a Design System from Scratch', excerpt: 'Step-by-step guide to creating a cohesive design system for your team.', author: 'Sarah Johnson', date: 'Jun 5, 2024', readTime: '12 min', category: 'Design' },
{ slug: 'api-design-patterns', title: 'REST API Design Patterns You Should Know', excerpt: 'Essential patterns for building robust and scalable REST APIs.', author: 'James Wilson', date: 'Jun 3, 2024', readTime: '9 min', category: 'Backend' },
{ slug: 'state-management-2024', title: 'State Management in 2024: What to Use', excerpt: 'Comparing Zustand, Jotai, Redux Toolkit, and React Context for modern apps.', author: 'Emily Rodriguez', date: 'Jun 1, 2024', readTime: '11 min', category: 'React' },
{ slug: 'web-performance-optimization', title: 'Web Performance Optimization Checklist', excerpt: 'A comprehensive checklist for making your web applications blazing fast.', author: 'Tom Anderson', date: 'May 28, 2024', readTime: '14 min', category: 'Performance' },
];

const categories = ['All', 'Tutorial', 'React', 'TypeScript', 'CSS', 'Design', 'Backend', 'Performance'];

return (
<div className="min-h-screen bg-background">
<div className="max-w-5xl mx-auto px-6 py-12">
<div className="mb-8">
<h1 className="text-3xl font-bold text-foreground">All Articles</h1>
<p className="mt-2 text-text-secondary">Browse our collection of tutorials, guides, and insights</p>
</div>

{/* Category Filter */}
<div className="flex flex-wrap gap-2 mb-8">
{categories.map((cat, i) => (
<button
key={cat}
className={`px-4 py-2 text-sm rounded-theme transition ${
i === 0
? 'bg-primary text-white'
: 'bg-bg-secondary text-text-secondary hover:text-foreground'
}`}
>
{cat}
</button>
))}
</div>

{/* Articles List */}
<div className="space-y-6">
{articles.map((article) => (
<Link
key={article.slug}
href={`/articles/${article.slug}`}
className="block border border-border rounded-theme p-6 bg-card hover:shadow-md transition group"
>
<div className="flex items-center gap-3 mb-3">
<span className="px-2 py-1 text-xs rounded-full bg-bg-secondary text-text-secondary">
{article.category}
</span>
<span className="text-xs text-text-secondary">{article.readTime} read</span>
</div>
<h2 className="text-xl font-semibold text-foreground group-hover:text-primary transition">
{article.title}
</h2>
<p className="mt-2 text-text-secondary leading-relaxed">
{article.excerpt}
</p>
<div className="mt-4 flex items-center gap-2 text-sm text-text-secondary">
<span className="font-medium text-foreground">{article.author}</span>
<span>&middot;</span>
<span>{article.date}</span>
</div>
</Link>
))}
</div>
</div>
</div>
);
}
43 changes: 43 additions & 0 deletions templates/blog/nextjs-monolith/app/authors/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Link from 'next/link';

export default function AuthorsPage() {
const authors = [
{ slug: 'jane-smith', name: 'Jane Smith', role: 'Senior Frontend Engineer', articles: 12, bio: 'Passionate about React, accessibility, and building great developer experiences.' },
{ slug: 'alex-chen', name: 'Alex Chen', role: 'Design Engineer', articles: 9, bio: 'Bridging the gap between design and engineering with CSS and design systems.' },
{ slug: 'maria-garcia', name: 'Maria Garcia', role: 'TypeScript Advocate', articles: 8, bio: 'Making TypeScript approachable for developers of all skill levels.' },
{ slug: 'david-park', name: 'David Park', role: 'Full-Stack Developer', articles: 7, bio: 'Building scalable applications with Next.js and modern backend technologies.' },
{ slug: 'sarah-johnson', name: 'Sarah Johnson', role: 'UI/UX Designer', articles: 6, bio: 'Creating beautiful, functional interfaces that users love.' },
{ slug: 'james-wilson', name: 'James Wilson', role: 'Backend Architect', articles: 5, bio: 'Designing robust APIs and distributed systems at scale.' },
];

return (
<div className="min-h-screen bg-background">
<div className="max-w-5xl mx-auto px-6 py-12">
<div className="mb-8">
<h1 className="text-3xl font-bold text-foreground">Authors</h1>
<p className="mt-2 text-text-secondary">Meet the people behind the articles</p>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{authors.map((author) => (
<Link
key={author.slug}
href={`/authors/${author.slug}`}
className="border border-border rounded-theme p-6 bg-card hover:shadow-md transition group text-center"
>
<div className="w-16 h-16 rounded-full bg-primary mx-auto flex items-center justify-center text-white text-xl font-bold mb-4">
{author.name.split(' ').map((n) => n[0]).join('')}
</div>
<h2 className="text-lg font-semibold text-foreground group-hover:text-primary transition">
{author.name}
</h2>
<p className="text-sm text-primary mt-1">{author.role}</p>
<p className="text-sm text-text-secondary mt-3 leading-relaxed">{author.bio}</p>
<p className="text-xs text-text-secondary mt-4">{author.articles} articles published</p>
</Link>
))}
</div>
</div>
</div>
);
}
47 changes: 47 additions & 0 deletions templates/blog/nextjs-monolith/app/categories/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Link from 'next/link';

export default function CategoriesPage() {
const categories = [
{ name: 'React', slug: 'react', count: 24, description: 'Components, hooks, patterns, and best practices for React development.' },
{ name: 'TypeScript', slug: 'typescript', count: 18, description: 'Type safety, generics, utility types, and advanced TypeScript patterns.' },
{ name: 'Next.js', slug: 'nextjs', count: 15, description: 'App Router, Server Components, API routes, and deployment strategies.' },
{ name: 'CSS & Design', slug: 'css-design', count: 12, description: 'Tailwind CSS, animations, responsive design, and design systems.' },
{ name: 'Backend', slug: 'backend', count: 10, description: 'APIs, databases, authentication, and server-side architecture.' },
{ name: 'DevOps', slug: 'devops', count: 8, description: 'CI/CD, Docker, deployment, monitoring, and infrastructure.' },
{ name: 'Performance', slug: 'performance', count: 7, description: 'Core Web Vitals, optimization techniques, and benchmarking.' },
{ name: 'Career', slug: 'career', count: 5, description: 'Job hunting, interviews, growth, and developer life.' },
];

return (
<div className="min-h-screen bg-background">
<div className="max-w-5xl mx-auto px-6 py-12">
<div className="mb-8">
<h1 className="text-3xl font-bold text-foreground">Categories</h1>
<p className="mt-2 text-text-secondary">Browse articles by topic</p>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{categories.map((category) => (
<Link
key={category.slug}
href={`/categories/${category.slug}`}
className="border border-border rounded-theme p-6 bg-card hover:shadow-md transition group"
>
<div className="flex items-center justify-between mb-2">
<h2 className="text-lg font-semibold text-foreground group-hover:text-primary transition">
{category.name}
</h2>
<span className="px-2 py-1 text-xs rounded-full bg-bg-secondary text-text-secondary">
{category.count} articles
</span>
</div>
<p className="text-text-secondary text-sm leading-relaxed">
{category.description}
</p>
</Link>
))}
</div>
</div>
</div>
);
}
59 changes: 59 additions & 0 deletions templates/blog/nextjs-monolith/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

/* ===== Base Theme: Minimal Clean (Default) ===== */
:root {
--bg-color: #ffffff;
--bg-secondary: #f9fafb;
--text-color: #111827;
--text-secondary: #6b7280;
--primary: #2563eb;
--primary-hover: #1d4ed8;
--border-color: #e5e7eb;
--card-bg: #ffffff;
--font-family: 'Inter', system-ui, sans-serif;
--radius: 0.5rem;
}

/* ===== Glassmorphism Theme ===== */
[data-theme="Glassmorphism"] {
--bg-color: #0f172a;
--bg-secondary: rgba(255, 255, 255, 0.05);
--text-color: #f1f5f9;
--text-secondary: #94a3b8;
--primary: #8b5cf6;
--primary-hover: #7c3aed;
--border-color: rgba(255, 255, 255, 0.1);
--card-bg: rgba(255, 255, 255, 0.08);
--font-family: 'Inter', system-ui, sans-serif;
--radius: 1rem;
}

[data-theme="Glassmorphism"] .glass {
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
}

/* ===== Dark Terminal Theme ===== */
[data-theme="Dark Terminal"] {
--bg-color: #000000;
--bg-secondary: #0a0a0a;
--text-color: #3fb950;
--text-secondary: #8b949e;
--primary: #3fb950;
--primary-hover: #2ea043;
--border-color: #21262d;
--card-bg: #0d1117;
--font-family: 'JetBrains Mono', 'Fira Code', monospace;
--radius: 0.25rem;
}

/* ===== Apply variables globally ===== */
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: var(--font-family);
}
122 changes: 122 additions & 0 deletions templates/blog/nextjs-monolith/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import './globals.css';
import AnimationProvider from '../components/AnimationProvider';
{{#if (eq design "Dark Terminal")}}
import { Terminal } from 'lucide-react';
{{/if}}

export const metadata: Metadata = {
title: '{{projectName}} - Blog',
description: 'A {{variant}} blog built with Opusify CLI.',
};

const navLinks = [
{ label: 'Home', href: '/' },
{ label: 'Articles', href: '/articles' },
{ label: 'Categories', href: '/categories' },
{ label: 'Authors', href: '/authors' },
];

function Navbar() {
return (
<header className="border-b border-border bg-card">
<nav className="max-w-5xl mx-auto px-6 h-16 flex items-center justify-between">
<Link href="/" className="text-xl font-bold text-primary flex items-center gap-2">
{{#if (eq design "Dark Terminal")}}
<Terminal className="w-5 h-5" />
{{/if}}
{{projectName}}
</Link>
<ul className="flex gap-6">
{navLinks.map((link) => (
<li key={link.href}>
<Link
href={link.href}
className="text-text-secondary hover:text-foreground transition"
>
{link.label}
</Link>
</li>
))}
</ul>
<div>
<button className="px-4 py-2 rounded-theme bg-primary text-white text-sm font-medium hover:bg-primary-hover transition">
Subscribe
</button>
</div>
</nav>
</header>
);
}

function Sidebar() {
return (
<aside className="w-64 border-r border-border bg-card min-h-screen p-6">
<Link href="/" className="text-xl font-bold text-primary flex items-center gap-2 mb-8">
{{#if (eq design "Dark Terminal")}}
<Terminal className="w-5 h-5" />
{{/if}}
{{projectName}}
</Link>
<nav className="mb-8">
<ul className="space-y-2">
{navLinks.map((link) => (
<li key={link.href}>
<Link
href={link.href}
className="block px-4 py-2 rounded-theme text-text-secondary hover:bg-bg-secondary hover:text-foreground transition"
>
{link.label}
</Link>
</li>
))}
</ul>
</nav>
<div className="border-t border-border pt-6">
<h3 className="text-xs font-medium text-text-secondary uppercase tracking-wider mb-3">Popular Tags</h3>
<div className="flex flex-wrap gap-2">
{['React', 'Next.js', 'TypeScript', 'CSS', 'Node.js', 'Design'].map((tag) => (
<span key={tag} className="px-2 py-1 text-xs rounded-theme bg-bg-secondary text-text-secondary">
{tag}
</span>
))}
</div>
</div>
</aside>
);
}

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const useSidebar = '{{includeSidebar}}' === 'true';

return (
<html lang="en" data-theme="{{design}}">
<body>
{useSidebar ? (
<div className="flex">
<Sidebar />
<main className="flex-1">
<AnimationProvider>
{children}
</AnimationProvider>
</main>
</div>
) : (
<>
<Navbar />
<main>
<AnimationProvider>
{children}
</AnimationProvider>
</main>
</>
)}
</body>
</html>
);
}
Loading
Loading