added dark mode and make wiki more detailed

This commit is contained in:
NillanHendrix
2026-05-09 11:16:26 +02:00
parent 7ffd5d5872
commit 7d9d63d120
5 changed files with 247 additions and 28 deletions
+16 -1
View File
@@ -1,4 +1,4 @@
import { useState } from 'react' import { useState, useEffect } from 'react'
import FooterNav from './components/FooterNav' import FooterNav from './components/FooterNav'
import Wiki from './pages/Wiki' import Wiki from './pages/Wiki'
import Calendar from './pages/Calendar' import Calendar from './pages/Calendar'
@@ -13,9 +13,24 @@ const pages = {
export default function App() { export default function App() {
const [page, setPage] = useState('myplants') const [page, setPage] = useState('myplants')
const [darkMode, setDarkMode] = useState(false)
useEffect(() => {
document.body.classList.toggle('dark-mode', darkMode)
document.documentElement.setAttribute('data-bs-theme', darkMode ? 'dark' : 'light')
}, [darkMode])
return ( return (
<> <>
<header className="position-fixed top-0 end-0 p-2">
<button
className="btn btn-outline-secondary btn-sm"
onClick={() => setDarkMode(!darkMode)}
title={darkMode ? 'Switch to light mode' : 'Switch to dark mode'}
>
{darkMode ? '☀️' : '🌙'}
</button>
</header>
<main className="app-main"> <main className="app-main">
{pages[page]} {pages[page]}
</main> </main>
+15 -17
View File
@@ -30,24 +30,22 @@
} }
} }
@media (prefers-color-scheme: dark) { .dark-mode {
:root { --text: #9ca3af;
--text: #9ca3af; --text-h: #f3f4f6;
--text-h: #f3f4f6; --bg: #16171d;
--bg: #16171d; --border: #2e303a;
--border: #2e303a; --code-bg: #1f2028;
--code-bg: #1f2028; --accent: #c084fc;
--accent: #c084fc; --accent-bg: rgba(192, 132, 252, 0.15);
--accent-bg: rgba(192, 132, 252, 0.15); --accent-border: rgba(192, 132, 252, 0.5);
--accent-border: rgba(192, 132, 252, 0.5); --social-bg: rgba(47, 48, 58, 0.5);
--social-bg: rgba(47, 48, 58, 0.5); --shadow:
--shadow: rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; }
}
#social .button-icon { .dark-mode #social .button-icon {
filter: invert(1) brightness(2); filter: invert(1) brightness(2);
}
} }
body { body {
+1
View File
@@ -1,6 +1,7 @@
import { StrictMode } from 'react' import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client'
import './index.css' import './index.css'
import 'bootstrap/dist/css/bootstrap.min.css'
import App from './App.jsx' import App from './App.jsx'
createRoot(document.getElementById('root')).render( createRoot(document.getElementById('root')).render(
+96
View File
@@ -144,6 +144,14 @@
.diff-hard { background: rgba(153,27,27,0.3); color: #fca5a5; } .diff-hard { background: rgba(153,27,27,0.3); color: #fca5a5; }
} }
.dark-mode .infobox {
background: rgba(31, 32, 40, 0.5);
}
.dark-mode .tutorial-card {
background: var(--bg);
}
.wiki-chevron { .wiki-chevron {
font-size: 11px; font-size: 11px;
color: var(--text); color: var(--text);
@@ -195,3 +203,91 @@
color: var(--text); color: var(--text);
margin-top: 48px; margin-top: 48px;
} }
.tutorials-section {
margin-bottom: 32px;
}
.tutorials-section h2 {
font-size: 24px;
margin-bottom: 16px;
}
.tutorials-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 16px;
}
.tutorial-card {
border: 1px solid var(--border);
border-radius: 12px;
padding: 16px;
background: var(--bg);
}
.tutorial-card h3 {
margin: 0 0 8px;
font-size: 18px;
}
.tutorial-card p {
margin: 0 0 12px;
color: var(--text);
}
.tutorial-card ol {
margin: 0;
padding-left: 20px;
}
.tutorial-card li {
margin-bottom: 4px;
color: var(--text);
}
.infobox {
float: right;
width: 250px;
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px;
margin: 0 0 16px 16px;
background: var(--code-bg);
font-size: 14px;
}
.infobox h3 {
margin: 0 0 8px;
font-size: 16px;
}
.infobox p {
margin: 4px 0;
font-size: 14px;
}
.wiki-card-body section {
margin-bottom: 20px;
}
.wiki-card-body section h3 {
font-size: 18px;
margin: 0 0 8px;
border-bottom: 1px solid var(--border);
padding-bottom: 4px;
}
.wiki-card-body section p {
margin: 0;
line-height: 1.6;
color: var(--text);
}
@media (max-width: 768px) {
.infobox {
float: none;
width: 100%;
margin: 0 0 16px;
}
}
+119 -10
View File
@@ -9,6 +9,12 @@ const plants = [
description: description:
'Known for its iconic split leaves, Monstera is a fast-growing tropical plant that thrives in warm, humid conditions. Perfect for adding a jungle vibe to any room.', 'Known for its iconic split leaves, Monstera is a fast-growing tropical plant that thrives in warm, humid conditions. Perfect for adding a jungle vibe to any room.',
emoji: '🌿', emoji: '🌿',
scientificName: 'Monstera deliciosa',
origin: 'Central America',
toxicity: 'Toxic to pets',
propagation: 'Stem cuttings in water or soil',
commonProblems: 'Yellow leaves (overwatering), brown tips (low humidity)',
tutorial: 'Prune aerial roots and provide support for climbing.',
}, },
{ {
id: 2, id: 2,
@@ -20,6 +26,12 @@ const plants = [
description: description:
'A rosette-forming succulent with thick, fleshy leaves. Extremely drought-tolerant and thrives on neglect. Ideal for beginners and sunny windowsills.', 'A rosette-forming succulent with thick, fleshy leaves. Extremely drought-tolerant and thrives on neglect. Ideal for beginners and sunny windowsills.',
emoji: '🪴', emoji: '🪴',
scientificName: 'Echeveria spp.',
origin: 'Mexico',
toxicity: 'Non-toxic',
propagation: 'Leaf cuttings or offsets',
commonProblems: 'Root rot (overwatering), etiolation (insufficient light)',
tutorial: 'Water from the bottom to avoid rot; repot every 2 years.',
}, },
{ {
id: 3, id: 3,
@@ -31,6 +43,12 @@ const plants = [
description: description:
'One of the few flowering plants that tolerates low light. Peace Lily also acts as an air purifier, removing toxins from indoor air.', 'One of the few flowering plants that tolerates low light. Peace Lily also acts as an air purifier, removing toxins from indoor air.',
emoji: '🌸', emoji: '🌸',
scientificName: 'Spathiphyllum spp.',
origin: 'Colombia and Venezuela',
toxicity: 'Toxic to pets',
propagation: 'Division of rhizomes',
commonProblems: 'Drooping leaves (thirsty), brown tips (fluoride in water)',
tutorial: 'Use filtered water; blooms indicate good health.',
}, },
{ {
id: 4, id: 4,
@@ -42,6 +60,12 @@ const plants = [
description: description:
'A culinary staple with fragrant leaves. Basil loves warmth and direct sunlight. Pinch flowers to keep leaves coming. Best grown on a kitchen windowsill.', 'A culinary staple with fragrant leaves. Basil loves warmth and direct sunlight. Pinch flowers to keep leaves coming. Best grown on a kitchen windowsill.',
emoji: '🌱', emoji: '🌱',
scientificName: 'Ocimum basilicum',
origin: 'India and Southeast Asia',
toxicity: 'Non-toxic',
propagation: 'Seeds or cuttings',
commonProblems: 'Bolting (stress from heat), aphids',
tutorial: 'Harvest leaves regularly; plant outdoors in summer.',
}, },
{ {
id: 5, id: 5,
@@ -53,6 +77,12 @@ const plants = [
description: description:
'Nearly indestructible, the Snake Plant tolerates neglect, low light, and irregular watering. Its upright leaves add architectural interest to any space.', 'Nearly indestructible, the Snake Plant tolerates neglect, low light, and irregular watering. Its upright leaves add architectural interest to any space.',
emoji: '🐍', emoji: '🐍',
scientificName: 'Sansevieria trifasciata',
origin: 'West Africa',
toxicity: 'Toxic to pets',
propagation: 'Leaf cuttings or division',
commonProblems: 'Root rot (overwatering), soft leaves (cold damage)',
tutorial: 'Rotate pot for even growth; clean leaves with damp cloth.',
}, },
{ {
id: 6, id: 6,
@@ -64,6 +94,12 @@ const plants = [
description: description:
'A dramatic statement plant with large, violin-shaped leaves. Fiddle Leaf Figs are sensitive to drafts and overwatering, but reward patience with stunning growth.', 'A dramatic statement plant with large, violin-shaped leaves. Fiddle Leaf Figs are sensitive to drafts and overwatering, but reward patience with stunning growth.',
emoji: '🎻', emoji: '🎻',
scientificName: 'Ficus lyrata',
origin: 'West Africa',
toxicity: 'Toxic to pets',
propagation: 'Stem cuttings with rooting hormone',
commonProblems: 'Leaf drop (stress), brown spots (overwatering)',
tutorial: 'Mist leaves; avoid moving plant frequently.',
}, },
{ {
id: 7, id: 7,
@@ -75,6 +111,12 @@ const plants = [
description: description:
'Fragrant and calming, lavender thrives in sunny spots with well-drained soil. Great for borders, pots, and drying for sachets.', 'Fragrant and calming, lavender thrives in sunny spots with well-drained soil. Great for borders, pots, and drying for sachets.',
emoji: '💜', emoji: '💜',
scientificName: 'Lavandula spp.',
origin: 'Mediterranean',
toxicity: 'Non-toxic',
propagation: 'Cuttings or seeds',
commonProblems: 'Root rot (poor drainage), powdery mildew',
tutorial: 'Prune after flowering; use gravel for drainage.',
}, },
{ {
id: 8, id: 8,
@@ -86,12 +128,54 @@ const plants = [
description: description:
'A trailing vine that can grow in almost any condition. Pothos is perfect for shelves and hanging baskets, and propagates effortlessly in water.', 'A trailing vine that can grow in almost any condition. Pothos is perfect for shelves and hanging baskets, and propagates effortlessly in water.',
emoji: '🍃', emoji: '🍃',
scientificName: 'Epipremnum aureum',
origin: 'Solomon Islands',
toxicity: 'Toxic to pets',
propagation: 'Stem cuttings in water',
commonProblems: 'Yellow leaves (overwatering), leggy growth (low light)',
tutorial: 'Trim vines to encourage bushiness; change water weekly for propagation.',
}, },
] ]
const categories = ['All', 'Tropical', 'Succulent', 'Herb'] const categories = ['All', 'Tropical', 'Succulent', 'Herb']
const difficulties = ['All', 'Very easy', 'Easy', 'Moderate', 'Hard'] const difficulties = ['All', 'Very easy', 'Easy', 'Moderate', 'Hard']
const tutorials = [
{
id: 1,
title: 'How to Propagate Houseplants',
description: 'Learn the basics of plant propagation with water and soil methods.',
steps: [
'Choose a healthy parent plant.',
'Take a cutting with at least one node.',
'Place in water or soil and wait for roots.',
'Transplant once rooted.',
],
},
{
id: 2,
title: 'Watering Guide: When and How Much',
description: 'Master the art of watering to keep your plants thriving.',
steps: [
'Check soil moisture with your finger.',
'Water thoroughly until it drains.',
'Empty saucer to prevent root rot.',
'Adjust frequency based on season.',
],
},
{
id: 3,
title: 'Repotting Your Plants',
description: 'Step-by-step guide to repotting for healthier growth.',
steps: [
'Choose pot 1-2 inches larger.',
'Use well-draining potting mix.',
'Gently remove plant from old pot.',
'Plant at same depth and water well.',
],
},
]
import { useState } from 'react' import { useState } from 'react'
import './Wiki.css' import './Wiki.css'
@@ -171,17 +255,42 @@ export default function Wiki() {
{expanded === plant.id && ( {expanded === plant.id && (
<div className="wiki-card-body"> <div className="wiki-card-body">
<p className="wiki-description">{plant.description}</p> <div className="infobox">
<div className="wiki-stats"> <h3>Quick Facts</h3>
<div className="stat"> <p><strong>Scientific Name:</strong> {plant.scientificName}</p>
<span className="stat-label">Light</span> <p><strong>Origin:</strong> {plant.origin}</p>
<span className="stat-value">{plant.light}</span> <p><strong>Toxicity:</strong> {plant.toxicity}</p>
</div> <p><strong>Difficulty:</strong> {plant.difficulty}</p>
<div className="stat">
<span className="stat-label">Watering</span>
<span className="stat-value">{plant.water}</span>
</div>
</div> </div>
<section>
<h3>Description</h3>
<p>{plant.description}</p>
</section>
<section>
<h3>Care Instructions</h3>
<div className="wiki-stats">
<div className="stat">
<span className="stat-label">Light</span>
<span className="stat-value">{plant.light}</span>
</div>
<div className="stat">
<span className="stat-label">Watering</span>
<span className="stat-value">{plant.water}</span>
</div>
</div>
</section>
<section>
<h3>Propagation</h3>
<p>{plant.propagation}</p>
</section>
<section>
<h3>Common Problems</h3>
<p>{plant.commonProblems}</p>
</section>
<section>
<h3>Tutorial Tip</h3>
<p>{plant.tutorial}</p>
</section>
</div> </div>
)} )}
</li> </li>