Skip to content
Snippets Groups Projects
Commit 68871889 authored by Kevin Portable's avatar Kevin Portable
Browse files

Ajout de la fonctionnalité thème light/dark, modification du design des page de :

login
signup
dashboard
navbar
parent d0d10a67
No related branches found
No related tags found
No related merge requests found
@import "tailwindcss"; @import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
...@@ -5,13 +5,15 @@ import Home from "@pages/Home"; ...@@ -5,13 +5,15 @@ import Home from "@pages/Home";
import "./App.css"; import "./App.css";
import Todolist from "@pages/Todolist"; import Todolist from "@pages/Todolist";
import { TasksProvider } from "@context/TasksContext"; import { TasksProvider } from "@context/TasksContext";
import { ThemeProvider } from "@context/ThemeContext";
import Navbar from "@components/Navbar.jsx"; import Navbar from "@components/Navbar.jsx";
function App() { function App() {
return ( return (
<ThemeProvider>
<TasksProvider> <TasksProvider>
<Router> <Router>
<div className="min-h-screen bg-gray-50"> <div className="min-h-screen bg-gray-50 dark:bg-gray-900">
<Navbar /> <Navbar />
<main className="pt-4"> <main className="pt-4">
<Routes> <Routes>
...@@ -24,6 +26,7 @@ function App() { ...@@ -24,6 +26,7 @@ function App() {
</div> </div>
</Router> </Router>
</TasksProvider> </TasksProvider>
</ThemeProvider>
); );
} }
......
...@@ -19,24 +19,24 @@ const Calendar = () => { ...@@ -19,24 +19,24 @@ const Calendar = () => {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="bg-violet-100 rounded-2xl p-6"> <div className="bg-violet-100 dark:bg-gray-800 rounded-2xl p-6 shadow-lg transition-all">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-violet-900"> <h2 className="text-lg font-semibold text-violet-900 dark:text-white">
{format(currentDate, 'MMMM yyyy', { locale: enUS })} {format(currentDate, 'MMMM yyyy', { locale: enUS })}
</h2> </h2>
<div className="flex gap-2"> <div className="flex gap-2">
<button onClick={prevMonth} className="p-1 hover:bg-violet-200 rounded"> <button onClick={prevMonth} className="p-1 hover:bg-violet-200 dark:hover:bg-gray-700 rounded transition">
<ChevronLeft className="w-5 h-5 text-violet-700" /> <ChevronLeft className="w-5 h-5 text-violet-700 dark:text-white" />
</button> </button>
<button onClick={nextMonth} className="p-1 hover:bg-violet-200 rounded"> <button onClick={nextMonth} className="p-1 hover:bg-violet-200 dark:hover:bg-gray-700 rounded transition">
<ChevronRight className="w-5 h-5 text-violet-700" /> <ChevronRight className="w-5 h-5 text-violet-700 dark:text-white" />
</button> </button>
</div> </div>
</div> </div>
<div className="grid grid-cols-7 gap-2 text-center mb-2"> <div className="grid grid-cols-7 gap-2 text-center mb-2">
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => ( {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => (
<div key={day} className="text-sm font-medium text-violet-800"> <div key={day} className="text-sm font-medium text-violet-800 dark:text-gray-300">
{day} {day}
</div> </div>
))} ))}
...@@ -55,10 +55,10 @@ const Calendar = () => { ...@@ -55,10 +55,10 @@ const Calendar = () => {
key={day.toString()} key={day.toString()}
onClick={() => setSelectedDate(day)} onClick={() => setSelectedDate(day)}
className={` className={`
p-2 rounded-full text-sm p-2 rounded-full text-sm transition
${isSelected ${isSelected
? 'bg-violet-500 text-white' ? 'bg-violet-500 text-white dark:bg-violet-400'
: 'text-violet-800 hover:bg-violet-100' : 'text-violet-800 dark:text-gray-300 hover:bg-violet-100 dark:hover:bg-gray-700'
} }
`} `}
> >
......
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { CheckCircle } from "lucide-react"; import { CheckCircle, Sun, Moon } from "lucide-react";
import { useTheme } from "@context/ThemeContext";
const Navbar = () => { const Navbar = () => {
const [isAuthenticated, setIsAuthenticated] = useState(!!localStorage.getItem("user")); const [isAuthenticated, setIsAuthenticated] = useState(!!localStorage.getItem("user"));
const navigate = useNavigate(); const navigate = useNavigate();
const { theme, toggleTheme } = useTheme();
useEffect(() => { useEffect(() => {
// Écouter les changements sur `localStorage` // Écouter les changements sur `localStorage`
...@@ -28,29 +30,35 @@ const Navbar = () => { ...@@ -28,29 +30,35 @@ const Navbar = () => {
}; };
return ( return (
<nav className="bg-white shadow-md"> <nav className="bg-white dark:bg-gray-900 shadow-md transition-colors">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16"> <div className="flex justify-between h-16">
<div className="flex items-center"> <div className="flex items-center">
<Link to="/" className="flex items-center gap-2"> <Link to="/" className="flex items-center gap-2">
<CheckCircle className="h-8 w-8 text-violet-600" /> <CheckCircle className="h-8 w-8 text-violet-600 dark:text-violet-400" />
<span className="text-xl font-semibold text-gray-900">TaskMaster</span> <span className="text-xl font-semibold text-gray-900 dark:text-white">TaskMaster</span>
</Link> </Link>
</div> </div>
<div className="flex items-center gap-6"> <div className="flex items-center gap-6">
<Link <Link
to="/" to="/"
className="text-gray-700 hover:text-violet-600 px-3 py-2 rounded-md text-sm font-medium" className="text-gray-700 dark:text-white hover:text-violet-600 dark:hover:text-violet-400 px-3 py-2 rounded-md text-sm font-medium"
> >
Dashboard Dashboard
</Link> </Link>
<Link <Link
to="/todolist" to="/todolist"
className="text-gray-700 hover:text-violet-600 px-3 py-2 rounded-md text-sm font-medium" className="text-gray-700 dark:text-white hover:text-violet-600 dark:hover:text-violet-400 px-3 py-2 rounded-md text-sm font-medium"
> >
Tasks List Tasks List
</Link> </Link>
{/* Bouton Light/Dark Mode */}
<button onClick={toggleTheme} className="p-2 rounded-md bg-gray-200 dark:bg-gray-700">
{theme === "light" ? <Moon className="h-5 w-5 text-gray-700" /> : <Sun className="h-5 w-5 text-yellow-400" />}
</button>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{isAuthenticated ? ( {isAuthenticated ? (
// Bouton Logout si l'utilisateur est connecté // Bouton Logout si l'utilisateur est connecté
...@@ -65,7 +73,7 @@ const Navbar = () => { ...@@ -65,7 +73,7 @@ const Navbar = () => {
<> <>
<Link <Link
to="/signin" to="/signin"
className="text-gray-700 hover:text-violet-600 px-3 py-2 rounded-md text-sm font-medium" className="text-gray-700 dark:text-white hover:text-violet-600 dark:hover:text-violet-400 px-3 py-2 rounded-md text-sm font-medium"
> >
Login Login
</Link> </Link>
......
...@@ -2,13 +2,13 @@ import React from "react"; ...@@ -2,13 +2,13 @@ import React from "react";
const TaskCard = ({ title, count }) => { const TaskCard = ({ title, count }) => {
return ( return (
<div className="bg-white rounded-lg p-4 shadow-sm border border-gray-100 min-w-[200px]"> <div className="bg-white dark:bg-gray-800 rounded-lg p-4 shadow-sm border border-gray-100 dark:border-gray-700 min-w-[200px]">
<div className="flex justify-between items-center mb-4"> <div className="flex justify-between items-center mb-4">
<h3 className="text-sm text-gray-600">{title}</h3> <h3 className="text-sm text-gray-600 dark:text-gray-300">{title}</h3>
</div> </div>
<div className="flex items-baseline gap-1"> <div className="flex items-baseline gap-1">
<span className="text-2xl font-semibold">{count}</span> <span className="text-2xl font-semibold text-gray-900 dark:text-white">{count}</span>
<span className="text-xs text-gray-500">Task count</span> <span className="text-xs text-gray-500 dark:text-gray-400">Task count</span>
</div> </div>
</div> </div>
); );
......
import React, { useContext } from "react"; import React from "react";
import TaskCard from "@components/dashboard/TaskCard"; import TaskCard from "@components/dashboard/TaskCard";
import { useTasks } from "@context/TasksContext"; import { useTasks } from "@context/TasksContext";
......
import React, { useContext } from "react"; import React from "react";
import { useTasks } from "@context/TasksContext"; import { useTasks } from "@context/TasksContext";
const TasksStatPercent = () => { const TasksStatPercent = () => {
...@@ -14,7 +14,7 @@ const TasksStatPercent = () => { ...@@ -14,7 +14,7 @@ const TasksStatPercent = () => {
return ( return (
<div> <div>
<h2 className="text-xl font-semibold mb-4"> All Tasks completion status</h2> <h2 className="text-xl font-semibold mb-4 dark:text-white">All Tasks completion status</h2>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="relative"> <div className="relative">
<svg width="120" height="120" className="transform -rotate-90"> <svg width="120" height="120" className="transform -rotate-90">
...@@ -35,24 +35,25 @@ const TasksStatPercent = () => { ...@@ -35,24 +35,25 @@ const TasksStatPercent = () => {
fill="none" fill="none"
strokeDasharray={circumference} strokeDasharray={circumference}
strokeDashoffset={strokeDashoffset} strokeDashoffset={strokeDashoffset}
className="dark:stroke-purple-400"
style={{ style={{
transition: 'stroke-dashoffset 0.5s ease' transition: 'stroke-dashoffset 0.5s ease'
}} }}
/> />
</svg> </svg>
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"> <div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<div className="text-2xl font-bold">{totalTasks}</div> <div className="text-2xl font-bold dark:text-white">{totalTasks}</div>
<div className="text-sm text-gray-500">Total</div> <div className="text-sm text-gray-500 dark:text-gray-400">Total</div>
</div> </div>
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<div className="bg-white p-3 rounded-lg shadow-sm border border-gray-100"> <div className="bg-white dark:bg-gray-800 p-3 rounded-lg shadow-sm border border-gray-100 dark:border-gray-700">
<div className="text-2xl font-bold text-violet-700">{completedPercentage}%</div> <div className="text-2xl font-bold text-violet-700 dark:text-violet-400">{completedPercentage}%</div>
<div className="text-sm text-gray-600">Completed</div> <div className="text-sm text-gray-600 dark:text-gray-300">Completed</div>
</div> </div>
<div className="bg-white p-3 rounded-lg shadow-sm border border-gray-100"> <div className="bg-white dark:bg-gray-800 p-3 rounded-lg shadow-sm border border-gray-100 dark:border-gray-700">
<div className="text-2xl font-bold text-violet-400">{100 - completedPercentage}%</div> <div className="text-2xl font-bold text-violet-400">{100 - completedPercentage}%</div>
<div className="text-sm text-gray-600">Uncompleted</div> <div className="text-sm text-gray-600 dark:text-gray-300">Uncompleted</div>
</div> </div>
</div> </div>
</div> </div>
......
import { createContext, useContext, useEffect, useState } from "react";
const ThemeContext = createContext();
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState(() => {
return localStorage.getItem("theme") || "light";
});
useEffect(() => {
document.documentElement.classList.toggle("dark", theme === "dark");
localStorage.setItem("theme", theme);
}, [theme]);
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
const useTheme = () => useContext(ThemeContext);
export { ThemeProvider, useTheme };
...@@ -7,28 +7,23 @@ const Home = () => { ...@@ -7,28 +7,23 @@ const Home = () => {
const navigate = useNavigate(); const navigate = useNavigate();
return ( return (
<div> <div>
<div className="p-6 bg-gray"> <div className="p-6 bg-gray-50 dark:bg-gray-900">
<TaskStats /> <TaskStats />
</div> </div>
<div className="min-h-screen bg-gray-100 p-8"> <div className="min-h-screen bg-gray-100 dark:bg-gray-800 p-8">
<div className="grid grid-cols-2 gap-6"> <div className="grid grid-cols-2 gap-6">
<div className="bg-white rounded-lg shadow-md p-6 min-h-[300px]"> <div className="bg-white dark:bg-gray-700 rounded-lg shadow-md p-6 min-h-[300px]">
</div> </div>
<div className="bg-white dark:bg-gray-700 rounded-lg shadow-md p-6 min-h-[300px]">
<div className="bg-white rounded-lg shadow-md p-6 min-h-[300px]">
<Calendar /> <Calendar />
</div> </div>
<div className="bg-white dark:bg-gray-700 rounded-lg shadow-md p-6 min-h-[300px]">
<div className="bg-white rounded-lg shadow-md p-6 min-h-[300px]">
</div> </div>
<div className="bg-white dark:bg-gray-700 rounded-lg shadow-md p-6 min-h-[300px]">
<div className="bg-white rounded-lg shadow-md p-6 min-h-[300px]">
<TasksStatPercent/> <TasksStatPercent/>
</div> </div>
......
...@@ -23,40 +23,50 @@ const SignIn = () => { ...@@ -23,40 +23,50 @@ const SignIn = () => {
}; };
return ( return (
<div className="flex min-h-screen items-center justify-center bg-gray-100"> <div className="flex min-h-screen items-center justify-center bg-gray-100 dark:bg-gray-900 transition-colors">
<div className="w-full max-w-md p-6 bg-white rounded-lg shadow-md"> <div className="w-full max-w-md p-6 bg-white dark:bg-gray-800 rounded-lg shadow-md transition-all">
<h2 className="text-2xl font-semibold text-center mb-6">Login to your to-do list</h2> <h2 className="text-2xl font-semibold text-center mb-6 text-gray-900 dark:text-white">
Login to your to-do list
</h2>
{error && <p className="text-red-500 text-sm text-center mb-4">{error}</p>} {error && <p className="text-red-500 text-sm text-center mb-4">{error}</p>}
<div className="border-b mb-4"></div> <div className="border-b mb-4 border-gray-300 dark:border-gray-600"></div>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="mb-4"> <div className="mb-4">
<label className="block text-gray-700">Email</label> <label className="block text-gray-700 dark:text-gray-300">Email</label>
<input <input
type="email" type="email"
className="w-full px-4 py-2 border rounded-lg" className="w-full px-4 py-2 border rounded-lg bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring focus:border-violet-500 dark:focus:border-violet-400"
value={email} value={email}
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
/> />
</div> </div>
<div className="mb-4"> <div className="mb-4">
<label className="block text-gray-700">Password</label> <label className="block text-gray-700 dark:text-gray-300">Password</label>
<input <input
type="password" type="password"
className="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring focus:border-blue-300" className="w-full px-4 py-2 border rounded-lg bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring focus:border-violet-500 dark:focus:border-violet-400"
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
/> />
<div className="text-right text-sm text-blue-600 cursor-pointer">Forgot?</div> <div className="text-right text-sm text-blue-600 dark:text-blue-400 cursor-pointer">
Forgot?
</div>
</div> </div>
<button type="submit" className="w-full bg-violet-600 text-white hover:bg-violet-700 py-2 rounded-lg">Login</button> <button
type="submit"
className="w-full bg-violet-600 dark:bg-violet-700 text-white hover:bg-violet-700 dark:hover:bg-violet-600 py-2 rounded-lg transition">
Login
</button>
</form> </form>
<p className="mt-4 text-center text-sm">
Don't have an account? <Link to="/signup" className="text-blue-600">Sign up</Link> <p className="mt-4 text-center text-sm text-gray-600 dark:text-gray-300">
Don't have an account?
<Link to="/signup" className="text-blue-600 dark:text-blue-400 ml-1">Sign up</Link>
</p> </p>
</div> </div>
</div> </div>
......
...@@ -3,7 +3,6 @@ import { useNavigate } from "react-router-dom"; ...@@ -3,7 +3,6 @@ import { useNavigate } from "react-router-dom";
import { signUp } from "../services/auth"; import { signUp } from "../services/auth";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
const SignUp = () => { const SignUp = () => {
const [name, setName] = useState(""); const [name, setName] = useState("");
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
...@@ -23,49 +22,57 @@ const SignUp = () => { ...@@ -23,49 +22,57 @@ const SignUp = () => {
}; };
return ( return (
<div className="flex min-h-screen items-center justify-center bg-gray-100"> <div className="flex min-h-screen items-center justify-center bg-gray-100 dark:bg-gray-900 transition-colors">
<div className="w-full max-w-md p-6 bg-white rounded-lg shadow-md"> <div className="w-full max-w-md p-6 bg-white dark:bg-gray-800 rounded-lg shadow-md transition-all">
<h2 className="text-2xl font-semibold text-center mb-6">Sign up to your to-do list</h2> <h2 className="text-2xl font-semibold text-center mb-6 text-gray-900 dark:text-white">
Sign up to your to-do list
</h2>
{error && <p className="text-red-500 text-sm text-center mb-4">{error}</p>} {error && <p className="text-red-500 text-sm text-center mb-4">{error}</p>}
<div className="border-b mb-4"></div> <div className="border-b mb-4 border-gray-300 dark:border-gray-600"></div>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<div className="mb-4"> <div className="mb-4">
<label className="block text-gray-700">Name</label> <label className="block text-gray-700 dark:text-gray-300">Name</label>
<input <input
type="text" type="text"
className="w-full px-4 py-2 border rounded-lg" className="w-full px-4 py-2 border rounded-lg bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring focus:border-violet-500 dark:focus:border-violet-400"
value={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
/> />
</div> </div>
<div className="mb-4"> <div className="mb-4">
<label className="block text-gray-700">Email</label> <label className="block text-gray-700 dark:text-gray-300">Email</label>
<input <input
type="email" type="email"
className="w-full px-4 py-2 border rounded-lg" className="w-full px-4 py-2 border rounded-lg bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring focus:border-violet-500 dark:focus:border-violet-400"
value={email} value={email}
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
/> />
</div> </div>
<div className="mb-4"> <div className="mb-4">
<label className="block text-gray-700">Password</label> <label className="block text-gray-700 dark:text-gray-300">Password</label>
<input <input
type="password" type="password"
className="w-full px-4 py-2 border rounded-lg" className="w-full px-4 py-2 border rounded-lg bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring focus:border-violet-500 dark:focus:border-violet-400"
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
/> />
</div> </div>
<button type="submit" className="w-full bg-violet-600 text-white hover:bg-violet-700 py-2 rounded-lg">Sign up</button> <button
type="submit"
className="w-full bg-violet-600 dark:bg-violet-700 text-white hover:bg-violet-700 dark:hover:bg-violet-600 py-2 rounded-lg transition">
Sign up
</button>
</form> </form>
<p className="mt-4 text-center text-sm">
Already have an account? <Link to="/signin" className="text-blue-600">Sign in</Link> <p className="mt-4 text-center text-sm text-gray-600 dark:text-gray-300">
Already have an account?
<Link to="/signin" className="text-blue-600 dark:text-blue-400 ml-1">Sign in</Link>
</p> </p>
</div> </div>
</div> </div>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment