Skip to content

Commit

Permalink
106 feature new artifact page (#118)
Browse files Browse the repository at this point in the history
* Remove redundant PR type spec

* Implemented routes, added pages

* Comments

* Link to artifact pages, use artifact id

* Artifact page basic components

* Artifact page responsive layout

* Extract props and fixed prop names

* Rich Link basic in place, fine-tuning sass

* Rich links with style

* Tweak margins, fixed back button styling

* Installed photoswipe...

* Added style and is rendering, but opening in new tab

* Fixed gallery not opening

* Set thumbnail width

* Extra comments
  • Loading branch information
kjy5 authored Dec 25, 2022
1 parent c2966d2 commit 0604d58
Show file tree
Hide file tree
Showing 23 changed files with 615 additions and 66 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
},
plugins: ["@typescript-eslint"],
root: true,
ignorePatterns: ["dist", "vite.config.ts"],
ignorePatterns: ["dist", "vite.config.ts", "src/components/Gallery.jsx"],
rules: {
"sort-imports": "error",
},
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Build Website
# Controls when the workflow will run
on:
pull_request:
types: [opened, synchronize, reopened]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/reformat-and-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: Reformat and Lint

on:
pull_request:
types: [opened, synchronize, reopened]

workflow_dispatch:

Expand Down
108 changes: 107 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@
"relint": "prettier --write . && eslint --fix ."
},
"dependencies": {
"photoswipe": "^5.3.4",
"photoswipe-dynamic-caption-plugin": "^1.2.7",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-router-dom": "^6.6.1"
},
"devDependencies": {
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@types/react-router-dom": "^5.3.3",
"@typescript-eslint/eslint-plugin": "^5.47.0",
"@typescript-eslint/parser": "^5.47.0",
"@vitejs/plugin-legacy": "^3.0.1",
Expand Down
22 changes: 14 additions & 8 deletions src/components/ArtifactCard.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import "../styles/ArtifactCard.sass";
import { Artifact } from "../scripts/interfaces";
import { ArtifactData } from "../scripts/interfaces";
import { NavLink } from "react-router-dom";

/**
* Artifact card component. Displays high-level information about an artifact (title, subtitle, 3D graphic).
* @param props {Artifact} artifact - Artifact object
* ArtifactPage card component. Displays high-level information about an artifact (title, subtitle, 3D graphic).
* @param {{artifact: ArtifactData}} props - Artifact to display
* @constructor
* @return {JSX.Element}
*/
export default function ArtifactCard(props: {
artifact: Artifact;
artifact: ArtifactData;
}): JSX.Element {
// Extract props
const { id, title, subtitle } = props.artifact;

// Render
return (
<div className="artifact-card">
/* skipcq: JS-0394 */
<NavLink to={`/honors-portfolio/${id}`} className="artifact-card">
<div className="artifact-card__graphic-container" />
<h1 className="artifact-card__title">{props.artifact.title}</h1>
<h3 className="artifact-card__subtitle">{props.artifact.subtitle}</h3>
</div>
<h1 className="artifact-card__title">{title}</h1>
<h3 className="artifact-card__subtitle">{subtitle}</h3>
</NavLink>
);
}
3 changes: 3 additions & 0 deletions src/components/Gallery.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ImageData } from "../scripts/interfaces";

export default function Gallery(props: { images: ImageData[] }): JSX.Element;
93 changes: 93 additions & 0 deletions src/components/Gallery.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// noinspection JSUnusedGlobalSymbols

import "../styles/Gallery.sass";
import { useEffect } from "react";
import PhotoSwipeLightbox from "photoswipe/lightbox";
import "photoswipe/style.css";
import "photoswipe-dynamic-caption-plugin/photoswipe-dynamic-caption-plugin.css";
import PropTypes from "prop-types";
import PhotoSwipeDynamicCaption from "photoswipe-dynamic-caption-plugin";

/**
* Gallery component, displays a gallery of images
* @param {object} props - Images to display
* @constructor
* @returns {JSX.Element}
*/
export default function Gallery(props) {
// Extract prop data
const { images } = props;
const galleryID = images[0].artifact.replaceAll(" ", "-").toLowerCase();

// Initialize the gallery
useEffect(() => {
// Create lightbox
let lightbox = new PhotoSwipeLightbox({
gallery: `#${galleryID}`,
children: "a",
padding: { top: 30, right: 70, bottom: 30, left: 70 },
preloaderDelay: 0,
pswpModule: () => import("photoswipe"),
});

// Add dynamic caption plugin
// noinspection JSUnusedLocalSymbols
const _photoSwipeDynamicCaption = new PhotoSwipeDynamicCaption(lightbox, {
type: "auto",
captionContent: ".pswp-caption-content",
});

// Start the lightbox
lightbox.init();

// Cleanup
return () => {
lightbox.destroy();
lightbox = null;
};
}, []);

// Render
return (
<div className={"Gallery"} id={galleryID}>
{images.map((image) => (
<a
key={image.name}
href={image.image}
data-pswp-width={image.width}
data-pswp-height={image.height}
target={"_blank"}
rel={"noopener noreferrer"}
>
{/* Thumbnail */}
<img
className={"Gallery__thumbnail"}
src={image.thumbnail}
alt={image.name}
/>

{/* Caption */}
<span className={"pswp-caption-content"}>
<h2>{image.name}</h2>
<br />
{image.description}
</span>
</a>
))}
</div>
);
}

Gallery.propTypes = {
images: PropTypes.arrayOf(
PropTypes.shape({
artifact: PropTypes.string.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
description: PropTypes.string,
thumbnail: PropTypes.string.isRequired,
image: PropTypes.string.isRequired,
})
),
};
13 changes: 7 additions & 6 deletions src/components/Quarter.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import "../styles/Quarter.sass";
import { Artifact } from "../scripts/interfaces";
import ArtifactCard from "./ArtifactCard";
import { ArtifactData } from "../scripts/interfaces";

/**
* Quarter component. Groups a quarter heading with a grid of artifacts.
* @param props {Artifact[]} filterArtifacts - Artifacts filtered by quarter
* @param {{filteredArtifacts: ArtifactData[]}} props - filterArtifacts - Artifacts filtered by quarter
* @constructor
* @return {JSX.Element}
*/
export default function Quarter(props: {
filterArtifacts: Artifact[];
filteredArtifacts: ArtifactData[];
}): JSX.Element {
// Compute quarter string
let quarter = "Fall";
switch (props.filterArtifacts[0].quarter) {
switch (props.filteredArtifacts[0].quarter) {
case 1:
quarter = "Winter";
break;
Expand All @@ -27,12 +27,13 @@ export default function Quarter(props: {
break;
}

// Render
return (
<div className="quarter">
<h1 className="quarter__name">{quarter}</h1>
<div className="quarter__artifacts">
{props.filterArtifacts.map((artifact: Artifact) => (
<ArtifactCard key={artifact.title} artifact={artifact} />
{props.filteredArtifacts.map((artifact: ArtifactData) => (
<ArtifactCard key={artifact.id} artifact={artifact} />
))}
</div>
</div>
Expand Down
Loading

0 comments on commit 0604d58

Please sign in to comment.