Skip to content

Commit

Permalink
Merge pull request #49 from hack4impact-calpoly/selected_POI_page_com…
Browse files Browse the repository at this point in the history
…ponent

Selected POI Page Component
  • Loading branch information
emily-yarvis authored Feb 19, 2025
2 parents 89d3864 + 9aea03a commit b6f678e
Show file tree
Hide file tree
Showing 7 changed files with 373 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

#env
/.env

# dependencies
/node_modules
/.pnp
Expand Down
Binary file added public/lcslo_placeholder.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import Navbar from "@/components/Navbar";
import POICardList from "@/components/POICardList";

export default function Home() {
return (
<main>
<Navbar />

<POICardList></POICardList>
</main>
);
Expand Down
108 changes: 108 additions & 0 deletions src/components/Key_Stats.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
.container {
display: flex;
width: 100vw;
}

.section {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #eeebe6;
padding: 1.5rem;
}

.audioIcon {
height: 75px;
width: 75px;
color: #d29561;
align-items: start;
padding-top: 20px;
}

.paText {
font-size: 1.25rem;
font-weight: 500;
text-align: center;
color: black;
padding-top: 20px;
}

.adText {
font-size: 1.25rem;
font-weight: 500;
text-align: center;
color: black;
padding-top: 25px;
}

.tpText {
font-size: 1.25rem;
font-weight: 500;
text-align: center;
color: black;
}

.audioDuration {
font-size: 1.875rem;
font-weight: bold;
color: black;
padding-top: 25px;
}

.progressText {
position: absolute;
font-size: 1.25rem;
font-weight: bold;
color: black;
}

.sideContainer {
width: 33.33vw;
height: 40vw;
}

.centerContainer {
width: 33.33vw;
height: 40vw;
border-left: 5px solid #e5e5e5; /* Left border */
border-right: 5px solid #e5e5e5; /* Right border */
border-top: none;
border-bottom: none;
}

.progressContainer {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 6rem;
height: 6rem;
}

.progressText {
position: absolute;
font-size: 1.25rem;
font-weight: bold;
color: black;
}

.progressSvg {
position: absolute;
transform: rotate(90deg);
}

.progressBgCircle {
stroke: #d29561;
stroke-width: 10;
fill: none;
}

.progressFillCircle {
stroke: #f7cba6;
stroke-width: 10;
fill: none;
stroke-linecap: round;
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
112 changes: 112 additions & 0 deletions src/components/Key_Stats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import Link from "next/link";
import React from "react";
import { FaPlay } from "react-icons/fa";
import styles from "./Key_Stats.module.css";

/*
PlayAudio Component (1 of 3)
- contains a play audio icon to play POI audio (to be implemented in a later issue)
*/
interface PA_Props {
audio_link: string;
}
const PlayAudio: React.FC<PA_Props> = ({ audio_link }) => {
return (
<div className={styles.section}>
<Link href={audio_link}>
<FaPlay className={styles.audioIcon} />
</Link>
<span className={styles.paText}>Play Audio</span>
</div>
);
};

/*
AudioDuration Component (2 of 3)
- contains the duration of the audio segment for this POI
- passed in as seconds, converted into a minute:second format
*/
interface AD_Props {
duration_sec: number;
}
const AudioDuration: React.FC<AD_Props> = ({ duration_sec }) => {
//convert total seconds into minutes and seconds
const minutes = Math.floor(duration_sec / 60);
const seconds = duration_sec % 60;

return (
<div className={styles.section}>
<span className={styles.audioDuration}>
{minutes}:{seconds}
</span>
<span className={styles.adText}>Audio Duration</span>
</div>
);
};

/*
TourProgress Component (3 of 3)
- contains circular progress bar to indicate overall progress
- takes in current progress, and total number of tours
*/
interface TP_Props {
tour_progress: number;
total_tours: number;
}
const TourProgress: React.FC<TP_Props> = ({ tour_progress, total_tours }) => {
return (
<div className={styles.section}>
<div className={styles.progressContainer}>
<svg className={styles.progressSvg} width="75" height="75" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="45" className={styles.progressBgCircle} />
<circle
cx="50"
cy="50"
r="45"
className={styles.progressFillCircle}
strokeDasharray={2 * Math.PI * 45}
strokeDashoffset={(tour_progress / total_tours) * 2 * Math.PI * 45}
/>
</svg>
<div className={styles.progressText}>
{tour_progress}/{total_tours}
</div>
</div>
<span className={styles.tpText}>Tour Progress</span>
</div>
);
};

/*
Main KeyStats Component (contains the previous three and is exported)
- contains the three above components side by side
- used within the larger Selected_POI_Page component that additionally displays images and
POI description/content
*/
interface KS_Props {
audio_link: string;
duration_sec: number;
tour_progress: number;
total_tours: number;
}

const KeyStats: React.FC<KS_Props> = ({ audio_link, duration_sec, tour_progress, total_tours }) => {
return (
<div className={styles.container}>
<div className={styles.sideContainer}>
{/* Play Audio Section */}
<PlayAudio audio_link={audio_link}></PlayAudio>
</div>
<div className={styles.centerContainer}>
{/* Audio Duration Section */}
<AudioDuration duration_sec={duration_sec}></AudioDuration>
</div>
<div className={styles.sideContainer}>
{/* Tour Progress Section */}
<TourProgress total_tours={total_tours} tour_progress={tour_progress}></TourProgress>
</div>
</div>
);
};

export default KeyStats;
85 changes: 85 additions & 0 deletions src/components/Selected_POI_Page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
.pageContainer {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
position: relative;
background-color: black;
}

/* First div with main image */
.mainImageContainer {
display: flex;
align-items: center;
justify-content: center;
height: 30%;
}

.mainImage {
width: 100%;
height: 100%;
object-fit: cover;
filter: blur(1.65px) brightness(70%);
}

/* Second div (content section) */
.contentContainer {
flex: 1;
border-top-left-radius: 1.5rem;
border-top-right-radius: 1.5rem;
margin-top: -2rem;
z-index: 10;
background-color: #f0ebe7;
overflow: visible;
padding-bottom: 1rem;
display: flex;
flex-direction: column;
justify-content: flex-start;
padding-bottom: 1rem;
}

/* Overlay Image */
.overlayContainer {
display: flex;
flex-direction: column;
z-index: 30;
position: relative;
}

.overlayHeader {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%) translateY(-420%);
color: white;
font-size: 1.875rem; /* text-3xl */
white-space: nowrap;
}

.overlayImage {
position: relative;
margin-top: -2.5rem;
z-index: 20;
top: 0;
left: 50%;
transform: translateY(-50%) translateX(-50%);
width: 60%;
border-radius: 0.75rem;
border: 4px solid white;
}

/* KeyStats Wrapper */
.statsWrapper {
transform: translateY(-30%);
}

/* Text Content */
.textContent {
color: #1c1c1c;
margin-left: 1.25rem; /* ml-5 */
margin-right: 1.25rem; /* mr-5 */
padding-top: 25px;
overflow-y: auto; /* Enable scrolling */
flex-grow: 1; /* Let this section take up space without pushing others */
max-height: 50vh; /* Limit height so it doesn't push up other elements */
}
63 changes: 63 additions & 0 deletions src/components/Selected_POI_Page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from "react";
import KeyStats from "./Key_Stats";
import styles from "./Selected_POI_Page.module.css";

//Subcomponent to display image (unblurred) and header of the POI name
interface OverlayImageProps {
src: string;
header: string;
}
const OverlayImage: React.FC<OverlayImageProps> = ({ src, header }) => {
return (
<div className={styles.overlayContainer}>
<h1 className={styles.overlayHeader}>{header}</h1>
<img src={src} alt="Overlay" className={styles.overlayImage} />
</div>
);
};

//Main component containing Key_Stats subcomponent, and content
interface POIProps {
mainImage: string;
name: string;
content: string;
audio_link: string;
duration_sec: number;
tour_progress: number;
total_tours: number;
}
const Selected_POI_Page: React.FC<POIProps> = ({
mainImage,
name,
content,
audio_link,
duration_sec,
tour_progress,
total_tours,
}) => {
return (
//overall container
<div className={styles.pageContainer}>
{/* first div with blurred image*/}
<div className={styles.mainImageContainer}>
<img src={mainImage} alt="Main" className={styles.mainImage} />
</div>

{/* second div with overlage and key stats sub components*/}
<div className={styles.contentContainer}>
<OverlayImage src={mainImage} header={name} />
<div className={styles.statsWrapper}>
<KeyStats
audio_link={audio_link}
duration_sec={duration_sec}
tour_progress={tour_progress}
total_tours={total_tours}
/>
<p className={styles.textContent}>{content}</p>
</div>
</div>
</div>
);
};

export default Selected_POI_Page;

0 comments on commit b6f678e

Please sign in to comment.