Skip to content

Commit

Permalink
Merge pull request #121 from UoaWDCC/74_history-component
Browse files Browse the repository at this point in the history
74 History Component
  • Loading branch information
Oculux314 authored Sep 19, 2024
2 parents 50cc3c1 + 7074114 commit 16c528d
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 36 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"**/node_modules": true,
"**/.next": true,
"**/.cache": true,
"**/.tmp": true,
// "**/.tmp": true,
"**/build": true
},

Expand Down
37 changes: 5 additions & 32 deletions next/app/about/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import flair from "@/assets/about/flair.png";
import valueFlair1 from "@/assets/about/value1.png";
import valueFlair2 from "@/assets/about/value2.png";
import HistoryText from "@/components/history/HistoryText";
import { aboutPageSchema, TimelineElement } from "@/schemas/single/AboutPage";
import fetchStrapi from "@/util/strapi";
import Image from "next/image";
import styles from "./styles.module.css";
import History from "@/components/history/History";

export default async function AboutPage() {
const data = await fetchStrapi("about-page", aboutPageSchema);
Expand All @@ -17,6 +19,8 @@ export default async function AboutPage() {
};
}).sort((a, b) => a.Date.getTime() - b.Date.getTime());

console.log(timeline);

return (
<>
<Image src={flair} alt="" className="absolute -z-10 top-[70%]" />
Expand Down Expand Up @@ -48,38 +52,7 @@ export default async function AboutPage() {
<h2 className="md:text-8xl sm:text-7xl text-6xl font-bold leading-[0.95] uppercase mb-12">
Our History
</h2>
<div className="text-left max-w-xl mx-auto">
<ol className="relative border-s border-gray-100 text-b-dark-blue">
{timeline.map((e, i) => {
const isImage = "Image" in e;

return (
<li key={i} className="mb-10 ms-4">
<div className="absolute w-3 h-3 bg-gray-100 rounded-full mt-1.5 -start-1.5 border border-white"></div>
<time className="mb-1 text-sm font-normal leading-none italic">
{e.Date.toLocaleDateString()}
</time>
{isImage ? (
<Image
src={e.Image}
alt=""
className="w-full rounded-lg mb-4 shadow-xl"
width={200}
height={200}
/>
) : (
<div>
<h3 className="text-lg font-semibold">{e.Title}</h3>
<p className="mb-4 text-base font-normal ">
{e.Description}
</p>
</div>
)}
</li>
);
})}
</ol>
</div>
<History timelineElements={timeline} />
</section>
</>
);
Expand Down
22 changes: 22 additions & 0 deletions next/app/test/deiza/historytest/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import History from "@/components/history/History";
import { aboutPageSchema, TimelineElement } from "@/schemas/single/AboutPage";
import fetchStrapi from "@/util/strapi";

export default async function HistoryTest() {
const data = await fetchStrapi("about-page", aboutPageSchema);

// Get Timeline part of About Page (with Date objects)
const timelineElements: TimelineElement[] = data.Timeline.map((e) => {
const date = new Date(e.Date);
return {
...e,
Date: date,
};
});

return (
<div className="mt-56">
<History timelineElements={timelineElements} />
</div>
);
}
16 changes: 16 additions & 0 deletions next/components/history/FloatingDate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
type FloatingDateProps = {
date: Date;
position: "top" | "bottom"; // Position of the main component
};

export default function FloatingDate({ date, position }: FloatingDateProps) {
const positionStyle = position === "top" ? "-bottom-10" : "-top-10";

return (
<div
className={`absolute ${positionStyle} px-6 py-4 text-white text-xs font-bold`}
>
{date.toLocaleDateString()}
</div>
);
}
42 changes: 42 additions & 0 deletions next/components/history/History.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { TimelineElement } from "@/schemas/single/AboutPage";
import HistoryComponent from "./HistoryComponent";

type HistoryComponentProps = {
timelineElements: TimelineElement[];
};

export default function History({ timelineElements }: HistoryComponentProps) {
// Sort timeline by date
const sortedTimelineElements: TimelineElement[] = timelineElements.sort(
(a, b) => a.Date.getTime() - b.Date.getTime(),
);

// Split timeline + map TimelineElements -> components
const topTimeline: TimelineElement[] = [];
const bottomTimeline: TimelineElement[] = [];
for (let i = 0; i < sortedTimelineElements.length; i++) {
if (i % 2 == 0) {
// Even elements go on top
topTimeline.push(sortedTimelineElements[i]);
} else {
// Odd elements go on bottom
bottomTimeline.push(sortedTimelineElements[i]);
}
}

return (
<div className="mx-16">
<div className="flex items-end">
{topTimeline.map((element) => (
<HistoryComponent element={element} position="top" />
))}
</div>
<div className="bg-white h-1 w-full" />
<div className="flex items-start ml-[12rem]">
{bottomTimeline.map((element) => (
<HistoryComponent element={element} position="bottom" />
))}
</div>
</div>
);
}
49 changes: 49 additions & 0 deletions next/components/history/HistoryComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
ImageTimelineElement,
TextTimelineElement,
TimelineElement,
} from "@/schemas/single/AboutPage";
import { getLargestImageUrl } from "@/util/image";
import HistoryImage from "./HistoryImage";
import HistoryText from "./HistoryText";
import FloatingDate from "./FloatingDate";

