Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,405 changes: 1,275 additions & 130 deletions client/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
Expand All @@ -18,6 +18,7 @@
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-howler": "^5.2.0",
"react-markdown": "^10.1.0",
"react-router-dom": "^7.5.2"
},
"devDependencies": {
Expand Down
Binary file added client/public/alienScream.mp3
Binary file not shown.
Binary file added client/public/cave-monster.mp3
Binary file not shown.
Binary file added client/public/mad-keyboard-typing.mp3
Binary file not shown.
Binary file added client/public/snakeHiss.mp3
Binary file not shown.
5 changes: 2 additions & 3 deletions client/src/components/DanismEvent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState, useEffect } from "react";
import NarrationModal from "@/components/NarrationModal";
import { useState, useEffect } from "react";
import SoundPlayer from "@/components/SoundPlayer";
import { preloadSounds } from "../Utils/preloadSounds";
import { preloadSounds } from "../utils/preloadSounds";
import { getRandomDanismAndSound } from "../utils/handleAnswer";


Expand Down
24 changes: 12 additions & 12 deletions client/src/components/MinionModal.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";

interface MinionModalProps {
isOpen: boolean;
onClose: () => void;
minionName: string;
minionQuote: string;
colorClass?: string;
}

const MinionModal = ({ isOpen, onClose, minionName, minionQuote }: MinionModalProps) => {
const MinionModal = ({ isOpen, minionName, minionQuote, colorClass }: MinionModalProps) => {
if (!isOpen) return null;

return (
<Dialog open={isOpen} onOpenChange={(open) => { if (!open) onClose(); }}>
<DialogContent>
<DialogHeader>
<DialogTitle>{minionName} Appears!</DialogTitle>
</DialogHeader>
<p>{minionQuote}</p>
</DialogContent>
</Dialog>
<div
className={`absolute -top-14 left-1/2 -translate-x-1/2 px-3 py-2 rounded-lg text-sm shadow-lg whitespace-nowrap z-50 ${colorClass || "bg-gray-800 text-white"}`}
>
<strong>{minionName}</strong>: <em>{minionQuote}</em>
{/* Optional triangle tail */}
<div className="absolute left-1/2 translate-x-[-50%] top-full w-2 h-2 rotate-45 bg-inherit z-[-1]"></div>
</div>
);
};

export default MinionModal;

24 changes: 0 additions & 24 deletions client/src/components/NarrationModal.tsx

This file was deleted.

79 changes: 46 additions & 33 deletions client/src/components/screens/GameMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import Minion from './Minions';
import { preloadSounds } from '../../Utils/preloadSounds';
import { preloadSounds } from '../../utils/preloadSounds';
import '../../styles/codezilla.css';
import drDanImg from '../../../avatars/drdan2.png';
import flameImg from '../../assets/flame.png';
Expand Down Expand Up @@ -41,6 +41,9 @@ const GameMap: React.FC = () => {
image: '/minions/nullbyte3a.png',
name: 'Nullbyte',
questionId: 'q1',
taunt: "Don't blank out now... this should be easy.",
sound: '/public/cave-monster.mp3',
colorClass: 'bg-blue-600 text-white',
},
{
id: '2',
Expand All @@ -49,6 +52,9 @@ const GameMap: React.FC = () => {
image: '/minions/dbug2a.png',
name: 'Dbug',
questionId: 'q2',
taunt: "Let's squash some bugs... or get squashed.",
sound: '/public/alienScream.mp3',
colorClass: 'bg-yellow-500 text-black',
},
{
id: '3',
Expand All @@ -57,6 +63,9 @@ const GameMap: React.FC = () => {
image: '/minions/typerrorus.png',
name: 'Typerrorasaurus',
questionId: 'q3',
taunt: "Let’s see how you handle *this* error.",
sound: '/public/mad-keyboard-typing.mp3',
colorClass: 'bg-red-600 text-white',
},
{
id: '4',
Expand All @@ -65,6 +74,9 @@ const GameMap: React.FC = () => {
image: '/minions/pie-thon.png',
name: 'Pie-Thon',
questionId: 'q4',
taunt: "The only slice you'll get is defeat.",
sound: '/public/snakeHiss.mp3',
colorClass: 'bg-green-700 text-white',
},
{
id: '5',
Expand All @@ -73,6 +85,9 @@ const GameMap: React.FC = () => {
image: '/minions/codezilla2.png',
name: 'Codezilla',
questionId: 'q5',
taunt: "You dare challenge ME?",
sound: '/public/godzilla.roar.mp3',
colorClass: 'bg-purple-800 text-white',
},
];

Expand All @@ -95,7 +110,7 @@ const GameMap: React.FC = () => {
const pathId = `${nodes[currentIndex].id}-${nodes[currentIndex + 1].id}`;
setCompletedPaths(prev => [...prev, pathId]);
}
const minion = minions.find(m => m.questionId === questionId);
const minion = minions.find(m => m.questionId === questionId);
if (minion) {
setSelectedMinionId(minion.id);
}
Expand All @@ -121,7 +136,6 @@ const GameMap: React.FC = () => {
);
})}


{/* GLOWING OUTER CIRCLE + DARKER INNER CIRCLE */}
{nodes.map((node, index) => {
const isCompleted = index < completedPaths.length;
Expand All @@ -145,42 +159,40 @@ const GameMap: React.FC = () => {
})}
</svg>
<div className="dr-dan-wrapper">
<div className="glow-circle"></div>
<img src={drDanImg} alt="Dr. Dan" className="dr-dan-image" />
</div>

{selectedAvatar && (
<div className="player-avatar-wrapper">
<div className="player-glow-circle"></div>
<img src={selectedAvatar} alt="Your Avatar" className="player-avatar" />


<div className="player-info-wrapper">
<div className="player-info-box">
<p className="player-name">{username}</p>
<p className="player-level">Level 1</p>
<div className="glow-circle"></div>
<img src={drDanImg} alt="Dr. Dan" className="dr-dan-image" />
</div>

<div className="learning-info-box">
<p className='learning-title'> Studying</p>
<p className="learning-text">Coding Bootcamp</p>
</div>
{/* Lifeline Box */}
<div className='flames'>
<div className="lifeline-info-box">
<div className="lifeline-flames">
<p className='learning-title'> Life Lines</p>
<img src={flameImg} alt="Flame 1" />
<img src={flameImg} alt="Flame 2" />
<img src={flameImg} alt="Flame 3" />
</div>
{selectedAvatar && (
<div className="player-avatar-wrapper">
<div className="player-glow-circle"></div>
<img src={selectedAvatar} alt="Your Avatar" className="player-avatar" />

<div className="player-info-wrapper">
<div className="player-info-box">
<p className="player-name">{username}</p>
<p className="player-level">Level 1</p>
</div>

<div className="learning-info-box">
<p className='learning-title'> Studying</p>
<p className="learning-text">Coding Bootcamp</p>
</div>
{/* Lifeline Box */}
<div className='flames'>
<div className="lifeline-info-box">
<div className="lifeline-flames">
<p className='learning-title'> Life Lines</p>
<img src={flameImg} alt="Flame 1" />
<img src={flameImg} alt="Flame 2" />
<img src={flameImg} alt="Flame 3" />
</div>
</div>
</div>
</div>
</div>
)}


{minions.map((minion) => (
<Minion
key={minion.id}
Expand All @@ -191,12 +203,13 @@ const GameMap: React.FC = () => {
name={minion.name}
questionId={minion.questionId}
goToQuestion={goToQuestion}
size={3} // Add the size property with an appropriate value
size={120}
selectedMinionId={selectedMinionId}
taunt={minion.taunt}
sound={minion.sound}
colorClass={minion.colorClass}
/>
))}

</div>
);
};
Expand Down
81 changes: 55 additions & 26 deletions client/src/components/screens/Minions.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,86 @@
import React from 'react';
import React, { useState } from "react";
import MinionModal from "../MinionModal"; // Adjust path if needed

interface MinionProps {
id: string;
name: string;
image: string;
xPercent: number;
yPercent: number;
image: string;
name: string;
questionId: string;
goToQuestion: (questionId: string) => void;
size: number;
selectedMinionId: string | null;
goToQuestion: (id: string) => void;
size?: number;
selectedMinionId?: string | null;
taunt?: string;
sound?: string;
colorClass?: string;
}

const Minion: React.FC<MinionProps> = ({
id,
xPercent,
yPercent,
image,
name,
questionId,
const Minion: React.FC<MinionProps> = ({
id,
xPercent,
yPercent,
image,
name,
questionId,
goToQuestion,
selectedMinionId,
}) => {
taunt,
sound,
colorClass,
}) => {
const [showModal, setShowModal] = useState(false);
const isSelected = selectedMinionId === id;


const handleMouseEnter = () => {
setShowModal(true);
if (sound) {
const audio = new Audio(sound);
audio.play();
}
};

const handleMouseLeave = () => {
setShowModal(false);
};

return (
<div
id={`minion-${id}`}
className={`minion ${isSelected ? 'selected' : ''}`}

className={`minion ${isSelected ? "selected" : ""}`}
style={{
position: 'absolute',
position: "absolute",
top: `${yPercent}%`,
left: `${xPercent}%`,
width: '120px',
height: '120px',
transform: 'translate(-50%, -50%)',
cursor: 'pointer',
width: "120px",
height: "120px",
transform: "translate(-50%, -50%)",
cursor: "pointer",
zIndex: 2,
}}
onClick={() => goToQuestion(questionId)}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
title={name}
>
<img
src={image}
alt={name}
className='minion-image'
className="minion-image"
style={{
width: '100%',
height: '100%',
objectFit: 'contain',
width: "100%",
height: "100%",
objectFit: "contain",
}}
/>

<MinionModal
isOpen={showModal}
minionName={name}
minionQuote={taunt || ""}
colorClass={colorClass}
/>

</div>
);
};
Expand Down
Loading