feat: suppression boutique legacy + refonte achievements milestones Clickerz

- Suppression route /boutique + Boutique.jsx, BoutiqueCard.jsx, shop.json, scss associés
  (le GeneratorShop sidebar fait déjà le job)
- Refonte complète achievements : 27 milestones basés sur le GameState réel
  (paliers ressources, générateurs, prestige, évolution, easter eggs humour)
- Suppression ancien système JSON statique + AchievementsCard legacy
- Page achievements : unlocked/locked state-aware, compteur progression
This commit is contained in:
2026-03-20 14:34:48 +01:00
parent 0374602047
commit 0c9170af65
12 changed files with 360 additions and 734 deletions

View File

@@ -1,28 +0,0 @@
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;

View File

@@ -1,65 +0,0 @@
// BoutiqueCard.jsx — Legacy shop card (shop.json boosters)
// TODO: Migrate to economy.ts generator system in a future step
import "../scss/components/boutiquecard.scss";
import "../scss/components/buttons.scss";
import PropTypes from "prop-types";
import { useGameStore } from "../store/useGameStore";
export default function BoutiqueCard({
name,
price,
incrementValue,
description,
image,
type,
}) {
const resources = useGameStore((s) => s.state.resources);
// Legacy shop — disabled for now, generators are in GeneratorShop
const canAfford = resources >= price;
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
disabled={!canAfford}
className="primary-button"
style={{ opacity: canAfford ? 1 : 0.5 }}
>
Bientôt
</button>
</div>
</div>
);
}
BoutiqueCard.propTypes = {
name: PropTypes.string.isRequired,
price: PropTypes.number.isRequired,
incrementValue: PropTypes.number.isRequired,
description: PropTypes.string.isRequired,
image: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
};

View File

@@ -1,308 +0,0 @@
[
{
"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 sest attaqué à Chuck Norris. Depuis, il fait de lasthme."
},
{
"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": "Peau de grenouille rare",
"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": "Kit de survie du marais 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": "Couronne de nénuphars lumineuse",
"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 sest 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"
}
]

View File

