dynamic image urls + animation
continuous-integration/drone/push Build is failing Details

This commit is contained in:
b38peng 2021-08-09 19:45:03 -03:00
parent 80cb6e3897
commit 972b7f4200
8 changed files with 106 additions and 45 deletions

View File

@ -29,11 +29,12 @@
@media only screen and (max-width: calc(768rem / 16)) {
.img {
width: calc(85rem / 16);
width: 100%;
}
.caption {
font-size: calc(11rem / 16);
text-align: center;
font-size: calc(14rem / 16);
margin-top: 1rem;
}
}

View File

@ -1,21 +1,21 @@
import React from "react";
import styles from "./TeamMember.module.css";
import { Image } from "./Image";
import { getMemberImagePath } from "../lib/team";
import styles from "./TeamMember.module.css";
interface TeamMemberProps {
name: string;
role: string;
image: string;
}
export const TeamMember: React.FC<TeamMemberProps> = ({ name, role }) => {
export const TeamMember: React.FC<TeamMemberProps> = ({
name,
role,
image,
}) => {
return (
<div className={styles.container}>
<Image
className={styles.img}
src={getMemberImagePath(name)}
alt={`Picture of ${name}`}
/>
<Image className={styles.img} src={image} alt={`Picture of ${name}`} />
<div className={styles.caption}>
<div className={styles.name}>{name}</div>
<div className={styles.role}>{role}</div>

View File

@ -54,26 +54,45 @@
/* Popup */
@keyframes popup {
0% {
transform: scale(0.4) translate(0, -50%);
}
100% {
transform: scale(1) translate(0, -50%);
}
}
@keyframes revealBg {
0% {
opacity: 0;
}
100% {
opacity: 100%;
}
}
.popupBackground {
position: fixed;
z-index: 11;
background-color: var(--navbar-page-overlay);
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1;
animation: revealBg 0.2s forwards;
}
.popupContainer {
position: fixed;
display: flex;
z-index: 12;
flex-direction: column;
background-color: var(--secondary-background);
padding: calc(20rem / 16) calc(40rem / 16);
left: 0;
top: 50%;
transform: translate(0, -50%);
z-index: 2;
animation: popup 0.7s forwards;
}
.closeBtn {

View File

@ -2,15 +2,20 @@ import React, { useState } from "react";
import { Image } from "./Image";
import { useWindowDimension } from "../hooks/useWindowDimension";
import styles from "./TeamMemberCard.module.css";
import { getMemberImagePath } from "../lib/team";
export interface TeamMemberCardProps {
name: string;
role: string;
image: string;
children: React.ReactNode;
}
export function TeamMemberCard({ name, role, children }: TeamMemberCardProps) {
export function TeamMemberCard({
name,
role,
image,
children,
}: TeamMemberCardProps) {
const { width } = useWindowDimension();
const [isOpen, setIsOpen] = useState(false);
const handleClick = () => {
@ -24,7 +29,7 @@ export function TeamMemberCard({ name, role, children }: TeamMemberCardProps) {
<div className={styles.picture}>
<Image
className={styles.image}
src={getMemberImagePath(name)}
src={image}
alt={`Picture of ${name}`}
/>
</div>
@ -33,7 +38,12 @@ export function TeamMemberCard({ name, role, children }: TeamMemberCardProps) {
<div className={styles.description}>{children}</div>
</article>
{isOpen && (
<ExecPopup name={name} role={role} handleClick={handleClick}>
<ExecPopup
name={name}
role={role}
image={image}
handleClick={handleClick}
>
{children}
</ExecPopup>
)}
@ -45,7 +55,7 @@ interface Propup extends TeamMemberCardProps {
handleClick: () => void;
}
function ExecPopup({ name, role, children, handleClick }: Propup) {
function ExecPopup({ name, role, image, children, handleClick }: Propup) {
return (
<>
<div className={styles.popupBackground} onClick={handleClick} />
@ -57,7 +67,7 @@ function ExecPopup({ name, role, children, handleClick }: Propup) {
<div className={styles.picture}>
<Image
className={styles.popupImage}
src={getMemberImagePath(name)}
src={image}
alt={`Picture of ${name}`}
/>
</div>

View File

@ -9,6 +9,7 @@ const fileType = ".md";
export interface Metadata {
name: string;
role: string;
image: string;
}
export async function getExecNames() {
@ -20,22 +21,34 @@ export async function getExecNames() {
export async function getExec(fileName: string, convert = true) {
const raw = await readFile(path.join(EXECS_PATH, `${fileName}${fileType}`));
const { content, data: metadata } = matter(raw);
const image = await getMemberImagePath(metadata.name);
return {
content: convert ? await serialize(content) : content,
metadata,
metadata: { ...metadata, image } as Metadata,
};
}
export function getMemberImagePath(name: string) {
const imgPath = "/images/team/" + name.replace(" ", "") + ".jpg";
const placeholder = "/images/team/team-member-placeholder.svg";
let img;
access(imgPath)
.then(() => {
img = imgPath;
})
.catch(() => {
img = placeholder;
});
async function getImage(imgPath: string) {
try {
await access(path.join("public", imgPath));
return imgPath;
} catch {
return undefined;
}
}
export async function getMemberImagePath(name: string) {
const imgPath = path.join("images", "team", name.replace(" ", ""));
const placeholder = path.join(
"images",
"team",
"team-member-placeholder.svg"
);
const img =
(await getImage(imgPath + ".jpg")) ??
(await getImage(imgPath + ".png")) ??
(await getImage(imgPath + ".gif")) ??
placeholder;
return img;
}

View File

@ -95,17 +95,12 @@
padding-bottom: calc(15rem / 16);
}
.execs {
.execs, .members {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(calc(132rem / 16), 1fr));
grid-template-columns: repeat(auto-fill, minmax(calc(130rem / 16), 1fr));
justify-items: center;
}
.members {
row-gap: calc(24rem / 16);
column-gap: calc(1rem / 16);
}
.elections {
padding: 2rem;
}

View File

@ -1,5 +1,10 @@
import React from "react";
import { getExec, getExecNames, Metadata } from "../../lib/team";
import {
getExec,
getExecNames,
Metadata,
getMemberImagePath,
} from "../../lib/team";
import { MDXRemote, MDXRemoteSerializeResult } from "next-mdx-remote";
import { GetStaticProps } from "next";
import { Image } from "../../components/Image";
@ -7,9 +12,9 @@ import { TeamMemberCard } from "../../components/TeamMemberCard";
import { TeamMember } from "../../components/TeamMember";
import { Link } from "../../components/Link";
import { Bubble } from "../../components/Bubble";
import programme from "../../content/meet-the-team/programme-committee.json";
import website from "../../content/meet-the-team/website-committee.json";
import systems from "../../content/meet-the-team/systems-committee.json";
import programmeData from "../../content/meet-the-team/programme-committee.json";
import websiteData from "../../content/meet-the-team/website-committee.json";
import systemsData from "../../content/meet-the-team/systems-committee.json";
import styles from "./team.module.css";
// TODO: fix hotdog for elections
@ -22,9 +27,12 @@ interface SerializedExec {
interface Props {
execs: SerializedExec[];
programme: Metadata[];
website: Metadata[];
systems: Metadata[];
}
export default function Team({ execs }: Props) {
export default function Team({ execs, programme, website, systems }: Props) {
return (
<>
<div className={styles.headerContainer}>
@ -82,7 +90,7 @@ export default function Team({ execs }: Props) {
}
interface MembersProps {
team: Array<Metadata>;
team: Metadata[];
}
function MembersList(props: MembersProps) {
@ -95,13 +103,28 @@ function MembersList(props: MembersProps) {
);
}
async function getMemberImage(team: Omit<Metadata, "image">[]) {
return await Promise.all(
team.map(async (member) => {
const image = await getMemberImagePath(member.name);
return {
...member,
image,
};
})
);
}
export const getStaticProps: GetStaticProps<Props> = async () => {
const execNames = await getExecNames();
const execs = (await Promise.all(
execNames.map((name) => getExec(name))
)) as SerializedExec[];
const programme = await getMemberImage(programmeData);
const website = await getMemberImage(websiteData);
const systems = await getMemberImage(systemsData);
return {
props: { execs },
props: { execs, programme, website, systems },
};
};

View File

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB