Update website content, add quote of the day

This commit is contained in:
Jake Runyan 2026-02-12 23:15:01 -08:00
parent f2b6e8b1c2
commit 153c73f438
9 changed files with 140 additions and 65 deletions

View File

@ -1,8 +1,8 @@
import type { Metadata } from 'next'; import type { Metadata } from 'next';
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'About - Cooking', title: 'About - PWS Recipes',
description: 'Learn more about our recipe collection', description: 'Learn more about the PWS recipe collection',
}; };
export default function AboutPage() { export default function AboutPage() {
@ -10,22 +10,20 @@ export default function AboutPage() {
<div className="max-w-3xl space-y-8"> <div className="max-w-3xl space-y-8">
<div className="space-y-4"> <div className="space-y-4">
<h1 className="text-4xl font-bold text-gray-900 dark:text-white"> <h1 className="text-4xl font-bold text-gray-900 dark:text-white">
About About PWS Recipes
</h1> </h1>
<p className="text-lg text-gray-600 dark:text-gray-400"> <p className="text-lg text-gray-600 dark:text-gray-400">
Welcome to our content-first recipe site Explore recipes in a user-friendly manner on a website that prioritizes your cooking experience over monetizing your clicks.
</p> </p>
</div> </div>
<div className="prose dark:prose-invert max-w-none"> <div className="prose dark:prose-invert max-w-none">
<section className="space-y-4"> <section className="space-y-4">
<h2 className="text-2xl font-semibold text-gray-900 dark:text-white"> <h2 className="text-2xl font-semibold text-gray-900 dark:text-white">
Our Mission The PWS Mission
</h2> </h2>
<p className="text-gray-600 dark:text-gray-400"> <p className="text-gray-600 dark:text-gray-400">
We believe cooking should be accessible, enjoyable, and creative. Our goal is to provide We believe that cooking should be accessible, enjoyable, and creative. Our goal while collecting and organizing these recipes is to make knowledge readily available and keep your cooking experience a cathartic and fun one.
high-quality recipes with clear instructions and beautiful photography to inspire home cooks
everywhere.
</p> </p>
</section> </section>
@ -48,8 +46,7 @@ export default function AboutPage() {
Technology Technology
</h2> </h2>
<p className="text-gray-600 dark:text-gray-400"> <p className="text-gray-600 dark:text-gray-400">
Built with modern web technologies including Next.js, React, TypeScript, and Tailwind CSS Built with modern web technologies including Next.js, React, TypeScript, and Tailwind CSS to ensure fast performance.
to ensure fast performance and excellent SEO.
</p> </p>
</section> </section>
</div> </div>

View File

@ -9,7 +9,7 @@
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--background: #0a0a0a; --background: #111827;
--foreground: #ededed; --foreground: #ededed;
} }
} }

View File

