Add initial README.md for Astro Starter Kit: Minimal

This commit is contained in:
2025-06-18 21:21:42 +02:00
parent 013b46a7c4
commit ca04704a0b
42 changed files with 10112 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
# jetbrains setting folder
.idea/

4
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

11
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

View File

@@ -0,0 +1,47 @@
# Astro Starter Kit: Minimal
```sh
npm create astro@latest -- --template minimal
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/minimal)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/minimal/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```text
/
├── public/
├── src/
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

15
astro.config.mjs Normal file
View File

@@ -0,0 +1,15 @@
// @ts-check
import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
import react from '@astrojs/react';
// https://astro.build/config
export default defineConfig({
vite: {
plugins: [tailwindcss()]
},
integrations: [react()]
});

View File

@@ -0,0 +1,8 @@
---
title: "Omoluabi Cultural Night"
date: "2023-03-15"
category: "Cultural"
image: "/images/events/cultural-night.jpg"
description: "A night to celebrate Yoruba culture, music, and food."
---
Experience the richness of Yoruba culture with music, dance, and traditional cuisine.

View File

@@ -0,0 +1,8 @@
---
title: "OMOLUABI WOMEN WING COURTESY VISIT TO THE NEW AMBASSADOR (DR ENIOLA AJAYI)"
date: "2023-04-01"
category: "Programme"
image: "/images/events/women-ambassador.jpg"
description: "4 man delegate of Omoluabi ladies to welcome the new ambassador to the Netherlands."
---
A beautiful courtesy visit by the Omoluabi women to the new ambassador.

View File

@@ -0,0 +1,8 @@
---
title: "Omoluabi Association Netherland Covid-19 Relief Programme"
date: "2023-04-25"
category: "Programme"
image: "/images/events/covid-relief.jpg"
description: "Covid-19 Relief Programme for the Nigerian community in the Netherlands."
---
Supporting our community during challenging times with relief efforts and solidarity.

View File

@@ -0,0 +1,8 @@
---
title: "Omoluabi Association Netherland Day & Launching"
date: "2023-08-26"
category: "Programme"
image: "/images/events/omoluabi-day.jpg"
description: "Omoluabi Association Netherlands Day and Launching 2023 Date: Saturday 26th August, 2023 Time: 5pm - 1:00am Location: Egoli 1, 1103 AC Amsterdam."
---
The Omoluabi Association Netherlands Day and Launching is a celebration of Yoruba culture and community in the Netherlands. Join us for a day of festivities, music, and cultural exchange!

View File

@@ -0,0 +1,9 @@
---
title: "Homepage Gallery"
images:
- "/images/gallery/photo1.jpg"
- "/images/gallery/photo2.jpg"
- "/images/gallery/photo3.jpg"
- "/images/gallery/photo4.jpg"
---
A sample gallery for the homepage. Add or remove images as needed.

View File

@@ -0,0 +1,23 @@
---
intro: |
Membership Benefits/Welfare Packages
1. A member recipients of any benefits must have been a financial member for a minimum period of 6(six) months and must be financially up to date.
2. The next of kin of a deceased member are entitled to the sum of 250.00 Euro.
3. Bereavement of an immediate family member ( e.g. Father, Mother, Wife, Son or Daughter) attracts the sum of 200.00 Euro.
4. Any financial member who is sent or deported home is entitled to the sum of 200.00 Euro.
5. Happy Ceremonies or Occasions (excluding Birthdays) of members on official invitation of the association attracts the sum of 200.00 Euro
members:
- name: "Chief (Mrs) Example A"
role: "President"
image: "/images/members/member1.jpg"
- name: "Chief Example B"
role: "Vice President"
image: "/images/members/member2.jpg"
- name: "Chief Example C"
role: "Secretary"
image: "/images/members/member3.jpg"
- name: "Chief Example D"
role: "Treasurer"
image: "/images/members/member4.jpg"
---
Sample members and benefits for the Omoluabi Association.

6101
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

23
package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "omoluabi",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/react": "^4.3.0",
"@tailwindcss/vite": "^4.1.10",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"astro": "^5.9.4",
"daisyui": "^5.0.43",
"keen-slider": "^6.8.6",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tailwindcss": "^4.1.10"
}
}

9
public/favicon.svg Normal file
View File

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
<style>
path { fill: #000; }
@media (prefers-color-scheme: dark) {
path { fill: #FFF; }
}
</style>
</svg>

After

Width:  |  Height:  |  Size: 749 B

View File

View File

View File

View File

0
public/images/hero1.jpg Normal file
View File

0
public/images/hero2.jpg Normal file
View File

0
public/images/hero3.jpg Normal file
View File

View File

View File

View File

View File

BIN
public/images/whoAreWe.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

View File

@@ -0,0 +1,46 @@
import { useState } from "react";
export default function ContactForm() {
const [status, setStatus] = useState("");
const handleSubmit = async (e) => {
e.preventDefault();
const form = e.target;
// Honeypot check
if (form.honey.value !== "") {
setStatus("Spam detected.");
return;
}
setStatus("Sending...");
// Placeholder: would POST to /api/contact
setTimeout(() => setStatus("Message sent (placeholder, not yet implemented)."), 1000);
};
return (
<form className="max-w-xl mx-auto bg-base-100 p-8 rounded-xl shadow-lg" onSubmit={handleSubmit} autoComplete="off">
<div className="mb-4">
<label htmlFor="name" className="block font-bold mb-1">Name</label>
<input type="text" id="name" name="name" className="input input-bordered w-full" required autoComplete="off" />
</div>
<div className="mb-4">
<label htmlFor="email" className="block font-bold mb-1">Email</label>
<input type="email" id="email" name="email" className="input input-bordered w-full" required autoComplete="off" />
</div>
<div className="mb-4">
<label htmlFor="subject" className="block font-bold mb-1">Subject</label>
<input type="text" id="subject" name="subject" className="input input-bordered w-full" required autoComplete="off" />
</div>
<div className="mb-4">
<label htmlFor="message" className="block font-bold mb-1">Message</label>
<textarea id="message" name="message" className="textarea textarea-bordered w-full" rows={5} required></textarea>
</div>
{/* Honeypot field for spam protection */}
<div style={{ display: "none" }}>
<label htmlFor="honey">Do not fill this out</label>
<input type="text" id="honey" name="honey" tabIndex="-1" autoComplete="off" />
</div>
<button type="submit" className="btn btn-primary w-full">Send Message</button>
{status && <div className="mt-4 text-center text-sm text-success">{status}</div>}
</form>
);
}

206
src/components/Footer.astro Normal file
View File

@@ -0,0 +1,206 @@
---
// Footer.astro - Modern Nigerian-themed footer
---
<footer class="bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 text-white relative overflow-hidden">
<!-- Background Pattern -->
<div class="absolute inset-0 opacity-5">
<div class="absolute inset-0" style="background-image: url('data:image/svg+xml,%3Csvg width=\"60\" height=\"60\" viewBox=\"0 0 60 60\" xmlns=\"http://www.w3.org/2000/svg\"%3E%3Cg fill=\"none\" fill-rule=\"evenodd\"%3E%3Cg fill=\"%23ffffff\" fill-opacity=\"0.1\"%3E%3Cpath d=\"M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z\"/%3E%3C/g%3E%3C/g%3E%3C/svg%3E');"></div>
</div>
<!-- Decorative Top Border -->
<div class="h-2 bg-gradient-to-r from-nigerian-green-500 via-kente-gold-500 to-ankara-red-500"></div>
<div class="container mx-auto px-4 py-16 relative z-10">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-12">
<!-- Brand Section -->
<div class="lg:col-span-2">
<div class="flex items-center gap-4 mb-6">
<!-- Logo -->
<div class="relative">
<div class="w-16 h-16 rounded-full bg-gradient-to-r from-nigerian-green-500 via-white to-nigerian-green-500 p-0.5 shadow-xl">
<div class="w-full h-full rounded-full bg-gray-800 flex items-center justify-center">
<div class="w-12 h-12 rounded-full bg-gradient-to-br from-nigerian-green-500 to-kente-gold-500 flex items-center justify-center">
<span class="text-white font-bold text-xl">O</span>
</div>
</div>
</div>
<div class="absolute -top-1 -right-1 w-5 h-5 bg-kente-gold-400 rounded-full animate-pulse"></div>
</div>
<div>
<h3 class="font-headline text-3xl font-bold bg-gradient-to-r from-nigerian-green-400 to-kente-gold-400 bg-clip-text text-transparent">
Omoluabi Foundation
</h3>
<p class="text-gray-400 text-sm">Building Bridges, Celebrating Heritage</p>
</div>
</div>
<p class="text-gray-300 leading-relaxed mb-6 max-w-md">
Connecting Nigerian hearts in the Netherlands through culture, community, and compassion.
Together, we preserve our heritage while embracing our future.
</p>
<!-- Nigerian Flag Colors Accent -->
<div class="flex items-center gap-4 mb-6">
<div class="flex gap-1">
<div class="w-4 h-6 bg-nigerian-green-500 rounded-sm"></div>
<div class="w-4 h-6 bg-white rounded-sm"></div>
<div class="w-4 h-6 bg-nigerian-green-500 rounded-sm"></div>
</div>
<span class="text-sm text-gray-400">Proudly Nigerian 🇳🇬 in the Netherlands 🇳🇱</span>
</div>
<!-- Social Media Links -->
<div class="flex gap-4">
<a href="#" class="group bg-gray-800 hover:bg-nigerian-green-500 p-3 rounded-full transition-all duration-300 transform hover:scale-110 hover:rotate-6">
<svg class="w-5 h-5 group-hover:text-white transition-colors" fill="currentColor" viewBox="0 0 24 24">
<path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"/>
</svg>
</a>
<a href="#" class="group bg-gray-800 hover:bg-kente-gold-500 p-3 rounded-full transition-all duration-300 transform hover:scale-110 hover:rotate-6">
<svg class="w-5 h-5 group-hover:text-white transition-colors" fill="currentColor" viewBox="0 0 24 24">
<path d="M22.46 6c-.77.35-1.6.58-2.46.69.88-.53 1.56-1.37 1.88-2.38-.83.5-1.75.85-2.72 1.05C18.37 4.5 17.26 4 16 4c-2.35 0-4.27 1.92-4.27 4.29 0 .34.04.67.11.98C8.28 9.09 5.11 7.38 3 4.79c-.37.63-.58 1.37-.58 2.15 0 1.49.75 2.81 1.91 3.56-.71 0-1.37-.2-1.95-.5v.03c0 2.08 1.48 3.82 3.44 4.21a4.22 4.22 0 0 1-1.93.07 4.28 4.28 0 0 0 4 2.98 8.521 8.521 0 0 1-5.33 1.84c-.34 0-.68-.02-1.02-.06C3.44 20.29 5.7 21 8.12 21 16 21 20.33 14.46 20.33 8.79c0-.19 0-.37-.01-.56.84-.6 1.56-1.36 2.14-2.23z"/>
</svg>
</a>
<a href="#" class="group bg-gray-800 hover:bg-ankara-red-500 p-3 rounded-full transition-all duration-300 transform hover:scale-110 hover:rotate-6">
<svg class="w-5 h-5 group-hover:text-white transition-colors" fill="currentColor" viewBox="0 0 24 24">
<path d="M12.017 0C5.396 0 .029 5.367.029 11.987c0 5.079 3.158 9.417 7.618 11.174-.105-.949-.199-2.403.041-3.439.219-.937 1.406-5.957 1.406-5.957s-.359-.72-.359-1.781c0-1.663.967-2.911 2.168-2.911 1.024 0 1.518.769 1.518 1.688 0 1.029-.653 2.567-.992 3.992-.285 1.193.6 2.165 1.775 2.165 2.128 0 3.768-2.245 3.768-5.487 0-2.861-2.063-4.869-5.008-4.869-3.41 0-5.409 2.562-5.409 5.199 0 1.033.394 2.143.889 2.741.097.118.112.221.083.343-.09.375-.293 1.199-.334 1.363-.053.225-.172.271-.402.165-1.495-.69-2.433-2.878-2.433-4.646 0-3.776 2.748-7.252 7.92-7.252 4.158 0 7.392 2.967 7.392 6.923 0 4.135-2.607 7.462-6.233 7.462-1.214 0-2.357-.629-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24.009 12.017 24.009c6.624 0 11.99-5.367 11.99-11.988C24.007 5.367 18.641.001.012.001z"/>
</svg>
</a>
<a href="#" class="group bg-gray-800 hover:bg-adire-blue-500 p-3 rounded-full transition-all duration-300 transform hover:scale-110 hover:rotate-6">
<svg class="w-5 h-5 group-hover:text-white transition-colors" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
</svg>
</a>
</div>
</div>
<!-- Quick Links -->
<div>
<h4 class="font-headline text-xl font-bold mb-6 text-white flex items-center gap-2">
<span class="w-1 h-6 bg-gradient-to-b from-nigerian-green-400 to-kente-gold-400 rounded-full"></span>
Quick Links
</h4>
<nav class="space-y-3">
<a href="/" class="block text-gray-300 hover:text-nigerian-green-400 transition-colors duration-200 hover:translate-x-1 transform">
Home
</a>
<a href="/events" class="block text-gray-300 hover:text-nigerian-green-400 transition-colors duration-200 hover:translate-x-1 transform">
Events
</a>
<a href="/members" class="block text-gray-300 hover:text-nigerian-green-400 transition-colors duration-200 hover:translate-x-1 transform">
Members
</a>
<a href="/orphanage" class="block text-gray-300 hover:text-nigerian-green-400 transition-colors duration-200 hover:translate-x-1 transform">
Orphanage
</a>
<a href="/contact" class="block text-gray-300 hover:text-nigerian-green-400 transition-colors duration-200 hover:translate-x-1 transform">
Contact
</a>
<a href="/join" class="block text-kente-gold-400 hover:text-kente-gold-300 transition-colors duration-200 hover:translate-x-1 transform font-semibold">
Join Us →
</a>
</nav>
</div>
<!-- Contact Info -->
<div>
<h4 class="font-headline text-xl font-bold mb-6 text-white flex items-center gap-2">
<span class="w-1 h-6 bg-gradient-to-b from-ankara-red-400 to-nigerian-green-400 rounded-full"></span>
Get in Touch
</h4>
<div class="space-y-4">
<div class="flex items-start gap-3">
<div class="bg-nigerian-green-500/20 p-2 rounded-lg mt-1">
<svg class="w-4 h-4 text-nigerian-green-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd"></path>
</svg>
</div>
<div>
<p class="text-gray-300 text-sm leading-relaxed">
Amsterdam, Netherlands<br/>
Various locations across NL
</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="bg-kente-gold-500/20 p-2 rounded-lg mt-1">
<svg class="w-4 h-4 text-kente-gold-400" fill="currentColor" viewBox="0 0 20 20">
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z"></path>
</svg>
</div>
<div>
<p class="text-gray-300 text-sm">
+31 (0) 123 456 789
</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="bg-ankara-red-500/20 p-2 rounded-lg mt-1">
<svg class="w-4 h-4 text-ankara-red-400" fill="currentColor" viewBox="0 0 20 20">
<path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z"></path>
<path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"></path>
</svg>
</div>
<div>
<p class="text-gray-300 text-sm">
info@omoluabi.nl
</p>
</div>
</div>
</div>
<!-- Newsletter Signup -->
<div class="mt-8 p-4 bg-gray-800/50 rounded-xl border border-gray-700">
<h5 class="font-semibold mb-3 text-white">Stay Updated</h5>
<div class="flex gap-2">
<input
type="email"
placeholder="Your email"
class="flex-1 px-3 py-2 bg-gray-700 border border-gray-600 rounded-lg text-sm text-white placeholder-gray-400 focus:border-nigerian-green-400 focus:outline-none"
/>
<button class="bg-nigerian-green-500 hover:bg-nigerian-green-600 px-4 py-2 rounded-lg transition-colors duration-200">
<svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
</svg>
</button>
</div>
</div>
</div>
</div>
<!-- Bottom Section -->
<div class="border-t border-gray-700 mt-12 pt-8">
<div class="flex flex-col md:flex-row justify-between items-center gap-4">
<!-- Copyright -->
<div class="text-gray-400 text-sm">
<span>&copy; {new Date().getFullYear()} Omoluabi Foundation Netherlands. </span>
<span class="text-nigerian-green-400">Made with ❤️ </span>
<span>for the Nigerian community.</span>
</div>
<!-- Additional Links -->
<div class="flex gap-6 text-sm">
<a href="/privacy" class="text-gray-400 hover:text-white transition-colors">Privacy Policy</a>
<a href="/terms" class="text-gray-400 hover:text-white transition-colors">Terms of Service</a>
<a href="/sitemap" class="text-gray-400 hover:text-white transition-colors">Sitemap</a>
</div>
</div>
<!-- Cultural Quote -->
<div class="mt-6 text-center">
<p class="text-gray-500 italic text-sm">
"Omoluabi ni wa" - We are people of good character
</p>
<div class="flex justify-center mt-2 gap-1">
<span class="text-nigerian-green-400">🌟</span>
<span class="text-kente-gold-400">🌟</span>
<span class="text-ankara-red-400">🌟</span>
</div>
</div>
</div>
</div>
</footer>

189
src/components/Header.astro Normal file
View File

@@ -0,0 +1,189 @@
---
// Header.astro - Updated with better navigation and active states
---
<header class="fixed top-0 left-0 right-0 z-50 bg-white/95 backdrop-blur-lg border-b border-gray-200/50 shadow-lg">
<div class="max-w-7xl mx-auto px-4">
<!-- Top bar with cultural elements -->
<div class="hidden md:flex items-center justify-between py-2 text-sm border-b border-gray-100">
<div class="flex items-center gap-4 text-gray-600">
<div class="flex items-center gap-2">
<svg class="w-4 h-4 text-green-600" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z" clip-rule="evenodd"></path>
</svg>
<span>Netherlands</span>
</div>
<div class="flex items-center gap-2">
<svg class="w-4 h-4 text-amber-600" fill="currentColor" viewBox="0 0 20 20">
<path d="M2 3a1 1 0 011-1h2.153a1 1 0 01.986.836l.74 4.435a1 1 0 01-.54 1.06l-1.548.773a11.037 11.037 0 006.105 6.105l.774-1.548a1 1 0 011.059-.54l4.435.74a1 1 0 01.836.986V17a1 1 0 01-1 1h-2C7.82 18 2 12.18 2 5V3z"></path>
</svg>
<span>+31 (0) 123 456 789</span>
</div>
</div>
<div class="flex items-center gap-1">
<span class="text-gray-500">🇳🇬</span>
<span class="font-semibold text-green-700">Celebrating Nigerian Heritage</span>
<span class="text-gray-500">🇳🇱</span>
</div>
</div>
<!-- Main navigation -->
<nav class="flex items-center justify-between py-4">
<!-- Logo -->
<a href="/" class="flex items-center gap-3 group">
<div class="relative">
<!-- Nigerian flag inspired logo -->
<div class="w-12 h-12 rounded-full bg-gradient-to-r from-green-500 via-white to-green-500 p-0.5 shadow-lg group-hover:shadow-xl transition-all duration-300">
<div class="w-full h-full rounded-full bg-white flex items-center justify-center">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-green-500 to-amber-500 flex items-center justify-center">
<span class="text-white font-bold text-sm">O</span>
</div>
</div>
</div>
<!-- Floating accent -->
<div class="absolute -top-1 -right-1 w-4 h-4 bg-amber-400 rounded-full animate-bounce"></div>
</div>
<div class="flex flex-col">
<span class="font-bold text-2xl bg-gradient-to-r from-green-600 to-amber-600 bg-clip-text text-transparent">
Omoluabi
</span>
<span class="text-sm text-gray-600 font-medium -mt-1">Foundation</span>
</div>
</a>
<!-- Desktop Navigation -->
<div class="hidden lg:flex items-center gap-1">
<a href="/" class="nav-link px-4 py-2 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200 relative group">
Home
<span class="absolute bottom-0 left-0 w-0 h-0.5 bg-green-600 group-hover:w-full transition-all duration-300"></span>
</a>
<a href="/about" class="nav-link px-4 py-2 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200 relative group">
About
<span class="absolute bottom-0 left-0 w-0 h-0.5 bg-green-600 group-hover:w-full transition-all duration-300"></span>
</a>
<a href="/events" class="nav-link px-4 py-2 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200 relative group">
Events
<span class="absolute bottom-0 left-0 w-0 h-0.5 bg-green-600 group-hover:w-full transition-all duration-300"></span>
</a>
<a href="/members" class="nav-link px-4 py-2 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200 relative group">
Members
<span class="absolute bottom-0 left-0 w-0 h-0.5 bg-green-600 group-hover:w-full transition-all duration-300"></span>
</a>
<a href="/orphanage" class="nav-link px-4 py-2 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200 relative group">
Orphanage
<span class="absolute bottom-0 left-0 w-0 h-0.5 bg-green-600 group-hover:w-full transition-all duration-300"></span>
</a>
<a href="/contact" class="nav-link px-4 py-2 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200 relative group">
Contact
<span class="absolute bottom-0 left-0 w-0 h-0.5 bg-green-600 group-hover:w-full transition-all duration-300"></span>
</a>
</div>
<!-- CTA Buttons -->
<div class="flex items-center gap-3">
<a href="/donate" class="inline-flex items-center px-6 py-2 bg-gradient-to-r from-red-500 to-red-600 text-white rounded-lg shadow-lg hover:shadow-xl hover:from-red-600 hover:to-red-700 transition-all duration-200 font-medium">
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z" clip-rule="evenodd"></path>
</svg>
Donate
</a>
<a href="/join" class="inline-flex items-center px-6 py-2 bg-gradient-to-r from-amber-500 to-amber-600 text-white rounded-lg shadow-lg hover:shadow-xl hover:from-amber-600 hover:to-amber-700 transition-all duration-200 font-medium">
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path d="M8 9a3 3 0 100-6 3 3 0 000 6zM8 11a6 6 0 016 6H2a6 6 0 016-6zM16 7a1 1 0 10-2 0v1h-1a1 1 0 100 2h1v1a1 1 0 102 0v-1h1a1 1 0 100-2h-1V7z"></path>
</svg>
Join Us
</a>
<!-- Mobile menu button -->
<button class="lg:hidden p-2 rounded-lg hover:bg-gray-100 transition-colors duration-200" onclick="toggleMobileMenu()">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</button>
</div>
</nav>
</div>
<!-- Mobile Navigation -->
<div id="mobile-menu" class="lg:hidden hidden bg-white border-t border-gray-200 shadow-lg">
<div class="max-w-7xl mx-auto px-4 py-4 space-y-2">
<a href="/" class="block px-4 py-3 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200">
🏠 Home
</a>
<a href="/about" class="block px-4 py-3 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200">
About
</a>
<a href="/events" class="block px-4 py-3 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200">
📅 Events
</a>
<a href="/members" class="block px-4 py-3 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200">
👥 Members
</a>
<a href="/orphanage" class="block px-4 py-3 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200">
🏠 Orphanage
</a>
<a href="/contact" class="block px-4 py-3 rounded-lg font-medium text-gray-700 hover:text-green-600 hover:bg-green-50 transition-all duration-200">
📞 Contact
</a>
</div>
</div>
</header>
<script>
function toggleMobileMenu() {
const menu = document.getElementById('mobile-menu');
menu.classList.toggle('hidden');
}
// Add active state to current page
document.addEventListener('DOMContentLoaded', function() {
const currentPath = window.location.pathname;
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
const href = link.getAttribute('href');
if (href === currentPath || (currentPath !== '/' && href !== '/' && currentPath.startsWith(href))) {
link.classList.add('text-green-600', 'bg-green-50');
const underline = link.querySelector('span');
if (underline) {
underline.classList.add('w-full');
}
}
});
});
</script>
<style>
/* Add some breathing room for fixed header */
body {
padding-top: 120px;
}
@media (max-width: 768px) {
body {
padding-top: 80px;
}
}
/* Ensure smooth transitions */
.nav-link {
position: relative;
overflow: hidden;
}
/* Custom bounce animation */
@keyframes bounce {
0%, 20%, 53%, 80%, 100% {
transform: translate3d(0,0,0);
}
40%, 43% {
transform: translate3d(0,-8px,0);
}
70% {
transform: translate3d(0,-4px,0);
}
90% {
transform: translate3d(0,-2px,0);
}
}
</style>