@@ -0,0 +1,216 @@
// achievements.ts — Milestones Clickerz basés sur le GameState réel
import { GameState } from "../core/economy";
export interface Achievement {
id: string;
name: string;
description: string;
icon: string;
check: (state: GameState) => boolean;
}
function totalGeneratorsOwned(state: GameState): number {
return state.generators.reduce((sum, g) => sum + g.owned, 0);
}
function hasGenerator(state: GameState, genId: string): boolean {
return state.generators.some((g) => g.id === genId && g.owned > 0);
}
function hasEvolutionNode(state: GameState, nodeId: string): boolean {
return state.evolutionTree.some((n) => n.id === nodeId && n.unlocked);
}
export const ACHIEVEMENTS: Achievement[] = [
// --- Paliers de ressources ---
{
id: "first_tadpole",
name: "Premier Têtard",
description: "Faire éclore son tout premier têtard.",
icon: "🥚",
check: (s) => s.resources >= 1 || s.lifetimeTadpoles >= 1,
},
{
id: "colony",
name: "Colonie",
description: "Atteindre 100 têtards.",
icon: "🌱",
check: (s) => s.resources >= 100 || s.lifetimeTadpoles >= 100,
},
{
id: "village",
name: "Village",
description: "Atteindre 1 000 têtards.",
icon: "🏘️",
check: (s) => s.resources >= 1_000 || s.lifetimeTadpoles >= 1_000,
},
{
id: "city",
name: "Cité",
description: "Atteindre 10 000 têtards.",
icon: "🏙️",
check: (s) => s.resources >= 10_000 || s.lifetimeTadpoles >= 10_000,
},
{
id: "metropolis",
name: "Métropole",
description: "Atteindre 100 000 têtards.",
icon: "🌆",
check: (s) => s.resources >= 100_000 || s.lifetimeTadpoles >= 100_000,
},
{
id: "empire",
name: "Empire du Marais",
description: "Atteindre 1 000 000 de têtards.",
icon: "👑",
check: (s) => s.resources >= 1_000_000 || s.lifetimeTadpoles >= 1_000_000,
},
// --- Générateurs ---
{
id: "first_nid",
name: "Nidificateur",
description: "Construire son premier Nid.",
icon: "🪹",
check: (s) => hasGenerator(s, "nid"),
},
{
id: "first_mare",
name: "Batracien",
description: "Aménager sa première Mare.",
icon: "💧",
check: (s) => hasGenerator(s, "mare"),
},
{
id: "first_marecage",
name: "Marécageux",
description: "S'enfoncer dans son premier Marécage.",
icon: "🌿",
check: (s) => hasGenerator(s, "marecage"),
},
{
id: "first_etang",
name: "Gardien de l'Étang",
description: "Découvrir un Étang Ancien.",
icon: "🏛️",
check: (s) => hasGenerator(s, "etang"),
},
{
id: "first_lac",
name: "Seigneur du Lac",
description: "Accéder au Lac Mystique.",
icon: "🔮",
check: (s) => hasGenerator(s, "lac"),
},
{
id: "industriel",
name: "Industriel",
description: "Posséder 10 générateurs au total.",
icon: "🏭",
check: (s) => totalGeneratorsOwned(s) >= 10,
},
{
id: "magnate",
name: "Magnate",
description: "Posséder 50 générateurs au total.",
icon: "💎",
check: (s) => totalGeneratorsOwned(s) >= 50,
},
{
id: "tycoon",
name: "Tycoon du Marais",
description: "Posséder 100 générateurs au total.",
icon: "🐸",
check: (s) => totalGeneratorsOwned(s) >= 100,
},
// --- Prestige ---
{
id: "first_prestige",
name: "Nouvelle Génération",
description: "Effectuer son premier prestige.",
icon: "🧬",
check: (s) => s.prestigeCount >= 1,
},
{
id: "veteran",
name: "Vétéran",
description: "Atteindre 5 prestiges.",
icon: "⭐",
check: (s) => s.prestigeCount >= 5,
},
{
id: "legend",
name: "Légende du Marais",
description: "Atteindre 10 prestiges.",
icon: "🏆",
check: (s) => s.prestigeCount >= 10,
},
// --- ADN & Évolution ---
{
id: "first_dna",
name: "ADN Ancestral",
description: "Accumuler son premier ADN.",
icon: "🧪",
check: (s) => s.ancestralDna >= 1,
},
{
id: "first_evolution",
name: "Première Mutation",
description: "Débloquer la Ponte Améliorée.",
icon: "🦎",
check: (s) => hasEvolutionNode(s, "ponte_amelioree"),
},
{
id: "full_tree",
name: "Évolution Complète",
description: "Débloquer tous les noeuds de l'arbre.",
icon: "🌳",
check: (s) => s.evolutionTree.every((n) => n.unlocked),
},
// --- Easter eggs & humour ---
{
id: "chuck_norris",
name: "Blague",
description: "Quand Chuck Norris fait un programme, il installe les modules, code et vend le programme... ensuite il demande à quoi il doit servir.",
icon: "🤜",
check: (s) => s.lifetimeTadpoles >= 42,
},
{
id: "patience",
name: "Patience de Têtard",
description: "Un têtard ne devient pas grenouille en un jour. Toi non plus visiblement.",
icon: "🐌",
check: (s) => hasGenerator(s, "nid") && s.resources < 50,
},
{
id: "brain_powered",
name: "Powered by Brain",
description: "Le Brain a codé ce succès avant de savoir pourquoi. Classique.",
icon: "🧠",
check: (s) => s.prestigeCount >= 1 && totalGeneratorsOwned(s) >= 10,
},
{
id: "marecage_addict",
name: "Addict au Marécage",
description: "T'as 10 marécages. Tu sens un peu la vase mais on respecte l'engagement.",
icon: "🫠",
check: (s) => s.generators.find((g) => g.id === "marecage")?.owned >= 10,
},
{
id: "overkill",
name: "Overkill",
description: "25 Nids. T'aurais pu investir dans un Lac, mais non.",
icon: "😅",
check: (s) => s.generators.find((g) => g.id === "nid")?.owned >= 25,
},
{
id: "symbiose_joke",
name: "Le Cercle de la Vie",
description: "Symbiose activée. Même Mufasa serait fier.",
icon: "🦁",
check: (s) => hasEvolutionNode(s, "symbiose"),
},
];