@ -4,16 +4,16 @@ import Header from "@/components/Header";
import Footer from "@/components/Footer"; import Footer from "@/components/Footer";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Cooking - Recipe Collection", title: "PWS Recipes",
description: "A content-first recipe site with delicious recipes and cooking tips", description: "A content-first recipe site with delicious recipes and cooking tips.",
keywords: ["recipes", "cooking", "food", "kitchen"], keywords: ["recipes", "cooking", "food", "kitchen"],
authors: [{ name: "Cooking" }], authors: [{ name: "Cooking" }],
openGraph: { openGraph: {
type: "website", type: "website",
locale: "en_US", locale: "en_US",
url: "https://cooking.example.com", url: "https://recipes.whitney.rip",
siteName: "Cooking", siteName: "PWS Recipes",
title: "Cooking - Recipe Collection", title: "PWS Recipes",
description: "A content-first recipe site with delicious recipes and cooking tips", description: "A content-first recipe site with delicious recipes and cooking tips",
}, },
}; };
@ -25,7 +25,7 @@ export default function RootLayout({
}>) { }>) {
return ( return (
<html lang="en"> <html lang="en">
<body className="flex flex-col min-h-screen"> <body className="flex flex-col min-h-screen bg-white dark:bg-gray-900">
<Header /> <Header />
<main className="flex-1 max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-8"> <main className="flex-1 max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-8">
{children} {children}

View File

@ -1,28 +1,27 @@
import Image from 'next/image'; import Image from 'next/image';
import Link from 'next/link'; import Link from 'next/link';
import QuoteOfTheDay from '@/components/QuoteOfTheDay';
export default function Home() { export default function Home() {
return ( return (
<div className="space-y-12"> <div className="space-y-12">
<section className="text-center space-y-6"> <section className="text-center space-y-6">
<h1 className="text-5xl font-bold text-gray-900 dark:text-white"> <h1 className="text-5xl font-bold text-gray-900 dark:text-white">
Welcome to Cooking PWS Recipes
</h1> </h1>
<p className="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto"> <QuoteOfTheDay />
Discover delicious recipes, cooking tips, and culinary inspiration for every occasion.
</p>
<div className="flex gap-4 justify-center"> <div className="flex gap-4 justify-center">
<Link <Link
href="/recipes" href="/recipes"
className="px-6 py-3 bg-gray-900 dark:bg-white text-white dark:text-gray-900 rounded-lg hover:bg-gray-700 dark:hover:bg-gray-200 transition-colors font-medium" className="px-6 py-3 bg-gray-900 dark:bg-white text-white dark:text-gray-900 rounded-lg hover:bg-gray-700 dark:hover:bg-gray-200 transition-colors font-medium"
> >
Browse Recipes Cook Something!
</Link> </Link>
<Link <Link
href="/about" href="/about"
className="px-6 py-3 border border-gray-900 dark:border-white text-gray-900 dark:text-white rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium" className="px-6 py-3 border border-gray-900 dark:border-white text-gray-900 dark:text-white rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
> >
Learn More Why PWS Recipes?
</Link> </Link>
</div> </div>
</section> </section>
@ -32,16 +31,16 @@ export default function Home() {
<div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg"> <div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg">
<Image <Image
src="/assets/want_to_cook.svg" src="/assets/want_to_cook.svg"
alt="Person deciding what to cook" alt="Person happily cooking a stew"
fill fill
className="object-cover" className="object-cover"
unoptimized unoptimized
/> />
</div> </div>
<div className="w-full md:w-2/5 space-y-4"> <div className="w-full md:w-2/5 space-y-4 text-center md:text-left">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">Easy Recipes</h2> <h2 className="text-3xl font-bold text-gray-900 dark:text-white">You Want to Cook</h2>
<p className="text-lg text-gray-600 dark:text-gray-400"> <p className="text-lg text-gray-600 dark:text-gray-400">
Step-by-step instructions for home cooks of all skill levels. Whether you&apos;re a beginner or an experienced cook, every recipe is written with clarity in mind. Cooking is fun, theraputic, and you need to eat stuff to survive. I&apos;ve collected and tweaked recipes over the years, but over time the bookmark folder has gotten big and recipe sites have gotten worse...
</p> </p>
<Link <Link
href="/recipes" href="/recipes"
@ -55,17 +54,17 @@ export default function Home() {
<div className="flex flex-col md:flex-row-reverse items-center gap-12"> <div className="flex flex-col md:flex-row-reverse items-center gap-12">
<div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg"> <div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg">
<Image <Image
src="/assets/online_cookbook.svg" src="/assets/recipe_sites_suck.svg"
alt="Online cookbook illustration" alt="Online cookbook illustration"
fill fill
className="object-cover" className="object-cover"
unoptimized unoptimized
/> />
</div> </div>
<div className="w-full md:w-2/5 space-y-4"> <div className="w-full md:w-2/5 space-y-4 text-center md:text-left">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">Beautiful Photos</h2> <h2 className="text-3xl font-bold text-gray-900 dark:text-white">But Recipe Sites Suck!</h2>
<p className="text-lg text-gray-600 dark:text-gray-400"> <p className="text-lg text-gray-600 dark:text-gray-400">
High-quality images accompany every recipe to inspire your cooking journey. See exactly what you&apos;re making before you start. Monetized recipe sites don't bother me, but I do mind when sites have overly aggressive ad integrations that block or move around the main content. Many modern sites share the same user-unfriendly plugins.
</p> </p>
</div> </div>
</div> </div>
@ -73,17 +72,17 @@ export default function Home() {
<div className="flex flex-col md:flex-row items-center gap-12"> <div className="flex flex-col md:flex-row items-center gap-12">
<div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg"> <div className="w-full md:w-3/5 relative aspect-[3/2] rounded-2xl overflow-hidden shadow-lg">
<Image <Image
src="/assets/recipe_sites_suck.svg" src="/assets/online_cookbook.svg"
alt="Organized recipe collection" alt="Organized recipe collection"
fill fill
className="object-cover" className="object-cover"
unoptimized unoptimized
/> />
</div> </div>
<div className="w-full md:w-2/5 space-y-4"> <div className="w-full md:w-2/5 space-y-4 text-center md:text-left">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">No Nonsense</h2> <h2 className="text-3xl font-bold text-gray-900 dark:text-white">Welcome to my Self-Hosted Cookbook!</h2>
<p className="text-lg text-gray-600 dark:text-gray-400"> <p className="text-lg text-gray-600 dark:text-gray-400">
Just recipes. Find what you need quickly by browsing categories, filtering by tags, or searching by ingredient. Rather than make a physical cookbook, I have built this website to collect my recipes. This content-first website framework renders each page from a MDX markdown file, offering a friendly approach to frontend design for us backend engineers.
</p> </p>
</div> </div>
</div> </div>

View File

@ -9,7 +9,7 @@ export default function Header() {
href="/" href="/"
className="text-2xl font-bold text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300 transition-colors" className="text-2xl font-bold text-gray-900 dark:text-white hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
> >
Cooking PWS Recipes
</Link> </Link>
<div className="flex space-x-8"> <div className="flex space-x-8">

View File

@ -0,0 +1,62 @@
'use client';
import { useState, useEffect } from 'react';
import quotes from '@/public/quotes.json';
interface Quote {
text: string;
author?: string;
link?: string;
}
function getDayOfYear(): number {
const now = new Date();
const start = new Date(now.getFullYear(), 0, 0);
const diff = now.getTime() - start.getTime();
return Math.floor(diff / (1000 * 60 * 60 * 24));
}
export default function QuoteOfTheDay() {
const [quote, setQuote] = useState<Quote | null>(null);
useEffect(() => {
const index = getDayOfYear() % quotes.length;
setQuote(quotes[index] as Quote);
}, []);
if (!quote) {
return <p className="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">&nbsp;</p>;
}
const content = quote.author ? (
<>
<span className="italic">&ldquo;{quote.text}&rdquo;</span>
<span> &mdash; {quote.author}</span>
</>
) : (
<span>{quote.text}</span>
);
const href = quote.link && !/^https?:\/\//.test(quote.link)
? `https://${quote.link}`
: quote.link;
const wrapper = href ? (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="hover:text-gray-900 dark:hover:text-gray-200 hover:underline transition-colors"
>
{content}
</a>
) : (
content
);
return (
<p className="text-xl text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
{wrapper}
</p>
);
}

View File

@ -34,66 +34,76 @@ export default function RecipeLayout({
{/* Mobile Overlay */} {/* Mobile Overlay */}
{sidebarOpen && ( {sidebarOpen && (
<div <div
className="lg:hidden fixed inset-0 bg-black bg-opacity-50 z-40" className="lg:hidden fixed inset-0 bg-black/50 z-40"
onClick={() => setSidebarOpen(false)} onClick={() => setSidebarOpen(false)}
aria-hidden="true" aria-hidden="true"
/> />
)} )}
{/* Mobile menu button - only visible on mobile */} {/* Mobile filter button */}
<div className="lg:hidden sticky top-0 z-30 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700 p-4"> <div className="lg:hidden mb-4">
<button <button
onClick={() => setSidebarOpen(true)} onClick={() => setSidebarOpen(true)}
className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors" className="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-800 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors"
aria-label="Open filters sidebar" aria-label="Open filters sidebar"
aria-expanded={sidebarOpen} aria-expanded={sidebarOpen}
aria-controls="recipes-sidebar" aria-controls="recipes-sidebar"
> >
<span aria-hidden="true"></span> <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
</svg>
<span>Filters</span> <span>Filters</span>
</button> </button>
</div> </div>
<div className="flex"> <div className="flex">
{/* Sidebar - Always visible on desktop (lg+), slide-out on mobile */} {/* Sidebar - Always visible on desktop (lg+), slide-out drawer on mobile */}
<aside <aside
id="recipes-sidebar" id="recipes-sidebar"
className={` className={`
fixed lg:relative z-50 lg:z-0 fixed lg:relative z-50 lg:z-0
bg-white dark:bg-gray-900 border-r border-gray-200 dark:border-gray-700 top-0 bottom-0 left-0
w-64 lg:w-64 w-72 lg:w-64
h-screen lg:h-auto bg-white dark:bg-gray-900
border-r border-gray-200 dark:border-gray-700
transition-transform duration-300 ease-in-out transition-transform duration-300 ease-in-out
${sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'} ${sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'}
`} `}
aria-label="Recipe filters" aria-label="Recipe filters"
> >
<div className="h-full lg:sticky lg:top-0 flex flex-col p-4 overflow-y-auto"> <div className="h-full lg:sticky lg:top-0 flex flex-col overflow-y-auto">
{/* Mobile close button */} {/* Mobile sidebar header */}
<button <div className="lg:hidden flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
onClick={() => setSidebarOpen(false)} <span className="text-sm font-semibold text-gray-900 dark:text-white">Filters</span>
className="lg:hidden absolute top-4 right-4 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 text-xl" <button
aria-label="Close filters sidebar" onClick={() => setSidebarOpen(false)}
> className="p-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
<span aria-hidden="true"></span> aria-label="Close filters sidebar"
</button> >
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/* Sidebar content */} {/* Sidebar content */}
{showFilters && filters && ( <div className="p-4">
<RecipesSidebar {showFilters && filters && (
categories={categories} <RecipesSidebar
tags={tags} categories={categories}
filters={filters} tags={tags}
onFilterChange={handleFilterChange} filters={filters}
/> onFilterChange={handleFilterChange}
)} />
)}
</div>
</div> </div>
</aside> </aside>
{/* Main content */} {/* Main content */}
<main className="flex-1 p-6"> <div className="flex-1 min-w-0">
{children} {children}
</main> </div>
</div> </div>
</div> </div>
); );

View File

@ -12,7 +12,7 @@ interface RecipePageClientProps {
export default function RecipePageClient({ recipe, sections }: RecipePageClientProps) { export default function RecipePageClient({ recipe, sections }: RecipePageClientProps) {
return ( return (
<div className="min-h-screen p-6"> <div>
<article className="max-w-4xl mx-auto"> <article className="max-w-4xl mx-auto">
{/* Back navigation */} {/* Back navigation */}
<nav aria-label="Breadcrumb"> <nav aria-label="Breadcrumb">

7
public/quotes.json Normal file
View File

@ -0,0 +1,7 @@
[
{ "text": "Let him Cook!", "author": "Lil B", "link": "https://knowyourmeme.com/memes/let-him-cook-let-that-boy-cook"},
{ "text": "I think careful cooking is love, don't you?", "author": "Julia Child" },
{ "text": "The only time to eat diet food is while you're waiting for the steak to cook.", "author": "Julia Child" },
{ "text": "A recipe has no soul. You, as the cook, must bring soul to the recipe.", "author": "Thomas Keller"},
{ "text": "People who love to eat are always the best people.", "author": "Julia Child" }
]