View File

@@ -0,0 +1,220 @@
import { useState, useEffect } from "react";
const slides = [
{
image: "/images/hero1.jpg",
alt: "Nigerian community gathering",
title: "Celebrating Nigerian Culture",
subtitle: "in the Heart of Netherlands",
description: "Join our vibrant community events that showcase the rich traditions, music, and cuisine of Nigeria while building lasting friendships.",
cta: "Join Our Events",
theme: "green"
},
{
image: "/images/hero2.jpg",
alt: "Children at orphanage",
title: "Supporting Our Future",
subtitle: "Orphanage Outreach Program",
description: "Making a real difference in the lives of children through education, healthcare, and providing hope for a brighter tomorrow.",
cta: "Learn More",
theme: "gold"
},
{
image: "/images/hero3.jpg",
alt: "Nigerian textiles and art",
title: "Proud Heritage",
subtitle: "United in Our Mission",
description: "Preserving and promoting Nigerian arts, crafts, and cultural traditions while fostering integration in Dutch society.",
cta: "Explore Culture",
theme: "red"
},
];
const themeColors = {
green: {
primary: "from-green-600 to-green-800",
secondary: "from-green-500 to-green-700",
accent: "bg-green-500",
text: "text-green-600"
},
gold: {
primary: "from-yellow-500 to-orange-600",
secondary: "from-yellow-400 to-orange-500",
accent: "bg-yellow-500",
text: "text-yellow-600"
},
red: {
primary: "from-red-600 to-red-800",
secondary: "from-red-500 to-red-700",
accent: "bg-red-500",
text: "text-red-600"
}
};
export default function HeroCarousel() {
const [currentSlide, setCurrentSlide] = useState(0);
const [isPlaying, setIsPlaying] = useState(true);
useEffect(() => {
if (!isPlaying) return;
const interval = setInterval(() => {
setCurrentSlide((prev) => (prev + 1) % slides.length);
}, 6000);
return () => clearInterval(interval);
}, [isPlaying]);
const nextSlide = () => {
setCurrentSlide((prev) => (prev + 1) % slides.length);
};
const prevSlide = () => {
setCurrentSlide((prev) => (prev - 1 + slides.length) % slides.length);
};
const goToSlide = (index) => {
setCurrentSlide(index);
};
return (
<div className="relative w-full max-w-6xl mx-auto rounded-2xl overflow-hidden shadow-2xl bg-white">
{/* Main Carousel Container */}
<div className="relative h-[600px] overflow-hidden">
{slides.map((slide, index) => {
const theme = themeColors[slide.theme];
return (
<div
key={index}
className={`absolute inset-0 transition-all duration-1000 ease-in-out ${
index === currentSlide
? 'opacity-100 translate-x-0'
: index < currentSlide
? 'opacity-0 -translate-x-full'
: 'opacity-0 translate-x-full'
}`}
>
{/* Background Image */}
<div className="absolute inset-0">
<img
src={slide.image}
alt={slide.alt}
className="w-full h-full object-cover"
/>
<div className={`absolute inset-0 bg-gradient-to-r ${theme.primary} opacity-80`}></div>
<div className="absolute inset-0 bg-gradient-to-t from-black/50 via-transparent to-transparent"></div>
</div>
{/* Content */}
<div className="relative z-10 h-full flex items-center">
<div className="container mx-auto px-8">
<div className="max-w-2xl text-white">
{/* Animated Content */}
<div className={`transition-all duration-1000 delay-300 ${
index === currentSlide ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'
}`}>
<div className="flex items-center gap-3 mb-4">
<div className={`w-2 h-12 ${theme.accent} rounded-full`}></div>
<span className="text-sm font-semibold uppercase tracking-wider opacity-90">
Omoluabi Foundation
</span>
</div>
<h1 className="text-5xl md:text-6xl font-bold mb-2 leading-tight">
{slide.title}
</h1>
<h2 className="text-2xl md:text-3xl font-light mb-6 text-yellow-200">
{slide.subtitle}
</h2>
<p className="text-lg md:text-xl mb-8 leading-relaxed opacity-90 max-w-xl">
{slide.description}
</p>
<div className="flex flex-col sm:flex-row gap-4">
<button className="bg-white text-gray-900 px-8 py-4 rounded-xl font-bold hover:bg-gray-100 transition-all duration-300 transform hover:scale-105 shadow-lg">
{slide.cta}
</button>
<button className="border-2 border-white text-white px-8 py-4 rounded-xl font-bold hover:bg-white hover:text-gray-900 transition-all duration-300 transform hover:scale-105">
Learn More
</button>
</div>
</div>
</div>
</div>
</div>
{/* Decorative Elements */}
<div className="absolute top-10 right-10 w-32 h-32 border-2 border-white/20 rounded-full animate-spin" style={{animationDuration: '20s'}}></div>
<div className="absolute bottom-10 left-10 w-24 h-24 border-2 border-white/20 rounded-full animate-bounce"></div>
</div>
);
})}
</div>
{/* Navigation Arrows */}
<button
onClick={prevSlide}
className="absolute left-4 top-1/2 -translate-y-1/2 bg-white/20 backdrop-blur-sm hover:bg-white/30 text-white p-3 rounded-full transition-all duration-300 hover:scale-110 group"
aria-label="Previous slide"
>
<svg className="w-6 h-6 group-hover:-translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
</button>
<button
onClick={nextSlide}
className="absolute right-4 top-1/2 -translate-y-1/2 bg-white/20 backdrop-blur-sm hover:bg-white/30 text-white p-3 rounded-full transition-all duration-300 hover:scale-110 group"
aria-label="Next slide"
>
<svg className="w-6 h-6 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
{/* Slide Indicators */}
<div className="absolute bottom-6 left-1/2 -translate-x-1/2 flex gap-3">
{slides.map((_, index) => (
<button
key={index}
onClick={() => goToSlide(index)}
className={`w-3 h-3 rounded-full transition-all duration-300 ${
index === currentSlide
? 'bg-white scale-125'
: 'bg-white/50 hover:bg-white/75'
}`}
aria-label={`Go to slide ${index + 1}`}
/>
))}
</div>
{/* Play/Pause Button */}
<button
onClick={() => setIsPlaying(!isPlaying)}
className="absolute top-4 right-4 bg-white/20 backdrop-blur-sm hover:bg-white/30 text-white p-2 rounded-full transition-all duration-300 hover:scale-110"
aria-label={isPlaying ? "Pause slideshow" : "Play slideshow"}
>
{isPlaying ? (
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clipRule="evenodd" />
</svg>
) : (
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clipRule="evenodd" />
</svg>
)}
</button>
{/* Progress Bar */}
<div className="absolute bottom-0 left-0 right-0 h-1 bg-white/20">
<div
className="h-full bg-gradient-to-r from-yellow-400 to-red-500 transition-all duration-100"
style={{
width: `${((currentSlide + 1) / slides.length) * 100}%`
}}
/>
</div>
</div>
);
}

