Edit the light mode
This commit is contained in:
parent
346fb57e39
commit
f5cd32bd58
@ -557,3 +557,154 @@ select {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Theme Toggle (fixed floating button) */
|
||||
.theme-toggle {
|
||||
position: fixed;
|
||||
top: 1.5rem;
|
||||
right: 1.5rem;
|
||||
z-index: 100;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--border-subtle);
|
||||
background: var(--card);
|
||||
color: var(--text-main);
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
|
||||
transition: all 180ms ease;
|
||||
}
|
||||
|
||||
.theme-toggle:hover {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.theme-toggle:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
/* Update body to apply bg properly in both themes */
|
||||
body {
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
[data-theme="dark"] body {
|
||||
background: radial-gradient(circle at top, #0f172a 0, #020617 55%);
|
||||
}
|
||||
|
||||
[data-theme="light"] {
|
||||
--bg: #f9fafb7a;
|
||||
--bg-elevated: #ffffff7c;
|
||||
--card: #ffffff54;
|
||||
--card-soft: #f3f4f6;
|
||||
--border-subtle: rgba(107, 114, 128, 0.25);
|
||||
--accent: #059669;
|
||||
--accent-soft: rgba(5, 150, 105, 0.12);
|
||||
--accent-strong: #047857;
|
||||
--text-main: #1f2937;
|
||||
--text-muted: #6b7280;
|
||||
--danger: #dc2626;
|
||||
}
|
||||
|
||||
[data-theme="light"] body {
|
||||
background: linear-gradient(180deg, #ac8d75 0%, #f6f8fa 100%);
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
[data-theme="light"] .topbar {
|
||||
background: linear-gradient(90deg, #e7be9e, #e2b08a);
|
||||
border: 1px solid rgba(107, 114, 128, 0.3);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
[data-theme="light"] .btn.primary {
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
|
||||
color: #ffffff;
|
||||
box-shadow: 0 4px 12px rgba(5, 150, 105, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="light"] .btn.accent {
|
||||
background: var(--accent-soft);
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
[data-theme="light"] .btn.accent:hover {
|
||||
background: rgba(5, 150, 105, 0.2);
|
||||
}
|
||||
|
||||
[data-theme="light"] .btn.ghost {
|
||||
background: transparent;
|
||||
color: var(--text-main);
|
||||
border: 1px solid rgba(107, 114, 128, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="light"] .btn.ghost:hover {
|
||||
background: rgba(107, 114, 128, 0.1);
|
||||
}
|
||||
|
||||
[data-theme="light"] .btn.danger {
|
||||
background: rgba(220, 38, 38, 0.12);
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
[data-theme="light"] .btn.danger:hover {
|
||||
background: rgba(220, 38, 38, 0.2);
|
||||
}
|
||||
|
||||
[data-theme="light"] input,
|
||||
[data-theme="light"] select {
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(107, 114, 128, 0.3);
|
||||
background: #d4cfcf;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
[data-theme="light"] input::placeholder {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
[data-theme="light"] option {
|
||||
background: #ffffff;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
[data-theme="light"] .panel {
|
||||
background: var(--card);
|
||||
border: 1px solid rgba(107, 114, 128, 0.2);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
[data-theme="light"] .modal {
|
||||
background: var(--card);
|
||||
border: 1px solid rgba(107, 114, 128, 0.2);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
[data-theme="light"] .drawer {
|
||||
background: #ffffff;
|
||||
border-left: 1px solid rgba(107, 114, 128, 0.2);
|
||||
box-shadow: -4px 0 15px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
[data-theme="light"] .error-banner {
|
||||
background: rgba(220, 38, 38, 0.08);
|
||||
border: 1px solid rgba(248, 113, 113, 0.5);
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
[data-theme="light"] .pill {
|
||||
background: rgba(107, 114, 128, 0.1);
|
||||
border: 1px solid rgba(107, 114, 128, 0.3);
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
[data-theme="light"] .tag {
|
||||
background: rgba(107, 114, 128, 0.1);
|
||||
border: 1px solid rgba(107, 114, 128, 0.3);
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import RecipeDetails from "./components/RecipeDetails";
|
||||
import RecipeFormDrawer from "./components/RecipeFormDrawer";
|
||||
import Modal from "./components/Modal";
|
||||
import ToastContainer from "./components/ToastContainer";
|
||||
import ThemeToggle from "./components/ThemeToggle";
|
||||
import { getRecipes, getRandomRecipe, createRecipe, updateRecipe, deleteRecipe } from "./api";
|
||||
|
||||
function App() {
|
||||
@ -25,11 +26,25 @@ function App() {
|
||||
|
||||
const [deleteModal, setDeleteModal] = useState({ isOpen: false, recipeId: null, recipeName: "" });
|
||||
const [toasts, setToasts] = useState([]);
|
||||
const [theme, setTheme] = useState(() => {
|
||||
try {
|
||||
return localStorage.getItem("theme") || "dark";
|
||||
} catch {
|
||||
return "dark";
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
loadRecipes();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
try {
|
||||
localStorage.setItem("theme", theme);
|
||||
} catch {}
|
||||
}, [theme]);
|
||||
|
||||
const loadRecipes = async () => {
|
||||
try {
|
||||
const list = await getRecipes();
|
||||
@ -147,6 +162,7 @@ function App() {
|
||||
|
||||
return (
|
||||
<div className="app-root">
|
||||
<ThemeToggle theme={theme} onToggleTheme={() => setTheme((t) => (t === "dark" ? "light" : "dark"))} />
|
||||
<TopBar onAddClick={() => setDrawerOpen(true)} />
|
||||
|
||||
<main className="layout">
|
||||
@ -210,7 +226,6 @@ function App() {
|
||||
<RecipeDetails
|
||||
recipe={selectedRecipe}
|
||||
onEditClick={handleEditRecipe}
|
||||
onDeleteClick={handleShowDeleteModal}
|
||||
onShowDeleteModal={handleShowDeleteModal}
|
||||
/>
|
||||
</section>
|
||||
|
||||
@ -16,7 +16,7 @@ function RecipeDetails({ recipe, onEditClick, onDeleteClick, onShowDeleteModal }
|
||||
<header className="recipe-header">
|
||||
<div>
|
||||
<h2>{recipe.name}</h2>
|
||||
<p className="recipe-subtitle">qwwa
|
||||
<p className="recipe-subtitle">
|
||||
{translateMealType(recipe.meal_type)} · {recipe.time_minutes} דקות הכנה
|
||||
</p>
|
||||
</div>
|
||||
|
||||
14
frontend/src/components/ThemeToggle.jsx
Normal file
14
frontend/src/components/ThemeToggle.jsx
Normal file
@ -0,0 +1,14 @@
|
||||
function ThemeToggle({ theme, onToggleTheme }) {
|
||||
return (
|
||||
<button
|
||||
className="theme-toggle"
|
||||
title={theme === "dark" ? "הפעל מצב בהיר" : "הפעל מצב חשוך"}
|
||||
onClick={onToggleTheme}
|
||||
aria-label="Toggle theme"
|
||||
>
|
||||
{theme === "dark" ? "🌤" : "🌙"}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default ThemeToggle;
|
||||
@ -11,9 +11,11 @@ function TopBar({ onAddClick }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", gap: "0.6rem", alignItems: "center" }}>
|
||||
<button className="btn primary" onClick={onAddClick}>
|
||||
+ מתכון חדש
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user