Initial Nusqool website replica with Next.js and Tailwind CSS

- Hero section with main tagline
- About Thu section with founder story
- The Space section (converted schoolhouse)
- 6 service offerings grid (virtual, in-person, workshops, etc.)
- Care Tent pop-up sanctuary section
- Dandelion Manifesto section
- Coralus Venture announcement
- Newsletter signup form
- Footer with Instagram and press mentions
- Responsive navigation with mobile menu
- Custom color palette (yellow, cream, brown, sage)
- Playfair Display + Inter typography

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2025-12-26 10:29:58 -05:00
commit 948e9c9c05
10 changed files with 6869 additions and 0 deletions

36
.gitignore vendored Normal file
View File

@ -0,0 +1,36 @@
# Dependencies
node_modules/
# Next.js
.next/
out/
# Production
build/
dist/
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Local env files
.env*.local
.env
# Vercel
.vercel
# TypeScript
*.tsbuildinfo
next-env.d.ts
# IDE
.idea/
.vscode/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db

9
next.config.ts Normal file
View File

@ -0,0 +1,9 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
images: {
domains: ["images.squarespace-cdn.com"],
},
};
export default nextConfig;

6114
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

1
package.json Normal file
View File

@ -0,0 +1 @@
{"name":"nusqool-replica","version":"0.1.0","private":true,"scripts":{"dev":"next dev","build":"next build","start":"next start","lint":"next lint"},"dependencies":{"next":"^15.0.0","react":"^19.0.0","react-dom":"^19.0.0"},"devDependencies":{"@types/node":"^22.0.0","@types/react":"^19.0.0","@types/react-dom":"^19.0.0","autoprefixer":"^10.4.0","eslint":"^9.0.0","eslint-config-next":"^15.0.0","postcss":"^8.4.0","tailwindcss":"^3.4.0","typescript":"^5.0.0"}}

9
postcss.config.mjs Normal file
View File

@ -0,0 +1,9 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
export default config;

69
src/app/globals.css Normal file
View File

@ -0,0 +1,69 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--foreground-rgb: 74, 55, 40;
--background-rgb: 250, 248, 245;
}
html {
scroll-behavior: smooth;
}
body {
color: rgb(var(--foreground-rgb));
background: rgb(var(--background-rgb));
}
@layer base {
h1, h2, h3, h4 {
@apply font-serif;
}
}
@layer components {
.btn-primary {
@apply inline-block px-8 py-3 bg-nusqool-yellow text-nusqool-brown font-medium
rounded-sm hover:bg-opacity-90 transition-all duration-300;
}
.btn-secondary {
@apply inline-block px-8 py-3 border-2 border-nusqool-brown text-nusqool-brown
font-medium rounded-sm hover:bg-nusqool-brown hover:text-white transition-all duration-300;
}
.section-padding {
@apply py-16 md:py-24 lg:py-32 px-6 md:px-12 lg:px-20;
}
.heading-xl {
@apply text-3xl md:text-4xl lg:text-5xl font-serif leading-tight;
}
.heading-lg {
@apply text-2xl md:text-3xl lg:text-4xl font-serif leading-tight;
}
.body-text {
@apply text-base md:text-lg leading-relaxed text-nusqool-warmGray;
}
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #FAF8F5;
}
::-webkit-scrollbar-thumb {
background: #E8C547;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #d4b03e;
}

42
src/app/layout.tsx Normal file
View File