View File

@@ -0,0 +1,14 @@
---
const gallery = await Astro.glob('../../content/gallery/gallery-sample.md');
const images = gallery[0]?.frontmatter.images || [];
---
<section class="max-w-6xl mx-auto my-20">
<h2 class="text-2xl font-headline font-bold mb-6 text-primary text-center">Gallery</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
{images.map((img, idx) => (
<div class="rounded-lg overflow-hidden shadow-md bg-base-100" key={idx}>
<img src={img} alt={`Gallery photo ${idx + 1}`} class="w-full h-40 object-cover hover:scale-105 transition-transform duration-200 cursor-pointer" />
</div>
))}
</div>
</section>

View File

@@ -0,0 +1,41 @@
---
// Base layout for all pages
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
---
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Omoluabi Foundation</title>
<meta name="description" content="Supporting Nigerians in the Netherlands" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<slot name="head" />
</head>
<body style="
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #fafafa 0%, #f0fdf4 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
padding-top: 80px;
">
<Header />
<main style="flex: 1;">
<slot />
</main>
<Footer />
</body>
</html>
<style>
@media (min-width: 768px) {
body {
padding-top: 120px !important;
}
}
</style>

1038
src/pages/about.astro Normal file

File diff suppressed because it is too large Load Diff

9
src/pages/contact.astro Normal file
View File

@@ -0,0 +1,9 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import ContactForm from '../components/ContactForm.jsx';
---
<BaseLayout>
<h1 class="text-3xl font-headline font-bold text-primary mt-12 text-center">Contact Us</h1>
<p class="mt-4 text-center">We'd love to hear from you! Please use the form below or reach out via our contact details.</p>
<ContactForm client:load />
</BaseLayout>

0
src/pages/donate.astro Normal file
View File

27
src/pages/events.astro Normal file
View File

@@ -0,0 +1,27 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
const events = await Astro.glob('../../content/events/*.md');
const sortedEvents = events.sort((a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date));
---
<BaseLayout>
<h1 class="text-3xl font-headline font-bold text-primary mt-12 text-center">Events</h1>
<p class="mt-4 text-center">See our upcoming and past events below.</p>
<section class="max-w-5xl mx-auto mt-8 grid grid-cols-1 md:grid-cols-2 gap-8 px-4">
{sortedEvents.map(event => (
<article class="card bg-base-100 shadow-lg">
<figure>
<img src={event.frontmatter.image} alt={event.frontmatter.title} class="w-full h-48 object-cover" />
</figure>
<div class="card-body">
<div class="flex items-center gap-2 mb-2">
<span class="badge badge-secondary">{event.frontmatter.category}</span>
<span class="text-xs text-gray-500">{new Date(event.frontmatter.date).toLocaleDateString()}</span>
</div>
<h2 class="card-title text-lg font-bold">{event.frontmatter.title}</h2>
<p class="text-sm mb-2">{event.frontmatter.description}</p>
<div class="text-xs text-gray-400">{event.compiledContent()}</div>
</div>
</article>
))}
</section>
</BaseLayout>

