added some changes in Detail and accueil, added space between
This commit is contained in:
+144
-141
@@ -1,184 +1,187 @@
|
||||
.counter {
|
||||
font-size: 16px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
color: var(--accent);
|
||||
background: var(--accent-bg);
|
||||
border: 2px solid transparent;
|
||||
transition: border-color 0.3s;
|
||||
margin-bottom: 24px;
|
||||
font-size: 16px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
color: var(--accent);
|
||||
background: var(--accent-bg);
|
||||
border: 2px solid transparent;
|
||||
transition: border-color 0.3s;
|
||||
margin-bottom: 24px;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--accent-border);
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
&:hover {
|
||||
border-color: var(--accent-border);
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
|
||||
.base,
|
||||
.framework,
|
||||
.vite {
|
||||
inset-inline: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.base {
|
||||
width: 170px;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.framework,
|
||||
.vite {
|
||||
position: absolute;
|
||||
}
|
||||
.base,
|
||||
.framework,
|
||||
.vite {
|
||||
inset-inline: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.framework {
|
||||
z-index: 1;
|
||||
top: 34px;
|
||||
height: 28px;
|
||||
transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
|
||||
scale(1.4);
|
||||
}
|
||||
.base {
|
||||
width: 170px;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.vite {
|
||||
z-index: 0;
|
||||
top: 107px;
|
||||
height: 26px;
|
||||
width: auto;
|
||||
transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
|
||||
scale(0.8);
|
||||
}
|
||||
.framework,
|
||||
.vite {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.framework {
|
||||
z-index: 1;
|
||||
top: 34px;
|
||||
height: 28px;
|
||||
transform: perspective(2000px) rotateZ(300deg) rotateX(44deg)
|
||||
rotateY(39deg) scale(1.4);
|
||||
}
|
||||
|
||||
.vite {
|
||||
z-index: 0;
|
||||
top: 107px;
|
||||
height: 26px;
|
||||
width: auto;
|
||||
transform: perspective(2000px) rotateZ(300deg) rotateX(40deg)
|
||||
rotateY(39deg) scale(0.8);
|
||||
}
|
||||
}
|
||||
|
||||
#center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 25px;
|
||||
place-content: center;
|
||||
place-items: center;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 25px;
|
||||
place-content: center;
|
||||
place-items: center;
|
||||
flex-grow: 1;
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
padding: 32px 20px 24px;
|
||||
gap: 18px;
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
padding: 32px 20px 24px;
|
||||
gap: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
#next-steps {
|
||||
display: flex;
|
||||
border-top: 1px solid var(--border);
|
||||
text-align: left;
|
||||
display: flex;
|
||||
border-top: 1px solid var(--border);
|
||||
text-align: left;
|
||||
|
||||
& > div {
|
||||
flex: 1 1 0;
|
||||
padding: 32px;
|
||||
@media (max-width: 1024px) {
|
||||
padding: 24px 20px;
|
||||
& > div {
|
||||
flex: 1 1 0;
|
||||
padding: 32px;
|
||||
@media (max-width: 1024px) {
|
||||
padding: 24px 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-bottom: 16px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
.icon {
|
||||
margin-bottom: 16px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
#docs {
|
||||
border-right: 1px solid var(--border);
|
||||
border-right: 1px solid var(--border);
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
}
|
||||
|
||||
#next-steps ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin: 32px 0 0;
|
||||
|
||||
.logo {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--text-h);
|
||||
font-size: 16px;
|
||||
border-radius: 6px;
|
||||
background: var(--social-bg);
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
padding: 6px 12px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
text-decoration: none;
|
||||
transition: box-shadow 0.3s;
|
||||
margin: 32px 0 0;
|
||||
|
||||
&:hover {
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.button-icon {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
margin-top: 20px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
li {
|
||||
flex: 1 1 calc(50% - 8px);
|
||||
.logo {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
a {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
color: var(--text-h);
|
||||
font-size: 16px;
|
||||
border-radius: 6px;
|
||||
background: var(--social-bg);
|
||||
display: flex;
|
||||
padding: 6px 12px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
text-decoration: none;
|
||||
transition: box-shadow 0.3s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.button-icon {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
margin-top: 20px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
||||
li {
|
||||
flex: 1 1 calc(50% - 8px);
|
||||
}
|
||||
|
||||
a {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#spacer {
|
||||
height: 88px;
|
||||
border-top: 1px solid var(--border);
|
||||
@media (max-width: 1024px) {
|
||||
.spacer {
|
||||
height: 48px;
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.smallgap {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.ticks {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -4.5px;
|
||||
border: 5px solid transparent;
|
||||
}
|
||||
&::before,
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -4.5px;
|
||||
border: 5px solid transparent;
|
||||
}
|
||||
|
||||
&::before {
|
||||
left: 0;
|
||||
border-left-color: var(--border);
|
||||
}
|
||||
&::after {
|
||||
right: 0;
|
||||
border-right-color: var(--border);
|
||||
}
|
||||
&::before {
|
||||
left: 0;
|
||||
border-left-color: var(--border);
|
||||
}
|
||||
&::after {
|
||||
right: 0;
|
||||
border-right-color: var(--border);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,46 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Routes, Route } from "react-router-dom";
|
||||
import Header from "./components/Header";
|
||||
import Footer from "./components/Footer";
|
||||
import { Routes, Route } from "react-router-dom";
|
||||
import Accueil from "./pages/Accueil";
|
||||
import Detail from "./pages/Detail";
|
||||
import "./App.css";
|
||||
|
||||
function App() {
|
||||
const [jeux, setJeux] = useState([]);
|
||||
const [likes, setLikes] = useState(() =>
|
||||
JSON.parse(localStorage.getItem("likes") || "{}"),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/zelda.json")
|
||||
.then((r) => r.json())
|
||||
.then(setJeux);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem("likes", JSON.stringify(likes));
|
||||
}, [likes]);
|
||||
|
||||
function liker(id) {
|
||||
setLikes((prev) => ({ ...prev, [id]: (prev[id] || 0) + 1 }));
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<Routes>
|
||||
<Route path="/" element={<Accueil />} />
|
||||
<Route path="/jeu/:id" element={<Detail />} />
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<Accueil
|
||||
jeux={jeux}
|
||||
setJeux={setJeux}
|
||||
likes={likes}
|
||||
onLike={liker}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route path="/jeu/:id" element={<Detail jeux={jeux} likes={likes} />} />
|
||||
</Routes>
|
||||
<Footer />
|
||||
</>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
function Carte(props) {
|
||||
console.log(props.gameId);
|
||||
const [likes, setLikes] = useState(
|
||||
() => Number(localStorage.getItem("likes-" + props.gameId)) || 0,
|
||||
);
|
||||
@@ -27,6 +26,7 @@ function Carte(props) {
|
||||
>
|
||||
❤️ {likes}
|
||||
</button>
|
||||
<section className="smallgap"></section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import Carte from "../components/Carte";
|
||||
import BarreRecherche from "../components/BarreRecherche";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
|
||||
function Accueil() {
|
||||
function Accueil({ jeux, setJeux, likes, onLike }) {
|
||||
const [recherche, setRecherche] = useState("");
|
||||
const [total, setTotal] = useState(0);
|
||||
const [jeux, setJeux] = useState([]);
|
||||
const [chargement, setChargement] = useState(true);
|
||||
const [total] = useState(0);
|
||||
const [titre, setTitre] = useState("");
|
||||
const [annee, setAnnee] = useState("");
|
||||
const [plateforme, setPlateforme] = useState("");
|
||||
const [tri, setTri] = useState("titre");
|
||||
const medailles = ["🥇", "🥈", "🥉"];
|
||||
const [filtreType, setFiltreType] = useState("tous");
|
||||
|
||||
const top = [...jeux]
|
||||
.sort((a, b) => (likes[b.id] || 0) - (likes[a.id] || 0))
|
||||
.slice(0, 3);
|
||||
|
||||
function ajouter(e) {
|
||||
e.preventDefault();
|
||||
@@ -30,50 +34,62 @@ function Accueil() {
|
||||
|
||||
const affiches = [...jeux]
|
||||
.filter((j) => j.titre.toLowerCase().includes(recherche.toLowerCase()))
|
||||
.filter((j) => filtreType === "tous" || j.Type === filtreType)
|
||||
.sort((a, b) => {
|
||||
if (tri === "titre") return a.titre.localeCompare(b.titre);
|
||||
if (tri === "annee") return a.annee - b.annee;
|
||||
return 0;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/zelda.json")
|
||||
.then((r) => r.json())
|
||||
.then((data) => {
|
||||
setJeux(data);
|
||||
document.title = `${data.length} jeux Zelda`;
|
||||
setChargement(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
if (chargement) return <p>Chargement…</p>;
|
||||
return (
|
||||
<>
|
||||
<BarreRecherche
|
||||
valeur={recherche}
|
||||
onChange={(e) => setRecherche(e.target.value)}
|
||||
/>
|
||||
<select value={tri} onChange={(e) => setTri(e.target.value)}>
|
||||
<option value="titre">Titre (A→Z)</option>
|
||||
<option value="annee">Année</option>
|
||||
</select>
|
||||
<div>
|
||||
<BarreRecherche
|
||||
valeur={recherche}
|
||||
onChange={(e) => setRecherche(e.target.value)}
|
||||
/>
|
||||
<select value={tri} onChange={(e) => setTri(e.target.value)}>
|
||||
<option value="titre">Titre (A→Z)</option>
|
||||
<option value="annee">Année</option>
|
||||
</select>
|
||||
<button onClick={() => setFiltreType("tous")}>Tous</button>
|
||||
<button onClick={() => setFiltreType("2d")}>2D</button>
|
||||
<button onClick={() => setFiltreType("3d")}>3D</button>
|
||||
</div>
|
||||
|
||||
{affiches.length === 0 && <p>Aucun jeu trouvé 😕</p>}
|
||||
|
||||
<section class="spacer"></section>
|
||||
|
||||
<div className="hall">
|
||||
{top.map((j, index) => (
|
||||
<p key={j.id}>
|
||||
{medailles[index]} {j.titre} — {likes[j.id] || 0} ❤️
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<section class="spacer"></section>
|
||||
|
||||
{affiches.map((jeu) => (
|
||||
<Carte
|
||||
key={jeu.id}
|
||||
gameId={jeu.id}
|
||||
titre={jeu.titre}
|
||||
console={jeu.console}
|
||||
console={jeu.plateforme}
|
||||
annee={jeu.annee}
|
||||
Type={jeu.Type}
|
||||
onLike={() => setTotal((t) => t + 1)}
|
||||
likes={likes[jeu.id] || 0}
|
||||
onLike={() => onLike(jeu.id)}
|
||||
/>
|
||||
))}
|
||||
|
||||
<section class="spacer"></section>
|
||||
|
||||
<p> Total de likes : {total}</p>
|
||||
|
||||
<section class="spacer"></section>
|
||||
|
||||
<form onSubmit={ajouter}>
|
||||
<input
|
||||
value={titre}
|
||||
@@ -91,7 +107,7 @@ function Accueil() {
|
||||
placeholder="Console"
|
||||
/>
|
||||
<button type="submit">Ajouter</button>
|
||||
<section id="spacer"></section>
|
||||
<section class="spacer"></section>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useParams, Link } from "react-router-dom";
|
||||
|
||||
function Detail() {
|
||||
function Detail({ jeux, likes }) {
|
||||
const { id } = useParams();
|
||||
return <h1>Détails du jeu {id}</h1>;
|
||||
const jeu = jeux.find((j) => String(j.id) === id);
|
||||
if (!jeu)
|
||||
return (
|
||||
<p>
|
||||
Introuvable — <Link to="/">retour</Link>
|
||||
</p>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="detail">
|
||||
<Link to="/">← Retour</Link>
|
||||
<h1>{jeu.titre}</h1>
|
||||
<p>
|
||||
{jeu.console} — {jeu.annee} — {jeu.Type}
|
||||
</p>
|
||||
<p>❤️ Likes : {likes[jeu.id] || 0}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Detail;
|
||||
|
||||
Reference in New Issue
Block a user