View File

@@ -1,92 +0,0 @@
[
{
"name": "Griffes de Grenouille",
"price": 15,
"incrementValue": 1,
"description": "Des griffes acérées pour une ponte plus efficace. +1 par clic.",
"link": "/",
"image": "./svg/Hand.svg",
"buyed": false,
"type": "actif"
},
{
"name": "Algues Nutritives",
"price": 15,
"incrementValue": 1,
"description": "Les algues nourrissent le marais en continu. +1 têtard/s.",
"link": "/",
"image": "./svg/Tasse.svg",
"buyed": false,
"type": "passif"
},
{
"name": "Crapaud Gardien",
"price": 150,
"incrementValue": 10,
"description": "Un ancien du marais qui veille sur les pontes. +10 par clic.",
"link": "/",
"image": "./svg/Bonhome.svg",
"buyed": false,
"type": "actif"
},
{
"name": "Nénuphar Géant",
"price": 150,
"incrementValue": 10,
"description": "Un nénuphar massif qui attire les têtards. +10 têtards/s.",
"link": "/",
"image": "./svg/Bonnet.svg",
"buyed": false,
"type": "passif"
},
{
"name": "Oeuf Doré",
"price": 1500,
"incrementValue": 100,
"description": "Un oeuf rare qui éclot en masse. +100 par clic.",
"link": "/",
"image": "./svg/Cookie.svg",
"buyed": false,
"type": "actif"
},
{
"name": "Mousse Lumineuse",
"price": 1500,
"incrementValue": 100,
"description": "La mousse phosphorescente accélère la croissance. +100 têtards/s.",
"link": "/",
"image": "./svg/Canne.svg",
"buyed": false,
"type": "passif"
},
{
"name": "Couronne de Roseaux",
"price": 15000,
"incrementValue": 1000,
"description": "Le symbole du Gardien suprême du Marais. +1000 par clic.",
"link": "/",
"image": "./svg/Courone.svg",
"buyed": false,
"type": "actif"
},
{
"name": "Esprit du Marais",
"price": 15000,
"incrementValue": 1000,
"description": "L'esprit ancestral bénit les eaux. +1000 têtards/s.",
"link": "/",
"image": "./svg/PainDep.svg",
"buyed": false,
"type": "passif"
},
{
"name": "Nectar de Lotus",
"price": 8000,
"incrementValue": 1000,
"description": "Un nectar enivrant qui trouble les eaux... mais booste la ponte. Attention aux effets secondaires.",
"link": "/",
"image": "./svg/Beer.svg",
"buyed": false,
"type": "actif"
}
]

View File