@ -0,0 +1,42 @@
import type { Metadata } from "next";
import { Inter, Playfair_Display } from "next/font/google";
import "./globals.css";
const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
});
const playfair = Playfair_Display({
subsets: ["latin"],
variable: "--font-playfair",
});
export const metadata: Metadata = {
title: "Nusqool | Where Old Souls Come to Grow New Roots",
description:
"A healing and growth sanctuary in rural Ontario, Canada. Offering somatic practices, coaching, embodiment circles, and space for reconnection to your true self.",
keywords: [
"healing",
"somatic practices",
"coaching",
"embodiment",
"wellness",
"Ontario",
"retreat",
],
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${inter.variable} ${playfair.variable} font-sans antialiased`}>
{children}
</body>
</html>
);
}

520
src/app/page.tsx Normal file
View File

@ -0,0 +1,520 @@
"use client";
import { useState } from "react";
import Image from "next/image";
// Navigation Component
function Navigation() {
const [isOpen, setIsOpen] = useState(false);
const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
const menuItems = [
{
label: "Work with Thu",
submenu: [
"About Thu",
"Growth Adventure",
"Embodiment Circle",
"TRE",
"Coaching",
"Testimonials",
],
},
{ label: "Work with Chris", submenu: null },
{ label: "Events", submenu: null },
{ label: "Peace Pole", submenu: null },
{ label: "Contact Us", submenu: null },
];
return (
<nav className="fixed top-0 left-0 right-0 z-50 bg-nusqool-cream/95 backdrop-blur-sm">
<div className="max-w-7xl mx-auto px-6 py-4">
<div className="flex items-center justify-between">
{/* Logo */}
<a href="/" className="flex items-center">
<span className="text-2xl md:text-3xl font-serif text-nusqool-yellow font-bold tracking-wide">
Nusqool
</span>
</a>
{/* Desktop Menu */}
<div className="hidden lg:flex items-center space-x-8">
{menuItems.map((item) => (
<div
key={item.label}
className="relative"
onMouseEnter={() => setActiveDropdown(item.label)}
onMouseLeave={() => setActiveDropdown(null)}
>
<button className="text-nusqool-brown hover:text-nusqool-yellow transition-colors py-2">
{item.label}
{item.submenu && (
<span className="ml-1 text-xs"></span>
)}
</button>
{item.submenu && activeDropdown === item.label && (
<div className="absolute top-full left-0 bg-white shadow-lg rounded-sm py-2 min-w-48">
{item.submenu.map((subItem) => (
<a
key={subItem}
href="#"
className="block px-4 py-2 text-nusqool-brown hover:bg-nusqool-cream hover:text-nusqool-yellow transition-colors"
>
{subItem}
</a>
))}
</div>
)}
</div>
))}
<button className="text-nusqool-brown hover:text-nusqool-yellow transition-colors">
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
</svg>
</button>
</div>
{/* Mobile Menu Button */}
<button
className="lg:hidden text-nusqool-brown"
onClick={() => setIsOpen(!isOpen)}
>
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
{isOpen ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
</button>
</div>
{/* Mobile Menu */}
{isOpen && (
<div className="lg:hidden mt-4 pb-4 border-t border-nusqool-brown/10">
{menuItems.map((item) => (
<div key={item.label} className="py-2">
<a href="#" className="block text-nusqool-brown hover:text-nusqool-yellow py-2">
{item.label}
</a>
{item.submenu && (
<div className="pl-4">
{item.submenu.map((subItem) => (
<a
key={subItem}
href="#"
className="block text-nusqool-warmGray hover:text-nusqool-yellow py-1 text-sm"
>
{subItem}
</a>
))}
</div>
)}
</div>
))}
</div>
)}
</div>
</nav>
);
}
// Hero Section
function Hero() {
return (
<section className="relative min-h-screen flex items-center justify-center bg-nusqool-sage/20">
{/* Background Pattern */}
<div className="absolute inset-0 opacity-10">
<div className="absolute inset-0 bg-gradient-to-br from-nusqool-sage/30 to-transparent" />
</div>
{/* Hero Image Placeholder */}
<div className="absolute inset-0 bg-gradient-to-b from-nusqool-cream/80 via-transparent to-nusqool-cream/90" />
<div className="relative z-10 text-center max-w-4xl mx-auto px-6 pt-20">
<h1 className="heading-xl text-nusqool-brown mb-6">
Nusqool: where old souls come to grow new roots
</h1>
<p className="body-text max-w-2xl mx-auto mb-10">
A sanctuary for healing, growth, and reconnection in the heart of rural Ontario.
</p>
<a href="#adventure" className="btn-primary">
Choose your own growth adventure
</a>
</div>
{/* Scroll indicator */}
<div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 animate-bounce">
<svg className="w-6 h-6 text-nusqool-brown/50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
</svg>
</div>
</section>
);
}
// About Section
function About() {
return (
<section id="about" className="section-padding bg-white">
<div className="max-w-7xl mx-auto">
<div className="grid lg:grid-cols-2 gap-12 lg:gap-20 items-center">
{/* Image */}
<div className="relative aspect-[4/5] bg-nusqool-sage/20 rounded-sm overflow-hidden">
<div className="absolute inset-0 flex items-center justify-center text-nusqool-sage/40">
<svg className="w-24 h-24" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
</div>
<div className="absolute bottom-0 left-0 right-0 h-1/3 bg-gradient-to-t from-nusqool-brown/20 to-transparent" />
</div>
{/* Content */}
<div>
<h2 className="heading-lg text-nusqool-brown mb-6">
There comes a moment when your old ways of being no longer fits your becoming
</h2>
<div className="space-y-6 body-text">
<p>
I&apos;ve unraveled many timesafter medical emergencies, through cancer, through
near-death experiences, and startup failures.
</p>
<p>
Each time, I found myself craving a safe space where my body could simply
<em> be</em>without pressure to perform or explain. A space to breathe, to
feel, to slowly find my way back to myself.
</p>
<p>
That longing became the seed of <strong>Nusqool</strong>.
</p>
</div>
<div className="mt-8">
<a href="#" className="btn-secondary">
Learn more about Thu
</a>
</div>
</div>
</div>
</div>
</section>
);
}
// The Space Section
function TheSpace() {
return (
<section className="section-padding bg-nusqool-cream">
<div className="max-w-7xl mx-auto">
<div className="grid lg:grid-cols-2 gap-12 lg:gap-20 items-center">
{/* Content */}
<div className="lg:order-2">
<h2 className="heading-lg text-nusqool-brown mb-6">
So we converted an old school house into a space for healing, creative expression
and reconnection to our true selves
</h2>
<div className="space-y-6 body-text">
<p>
Nestled in the countryside of rural Ontario, Nusqool is surrounded by
meadows, forests, and the gentle rhythm of nature.
</p>
<p>
Here, we offer programming through 1:1 work and Embodiment Circles,
alongside a community of facilitators, creatives, healers, musicians, and coaches.
</p>
<p className="font-medium text-nusqool-brown">
If you&apos;re looking for a space for your sacred pause, we welcome you.
</p>
</div>
</div>
{/* Image Grid */}
<div className="lg:order-1 grid grid-cols-2 gap-4">
<div className="aspect-square bg-nusqool-sage/20 rounded-sm" />
<div className="aspect-square bg-nusqool-yellow/20 rounded-sm" />
<div className="aspect-square bg-nusqool-brown/10 rounded-sm" />
<div className="aspect-square bg-nusqool-sage/30 rounded-sm" />
</div>
</div>
</div>
</section>
);
}
// Services Section
function Services() {
const services = [
{
title: "Virtual Sessions",
description: "1:1 support that meets you where you are — weaving somatics, coaching, and embodied leadership",
icon: "💻",
},
{
title: "In Person Sessions",
description: "Custom days at Nusqool including self-reflection with tea, movement, nature, and deep rest",
icon: "🌿",
},
{
title: "Group Workshops",
description: "Rooted in lived experience and uplifting collaborations",
icon: "👥",
},
{
title: "Team Building & Offsites",
description: "Indoor and outdoor space for groups to slow down and reconnect",
icon: "🏡",
},
{
title: "Keynotes & Speaking",
description: "Topics include authenticity, worthiness, belonging, burnout, and nervous system healing",
icon: "🎤",
},
{
title: "Neurogenic Dancing",
description: "Music and movement for conscious gatherings, weaving Ecstatic Dance with Neurogenic Tremoring",
icon: "💃",
},
];
return (
<section id="adventure" className="section-padding bg-white">
<div className="max-w-7xl mx-auto">
<div className="text-center mb-16">
<h2 className="heading-lg text-nusqool-brown mb-4">
Choose Your Own Growth Adventure
</h2>
<p className="body-text max-w-2xl mx-auto">
Whether you&apos;re seeking individual support or a collective experience,
we offer pathways to help you feel, heal, grow, create, and return to
the pulse of your true self.
</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{services.map((service, index) => (
<div
key={index}
className="group p-8 bg-nusqool-cream rounded-sm hover:shadow-lg transition-all duration-300"
>
<div className="text-4xl mb-4">{service.icon}</div>
<h3 className="text-xl font-serif text-nusqool-brown mb-3 group-hover:text-nusqool-yellow transition-colors">
{service.title}
</h3>
<p className="body-text text-sm">{service.description}</p>
</div>
))}
</div>
</div>
</section>
);
}
// Care Tent Section
function CareTent() {
return (
<section className="section-padding bg-nusqool-sage/10">
<div className="max-w-7xl mx-auto">
<div className="grid lg:grid-cols-2 gap-12 lg:gap-20 items-center">
{/* Image */}
<div className="relative aspect-video bg-nusqool-sage/20 rounded-sm overflow-hidden">
<div className="absolute inset-0 flex items-center justify-center text-nusqool-sage/40">
<svg className="w-16 h-16" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 3L2 12h3v8h6v-6h2v6h6v-8h3L12 3z"/>
</svg>
</div>
</div>
{/* Content */}
<div>
<span className="text-sm uppercase tracking-wider text-nusqool-sage font-medium">
Pop-Up Sanctuary
</span>
<h2 className="heading-lg text-nusqool-brown mt-2 mb-6">
The Care Tent
</h2>
<div className="space-y-4 body-text">
<p>
Launched at the Coralus 10th Year Anniversary, the Care Tent is a
pop-up sanctuary for conferences and festivalsa space for rest,
regulation, and gentle reconnection.
</p>
<ul className="space-y-2 pl-4">
<li className="flex items-start">
<span className="text-nusqool-yellow mr-2"></span>
Rest spaces with hammocks, rugs, and pillows
</li>
<li className="flex items-start">
<span className="text-nusqool-yellow mr-2"></span>
Self-guided practices and art supplies
</li>
<li className="flex items-start">
<span className="text-nusqool-yellow mr-2"></span>
Nervous system reset tools
</li>
<li className="flex items-start">
<span className="text-nusqool-yellow mr-2"></span>
Optional 1:1 somatic sessions
</li>
</ul>
</div>
<div className="mt-8">
<a href="#" className="btn-primary">
Get in touch
</a>
</div>
</div>
</div>
</div>
</section>
);
}
// Manifesto Section
function Manifesto() {
return (
<section className="section-padding bg-nusqool-brown text-white">
<div className="max-w-4xl mx-auto text-center">
<h2 className="heading-lg text-nusqool-yellow mb-8">
Let&apos;s bloom and navigate the mysteries of liminal space together
</h2>
<div className="space-y-6 text-lg leading-relaxed text-white/80">
<p>
Like the dandelion, we trust the wisdom of being scattered.
</p>
<p>
We believe that on the other side of fear is not failure
<span className="text-nusqool-yellow font-medium"> but Transformation.</span>
</p>
</div>
<div className="mt-10">
<a
href="#"
className="inline-block px-8 py-3 bg-nusqool-yellow text-nusqool-brown font-medium rounded-sm hover:bg-opacity-90 transition-all duration-300"
>
Read our Dandelion Manifesto
</a>
</div>
</div>
</section>
);
}
// Coralus Section
function Coralus() {
return (
<section className="section-padding bg-white">
<div className="max-w-4xl mx-auto text-center">
<div className="inline-block p-4 bg-nusqool-cream rounded-full mb-6">
<svg className="w-16 h-16 text-nusqool-sage" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2L4 7v10l8 5 8-5V7l-8-5zm0 2.18l6 3.72v7.2l-6 3.72-6-3.72v-7.2l6-3.72z"/>
</svg>
</div>
<p className="text-sm uppercase tracking-wider text-nusqool-sage font-medium mb-2">
March 26, 2025
</p>
<h2 className="heading-lg text-nusqool-brown mb-6">
Nusqool has been selected as a Coralus Venture
</h2>
<p className="body-text max-w-2xl mx-auto">
We&apos;re honored to join a community of women and non-binary entrepreneurs
who are building businesses that create positive change in the world.
</p>
</div>
</section>
);
}
// Newsletter Section
function Newsletter() {
return (
<section className="section-padding bg-nusqool-cream">
<div className="max-w-2xl mx-auto text-center">
<h2 className="heading-lg text-nusqool-brown mb-4">
Stay Connected
</h2>
<p className="body-text mb-8">
Join our community and receive updates on events, offerings, and
musings on growth and healing.
</p>
<form className="flex flex-col sm:flex-row gap-4 max-w-md mx-auto">
<input
type="email"
placeholder="Your email address"
className="flex-1 px-4 py-3 border border-nusqool-brown/20 rounded-sm bg-white focus:outline-none focus:border-nusqool-yellow transition-colors"
/>
<button type="submit" className="btn-primary whitespace-nowrap">
Subscribe
</button>
</form>
<p className="text-sm text-nusqool-warmGray/60 mt-4">
We respect your privacy.
</p>
</div>
</section>
);
}
// Footer
function Footer() {
return (
<footer className="bg-nusqool-brown text-white py-12 px-6">
<div className="max-w-7xl mx-auto">
<div className="grid md:grid-cols-3 gap-8 items-center">
{/* Logo */}
<div>
<span className="text-2xl font-serif text-nusqool-yellow font-bold">
Nusqool
</span>
<p className="text-white/60 mt-2 text-sm">
Where old souls come to grow new roots
</p>
</div>
{/* Social */}
<div className="text-center">
<a
href="https://instagram.com/nusqool"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center text-white/80 hover:text-nusqool-yellow transition-colors"
>
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<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>
@nusqool
</a>
</div>
{/* Press */}
<div className="text-right">
<p className="text-white/60 text-sm">
Featured in <span className="text-white">Toronto Life</span>
</p>
<p className="text-white/40 text-xs">October 2020</p>
</div>
</div>
<div className="border-t border-white/10 mt-8 pt-8 text-center text-white/40 text-sm">
<p>© {new Date().getFullYear()} Nusqool. Rural Ontario, Canada.</p>
</div>
</div>
</footer>
);
}
// Main Page Component
export default function Home() {
return (
<main>
<Navigation />
<Hero />
<About />
<TheSpace />
<Services />
<CareTent />
<Manifesto />
<Coralus />
<Newsletter />
<Footer />
</main>
);
}

29
tailwind.config.ts Normal file
View File

@ -0,0 +1,29 @@
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
nusqool: {
yellow: "#E8C547",
cream: "#FAF8F5",
brown: "#4A3728",
sage: "#7A8B6E",
warmGray: "#6B6461",
},
},
fontFamily: {
sans: ["var(--font-inter)", "system-ui", "sans-serif"],
serif: ["var(--font-playfair)", "Georgia", "serif"],
},
},
},
plugins: [],
};
export default config;

40
tsconfig.json Normal file
View File

@ -0,0 +1,40 @@
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./src/*"
]
},
"target": "ES2017"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}