Refactor body into multiple files

This commit is contained in:
Michael Bradley 2025-02-21 02:06:51 -05:00
parent 36db4c2c0c
commit a513e3786c
Signed by: MichaelBradley
SSH key fingerprint: SHA256:cj/YZ5VT+QOKncqSkx+ibKTIn0Obg7OIzwzl9BL8EO8
10 changed files with 168 additions and 151 deletions

View file

@ -1,150 +0,0 @@
import "./style.css";
import type { PropsWithChildren } from "react";
import hero from "./assets/MichaelBradley.jpeg?format=avif;webp;jpeg&as=picture";
import CV from "./assets/cv.svg?react";
import Git from "./assets/git.svg?react";
import LinkedIn from "./assets/linkedin.svg?react";
import Mastodon from "./assets/mastodon.svg?react";
import DarkModeToggleIcon from "./assets/darkmodetoggle.svg?react";
type ColouredBlockProps = {
colorNum: number;
};
const ColouredBlock = ({ colorNum }: ColouredBlockProps) => (
<span style={{ color: `var(--color${colorNum})` }}></span>
);
type ColouredLineProps = {
light: boolean;
};
const ProfilePicture = () => (
<div id="michael-photo-container">
<picture>
{Object.entries(hero.sources).map(([format, src]) => (
<source srcSet={src} type={`image/${format}`} key={format} />
))}
<img src={hero.img.src} alt="A picture of me in a suit smiling" id="michael-photo" />
</picture>
</div>
);
const Highlight = ({ children }: PropsWithChildren) => <span className="text-highlight">{children}</span>;
type FetchHeaderProps = {
user: string;
hostname: string;
};
const FetchHeader = ({ user, hostname }: FetchHeaderProps) => (
<>
<p>
<Highlight>{user}</Highlight>@<Highlight>{hostname}</Highlight>
</p>
<p>{"-".repeat(user.length + 1 + hostname.length)}</p>
</>
);
type InfoLineProps = {
label: string;
value: string;
};
const InfoLine = ({ label, value }: InfoLineProps) => (
<p>
<span className="text-highlight">{label}</span>: {value}
</p>
);
const BlankLine = () => (
<p>
<br />
</p>
);
const Description = () => (
<div className="invisible-div">
<FetchHeader user="website" hostname="MichaelBradley" />
<InfoLine label="Degree" value="Bachelor of Computer Science" />
<InfoLine label="University" value="Carleton" />
<InfoLine label="Major CGPA" value="11.52/12 (A+)" />
<InfoLine label="Languages" value="C/C++, Python, TypeScript" />
<InfoLine label="Skills" value="Linux, Git, Testing" />
<InfoLine label="Work Experience" value="2 years" />
<InfoLine label="Applying for" value="Full-time job" />
<InfoLine label="Location" value="Toronto or Remote" />
</div>
);
const ColouredLine = ({ light }: ColouredLineProps) => {
const startIndex = light ? 8 : 0;
return (
<p className="blocks">
{Array.from({ length: 8 }).map(
(
_value,
index, // Apparently this is the best way to map a range in JavaScript
) => (
<ColouredBlock colorNum={startIndex + index} key={index} />
),
)}
</p>
);
};
// TODO: Automate screenshot of info for thumbnail?
const Fetch = () => {
return (
<div id="fetch-container">
<div id="fetch">
<ProfilePicture />
<div id="basic-info">
<Description />
<BlankLine />
<ColouredLine light={false} />
<ColouredLine light={true} />
</div>
</div>
</div>
);
};
type ImageLinkProps = {
href: string;
title: string;
Image: typeof Git; // Not ideal, but I can't figure out how to import the type directly from the declared wildcard module
};
const ImageLink = ({ href, title, Image }: ImageLinkProps) => (
<a rel="me" href={href} title={title}>
<Image width="100%" />
</a>
);
const Links = () => (
<div className="links">
<ImageLink href="https://git.mmbradley.ca/MichaelBradley/" title="Forgejo instance" Image={Git} />
<ImageLink href="https://www.linkedin.com/in/michaelmbradley/" title="LinkedIn account" Image={LinkedIn} />
<ImageLink href="https://mmbradley.ca/resume.pdf" title="My Résumé" Image={CV} />
<ImageLink href="https://mstdn.ca/@michaelbradley/" title="Mastodon account" Image={Mastodon} />
<input id="dark-mode-toggle" type="checkbox" aria-label="Toggle dark mode" />
<label htmlFor="dark-mode-toggle" id="dark-mode-toggle-label" title="Toggle dark mode">
<DarkModeToggleIcon width="100%" />
</label>
</div>
);
const Body = () => {
return (
<>
<Fetch />
<Links />
</>
);
};
export default Body;

View file

@ -0,0 +1,29 @@
type ColouredBlockProps = {
colorNum: number;
};
const ColouredBlock = ({ colorNum }: ColouredBlockProps) => (
<span style={{ color: `var(--color${colorNum})` }}></span>
);
type ColouredLineProps = {
light: boolean;
};
const ColouredLine = ({ light }: ColouredLineProps) => {
const startIndex = light ? 8 : 0;
return (
<p className="blocks">
{Array.from({ length: 8 }).map(
(
_value,
index, // Apparently this is the best way to map a range in JavaScript
) => (
<ColouredBlock colorNum={startIndex + index} key={index} />
),
)}
</p>
);
};
export default ColouredLine;