@@ -7,7 +7,6 @@ import ErrorPage from "./pages/404";
import Login from "./pages/Login";
import AuthCallback from "./pages/AuthCallback";
import { AuthProvider } from "./context/AuthContext";
import Boutique from "./pages/Boutique";
import Achievements from "./pages/Achievements";
import Legal from "./pages/Legal";
import Cookie from "./pages/Cookie";
@@ -25,10 +24,6 @@ const router = createBrowserRouter([
path: "/jeu",
element: <Home />,
},
{
path: "/boutique",
element: <Boutique />,
},
{
path: "/achievements",
element: <Achievements />,

View File

@@ -1,33 +1,41 @@
import { useState } from "react";
import AchievementsCard from "../components/AchievementsCard";
import "../scss/achievements.scss";
import { useGameStore } from "../store/useGameStore";
import achievements from "../data/Achievements.json";
import { ACHIEVEMENTS } from "../data/achievements";
import "../scss/achievements.scss";
function Achievements() {
const resources = useGameStore((s) => s.state.resources);
let score = 1;
if (resources >= 25) {
score = Math.floor((resources - 25) / 400) + 1;
} else {
score = 0;
}
const state = useGameStore((s) => s.state);
const unlocked = ACHIEVEMENTS.filter((a) => a.check(state));
const locked = ACHIEVEMENTS.filter((a) => !a.check(state));
return (
<div className="fullachieve">
<h1>Succès</h1>
<p className="achieve-counter">
{unlocked.length} / {ACHIEVEMENTS.length}
</p>
<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}
/>
);
})}
{unlocked.map((a) => (
<div key={a.id} className="achieve-card achieve-unlocked">
<span className="achieve-icon">{a.icon}</span>
<div className="achieve-info">
<p className="achieve-name">{a.name}</p>
<p className="achieve-desc">{a.description}</p>
</div>
</div>
))}
{locked.map((a) => (
<div key={a.id} className="achieve-card achieve-locked">
<span className="achieve-icon">🔒</span>
<div className="achieve-info">
<p className="achieve-name">{a.name}</p>
<p className="achieve-desc">???</p>
</div>
</div>
))}
</div>
</div>
</div>

View File

@@ -1,32 +0,0 @@
import BoutiqueCard from "../components/BoutiqueCard";
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>
);
}

View File

@@ -1,31 +1,98 @@
.fullachieve {
display: flex;
flex-direction: column;
padding-top: 10rem;
padding-top: 6rem;
padding-bottom: 3rem;
background-color: var(--color-blue-light);
width: 100%;
max-width: 1280px;
margin: 0 auto;
min-height: 80vh;
h1 {
text-align: center;
font-family: var(--font);
font-size: 2.5rem;
color: var(--color-grey);
margin-bottom: 0.5rem;
}
}
.achieve-counter {
text-align: center;
font-family: var(--font);
font-size: 1.1rem;
color: var(--color-grey);
opacity: 0.7;
margin-bottom: 2rem;
}
.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;
width: 100%;
padding: 0 2rem;
}
.achievementscardcontainer {
display: flex;
justify-content: center;
flex-wrap: wrap;
min-height: 300px;
gap: 3rem;
min-height: 200px;
gap: 1rem;
width: 100%;
}
.achieve-card {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem 1.2rem;
border-radius: 0.75rem;
width: 100%;
max-width: 380px;
transition: transform 0.15s ease;
&:hover {
transform: translateY(-2px);
}
}
.achieve-unlocked {
background: rgba(16, 185, 129, 0.12);
border: 1px solid rgba(16, 185, 129, 0.3);
}
.achieve-locked {
background: rgba(107, 114, 128, 0.08);
border: 1px solid rgba(107, 114, 128, 0.15);
opacity: 0.5;
}
.achieve-icon {
font-size: 2rem;
flex-shrink: 0;
width: 3rem;
text-align: center;
}
.achieve-info {
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.achieve-name {
font-family: var(--font);
font-size: 1rem;
font-weight: 600;
color: var(--color-grey);
}
.achieve-desc {
font-family: var(--font);
font-size: 0.85rem;
color: var(--color-grey);
opacity: 0.7;
}

View File

@@ -1,33 +0,0 @@
.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;
}

View File

@@ -1,76 +0,0 @@
.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("/svg/tadpole.svg");
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
}
}
.description {
font-size: 1rem;
font-weight: 400;
color: var(--color-grey);
}
}
.buttoncard {
width: 100%;
}
}

View File

@@ -1,26 +0,0 @@
.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;
}
}