This commit is contained in:
2026-03-23 19:00:17 -05:00
parent f0c19fbbfa
commit 92676e652a
94 changed files with 9558 additions and 6871 deletions

View File

@@ -1,5 +1,5 @@
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import Header from './components/Header';
import Footer from './components/Footer';
import Cart from './components/Cart';
@@ -20,7 +20,6 @@ const ArticleDetail = lazy(() => import('./pages/ArticleDetail'));
const Checkout = lazy(() => import('./pages/Checkout'));
const MockPayment = lazy(() => import('./pages/MockPayment'));
const Success = lazy(() => import('./pages/Success'));
const Admin = lazy(() => import('./pages/Admin'));
const FAQ = lazy(() => import('./pages/FAQ'));
const Shipping = lazy(() => import('./pages/Shipping'));
const Returns = lazy(() => import('./pages/Returns'));
@@ -43,11 +42,14 @@ function App() {
<Route path="/collections/:slug" element={<ProductDetail />} />
<Route path="/atelier" element={<Atelier />} />
<Route path="/editorial" element={<Editorial />} />
<Route path="/editorial/product-photography-for-small-businesses" element={<ProductPhotography />} />
<Route path="/editorial/how-to-care-for-handmade-ceramics" element={<PackagingGuide />} />
<Route path="/editorial/finding-motivation-in-clay" element={<MotivationInClay />} />
<Route path="/editorial/:slug" element={<ArticleDetail />} />
<Route path="/checkout" element={<Checkout />} />
<Route path="/mock-payment" element={<MockPayment />} />
<Route path="/success" element={<Success />} />
<Route path="/admin" element={<Admin />} />
<Route path="/admin" element={<Navigate to="/" replace />} />
<Route path="/faq" element={<FAQ />} />
<Route path="/shipping" element={<Shipping />} />
<Route path="/returns" element={<Returns />} />

View File

@@ -10,6 +10,7 @@ interface BlogPostLayoutProps {
image: string;
imageAlt: string;
children: React.ReactNode;
author?: string;
}
const BlogPostLayout: React.FC<BlogPostLayoutProps> = ({
@@ -19,9 +20,13 @@ const BlogPostLayout: React.FC<BlogPostLayoutProps> = ({
image,
imageAlt,
children,
author = 'Claudia Knuth',
}) => {
const { articles } = useStore();
// Scroll to top on mount
const getArticleHref = (slug: string) => (
slug.startsWith('/editorial/') ? slug : `/editorial/${slug}`
);
useEffect(() => {
window.scrollTo(0, 0);
}, []);
@@ -30,13 +35,12 @@ const BlogPostLayout: React.FC<BlogPostLayoutProps> = ({
return (
<div className="bg-stone-50 dark:bg-black min-h-screen font-body transition-colors duration-500">
<main className="pt-32 pb-24">
{/* Article Header */}
<article className="max-w-4xl mx-auto px-6 md:px-12">
<div className="flex items-center space-x-4 mb-8 justify-center">
<div className="flex items-center space-x-4 mb-8 justify-center flex-wrap gap-y-2">
<span className="text-xs uppercase tracking-[0.2em] text-text-muted border border-text-muted/30 px-3 py-1 rounded-full">{category}</span>
<span className="text-xs uppercase tracking-[0.2em] text-text-muted">{date}</span>
<span className="text-xs text-text-muted">by <span className="font-medium" itemProp="author">{author}</span></span>
</div>
<motion.h1
@@ -48,7 +52,6 @@ const BlogPostLayout: React.FC<BlogPostLayoutProps> = ({
{title}
</motion.h1>
{/* Hero Image */}
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
@@ -62,18 +65,16 @@ const BlogPostLayout: React.FC<BlogPostLayoutProps> = ({
/>
</motion.div>
{/* Content Container */}
<div className="prose prose-stone dark:prose-invert max-w-none mx-auto prose-headings:font-display prose-headings:font-light prose-p:font-light prose-p:leading-loose prose-a:text-terracotta hover:prose-a:text-terracotta-dark prose-img:rounded-sm">
{children}
</div>
{/* Read Next Section */}
{nextArticles.length > 0 && (
<div className="mt-24 pt-16 border-t border-stone-200 dark:border-stone-800">
<h3 className="font-display text-3xl text-center mb-12 text-text-main dark:text-white">Read Next</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{nextArticles.map((post) => (
<Link key={post.id} to={`/editorial/${post.slug}`} className="group block">
<Link key={post.id} to={getArticleHref(post.slug)} className="group block">
<div className="aspect-[3/2] overflow-hidden bg-stone-100 mb-4">
<img
src={post.image}
@@ -86,7 +87,7 @@ const BlogPostLayout: React.FC<BlogPostLayoutProps> = ({
</h4>
<div className="flex items-center space-x-2 text-sm text-stone-500 uppercase tracking-widest">
<span>{post.category}</span>
<span></span>
<span>-</span>
<span>{post.date}</span>
</div>
</Link>
@@ -95,7 +96,6 @@ const BlogPostLayout: React.FC<BlogPostLayoutProps> = ({
</div>
)}
{/* Back Link */}
<div className="mt-20 text-center">
<Link to="/editorial" className="inline-block border-b border-black dark:border-white pb-1 text-sm uppercase tracking-widest hover:text-stone-500 transition-colors">
Back to Editorial
@@ -103,8 +103,6 @@ const BlogPostLayout: React.FC<BlogPostLayoutProps> = ({
</div>
</article>
</main>
</div>
);
};

View File

@@ -22,9 +22,10 @@ const cardVariants = {
};
const Collections: React.FC = () => {
const col1 = [COLLECTIONS[0], COLLECTIONS[1]];
const col2 = [COLLECTIONS[2], COLLECTIONS[3]];
const col3 = [COLLECTIONS[4], COLLECTIONS[5]];
const col1 = COLLECTIONS.filter((_, i) => i % 4 === 0);
const col2 = COLLECTIONS.filter((_, i) => i % 4 === 1);
const col3 = COLLECTIONS.filter((_, i) => i % 4 === 2);
const col4 = COLLECTIONS.filter((_, i) => i % 4 === 3);
const renderCard = (item: CollectionItem, index: number) => (
<motion.a
@@ -62,22 +63,6 @@ const Collections: React.FC = () => {
style={{ transformOrigin: "left" }}
/>
</div>
<motion.div
className="flex justify-between items-center border-t border-gray-400/50 dark:border-gray-800 pt-4"
initial={{ opacity: 0.8 }}
whileHover={{ opacity: 1 }}
>
<h3 className="font-display text-3xl font-light text-text-main dark:text-white group-hover:italic transition-all duration-300">
{item.title}
</h3>
<motion.span
className="text-xs uppercase tracking-widest text-text-muted"
whileHover={{ x: 5 }}
transition={{ duration: 0.3 }}
>
{item.number}
</motion.span>
</motion.div>
</motion.a>
);
@@ -99,16 +84,19 @@ const Collections: React.FC = () => {
</p>
</motion.div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 lg:gap-16">
<div className="flex flex-col space-y-16 md:space-y-32">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 md:gap-8 lg:gap-12">
<div className="flex flex-col space-y-8 md:space-y-16">
{col1.map((item, idx) => renderCard(item, idx))}
</div>
<div className="flex flex-col space-y-16 md:space-y-32 md:pt-32">
<div className="flex flex-col space-y-8 md:space-y-16 pt-16 md:pt-24">
{col2.map((item, idx) => renderCard(item, idx + 2))}
</div>
<div className="flex flex-col space-y-16 md:space-y-32 md:pt-16 lg:pt-0">
<div className="flex flex-col space-y-8 md:space-y-16 pt-8 md:pt-12 lg:pt-0">
{col3.map((item, idx) => renderCard(item, idx + 4))}
</div>
<div className="flex flex-col space-y-8 md:space-y-16 pt-24 md:pt-32 lg:pt-24">
{col4.map((item, idx) => renderCard(item, idx + 6))}
</div>
</div>
</div>
</section>

View File

@@ -41,28 +41,24 @@ const FAQ: React.FC = () => {
const faqs = [
{
question: "Do you ship your ceramics internationally?",
answer: "Currently, we ship our handmade pottery mainly within Texas and the United States. We occasionally open international shipping spots for specific drops. Sign up for our newsletter to be notified."
question: "Is the online shop currently open?",
answer: "Our online shop is temporarily closed while we focus on new collections and studio work. Follow us on Instagram or sign up for our newsletter to be the first to know when it reopens. For commissions, reach out directly at knuth.claudia@gmail.com."
},
{
question: "Are your pieces dishwasher and microwave safe?",
answer: "Yes! Our functional stoneware, including mugs, plates, and bowls, is fired to cone 6 oxidation, making it durable for daily use. However, hand washing is always recommended to prolong the life of your unique handmade ceramics."
answer: "Yes! Our functional stoneware, including mugs, plates, and bowls, is high-fire kiln fired, making it durable for daily use. However, hand washing is always recommended to prolong the life of your unique handmade ceramics."
},
{
question: "Where is your studio located?",
answer: "Our studio is based in the heart of Corpus Christi, Texas. We take inspiration from the Gulf Coast landscape. We offer local pickup for our Corpus Christi neighbors!"
answer: "Our work is rooted in Corpus Christi, Texas, inspired by the colors and textures of the Gulf Coast."
},
{
question: "Do you offer pottery classes in Corpus Christi?",
answer: "We are working on bringing intimate wheel-throwing workshops to our Corpus Christi studio soon. Check our 'Atelier' page or follow us on Instagram for announcements."
answer: "Pottery classes and wheel-throwing workshops are available through the Art Center of Corpus Christi. Visit the Art Center for current schedules and registration."
},
{
question: "Do you take custom orders or commissions?",
answer: "We accept a limited number of custom dinnerware commissions each year. If you are looking for a bespoke set for your home or restaurant, please contact us directly."
},
{
question: "How often do you restock the shop?",
answer: "We work in small batches and typically release a new 'Sandstone' or 'Seafoam' collection every 4-6 weeks. Join our email list to get early access to the next kiln opening."
answer: "We accept a limited number of custom dinnerware commissions each year. If you are looking for a bespoke set for your home or restaurant, reach out directly at knuth.claudia@gmail.com."
},
{
question: "What clay bodies and glazes do you use?",

View File

@@ -59,14 +59,18 @@ const FeatureSection: React.FC = () => {
<section ref={sectionRef} className="py-32 md:py-48 bg-sage dark:bg-stone-900 overflow-hidden relative transition-colors duration-500">
<div className="max-w-[1800px] mx-auto px-6">
<div className="relative flex flex-col md:block">
<div className="hidden md:block absolute -top-24 left-10 z-0 select-none opacity-[0.03] dark:opacity-[0.05] pointer-events-none">
<div className="hidden md:block absolute -top-24 left-10 z-0 select-none opacity-10 dark:opacity-20 pointer-events-none">
<span className="font-display text-[20rem] leading-none text-black dark:text-white">CRAFT</span>
</div>
<div
ref={imageRef}
className="w-full md:w-3/5 h-[600px] md:h-[800px] ml-auto relative z-10 shadow-2xl bg-center bg-cover bg-no-repeat"
style={{ backgroundImage: "url('/ceramic-cups.png')" }}
className="w-full md:w-3/5 h-[400px] md:h-[600px] ml-auto relative z-10 shadow-2xl overflow-hidden"
>
<img
src="/landingpage/2.png"
alt="Handcrafted stoneware ceramics by KNUTH Ceramics — slow-made pottery from Corpus Christi, Texas"
className="w-full h-full object-cover object-center"
/>
</div>
<div ref={contentRef} className="relative z-20 mt-[-100px] md:mt-0 md:absolute md:top-1/2 md:left-20 md:-translate-y-1/2 bg-white dark:bg-stone-900 p-12 md:p-20 shadow-xl max-w-xl mx-auto md:mx-0">
<span className="block w-12 h-[1px] bg-text-main mb-8"></span>

View File

@@ -8,6 +8,8 @@ const DISABLED_FOOTER_LINKS = new Set([
'Sustainability',
'Careers',
'Press',
'Shipping',
'Returns',
]);
const Footer: React.FC = () => {
@@ -36,29 +38,38 @@ const Footer: React.FC = () => {
{/* Brand & Mission */}
<div className="lg:col-span-5 flex flex-col justify-between h-full">
<div>
<h2 className="font-display text-6xl md:text-8xl leading-none tracking-tighter mb-8 bg-gradient-to-br from-white to-stone-400 bg-clip-text text-transparent">
<h2 className="font-display text-6xl md:text-8xl leading-none tracking-tighter mb-6 bg-gradient-to-br from-white to-stone-400 bg-clip-text text-transparent">
KNUTH Ceramics
</h2>
<div className="mb-8">
<span className="font-body text-[0.7rem] uppercase tracking-[0.2em] border border-stone-800 px-3 py-1.5 inline-block text-stone-300 bg-stone-900/40">
Online Shop Opening Coming Soon
</span>
</div>
<p className="font-body text-lg font-light text-stone-400 leading-relaxed max-w-md">
Handcrafted ceramics for the modern home. Created with intention, fired with patience, and delivered with care.
</p>
</div>
<div className="mt-16 lg:mt-0">
<h4 className="text-sm font-bold uppercase tracking-widest mb-6">Join our newsletter</h4>
<form className="flex flex-col sm:flex-row gap-4 max-w-md" onSubmit={(e) => e.preventDefault()}>
<input
className="bg-white/5 border border-white/10 text-white placeholder-stone-500 focus:outline-none focus:border-white/30 text-sm px-6 py-4 w-full transition-colors"
placeholder="Enter your email"
type="email"
/>
<button
className="bg-white text-black px-8 py-4 text-xs font-bold uppercase tracking-widest hover:bg-stone-200 transition-colors"
type="submit"
<h4 className="text-sm font-bold uppercase tracking-widest mb-4">Get in touch</h4>
<a
href="mailto:knuth.claudia@gmail.com"
className="font-body text-stone-400 hover:text-white transition-colors text-base block mb-2"
>
Subscribe
</button>
</form>
knuth.claudia@gmail.com
</a>
<a
href="https://www.instagram.com/knuth.ceramics"
target="_blank"
rel="noopener noreferrer"
className="font-body text-stone-400 hover:text-white transition-colors text-base block"
aria-label="Instagram"
>
<svg viewBox="0 0 24 24" fill="currentColor" className="w-5 h-5">
<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/>
</svg>
</a>
</div>
</div>
@@ -99,12 +110,11 @@ const Footer: React.FC = () => {
{/* Bottom Bar */}
<div className="border-t border-white/10 pt-12 flex flex-col md:flex-row justify-between items-center text-xs text-stone-500 tracking-widest uppercase font-light">
<p>© 2025 KNUTH Ceramics. All rights reserved.</p>
<p>© 2026 KNUTH Ceramics. All rights reserved.</p>
<div className="flex space-x-8 mt-6 md:mt-0">
<Link className="hover:text-white transition-colors" to="/privacy">Privacy</Link>
<Link className="hover:text-white transition-colors" to="/returns">Terms</Link>
<Link className="hover:text-white transition-colors" to="/cookies">Cookies</Link>
<Link className="hover:text-white transition-colors" to="/admin">Admin</Link>
</div>
</div>
</div>

View File

@@ -26,18 +26,18 @@ const GallerySection: React.FC = () => {
viewport={{ once: true }}
transition={{ duration: 0.6 }}
>
<div className="flex items-center gap-4">
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 via-pink-500 to-orange-400 p-[2px]">
<a href="https://www.instagram.com/knuth.ceramics" target="_blank" rel="noopener noreferrer" className="flex items-center gap-4 group cursor-pointer">
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 via-pink-500 to-orange-400 p-[2px] transition-transform group-hover:scale-105 duration-300">
<div className="w-full h-full rounded-full bg-white dark:bg-background-dark flex items-center justify-center">
<span className="font-display text-lg">K</span>
</div>
</div>
<div>
<h4 className="font-display text-xl text-text-main dark:text-white">@knuth_ceramics</h4>
<h4 className="font-display text-xl text-text-main dark:text-white group-hover:underline">@knuth_ceramics</h4>
<p className="text-xs text-text-muted">24.8k followers</p>
</div>
</div>
<a className="px-6 py-2 border border-text-main dark:border-white text-xs uppercase tracking-widest text-text-main dark:text-white hover:bg-text-main hover:text-white dark:hover:bg-white dark:hover:text-black transition-all duration-300 rounded-full" href="#">
</a>
<a className="px-6 py-2 border border-text-main dark:border-white text-xs uppercase tracking-widest text-text-main dark:text-white hover:bg-text-main hover:text-white dark:hover:bg-white dark:hover:text-black transition-all duration-300 rounded-full" href="https://www.instagram.com/knuth.ceramics" target="_blank" rel="noopener noreferrer">
Follow
</a>
</motion.div>

View File

@@ -63,9 +63,7 @@ const Header: React.FC = () => {
{/* Icons */}
<div className="flex items-center space-x-6 text-text-main dark:text-white">
<button className="hover:scale-110 transition-transform duration-300 hidden sm:block p-2">
<span className="material-symbols-outlined text-xl font-light">search</span>
</button>
{/*
<button
onClick={() => setCartOpen(true)}
className="hover:scale-110 transition-transform duration-300 relative group p-2"
@@ -78,6 +76,7 @@ const Header: React.FC = () => {
</span>
)}
</button>
*/}
</div>
</div>
</div>

View File

@@ -1,34 +1,38 @@
import React from 'react';
import { Link } from 'react-router-dom';
const Hero: React.FC = () => {
return (
<section className="relative min-h-screen pt-24 w-full flex flex-col md:flex-row items-center overflow-hidden bg-background-light dark:bg-background-dark">
<div className="w-full md:w-5/12 h-full flex flex-col justify-center px-6 md:pl-20 md:pr-12 py-20 z-10">
<span className="font-body text-xs uppercase tracking-[0.3em] text-text-muted mb-8 ml-1 block">
New Collection 2024
<section className="relative min-h-[85vh] pt-24 pb-12 w-full flex flex-col md:flex-row items-center overflow-hidden bg-background-light dark:bg-background-dark">
<div className="w-full md:w-1/2 h-full flex flex-col justify-center px-6 md:pl-20 md:pr-12 py-12 z-10">
<span className="font-body text-xs uppercase tracking-[0.3em] text-text-muted mb-12 ml-1 block">
New Collection 2026
</span>
<h1 className="font-display text-6xl md:text-7xl lg:text-8xl xl:text-9xl text-text-main dark:text-white font-thin leading-[0.9] mb-10">
Earth <br /><span className="italic pl-12 md:pl-20 text-text-muted">of</span> Ocean
<span className="font-body text-[0.7rem] uppercase tracking-[0.2em] border border-stone-300 dark:border-stone-700 px-3 py-1.5 inline-block text-stone-700 dark:text-stone-300 mt-4">
Online Shop Opening Coming Soon
</span>
<h1 className="font-display text-5xl md:text-6xl lg:text-7xl xl:text-8xl text-text-main dark:text-white font-thin leading-[0.9] mb-8">
<span className="whitespace-nowrap">German Craft.</span><br /><span className="italic pl-8 md:pl-16 text-text-muted whitespace-nowrap">Coastal Soul.</span>
</h1>
<p className="font-body text-text-muted dark:text-gray-400 text-sm md:text-base font-light mb-12 max-w-sm leading-loose ml-1">
<p className="font-body text-text-muted dark:text-gray-400 text-sm font-light mb-8 max-w-sm leading-relaxed ml-1">
Handcrafted ceramics from the Texas Coast. Functional art inspired by the raw textures and colors of Corpus Christi. Small batch, slow-made.
</p>
<div className="ml-1">
<a className="inline-block border-b border-text-main dark:border-white pb-1 text-text-main dark:text-white font-body text-xs uppercase tracking-[0.2em] hover:text-text-muted transition-colors duration-300" href="#">
<div className="ml-1 mt-8">
<Link className="inline-block border-b border-text-main dark:border-white pb-1 text-text-main dark:text-white font-body text-xs uppercase tracking-[0.2em] hover:text-text-muted transition-colors duration-300" to="/collections">
View The Collection
</a>
</Link>
</div>
</div>
<div className="w-full md:w-7/12 h-[60vh] md:h-screen relative">
<div className="w-full md:w-1/2 h-[50vh] md:h-[75vh] relative mt-12 md:mt-0">
<div className="absolute inset-0 bg-stone-200 dark:bg-stone-800">
<img
alt="Minimalist ceramic vase with single branch"
className="w-full h-full object-cover object-center brightness-95"
src="/pottery-studio.png"
src="/landingpage/1.png"
/>
</div>
<div className="absolute bottom-10 left-10 md:left-auto md:right-20 bg-background-light/90 dark:bg-background-dark/90 backdrop-blur p-6 max-w-xs hidden md:block shadow-sm">
<p className="font-display italic text-xl text-text-main dark:text-gray-200">
<div className="absolute bottom-16 left-10 md:left-auto md:right-20 bg-background-light/90 dark:bg-background-dark/90 backdrop-blur p-6 max-w-xs hidden md:block shadow-sm">
<p className="font-display italic text-lg text-text-main dark:text-gray-200">
"In emptiness, there is fullness."
</p>
</div>

View File

@@ -5,11 +5,11 @@ import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
const horizontalImages = [
{ src: '/pottery-vase.png', title: 'Handcrafted Vases', description: 'Each vase tells a story of patience and craft' },
{ src: '/pottery-bowls.png', title: 'Artisan Bowls', description: 'Organic forms inspired by nature' },
{ src: '/pottery-plates.png', title: 'Dinner Collection', description: 'Elevate your everyday dining experience' },
{ src: '/pottery-studio.png', title: 'Our Studio', description: 'Where creativity meets tradition' },
{ src: '/ceramic-cups.png', title: 'Ceramic Cups', description: 'Handmade with love and intention' },
{ src: '/product_images/kitchenware.png', title: 'Coffee Cups', description: 'Wheel-thrown cups for your morning ritual — no two alike' },
{ src: '/product_images/lass_das_so_202603231510.png', title: 'Bowls', description: 'Handcrafted stoneware bowls for the table and the kitchen' },
{ src: '/product_images/Produkt_foto_studio_202603231654 (1).png', title: 'Tableware', description: 'Small-batch dinnerware made to be used every day' },
{ src: '/product_images/Produkt_foto_studio_202603231744.png', title: 'Kitchenware', description: 'Functional ceramics built for the rhythms of daily life' },
{ src: '/product_images/Produkt_foto_studio_202603231654 (2).png', title: 'Decoration', description: 'Sculptural pieces inspired by the textures of the Gulf Coast' },
];
const HorizontalScrollSection: React.FC = () => {
@@ -22,15 +22,22 @@ const HorizontalScrollSection: React.FC = () => {
if (!container || !scrollContainer) return;
const scrollWidth = scrollContainer.scrollWidth - window.innerWidth;
const cards = Array.from(scrollContainer.children) as HTMLDivElement[];
const lastCard = cards[cards.length - 1];
if (!lastCard) return;
const lastCardRightEdge = lastCard.offsetLeft + lastCard.offsetWidth;
const mobileEndInset = window.innerWidth < 768 ? 24 : 64;
const maxScroll = Math.max(lastCardRightEdge - window.innerWidth + mobileEndInset, 0);
const tween = gsap.to(scrollContainer, {
x: -scrollWidth,
x: -maxScroll,
ease: 'none',
scrollTrigger: {
trigger: container,
start: 'top top',
end: () => `+=${scrollWidth * 0.5}`,
end: () => `+=${maxScroll * 0.5}`,
scrub: 1,
pin: true,
anticipatePin: 1,
@@ -44,7 +51,7 @@ const HorizontalScrollSection: React.FC = () => {
}, []);
return (
<section ref={containerRef} className="relative overflow-hidden bg-clay-dark">
<section ref={containerRef} className="relative overflow-hidden bg-clay-dark h-screen w-full">
<div
ref={scrollRef}
className="flex h-screen items-center"
@@ -52,21 +59,21 @@ const HorizontalScrollSection: React.FC = () => {
{horizontalImages.map((image, index) => (
<div
key={index}
className="relative flex-shrink-0 w-[90vw] md:w-[75vw] h-screen flex items-center justify-center p-4 md:p-8"
className="relative flex-shrink-0 w-[86vw] md:w-[75vw] h-screen flex items-center justify-center px-4 pr-16 md:p-8"
>
<div className="relative w-full h-full max-w-5xl max-h-[80vh] overflow-hidden rounded-lg shadow-2xl group">
<div className="relative w-full h-full max-w-4xl max-h-[60vh] overflow-hidden rounded-lg shadow-2xl group">
<img
src={image.src}
alt={image.title}
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent" />
<div className="absolute bottom-0 left-0 p-12 text-white">
<h3 className="font-display text-5xl md:text-6xl font-light mb-4">{image.title}</h3>
<p className="font-body text-lg font-light opacity-80 max-w-md">{image.description}</p>
<div className="absolute bottom-0 left-0 p-8 md:p-12 text-white">
<h3 className="font-display text-4xl md:text-5xl font-light mb-4">{image.title}</h3>
<p className="font-body text-base md:text-lg font-light opacity-80 max-w-md">{image.description}</p>
</div>
</div>
<div className="absolute top-1/2 right-8 -translate-y-1/2 text-white/20 font-display text-[15rem] leading-none select-none pointer-events-none">
<div className="absolute top-1/2 right-3 translate-x-[24%] -translate-y-1/2 text-white/20 font-display text-[4.5rem] sm:text-[6rem] md:right-0 md:translate-x-[42%] md:text-[12rem] xl:text-[15rem] leading-none select-none pointer-events-none">
{String(index + 1).padStart(2, '0')}
</div>
</div>

View File

@@ -0,0 +1,176 @@
import React, { useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
declare global {
interface Window {
instgrm?: {
Embeds: {
process: () => void;
};
};
}
}
const posts = [
'https://www.instagram.com/p/DSOFijljukL/',
'https://www.instagram.com/p/DSGh7rMjVes/',
'https://www.instagram.com/p/DRIIUECj4f6/',
'https://www.instagram.com/p/DJOvmvcIoo7/',
'https://www.instagram.com/p/DJOu5b7IL4t/',
'https://www.instagram.com/p/DIQnhO0oJgw/',
'https://www.instagram.com/p/DIJUVqbI4EH/',
'https://www.instagram.com/p/DHlvDNyIDRa/',
'https://www.instagram.com/p/DHlub_iojwv/',
'https://www.instagram.com/p/DJOvdVLIZpM/',
];
const InstagramFeed: React.FC = () => {
const [selectedPost, setSelectedPost] = useState<string | null>(null);
// Double the list for seamless infinite marquee scroll
const duplicatedPosts = [...posts, ...posts];
useEffect(() => {
// Process Instagram embeds whenever the component mounts or the lightbox opens
if (window.instgrm) {
window.instgrm.Embeds.process();
} else {
const script = document.createElement('script');
script.src = '//www.instagram.com/embed.js';
script.async = true;
document.body.appendChild(script);
}
}, [selectedPost]);
return (
<>
<section className="py-24 px-6 md:px-12 bg-stone-50 dark:bg-stone-900 overflow-hidden">
<div className="max-w-[1400px] mx-auto">
<span className="block font-body text-xs uppercase tracking-[0.3em] text-stone-400 mb-6">
Follow Along
</span>
<div className="flex items-end justify-between mb-16 px-2">
<h2 className="font-display text-4xl md:text-5xl text-text-main dark:text-white leading-none">
From the Studio
</h2>
<a
href="https://www.instagram.com/knuth.ceramics"
target="_blank"
rel="noopener noreferrer"
className="text-xs font-bold uppercase tracking-widest text-stone-500 hover:text-stone-900 dark:hover:text-white transition-colors"
>
@knuth.ceramics
</a>
</div>
{/* Infinite Carousel */}
<div className="relative group overflow-hidden">
<style>{`
@keyframes marquee {
0% { transform: translateX(0); }
100% { transform: translateX(-${posts.length * 342}px); /* 326px width + 16px gap */ }
}
.animate-marquee {
animation: marquee 50s linear infinite;
}
.animate-marquee:hover {
animation-play-state: paused;
}
`}</style>
<div className="flex gap-4 animate-marquee w-max py-4">
{duplicatedPosts.map((permalink, idx) => (
<div
key={idx}
className="relative flex-shrink-0 w-[326px] overflow-hidden rounded-[8px] group/item cursor-pointer bg-white"
>
{/* Invisible Overlay to capture clicks.
Because iframes block events, we put a div above it.
On hover it reveals a subtle mask to indicate interactivity. */}
<div
className="absolute inset-0 z-10 bg-black/0 group-hover/item:bg-black/50 transition-colors duration-300 flex flex-col items-center justify-center opacity-0 group-hover/item:opacity-100"
onClick={() => setSelectedPost(permalink)}
>
<p className="text-white font-display text-lg px-4 text-center font-bold drop-shadow-md">
View Post
</p>
</div>
{/* The Instagram Embed itself.
By omitting data-instgrm-captioned we hide the caption/hashtags directly. */}
<div className="pointer-events-none">
<blockquote
className="instagram-media"
data-instgrm-permalink={`${permalink}?utm_source=ig_embed&utm_campaign=loading`}
data-instgrm-version="14"
style={{
background: '#FFF',
border: 0,
margin: 0,
maxWidth: '540px',
minWidth: '326px',
padding: 0,
width: '100%',
}}
/>
</div>
</div>
))}
</div>
</div>
</div>
</section>
{/* Lightbox Modal */}
<AnimatePresence>
{selectedPost && (
<motion.div
className="fixed inset-0 bg-black/90 z-50 flex items-center justify-center p-4 overflow-y-auto pt-[100px]"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setSelectedPost(null)}
>
<motion.div
className="relative max-w-lg w-full bg-white dark:bg-stone-900 rounded-xl overflow-hidden my-auto"
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.9, opacity: 0 }}
transition={{ type: 'spring', damping: 25, stiffness: 300 }}
onClick={(e) => e.stopPropagation()}
>
{/* Close button inside modal container */}
<button
className="absolute top-2 right-2 text-stone-500 bg-white border border-stone-200 shadow-md rounded-full w-8 h-8 flex items-center justify-center hover:bg-stone-100 transition-colors z-[60]"
onClick={() => setSelectedPost(null)}
>
<span className="font-bold">×</span>
</button>
{/* Instagram Embed WITH caption shown in the Lightbox */}
<div className="w-full bg-white mt-12 pb-4 px-2">
<blockquote
className="instagram-media"
data-instgrm-captioned
data-instgrm-permalink={`${selectedPost}?utm_source=ig_embed&utm_campaign=loading`}
data-instgrm-version="14"
style={{
background: '#FFF',
border: 0,
boxShadow: 'none',
margin: '0',
maxWidth: '540px',
minWidth: '326px',
padding: 0,
width: '100%',
}}
/>
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</>
);
};
export default InstagramFeed;

View File

@@ -3,6 +3,10 @@ import { Link } from 'react-router-dom';
import { JOURNAL_ENTRIES } from '../constants';
const JournalSection: React.FC = () => {
const getArticleHref = (slug: string) => (
slug.startsWith('/editorial/') ? slug : `/editorial/${slug}`
);
return (
<section className="relative py-32 bg-terracotta-soft dark:bg-black overflow-hidden transition-colors duration-500">
<div className="absolute inset-0 z-0 mix-blend-multiply opacity-30">
@@ -19,7 +23,7 @@ const JournalSection: React.FC = () => {
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-12">
{JOURNAL_ENTRIES.map((entry) => (
<Link key={entry.id} to={entry.slug} className={`group cursor-pointer block ${entry.marginTop ? 'lg:mt-20' : ''}`}>
<Link key={entry.id} to={getArticleHref(entry.slug)} className={`group cursor-pointer block ${entry.marginTop ? 'lg:mt-20' : ''}`}>
<article>
<div className="relative h-[500px] overflow-hidden mb-8 shadow-md">
<img

View File

@@ -0,0 +1,84 @@
import React, { useEffect } from 'react';
// TODO: Update SITE_URL to your actual domain before deploying
export const SITE_URL = 'https://knuthceramics.com';
export const SITE_NAME = 'KNUTH Ceramics';
const DEFAULT_OG_IMAGE = `${SITE_URL}/landingpage/artelier.png`;
type Schema = Record<string, unknown>;
interface SEOProps {
title: string;
description: string;
canonical?: string;
schema?: Schema | Schema[];
ogImage?: string;
ogType?: 'website' | 'article' | 'product';
}
function setMeta(selector: string, attr: string, value: string) {
let el = document.querySelector<HTMLMetaElement>(selector);
if (!el) {
el = document.createElement('meta');
const [attrName, attrVal] = selector.replace('meta[', '').replace(']', '').split('="');
el.setAttribute(attrName, attrVal.replace('"', ''));
document.head.appendChild(el);
}
el.setAttribute(attr, value);
}
const SEO: React.FC<SEOProps> = ({
title,
description,
canonical,
schema,
ogImage = DEFAULT_OG_IMAGE,
ogType = 'website',
}) => {
const schemaStr = schema ? JSON.stringify(schema) : null;
useEffect(() => {
const fullTitle = title.includes(SITE_NAME) ? title : `${title} | ${SITE_NAME}`;
document.title = fullTitle;
setMeta('meta[name="description"]', 'content', description);
setMeta('meta[property="og:title"]', 'content', fullTitle);
setMeta('meta[property="og:description"]', 'content', description);
setMeta('meta[property="og:type"]', 'content', ogType);
setMeta('meta[property="og:image"]', 'content', ogImage);
setMeta('meta[property="og:site_name"]', 'content', SITE_NAME);
setMeta('meta[name="twitter:card"]', 'content', 'summary_large_image');
setMeta('meta[name="twitter:title"]', 'content', fullTitle);
setMeta('meta[name="twitter:description"]', 'content', description);
setMeta('meta[name="twitter:image"]', 'content', ogImage);
let canonicalEl = document.querySelector<HTMLLinkElement>('link[rel="canonical"]');
if (!canonicalEl) {
canonicalEl = document.createElement('link');
canonicalEl.setAttribute('rel', 'canonical');
document.head.appendChild(canonicalEl);
}
canonicalEl.setAttribute('href', canonical ?? `${SITE_URL}${window.location.pathname}`);
// Remove previous page-level schemas, inject new ones
document.querySelectorAll('script[data-seo="page"]').forEach(el => el.remove());
if (schemaStr) {
const schemas = Array.isArray(JSON.parse(schemaStr)) ? JSON.parse(schemaStr) : [JSON.parse(schemaStr)];
schemas.forEach((s: Schema) => {
const script = document.createElement('script');
script.setAttribute('type', 'application/ld+json');
script.setAttribute('data-seo', 'page');
script.textContent = JSON.stringify(s);
document.head.appendChild(script);
});
}
return () => {
document.querySelectorAll('script[data-seo="page"]').forEach(el => el.remove());
};
}, [title, description, canonical, ogImage, ogType, schemaStr]);
return null;
};
export default SEO;

View File

@@ -1,78 +1,226 @@
import { NavItem, CollectionItem, JournalEntry, FooterSection } from './types';
export const NAV_ITEMS: NavItem[] = [
{ label: 'Collections', href: '#' },
{ label: 'Atelier', href: '#' },
{ label: 'Editorial', href: '#' },
{ label: 'Collections', href: '/collections' },
{ label: 'Atelier', href: '/atelier' },
{ label: 'Editorial', href: '/editorial' },
];
export const COLLECTIONS: CollectionItem[] = [
// --- Tableware ---
{
id: 1,
title: 'Tableware',
slug: 'tableware-set',
title: 'Coastal Grey Tableware Set',
slug: 'coastal-grey-tableware-set',
number: '01',
image: '/collection-tableware.png',
images: ['/collection-tableware.png', '/pottery-plates.png', '/ceramic-cups.png'],
price: 185,
description: 'A complete hand-thrown tableware set for four. Finished in our signature matte white glaze with raw clay rims.',
aspectRatio: 'aspect-[3/4]',
},
{
id: 2,
title: 'Lighting',
slug: 'ceramic-lighting',
number: '04',
image: '/collection-lighting.png',
images: ['/collection-lighting.png', '/pottery-studio.png', '/collection-vases.png'],
price: 240,
description: 'Sculptural ceramic pendant lights that bring warmth and texture to any space. Each piece is unique.',
image: '/product_images/Lass_aussehen_produkt_202603231513 (1).png',
images: ['/product_images/Lass_aussehen_produkt_202603231513 (1).png'],
price: 140,
description: 'A wheel-thrown set of cups, bowls, and saucers finished in a speckled coastal grey glaze. Handmade in Corpus Christi, TX. Dishwasher safe.',
aspectRatio: 'aspect-[4/3]',
},
{
id: 3,
title: 'Vases',
slug: 'organic-vases',
number: '02',
image: '/collection-vases.png',
images: ['/collection-vases.png', '/pottery-vase.png', '/collection-lighting.png'],
price: 95,
description: 'Organic forms inspired by the dunes of Padre Island. Perfect for dried stems or fresh bouquets.',
id: 13,
title: 'Ceramic Place Setting',
slug: 'ceramic-place-setting',
number: '13',
image: '/product_images/Produkt_foto_studio_202603231654 (1).png',
images: ['/product_images/Produkt_foto_studio_202603231654 (1).png'],
price: 120,
description: 'A handmade ceramic plate with a small ceramic tree accent piece. A complete place setting for the table, made in small batches in Corpus Christi, TX.',
aspectRatio: 'aspect-square',
},
{
id: 4,
title: 'Serving',
slug: 'serving-bowls',
number: '05',
image: '/pottery-bowls.png',
images: ['/pottery-bowls.png', '/collection-kitchenware.png', '/pottery-plates.png'],
price: 120,
description: 'Large, shallow serving bowls designed for communal gatherings. Durable and dishwasher safe.',
id: 18,
title: 'Textured Floral Plates — Set of Four',
slug: 'textured-floral-plates',
number: '18',
image: '/product_images/Produkt_foto_studio_202603231654 (6).png',
images: ['/product_images/Produkt_foto_studio_202603231654 (6).png'],
price: 210,
description: 'A set of four round stoneware plates with a hand-pressed floral texture. Each plate varies slightly in glaze — soft white and sage tones inspired by the Gulf Coast.',
aspectRatio: 'aspect-[3/4]',
},
// --- Coffee Cups ---
{
id: 4,
title: 'Set of Three Stoneware Cups',
slug: 'set-of-three-stoneware-cups',
number: '04',
image: '/product_images/lass_das_so_202603231510 (3).png',
images: ['/product_images/lass_das_so_202603231510 (3).png'],
price: 120,
description: 'Three wheel-thrown stoneware cups with a layered grey-green interior glaze and dark clay body. No two are alike. Ideal for coffee, tea, or espresso.',
aspectRatio: 'aspect-[4/5]',
},
{
id: 5,
title: 'Kitchenware',
slug: 'kitchen-essentials',
number: '03',
image: '/collection-kitchenware.png',
images: ['/collection-kitchenware.png', '/ceramic-cups.png', '/pottery-bowls.png'],
title: 'Dog Mam Cup — Teal',
slug: 'dog-mam-cup-teal',
number: '05',
image: '/product_images/lass_das_so_202603231511.png',
images: ['/product_images/lass_das_so_202603231511.png'],
price: 65,
description: 'Everyday essentials including berry bowls, spoon rests, and utensil holders. Functional beauty.',
aspectRatio: 'aspect-[3/5]',
description: 'A handmade ceramic cup stamped with "Dog Mam" in the clay. Finished in a flowing orange and teal coastal glaze. A one-of-a-kind gift for dog lovers.',
aspectRatio: 'aspect-square',
},
{
id: 6,
title: 'Textiles',
slug: 'linen-textiles',
title: 'Dog Mam Cup — Blush',
slug: 'dog-mam-cup-blush',
number: '06',
image: '/pottery-plates.png',
images: ['/pottery-plates.png', '/collection-tableware.png', '/collection-vases.png'],
image: '/product_images/lass_das_so_202603231511 (1).png',
images: ['/product_images/lass_das_so_202603231511 (1).png'],
price: 45,
description: 'Natural linen napkins and runners that perfectly complement our stoneware ceramics.',
description: 'A handmade ceramic cup stamped with "Dog Mam" in the clay. Finished in a warm blush and amber glaze. A one-of-a-kind gift for dog lovers.',
aspectRatio: 'aspect-[3/4]',
},
{
id: 8,
title: 'Dark Stoneware Cups — Amber Drip',
slug: 'dark-stoneware-cups-amber-drip',
number: '08',
image: '/product_images/lass_das_so_202603231511 (3).png',
images: ['/product_images/lass_das_so_202603231511 (3).png'],
price: 110,
description: 'Five handmade stoneware cups with a dark clay body and flowing amber drip glaze. Small-batch, wheel-thrown in Corpus Christi. Each piece is unique.',
aspectRatio: 'aspect-square',
},
// --- Bowls ---
{
id: 3,
title: 'Dark Stoneware Bowl',
slug: 'dark-stoneware-bowl',
number: '03',
image: '/product_images/lass_das_so_202603231510 (2).png',
images: ['/product_images/lass_das_so_202603231510 (2).png'],
price: 95,
description: 'A single wheel-thrown stoneware bowl with a dark exterior and rich amber interior glaze. Made in Corpus Christi, TX. Dishwasher safe.',
aspectRatio: 'aspect-[3/4]',
},
{
id: 7,
title: 'Pastel Bowl Collection',
slug: 'pastel-bowl-collection',
number: '07',
image: '/product_images/lass_das_so_202603231511 (2).png',
images: ['/product_images/lass_das_so_202603231511 (2).png'],
price: 150,
description: 'A collection of handmade stoneware bowls and cups in soft coastal pastels — blush pink, sky blue, buttercup yellow, and white. Each piece is unique.',
aspectRatio: 'aspect-[4/3]',
},
{
id: 10,
title: 'Coastal Sunset Bowl Set',
slug: 'coastal-sunset-bowl-set',
number: '10',
image: '/product_images/lass_das_so_202603231510.png',
images: ['/product_images/lass_das_so_202603231510.png'],
price: 185,
description: 'Stacked stoneware bowls glazed in warm coastal tones — amber, orange, pink, and teal — inspired by the Gulf Coast sunsets of Corpus Christi.',
aspectRatio: 'aspect-[3/4]',
},
{
id: 11,
title: 'Handmade Blush Bowl',
slug: 'handmade-blush-bowl',
number: '11',
image: '/product_images/lass_das_so_202603231510 (1).png',
images: ['/product_images/lass_das_so_202603231510 (1).png'],
price: 240,
description: 'A single handmade stoneware bowl with a luminous blush and rose interior glaze. Wheel-thrown and one-of-a-kind. Made in Corpus Christi, TX.',
aspectRatio: 'aspect-[4/3]',
},
// --- Kitchenware ---
{
id: 12,
title: 'Dark Stoneware Vessel',
slug: 'dark-stoneware-vessel',
number: '12',
image: '/product_images/Produkt_foto_studio_202603231654.png',
images: ['/product_images/Produkt_foto_studio_202603231654.png'],
price: 150,
description: 'A squat wheel-thrown stoneware vessel with a textured dark clay body and amber drip glaze. Functional and sculptural — use as a utensil holder or vase.',
aspectRatio: 'aspect-[3/4]',
},
{
id: 16,
title: 'Studio Collection — Mixed Pieces',
slug: 'studio-collection-mixed-pieces',
number: '16',
image: '/product_images/Produkt_foto_studio_202603231654 (4).png',
images: ['/product_images/Produkt_foto_studio_202603231654 (4).png'],
price: 145,
description: 'A curated grouping from the studio — includes small bowls, trinket dishes, a flower frog, and miniature ceramic houses. Each piece handmade in Corpus Christi.',
aspectRatio: 'aspect-square',
},
// --- Decoration ---
{
id: 2,
title: 'Handmade Ceramic Rose',
slug: 'handmade-ceramic-rose',
number: '02',
image: '/product_images/Lass_aussehen_produkt_202603231513 (2).png',
images: ['/product_images/Lass_aussehen_produkt_202603231513 (2).png'],
price: 160,
description: 'A hand-sculpted ceramic rose in unglazed white stoneware. A one-of-a-kind decorative piece — no two petals are the same. Made in Corpus Christi, TX.',
aspectRatio: 'aspect-square',
},
{
id: 9,
title: 'Hope Bowl with Clay Tokens',
slug: 'hope-bowl-with-clay-tokens',
number: '09',
image: '/product_images/Lass_aussehen_produkt_202603231513.png',
images: ['/product_images/Lass_aussehen_produkt_202603231513.png'],
price: 130,
description: 'A decorative stoneware bowl filled with handmade clay word tokens — small houses and tags stamped with "Hope". An intentional piece for your home.',
aspectRatio: 'aspect-[3/4]',
},
{
id: 14,
title: 'Ceramic House Lanterns — Set of Four',
slug: 'ceramic-house-lanterns',
number: '14',
image: '/product_images/Produkt_foto_studio_202603231654 (2).png',
images: ['/product_images/Produkt_foto_studio_202603231654 (2).png'],
price: 95,
description: 'Four handmade ceramic house lanterns with cut-out windows that glow when lit from inside. Each house has a unique facade — hearts, stars, and arched details.',
aspectRatio: 'aspect-[4/3]',
},
{
id: 15,
title: 'Flower Frog Vase — Gulf Blue',
slug: 'flower-frog-vase-gulf-blue',
number: '15',
image: '/product_images/Produkt_foto_studio_202603231654 (3).png',
images: ['/product_images/Produkt_foto_studio_202603231654 (3).png'],
price: 180,
description: 'A dome-shaped ceramic flower frog glazed in soft Gulf blue. Holds dried or fresh flowers through pin holes on top. Handmade in Corpus Christi, TX.',
aspectRatio: 'aspect-[3/4]',
},
{
id: 17,
title: 'Miniature Ceramic Village',
slug: 'miniature-ceramic-village',
number: '17',
image: '/product_images/Produkt_foto_studio_202603231654 (5).png',
images: ['/product_images/Produkt_foto_studio_202603231654 (5).png'],
price: 165,
description: 'Small ceramic house sculptures arranged on round clay discs — each village is unique. A handmade decorative piece with hand-carved door and window details.',
aspectRatio: 'aspect-[4/5]',
},
{
id: 19,
title: 'Stoneware Kitchen Vessel',
slug: 'stoneware-kitchen-vessel',
number: '19',
image: '/product_images/Produkt_foto_studio_202603231744.png',
images: ['/product_images/Produkt_foto_studio_202603231744.png'],
price: 135,
description: 'A versatile wheel-thrown stoneware vessel designed for kitchen utility. Minimalist form with a responsive glaze.',
aspectRatio: 'aspect-[3/4]',
},
];
export const JOURNAL_ENTRIES: JournalEntry[] = [
@@ -89,9 +237,9 @@ export const JOURNAL_ENTRIES: JournalEntry[] = [
id: 2,
category: 'Guide',
date: 'Jul 15',
title: 'The Art of Packaging',
slug: '/editorial/the-art-of-packaging',
description: "A practical guide for potters who want to package and send their handmade ceramics with care and confidence.",
title: 'How to Care for Handmade Ceramics',
slug: '/editorial/how-to-care-for-handmade-ceramics',
description: 'How to care for handmade ceramics: a practical daily care guide for mugs, bowls, and plates, including dishwasher, microwave, crazing, and cleaning tips.',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuAaWGnX_NYT3S_lOflL2NJZGbWge4AAkvra4ymvF8ag-c1UKsOAIB-rsLVQXW5xIlPZipDiK8-ysPyv22xdgsvzs4EOXSSCcrT4Lb2YCe0u5orxRaZEA5TgxeoKq15zaWKSlmnHyPGjPd_7yglpfO13eZmbU5KaxFJ1KGO0UAxoO9BpsyCYgbgINMoSz3epGe5ZdwBWRH-5KCzjoLuXimFTLcd5bqg9T1YofTxgy2hWBMJzKkafyEniq8dP6hMmfNCLVcCHHHx0hRU',
marginTop: true,
},
@@ -107,22 +255,21 @@ export const JOURNAL_ENTRIES: JournalEntry[] = [
];
export const GALLERY_IMAGES = [
{ src: '/ceramic-cups.png', likes: 2847, comments: 124, caption: 'Morning rituals ☕' },
{ src: '/pottery-vase.png', likes: 3521, comments: 89, caption: 'Crafted with intention 🏺' },
{ src: '/pottery-bowls.png', likes: 1956, comments: 67, caption: 'Wabi-sabi collection' },
{ src: '/pottery-plates.png', likes: 4102, comments: 156, caption: 'Ready for your table ✨' },
{ src: '/pottery-studio.png', likes: 5234, comments: 203, caption: 'Where the magic happens' },
{ src: '/collection-tableware.png', likes: 2678, comments: 94, caption: 'Stacked with love' },
{ src: '/collection-vases.png', likes: 3189, comments: 112, caption: 'Organic forms' },
{ src: '/collection-kitchenware.png', likes: 1847, comments: 78, caption: 'Matcha time 🍵' },
{ src: '/product_images/kitchenware.png', likes: 2847, comments: 124, caption: 'Morning rituals ☕' },
{ src: '/product_images/vases.png', likes: 3521, comments: 89, caption: 'Crafted with intention 🏺' },
{ src: '/product_images/serving.png', likes: 1956, comments: 67, caption: 'Wabi-sabi collection' },
{ src: '/product_images/textiles.png', likes: 4102, comments: 156, caption: 'Ready for your table ✨' },
{ src: '/landingpage/artelier.png', likes: 5234, comments: 203, caption: 'Where the magic happens' },
{ src: '/product_images/tableware.png', likes: 2678, comments: 94, caption: 'Stacked with love' },
{ src: '/product_images/vases.png', likes: 3189, comments: 112, caption: 'Organic forms' },
{ src: '/product_images/kitchenware.png', likes: 1847, comments: 78, caption: 'Matcha time 🍵' },
];
export const FOOTER_LINKS: FooterSection[] = [
{
title: 'Shop',
links: [
{ label: 'All Ceramics', href: '#' },
{ label: 'New Arrivals', href: '#' },
{ label: 'All Ceramics', href: '/collections' },
{ label: 'Best Sellers', href: '#' },
{ label: 'Gift Cards', href: '#' },
],
@@ -130,7 +277,7 @@ export const FOOTER_LINKS: FooterSection[] = [
{
title: 'Company',
links: [
{ label: 'Our Story', href: '#' },
{ label: 'Our Story', href: '/atelier' },
{ label: 'Sustainability', href: '#' },
{ label: 'Careers', href: '#' },
{ label: 'Press', href: '#' },

View File

@@ -3,7 +3,101 @@
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>KNUTH Ceramics - Editorial Collection</title>
<title>KNUTH Ceramics — Handcrafted Pottery from Corpus Christi, Texas</title>
<meta name="description" content="KNUTH Ceramics crafts small-batch stoneware pottery in Corpus Christi, Texas. Shop handmade vases, bowls, tableware, and dinnerware inspired by the Gulf Coast. Custom commissions welcome."/>
<meta name="robots" content="index, follow"/>
<link rel="canonical" href="https://knuthceramics.com/"/>
<!-- Open Graph -->
<meta property="og:title" content="KNUTH Ceramics — Handcrafted Pottery from Corpus Christi, Texas"/>
<meta property="og:description" content="Small-batch stoneware pottery made in Corpus Christi, TX. Handcrafted vases, bowls, and tableware inspired by the Texas Gulf Coast. Custom dinnerware commissions accepted."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://knuthceramics.com/"/>
<meta property="og:image" content="https://knuthceramics.com/landingpage/artelier.png"/>
<meta property="og:site_name" content="KNUTH Ceramics"/>
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:title" content="KNUTH Ceramics — Handcrafted Pottery from Corpus Christi, Texas"/>
<meta name="twitter:description" content="Small-batch stoneware pottery made in Corpus Christi, TX. Handcrafted vases, bowls, and tableware inspired by the Texas Gulf Coast."/>
<meta name="twitter:image" content="https://knuthceramics.com/landingpage/artelier.png"/>
<!-- Static JSON-LD: Organization + LocalBusiness (visible to crawlers that don't execute JS) -->
<script type="application/ld+json" data-seo="site">
{
"@context": "https://schema.org",
"@type": ["LocalBusiness", "ArtGallery"],
"name": "KNUTH Ceramics",
"alternateName": "Knuth Ceramics",
"description": "Handcrafted ceramics by Claudia Knuth. Small-batch stoneware pottery inspired by the raw textures and colors of the Texas Gulf Coast in Corpus Christi, TX. German craft tradition meets coastal soul.",
"url": "https://knuthceramics.com",
"logo": "https://knuthceramics.com/landingpage/artelier.png",
"image": "https://knuthceramics.com/landingpage/artelier.png",
"email": "knuth.claudia@gmail.com",
"telephone": "",
"address": {
"@type": "PostalAddress",
"addressLocality": "Corpus Christi",
"addressRegion": "TX",
"addressCountry": "US"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": "27.8006",
"longitude": "-97.3964"
},
"sameAs": [
"https://www.instagram.com/knuth.ceramics"
],
"founder": {
"@type": "Person",
"name": "Claudia Knuth",
"email": "knuth.claudia@gmail.com",
"jobTitle": "Ceramic Artist & Potter"
},
"priceRange": "$$",
"currenciesAccepted": "USD",
"paymentAccepted": "Credit Card",
"areaServed": [
{
"@type": "State",
"name": "Texas"
},
{
"@type": "Country",
"name": "United States"
}
],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Handcrafted Ceramics",
"itemListElement": [
{"@type": "Offer", "itemOffered": {"@type": "Product", "name": "Handmade Ceramic Vases"}},
{"@type": "Offer", "itemOffered": {"@type": "Product", "name": "Handmade Ceramic Bowls"}},
{"@type": "Offer", "itemOffered": {"@type": "Product", "name": "Handmade Tableware & Dinnerware"}},
{"@type": "Offer", "itemOffered": {"@type": "Product", "name": "Custom Ceramic Commissions"}}
]
},
"knowsAbout": [
"Wheel-thrown pottery",
"Stoneware ceramics",
"Handmade tableware",
"Coastal-inspired ceramics",
"Custom dinnerware"
]
}
</script>
<!-- WebSite schema for sitelinks search -->
<script type="application/ld+json" data-seo="site">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "KNUTH Ceramics",
"url": "https://knuthceramics.com",
"description": "Handcrafted ceramics from Corpus Christi, Texas"
}
</script>
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;1,300;1,400&amp;family=Manrope:wght@200;300;400;500&amp;display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&amp;display=swap" rel="stylesheet"/>

View File

@@ -7,9 +7,18 @@ if (!rootElement) {
throw new Error("Could not find root element to mount to");
}
const root = ReactDOM.createRoot(rootElement);
root.render(
// Use hydrateRoot when react-snap has pre-rendered HTML, createRoot for normal dev/fallback
if (rootElement.hasChildNodes()) {
ReactDOM.hydrateRoot(
rootElement,
<React.StrictMode>
<App />
</React.StrictMode>
);
);
} else {
ReactDOM.createRoot(rootElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,8 +6,26 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"postbuild": "react-snap",
"preview": "vite preview"
},
"reactSnap": {
"source": "dist",
"include": [
"/",
"/collections",
"/atelier",
"/faq",
"/editorial",
"/contact",
"/shipping",
"/returns"
],
"headless": true,
"waitFor": 800,
"puppeteerArgs": ["--no-sandbox", "--disable-setuid-sandbox"],
"inlineCss": false
},
"dependencies": {
"framer-motion": "^12.26.0",
"gsap": "^3.14.2",
@@ -18,6 +36,7 @@
"devDependencies": {
"@types/node": "^22.14.0",
"@vitejs/plugin-react": "^5.0.0",
"react-snap": "^1.23.0",
"typescript": "~5.8.2",
"vite": "^6.2.0"
}

View File

@@ -1,8 +1,39 @@
import React from 'react';
import { motion } from 'framer-motion';
import InstagramFeed from '../components/InstagramFeed';
import SEO, { SITE_URL } from '../components/SEO';
const atelierSchema = {
"@context": "https://schema.org",
"@type": "AboutPage",
"name": "The Studio | KNUTH Ceramics — Pottery in Corpus Christi, TX",
"description": "Discover the KNUTH Ceramics atelier in Corpus Christi, Texas. Claudia Knuth creates wheel-thrown stoneware inspired by the raw textures and colors of the Texas Gulf Coast.",
"url": `${SITE_URL}/atelier`,
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": `${SITE_URL}/` },
{ "@type": "ListItem", "position": 2, "name": "Atelier", "item": `${SITE_URL}/atelier` }
]
},
"about": {
"@type": "Person",
"name": "Claudia Knuth",
"jobTitle": "Ceramic Artist & Potter",
"email": "knuth.claudia@gmail.com",
"knowsAbout": ["Wheel-throwing", "Stoneware pottery", "Coastal ceramics", "Custom dinnerware"]
}
};
const Atelier: React.FC = () => {
return (
<>
<SEO
title="The Studio — Pottery in Corpus Christi, TX | KNUTH Ceramics"
description="The KNUTH Ceramics atelier in Corpus Christi, Texas. Claudia Knuth creates wheel-thrown stoneware inspired by the Gulf Coast — fired to cone 6, designed for daily coastal living."
canonical={`${SITE_URL}/atelier`}
schema={atelierSchema}
/>
<div className="bg-stone-50 dark:bg-stone-900 min-h-screen pt-32 pb-24">
<div className="max-w-[1920px] mx-auto px-6 md:px-12">
{/* Intro */}
@@ -40,7 +71,7 @@ const Atelier: React.FC = () => {
transition={{ delay: 0.2, duration: 1.5, ease: "easeOut" }}
className="h-full w-full"
>
<img src="/pottery-studio.png" alt="Pottery Studio in Corpus Christi" className="w-full h-full object-cover" />
<img src="/landingpage/artelier.png" alt="Pottery Studio in Corpus Christi" className="w-full h-full object-cover" />
</motion.div>
</div>
</div>
@@ -49,7 +80,7 @@ const Atelier: React.FC = () => {
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 border-t border-stone-200 dark:border-stone-800 pt-24">
{[
{ title: "Coastal Clay", text: "We work with stoneware clay bodies that reflect the sandy textures of the Gulf Coast." },
{ title: "Electric Firing", text: "Fired in oxidation to cone 6, creating durable surfaces that mimic the bleached colors of driftwood and shell." },
{ title: "Electric Firing", text: "Fired in an electric kiln, creating durable surfaces that mimic the bleached colors of driftwood and shell." },
{ title: "Functional Art", text: "Designed to be used and loved. Our ceramics are durable, dishwasher safe, and meant for daily coastal living." }
].map((item, idx) => (
<motion.div
@@ -67,6 +98,8 @@ const Atelier: React.FC = () => {
</div>
</div>
</div>
<InstagramFeed />
</>
);
};

View File

@@ -1,11 +1,58 @@
import React from 'react';
import { motion } from 'framer-motion';
import { Link } from 'react-router-dom';
import { AnimatePresence, motion } from 'framer-motion';
import { useStore } from '../src/context/StoreContext';
import { CollectionItem } from '../types';
import SEO, { SITE_URL } from '../components/SEO';
const Collections: React.FC = () => {
const { products } = useStore();
const [selectedProduct, setSelectedProduct] = React.useState<CollectionItem | null>(null);
React.useEffect(() => {
if (!selectedProduct) {
return undefined;
}
const handleEscape = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
setSelectedProduct(null);
}
};
window.addEventListener('keydown', handleEscape);
return () => window.removeEventListener('keydown', handleEscape);
}, [selectedProduct]);
const collectionsSchema = {
"@context": "https://schema.org",
"@type": "CollectionPage",
"name": "Handcrafted Ceramic Collection | KNUTH Ceramics",
"description": "Browse KNUTH Ceramics' handcrafted stoneware collection. Each piece is wheel-thrown in Corpus Christi, Texas, inspired by the Gulf Coast. Vases, bowls, tableware, and more from $45.",
"url": `${SITE_URL}/collections`,
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": `${SITE_URL}/` },
{ "@type": "ListItem", "position": 2, "name": "Collections", "item": `${SITE_URL}/collections` }
]
},
"numberOfItems": products.length,
"itemListElement": products.map((p, i) => ({
"@type": "ListItem",
"position": i + 1,
"url": `${SITE_URL}/collections/${p.slug}`,
"name": p.title
}))
};
return (
<>
<SEO
title="Handcrafted Ceramic Collection | KNUTH Ceramics"
description="Browse KNUTH Ceramics' handcrafted stoneware collection. Each piece is wheel-thrown in Corpus Christi, Texas. Vases, bowls, and tableware from $45 — made in the Gulf Coast tradition."
canonical={`${SITE_URL}/collections`}
schema={collectionsSchema}
/>
<section className="pt-32 pb-24 px-6 md:px-12 bg-stone-50 dark:bg-stone-900 min-h-screen">
<div className="max-w-[1920px] mx-auto">
{/* Header */}
@@ -16,7 +63,7 @@ const Collections: React.FC = () => {
transition={{ delay: 0.5, duration: 0.8 }}
className="font-display text-5xl md:text-7xl font-light mb-6 text-text-main dark:text-white"
>
Shop Collection
Collection
</motion.h1>
<motion.p
initial={{ y: 20, opacity: 0 }}
@@ -24,49 +71,72 @@ const Collections: React.FC = () => {
transition={{ delay: 0.7, duration: 0.8 }}
className="font-body text-stone-500 max-w-xl mx-auto text-lg font-light leading-relaxed"
>
Curated series of functional objects. From our 'Sandstone' mugs to 'Seafoam' vases, each collection celebrates the palette of the Texas coast.
A gallery of handmade objects. Select any piece to view it larger, then close when you are done.
</motion.p>
</div>
{/* Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-12 gap-y-16 lg:gap-x-16 px-4">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-x-6 gap-y-10 lg:gap-x-10 px-4">
{products.map((collection, index) => (
<Link to={`/collections/${collection.slug}`} key={collection.id} className="block group cursor-pointer">
<motion.div
<motion.button
key={collection.id}
type="button"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: index * 0.1 }}
onClick={() => setSelectedProduct(collection)}
className="group block cursor-pointer text-left"
>
<div className="relative overflow-hidden mb-6 aspect-[4/5] bg-stone-100">
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/5 transition-colors duration-500 z-10" />
<img
src={collection.image}
alt={collection.title}
className="w-full h-full object-cover transition-transform duration-700 ease-out group-hover:scale-110"
className="w-full h-full object-cover transition-transform duration-700 ease-out group-hover:scale-105"
/>
{/* Quick overlay info */}
<div className="absolute bottom-6 left-6 z-20 opacity-0 group-hover:opacity-100 transition-opacity duration-300">
<span className="bg-white dark:bg-black px-4 py-2 text-xs uppercase tracking-widest text-text-main dark:text-white">View Item</span>
</div>
</div>
<div className="flex justify-between items-baseline pr-2">
<div>
<h2 className="font-display text-3xl font-light text-text-main dark:text-white mb-1 group-hover:underline decoration-1 underline-offset-4">
{collection.title}
</h2>
</div>
<span className="text-lg font-light text-text-main dark:text-white">
${collection.price}
</span>
</div>
</motion.div>
</Link>
</motion.button>
))}
</div>
</div>
</section>
<AnimatePresence>
{selectedProduct && (
<motion.div
className="fixed inset-0 z-[70] bg-black/80 backdrop-blur-sm flex items-center justify-center p-4 sm:p-8"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setSelectedProduct(null)}
>
<motion.div
className="relative flex w-full max-w-6xl items-center justify-center"
initial={{ scale: 0.96, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.96, opacity: 0 }}
transition={{ duration: 0.2 }}
onClick={(event) => event.stopPropagation()}
>
<img
src={selectedProduct.image}
alt={selectedProduct.title}
className="max-h-[92vh] max-w-full object-contain"
/>
<button
type="button"
onClick={() => setSelectedProduct(null)}
className="absolute right-3 top-3 text-4xl font-normal leading-none text-red-500 transition-colors hover:text-red-400"
aria-label="Close image preview"
>
x
</button>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</>
);
};

View File

@@ -28,20 +28,14 @@ const Contact: React.FC = () => {
{
icon: "📧",
title: "Email",
detail: "support@knuthceramics.com",
description: "Best for order inquiries or detailed questions"
},
{
icon: "📞",
title: "Phone",
detail: "(361) 555-1234",
description: "MonFri, 9am5pm CST"
detail: "knuth.claudia@gmail.com",
description: "For commissions, inquiries, and custom orders. We reply within 12 business days."
},
{
icon: "📍",
title: "Workshop",
detail: "123 Artisan Lane, Corpus Christi, TX 78401",
description: "Please note: this is our workshop, not a retail store"
title: "Location",
detail: "Corpus Christi, Texas",
description: "Our studio is based on the Gulf Coast of South Texas."
}
];
@@ -193,7 +187,7 @@ const Contact: React.FC = () => {
</p>
<div className="flex justify-center gap-6">
<a
href="https://instagram.com/knuthceramics"
href="https://instagram.com/knuth.ceramics"
target="_blank"
rel="noopener noreferrer"
className="px-8 py-3 bg-white dark:bg-stone-900 text-black dark:text-white border border-stone-300 dark:border-stone-700 text-xs font-bold uppercase tracking-widest hover:bg-stone-100 dark:hover:bg-stone-800 transition-colors"

View File

@@ -5,6 +5,9 @@ import { useStore } from '../src/context/StoreContext';
const Editorial: React.FC = () => {
const { articles, isLoading } = useStore();
const getArticleHref = (slug: string) => (
slug.startsWith('/editorial/') ? slug : `/editorial/${slug}`
);
if (isLoading) return <div className="min-h-screen flex items-center justify-center pt-24 font-light text-stone-400">Loading Journal...</div>;
if (!articles || articles.length === 0) {
@@ -25,7 +28,7 @@ const Editorial: React.FC = () => {
{/* Featured Post */}
<section className="px-6 mb-32">
<div className="max-w-[1400px] mx-auto">
<Link to={`/editorial/${featuredArticle.slug}`} className="group block">
<Link to={getArticleHref(featuredArticle.slug)} className="group block">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
<div className="lg:col-span-8 overflow-hidden rounded-sm aspect-[16/9]">
<motion.img
@@ -66,7 +69,7 @@ const Editorial: React.FC = () => {
<div className="max-w-[1400px] mx-auto">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-8 gap-y-16">
{otherArticles.map((entry, idx) => (
<Link key={entry.id} to={`/editorial/${entry.slug}`} className="group block">
<Link key={entry.id} to={getArticleHref(entry.slug)} className="group block">
<motion.div
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}

View File

@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { motion, AnimatePresence } from 'framer-motion';
import SEO, { SITE_URL } from '../components/SEO';
interface FAQItem {
question: string;
@@ -14,30 +15,48 @@ const faqData: FAQItem[] = [
},
{
question: "How unique is each piece?",
answer: "Every piece in our shop is designed and handcrafted in small batches. That means no two pieces are exactly alike. You will see slight variations and unique markings that make each item one-of-a-kind. We do our best to photograph products accurately, but please allow for some artisanal differences. These natural imperfections are a sign of true craftsmanship."
answer: "Every piece we create is handcrafted in small batches at our Corpus Christi studio. No two pieces are exactly alike — you will see slight variations and unique markings that make each item one-of-a-kind. These natural imperfections are a sign of true craftsmanship and the human hand behind every piece."
},
{
question: "How long will it take to receive my order?",
answer: "Once you place an order, please allow 13 business days for us to carefully prepare and package your item (handmade pottery takes a bit of extra time). After that, standard shipping via USPS usually takes 35 business days within the U.S. You'll receive a tracking number by email as soon as your order ships."
question: "Is the online shop currently open?",
answer: "Our online shop is temporarily closed while we focus on new collections and studio work. You can still reach us directly for custom commissions or inquiries. Sign up for our newsletter or follow us on Instagram to be the first to know when the shop reopens."
},
{
question: "Do you ship outside the USA?",
answer: "Currently we ship nationwide within the U.S. only. We do not offer international shipping at this time. Orders ship from Corpus Christi, Texas. We focus on providing fast, reliable delivery to Texas and all U.S. customers."
question: "Do you take custom orders or commissions?",
answer: "Yes — we accept a limited number of custom commissions each year. Claudia's work is rooted in the Art Center of Corpus Christi community. Whether you are looking for a bespoke dinnerware set or a one-of-a-kind gift, reach out directly at knuth.claudia@gmail.com to discuss your vision, timeline, and pricing."
},
{
question: "What if my order arrives damaged?",
answer: "We take great care in packaging each piece using recyclable and padded materials. Still, accidents happen. If any item arrives broken or damaged, please contact us immediately. Take a photo of the damage (and packaging, if possible), and email us within 7 days of receipt. All orders are fully insured during transit. Once we review the details, we'll be happy to repair, replace, or refund damaged items at no additional cost to you."
},
{
question: "What is your return/exchange policy?",
answer: "We want you to love your purchase. Because each piece is handmade and unique, all sales are final except in cases of damage or defect. If something isn't right with your order, please let us know. We handle returns or exchanges for defective items (typically within 14 days of delivery). You'll just need to return the piece unused, in its original condition and packaging. (Sorry, we cannot accept returns on change-of-mind or carelessly broken items.) See our Returns page for full details."
question: "Do you offer pottery classes or workshops?",
answer: "Pottery classes and wheel-throwing workshops are available through the Art Center of Corpus Christi. Visit the Art Center for current class schedules and registration."
},
{
question: "How do I contact you with questions?",
answer: "We're here to help! Feel free to reach out anytime. You can email our customer support at support@knuthceramics.com or use the contact form on our site. We aim to respond within 12 business days. Thank you for choosing KNUTH Ceramics we love answering your questions and hearing your feedback!"
answer: "We are here to help! You can reach us directly at knuth.claudia@gmail.com or use the contact form on our site. We aim to respond within 12 business days. Thank you for your interest in KNUTH Ceramics we love hearing from you."
}
];
const faqSchema = {
"@context": "https://schema.org",
"@type": "FAQPage",
"name": "FAQ | KNUTH Ceramics — Handcrafted Pottery Corpus Christi",
"url": `${SITE_URL}/faq`,
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": `${SITE_URL}/` },
{ "@type": "ListItem", "position": 2, "name": "FAQ", "item": `${SITE_URL}/faq` }
]
},
"mainEntity": faqData.map(item => ({
"@type": "Question",
"name": item.question,
"acceptedAnswer": {
"@type": "Answer",
"text": item.answer
}
}))
};
const FAQ: React.FC = () => {
const [openIndex, setOpenIndex] = useState<number | null>(null);
@@ -47,6 +66,12 @@ const FAQ: React.FC = () => {
return (
<div className="bg-stone-50 dark:bg-stone-900 min-h-screen pt-32 pb-24">
<SEO
title="FAQ — Handcrafted Ceramics & Pottery Classes | KNUTH Ceramics"
description="Answers to common questions about KNUTH Ceramics: food safety, custom commissions, pottery classes in Corpus Christi TX, clay bodies, glazes, and how to order."
canonical={`${SITE_URL}/faq`}
schema={faqSchema}
/>
<div className="max-w-[1200px] mx-auto px-6 md:px-12">
{/* Header */}
<div className="mb-24">

View File

@@ -5,18 +5,93 @@ import HorizontalScrollSection from '../components/HorizontalScrollSection';
import Collections from '../components/Collections';
import QuoteSection from '../components/QuoteSection';
import JournalSection from '../components/JournalSection';
import GallerySection from '../components/GallerySection';
import InstagramFeed from '../components/InstagramFeed';
import FAQ from '../components/FAQ';
import SEO, { SITE_URL } from '../components/SEO';
const homeSchema = {
"@context": "https://schema.org",
"@type": "WebPage",
"name": "KNUTH Ceramics — Handcrafted Pottery from Corpus Christi, Texas",
"description": "KNUTH Ceramics crafts small-batch stoneware pottery in Corpus Christi, Texas. Shop handmade vases, bowls, tableware, and dinnerware inspired by the Gulf Coast. Custom commissions welcome.",
"url": `${SITE_URL}/`,
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": `${SITE_URL}/` }
]
}
};
const faqSchema = {
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Is the online shop currently open?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Our online shop is temporarily closed while we focus on new collections and studio work. Follow us on Instagram @knuth.ceramics or email knuth.claudia@gmail.com for commissions and updates."
}
},
{
"@type": "Question",
"name": "Are your ceramics dishwasher and microwave safe?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes. Our functional stoneware — including mugs, plates, and bowls — is fired to cone 6 oxidation, making it durable for daily use. Hand washing is recommended to extend the life of your piece."
}
},
{
"@type": "Question",
"name": "Where is KNUTH Ceramics located?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Our studio is rooted in Corpus Christi, Texas, inspired by the colors and textures of the Gulf Coast."
}
},
{
"@type": "Question",
"name": "Do you offer pottery classes in Corpus Christi?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Pottery classes and wheel-throwing workshops are available through the Art Center of Corpus Christi. Visit the Art Center for current schedules and registration."
}
},
{
"@type": "Question",
"name": "Do you accept custom ceramic commissions?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes. We accept a limited number of custom dinnerware commissions each year. Contact Claudia at knuth.claudia@gmail.com to discuss your vision, timeline, and pricing."
}
},
{
"@type": "Question",
"name": "What clay and glazes does KNUTH Ceramics use?",
"acceptedAnswer": {
"@type": "Answer",
"text": "We use a stoneware clay body that reflects the sandy textures of the Texas Gulf Coast. Our glazes are formulated in-house to capture the colors of the sea and sand along the Corpus Christi shoreline."
}
}
]
};
const Home: React.FC = () => {
return (
<main>
<SEO
title="Handcrafted Pottery from Corpus Christi, Texas | KNUTH Ceramics"
description="KNUTH Ceramics creates small-batch stoneware pottery in Corpus Christi, TX. Shop handmade vases, bowls, and tableware inspired by the Texas Gulf Coast. Custom commissions welcome."
canonical={`${SITE_URL}/`}
schema={[homeSchema, faqSchema]}
/>
<Hero />
<FeatureSection />
<HorizontalScrollSection />
<Collections />
<GallerySection />
<InstagramFeed />
<JournalSection />
<QuoteSection />
<FAQ />

View File

@@ -1,95 +1,142 @@
import React from 'react';
import { Link } from 'react-router-dom';
import BlogPostLayout from '../../components/BlogPostLayout';
import SEO, { SITE_URL } from '../../components/SEO';
const HERO_IMAGE = 'https://lh3.googleusercontent.com/aida-public/AB6AXuB8NOE5fGfN4d87cbcB27_Sh-nrlZlqxsTlYKbCZk98SoL-gHsPSWFNuxd1DxBq0g8Qysh0RBZ_btu-_WaH68UjV8SXPUalyxREvUqao4oXmra--pWAsaooWwKvWCzReYZ8kj7G-KIYIAo5mqudzB8n9C6-HVTNPPx9QgZHr_YsojMxlmmVcQ5bqk7-Lp0KtSAiVIPD2-1UE1dMGnkVSLUXKdgA65JIh8M3TtNkaJTGONuFKoTERrYOWe7u2BILnqyukTzlNcvK7Sc';
const SOURCES = [
{
label: 'IKKAI Ceramics - Pottery Motivation: 10 Tips for When You Are Feeling Stuck',
href: 'https://ikkaiceramics.nl/blogs/welcome-to-my-journal/10-gentle-tips-for-pottery-motivation-when-youre-feeling-stuck',
},
{
label: 'Ceramic Arts Network - Ceramics Monthly',
href: 'https://ceramicartsnetwork.org/ceramics-monthly/',
},
];
const articleSchema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: 'Finding Motivation in Clay',
description: 'Finding motivation in clay during slow seasons and creative blocks. Ten gentle, practical ideas for potters who need a steadier way back into the studio.',
author: { '@type': 'Person', name: 'Claudia Knuth' },
publisher: { '@type': 'Organization', name: 'KNUTH Ceramics', url: SITE_URL },
datePublished: '2024-06-11',
url: `${SITE_URL}/editorial/finding-motivation-in-clay`,
image: HERO_IMAGE,
mainEntityOfPage: `${SITE_URL}/editorial/finding-motivation-in-clay`,
keywords: 'finding motivation in clay, pottery motivation, creative block potters, ceramic artist inspiration, potter burnout',
};
const MotivationInClay: React.FC = () => {
React.useEffect(() => {
document.title = "Creative Block for Potters: 10 Tips for Motivation | KNUTH Ceramics";
let meta = document.querySelector('meta[name="description"]');
if (!meta) {
meta = document.createElement('meta');
meta.setAttribute('name', 'description');
document.head.appendChild(meta);
}
meta.setAttribute('content', 'Overcoming Creative Block for Potters is possible. Use these 10 gentle, practical tips to rediscover your motivation and love for clay. Read more now.');
}, []);
return (
<>
<SEO
title="Finding Motivation in Clay"
description="Finding motivation in clay during slow seasons and creative blocks. Ten gentle, practical ideas for potters who need a steadier way back into the studio."
canonical={`${SITE_URL}/editorial/finding-motivation-in-clay`}
schema={articleSchema}
ogType="article"
ogImage={HERO_IMAGE}
/>
<BlogPostLayout
title="Creative Block for Potters: 10 Tips for Motivation"
title="Finding Motivation in Clay"
category="Wellness"
date="Jun 11"
image="https://lh3.googleusercontent.com/aida-public/AB6AXuB8NOE5fGfN4d87cbcB27_Sh-nrlZlqxsTlYKbCZk98SoL-gHsPSWFNuxd1DxBq0g8Qysh0RBZ_btu-_WaH68UjV8SXPUalyxREvUqao4oXmra--pWAsaooWwKvWCzReYZ8kj7G-KIYIAo5mqudzB8n9C6-HVTNPPx9QgZHr_YsojMxlmmVcQ5bqk7-Lp0KtSAiVIPD2-1UE1dMGnkVSLUXKdgA65JIh8M3TtNkaJTGONuFKoTERrYOWe7u2BILnqyukTzlNcvK7Sc"
imageAlt="Creative Block for Potters tips"
image={HERO_IMAGE}
imageAlt="Finding motivation in clay - a potter's hands resting beside an unfinished ceramic piece"
>
<p className="lead text-xl text-stone-600 dark:text-stone-300 italic mb-8">
Dealing with <strong>Creative Block for Potters</strong> (and finding new <strong>Pottery Inspiration</strong>) is a common struggle in the studio. Where the physical labor is intense and the failure rate is high, burnout is real. Whether you are facing general exhaustion or a specific artistic wall, know that this season is part of the cycle.
<strong>Finding motivation in clay</strong> is part of the work. Every potter knows the feeling of walking into the studio, seeing the wheel ready, and still thinking: maybe tomorrow.
</p>
<p className="mb-6">
Here is how to overcome <strong>Creative Block for Potters</strong> and find your flow again.
Sometimes the block is exhaustion. Sometimes it is perfectionism. Sometimes it is the quieter anxiety of not knowing what to make next. The tips below are not a cure-all. They are gentler than that. They are ways back in.
</p>
<img
src="https://images.unsplash.com/photo-1459156212016-c812468e2115?q=80&w=2574&auto=format&fit=crop"
alt="Creative Block for Potters guide"
className="w-full my-12 shadow-lg"
src="/product_images/motivation_pottery_mid_v4.png"
alt="Finding motivation in clay - hands working with wet clay at a pottery wheel"
className="w-full my-12 shadow-lg rounded-sm"
/>
<h2 className="mt-16 mb-8 text-3xl">1. Play without Purpose</h2>
<p className="mb-6">
Stop making <Link to="/collections">Collections</Link>. Stop thinking about what will sell. Grab a lump of clay and just <em>pinch</em>. When you remove the pressure, you often solve the <strong>Creative Block for Potters</strong> naturally.
<p className="text-sm text-center text-stone-500 -mt-8 mb-12 italic">
Sometimes the most useful goal is simply getting your hands back into clay.
</p>
<h2 className="mt-16 mb-8 text-3xl">2. Switch Your Technique</h2>
<p className="mb-6">
If you are a wheel thrower, try <strong>hand building</strong>. Changing your physical movements can unlock new neural pathways.
<h2 className="mt-16 mb-4 text-3xl">1. Make something just because</h2>
<p className="mb-8">
Stop trying to make the saleable version of yourself for an hour. Make a crooked cup. Make something too small. Make something experimental. The pressure to be good can freeze the hands; curiosity usually unfreezes them.
</p>
<h2 className="mt-16 mb-8 text-3xl">3. The "100 Pattern" Challenge</h2>
<p className="mb-6">
Commit to making 100 small test tiles. Constraints actually breed creativity.
<h2 className="mt-16 mb-4 text-3xl">2. Choose quantity over perfection</h2>
<p className="mb-8">
Potters learn by volume. Ten quick cylinders can teach more than one overworked perfect mug. On difficult days, make the goal output rather than excellence. The body often remembers how to keep going before the mind does.
</p>
<h2 className="mt-16 mb-8 text-3xl">4. Clean Your Studio (Reset)</h2>
<p className="mb-6">
A cluttered space leads to a cluttered mind. Spend a day organizing your <Link to="/atelier">Atelier</Link>. A fresh, clean bat on the wheel is an invitation.
<h2 className="mt-16 mb-4 text-3xl">3. Separate practice from production</h2>
<p className="mb-8">
Not every studio session needs to produce something worth selling. Protect a few sessions as research days. Use them to test forms, glaze ideas, trimming decisions, or scale. Failure feels different when failure is part of the brief.
</p>
<h2 className="mt-16 mb-8 text-3xl">5. Look Outside of Pottery</h2>
<p className="mb-6">
Don't look at other potters on Instagram. That leads to comparison. instead, look at:
<h2 className="mt-16 mb-4 text-3xl">4. Notice your studio self-talk</h2>
<p className="mb-8">
Replace &quot;I am terrible at this&quot; with &quot;this part is still new for me.&quot; Replace &quot;that failed&quot; with &quot;that taught me something.&quot; Motivation rarely grows in a studio ruled by contempt.
</p>
<ul className="mb-12 space-y-4">
<li><strong>Architecture</strong>: for structural shapes.</li>
<li><strong>Nature</strong>: for textures (tree bark, river stones).</li>
<h2 className="mt-16 mb-4 text-3xl">5. Tend to the space before the work</h2>
<p className="mb-8">
Wipe the table. Sweep the floor. Put on music. Bring something in from outside. The studio does not need to be perfect, but it helps when it feels intentional. We pay attention to that on the <Link to="/atelier">atelier page</Link> because atmosphere changes how the body arrives to work.
</p>
<h2 className="mt-16 mb-4 text-3xl">6. Let clay be grounding, not only productive</h2>
<p className="mb-8">
Clay asks for presence. Your hands are wet. Your phone is useless. Your attention has to come back to pressure, speed, breath, and touch. On low-motivation days, that may be enough. The point does not have to be output. The point can be contact.
</p>
<h2 className="mt-16 mb-4 text-3xl">7. Go outward before you force ideas</h2>
<p className="mb-8">
Visit a gallery. Walk near water. Look at bark, shells, stone, weathered wood, old handles, old bowls. Texture and form have to go in before they can come back out through your hands. Along the coast here, those cues are everywhere, and they show up in our <Link to="/collections">glazes and forms</Link> whether we mean them to or not.
</p>
<h2 className="mt-16 mb-4 text-3xl">8. Let community carry some of the weight</h2>
<p className="mb-8">
Pottery can be solitary, but it does not have to be isolating. A class, guild, open studio, or workshop can reset your energy quickly. Being around other people making things changes the room inside your head.
</p>
<h2 className="mt-16 mb-4 text-3xl">9. Protect creative time from business time</h2>
<p className="mb-8">
Pricing, shipping, social media, and orders can quietly consume the same mental space that used to belong to making. Sometimes motivation returns not because you found it, but because you protected it structurally. Put business tasks somewhere else in the week.
</p>
<h2 className="mt-16 mb-4 text-3xl">10. Set one small goal and let it count</h2>
<p className="mb-8">
Pull one taller wall. Trim one foot cleanly. Test one glaze combination. Small goals create traction because they can actually be finished. And when you finish them, name that. Momentum grows faster when it is noticed.
</p>
<h2 className="mt-16 mb-6 text-3xl">A note on the clay itself</h2>
<p className="mb-6">
What runs through all of this is simpler than any technique. Working with clay is one of the most human forms of grounding we have. The hand pressing into soft material and receiving a response is not incidental to the art. It is the art.
</p>
<p className="mb-12">
When motivation feels far away, come back to the smallest version of the practice. Wedge. Pinch. Press your thumb into a ball of clay. Start there.
</p>
<div className="mt-20 pt-12 border-t border-stone-200 dark:border-stone-800">
<h3 className="font-display text-xl mb-6 text-stone-500 dark:text-stone-400 uppercase tracking-widest text-sm">Sources & Further Reading</h3>
<ul className="space-y-2 text-sm text-stone-500 dark:text-stone-400 font-light">
{SOURCES.map((source) => (
<li key={source.href}>
<a href={source.href} target="_blank" rel="noreferrer" className="underline decoration-stone-300 underline-offset-4 hover:text-stone-700 dark:hover:text-stone-200">
{source.label}
</a>
</li>
))}
<li>Bayles &amp; Orland - <em>Art and Fear</em></li>
</ul>
<h2 className="mt-16 mb-8 text-3xl">6. Take a Class</h2>
<p className="mb-6">
Even masters are students. Taking a workshop puts you back in the "beginner's mind," which is a fertile place for ideas.
</p>
<h2 className="mt-16 mb-8 text-3xl">7. Revisit Your "Why"</h2>
<p className="mb-6">
Look at the very first pot you ever kept. Reconnecting with your origin story can fuel your current practice.
</p>
<h2 className="mt-16 mb-8 text-3xl">8. Limit Your Time</h2>
<p className="mb-6">
Tell yourself, "I will only work for 20 minutes." Often, the hardest part is just starting.
</p>
<h2 className="mt-16 mb-8 text-3xl">9. Embrace functionality</h2>
<p className="mb-6">
Make something you <em>need</em>. A spoon rest. A soap dish. Solving a simple, functional problem is a great way to handle <strong>Creative Block for Potters</strong>.
</p>
<h2 className="mt-16 mb-8 text-3xl">10. Rest</h2>
<p className="mb-6">
Sometimes, the block isn't mental; it's physical. Take a week off. The clay will be there when you get back.
</p>
</div>
</BlogPostLayout>
</>
);
};

View File

@@ -1,89 +1,157 @@
import React from 'react';
import { Link } from 'react-router-dom';
import BlogPostLayout from '../../components/BlogPostLayout';
import SEO, { SITE_URL } from '../../components/SEO';
const HERO_IMAGE = 'https://lh3.googleusercontent.com/aida-public/AB6AXuAaWGnX_NYT3S_lOflL2NJZGbWge4AAkvra4ymvF8ag-c1UKsOAIB-rsLVQXW5xIlPZipDiK8-ysPyv22xdgsvzs4EOXSSCcrT4Lb2YCe0u5orxRaZEA5TgxeoKq15zaWKSlmnHyPGjPd_7yglpfO13eZmbU5KaxFJ1KGO0UAxoO9BpsyCYgbgINMoSz3epGe5ZdwBWRH-5KCzjoLuXimFTLcd5bqg9T1YofTxgy2hWBMJzKkafyEniq8dP6hMmfNCLVcCHHHx0hRU';
const SOURCES = [
{
label: 'The Pottery Wheel - Is Pottery Dishwasher Safe? Washing Handmade Ceramics',
href: 'https://thepotterywheel.com/is-pottery-dishwasher-safe/',
},
{
label: 'Mayco Colors - Dinnerware and Food Safety',
href: 'https://www.maycocolors.com/resources/dinnerware-food-safety/',
},
{
label: 'Mayco Colors - Stoneware Bisque',
href: 'https://www.maycocolors.com/forms/stoneware-bisque',
},
{
label: 'FDA - Questions and Answers on Lead-Glazed Traditional Pottery',
href: 'https://www.fda.gov/food/environmental-contaminants-food/questions-and-answers-lead-glazed-traditional-pottery',
},
];
const articleSchema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: 'How to Care for Handmade Ceramics',
description: 'How to care for handmade ceramics: a practical daily care guide for mugs, bowls, and plates, including dishwasher, microwave, crazing, and cleaning tips.',
author: { '@type': 'Person', name: 'Claudia Knuth' },
publisher: { '@type': 'Organization', name: 'KNUTH Ceramics', url: SITE_URL },
datePublished: '2024-07-15',
url: `${SITE_URL}/editorial/how-to-care-for-handmade-ceramics`,
image: HERO_IMAGE,
mainEntityOfPage: `${SITE_URL}/editorial/how-to-care-for-handmade-ceramics`,
keywords: 'how to care for handmade ceramics, pottery care, handmade pottery care, ceramic care guide',
};
const PackagingGuide: React.FC = () => {
React.useEffect(() => {
document.title = "How to Package Pottery for Shipping: A Safe Guide | KNUTH Ceramics";
let meta = document.querySelector('meta[name="description"]');
if (!meta) {
meta = document.createElement('meta');
meta.setAttribute('name', 'description');
document.head.appendChild(meta);
}
meta.setAttribute('content', 'Learn how to package pottery for shipping safely. Use our double-box method and sustainable tips to ensure your handmade ceramics arrive intact. Read now.');
}, []);
return (
<>
<SEO
title="How to Care for Handmade Ceramics | Daily Care Guide"
description="How to care for handmade ceramics: a practical daily care guide for mugs, bowls, and plates, including dishwasher, microwave, crazing, and cleaning tips."
canonical={`${SITE_URL}/editorial/how-to-care-for-handmade-ceramics`}
schema={articleSchema}
ogType="article"
ogImage={HERO_IMAGE}
/>
<BlogPostLayout
title="How to Package Pottery for Shipping"
title="How to Care for Handmade Ceramics"
category="Guide"
date="Jul 15"
image="https://lh3.googleusercontent.com/aida-public/AB6AXuAaWGnX_NYT3S_lOflL2NJZGbWge4AAkvra4ymvF8ag-c1UKsOAIB-rsLVQXW5xIlPZipDiK8-ysPyv22xdgsvzs4EOXSSCcrT4Lb2YCe0u5orxRaZEA5TgxeoKq15zaWKSlmnHyPGjPd_7yglpfO13eZmbU5KaxFJ1KGO0UAxoO9BpsyCYgbgINMoSz3epGe5ZdwBWRH-5KCzjoLuXimFTLcd5bqg9T1YofTxgy2hWBMJzKkafyEniq8dP6hMmfNCLVcCHHHx0hRU"
imageAlt="How to Package Pottery for Shipping Safely guide"
image={HERO_IMAGE}
imageAlt="how to care for handmade ceramics - handmade pottery drying after washing"
>
<p className="lead text-xl text-stone-600 dark:text-stone-300 italic mb-8">
<strong>How to Package Pottery for Shipping</strong> safely is the most important skill for a small business owner. There is nothing more heartbreaking than a shattered creation, so mastering this art form ensures your hard work survives the journey.
<strong>How to care for handmade ceramics</strong> is one of the most important questions to answer when pottery becomes part of daily life. Handmade mugs, bowls, and plates are meant to be used and loved often, but they do last better when they are treated with a little attention.
</p>
<p className="mb-6">
Here is your comprehensive guide on shipping handmade art so it arrives safely every single time.
There is something different about living with handmade work. A mug becomes part of a morning ritual. A bowl begins to hold fruit, soup, or sea salt on the kitchen counter. A plate starts to feel less like an object and more like part of the rhythm of the home. That is exactly why learning how to care for handmade ceramics matters.
</p>
<h2 className="mt-16 mb-8 text-3xl">1. The Double-Box Method (The Golden Rule)</h2>
<p className="mb-6">
When considering safe deliveryespecially for large itemsthe <strong>double-box method</strong> is the industry standard.
Good pottery does not need fussy care. It needs thoughtful care. If you understand a few basics about cleaning, temperature changes, glaze surfaces, and daily use, your favorite pieces can stay beautiful and functional for years.
</p>
<ul className="mb-12 space-y-4">
<li><strong>Inner Box</strong>: Wrap your <Link to="/collections">Collections</Link> piece and place it in a small box. It should fit snugly.</li>
<li><strong>Outer Box</strong>: Place the small box inside a larger shipping box, with at least 2 inches of padding on all sides.</li>
<li><em>Why?</em> The outer box absorbs the shock, keeping your art safe.</li>
</ul>
<h2 className="mt-16 mb-8 text-3xl">2. Wrapping Materials: Layers Matter</h2>
<h2 className="mt-16 mb-6 text-3xl">Start with the maker&apos;s care instructions</h2>
<p className="mb-6">
Don't rely on just one material when you plan your packing strategy.
The first rule in how to care for handmade ceramics is simple: trust the maker first. Whether a piece is dishwasher-safe, microwave-safe, or oven-safe depends on the clay body, the glaze fit, and the firing temperature. Properly fired stoneware and porcelain are often more durable than earthenware, but not every handmade ceramic piece should be treated the same way.
</p>
<p className="mb-6">
If the potter recommends hand washing, hand wash it. If the potter says a piece is decorative only, keep it out of food use. That guidance matters more than assumptions.
</p>
<h2 className="mt-16 mb-6 text-3xl">Dishwasher-safe does not always mean best in the dishwasher</h2>
<p className="mb-6">
A big part of how to care for handmade ceramics is understanding the difference between safe and ideal. Some handmade pottery can go in the dishwasher, especially vitrified stoneware or porcelain, but repeated dishwasher cycles can still dull glossy glazes, discolor unglazed foot rings, and expose pieces to small knocks from other dishes.
</p>
<p className="mb-6">
For everyday care, hand washing is often the gentler choice. Warm water, mild soap, and a soft sponge are usually enough. If you want a favorite mug or bowl to age well, hand washing is usually the safer long-term habit.
</p>
<ul className="mb-12 space-y-4">
<li><strong>Layer 1: Tissue Paper</strong>: Protects the glaze.</li>
<li><strong>Layer 2: Bubble Wrap</strong>: The workhorse. Wrap the piece <em>tightly</em> in small-bubble wrap.</li>
<li><strong>The Shake Test</strong>: Shake the box hard. If you hear movement, add tougher filler.</li>
</ul>
<div className="my-16">
<img
src="/assets/images/packaging_guide.png"
alt="Sustainable pottery packaging materials including honeycomb paper and packing peanuts"
className="w-full shadow-lg rounded-sm"
src="/product_images/care_guide_mid_v2.png"
alt="how to care for handmade ceramics - handmade pottery drying after washing"
className="w-full my-12 shadow-lg rounded-sm"
/>
<p className="text-sm text-center text-stone-500 mt-4 italic">Eco-friendly packaging materials ready for use.</p>
</div>
<h2 className="mt-16 mb-8 text-3xl">3. Sustainable Packaging Alternatives</h2>
<p className="mb-6">
Many customers value sustainability in our <Link to="/atelier">Atelier</Link>.
<p className="text-sm text-center text-stone-500 -mt-8 mb-12 italic">
Handmade ceramics last best when daily care is gentle, consistent, and suited to the way they were made.
</p>
<ul>
<li><strong>Honeycomb Paper</strong>: A biodegradable alternative.</li>
<li><strong>Corn Starch Peanuts</strong>: Dissolve in water.</li>
<li><strong>Cardboard Scraps</strong>: Excellent dense filler.</li>
<h2 className="mt-16 mb-6 text-3xl">Watch for crazing, cracks, and chips</h2>
<p className="mb-6">
Another important part of how to care for handmade ceramics is paying attention when a piece changes. Fine crack lines in the glaze, called crazing, may affect how easy a surface is to clean. Chips on rims or cracks that catch your fingernail are signs that a functional piece may no longer be ideal for food use.
</p>
<p className="mb-6">
That does not mean the piece has to be discarded. A cracked mug can become a pencil cup. A crazed bowl can hold keys, shells, or dried flowers. But damaged foodware is often better retired from the table.
</p>
<h2 className="mt-16 mb-6 text-3xl">Be careful with sudden temperature changes</h2>
<p className="mb-6">
If you are learning how to care for handmade ceramics, thermal shock is worth remembering. Ceramics do not like abrupt changes in temperature. A cold bowl moved straight into a hot oven, or a hot mug rinsed immediately under cold water, can crack from stress.
</p>
<p className="mb-6">
It is always safer to warm pottery gradually and let it cool naturally. Even if a piece is microwave- or oven-friendly, gentle handling helps it last longer.
</p>
<h2 className="mt-16 mb-6 text-3xl">Know what should and should not touch food</h2>
<p className="mb-6">
Food safety is part of how to care for handmade ceramics too. Handmade pottery from a reliable studio is very different from older decorative ware or uncertain imports. FDA guidance continues to warn that some traditional pottery may contain unsafe levels of lead, especially when the source and intended use are unclear.
</p>
<p className="mb-6">
For that reason, it is always best to buy functional pottery from makers who understand food-safe surfaces and can clearly tell you how the piece is intended to be used.
</p>
<h2 className="mt-16 mb-6 text-3xl">A few everyday habits help a lot</h2>
<ul className="mb-8 space-y-4 list-none pl-0">
<li><strong>Store pieces fully dry.</strong> Moisture trapped in stacked pottery can lead to marks and odor.</li>
<li><strong>Avoid metal scouring pads.</strong> Soft sponges are safer for glaze surfaces.</li>
<li><strong>Stack with care.</strong> Handmade rims and feet do not love rough contact.</li>
<li><strong>Lift larger mugs by the body when possible.</strong> It is simply gentler over time.</li>
<li><strong>Pay attention to unusual heat in the microwave.</strong> If a piece gets very hot quickly, stop using it that way.</li>
</ul>
<h2 className="mt-16 mb-8 text-3xl">4. Branding Your Unboxing Experience</h2>
<ul className="mb-12 space-y-4">
<li><strong>The "Thank You" Note</strong>: Builds a connection.</li>
<li><strong>Care Instructions</strong>: Explain microwave/dishwasher safety.</li>
<li><strong>Stickers</strong>: Build anticipation.</li>
</ul>
<p className="mb-6">
If you want to see how our functional work is made and presented, browse the <Link to="/collections">collection</Link>, visit the <Link to="/atelier">atelier</Link>, or read more through the <Link to="/editorial">editorial archive</Link>. For practical buying questions, the <Link to="/faq">FAQ</Link> is a useful next stop too.
</p>
<h2 className="mt-16 mb-8 text-3xl">5. Insurance and labeling</h2>
<ul className="mb-12 space-y-4">
<li><strong>Fragile Stickers</strong>: Helpful, but not a guarantee.</li>
<li><strong>Shipping Insurance</strong>: Always pay the extra few dollars for peace of mind.</li>
<h2 className="mt-16 mb-6 text-3xl">Handmade pottery is meant to be used</h2>
<p className="mb-6">
The heart of how to care for handmade ceramics is not perfection. It is attention. Use your pottery often. Wash it kindly. Store it dry. Notice when a piece needs a softer kind of use.
</p>
<p className="mb-12">
The best handmade ceramics are not the ones hidden away in a cabinet. They are the ones that become part of daily life. Knowing how to care for handmade ceramics simply helps those pieces stay with you longer.
</p>
<div className="mt-20 pt-12 border-t border-stone-200 dark:border-stone-800">
<h3 className="font-display text-xl mb-6 text-stone-500 dark:text-stone-400 uppercase tracking-widest text-sm">Sources & Further Reading</h3>
<ul className="space-y-2 text-sm text-stone-500 dark:text-stone-400 font-light">
{SOURCES.map((source) => (
<li key={source.href}>
<a href={source.href} target="_blank" rel="noreferrer" className="underline decoration-stone-300 underline-offset-4 hover:text-stone-700 dark:hover:text-stone-200">
{source.label}
</a>
</li>
))}
</ul>
</div>
</BlogPostLayout>
</>
);
};

View File

@@ -1,92 +1,154 @@
import React from 'react';
import { Link } from 'react-router-dom';
import BlogPostLayout from '../../components/BlogPostLayout';
// Wait, I don't know if react-helmet is installed. Checking package.json... it was not.
// I will adhere to the "no new dependencies" rule unless necessary. I'll just render the meta tags usually, but without Helmet they won't lift to head.
// The user asked for "Meta Title" and "Meta Description" implementation. I will add a helper to update document.title.
import SEO, { SITE_URL } from '../../components/SEO';
const HERO_IMAGE = 'https://lh3.googleusercontent.com/aida-public/AB6AXuAipMlYLTcRT_hdc3VePfFIlrA56VzZ5G2y3gcRfmIZMERwGFKq2N19Gqo6mw7uZowXmjl2eJ89TI3Mcud2OyOfadO3mPVF_v0sI0OHupqM49WEFcWzH-Wbu3DL6bQ46F2Y8SIAk-NUQy8psjcIdBKRrM8fqdn4eOPANYTXpVxkLMAm4R0Axy4aEKNdmj917ZKKTxvXB-J8nGlITJkJ-ua7XcZOwGnfK5ttzyWW35A0oOSffCf972gmpV27wrVQgYJNLS7UyDdyQIQ';
const SOURCES = [
{
label: 'Ceramic Arts Network - A Guide to Pottery Photography That Will Make Your Work Pop',
href: 'https://ceramicartsnetwork.org/daily/article/A-Guide-to-Pottery-Photography-That-Will-Make-Your-Work-Pop',
},
{
label: "Etsy Seller Handbook - The Ultimate Guide to Telling Your Etsy Shop's Visual Story",
href: 'https://www.etsy.com/seller-handbook/article/the-ultimate-guide-to-telling-your-etsy/22722480541',
},
{
label: 'ClayShare - Photographing Your Pottery',
href: 'https://www.clayshare.com/photographing-your-pottery',
},
];
const articleSchema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: 'Product Photography for Small Businesses',
description: 'Product photography for small businesses selling handmade ceramics. Learn light, angles, styling, and listing-photo essentials that help convert browsers into buyers.',
author: { '@type': 'Person', name: 'Claudia Knuth' },
publisher: { '@type': 'Organization', name: 'KNUTH Ceramics', url: SITE_URL },
datePublished: '2024-10-03',
url: `${SITE_URL}/editorial/product-photography-for-small-businesses`,
image: HERO_IMAGE,
mainEntityOfPage: `${SITE_URL}/editorial/product-photography-for-small-businesses`,
keywords: 'product photography for small businesses, pottery photography, ceramic product photos, handmade business photography',
};
const ProductPhotography: React.FC = () => {
React.useEffect(() => {
document.title = "Product Photography for Pottery: Tips for Sales | KNUTH Ceramics";
// Simple meta description update for basic SPA
let meta = document.querySelector('meta[name="description"]');
if (!meta) {
meta = document.createElement('meta');
meta.setAttribute('name', 'description');
document.head.appendChild(meta);
}
meta.setAttribute('content', 'Master Product Photography for Pottery with our DIY guide. Learn lighting and styling tips to boost your handmade ceramic sales online. Read more now.');
}, []);
return (
<>
<SEO
title="Product Photography for Small Businesses"
description="Product photography for small businesses selling handmade ceramics. Learn light, angles, styling, and listing-photo essentials that help convert browsers into buyers."
canonical={`${SITE_URL}/editorial/product-photography-for-small-businesses`}
schema={articleSchema}
ogType="article"
ogImage={HERO_IMAGE}
/>
<BlogPostLayout
title="Product Photography for Pottery"
title="Product Photography for Small Businesses"
category="Studio"
date="Oct 03"
image="https://lh3.googleusercontent.com/aida-public/AB6AXuAipMlYLTcRT_hdc3VePfFIlrA56VzZ5G2y3gcRfmIZMERwGFKq2N19Gqo6mw7uZowXmjl2eJ89TI3Mcud2OyOfadO3mPVF_v0sI0OHupqM49WEFcWzH-Wbu3DL6bQ46F2Y8SIAk-NUQy8psjcIdBKRrM8fqdn4eOPANYTXpVxkLMAm4R0Axy4aEKNdmj917ZKKTxvXB-J8nGlITJkJ-ua7XcZOwGnfK5ttzyWW35A0oOSffCf972gmpV27wrVQgYJNLS7UyDdyQIQ"
imageAlt="DIY Product Photography for Pottery setup with natural light"
image={HERO_IMAGE}
imageAlt="Product photography for small businesses - handmade pottery styled near a window with natural light"
>
<p className="lead text-xl text-stone-600 dark:text-stone-300 italic mb-8">
Mastering <strong>Product Photography for Pottery</strong> is essential because in the world of handmade business, your work is only as good as the photo that represents it. Since customers can't touch your mugs online, your photos must bridge the gap between browsing and buying.
<strong>Product photography for small businesses</strong> is one of the most powerful tools a maker has, and one of the most overlooked. Beautiful pots are not enough on their own. You also need beautiful photos to tell the story.
</p>
<p>
Here is how to elevate your <strong>Product Photography for Pottery</strong> without expensive gear.
<p className="mb-6">
I remember a specific moment clearly. I had just finished a batch of Gulf-glazed mugs - soft seafoam bleeding into sandy cream, exactly the way the water looks near the shore on a quiet morning. I listed them on my shop within the hour, took a quick photo on my kitchen counter, and waited. Nothing.
</p>
<p className="mb-6">
A few weeks later I was scrolling through another potter&apos;s shop. The work was technically similar to mine, but her photos stopped me mid-scroll. Soft light across the throwing lines. A hand around a mug. A top-down shot that showed glaze pooling at the center of a bowl. I bought something without even meaning to.
</p>
<p className="mb-6">
That was the lesson: I was not selling bad pots. I was telling a bad story.
</p>
<h2 className="mt-16 mb-6 text-3xl">Why product photography matters so much</h2>
<p className="mb-6">
The strongest seller education on Etsy, Ceramic Arts Network, and ClayShare keeps circling the same truth: online buyers decide visually, and they decide quickly. For handmade ceramics, photos carry even more weight because customers cannot feel the clay body, read the glaze surface, or judge scale with their hands. Your images have to do that work for them.
</p>
<p className="mb-6">
Your job is to give the customer&apos;s hands something to imagine.
</p>
<h2 className="mt-16 mb-6 text-3xl">1. Start with light, not your camera</h2>
<p className="mb-6">
The camera matters less than the light. The most effective setup I know costs almost nothing: a large window, an overcast day, and a sheet of white foam board placed opposite the light source to lift the shadows.
</p>
<p className="mb-6">
What you want to avoid is direct sunlight. It creates harsh hotspots, flattens matte glazes, and blows out glossy surfaces. Soft directional light does the opposite. It reveals form, texture, and the subtle transitions that make handmade work feel alive.
</p>
<p className="mb-6">
If you need consistency year-round, two daylight-balanced LED lights with diffusion are enough for a small studio setup. But if you are just beginning, use the window first. Learn to see light before you spend money.
</p>
<img
src="https://images.unsplash.com/photo-1516483638261-f4dbaf036963?q=80&w=2574&auto=format&fit=crop"
alt="Product Photography for Pottery setup"
title="DIY Setup"
className="w-full my-12 shadow-lg"
src="/product_images/product_photography_mid_v2.png"
alt="Product photography for small businesses - ceramics styled near a window with soft natural light"
className="w-full my-12 shadow-lg rounded-sm"
/>
<h2 className="mt-16 mb-8 text-3xl">1. Treasure the Natural Light</h2>
<p className="mb-6">
Lighting is the single most critical element of successful <strong>Product Photography for Pottery</strong>. Avoid the harsh, yellow glow of indoor lamps. Instead, set up your "studio" next to a large North or South-facing window, similar to the natural light in our <Link to="/atelier">Atelier</Link>.
<p className="text-sm text-center text-stone-500 -mt-8 mb-12 italic">
Natural window light is still the easiest and most flattering starting point for pottery photography.
</p>
<ul className="mb-12 space-y-4">
<li><strong>Diffused Light is Best</strong>: If the sun is beaming directly in, tape a sheet of white parchment paper over the window. This creates soft shadows that highlight the curves of your <strong>ceramic vessels</strong> without blinding glare.</li>
<li><strong>The Golden Hour</strong>: For lifestyle shots, try shooting during the hour after sunrise or before sunset for a warm, magical glow.</li>
<h2 className="mt-16 mb-6 text-3xl">2. The six photos every listing needs</h2>
<p className="mb-6">
You do not need twenty angles. You need the right six:
</p>
<ul className="mb-8 space-y-4 list-none pl-0">
<li><strong>The hero shot.</strong> Slightly elevated, clean background, the image that carries the listing.</li>
<li><strong>The front profile.</strong> Shows silhouette, proportion, and handle placement.</li>
<li><strong>The top-down.</strong> Essential for bowls and plates because the interior matters.</li>
<li><strong>The detail shot.</strong> Throwing lines, glaze breaks, clay texture. This is where handmade work wins.</li>
<li><strong>The scale shot.</strong> A hand, spoon, or book nearby so size is unmistakable.</li>
<li><strong>The in-use shot.</strong> A mug with coffee, a bowl with fruit, a vase with something from outside. This is where people start seeing the piece in their own life.</li>
</ul>
<h2 className="mt-16 mb-8 text-3xl">2. Master the "Hero Shot"</h2>
<h2 className="mt-16 mb-6 text-3xl">3. Backgrounds and props should support the pot</h2>
<p className="mb-6">
Every listing needs a clear shot. When mastering <strong>Product Photography for Pottery</strong>, the "Hero Shot" usually requires a clean background for your <Link to="/collections">Collections</Link>.
For listing images, stay neutral: white paper, linen, stone, raw wood. For lifestyle images, use props that feel like they come from the same world as the clay. In my studio here in Corpus Christi, that often means weathered wood, natural fiber cloth, and something gathered from outside.
</p>
<ul className="mb-12 space-y-4">
<li><strong>The Infinite Curve</strong>: Use a large sheet of white poster board. Tape one end to the wall and let it curve gently down onto the table. This seamless background eliminates distracting horizon lines.</li>
<li><strong>Tripod Stability</strong>: Blurry photos are a dealbreaker. If you don't have a tripod, prop your phone up against a stack of books.</li>
<p className="mb-6">
The rule I keep coming back to is simple: props support the pot. They do not perform alongside it. If someone remembers the eucalyptus stem more than the bowl, pull the eucalyptus.
</p>
<h2 className="mt-16 mb-6 text-3xl">4. A few phone-camera habits matter more than gear</h2>
<ul className="mb-8 space-y-4 list-none pl-0">
<li><strong>Lock focus and exposure.</strong> Let the composition stay stable from shot to shot.</li>
<li><strong>Do not use digital zoom.</strong> Move closer instead.</li>
<li><strong>Use a tripod.</strong> Even a small tabletop phone tripod makes a visible difference.</li>
<li><strong>Keep white balance consistent.</strong> One glaze should not look like three different colors across one listing.</li>
<li><strong>Photograph details intentionally.</strong> Texture is part of the value of handmade work.</li>
</ul>
<h2 className="mt-16 mb-8 text-3xl">3. Tell a Story with Props</h2>
<p className="mb-6">
While a clean background shows the details, lifestyle **Product Photography for Pottery** sells the <em>dream</em>.
You can browse our <Link to="/collections">current collection</Link> to see how we approach consistency across listings, and our <Link to="/atelier">atelier page</Link> for the studio atmosphere those images grow out of.
</p>
<ul className="mb-12 space-y-4">
<li><strong>Context matters</strong>: Don't just show a mug; show it steaming with coffee next to a half-read book.</li>
<li><strong>Keep it subtle</strong>: Your props should never compete with your work. Neutral linens complement the vibrant <strong>glaze colors</strong> of your <Link to="/collections">Collections</Link>.</li>
</ul>
<h2 className="mt-16 mb-8 text-3xl">4. Angles & Details</h2>
<h2 className="mt-16 mb-6 text-3xl">This is craft, too</h2>
<p className="mb-6">
Don't stop at one angle. Online buyers need to see everything.
Product photography for small businesses is a craft skill the same way trimming or pulling a handle is a craft skill. It takes repetition. It takes attention. And it gets better when you treat it as part of the work rather than something separate from it.
</p>
<p className="mb-12">
Beautiful pots deserve an audience. Good photographs are often how they find one.
</p>
<ul className="mb-12 space-y-4">
<li><strong>The Eye-Level Shot</strong>: Perfect for showing the profile of a vase.</li>
<li><strong>The Top-Down Shot</strong>: Ideal for plates and bowls.</li>
<li><strong>The Detail Macro</strong>: Get close. Show the texture of the raw clay body.</li>
</ul>
<h2 className="mt-16 mb-8 text-3xl">5. Editing: Less is More</h2>
<p className="mb-6">
You don't need Photoshop. Free apps like <strong>Snapseed</strong> or <strong>Lightroom Mobile</strong> are powerful tools for editing <strong>Product Photography for Pottery</strong>.
</p>
<ul className="mb-12 space-y-4">
<li><strong>Correction, not Alteration</strong>: Adjust brightness, contrast, and white balance.</li>
<li><strong>True-to-Life Color</strong>: Be very careful not to over-saturate.</li>
<div className="mt-20 pt-12 border-t border-stone-200 dark:border-stone-800">
<h3 className="font-display text-xl mb-6 text-stone-500 dark:text-stone-400 uppercase tracking-widest text-sm">Sources & Further Reading</h3>
<ul className="space-y-2 text-sm text-stone-500 dark:text-stone-400 font-light">
{SOURCES.map((source) => (
<li key={source.href}>
<a href={source.href} target="_blank" rel="noreferrer" className="underline decoration-stone-300 underline-offset-4 hover:text-stone-700 dark:hover:text-stone-200">
{source.label}
</a>
</li>
))}
</ul>
</div>
</BlogPostLayout>
</>
);
};

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { useParams, Link } from 'react-router-dom';
import { motion } from 'framer-motion';
import { useStore } from '../src/context/StoreContext';
import SEO, { SITE_URL } from '../components/SEO';
const ProductDetail: React.FC = () => {
const { slug } = useParams<{ slug: string }>();
@@ -17,8 +18,56 @@ const ProductDetail: React.FC = () => {
);
}
const productSchema = {
"@context": "https://schema.org",
"@type": "Product",
"name": product.title,
"description": `${product.description} Handcrafted in Corpus Christi, TX by Claudia Knuth. Made in small batches using stoneware clay inspired by the Texas Gulf Coast.`,
"image": `${SITE_URL}${product.image}`,
"url": `${SITE_URL}/collections/${product.slug}`,
"brand": {
"@type": "Brand",
"name": "KNUTH Ceramics"
},
"manufacturer": {
"@type": "LocalBusiness",
"name": "KNUTH Ceramics",
"address": {
"@type": "PostalAddress",
"addressLocality": "Corpus Christi",
"addressRegion": "TX",
"addressCountry": "US"
}
},
"offers": {
"@type": "Offer",
"availability": "https://schema.org/InStock",
"priceCurrency": "USD",
"seller": {
"@type": "Organization",
"name": "KNUTH Ceramics"
}
},
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": `${SITE_URL}/` },
{ "@type": "ListItem", "position": 2, "name": "Collections", "item": `${SITE_URL}/collections` },
{ "@type": "ListItem", "position": 3, "name": product.title, "item": `${SITE_URL}/collections/${product.slug}` }
]
}
};
return (
<div className="bg-white dark:bg-stone-950 min-h-screen pt-32 pb-24">
<SEO
title={`${product.title} — Handmade Ceramic | KNUTH Ceramics`}
description={`${product.description} Handcrafted in Corpus Christi, TX. $${product.price} — free shipping on orders over $150.`}
canonical={`${SITE_URL}/collections/${product.slug}`}
ogImage={`${SITE_URL}${product.image}`}
ogType="product"
schema={productSchema}
/>
<div className="max-w-[1920px] mx-auto px-6 md:px-12">
{/* Breadcrumb */}
<div className="mb-12 text-sm uppercase tracking-widest text-stone-500">
@@ -91,6 +140,7 @@ const ProductDetail: React.FC = () => {
</ul>
</motion.div>
{/*
<motion.button
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
@@ -101,6 +151,7 @@ const ProductDetail: React.FC = () => {
>
Add to Cart
</motion.button>
*/}
<div className="mt-12 pt-12 border-t border-stone-200 dark:border-stone-800 text-sm text-stone-500 font-light space-y-2">
<p>Free shipping on orders over $150</p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 622 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 794 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 808 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 695 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 879 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@@ -0,0 +1,37 @@
# KNUTH Ceramics — robots.txt
# https://knuthceramics.com
User-agent: *
Allow: /
Disallow: /checkout
Disallow: /mock-payment
Disallow: /success
Disallow: /admin
# AI Search Crawlers — explicitly allowed for citation visibility
User-agent: GPTBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: anthropic-ai
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: Bingbot
Allow: /
# Training-only crawlers — blocked (prevents scraping without citation benefit)
User-agent: CCBot
Disallow: /
Sitemap: https://knuthceramics.com/sitemap.xml

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<!-- Core pages -->
<url>
<loc>https://knuthceramics.com/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://knuthceramics.com/collections</loc>
<changefreq>weekly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://knuthceramics.com/atelier</loc>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://knuthceramics.com/editorial</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://knuthceramics.com/faq</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://knuthceramics.com/contact</loc>
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://knuthceramics.com/shipping</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knuthceramics.com/returns</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<!-- Product pages — Tableware -->
<url><loc>https://knuthceramics.com/collections/coastal-grey-tableware-set</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/ceramic-place-setting</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/textured-floral-plates</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<!-- Product pages — Coffee Cups -->
<url><loc>https://knuthceramics.com/collections/set-of-three-stoneware-cups</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/dog-mam-cup-teal</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/dog-mam-cup-blush</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/dark-stoneware-cups-amber-drip</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<!-- Product pages — Bowls -->
<url><loc>https://knuthceramics.com/collections/dark-stoneware-bowl</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/pastel-bowl-collection</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/coastal-sunset-bowl-set</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/handmade-blush-bowl</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<!-- Product pages — Kitchenware -->
<url><loc>https://knuthceramics.com/collections/dark-stoneware-vessel</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/studio-collection-mixed-pieces</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<!-- Product pages — Decoration -->
<url><loc>https://knuthceramics.com/collections/handmade-ceramic-rose</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/hope-bowl-with-clay-tokens</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/ceramic-house-lanterns</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/flower-frog-vase-gulf-blue</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<url><loc>https://knuthceramics.com/collections/miniature-ceramic-village</loc><changefreq>monthly</changefreq><priority>0.8</priority></url>
<!-- Journal / Editorial -->
<url>
<loc>https://knuthceramics.com/editorial/product-photography-for-small-businesses</loc>
<changefreq>yearly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://knuthceramics.com/editorial/the-art-of-packaging</loc>
<changefreq>yearly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://knuthceramics.com/editorial/finding-motivation-in-clay</loc>
<changefreq>yearly</changefreq>
<priority>0.6</priority>
</url>
</urlset>

View File

@@ -54,9 +54,9 @@ async function setup() {
{
title: 'Tableware',
price: 185,
image: '/collection-tableware.png',
image: '/product_images/tableware.png',
description: 'A complete hand-thrown tableware set for four. Finished in our signature matte white glaze with raw clay rims.',
gallery: ['/collection-tableware.png', '/pottery-plates.png', '/ceramic-cups.png'],
gallery: ['/product_images/tableware.png', '/product_images/textiles.png', '/product_images/kitchenware.png'],
slug: 'tableware-set',
number: '01',
aspect_ratio: 'aspect-[3/4]'
@@ -64,9 +64,9 @@ async function setup() {
{
title: 'Lighting',
price: 240,
image: '/collection-lighting.png',
image: '/product_images/lighting.png',
description: 'Sculptural ceramic pendant lights that bring warmth and texture to any space. Each piece is unique.',
gallery: ['/collection-lighting.png', '/pottery-studio.png', '/collection-vases.png'],
gallery: ['/product_images/lighting.png', '/landingpage/artelier.png', '/product_images/vases.png'],
slug: 'ceramic-lighting',
number: '04',
aspect_ratio: 'aspect-[4/3]'
@@ -74,9 +74,9 @@ async function setup() {
{
title: 'Vases',
price: 95,
image: '/collection-vases.png',
image: '/product_images/vases.png',
description: 'Organic forms inspired by the dunes of Padre Island. Perfect for dried stems or fresh bouquets.',
gallery: ['/collection-vases.png', '/pottery-vase.png', '/collection-lighting.png'],
gallery: ['/product_images/vases.png', '/product_images/vases.png', '/product_images/lighting.png'],
slug: 'organic-vases',
number: '02',
aspect_ratio: 'aspect-square'

View File

@@ -38,6 +38,7 @@ interface StoreContextType {
addArticle: (article: JournalEntry) => void;
updateArticle: (article: JournalEntry) => void;
deleteArticle: (id: number) => void;
isLoading: boolean;
}
const StoreContext = createContext<StoreContextType | undefined>(undefined);
@@ -283,9 +284,10 @@ export const StoreProvider: React.FC<{ children: ReactNode }> = ({ children }) =
deleteProduct,
addArticle,
updateArticle,
deleteArticle
deleteArticle,
isLoading
}}>
{isLoading ? <div className="fixed inset-0 bg-white z-50 flex items-center justify-center font-display text-xl animate-pulse">Loading Store...</div> : children}
{children}
</StoreContext.Provider>
);
};

6
package-lock.json generated Normal file
View File

@@ -0,0 +1,6 @@
{
"name": "hotschpotsh",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}