View file

@ -0,0 +1,42 @@
import { Highlight } from "./utils";
type HeaderProps = {
user: string;
hostname: string;
};
const Header = ({ user, hostname }: HeaderProps) => (
<>
<p>
<Highlight>{user}</Highlight>@<Highlight>{hostname}</Highlight>
</p>
<p>{"-".repeat(user.length + 1 + hostname.length)}</p>
</>
);
type InfoLineProps = {
label: string;
value: string;
};
const InfoLine = ({ label, value }: InfoLineProps) => (
<p>
<span className="text-highlight">{label}</span>: {value}
</p>
);
const Description = () => (
<div className="invisible-div">
<Header user="website" hostname="MichaelBradley" />
<InfoLine label="Degree" value="Bachelor of Computer Science" />
<InfoLine label="University" value="Carleton" />
<InfoLine label="Major CGPA" value="11.52/12 (A+)" />
<InfoLine label="Languages" value="C/C++, Python, TypeScript" />
<InfoLine label="Skills" value="Linux, Git, Testing" />
<InfoLine label="Work Experience" value="2 years" />
<InfoLine label="Applying for" value="Full-time job" />
<InfoLine label="Location" value="Toronto or Remote" />
</div>
);
export default Description;

View file

@ -0,0 +1,14 @@
import hero from "../../assets/MichaelBradley.jpeg?format=avif;webp;jpeg&as=picture";
const ProfilePicture = () => (
<div id="michael-photo-container">
<picture>
{Object.entries(hero.sources).map(([format, src]) => (
<source srcSet={src} type={`image/${format}`} key={format} />
))}
<img src={hero.img.src} alt="A picture of me in a suit smiling" id="michael-photo" />
</picture>
</div>
);
export default ProfilePicture;

23
src/Body/Fetch/index.tsx Normal file
View file

@ -0,0 +1,23 @@
import ColouredLine from "./ColouredLine";
import Description from "./Description";
import ProfilePicture from "./ProfilePicture";
import { BlankLine } from "./utils";
// TODO: Automate screenshot of info for thumbnail?
const Fetch = () => {
return (
<div id="fetch-container">
<div id="fetch">
<ProfilePicture />
<div id="basic-info">
<Description />
<BlankLine />
<ColouredLine light={false} />
<ColouredLine light={true} />
</div>
</div>
</div>
);
};
export default Fetch;

9
src/Body/Fetch/utils.tsx Normal file
View file

@ -0,0 +1,9 @@
import type { PropsWithChildren } from "react";
export const Highlight = ({ children }: PropsWithChildren) => <span className="text-highlight">{children}</span>;
export const BlankLine = () => (
<p>
<br />
</p>
);

32
src/Body/Links.tsx Normal file
View file

@ -0,0 +1,32 @@
import CV from "../assets/cv.svg?react";
import Git from "../assets/git.svg?react";
import LinkedIn from "../assets/linkedin.svg?react";
import Mastodon from "../assets/mastodon.svg?react";
import DarkModeToggleIcon from "../assets/darkmodetoggle.svg?react";
type ImageLinkProps = {
href: string;
title: string;
Image: typeof Git; // Not ideal, but I can't figure out how to import the type directly from the declared wildcard module
};
const ImageLink = ({ href, title, Image }: ImageLinkProps) => (
<a rel="me" href={href} title={title}>
<Image width="100%" />
</a>
);
const Links = () => (
<div className="links">
<ImageLink href="https://git.mmbradley.ca/MichaelBradley/" title="Forgejo instance" Image={Git} />
<ImageLink href="https://www.linkedin.com/in/michaelmbradley/" title="LinkedIn account" Image={LinkedIn} />
<ImageLink href="https://mmbradley.ca/resume.pdf" title="My Résumé" Image={CV} />
<ImageLink href="https://mstdn.ca/@michaelbradley/" title="Mastodon account" Image={Mastodon} />
<input id="dark-mode-toggle" type="checkbox" aria-label="Toggle dark mode" />
<label htmlFor="dark-mode-toggle" id="dark-mode-toggle-label" title="Toggle dark mode">
<DarkModeToggleIcon width="100%" />
</label>
</div>
);
export default Links;

13
src/Body/index.tsx Normal file
View file

@ -0,0 +1,13 @@
import Fetch from "./Fetch";
import Links from "./Links";
const Body = () => {
return (
<>
<Fetch />
<Links />
</>
);
};
export default Body;

View file

@ -1,6 +1,9 @@
// Entry point for development // Entry point for development
import "./style.css";
import { StrictMode } from "react"; import { StrictMode } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import Body from "./Body"; import Body from "./Body";
import Head from "./Head"; import Head from "./Head";

View file

@ -1,8 +1,10 @@
// Entry point for SSG // Entry point for SSG
import style from "./style.css?inline";
import { renderToString } from "react-dom/server"; import { renderToString } from "react-dom/server";
import Body from "./Body"; import Body from "./Body";
import Head from "./Head"; import Head from "./Head";
import style from "./style.css?inline";
export const render = () => { export const render = () => {
const html = const html =