1299
src/pages/index.astro Normal file

File diff suppressed because it is too large Load Diff

22
src/pages/members.astro Normal file
View File

@@ -0,0 +1,22 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
const membersData = await Astro.glob('../../content/members/members-sample.md');
const intro = membersData[0]?.frontmatter.intro || '';
const members = membersData[0]?.frontmatter.members || [];
---
<BaseLayout>
<h1 class="text-3xl font-headline font-bold text-primary mt-12 text-center">Meet Our Members</h1>
<section class="max-w-3xl mx-auto mt-8 mb-12 bg-base-100 rounded-xl shadow p-6">
<h2 class="text-xl font-bold mb-4 text-accent">Membership Benefits/Welfare Packages</h2>
<div class="text-gray-700 whitespace-pre-line">{intro}</div>
</section>
<section class="max-w-6xl mx-auto grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-8 px-4 mb-20">
{members.map(member => (
<div class="card bg-base-100 shadow-lg rounded-xl flex flex-col items-center p-4">
<img src={member.image} alt={member.name} class="w-40 h-40 object-cover rounded-lg mb-4" />
<h3 class="font-bold text-lg text-primary mb-1">{member.name}</h3>
<p class="text-sm text-gray-600">{member.role}</p>
</div>
))}
</section>
</BaseLayout>

View File

@@ -0,0 +1,8 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout>
<h1 class="text-3xl font-headline font-bold text-nigerian-green mt-12 text-center">Orphanage</h1>
<p class="mt-4 text-center">Learn more about our affiliated orphanage and how you can help.</p>
<!-- Orphanage info, gallery, and donation details will go here -->
</BaseLayout>

397
src/styles/global.css Normal file
View File