type HistoryComponentProps = {
element: TimelineElement;
position: "top" | "bottom";
};

export default function HistoryComponent({
element,
position,
}: HistoryComponentProps) {
const line = <div className="bg-white w-1 h-14" />;
const hasLineAbove = position === "bottom";

return (
<div className="relative flex flex-col items-center mx-12 h-56 w-72">
{hasLineAbove && line}
{elementToComponent(element)}
{!hasLineAbove && line}
<FloatingDate date={element.Date} position={position} />
</div>
);
}

// TimelineElement -> React component
function elementToComponent(element: TimelineElement): React.ReactNode {
if (element.__component == "project-timeline.text-timeline-item") {
// Text components
const textElement = element as TextTimelineElement;
return (
<HistoryText
title={textElement.Title}
description={textElement.Description}
/>
);
} else {
// Image components
const imageElement = element as ImageTimelineElement;
return <HistoryImage src={getLargestImageUrl(imageElement.Image)} />;
}
}
17 changes: 17 additions & 0 deletions next/components/history/HistoryImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Image from "next/image";

type HistoryImageProps = {
src: string;
};

export default function HistoryImage({ src }: HistoryImageProps) {
return (
<Image
src={src}
alt=""
width={256}
height={170}
className="h-full w-auto rounded-3xl shadow-lg"
/>
);
}
14 changes: 14 additions & 0 deletions next/components/history/HistoryText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
type HistoryTextProps = {
title: string;
description: string;
};

export default function HistoryText({ title, description }: HistoryTextProps) {
return (
<div className="bg-b-orange text-b-dark-blue px-6 py-4 rounded-3xl shadow-lg h-full w-full overflow-hidden">
{" "}
<h1 className="text-lg font-semibold mb-2">{title}</h1>
<p className="mb-4 text-base font-normal ">{description}</p>
</div>
);
}
11 changes: 8 additions & 3 deletions next/schemas/single/AboutPage.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { z } from "zod";
import { imageSchema } from "../Image";

const imageTimelineSchema = z.object({
export const imageTimelineSchema = z.object({
Date: z.date(),
Image: z.string(),
Image: imageSchema,
__component: z.string(),
});

const textTimelineSchema = z.object({
export const textTimelineSchema = z.object({
Date: z.date(),
Title: z.string(),
Description: z.string(),
__component: z.string(),
});

export const timelineElementSchema = z.union([
imageTimelineSchema,
textTimelineSchema,
]);

export type ImageTimelineElement = z.infer<typeof imageTimelineSchema>;
export type TextTimelineElement = z.infer<typeof textTimelineSchema>;
export type TimelineElement = z.infer<typeof timelineElementSchema>;

export const aboutPageSchema = z.object({
Expand Down

0 comments on commit 16c528d

Please sign in to comment.