Skip to content

Commit

Permalink
Merge pull request #161 from jerboa88/27-design-project-page
Browse files Browse the repository at this point in the history
27 design project page
  • Loading branch information
jerboa88 authored Jul 26, 2024
2 parents 8eef67b + fd993e9 commit 5183a6b
Show file tree
Hide file tree
Showing 17 changed files with 124 additions and 86 deletions.
6 changes: 3 additions & 3 deletions gatsby-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
getSocialImageGenerationConfigForType,
getTheme,
} from './src/common/config-manager';
import { SOCIAL_IMAGES_DIR } from './src/common/constants';
import { INDEX_PATH, SOCIAL_IMAGES_PATH } from './src/common/constants';
import { SocialImageType, ThemeType } from './src/common/types';
import { getAbsoluteUrl } from './src/common/utils';
import tailwindConfig from './tailwind.config';
Expand Down Expand Up @@ -71,7 +71,7 @@ const config: GatsbyConfig = {
changefreq: 'monthly',
}),
// Prevent temporary components rendered by gatsby-plugin-open-graph-images from being included in the sitemap
excludes: [`/${SOCIAL_IMAGES_DIR}/**/*`],
excludes: [`/${SOCIAL_IMAGES_PATH}/**/*`],
},
},
{
Expand All @@ -95,7 +95,7 @@ const config: GatsbyConfig = {
// biome-ignore lint/style/useNamingConvention: Naming convention is enforced by the plugin
short_name: SITE_METADATA.shortTitle,
// biome-ignore lint/style/useNamingConvention: Naming convention is enforced by the plugin
start_url: '/',
start_url: INDEX_PATH,
// biome-ignore lint/style/useNamingConvention: Naming convention is enforced by the plugin
background_color: DARK_THEME['base-100'],
// biome-ignore lint/style/useNamingConvention: Naming convention is enforced by the plugin
Expand Down
36 changes: 20 additions & 16 deletions gatsby-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import { join, resolve } from 'node:path';
import type { CreatePagesArgs, GatsbyNode } from 'gatsby';
import { getPageMetadata, getSiteMetadata } from './src/common/config-manager';
import {
ABOUT_PATH,
CONTACT_PATH,
EXPERIENCE_PATH,
INDEX_PATH,
PAGE_TEMPLATES_DIR,
PROJECTS_DIR,
PROJECTS_DIR_SHORT,
SOCIAL_IMAGES_DIR as SOCIAL_IMAGE_PAGES_DIR,
PROJECTS_PATH,
PROJECTS_PATH_SHORT,
RESUME_PATH,
SOCIAL_IMAGES_PATH,
SOCIAL_IMAGE_TEMPLATES_DIR,
} from './src/common/constants';
import {
Expand Down Expand Up @@ -121,7 +126,7 @@ function createIndexPage(
};

createPage({
path: '/',
path: INDEX_PATH,
component: INDEX_PAGE_TEMPLATE,
socialImageComponent: INDEX_OG_IMAGE_TEMPLATE,
context: context,
Expand All @@ -135,8 +140,8 @@ function sortByCreatedAt(a: Queries.GithubRepo, b: Queries.GithubRepo) {

// Create the resume page
function createResumePage(githubRepos: Queries.GithubRepo[]) {
const path = '/resume';
const pageMetadata: PageMetadata | EmptyObject = getPageMetadata(path) || {};
const pageMetadata: PageMetadata | EmptyObject =
getPageMetadata(RESUME_PATH) || {};
const context: ResumePageContext = {
pageMetadata,
githubRepos: getSubsetOfGithubRepos(
Expand All @@ -147,7 +152,7 @@ function createResumePage(githubRepos: Queries.GithubRepo[]) {
};

createPage({
path: path,
path: RESUME_PATH,
component: RESUME_PAGE_TEMPLATE,
socialImageComponent: OTHER_OG_IMAGE_TEMPLATE,
context: context,
Expand All @@ -158,11 +163,11 @@ function createResumePage(githubRepos: Queries.GithubRepo[]) {
function createProjectPages(githubRepos: Queries.GithubRepo[]) {
for (const githubRepo of githubRepos) {
const path: AbsolutePathString = join(
PROJECTS_DIR,
PROJECTS_PATH,
githubRepo.slug,
) as AbsolutePathString;
const shortPath: AbsolutePathString = join(
PROJECTS_DIR_SHORT,
PROJECTS_PATH_SHORT,
githubRepo.slug,
) as AbsolutePathString;
const context: ProjectPageContext = {
Expand All @@ -184,10 +189,10 @@ function createProjectPages(githubRepos: Queries.GithubRepo[]) {
// Create client-side redirects
function createRedirects() {
const redirects = [
['/about', '/#about'],
['/projects', '/#projects'],
['/experience', '/#experience'],
['/contact', '/#contact'],
[ABOUT_PATH, '/#about'],
[PROJECTS_PATH, '/#projects'],
[EXPERIENCE_PATH, '/#experience'],
[CONTACT_PATH, '/#contact'],
];

for (const [fromPath, toPath] of redirects) {
Expand Down Expand Up @@ -229,7 +234,7 @@ export const onCreatePage: GatsbyNode['onCreatePage'] = ({ page }) => {
}

// Skip social images
if (page.path.startsWith(SOCIAL_IMAGE_PAGES_DIR)) {
if (page.path.startsWith(SOCIAL_IMAGES_PATH)) {
return;
}

Expand Down Expand Up @@ -258,8 +263,7 @@ export const createPages: GatsbyNode['createPages'] = async ({ graphql }) => {
const githubRepos = await fetchGithubRepos(graphql);
const authorBioHtml = getAuthorBioHtml(githubRepos);

// TODO: Re-enable this when project pages are implemented
// createProjectPages(githubRepos);
createProjectPages(githubRepos);
createIndexPage(githubRepos, authorBioHtml);
createResumePage(githubRepos);
createRedirects();
Expand Down
17 changes: 14 additions & 3 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,20 @@ const FADE_TRANSITION_VARIANTS = {
export const PAGE_TEMPLATES_DIR: WorkingPathString = './src/templates/page';
export const SOCIAL_IMAGE_TEMPLATES_DIR: WorkingPathString =
'./src/templates/social-image';
export const PROJECTS_DIR: AbsolutePathString = '/projects';
export const PROJECTS_DIR_SHORT: AbsolutePathString = '/p';
export const SOCIAL_IMAGES_DIR: AbsolutePathString = '/__generatedSocialImages';

// Paths
export const INDEX_PATH: AbsolutePathString = '/';
export const ABOUT_PATH: AbsolutePathString = '/about';
export const EXPERIENCE_PATH: AbsolutePathString = '/experience';
export const PROJECTS_PATH: AbsolutePathString = '/projects';
export const PROJECTS_PATH_SHORT: AbsolutePathString = '/p';
export const CONTACT_PATH: AbsolutePathString = '/contact';
export const RESUME_PATH: AbsolutePathString = '/resume';
export const PRIVACY_POLICY_PATH: AbsolutePathString = '/privacy-policy';
export const NOT_FOUND_PATH: AbsolutePathString = '/404';
export const SOCIAL_IMAGES_PATH: AbsolutePathString =
'/__generatedSocialImages';
export const JSON_LD_AUTHOR_PATH: AbsolutePathString = '/author';

// ID used to group together elements for the title animation
export const TITLE_LAYOUT_ID = 'title-layout' as const;
Expand Down
6 changes: 3 additions & 3 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export function clamp(value: number, min: number, max: number) {
export function toKebabCase(string: string) {
return string
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.replace(/[\s_.]+/g, '-')
.toLowerCase();
}

Expand Down Expand Up @@ -174,8 +174,8 @@ export function prettify(json: object | undefined | null) {
}

// Given a path, return the absolute URL
export function getAbsoluteUrl(path: string) {
return new URL(path, SITE_METADATA.siteUrl);
export function getAbsoluteUrl(path: string, base?: string) {
return new URL(path, base ?? SITE_METADATA.siteUrl);
}

// Get the MIME type of a file URL based on its extension
Expand Down
3 changes: 2 additions & 1 deletion src/components/layout/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { faGithub, faLinkedin } from '@fortawesome/free-brands-svg-icons';
import { getSiteMetadata } from '../../common/config-manager';
import { PRIVACY_POLICY_PATH } from '../../common/constants';
import { TooltipPosition } from '../../common/types';
import { Divider } from '../divider';
import { GhostButtonLink } from '../links/ghost-button-link';
Expand All @@ -27,7 +28,7 @@ export function Footer() {
tooltipPosition={TooltipPosition.Right}
/>
<GhostButtonLink
to="/privacy-policy"
to={PRIVACY_POLICY_PATH}
text="Privacy"
tooltipText="View the Privacy Policy"
tooltipPosition={TooltipPosition.Right}
Expand Down
14 changes: 10 additions & 4 deletions src/components/layout/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ import { motion } from 'framer-motion';
import { getSiteMetadata } from '../../common/config-manager';
import { TITLE_LAYOUT_ID } from '../../common/constants';
import type { PageSection } from '../../common/types';
import { getClassNameProps } from '../../common/utils';
import { getClassNameProps, isDefined } from '../../common/utils';
import { Divider } from '../divider';
import { Tabs } from '../tabs';
import { Heading } from '../text/heading';

// Types

interface Props {
expandTitle?: boolean;
expandTitle?: boolean | undefined;
sections: PageSection[];
}

// Constants

const SITE_METADATA = getSiteMetadata();

export function Header({ expandTitle = false, sections }: Props) {
export function Header({ expandTitle, sections }: Props) {
const headerClassNameProps = getClassNameProps(
'fixed top-0 z-30 w-full transition',
!expandTitle && 'bg-glass backdrop-blur-md shadow-lg', // Transparent bg when title is expanded
Expand All @@ -36,13 +36,19 @@ export function Header({ expandTitle = false, sections }: Props) {
'transition-opacity',
expandTitle ? 'opacity-0' : 'opacity-100', // Hide divider when title is expanded
);
const layoutIdProp: { layoutId?: string } = {};

// If expandTitle is not specified, don't animate the title
if (isDefined(expandTitle)) {
layoutIdProp.layoutId = TITLE_LAYOUT_ID;
}

return (
<header {...headerClassNameProps}>
<div className="mix-blend-overlay">
<div {...containerClassNameProps}>
{!expandTitle && (
<motion.a href="/" layoutId={TITLE_LAYOUT_ID}>
<motion.a href="/" {...layoutIdProp}>
<Heading className="px-2 m-0 text-xl">
<span className="inline sm:hidden">
{SITE_METADATA.author.name.initial}
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/page-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const ParticlesBackground = lazy(() =>

export function PageLayout({
className,
expandTitle = false,
expandTitle,
sections = [],
children,
}: Props) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/resume-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
faPhoneSquare,
} from '@fortawesome/free-solid-svg-icons';
import { getSiteMetadata } from '../../common/config-manager';
import { CONTACT_PATH } from '../../common/constants';
import { type CityAndStateString, TooltipPosition } from '../../common/types';
import { getAbsoluteUrl, removeProtocol } from '../../common/utils';
import { GhostButton } from '../input/ghost-button';
Expand All @@ -19,7 +20,6 @@ import { Heading } from '../text/heading';
// Constants

const SITE_METADATA = getSiteMetadata();
const CONTACT_PATH = '/contact';
const CONTACT_URL = removeProtocol(getAbsoluteUrl(CONTACT_PATH));
const COMMON_GHOST_BUTTON_LINK_PROPS = {
tooltipPosition: TooltipPosition.Left,
Expand Down
7 changes: 6 additions & 1 deletion src/components/project-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { faGithub } from '@fortawesome/free-brands-svg-icons';
import { faStar } from '@fortawesome/free-solid-svg-icons';
import { PROJECTS_PATH } from '../common/constants';
import { getClassNameProps } from '../common/utils';
import { Card } from './card';
import { GhostButton } from './input/ghost-button';
Expand Down Expand Up @@ -87,5 +88,9 @@ export function ProjectCard({ repo }: Props) {
return cardElement;
}

return <LinkWrapper to={repo.url}>{cardElement}</LinkWrapper>;
return (
<LinkWrapper to={`${PROJECTS_PATH}/${repo.slug}`} isInternal>
{cardElement}
</LinkWrapper>
);
}
3 changes: 2 additions & 1 deletion src/components/seo/page-head.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { getSiteMetadata, getTheme } from '../../common/config-manager';
import { JSON_LD_AUTHOR_PATH } from '../../common/constants';
import {
type PageMetadataProp,
type PropsWithClassName,
Expand Down Expand Up @@ -102,7 +103,7 @@ export function PageHead({
...structuredData,
author: {
'@type': 'Person',
'@id': '/author',
'@id': JSON_LD_AUTHOR_PATH,
name: SITE_METADATA.author.name.full,
url: SITE_METADATA.siteUrl,
image: SITE_METADATA.author.imageUrl,
Expand Down
12 changes: 6 additions & 6 deletions src/config/github-repos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const githubReposConfig: GithubReposConfig = {
resume: EntryVisibility.Hide,
},
},
'Compare-Form-Backends': {
'compare-form-backends': {
visibilityForPage: {
index: EntryVisibility.Show,
},
Expand All @@ -32,7 +32,7 @@ export const githubReposConfig: GithubReposConfig = {
resume: EntryVisibility.Hide,
},
},
'Game-Maps': {
'game-maps': {
visibilityForPage: {
resume: EntryVisibility.Hide,
},
Expand All @@ -48,7 +48,7 @@ export const githubReposConfig: GithubReposConfig = {
resume: EntryVisibility.Hide,
},
},
'Image-Signer': {
'image-signer': {
visibilityForPage: {
index: EntryVisibility.Hide,
resume: EntryVisibility.Hide,
Expand All @@ -60,19 +60,19 @@ export const githubReposConfig: GithubReposConfig = {
resume: EntryVisibility.Hide,
},
},
'jerboa88.github.io': {
'jerboa88-github-io': {
visibilityForPage: {
index: EntryVisibility.Hide,
resume: EntryVisibility.Hide,
},
},
'Make-me-laugh': {
'make-me-laugh': {
visibilityForPage: {
index: EntryVisibility.Hide,
resume: EntryVisibility.Hide,
},
},
OnMyWay: {
'on-my-way': {
visibilityForPage: {
index: EntryVisibility.Show,
resume: EntryVisibility.Pin,
Expand Down
11 changes: 8 additions & 3 deletions src/config/metadata/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@
-----------------------------
*/

import {
NOT_FOUND_PATH,
PRIVACY_POLICY_PATH,
RESUME_PATH,
} from '../../common/constants';
import type { PagesMetadataConfig } from '../../common/types';

export const pagesMetadataConfig: PagesMetadataConfig = {
'/privacy-policy': {
[PRIVACY_POLICY_PATH]: {
title: 'Privacy Policy',
shortTitle: 'Privacy',
description:
'This privacy notice describes how and why johng.io might collect, store, use, and/or share your information.',
},
'/resume': {
[RESUME_PATH]: {
title: 'Resume',
shortTitle: 'Resume',
description:
'Resume for John Goodliff, a software developer based in Edmonton, Alberta.',
},
'/404': {
[NOT_FOUND_PATH]: {
title: '404 - Page Not Found',
shortTitle: '404',
description: "Oof, there's nothing here.",
Expand Down
Loading

0 comments on commit 5183a6b

Please sign in to comment.