@@ -0,0 +1,397 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700;800&family=Noto+Serif:wght@400;600;700&display=swap');
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
/* Root Variables for Nigerian Theme */
:root {
--nigerian-green: #16a34a;
--nigerian-white: #ffffff;
--kente-gold: #f59e0b;
--adire-blue: #2563eb;
--ankara-red: #dc2626;
--earth-brown: #a18072;
}
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', system-ui, sans-serif;
background: linear-gradient(135deg, #fafafa 0%, #f0fdf4 100%);
min-height: 100vh;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
}
::-webkit-scrollbar-thumb {
background: var(--nigerian-green);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #15803d;
}
/* Smooth hover transitions */
* {
transition: all 0.2s ease-in-out;
}
/* Nigerian pattern overlay */
.nigerian-pattern {
position: relative;
}
.nigerian-pattern::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23f59e0b' fill-opacity='0.03'%3E%3Cpath d='M20 20c0 11.046-8.954 20-20 20v-40c11.046 0 20 8.954 20 20zM40 20c0 11.046-8.954 20-20 20v-40c11.046 0 20 8.954 20 20z'/%3E%3C/g%3E%3C/svg%3E");
pointer-events: none;
}
/* Enhanced button styles */
.btn {
border-radius: 12px;
font-weight: 600;
letter-spacing: 0.025em;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
padding: 0.75rem 1.5rem;
border: none;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
text-decoration: none;
}
.btn-primary {
background: var(--nigerian-green);
color: white;
}
.btn-secondary {
background: var(--kente-gold);
color: white;
}
.btn-accent {
background: var(--ankara-red);
color: white;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s;
}
.btn:hover::before {
left: 100%;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px -3px rgba(0, 0, 0, 0.1);
}
.btn-lg {
padding: 1rem 2rem;
font-size: 1.125rem;
}
/* Card enhancements */
.card {
border-radius: 16px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid rgba(229, 229, 229, 0.8);
background: white;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.15);
}
.card-body {
padding: 1.5rem;
}
/* Input styling */
.input, .textarea {
border-radius: 12px;
border: 2px solid #e5e5e5;
transition: all 0.3s ease;
padding: 0.75rem 1rem;
width: 100%;
background: white;
}
.input:focus, .textarea:focus {
border-color: var(--nigerian-green);
box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.1);
outline: none;
}
/* Badge styling */
.badge {
border-radius: 20px;
font-weight: 600;
letter-spacing: 0.025em;
padding: 0.5rem 1rem;
font-size: 0.875rem;
display: inline-flex;
align-items: center;
}
.badge-primary {
background: var(--nigerian-green);
color: white;
}
.badge-secondary {
background: var(--kente-gold);
color: white;
}
.badge-lg {
padding: 0.75rem 1.25rem;
font-size: 1rem;
}
/* Hero text animations */
@keyframes textShine {
0% { background-position: -200% center; }
100% { background-position: 200% center; }
}
.text-shine {
background: linear-gradient(90deg, var(--nigerian-green), var(--kente-gold), var(--ankara-red), var(--nigerian-green));
background-size: 200% auto;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: textShine 3s linear infinite;
}
/* Animations */
@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
@keyframes slideUp {
0% { transform: translateY(30px); opacity: 0; }
100% { transform: translateY(0px); opacity: 1; }
}
@keyframes fadeIn {
0% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes bounceGentle {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-5px); }
}
.animate-float {
animation: float 6s ease-in-out infinite;
}
.animate-slide-up {
animation: slideUp 0.8s ease-out;
}
.animate-fade-in {
animation: fadeIn 1s ease-out;
}
.animate-bounce-gentle {
animation: bounceGentle 2s ease-in-out infinite;
}
/* Color utilities */
.text-nigerian-green { color: var(--nigerian-green); }
.text-kente-gold { color: var(--kente-gold); }
.text-ankara-red { color: var(--ankara-red); }
.text-primary { color: var(--nigerian-green); }
.text-secondary { color: var(--kente-gold); }
.text-accent { color: var(--ankara-red); }
.bg-nigerian-green { background-color: var(--nigerian-green); }
.bg-kente-gold { background-color: var(--kente-gold); }
.bg-ankara-red { background-color: var(--ankara-red); }
.bg-primary { background-color: var(--nigerian-green); }
.bg-secondary { background-color: var(--kente-gold); }
.bg-accent { background-color: var(--ankara-red); }
/* Gradient backgrounds */
.bg-nigerian-gradient {
background: linear-gradient(135deg, var(--nigerian-green) 0%, var(--kente-gold) 100%);
}
.bg-cultural-gradient {
background: linear-gradient(135deg, var(--nigerian-green) 0%, var(--kente-gold) 25%, var(--ankara-red) 75%, var(--nigerian-green) 100%);
}
/* Section padding utility */
.section-padding {
padding: 5rem 1rem;
}
@media (max-width: 768px) {
.section-padding {
padding: 3rem 1rem;
}
}
/* Grid utilities */
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
}
/* Typography */
.font-headline { font-family: 'Poppins', system-ui, sans-serif; }
.font-body { font-family: 'Inter', system-ui, sans-serif; }
.font-cultural { font-family: 'Noto Serif', serif; }
/* Text sizes */
.text-xs { font-size: 0.75rem; }
.text-sm { font-size: 0.875rem; }
.text-base { font-size: 1rem; }
.text-lg { font-size: 1.125rem; }
.text-xl { font-size: 1.25rem; }
.text-2xl { font-size: 1.5rem; }
.text-3xl { font-size: 1.875rem; }
.text-4xl { font-size: 2.25rem; }
.text-5xl { font-size: 3rem; }
.text-6xl { font-size: 3.75rem; }
.text-7xl { font-size: 4.5rem; }
/* Font weights */
.font-light { font-weight: 300; }
.font-normal { font-weight: 400; }
.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }
.font-bold { font-weight: 700; }
/* Spacing utilities */
.p-4 { padding: 1rem; }
.p-6 { padding: 1.5rem; }
.p-8 { padding: 2rem; }
.px-4 { padding-left: 1rem; padding-right: 1rem; }
.py-4 { padding-top: 1rem; padding-bottom: 1rem; }
.m-4 { margin: 1rem; }
.mb-4 { margin-bottom: 1rem; }
.mb-6 { margin-bottom: 1.5rem; }
.mb-8 { margin-bottom: 2rem; }
.mt-8 { margin-top: 2rem; }
.mt-12 { margin-top: 3rem; }
.mt-16 { margin-top: 4rem; }
.mt-20 { margin-top: 5rem; }
/* Layout utilities */
.flex { display: flex; }
.grid { display: grid; }
.block { display: block; }
.inline-flex { display: inline-flex; }
.items-center { align-items: center; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.gap-4 { gap: 1rem; }
.gap-6 { gap: 1.5rem; }
.gap-8 { gap: 2rem; }
.gap-12 { gap: 3rem; }
/* Grid utilities */
.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (min-width: 768px) {
.md\\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.md\\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
.lg\\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.lg\\:col-span-2 { grid-column: span 2 / span 2; }
}
/* Positioning */
.relative { position: relative; }
.absolute { position: absolute; }
.fixed { position: fixed; }
.top-0 { top: 0; }
.left-0 { left: 0; }
.right-0 { right: 0; }
.bottom-0 { bottom: 0; }
.inset-0 { top: 0; right: 0; bottom: 0; left: 0; }
.z-10 { z-index: 10; }
.z-50 { z-index: 50; }
/* Width and height */
.w-full { width: 100%; }
.h-full { height: 100%; }
.min-h-screen { min-height: 100vh; }
.max-w-2xl { max-width: 42rem; }
.max-w-3xl { max-width: 48rem; }
.max-w-4xl { max-width: 56rem; }
.max-w-5xl { max-width: 64rem; }
.max-w-6xl { max-width: 72rem; }
.mx-auto { margin-left: auto; margin-right: auto; }
/* Rounded corners */
.rounded-lg { border-radius: 0.5rem; }
.rounded-xl { border-radius: 0.75rem; }
.rounded-2xl { border-radius: 1rem; }
.rounded-full { border-radius: 9999px; }
/* Shadows */
.shadow-lg { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); }
.shadow-xl { box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); }
.shadow-2xl { box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); }
/* Transforms */
.transform { transform: translateX(var(--tw-translate-x, 0)) translateY(var(--tw-translate-y, 0)) rotate(var(--tw-rotate, 0)) skewX(var(--tw-skew-x, 0)) skewY(var(--tw-skew-y, 0)) scaleX(var(--tw-scale-x, 1)) scaleY(var(--tw-scale-y, 1)); }
.hover\\:scale-105:hover { --tw-scale-x: 1.05; --tw-scale-y: 1.05; }
.hover\\:-translate-y-2:hover { --tw-translate-y: -0.5rem; }
/* Text alignment */
.text-center { text-align: center; }
.text-left { text-align: left; }
/* Overflow */
.overflow-hidden { overflow: hidden; }
/* Background opacity */
.bg-opacity-80 { background-color: rgba(var(--tw-bg-opacity-value, 1), 0.8); }
.bg-opacity-90 { background-color: rgba(var(--tw-bg-opacity-value, 1), 0.9); }
/* Object fit */
.object-cover { object-fit: cover; }
.object-contain { object-fit: contain; }

