feat: initial import — ClickerZ formation project (Express + React/Vite)
This commit is contained in:
35
Frontend/src/App.jsx
Executable file
35
Frontend/src/App.jsx
Executable file
@@ -0,0 +1,35 @@
|
||||
import { useState } from "react";
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
||||
import Navbar from "./components/navbar";
|
||||
import Footer from "./components/footer";
|
||||
import Hud from "./components/Hud/Hud";
|
||||
|
||||
import "./scss/root.scss";
|
||||
import "./scss/components/footer.scss";
|
||||
|
||||
import navData from "./data/NavBarData.json";
|
||||
|
||||
function App() {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const [toggleSnow, setToggleSnow] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar
|
||||
navData={navData}
|
||||
isVisible={isVisible}
|
||||
setIsVisible={setIsVisible}
|
||||
toggleSnow={toggleSnow}
|
||||
setToggleSnow={setToggleSnow}
|
||||
/>
|
||||
<Hud isVisible={isVisible} setIsVisible={setIsVisible} />
|
||||
<main>
|
||||
<Outlet context={[toggleSnow, setToggleSnow]} />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
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;
|
||||
142
Frontend/src/context/AuthContext.jsx
Executable file
142
Frontend/src/context/AuthContext.jsx
Executable file
@@ -0,0 +1,142 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useMemo,
|
||||
useEffect,
|
||||
} from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import axios from "axios";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
|
||||
const AuthContext = createContext();
|
||||
|
||||
const AuthProvider = ({ children }) => {
|
||||
const [user, setUser] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const jwtToken = localStorage.getItem("token");
|
||||
|
||||
if (jwtToken) {
|
||||
try {
|
||||
const decodedPayload = jwtDecode(jwtToken);
|
||||
const res = await axios.get(
|
||||
`http://localhost:3310/api/users/${decodedPayload.user}`
|
||||
);
|
||||
setUser(res.data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching user data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem("token");
|
||||
setUser(null);
|
||||
};
|
||||
const editUser = async (updatedFields) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${import.meta.env.VITE_BACKEND_URL}/api/users/${user.id}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||
},
|
||||
body: JSON.stringify(updatedFields),
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const updatedUser = await response.json();
|
||||
setUser((prevUser) => ({
|
||||
...prevUser,
|
||||
...updatedUser.user,
|
||||
}));
|
||||
return "User updated successfully";
|
||||
}
|
||||
if (response.status === 400) {
|
||||
console.error("Bad Request:", response.statusText);
|
||||
throw new Error("Bad Request");
|
||||
} else if (response.status === 401) {
|
||||
console.error("Unauthorized:", response.statusText);
|
||||
throw new Error("Unauthorized");
|
||||
} else {
|
||||
console.error("Error updating user:", response.statusText);
|
||||
throw new Error("Error updating user");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating user:", error);
|
||||
throw new Error("An error occurred during user update");
|
||||
}
|
||||
};
|
||||
|
||||
const sendPasswordResetEmail = async (email) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${import.meta.env.VITE_BACKEND_URL}/api/forgot-password`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ mail: email }),
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
return "Password reset email sent successfully";
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
throw new Error(data.message || "Error sending password reset email");
|
||||
} catch (error) {
|
||||
console.error("Error sending password reset email:", error);
|
||||
throw new Error(
|
||||
"An error occurred while sending the password reset email"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const authContextValue = useMemo(() => {
|
||||
return {
|
||||
user,
|
||||
loading,
|
||||
logout,
|
||||
editUser,
|
||||
sendPasswordResetEmail,
|
||||
setUser: (newUser) => {
|
||||
setUser(newUser);
|
||||
},
|
||||
};
|
||||
}, [user, loading, logout]);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
AuthProvider.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
const useAuth = () => {
|
||||
const context = useContext(AuthContext);
|
||||
if (!context) {
|
||||
throw new Error("useAuth must be used within an AuthProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
229
Frontend/src/data/404-animation.json
Executable file
229
Frontend/src/data/404-animation.json
Executable file
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"v": "5.4.4",
|
||||
"fr": 29.9700012207031,
|
||||
"ip": 0,
|
||||
"op": 120.0000048877,
|
||||
"w": 1080,
|
||||
"h": 620,
|
||||
"nm": "Comp 2",
|
||||
"ddd": 0,
|
||||
"assets": [],
|
||||
"layers": [
|
||||
{
|
||||
"ddd": 0,
|
||||
"ind": 1,
|
||||
"ty": 4,
|
||||
"nm": "Shape Layer 1",
|
||||
"sr": 1,
|
||||
"ks": {
|
||||
"o": { "a": 0, "k": 100, "ix": 11 },
|
||||
"r": { "a": 0, "k": 0, "ix": 10 },
|
||||
"p": { "a": 0, "k": [539.5, 310, 0], "ix": 2 },
|
||||
"a": { "a": 0, "k": [0, 0, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [100, 100, 100], "ix": 6 }
|
||||
},
|
||||
"ao": 0,
|
||||
"shapes": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 81],
|
||||
[0, 0],
|
||||
[-77, 0],
|
||||
[0, -39],
|
||||
[0, 0],
|
||||
[17, -20],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"o": [
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, -81],
|
||||
[0, 0],
|
||||
[77, 0],
|
||||
[0, 39],
|
||||
[0, 0],
|
||||
[-17, 20],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"v": [
|
||||
[-539.25, 234],
|
||||
[-244, 234],
|
||||
[-244, 126],
|
||||
[-385, 126],
|
||||
[-385, 62],
|
||||
[-263, -238],
|
||||
[-178, -238],
|
||||
[-178, 54],
|
||||
[-150, 54],
|
||||
[-150, 120],
|
||||
[-176, 120],
|
||||
[-176, 234],
|
||||
[-59, 234],
|
||||
[-101, 143],
|
||||
[-101, -160],
|
||||
[-9, -248],
|
||||
[100, -165],
|
||||
[101, 157],
|
||||
[80, 220],
|
||||
[50, 240],
|
||||
[288, 240],
|
||||
[287, 123],
|
||||
[148, 123],
|
||||
[148, 56],
|
||||
[268, -239],
|
||||
[357, -239],
|
||||
[357, 51],
|
||||
[380, 51],
|
||||
[380, 122],
|
||||
[359, 122],
|
||||
[359, 241.75],
|
||||
[540.5, 242]
|
||||
],
|
||||
"c": false
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "st",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.1, 0.1, 0.1, 1],
|
||||
"ix": 3
|
||||
},
|
||||
"o": { "a": 0, "k": 100, "ix": 4 },
|
||||
"w": { "a": 0, "k": 5, "ix": 5 },
|
||||
"lc": 1,
|
||||
"lj": 1,
|
||||
"ml": 4,
|
||||
"bm": 0,
|
||||
"nm": "Stroke 1",
|
||||
"mn": "ADBE Vector Graphic - Stroke",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [0, 0], "ix": 2 },
|
||||
"a": { "a": 0, "k": [0, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [100, 100], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Shape 1",
|
||||
"np": 3,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tm",
|
||||
"s": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.667], "y": [0.992] },
|
||||
"o": { "x": [0.534], "y": [0.224] },
|
||||
"t": 47,
|
||||
"s": [0],
|
||||
"e": [100]
|
||||
},
|
||||
{ "t": 95.0000038694293 }
|
||||
],
|
||||
"ix": 1
|
||||
},
|
||||
"e": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.667], "y": [0.96] },
|
||||
"o": { "x": [0.677], "y": [0.024] },
|
||||
"t": 15,
|
||||
"s": [0],
|
||||
"e": [100]
|
||||
},
|
||||
{ "t": 82.0000033399285 }
|
||||
],
|
||||
"ix": 2
|
||||
},
|
||||
"o": { "a": 0, "k": 0, "ix": 3 },
|
||||
"m": 1,
|
||||
"ix": 2,
|
||||
"nm": "Trim Paths 1",
|
||||
"mn": "ADBE Vector Filter - Trim",
|
||||
"hd": false
|
||||
}
|
||||
],
|
||||
"ip": 0,
|
||||
"op": 120.0000048877,
|
||||
"st": 0,
|
||||
"bm": 0
|
||||
}
|
||||
],
|
||||
"markers": []
|
||||
}
|
||||
386
Frontend/src/data/Achievements.json
Executable file
386
Frontend/src/data/Achievements.json
Executable file
@@ -0,0 +1,386 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Véritable cactus en peluche",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/n0tuti.jpg"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Brosse à dents sans poil",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/hd42tk.jpg"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Un jour, Dark Vador s’est attaqué à Chuck Norris. Depuis, il fait de l’asthme."
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Photo d'Ayoub",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/fpanvh.jpg"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Pourquoi on met une selle sur un cheval ? Parce qu'en dessous, elle tomberait."
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Parapluie invisible",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/b8ms4o.jpg"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Qu'est-ce qui est plus merveilleux que de faire tourner un enfant sur un tourniquet ? L'arrêter avec une pelle."
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "Savon qui gratte",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/oeefev.jpg"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Pourquoi les moutons aiment le chewing-gum ? Car c'est bon pour la laine."
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Moule à glaçons géant",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/2sdm53.png"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Quand Chuck Norris fait un programme, il installe les modules, code et vend le programme... ensuite il demande à quoi il doit servir."
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "Casquette avec ventilateur intégré",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/wjhe5i.jpg"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Chuck Norris a invité Albert Einstein...à son dîner de cons."
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"name": "Game boy color de tonton",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/w82iwu.jpg"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Vous savez pourquoi les pets puent ? Pour que les sourds en profitent !"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"name": "Mug moustache",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/csu9z1.jpg"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Qu'est ce qui est jaune et qui n'attend pas ? Un citron pressé"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"name": "un pull de noël",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/uwjwn1.jpg"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Que met un développeur sur sa voiture en hiver ? Une bash."
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"name": "Stickers Gnia gnia gnia 5 minutes la présentation",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/8jids3.png"
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Comment une blonde fait-elle pour faire un double de ses clefs ? Elle les photocopie."
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"name": "Photo de ta mamie...",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/htqzwa.jpg"
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Qu'est-ce qu'un cochon volant ? Un aéroport."
|
||||
},
|
||||
{
|
||||
"id": 24,
|
||||
"name": "Livre de names de Tonton",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/avr4b4.png"
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Mon grand-père avait prédit que le Titanic coulerait, il l'avait répété maintes fois...Mais on a préféré le virer de la salle de cinéma"
|
||||
},
|
||||
{
|
||||
"id": 26,
|
||||
"name": "Oreiller qui ronfle",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/4ydby9.png"
|
||||
},
|
||||
{
|
||||
"id": 27,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Un jour, les Power Rangers ont combattu Chuck Norris. Depuis, on les appelle les Teletubbies."
|
||||
},
|
||||
{
|
||||
"id": 28,
|
||||
"name": "Haut-parleur de douche non étanche",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/ugqwdj.jpg"
|
||||
},
|
||||
{
|
||||
"id": 29,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Qu'est-ce qui a deux pattes et qui saigne ? Un demi-chien..."
|
||||
},
|
||||
{
|
||||
"id": 30,
|
||||
"name": "Calendrier de l'Avent avec des chocolats au wasabi et moutarde forte",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/dakyj9.png"
|
||||
},
|
||||
{
|
||||
"id": 31,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Sur quel site internet peut-on trouver un lave-vaisselle pas cher ? Meetic."
|
||||
},
|
||||
{
|
||||
"id": 32,
|
||||
"name": "Lunettes de soleil pour joueur de valorant",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/dxjicl.png"
|
||||
},
|
||||
{
|
||||
"id": 33,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Chuck Norris mine de la crypto-monnaie...avec la calculette de sa montre Casio"
|
||||
},
|
||||
{
|
||||
"id": 34,
|
||||
"name": "Parfum au PHP: aucune odeur",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/o2435t.png"
|
||||
},
|
||||
{
|
||||
"id": 35,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Quand Google ne trouve pas quelque chose, Il demande à Chuck Norris."
|
||||
},
|
||||
{
|
||||
"id": 36,
|
||||
"name": "Chapeau de Noël clignotant",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/d4su7e.png"
|
||||
},
|
||||
{
|
||||
"id": 37,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Quelles sont les choses les plus lourdes de l'univers ? Soleil, Étoiles, Trou noir...et node_modules..."
|
||||
},
|
||||
{
|
||||
"id": 38,
|
||||
"name": "Kit de survie pour la fin du monde",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/ltcik6.png"
|
||||
},
|
||||
{
|
||||
"id": 39,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Quelle est la fée la plus paresseuse ? La fée Néante"
|
||||
},
|
||||
{
|
||||
"id": 40,
|
||||
"name": "Bougie parfumée à l'essence de pizza",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/a3hv8n.jpg"
|
||||
},
|
||||
{
|
||||
"id": 41,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Que mettre dans un kit de survie pour la fin du monde ? Du chocolat, des cookies et un DVD de !"
|
||||
},
|
||||
{
|
||||
"id": 42,
|
||||
"name": "Le livre mein... craft",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/fuy8kq.png"
|
||||
},
|
||||
{
|
||||
"id": 43,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Un jour Hulk s’est battu contre Chuck Norris. Depuis, il fait de la pub pour du maïs."
|
||||
},
|
||||
{
|
||||
"id": 44,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Pourquoi les chaussettes ont-elles des orteils séparés ? Parce que même les pieds ont besoin d'intimité !"
|
||||
},
|
||||
{
|
||||
"id": 45,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "J'ai dit non ! Mon gynécologue m'a dit pas de sexe pendant 3 semaines. Et que t'as dit ton dentiste ?"
|
||||
},
|
||||
{
|
||||
"id": 46,
|
||||
"name": "Chaussettes avec orteils séparés",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/vn3xht.png"
|
||||
},
|
||||
{
|
||||
"id": 47,
|
||||
"name": "Blague:",
|
||||
"founded": false,
|
||||
"image": "https://images.pexels.com/photos/1115680/pexels-photo-1115680.jpeg",
|
||||
"description": "Quel est le jeu préféré des Portugais ?Call of d'outils"
|
||||
},
|
||||
|
||||
{
|
||||
"id": 48,
|
||||
"name": "Christopher",
|
||||
"description": "Un ange parmi les cieux, un nuage subtil et un glorieux soldat",
|
||||
"founded": false,
|
||||
"image": "./png/chris.png"
|
||||
},
|
||||
{
|
||||
"id": 49,
|
||||
"name": "Marie-Hermine",
|
||||
"description": "La logique, le franc parlé, sans nul doute une perle dans un monde de brutes ",
|
||||
"founded": false,
|
||||
"image": "./png/m-h.png"
|
||||
},
|
||||
{
|
||||
"id": 50,
|
||||
"name": "Yavuz",
|
||||
"description": "L'innovation culinaire, le cuisinier au grand coeur, l'avion petillant, l'or du Bayou. Il sait faire la fete, on l'appelle le PHP. ",
|
||||
"founded": false,
|
||||
"image": "./png/yavuz.png"
|
||||
},
|
||||
{
|
||||
"id": 51,
|
||||
"name": "Ayoub",
|
||||
"description": "Un ami cher, loyal et de bon conseil, il saura vous épauler, vous ecouter, mais gare à toi, âme sensible ses mots peuvent etre francs et coupants mais toujours bienveillants. Un ami quoi!",
|
||||
"founded": false,
|
||||
"image": "./png/ayoub.png"
|
||||
},
|
||||
{
|
||||
"id": 52,
|
||||
"name": "Anthony",
|
||||
"description": "Cupidon et Apollon n'ont qu'à bien se tenir, connu pour son physique legendaire, gardez vos femmes et vos hommes a double tour, a son passage c'est un ravage.",
|
||||
"founded": false,
|
||||
"image": "./png/antho.png"
|
||||
},
|
||||
{
|
||||
"id": 53,
|
||||
"name": "Vincent",
|
||||
"description": "L'âme voyageuse, le vagabond au grand coeur et la main sur la bouteille. Il est le compagnon idéal pour un voyage animé. Et vogue, vogue la galère...",
|
||||
"founded": false,
|
||||
"image": "./png/vincent.png"
|
||||
},
|
||||
{
|
||||
"id": 54,
|
||||
"name": "Julien",
|
||||
"description": "Il est l'élu, celui qui voit au dela de ce que vous voyez.",
|
||||
"founded": false,
|
||||
"image": "./png/julien.png"
|
||||
},
|
||||
{
|
||||
"id": 55,
|
||||
"name": "Benoit",
|
||||
"description": "Maitre du temps, maitre de l'espace, sa parole est d'or et si tu ne respectes pas son temps, tu sors. ",
|
||||
"founded": false,
|
||||
"image": "./png/benoit.png"
|
||||
},
|
||||
{
|
||||
"id": 56,
|
||||
"name": "Samuel",
|
||||
"description": "Des yeux perçants, les crocs acérés, tu le rencontreras dans la pénombre ou une foret enchantée. N'aies pas peur de ses canines affutées, son sourire et sa gentillesse sauront te rassurer. ",
|
||||
"founded": false,
|
||||
"image": "./png/samuel.png"
|
||||
},
|
||||
|
||||
{
|
||||
"id": 57,
|
||||
"name": "Ayoub Ultime",
|
||||
"description": "La carte ultime, c'est l'immunité à toutes épreuves! Un style, une classe, un élan d'élégance et une intelligence raffraîchissante. La meilleure carte. Tout simplement. ",
|
||||
"founded": false,
|
||||
"image": "./png/ayoub-ultimate.png"
|
||||
},
|
||||
{
|
||||
"id": 58,
|
||||
"name": "Une photo des formateurs de la Wild",
|
||||
"founded": false,
|
||||
"image": "https://i.goopics.net/8m6t45.jpg"
|
||||
}
|
||||
]
|
||||
20
Frontend/src/data/NavBarData.json
Executable file
20
Frontend/src/data/NavBarData.json
Executable file
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"linkname": "Jeu",
|
||||
"linkurl": "/",
|
||||
"btn": false
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"linkname": "Boutique",
|
||||
"linkurl": "/boutique",
|
||||
"btn": false
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"linkname": "Succès",
|
||||
"linkurl": "/achievements",
|
||||
"btn": false
|
||||
}
|
||||
]
|
||||
92
Frontend/src/data/shop.json
Executable file
92
Frontend/src/data/shop.json
Executable file
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"name": "Manic",
|
||||
"price": 15,
|
||||
"incrementValue": 1,
|
||||
"description": "Evite de vous bruler quand vous sortez les cookies du four, vous gagnez 5 CPS",
|
||||
"link": "/",
|
||||
"image": "./svg/Hand.svg",
|
||||
"buyed": false,
|
||||
"type": "actif"
|
||||
},
|
||||
{
|
||||
"name": "Tasse à café",
|
||||
"price": 15,
|
||||
"incrementValue": 1,
|
||||
"description": "Bien chaud vous permet de tenir sur la durée",
|
||||
"link": "/",
|
||||
"image": "./svg/Tasse.svg",
|
||||
"buyed": false,
|
||||
"type": "passif"
|
||||
},
|
||||
{
|
||||
"name": "Mr Bonhomme",
|
||||
"price": 150,
|
||||
"incrementValue": 10,
|
||||
"description": "Un assistant idéal pour le click",
|
||||
"link": "/",
|
||||
"image": "./svg/Bonhome.svg",
|
||||
"buyed": false,
|
||||
"type": "actif"
|
||||
},
|
||||
{
|
||||
"name": "Bonnet",
|
||||
"price": 150,
|
||||
"incrementValue": 10,
|
||||
"description": "Garder vos oreilles bien à l'abri du froid et click !",
|
||||
"link": "/",
|
||||
"image": "./svg/Bonnet.svg",
|
||||
"buyed": false,
|
||||
"type": "passif"
|
||||
},
|
||||
{
|
||||
"name": "Cookie",
|
||||
"price": 1500,
|
||||
"incrementValue": 100,
|
||||
"description": "Fait avec amour",
|
||||
"link": "/",
|
||||
"image": "./svg/Cookie.svg",
|
||||
"buyed": false,
|
||||
"type": "actif"
|
||||
},
|
||||
{
|
||||
"name": "Canne en sucre",
|
||||
"price": 1500,
|
||||
"incrementValue": 100,
|
||||
"description": "Le sucre c'est connu, ca reboost",
|
||||
"link": "/",
|
||||
"image": "./svg/Canne.svg",
|
||||
"buyed": false,
|
||||
"type": "passif"
|
||||
},
|
||||
{
|
||||
"name": "Couronne d'hiver",
|
||||
"price": 15000,
|
||||
"incrementValue": 1000,
|
||||
"description": "Un bisous ou rien du tout !",
|
||||
"link": "/",
|
||||
"image": "./svg/Courone.svg",
|
||||
"buyed": false,
|
||||
"type": "actif"
|
||||
},
|
||||
{
|
||||
"name": "Mr pain d'épice",
|
||||
"price": 15000,
|
||||
"incrementValue": 1000,
|
||||
"description": "Le meilleur c'est la tête",
|
||||
"link": "/",
|
||||
"image": "./svg/PainDep.svg",
|
||||
"buyed": false,
|
||||
"type": "passif"
|
||||
},
|
||||
{
|
||||
"name": "Bière",
|
||||
"price": 8000,
|
||||
"incrementValue": 1000,
|
||||
"description": "Boisson de qualité, double tout les CPS, attention à ne pas trop en abuser",
|
||||
"link": "/",
|
||||
"image": "./svg/Beer.svg",
|
||||
"buyed": false,
|
||||
"type": "actif"
|
||||
}
|
||||
]
|
||||
10
Frontend/src/index.css
Executable file
10
Frontend/src/index.css
Executable file
@@ -0,0 +1,10 @@
|
||||
:root {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 1px;
|
||||
display: none;
|
||||
|
||||
}
|
||||
56
Frontend/src/main.jsx
Executable file
56
Frontend/src/main.jsx
Executable file
@@ -0,0 +1,56 @@
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import App from "./App";
|
||||
import Home from "./pages/Home";
|
||||
import ErrorPage from "./pages/404";
|
||||
import { WildCoinProvider } from "./components/WildCoin/WildCoinContext";
|
||||
import Ameliorations from "./components/WildCoin/Amelioration";
|
||||
import Boutique from "./pages/Boutique";
|
||||
import Achievements from "./pages/Achievements";
|
||||
import Legal from "./pages/Legal";
|
||||
import Cookie from "./pages/Cookie";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <App />,
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
element: <Home />,
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
element: <ErrorPage />,
|
||||
},
|
||||
{
|
||||
path: "/ameliorations",
|
||||
element: <Ameliorations />,
|
||||
},
|
||||
{
|
||||
path: "/boutique",
|
||||
element: <Boutique />,
|
||||
},
|
||||
{
|
||||
path: "/achievements",
|
||||
element: <Achievements />,
|
||||
},
|
||||
{
|
||||
path: "/mentionslegales",
|
||||
element: <Legal />,
|
||||
},
|
||||
{
|
||||
path: "/cookies",
|
||||
element: <Cookie />,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
|
||||
root.render(
|
||||
<WildCoinProvider>
|
||||
<RouterProvider router={router} />
|
||||
</WildCoinProvider>
|
||||
);
|
||||
0
Frontend/src/pages/.gitkeep
Executable file
0
Frontend/src/pages/.gitkeep
Executable file
26
Frontend/src/pages/404.jsx
Executable file
26
Frontend/src/pages/404.jsx
Executable file
@@ -0,0 +1,26 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import "../scss/pages.scss";
|
||||
import Lottie from "react-lottie-player";
|
||||
import animation404 from "../data/404-animation.json";
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<section>
|
||||
<div className="containererror">
|
||||
<Lottie
|
||||
loop
|
||||
animationData={animation404}
|
||||
play
|
||||
style={{ width: 260, height: 150 }}
|
||||
/>
|
||||
<h1>Oops! Il semble que la page n'existe pas.</h1>
|
||||
<p className="message">
|
||||
Nous vous conseillons de retourner à la page d'accueil.
|
||||
</p>
|
||||
<Link className="btn-return" to="/">
|
||||
retourner à la page d'accueil
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
37
Frontend/src/pages/Achievements.jsx
Executable file
37
Frontend/src/pages/Achievements.jsx
Executable file
@@ -0,0 +1,37 @@
|
||||
import { useState } from "react";
|
||||
import AchievementsCard from "../components/AchievementsCard";
|
||||
import "../scss/achievements.scss";
|
||||
import { useWildCoin } from "../components/WildCoin/WildCoinContext";
|
||||
import achievements from "../data/Achievements.json";
|
||||
|
||||
function Achievements() {
|
||||
const { wildCoin } = useWildCoin();
|
||||
let score = 1;
|
||||
if (wildCoin >= 25) {
|
||||
score = Math.floor((wildCoin - 25) / 400) + 1;
|
||||
} else {
|
||||
score = 0;
|
||||
}
|
||||
return (
|
||||
<div className="fullachieve">
|
||||
<h1>Succès</h1>
|
||||
<div className="achievementscontainer">
|
||||
<div className="achievementscardcontainer">
|
||||
{achievements &&
|
||||
achievements.slice(0, score).map((a) => {
|
||||
return (
|
||||
<AchievementsCard
|
||||
key={a.id}
|
||||
name={a.name}
|
||||
description={a.description}
|
||||
image={a.image}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Achievements;
|
||||
33
Frontend/src/pages/Boutique.jsx
Executable file
33
Frontend/src/pages/Boutique.jsx
Executable file
@@ -0,0 +1,33 @@
|
||||
import BoutiqueCard from "../components/BoutiqueCard";
|
||||
// import { useWildCoin } from "..components/WildCoin/WildCoinContext";
|
||||
import "../scss/shop.scss";
|
||||
import shop from "../data/shop";
|
||||
|
||||
export default function Boutique() {
|
||||
|
||||
|
||||
return (
|
||||
<main>
|
||||
<div className="shoppagecontainer">
|
||||
<h1>Boutique</h1>
|
||||
<div className="cardcontainer">
|
||||
{shop.map((item) => {
|
||||
return (
|
||||
<BoutiqueCard
|
||||
key={item.name}
|
||||
name={item.name}
|
||||
price={item.price}
|
||||
incrementValue={item.incrementValue}
|
||||
description={item.description}
|
||||
image={item.image}
|
||||
link={item.link}
|
||||
type={item.type}
|
||||
buyed={item.buyed}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
100
Frontend/src/pages/Cookie.jsx
Executable file
100
Frontend/src/pages/Cookie.jsx
Executable file
@@ -0,0 +1,100 @@
|
||||
import "../scss/Cookie.scss";
|
||||
function Cookie() {
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="item">
|
||||
<h2>Qu’est-ce qu’un cookie ?</h2>
|
||||
<p>
|
||||
Un cookie est un petit fichier texte sauvegardé sur votre ordinateur
|
||||
lorsque vous visitez un site web. Ce fichier texte enregistre des
|
||||
informations qui peuvent être lues par un site web lorsque vous le
|
||||
visitez de nouveau plus tard. Certains de ces cookies sont nécessaires
|
||||
pour accéder à certaines fonctionnalités d’un site. D’autres cookies
|
||||
sont d’utilité pratique pour le visiteur : ils sauvegardent de manière
|
||||
sécurisée votre nom d’utilisateur ou vos préférences linguistiques par
|
||||
exemple. Les cookies signifient tout simplement qu’à chaque fois que
|
||||
vous visitez un site web, vous n’avez pas besoin de saisir à nouveau
|
||||
les mêmes informations.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="item">
|
||||
<h2>Pourquoi Xmass Clicker utilise des cookies ?</h2>
|
||||
<p>
|
||||
Nous utilisons des cookies pour vous fournir une expérience
|
||||
utilisateur optimale et adaptée à vos préférences personnelles. En
|
||||
utilisant les cookies, Les cookies sont également utilisés pour
|
||||
optimiser la performance du site. Xmass Clicker a pris toutes les
|
||||
mesures organisationnelles et techniques pour protéger vos données
|
||||
personnelles ainsi que d’une éventuelle perte d’informations ou de
|
||||
toute forme de traitement illicite. Pour davantage d’informations,
|
||||
consultez notre Politique de confidentialité.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="item">
|
||||
<h2>Comment puis-je désactiver les cookies ?</h2>
|
||||
<p>
|
||||
Vous pouvez paramétrer votre navigateur Internet pour désactiver les
|
||||
cookies. Notez toutefois que si vous désactivez les cookies, votre nom
|
||||
d’utilisateur ainsi que votre mot de passe ne seront plus sauvegardés
|
||||
sur aucun site web.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="item">
|
||||
<h2>Firefox :</h2>
|
||||
<p>
|
||||
1. Ouvrez Firefox <br />
|
||||
2. Appuyez sur la touche « Alt » <br />
|
||||
3. Dans le menu en haut de la page cliquez sur « Outils » puis «
|
||||
Options » <br />
|
||||
4. Sélectionnez l’onglet « Vie privée » <br />
|
||||
5. Dans le menu déroulant à droite de « Règles de conservation »,
|
||||
cliquez sur « utiliser les paramètres personnalisés pour l’historique
|
||||
» <br />
|
||||
6. Un peu plus bas, décochez « Accepter les cookies » <br />
|
||||
7. Sauvegardez vos préférences en cliquant sur « OK »
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="item">
|
||||
<h2>Internet Explorer/Edge :</h2>
|
||||
<p>
|
||||
1. Ouvrez Internet Explorer <br />
|
||||
2. Dans le menu « Outils », sélectionnez « Options Internet » <br />
|
||||
3. Cliquez sur l’onglet « Confidentialité » <br />
|
||||
4. Cliquez sur « Avancé » et décochez « Accepter » <br />
|
||||
5. Sauvegardez vos préférences en cliquant sur « OK »
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="item">
|
||||
<h2>Safari :</h2>
|
||||
<p>
|
||||
1. Ouvrez Safari <br />
|
||||
2. Dans la barre de menu en haut, cliquez sur « Safari », puis «
|
||||
Préférences » <br />
|
||||
3. Sélectionnez l’icône « Sécurité » <br />
|
||||
4. À côté de « Accepter les cookies », cochez « Jamais » <br />
|
||||
5. Si vous souhaitez voir les cookies qui sont déjà sauvegardés sur
|
||||
votre ordinateur, cliquez sur « Afficher les cookies »
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="item">
|
||||
<h2>Google Chrome :</h2>
|
||||
<p>
|
||||
1. Ouvrez Google Chrome <br />
|
||||
2. Cliquez sur l’icône d’outils dans la barre de menu <br />
|
||||
3. Sélectionnez « Options » <br />
|
||||
4. Cliquez sur l’onglet « Options avancées » <br />
|
||||
5. Dans le menu déroulant « Paramètres des cookies », sélectionnez «
|
||||
Bloquer tous les cookies »
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Cookie;
|
||||
231
Frontend/src/pages/Home.jsx
Executable file
231
Frontend/src/pages/Home.jsx
Executable file
@@ -0,0 +1,231 @@
|
||||
import { Helmet } from "react-helmet";
|
||||
import { useOutletContext } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
import "../scss/home.scss";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { useWildCoin } from "../components/WildCoin/WildCoinContext";
|
||||
|
||||
export default function Home() {
|
||||
const [toggleSnow, setToggleSnow] = useOutletContext();
|
||||
Home.propTypes = {
|
||||
setToggleSnow: PropTypes.function,
|
||||
toggleSnow: PropTypes.bool,
|
||||
}.isRequired;
|
||||
|
||||
const { biere, setBiere, santaDrunk, setSantaDrunk } = useWildCoin();
|
||||
|
||||
var snow = {
|
||||
wind: 0,
|
||||
maxXrange: 40,
|
||||
minXrange: 20,
|
||||
maxSpeed: 1,
|
||||
minSpeed: 3,
|
||||
color: "#fff",
|
||||
char: "*",
|
||||
maxSize: 32,
|
||||
minSize: 10,
|
||||
|
||||
flakes: [],
|
||||
WIDTH: -10,
|
||||
HEIGHT: 0,
|
||||
|
||||
init: function (nb) {
|
||||
var o = this,
|
||||
frag = document.createDocumentFragment();
|
||||
o.getSize();
|
||||
|
||||
for (var i = 0; i < nb; i++) {
|
||||
var flake = {
|
||||
x: o.random(o.WIDTH),
|
||||
y: -o.maxSize,
|
||||
xrange: o.minXrange + o.random(o.maxXrange - o.minXrange),
|
||||
yspeed: o.minSpeed + o.random(o.maxSpeed - o.minSpeed, 100),
|
||||
life: 0,
|
||||
size: o.minSize + o.random(o.maxSize - o.minSize),
|
||||
html: document.createElement("span"),
|
||||
};
|
||||
|
||||
flake.html.style.position = "absolute";
|
||||
flake.html.style.top = flake.y + "px";
|
||||
flake.html.style.left = flake.x + "px";
|
||||
flake.html.style.fontSize = flake.size + "px";
|
||||
flake.html.style.color = o.color;
|
||||
flake.html.appendChild(document.createTextNode(o.char));
|
||||
frag.appendChild(flake.html);
|
||||
flake.html.style.userSelect = "none";
|
||||
flake.html.style.overflow = "hidden";
|
||||
o.flakes.push(flake);
|
||||
}
|
||||
|
||||
document.body.appendChild(frag);
|
||||
o.animate();
|
||||
|
||||
window.onresize = function () {
|
||||
o.getSize();
|
||||
};
|
||||
},
|
||||
|
||||
animate: function () {
|
||||
var o = this;
|
||||
for (var i = 0, c = o.flakes.length; i < c; i++) {
|
||||
var flake = o.flakes[i],
|
||||
top = flake.y + flake.yspeed,
|
||||
left = flake.x + Math.sin(flake.life) * flake.xrange + o.wind;
|
||||
if (
|
||||
top < o.HEIGHT - flake.size - 10 &&
|
||||
left < o.WIDTH - flake.size &&
|
||||
left > 0
|
||||
) {
|
||||
flake.html.style.top = top + "px";
|
||||
flake.html.style.left = left + "px";
|
||||
flake.y = top;
|
||||
flake.x += o.wind;
|
||||
flake.life += 0.01;
|
||||
} else {
|
||||
flake.html.style.top = -o.maxSize + "px";
|
||||
flake.x = o.random(o.WIDTH);
|
||||
flake.y = -o.maxSize;
|
||||
flake.html.style.left = flake.x + "px";
|
||||
flake.life = 0;
|
||||
}
|
||||
}
|
||||
setTimeout(function () {
|
||||
o.animate();
|
||||
}, 20);
|
||||
},
|
||||
|
||||
stop: function () {
|
||||
for (var i = 0, c = this.flakes.length; i < c; i++) {
|
||||
document.body.removeChild(this.flakes[i].html);
|
||||
}
|
||||
this.flakes = [];
|
||||
},
|
||||
|
||||
random: function (range, num) {
|
||||
num = num ? num : 1;
|
||||
return Math.floor(Math.random() * (range + 1) * num) / num;
|
||||
},
|
||||
|
||||
getSize: function () {
|
||||
this.WIDTH = document.body.clientWidth || window.innerWidth;
|
||||
this.HEIGHT = document.body.clientHeight || window.innerHeight;
|
||||
},
|
||||
};
|
||||
|
||||
const { incrementClick, incrementWildCoin } = useWildCoin();
|
||||
|
||||
const createParticle = (x, y) => {
|
||||
const cookieClicks = document.querySelector(".pieces");
|
||||
|
||||
const particle = document.createElement("a");
|
||||
particle.style.backgroundImage = "url('/png/w-coin.png')";
|
||||
particle.setAttribute("class", "pieces-particle");
|
||||
particle.style.left = x + "%";
|
||||
particle.style.bottom = y + "px";
|
||||
|
||||
cookieClicks.appendChild(particle);
|
||||
|
||||
setTimeout(() => {
|
||||
cookieClicks.removeChild(particle);
|
||||
}, 1500);
|
||||
};
|
||||
|
||||
const handleIncrement = () => {
|
||||
incrementWildCoin(incrementClick);
|
||||
createParticle(50, 300);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (toggleSnow) {
|
||||
snow.init(10);
|
||||
} else {
|
||||
snow.stop();
|
||||
}
|
||||
|
||||
return () => {
|
||||
snow.stop();
|
||||
};
|
||||
}, [toggleSnow]);
|
||||
|
||||
useEffect(() => {
|
||||
const main = document.querySelector(".bghomecover");
|
||||
const santa = document.querySelector(".santaclaus");
|
||||
if (main !== undefined) {
|
||||
if (biere[1] >= 1) {
|
||||
santa.style.background = `url("/svg/SantaClause-drink.svg")`;
|
||||
if (santaDrunk === true) {
|
||||
main.style.filter = `blur(${biere[1]}px)`;
|
||||
|
||||
setTimeout(() => {
|
||||
console.count("setTimeOut");
|
||||
main.style.filter = `blur(0px)`;
|
||||
setSantaDrunk(false);
|
||||
}, biere[1] * 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [biere, setBiere]);
|
||||
|
||||
return (
|
||||
<main className="bghomecover">
|
||||
<Helmet>
|
||||
<meta
|
||||
name="description"
|
||||
content="Xmass Click votre nouveau Clicker préféré !"
|
||||
/>
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta
|
||||
name="googlebot"
|
||||
content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
|
||||
/>
|
||||
<meta
|
||||
name="bingbot"
|
||||
content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
|
||||
/>
|
||||
<link rel="canonical" href="https://xmass.click/" />
|
||||
<meta property="og:url" content="https://xmass.click/" />
|
||||
<meta property="og:site_name" content="Xmass Click" />
|
||||
<meta property="og:locale" content="fr_FR" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="mywebsite | title" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Xmass Click votre nouveau Clicker préféré !"
|
||||
/>
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://xmass.click/webp/share-cover.webp"
|
||||
/>
|
||||
<meta
|
||||
property="og:image:secure_url"
|
||||
content="https://xmass.click/webp/share-cover.webp"
|
||||
/>
|
||||
<meta property="og:image:width" content="584" />
|
||||
<meta property="og:image:height" content="384" />
|
||||
<meta property="fb:pages" content="" />
|
||||
<meta property="fb:admins" content="" />
|
||||
<meta property="fb:app_id" content="" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:site" content="" />
|
||||
<meta name="twitter:creator" content="" />
|
||||
<meta name="twitter:title" content="Xmass Click" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Xmass Click votre nouveau Clicker préféré !"
|
||||
/>
|
||||
<meta
|
||||
name="twitter:image"
|
||||
content="https://xmass.click/webp/share-cover.webp"
|
||||
/>
|
||||
|
||||
<title>Xmass Click</title>
|
||||
</Helmet>
|
||||
<div className="santaposition">
|
||||
<div className="pieces" />
|
||||
<div className="santaclaus" onClick={handleIncrement} />
|
||||
</div>
|
||||
<div className="boostList"></div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
53
Frontend/src/pages/Legal.jsx
Executable file
53
Frontend/src/pages/Legal.jsx
Executable file
@@ -0,0 +1,53 @@
|
||||
import "../scss/Legal.scss";
|
||||
function Legal() {
|
||||
return (
|
||||
<div className="mentionslegales">
|
||||
<h2>Éditeur :</h2>
|
||||
<p>
|
||||
Xmass'Click est un projet réalisé dans le cadre d'un hackathon sur 2
|
||||
jours.
|
||||
</p>
|
||||
|
||||
<h2>Coordonnées :</h2>
|
||||
<p>
|
||||
Téléphone : 04 22 52 10 10 <br />
|
||||
E-mail : pere-noel@laposte.net <br />
|
||||
Adresse : 250 avenue des Nuages, 1000 Pôle Nord <br />
|
||||
</p>
|
||||
|
||||
<h2>Responsabilité :</h2>
|
||||
<p>
|
||||
Xmass'Click décline toute responsabilité quant à l'utilisation du site.
|
||||
Les informations fournies sont à titre informatif et peuvent être
|
||||
sujettes à des erreurs.
|
||||
</p>
|
||||
|
||||
<h2>Propriété Intellectuelle :</h2>
|
||||
<p>
|
||||
Tout le contenu du site (textes, images, etc.) reste la propriété de
|
||||
Xmass'Click. Toute reproduction est interdite sans autorisation
|
||||
préalable.
|
||||
</p>
|
||||
|
||||
<h2>Protection des Données Personnelles :</h2>
|
||||
<p>
|
||||
Xmass'Click ne collecte pas de données personnelles. Aucune information
|
||||
personnelle n'est stockée lors de l'utilisation du site.
|
||||
</p>
|
||||
|
||||
<h2>Conditions Générales d'Utilisation :</h2>
|
||||
<p>
|
||||
Aucune condition générale d'utilisation n'est applicable. L'utilisation
|
||||
du site Xmass'Click se fait à titre gratuit et sans engagement.
|
||||
</p>
|
||||
|
||||
<h2>Loi Applicable :</h2>
|
||||
<p>
|
||||
Le présent site est régi par la loi du Pôle Nord. En cas de litige, les
|
||||
tribunaux du Père Noël seront compétents.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Legal;
|
||||
3
Frontend/src/scss/App.scss
Executable file
3
Frontend/src/scss/App.scss
Executable file
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
19
Frontend/src/scss/Cookie.scss
Executable file
19
Frontend/src/scss/Cookie.scss
Executable file
@@ -0,0 +1,19 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
max-width: 1280px;
|
||||
font-family: var(--font);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3rem;
|
||||
padding: 15rem 1rem 4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
font-family: var(--font);
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-grey);
|
||||
|
||||
}
|
||||
19
Frontend/src/scss/Legal.scss
Executable file
19
Frontend/src/scss/Legal.scss
Executable file
@@ -0,0 +1,19 @@
|
||||
.mentionslegales {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
max-width: 1280px;
|
||||
font-family: var(--font);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3rem;
|
||||
padding: 15rem 1rem 4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
|
||||
font-family: var(--font);
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-grey);
|
||||
|
||||
}
|
||||
31
Frontend/src/scss/achievements.scss
Executable file
31
Frontend/src/scss/achievements.scss
Executable file
@@ -0,0 +1,31 @@
|
||||
.fullachieve {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 10rem;
|
||||
background-color: var(--color-blue-light);
|
||||
width: 100%;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.achievementscontainer {
|
||||
margin: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-family: var(--font);
|
||||
font-size: 3rem;
|
||||
color: var(--color-grey);
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.achievementscardcontainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
min-height: 300px;
|
||||
gap: 3rem;
|
||||
}
|
||||
73
Frontend/src/scss/components/CardContact.scss
Executable file
73
Frontend/src/scss/components/CardContact.scss
Executable file
@@ -0,0 +1,73 @@
|
||||
|
||||
.Btn {
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition-duration: .4s;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
background-color: rgb(31, 31, 31);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svgIcon {
|
||||
transition-duration: .3s;
|
||||
}
|
||||
|
||||
.svgIcon path {
|
||||
fill: var(--color-white)
|
||||
}
|
||||
|
||||
.text {
|
||||
position: absolute;
|
||||
font-family: var(--font);
|
||||
color: var(--color-white);
|
||||
width: 120px;
|
||||
font-weight: 600;
|
||||
opacity: 0;
|
||||
transition-duration: .4s;
|
||||
}
|
||||
|
||||
.Btn:hover {
|
||||
width: 110px;
|
||||
transition-duration: .4s;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.Btn:hover .text {
|
||||
opacity: 1;
|
||||
transition-duration: .4s;
|
||||
}
|
||||
|
||||
.Btn:hover .svgIcon {
|
||||
opacity: 0;
|
||||
transition-duration: .3s;
|
||||
}
|
||||
|
||||
.cardContact {
|
||||
display: flex;
|
||||
min-width: 100px ;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cardContactContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.cardContact p {
|
||||
font-family: var(--font);
|
||||
color: var(--color-grey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
102
Frontend/src/scss/components/Hud.scss
Executable file
102
Frontend/src/scss/components/Hud.scss
Executable file
@@ -0,0 +1,102 @@
|
||||
.hudContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
|
||||
min-width: 260px;
|
||||
width: fit-content;
|
||||
max-width: 1280px;
|
||||
height: fit-content;
|
||||
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
background-color: var(--color-grey);
|
||||
color: var(--color-white);
|
||||
|
||||
font-family: var(--font);
|
||||
color: aliceblue;
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
z-index: 2;
|
||||
|
||||
.hudStats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.8rem;
|
||||
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.hudBooster {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
gap: 1rem;
|
||||
|
||||
min-width: 280px;
|
||||
width: auto;
|
||||
max-width: 1280px;
|
||||
height: fit-content;
|
||||
|
||||
color: var(--color-white);
|
||||
font-family: var(--font);
|
||||
color: aliceblue;
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.boosterItem {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
gap: 0.6rem;
|
||||
|
||||
.boosterIcon {
|
||||
width: 100%;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
.countbox {
|
||||
position: absolute;
|
||||
margin-top: 20px;
|
||||
margin-left: 15px;
|
||||
border: solid 1px var(--color-white);
|
||||
background-color: var(--color-white);
|
||||
border-radius: 20%;
|
||||
padding: 0.1rem;
|
||||
color: var(--color-grey);
|
||||
min-width: 20px;
|
||||
width: fit-content;
|
||||
height: 20px;
|
||||
box-shadow: -1px -1px 7px 0px var(--color-grey);
|
||||
}
|
||||
.boosterCount {
|
||||
font-family: var(--font);
|
||||
font-size: 0.7rem;
|
||||
text-align: center;
|
||||
font-weight: 900;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Frontend/src/scss/components/achievementscard.scss
Executable file
33
Frontend/src/scss/components/achievementscard.scss
Executable file
@@ -0,0 +1,33 @@
|
||||
.achievCardcontainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border: solid 0.05rem;
|
||||
max-width: 250px;
|
||||
border-radius: 1rem;
|
||||
background-color: rgb(255, 255, 255);
|
||||
margin-bottom: 1rem;
|
||||
box-shadow: 1px 1px 10px 2px var(--color-grey);
|
||||
|
||||
}
|
||||
|
||||
.achievecardpicture {
|
||||
width: 100%;
|
||||
border-radius: 1rem 1rem 0 0;
|
||||
}
|
||||
|
||||
.achievname {
|
||||
font-size: 1.2rem;
|
||||
margin-top: 0.2rem;
|
||||
font-family: var(--font);
|
||||
text-align: center;
|
||||
color:rgb(29, 30, 30);
|
||||
}
|
||||
.achievdescription {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
color: var(--color-grey);
|
||||
font-family: var(--font);
|
||||
color:rgb(25, 25, 26);
|
||||
padding: 1rem;
|
||||
}
|
||||
76
Frontend/src/scss/components/boutiquecard.scss
Executable file
76
Frontend/src/scss/components/boutiquecard.scss
Executable file
@@ -0,0 +1,76 @@
|
||||
.shopcardcontainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 300px;
|
||||
min-height: 520px;
|
||||
padding: 1rem;
|
||||
border-radius: 1rem;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--color-white);
|
||||
|
||||
font-family: var(--font);
|
||||
|
||||
.shopcontainer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
|
||||
.cardpicture {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
padding: 3rem;
|
||||
background-size: 50%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 10px;
|
||||
background-color: var(--color-purple-light);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.titlesection {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 1rem;
|
||||
|
||||
.itemname {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-grey);
|
||||
}
|
||||
|
||||
.price {
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
color: var(--color-grey);
|
||||
.itemprice {
|
||||
font-weight: 600;
|
||||
color: var(--color-red-light);
|
||||
}
|
||||
.priceicon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background-image: url("/png/w-coin.png");
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
color: var(--color-grey);
|
||||
}
|
||||
}
|
||||
.buttoncard {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
46
Frontend/src/scss/components/buttons.scss
Executable file
46
Frontend/src/scss/components/buttons.scss
Executable file
@@ -0,0 +1,46 @@
|
||||
.primary-button {
|
||||
display: flex;
|
||||
padding: 0.6rem 1rem;
|
||||
|
||||
height: fit-content;
|
||||
background-color: var(--color-red-light);
|
||||
border-radius: 0.6rem;
|
||||
justify-content: center;
|
||||
|
||||
text-decoration: none;
|
||||
font-family: var(--font);
|
||||
color: var(--color-white) !important;
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
transition: transform 0.1s ease-in-out;
|
||||
|
||||
border: none;
|
||||
&:hover {
|
||||
transform: scale(0.95);
|
||||
background-color: var(--color-red-light);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-button {
|
||||
display: flex;
|
||||
padding: 1rem 1rem;
|
||||
background-color: var(--color-white);
|
||||
border-radius: 0.6rem;
|
||||
justify-content: center;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
text-decoration: none;
|
||||
font-family: var(--font);
|
||||
color: var(--color-grey)!important;
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
transition: transform 0.1s ease-in-out;
|
||||
border: none;
|
||||
&:hover {
|
||||
transform: scale(0.95);
|
||||
background-color: var(--color-grey-hover);
|
||||
}
|
||||
}
|
||||
|
||||
92
Frontend/src/scss/components/footer.scss
Executable file
92
Frontend/src/scss/components/footer.scss
Executable file
@@ -0,0 +1,92 @@
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: var(--bg-color);
|
||||
border-top: solid 1px var(--color-grey);
|
||||
padding: 2rem 0;
|
||||
gap: 2rem;
|
||||
|
||||
|
||||
.footer-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
width: 90%;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.footer-logo {
|
||||
background-image: url(/svg/logo.svg);
|
||||
background-size: contain;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
width: 250px;
|
||||
height: 100px;
|
||||
transition: all 0.15s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
gap: 1.4rem;
|
||||
|
||||
.section-title {
|
||||
font-family: var(--font);
|
||||
font-size: 1.2rem;
|
||||
color: var(--color-grey);
|
||||
text-decoration-line: underline;
|
||||
text-underline-offset: 0.5rem;
|
||||
}
|
||||
|
||||
.section-text {
|
||||
max-width: 26ch;
|
||||
font-family: var(--font);
|
||||
font-size: 1rem;
|
||||
color: var(--color-grey);
|
||||
}
|
||||
.section-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
|
||||
gap: 1rem;
|
||||
list-style: none;
|
||||
|
||||
.section-item,
|
||||
a {
|
||||
width: fit-content;
|
||||
font-family: var(--font);
|
||||
font-size: 1rem;
|
||||
color: var(--color-grey);
|
||||
transition: all 0.15s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.spacing {
|
||||
min-width: 150px;
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
font-family: var(--font);
|
||||
font-size: 0.8rem;
|
||||
font-weight: 300;
|
||||
color: var(--color-grey);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
284
Frontend/src/scss/components/navbar.scss
Executable file
284
Frontend/src/scss/components/navbar.scss
Executable file
@@ -0,0 +1,284 @@
|
||||
.header-main {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
padding: 0rem 2rem;
|
||||
top: 0;
|
||||
background-color: var(--bg-color);
|
||||
background-blend-mode: darken;
|
||||
background-size: cover;
|
||||
z-index: 99;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
|
||||
@media (max-width: 999px) {
|
||||
padding: 0rem 0.4rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
width: 5rem;
|
||||
content: url(/svg/logo.svg);
|
||||
transition: 0.2s;
|
||||
|
||||
&:hover {
|
||||
width: 5rem;
|
||||
transition: 0.2s;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 1rem;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
|
||||
.nav-list {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1.6rem;
|
||||
align-items: center;
|
||||
|
||||
@media screen and (max-width: 999px) {
|
||||
display: none;
|
||||
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
font-family: var(--font);
|
||||
font-weight: 300;
|
||||
font-size: 1rem;
|
||||
color: var(--color-white);
|
||||
height: 100%;
|
||||
|
||||
|
||||
|
||||
.mainLink {
|
||||
text-decoration: none;
|
||||
color: var(--color-grey);
|
||||
font-weight: 500;
|
||||
padding: 30px 0;
|
||||
|
||||
|
||||
|
||||
&:hover {
|
||||
color: var(--color-red-light);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.dropLink {
|
||||
text-decoration: none;
|
||||
color: var(--color-white);
|
||||
font-weight: 400;
|
||||
|
||||
|
||||
&:hover {
|
||||
color: var(--color-red-light);
|
||||
font-weight: 400;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
@media screen and (max-width: 999px) {
|
||||
color: var(--color-white) !important;
|
||||
}
|
||||
li {
|
||||
float: left;
|
||||
width: fit-content;
|
||||
|
||||
|
||||
|
||||
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background: var(--color-black);
|
||||
transform: translateY(30px);
|
||||
min-width: 160px;
|
||||
box-shadow: 0px 8px 16px 0px rgba(10, 10, 10, 0.2);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
li.dropdown {
|
||||
display: inline-block;
|
||||
|
||||
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-white);
|
||||
width: fit-content;
|
||||
}
|
||||
a:hover,
|
||||
.dropdown:hover {
|
||||
color: var(--color-red-light);
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.dropdown-content a {
|
||||
color: var(--color-black);
|
||||
padding: 12px 16px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
|
||||
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-black);
|
||||
color: var(--color-gold);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown:hover .dropdown-content {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1000px) {
|
||||
.menuToggle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 999px) {
|
||||
.menuToggle {
|
||||
float: left;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
top: 2px;
|
||||
left: -10px;
|
||||
z-index: 99;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.menuToggle a {
|
||||
text-decoration: none;
|
||||
color: var(--color-grey);
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
.menuToggle a:hover {
|
||||
color: var(--color-red-light);
|
||||
}
|
||||
.menuToggle input {
|
||||
display: block;
|
||||
width: 40px;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
left: -5px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
-webkit-touch-callout: none;
|
||||
}
|
||||
.menuToggle span {
|
||||
display: block;
|
||||
width: 33px;
|
||||
height: 4px;
|
||||
margin-bottom: 5px;
|
||||
position: relative;
|
||||
background: var(--color-grey);
|
||||
border-radius: 3px;
|
||||
z-index: 1;
|
||||
transform-origin: 4px 0px;
|
||||
transition: transform 0.2s cubic-bezier(0.77, 0.2, 0.05, 1),
|
||||
background 0.2s cubic-bezier(0.77, 0.2, 0.05, 1), opacity 0.55s ease;
|
||||
}
|
||||
.menuToggle span:first-child {
|
||||
transform-origin: 0% 0%;
|
||||
}
|
||||
.menuToggle span:nth-last-child(2) {
|
||||
transform-origin: 0% 100%;
|
||||
}
|
||||
.menuToggle input:checked ~ span {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg) translate(-2px, -1px);
|
||||
background: var(--color-white);
|
||||
}
|
||||
.menuToggle input:checked ~ span:nth-last-child(3) {
|
||||
opacity: 0;
|
||||
transform: rotate(0deg) scale(0.2, 0.2);
|
||||
}
|
||||
.menuToggle input:checked ~ span:nth-last-child(2) {
|
||||
transform: rotate(-45deg) translate(0, -1px);
|
||||
}
|
||||
|
||||
.menu {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 280px;
|
||||
height: 110vh;
|
||||
margin: -100px 0 0 -231px;
|
||||
padding: 1.2rem;
|
||||
padding-top: 100px;
|
||||
background: var(--color-grey);
|
||||
list-style-type: none;
|
||||
transform-origin: 0% 0%;
|
||||
overflow: hidden !important;
|
||||
visibility: hidden;
|
||||
opacity: 0%;
|
||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
||||
|
||||
|
||||
|
||||
}
|
||||
.menu li {
|
||||
|
||||
padding: 10px 0;
|
||||
font-size: 1.2rem;
|
||||
font-family: var(--font);
|
||||
font-weight: 500;
|
||||
color: var(--color-white);
|
||||
|
||||
}
|
||||
.menuToggle input:checked ~ ul {
|
||||
visibility: visible;
|
||||
opacity: 100;
|
||||
|
||||
|
||||
|
||||
}
|
||||
.sousmenu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 1.2rem;
|
||||
color: var(--color-white);
|
||||
font-size: 1.2rem;
|
||||
font-family: var(--font);
|
||||
font-weight: 500;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
}
|
||||
.empty {
|
||||
line-height: 20rem;
|
||||
}
|
||||
}
|
||||
|
||||
.wildCoin {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: var(--font);
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-grey);
|
||||
}
|
||||
58
Frontend/src/scss/home.scss
Executable file
58
Frontend/src/scss/home.scss
Executable file
@@ -0,0 +1,58 @@
|
||||
.bghomecover {
|
||||
background-image: url("/webp/bg-cover.webp");
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: bottom;
|
||||
width: 100%;
|
||||
filter: blur(0px);
|
||||
transition: filter 1s ease-in-out;
|
||||
}
|
||||
.santaposition {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: end;
|
||||
|
||||
.santaclaus {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 5vh;
|
||||
|
||||
min-width: 320px;
|
||||
width: 320px;
|
||||
min-height: 320px;
|
||||
height: 320px;
|
||||
z-index: 1;
|
||||
|
||||
background: url("/svg/SantaClause-bag.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
transform: rotate(2deg);
|
||||
}
|
||||
}
|
||||
|
||||
.pieces-particle {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
animation: pieces-up 1.5s linear forwards;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
@keyframes pieces-up {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate3d(0, 1, 0, 180deg);
|
||||
opacity: 0;
|
||||
bottom: 100%;
|
||||
}
|
||||
}
|
||||
171
Frontend/src/scss/pages.scss
Executable file
171
Frontend/src/scss/pages.scss
Executable file
@@ -0,0 +1,171 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 132ch;
|
||||
width: 80%;
|
||||
gap: 3rem;
|
||||
margin: 150px auto 50px;
|
||||
|
||||
h1 {
|
||||
font-family: var(--font);
|
||||
color: var(--color-black);
|
||||
font-size: 1.8rem;
|
||||
text-align: center;
|
||||
width: fit-content;
|
||||
}
|
||||
.separator {
|
||||
border: solid 1px var(--color-gold-hover);
|
||||
}
|
||||
|
||||
.massageinfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
|
||||
.info {
|
||||
font-family: var(--font);
|
||||
color: var(--color-grey);
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-family: var(--font);
|
||||
color: var(--color-black);
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
|
||||
.subtitle {
|
||||
font-family: var(--font);
|
||||
color: var(--color-black);
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.paragraphe {
|
||||
font-family: var(--font);
|
||||
color: var(--color-grey);
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
margin-bottom: 0.5rem;
|
||||
list-style: inside;
|
||||
|
||||
a {
|
||||
font-family: var(--font);
|
||||
color: var(--color-gold-link);
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
list-style: inside;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-gold-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
.picture-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
|
||||
@media (max-width: 449px) {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.picture {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Massages pages
|
||||
|
||||
.listing-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 3rem;
|
||||
|
||||
.listcontent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.listdetail {
|
||||
font-family: var(--font);
|
||||
color: var(--color-grey);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 400;
|
||||
margin-bottom: 0.5rem;
|
||||
list-style-type: none;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//error pages
|
||||
section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 90vh;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
|
||||
.containererror {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
|
||||
h1 {
|
||||
font-family: var(--font);
|
||||
color: var(--color-black);
|
||||
font-size: 2rem;
|
||||
text-align: center;
|
||||
width: fit-content;
|
||||
}
|
||||
.message {
|
||||
font-family: var(--font);
|
||||
color: var(--color-grey);
|
||||
font-size: 1rem;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-return {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: fit-content;
|
||||
margin: auto;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: var(--color-grey);
|
||||
border: none;
|
||||
border-radius: 0.6rem;
|
||||
font-family: var(--font);
|
||||
color: var(--color-white);
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-grey);
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
Frontend/src/scss/root.scss
Executable file
31
Frontend/src/scss/root.scss
Executable file
@@ -0,0 +1,31 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
:root {
|
||||
--color-blue-light: #dcecf3;
|
||||
--color-purple-light: #e4e3f3;
|
||||
--color-red-light: #c33636;
|
||||
--color-white: #ffffff;
|
||||
--color-light: #eaeaea;
|
||||
--color-grey: #202020;
|
||||
--color-grey-hover: #606060;
|
||||
|
||||
--bg-color: var(--color-blue-light);
|
||||
|
||||
--font: "Hanken Grotesk", sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
main {
|
||||
min-height: 92vh;
|
||||
margin-top: 80px;
|
||||
padding: 0 0 2rem;
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
26
Frontend/src/scss/shop.scss
Executable file
26
Frontend/src/scss/shop.scss
Executable file
@@ -0,0 +1,26 @@
|
||||
|
||||
.shoppagecontainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
padding: 12rem 0 4rem;
|
||||
|
||||
h1 {
|
||||
font-family: var(--font);
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-grey);
|
||||
}
|
||||
.cardcontainer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
max-width: 1280px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
0
Frontend/src/services/.gitkeep
Executable file
0
Frontend/src/services/.gitkeep
Executable file
Reference in New Issue
Block a user