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
9 changes: 2 additions & 7 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,15 @@
},
"dependencies": {
"@radix-ui/react-dialog": "^1.1.11",
"howler": "^2.2.4",
"lucide-react": "^0.503.0",
"react": "^19.1.0",
"react-dom": "^19.0.0",
"react-router-dom": "^6.30.0"
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@tailwindcss/postcss": "^4.1.4",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@types/react-howler": "^5.2.3",
"@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.21",
"eslint": "^9.21.0",
Expand Down
42 changes: 21 additions & 21 deletions client/src/components/BackgroundMusic.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { useEffect } from 'react';
// import { useEffect } from 'react';

const BackgroundMusic = () => {
useEffect(() => {
const audio = new Audio('/80s-loop-5.wav'); // or '/background-music.mp3'
audio.loop = true;
audio.volume = 0.5;
// const BackgroundMusic = () => {
// useEffect(() => {
// const audio = new Audio('/80s-loop-5.wav'); // or '/background-music.mp3'
// audio.loop = true;
// audio.volume = 0.5;

// Try autoplay inside a user interaction-friendly trigger
const playAudio = () => {
audio.play().catch((err) => {
console.warn('Autoplay blocked by browser:', err);
});
};
// // Try autoplay inside a user interaction-friendly trigger
// const playAudio = () => {
// audio.play().catch((err) => {
// console.warn('Autoplay blocked by browser:', err);
// });
// };

// Listen for first click
document.body.addEventListener('click', playAudio, { once: true });
// // Listen for first click
// document.body.addEventListener('click', playAudio, { once: true });

return () => {
audio.pause();
};
}, []);
// return () => {
// audio.pause();
// };
// }, []);

return null;
};
// return null;
// };

export default BackgroundMusic;
// export default BackgroundMusic;
33 changes: 33 additions & 0 deletions client/src/components/ModalBase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// src/components/ModalBase.tsx

"use client";

import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";

interface ModalBaseProps {
open: boolean;
onOpenChange: (open: boolean) => void;
title: string;
description?: string;
children?: React.ReactNode;
}

const ModalBase = ({ open, onOpenChange, title, description, children }: ModalBaseProps) => {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle className="text-center text-2xl font-bold">{title}</DialogTitle>
{description && (
<DialogDescription className="text-center text-zinc-300">
{description}
</DialogDescription>
)}
</DialogHeader>
{children}
</DialogContent>
</Dialog>
);
};

export default ModalBase;
4 changes: 0 additions & 4 deletions client/src/components/ModalBasel.tsx

This file was deleted.

30 changes: 27 additions & 3 deletions client/src/components/NarrationModal.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
- Imports ModalBase
- Passes variant='narration'
- Can include avatar or sprite of Dr. Dan, text-only
// src/components/NarrationModal.tsx

"use client";

import ModalBase from "@/components/ModalBase";

interface NarrationModalProps {
isOpen: boolean;
onClose: () => void;
text: string;
}

const NarrationModal = ({ isOpen, onClose, text }: NarrationModalProps) => {
return (
<ModalBase
open={isOpen}
onOpenChange={(open: boolean) => { if (!open) onClose(); }}
title="Narration"
description={text}
>
{/* Optional: You can add more children here later if needed */}
</ModalBase>
);
};

export default NarrationModal;

27 changes: 23 additions & 4 deletions client/src/components/ResponseModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
- Imports ModalBase
- Passes variant='response'
- Includes buttons for Try Again or Next
- Custom feedback messages
"use client"

import ModalBase from "@/components/ModalBase";

interface ResponseModalProps {
isOpen: boolean;
onClose: () => void;
text: string;

}

const ResponseModal = ({ isOpen, onClose, text }: ResponseModalProps) => {
return (
<ModalBase
open={isOpen}
onOpenChange={(open: boolean) => { if(!open) onClose(); }}
title="Narration"
description={text}
>
</ModalBase>
);
};
export default ResponseModal;
36 changes: 25 additions & 11 deletions client/src/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const DialogPortal = ({ ...props }: DialogPrimitive.DialogPortalProps) => (
);

const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
Expand All @@ -29,19 +29,20 @@ const DialogOverlay = React.forwardRef<
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;

const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed z-[70] left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-lg rounded-xl bg-white dark:bg-zinc-900 p-6 shadow-2xl transition-all duration-300 ease-in-out",
className
)}
{...props}
>
ref={ref}
className={cn(
"fixed z-[70] left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-lg rounded-2xl bg-gradient-to-b from-blue-950 to-black text-white p-6 shadow-2xl ring-4 ring-blue-400/50 transition-all duration-500 ease-in-out animate-fadeIn",
className
)}
{...props}
>

<div className="space-y-4">{children}</div>
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2">
<X className="h-4 w-4" />
Expand All @@ -63,7 +64,7 @@ const DialogHeader = ({
DialogHeader.displayName = "DialogHeader";

const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
Expand All @@ -74,10 +75,23 @@ const DialogTitle = React.forwardRef<
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;

const DialogDescription = React.forwardRef<
React.ComponentRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;

export {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle
DialogTitle,
DialogDescription
};
Loading