284
tailwind.config.js Normal file
View File

@@ -0,0 +1,284 @@
// tailwind.config.mjs
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {
colors: {
// Nigerian flag colors as primary palette
'nigerian-green': {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d',
},
'nigerian-white': {
50: '#ffffff',
100: '#fefefe',
200: '#fafafa',
300: '#f5f5f5',
400: '#efefef',
500: '#e5e5e5',
},
// Rich cultural colors inspired by Nigerian textiles
'kente-gold': {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24',
500: '#f59e0b',
600: '#d97706',
700: '#b45309',
800: '#92400e',
900: '#78350f',
},
'adire-blue': {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
},
'ankara-red': {
50: '#fef2f2',
100: '#fee2e2',
200: '#fecaca',
300: '#fca5a5',
400: '#f87171',
500: '#ef4444',
600: '#dc2626',
700: '#b91c1c',
800: '#991b1b',
900: '#7f1d1d',
},
'earth-brown': {
50: '#fdf8f6',
100: '#f2e8e5',
200: '#eaddd7',
300: '#e0cfc5',
400: '#d2bab0',
500: '#bfa094',
600: '#a18072',
700: '#977669',
800: '#846358',
900: '#43302b',
}
},
fontFamily: {
'headline': ['Poppins', 'system-ui', 'sans-serif'],
'body': ['Inter', 'system-ui', 'sans-serif'],
'cultural': ['Noto Serif', 'serif'],
},
backgroundImage: {
'nigerian-pattern': `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23f59e0b' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`,
'kente-gradient': 'linear-gradient(135deg, #f59e0b 0%, #dc2626 25%, #16a34a 50%, #2563eb 75%, #f59e0b 100%)',
'hero-overlay': 'linear-gradient(135deg, rgba(22, 163, 74, 0.9) 0%, rgba(245, 158, 11, 0.8) 100%)',
},
animation: {
'float': 'float 6s ease-in-out infinite',
'slide-up': 'slideUp 0.8s ease-out',
'fade-in': 'fadeIn 1s ease-out',
'bounce-gentle': 'bounceGentle 2s ease-in-out infinite',
},
keyframes: {
float: {
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-10px)' },
},
slideUp: {
'0%': { transform: 'translateY(30px)', opacity: '0' },
'100%': { transform: 'translateY(0px)', opacity: '1' },
},
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
bounceGentle: {
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-5px)' },
}
},
boxShadow: {
'nigerian': '0 10px 25px -3px rgba(22, 163, 74, 0.1), 0 4px 6px -2px rgba(22, 163, 74, 0.05)',
'kente': '0 10px 25px -3px rgba(245, 158, 11, 0.2), 0 4px 6px -2px rgba(245, 158, 11, 0.1)',
}
},
},
daisyui: {
themes: [
{
omoluabi: {
"primary": "#16a34a", // Nigerian green
"secondary": "#f59e0b", // Kente gold
"accent": "#dc2626", // Ankara red
"neutral": "#fafafa", // Clean white base
"base-100": "#ffffff", // Pure white
"base-200": "#f5f5f5", // Light gray
"base-300": "#e5e5e5", // Medium gray
"info": "#2563eb", // Adire blue
"success": "#22c55e", // Success green
"warning": "#f59e0b", // Warning gold
"error": "#dc2626", // Error red
},
},
],
},
plugins: [require("daisyui")],
}
/* Updated global.css */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700;800&family=Noto+Serif:wght@400;600;700&display=swap');
@import "tailwindcss";
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', system-ui, sans-serif;
background: linear-gradient(135deg, #fafafa 0%, #f0fdf4 100%);
min-height: 100vh;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
}
::-webkit-scrollbar-thumb {
background: #16a34a;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #15803d;
}
/* Smooth hover transitions */
* {
transition: all 0.2s ease-in-out;
}
/* Nigerian pattern overlay */
.nigerian-pattern {
position: relative;
}
.nigerian-pattern::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23f59e0b' fill-opacity='0.03'%3E%3Cpath d='M20 20c0 11.046-8.954 20-20 20v-40c11.046 0 20 8.954 20 20zM40 20c0 11.046-8.954 20-20 20v-40c11.046 0 20 8.954 20 20z'/%3E%3C/g%3E%3C/svg%3E");
pointer-events: none;
}
/* Enhanced button styles */
.btn {
border-radius: 12px;
font-weight: 600;
letter-spacing: 0.025em;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s;
}
.btn:hover::before {
left: 100%;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px -3px rgba(0, 0, 0, 0.1);
}
/* Card enhancements */
.card {
border-radius: 16px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid rgba(229, 229, 229, 0.8);
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.1);
}
/* Input styling */
.input, .textarea {
border-radius: 12px;
border: 2px solid #e5e5e5;
transition: all 0.3s ease;
}
.input:focus, .textarea:focus {
border-color: #16a34a;
box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.1);
}
/* Badge styling */
.badge {
border-radius: 20px;
font-weight: 600;
letter-spacing: 0.025em;
}
/* Hero text animations */
@keyframes textShine {
0% { background-position: -200% center; }
100% { background-position: 200% center; }
}
.text-shine {
background: linear-gradient(90deg, #16a34a, #f59e0b, #dc2626, #16a34a);
background-size: 200% auto;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: textShine 3s linear infinite;
}
/* Loading animations */
.animate-pulse-slow {
animation: pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
/* Custom spacing utilities */
.section-padding {
padding: 5rem 1rem;
}
@media (max-width: 768px) {
.section-padding {
padding: 3rem 1rem;
}
}

14
tsconfig.json Normal file
View File

@@ -0,0 +1,14 @@
{
"extends": "astro/tsconfigs/strict",
"include": [
".astro/types.d.ts",
"**/*"
],
"exclude": [
"dist"
],
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react"
}
}