feat: initial import — ClickerZ formation project (Express + React/Vite)
This commit is contained in:
28
Frontend/src/components/AchievementsCard.jsx
Executable file
28
Frontend/src/components/AchievementsCard.jsx
Executable file
@@ -0,0 +1,28 @@
|
||||
import "../scss/components/achievementscard.scss";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
function AchievementsCard({ name, description, image, key }) {
|
||||
AchievementsCard.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
image: PropTypes.string.isRequired,
|
||||
key: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="achievCardcontainer">
|
||||
<img
|
||||
className="achievecardpicture"
|
||||
key={key}
|
||||
src={image}
|
||||
alt="cartes speciales"
|
||||
/>
|
||||
<div className="achievetitle">
|
||||
<p className="achievname">{name}</p>
|
||||
<p className="achievdescription">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AchievementsCard;
|
||||
130
Frontend/src/components/BoutiqueCard.jsx
Executable file
130
Frontend/src/components/BoutiqueCard.jsx
Executable file
@@ -0,0 +1,130 @@
|
||||
import { useWildCoin } from "./WildCoin/WildCoinContext";
|
||||
import "../scss/components/boutiquecard.scss";
|
||||
import "../scss/components/buttons.scss";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export default function BoutiqueCard({
|
||||
name,
|
||||
price,
|
||||
incrementValue,
|
||||
description,
|
||||
image,
|
||||
link,
|
||||
type,
|
||||
buyed,
|
||||
}) {
|
||||
BoutiqueCard.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
price: PropTypes.number.isRequired,
|
||||
incrementValue: PropTypes.number.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
image: PropTypes.string.isRequired,
|
||||
link: PropTypes.string.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
buyed: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const {
|
||||
wildCoin,
|
||||
incrementClick,
|
||||
setWildCoin,
|
||||
setIncrementClick,
|
||||
incrementPerSecond,
|
||||
setIncrementPerSecond,
|
||||
setCoffee,
|
||||
setSantaDrunk,
|
||||
setManic,
|
||||
setSnowman,
|
||||
setBonnet,
|
||||
setSugar,
|
||||
setCookie,
|
||||
setCouronne,
|
||||
setEpice,
|
||||
setBiere,
|
||||
} = useWildCoin();
|
||||
|
||||
const acheterAmelioration = (type, price, name) => {
|
||||
const prices = price;
|
||||
const value = prices;
|
||||
|
||||
|
||||
|
||||
if (wildCoin >= value) {
|
||||
if (type === "actif") {
|
||||
setIncrementClick(incrementClick + incrementValue);
|
||||
} else if (type === "passif") {
|
||||
setIncrementPerSecond(incrementPerSecond + incrementValue);
|
||||
}
|
||||
setWildCoin(wildCoin - value);
|
||||
switch (name) {
|
||||
case "Tasse à café":
|
||||
setCoffee((prevCoffee) => [true, prevCoffee[1] + 1]);
|
||||
break;
|
||||
case "Manic":
|
||||
setManic((prevManic) => [true, prevManic[1] + 1]);
|
||||
break;
|
||||
case "Bonnet":
|
||||
setBonnet((prevBonnet) => [true, prevBonnet[1] + 1]);
|
||||
break;
|
||||
case "Mr Bonhomme":
|
||||
setSnowman((prevSnowman) => [true, prevSnowman[1] + 1]);
|
||||
break;
|
||||
case "Canne en sucre":
|
||||
setSugar((prevSugar) => [true, prevSugar[1] + 1]);
|
||||
break;
|
||||
case "Cookie":
|
||||
setCookie((prevCookie) => [true, prevCookie[1] + 1]);
|
||||
break;
|
||||
case "Couronne d'hiver":
|
||||
setCouronne((prevCouronne) => [true, prevCouronne[1] + 1]);
|
||||
break;
|
||||
case "Mr pain d'épice":
|
||||
setEpice((prevEpice) => [true, prevEpice[1] + 1]);
|
||||
break;
|
||||
case "Bière":
|
||||
setBiere((prevBiere) => [true, prevBiere[1] + 1]);
|
||||
setSantaDrunk(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
console.log("Pas assez de WildCoin pour acheter cette amélioration.");
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="shopcardcontainer">
|
||||
<div className="shopcontainer">
|
||||
<div
|
||||
className="cardpicture"
|
||||
style={{ backgroundImage: `url(${image})` }}
|
||||
alt={`image de ${name}`}
|
||||
/>
|
||||
<div>
|
||||
<div className="titlesection">
|
||||
<p className="itemname">{name}</p>
|
||||
<div className="price">
|
||||
<p className="itemprice">{price}</p>
|
||||
|
||||
<div className="priceicon" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="description">
|
||||
<p className="itemdesc">
|
||||
<em>
|
||||
{type} + {incrementValue}
|
||||
</em>
|
||||
</p>
|
||||
<p className="itemdesc">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => acheterAmelioration(type, price, name)}
|
||||
className="primary-button"
|
||||
>
|
||||
Acheter
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
157
Frontend/src/components/Hud/Hud.jsx
Executable file
157
Frontend/src/components/Hud/Hud.jsx
Executable file
@@ -0,0 +1,157 @@
|
||||
import "../../scss/components/Hud.scss";
|
||||
import { useWildCoin } from "../WildCoin/WildCoinContext";
|
||||
import Timer from "../timer/Timer";
|
||||
import propTypes from "prop-types";
|
||||
|
||||
function Hud({ isVisible }) {
|
||||
Hud.propTypes = {
|
||||
isVisible: propTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const {
|
||||
manic,
|
||||
snowman,
|
||||
bonnet,
|
||||
sugar,
|
||||
cookie,
|
||||
couronne,
|
||||
epice,
|
||||
biere,
|
||||
coffee,
|
||||
} = useWildCoin();
|
||||
|
||||
const { incrementClick, incrementPerSecond } = useWildCoin();
|
||||
const hiddenDiv = isVisible ? "none" : null;
|
||||
|
||||
return (
|
||||
<div className="hudContainer">
|
||||
<div style={{ display: hiddenDiv }} className="hudStats">
|
||||
<div className="time section">
|
||||
<p>Temps de jeu</p>
|
||||
<p><Timer /></p>
|
||||
</div>
|
||||
<div className="auto section">
|
||||
<p>Auto CPS</p>
|
||||
<p>{incrementPerSecond}</p>
|
||||
</div>
|
||||
<div className="player section">
|
||||
<p>Player Click</p>
|
||||
<p>{incrementClick}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="hudBooster">
|
||||
{coffee[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/Tasse.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{coffee[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{manic[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/Hand.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{manic[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{snowman[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/Bonhome.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{snowman[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{bonnet[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/Bonnet.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{bonnet[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{sugar[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/Canne.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{sugar[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{cookie[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/Cookie.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{cookie[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{couronne[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/Courone.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{couronne[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{epice[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/PainDep.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{epice[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{biere[0] === true ? (
|
||||
<div className="boosterItem">
|
||||
<div
|
||||
className="boosterIcon"
|
||||
style={{ backgroundImage: `url(/svg/Beer.svg)` }}
|
||||
alt="coffee"
|
||||
/>
|
||||
<div className="countbox">
|
||||
<p className="boosterCount">{biere[1]}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Hud;
|
||||
75
Frontend/src/components/WildCoin/Amelioration.jsx
Executable file
75
Frontend/src/components/WildCoin/Amelioration.jsx
Executable file
@@ -0,0 +1,75 @@
|
||||
import { useWildCoin } from "./WildCoinContext";
|
||||
|
||||
function Ameliorations() {
|
||||
const {
|
||||
wildCoin,
|
||||
incrementClick,
|
||||
setWildCoin,
|
||||
setIncrementClick,
|
||||
incrementPerSecond,
|
||||
setIncrementPerSecond,
|
||||
} = useWildCoin();
|
||||
|
||||
const activePrices = [5, 15, 50, 500]; // prix
|
||||
const passivePrices = [5, 15, 50, 500];
|
||||
const activeIncrementValues = [1, 3, 10, 100]; // boost = incrementValue
|
||||
const passiveIncrementValues = [1, 3, 10, 100]; // = incrementValue
|
||||
|
||||
const acheterAmelioration = (type, amount) => {
|
||||
const prices = type === "actif" ? activePrices : passivePrices;
|
||||
const incrementValues =
|
||||
type === "actif" ? activeIncrementValues : passiveIncrementValues;
|
||||
|
||||
const price = prices[amount - 1];
|
||||
const incrementValue = incrementValues[amount - 1];
|
||||
|
||||
if (wildCoin >= price) {
|
||||
if (type === "actif") {
|
||||
setIncrementClick(incrementClick + incrementValue);
|
||||
} else if (type === "passif") {
|
||||
setIncrementPerSecond(incrementPerSecond + incrementValue);
|
||||
}
|
||||
setWildCoin(wildCoin - price);
|
||||
} else {
|
||||
console.log("Pas assez de WildCoin pour acheter cette amélioration.");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="divMagasinAmelio">
|
||||
<h2>Magasin d'Améliorations</h2>
|
||||
<div className="divAmelioActives">
|
||||
<p>Améliorations Actives :</p>
|
||||
{[1, 2, 3, 4].map((amount) => (
|
||||
<div key={amount}>
|
||||
Price: {activePrices[amount - 1]} - (+
|
||||
{activeIncrementValues[amount - 1]})
|
||||
<button
|
||||
className="amelioActives"
|
||||
onClick={() => acheterAmelioration("actif", amount)}
|
||||
>
|
||||
Acheter
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="divAmelioPassives">
|
||||
<p>Améliorations Passives :</p>
|
||||
{[1, 2, 3, 4].map((amount) => (
|
||||
<div key={amount}>
|
||||
Price: {passivePrices[amount - 1]} - (+
|
||||
{passiveIncrementValues[amount - 1]})
|
||||
<button
|
||||
className="amelioPassives"
|
||||
onClick={() => acheterAmelioration("passif", amount)}
|
||||
>
|
||||
Acheter
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Ameliorations;
|
||||
43
Frontend/src/components/WildCoin/WildCoinContent.jsx
Executable file
43
Frontend/src/components/WildCoin/WildCoinContent.jsx
Executable file
@@ -0,0 +1,43 @@
|
||||
import { createContext, useContext, useState, useEffect } from "react";
|
||||
|
||||
export const WildCoinContext = createContext();
|
||||
|
||||
export const useWildCoin = () => {
|
||||
return useContext(WildCoinContext);
|
||||
};
|
||||
|
||||
export function WildCoinProvider({ children }) {
|
||||
// Value of coin
|
||||
const [wildCoin, setWildCoin] = useState(0);
|
||||
// increment by click state
|
||||
const [incrementClick, setIncrementClick] = useState(1);
|
||||
// increment inner useEffect state
|
||||
const [incrementPerSecond, setIncrementPerSecond] = useState(1);
|
||||
|
||||
const incrementWildCoin = (amount) => {
|
||||
setWildCoin((prevWildCoin) => prevWildCoin + amount);
|
||||
};
|
||||
/**
|
||||
* @passiveGenerationInterval incre per sec wild coin in wildCoin
|
||||
* */
|
||||
useEffect(() => {
|
||||
const passiveGenerationInterval = setInterval(() => {
|
||||
incrementWildCoin(incrementPerSecond);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(passiveGenerationInterval);
|
||||
}, [incrementPerSecond]);
|
||||
|
||||
const value = {
|
||||
wildCoin,
|
||||
setWildCoin,
|
||||
incrementClick,
|
||||
incrementWildCoin,
|
||||
};
|
||||
|
||||
return (
|
||||
<WildCoinContext.Provider value={value}>
|
||||
{children}
|
||||
</WildCoinContext.Provider>
|
||||
);
|
||||
}
|
||||
138
Frontend/src/components/WildCoin/WildCoinContext.jsx
Executable file
138
Frontend/src/components/WildCoin/WildCoinContext.jsx
Executable file
@@ -0,0 +1,138 @@
|
||||
import { createContext, useContext, useState, useEffect } from "react";
|
||||
|
||||
export const WildCoinContext = createContext();
|
||||
export const useWildCoin = () => {
|
||||
return useContext(WildCoinContext);
|
||||
};
|
||||
|
||||
export function WildCoinProvider({ children }) {
|
||||
const initialState = {
|
||||
wildCoin: 0,
|
||||
incrementClick: 1,
|
||||
incrementPerSecond: 0,
|
||||
};
|
||||
|
||||
const [state, setState] = useState(() => {
|
||||
const storedContext = JSON.parse(localStorage.getItem("wildCoinContext"));
|
||||
return {
|
||||
...initialState,
|
||||
...(storedContext || {}),
|
||||
};
|
||||
});
|
||||
|
||||
const [coffee, setCoffee] = useState([false, 0]);
|
||||
const [manic, setManic] = useState([false, 0]);
|
||||
const [snowman, setSnowman] = useState([false, 0]);
|
||||
const [bonnet, setBonnet] = useState([false, 0]);
|
||||
const [sugar, setSugar] = useState([false, 0]);
|
||||
const [cookie, setCookie] = useState([false, 0]);
|
||||
const [couronne, setCouronne] = useState([false, 0]);
|
||||
const [epice, setEpice] = useState([false, 0]);
|
||||
const [biere, setBiere] = useState([false, 0]);
|
||||
|
||||
const [santaDrunk, setSantaDrunk] = useState(false);
|
||||
|
||||
const updateWildCoin = (amount) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
wildCoin: prev.wildCoin + amount,
|
||||
}));
|
||||
};
|
||||
|
||||
const incrementWildCoin = (amount) => {
|
||||
updateWildCoin(amount);
|
||||
};
|
||||
|
||||
const setIncrementClick = (amount) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
incrementClick: amount,
|
||||
}));
|
||||
};
|
||||
|
||||
const setIncrementPerSecond = (amount) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
incrementPerSecond: amount,
|
||||
}));
|
||||
};
|
||||
|
||||
const setWildCoin = (amount) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
wildCoin: amount,
|
||||
}));
|
||||
};
|
||||
|
||||
const [seconds, setSeconds] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
setSeconds((prevSeconds) => prevSeconds + 1);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(intervalId);
|
||||
}, []);
|
||||
|
||||
const formatTime = (time) => {
|
||||
const hours = Math.floor(time / 3600);
|
||||
const minutes = Math.floor((time % 3600) / 60);
|
||||
const seconds = time % 60;
|
||||
|
||||
const formattedTime = `${hours < 10 ? '0' : ''}${hours}:${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
|
||||
|
||||
return formattedTime;
|
||||
};
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem("wildCoinContext", JSON.stringify(state));
|
||||
}, [state]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const passiveGenerationInterval = setInterval(() => {
|
||||
updateWildCoin(state.incrementPerSecond);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(passiveGenerationInterval);
|
||||
}, [state.incrementPerSecond]);
|
||||
|
||||
const contextValue = {
|
||||
...state,
|
||||
incrementWildCoin,
|
||||
setIncrementClick,
|
||||
setIncrementPerSecond,
|
||||
setWildCoin,
|
||||
coffee,
|
||||
setCoffee,
|
||||
manic,
|
||||
setManic,
|
||||
snowman,
|
||||
setSnowman,
|
||||
bonnet,
|
||||
setBonnet,
|
||||
sugar,
|
||||
setSugar,
|
||||
cookie,
|
||||
setCookie,
|
||||
couronne,
|
||||
setCouronne,
|
||||
epice,
|
||||
setEpice,
|
||||
biere,
|
||||
setBiere,
|
||||
setSantaDrunk,
|
||||
santaDrunk,
|
||||
seconds,
|
||||
setSeconds,
|
||||
formatTime,
|
||||
};
|
||||
|
||||
return (
|
||||
<WildCoinContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</WildCoinContext.Provider>
|
||||
);
|
||||
}
|
||||
16
Frontend/src/components/WildCoin/WildCoinIncrementAction.jsx
Executable file
16
Frontend/src/components/WildCoin/WildCoinIncrementAction.jsx
Executable file
@@ -0,0 +1,16 @@
|
||||
import { useWildCoin } from "./WildCoinContext";
|
||||
import WildCoinS from "../../../public/WildCoin.svg";
|
||||
|
||||
function WildCoinIncrementAction() {
|
||||
const { incrementClick, incrementWildCoin } = useWildCoin();
|
||||
|
||||
const handleIncrement = () => {
|
||||
incrementWildCoin(incrementClick);
|
||||
};
|
||||
|
||||
return (
|
||||
<img src={WildCoinS} className="wildCoinBtn" style={{width:"40px", height:"40px"}} alt="Clique pour augmenter le score" aria-label="Clique pour augmenter le score" onClick={handleIncrement} />
|
||||
);
|
||||
}
|
||||
|
||||
export default WildCoinIncrementAction;
|
||||
76
Frontend/src/components/burger.jsx
Executable file
76
Frontend/src/components/burger.jsx
Executable file
@@ -0,0 +1,76 @@
|
||||
import { NavLink as Link } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
import "../scss/components/navbar.scss";
|
||||
|
||||
import "../scss/root.scss";
|
||||
import PrimaryButton from "./buttons/PrimaryButton";
|
||||
|
||||
export default function Burger({ navData }) {
|
||||
return (
|
||||
<nav className="menuToggle">
|
||||
|
||||
<input type="checkbox" aria-label="Menu" />
|
||||
<span />
|
||||
<span />
|
||||
<span />
|
||||
<ul className="menu">
|
||||
{navData.map((navIndex) => {
|
||||
if (navIndex.dropdown === undefined) {
|
||||
return navIndex.btn === false ? (
|
||||
<li key={navIndex.id}>
|
||||
<Link className="mainLink" to={navIndex.linkurl}>
|
||||
{navIndex.linkname}
|
||||
</Link>
|
||||
</li>
|
||||
) : (
|
||||
<li key={navIndex.id}>
|
||||
<PrimaryButton
|
||||
btnText={navIndex.linkname}
|
||||
btnLink={navIndex.linkurl}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<li key={navIndex.id} className="dropdown">
|
||||
<Link className="mainLink" to={navIndex.linkurl}>
|
||||
{navIndex.linkname}
|
||||
</Link>
|
||||
<ul className="sousmenu">
|
||||
{navIndex.dropdown.map((dropdown) => (
|
||||
<li key={dropdown.id}>
|
||||
<Link
|
||||
className="dropLink"
|
||||
to={navIndex.linkurl + dropdown.linkurl}
|
||||
>
|
||||
{dropdown.linkname}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
Burger.propTypes = {
|
||||
navData: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
btn: PropTypes.bool,
|
||||
id: PropTypes.string.isRequired,
|
||||
linkname: PropTypes.string.isRequired,
|
||||
linkurl: PropTypes.string.isRequired,
|
||||
dropdown: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
btn: PropTypes.bool,
|
||||
id: PropTypes.string.isRequired,
|
||||
linkname: PropTypes.string.isRequired,
|
||||
linkurl: PropTypes.string.isRequired,
|
||||
})
|
||||
),
|
||||
})
|
||||
),
|
||||
}.isRequired;
|
||||
16
Frontend/src/components/buttons/PrimaryButton.jsx
Executable file
16
Frontend/src/components/buttons/PrimaryButton.jsx
Executable file
@@ -0,0 +1,16 @@
|
||||
import PropTypes from "prop-types";
|
||||
import "../../scss/components/buttons.scss";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export default function PrimaryButton({ btnText, btnLink }) {
|
||||
PrimaryButton.propTypes = {
|
||||
btnText: PropTypes.string.isRequired,
|
||||
btnLink: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
return (
|
||||
<Link className="primary-button" to={btnLink}>
|
||||
{btnText}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
16
Frontend/src/components/buttons/SecondaryButton.jsx
Executable file
16
Frontend/src/components/buttons/SecondaryButton.jsx
Executable file
@@ -0,0 +1,16 @@
|
||||
import "../../scss/components/buttons.scss";
|
||||
import PropTypes from "prop-types";
|
||||
import { Link } from "react-router";
|
||||
|
||||
export default function SecondaryButton({ btnText, btnLink }) {
|
||||
SecondaryButton.propTypes = {
|
||||
btnText: PropTypes.string.isRequired,
|
||||
btnLink: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
return (
|
||||
<Link className="secondary-button" to={btnLink}>
|
||||
{btnText}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
30
Frontend/src/components/cardsContact/CardContact.jsx
Executable file
30
Frontend/src/components/cardsContact/CardContact.jsx
Executable file
@@ -0,0 +1,30 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
import "../../scss/components/CardContact.scss";
|
||||
|
||||
CardContact.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
gitHub: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
function CardContact({ name, gitHub }) {
|
||||
return (
|
||||
<div className="cardContact">
|
||||
<Link to={gitHub} target="_blank">
|
||||
<button className="Btn">
|
||||
<svg
|
||||
className="svgIcon"
|
||||
viewBox="0 0 496 512"
|
||||
height="1.4em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"></path>
|
||||
</svg>
|
||||
<span className="text">GitHub</span>
|
||||
</button>
|
||||
</Link>
|
||||
<p>{name}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default CardContact;
|
||||
84
Frontend/src/components/footer.jsx
Executable file
84
Frontend/src/components/footer.jsx
Executable file
@@ -0,0 +1,84 @@
|
||||
import "../scss/components/footer.scss";
|
||||
import { NavLink as Link } from "react-router-dom";
|
||||
import CardContact from "./cardsContact/CardContact";
|
||||
|
||||
const infoDev = [
|
||||
{
|
||||
id: "1",
|
||||
name: "Alix C",
|
||||
gitHub: "https://github.com/Halicksse",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "Sebatien L",
|
||||
gitHub: "https://github.com/Lambseb",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "Baptiste S",
|
||||
gitHub: "https://github.com/Batsave",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "Kevin T",
|
||||
gitHub: "https://github.com/tetardtek",
|
||||
},
|
||||
{
|
||||
id: "5",
|
||||
name: "Nicolas DF",
|
||||
gitHub: "https://github.com/Defreitasnicolas",
|
||||
},
|
||||
];
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="footer">
|
||||
<div className="footer-container">
|
||||
<Link
|
||||
to="/#home"
|
||||
className="footer-logo"
|
||||
alt="Logo"
|
||||
aria-label="Logo Officiel"
|
||||
title="Aller à la page d'accueil"
|
||||
/>
|
||||
<div className="section">
|
||||
<p className="section-title">A Propos</p>
|
||||
<p className="section-text">
|
||||
Ce site est un prototype d'exercice développé lors d'un Hackathon
|
||||
dans le cadre d’une formation de Développeur Web et Mobile au sein
|
||||
de la Wild Code School sur le campus Remote de Septembre 2023.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="section">
|
||||
<p className="section-title">Légale</p>
|
||||
<ul className="section-list">
|
||||
<li className="section-item">
|
||||
<Link
|
||||
to="/mentionslegales"
|
||||
title="Aller à la page Mentions Légales"
|
||||
>
|
||||
Mentions Légales
|
||||
</Link>
|
||||
</li>
|
||||
<li className="section-item">
|
||||
<Link to="/cookies" title="Aller à la page Cookies">
|
||||
Cookies
|
||||
</Link>
|
||||
</li>
|
||||
<li className="section-item"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="spacing" />
|
||||
</div>
|
||||
<div className="footer-section">
|
||||
<div className="cardContactContainer">
|
||||
{infoDev.map((info) => (
|
||||
<CardContact key={info.id} name={info.name} gitHub={info.gitHub} />
|
||||
))}
|
||||
</div>
|
||||
<p className="copyright">© 2023 | TrueQuiLeaks. Tous droits réservés.</p>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
146
Frontend/src/components/navbar.jsx
Executable file
146
Frontend/src/components/navbar.jsx
Executable file
@@ -0,0 +1,146 @@
|
||||
import { NavLink as Link } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import "../scss/components/navbar.scss";
|
||||
import "../scss/root.scss";
|
||||
|
||||
import PrimaryButton from "./buttons/PrimaryButton";
|
||||
import Burger from "./burger";
|
||||
import { useWildCoin } from "./WildCoin/WildCoinContext";
|
||||
import HUDON from "../../public/NavBar/HUDON.svg";
|
||||
import HUDOFF from "../../public/NavBar/HUDOFF.svg";
|
||||
import SnowOn from "../../public/NavBar/SnowOn.svg";
|
||||
import SnowOff from "../../public/NavBar/SnowOff.svg";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function Navbar({
|
||||
navData,
|
||||
isVisible,
|
||||
setIsVisible,
|
||||
toggleSnow,
|
||||
setToggleSnow,
|
||||
}) {
|
||||
Navbar.propTypes = {
|
||||
isVisible: PropTypes.bool,
|
||||
setIsVisible: PropTypes.function,
|
||||
setToggleSnow: PropTypes.function,
|
||||
toggleSnow: PropTypes.bool,
|
||||
}.isRequired;
|
||||
|
||||
const { wildCoin } = useWildCoin();
|
||||
const [imageSrc, setImageSrc] = useState(HUDON);
|
||||
const [snowImageSrc, setSnowImageSrc] = useState(SnowOff);
|
||||
const [timerVisible, setTimerVisible] = useState(false);
|
||||
const handleClickWildCoin = () => {
|
||||
setTimerVisible(true);
|
||||
};
|
||||
|
||||
const toggleHud = () => {
|
||||
if (!isVisible) {
|
||||
setIsVisible(true);
|
||||
setImageSrc(HUDOFF);
|
||||
} else {
|
||||
setIsVisible(false);
|
||||
setImageSrc(HUDON);
|
||||
}
|
||||
};
|
||||
function toggleSnowBtn() {
|
||||
if (toggleSnow === false) {
|
||||
setToggleSnow(true);
|
||||
setSnowImageSrc(SnowOn);
|
||||
} else {
|
||||
setToggleSnow(false);
|
||||
setSnowImageSrc(SnowOff);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<nav className="header-main">
|
||||
<Link
|
||||
className="logo"
|
||||
to="/"
|
||||
aria-label="Retourner à la page d'accueil"
|
||||
title="Logo XmassClick"
|
||||
/>
|
||||
<div className="navbar">
|
||||
<div className="wildCoin">
|
||||
{new Intl.NumberFormat().format(wildCoin)}
|
||||
</div>
|
||||
<ul className="nav-list">
|
||||
{navData.map((navIndex) => {
|
||||
if (navIndex.dropdown === undefined) {
|
||||
return navIndex.btn === false ? (
|
||||
<li key={navIndex.id}>
|
||||
<Link className="mainLink" to={navIndex.linkurl}>
|
||||
{navIndex.linkname}
|
||||
</Link>
|
||||
</li>
|
||||
) : (
|
||||
<li key={navIndex.id}>
|
||||
<PrimaryButton
|
||||
btnText={navIndex.linkname}
|
||||
btnLink={navIndex.linkurl}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<li key={navIndex.id} className="dropdown">
|
||||
<Link className="mainLink" to={navIndex.linkurl}>
|
||||
{navIndex.linkname}
|
||||
</Link>
|
||||
<ul className="dropdown-content">
|
||||
{navIndex.dropdown.map((dropdown) => (
|
||||
<li key={dropdown.id}>
|
||||
<Link
|
||||
className="dropLink"
|
||||
to={navIndex.linkurl + dropdown.linkurl}
|
||||
>
|
||||
{dropdown.linkname}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<img
|
||||
onClick={() => toggleHud()}
|
||||
src={imageSrc}
|
||||
style={{ height: "28px" }}
|
||||
alt="boutton on"
|
||||
/>
|
||||
<img
|
||||
onClick={() => toggleSnowBtn()}
|
||||
src={snowImageSrc}
|
||||
style={{ height: "28px" }}
|
||||
alt="boutton on"
|
||||
/>
|
||||
<Burger navData={navData} />
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
Navbar.propTypes = {
|
||||
navData: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
btn: PropTypes.bool,
|
||||
id: PropTypes.string,
|
||||
linkname: PropTypes.string,
|
||||
linkurl: PropTypes.string,
|
||||
dropdown: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
btn: PropTypes.bool,
|
||||
id: PropTypes.string,
|
||||
linkname: PropTypes.string,
|
||||
linkurl: PropTypes.string,
|
||||
})
|
||||
),
|
||||
})
|
||||
),
|
||||
};
|
||||
|
||||
Navbar.defaultProps = {
|
||||
navData: [],
|
||||
};
|
||||
13
Frontend/src/components/timer/Timer.jsx
Executable file
13
Frontend/src/components/timer/Timer.jsx
Executable file
@@ -0,0 +1,13 @@
|
||||
import { useWildCoin } from "../WildCoin/WildCoinContext";
|
||||
|
||||
function Timer() {
|
||||
const { formatTime, seconds } = useWildCoin();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>{formatTime(seconds)}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Timer;
|
||||
Reference in New Issue
Block a user