Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions src/components/NavBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,37 @@ import { Link, useLocation } from 'react-router-dom';
import styles from './NavBar.module.css';
import GlassCard from '@components/GlassCard';

/**
* Top-level navigation bar component for the application.
*
* Renders a logo link, a responsive hamburger toggle, and a list of navigation links.
* Internal links use client-side routing and receive an active style when their path matches the current location.
* External links open in a new tab, include an external-link icon, and have appropriate `rel` attributes for security.
*
* @returns {JSX.Element} A React element representing the navigation bar.
*/
export default function NavBar() {
const [isOpen, setIsOpen] = useState(false);
const location = useLocation();

const links = [
{ path: '/', label: 'Home' },
{ path: '/credits', label: 'Credits' },
{ path: '/about', label: 'About' },
{ path: 'https://github.com/Ryan-Millard/Img2Num', label: 'GitHub', external: true },
{ path: '/', label: 'Home', tooltip: 'Go to the home page' },
{ path: '/credits', label: 'Credits', tooltip: 'View project credits' },
{ path: '/about', label: 'About', tooltip: 'Learn more about Img2Num' },
{ path: 'https://github.com/Ryan-Millard/Img2Num', label: 'GitHub', tooltip: 'Open the project on GitHub', external: true },
];

const renderLinks = links.map((link) => {
const isActive = !link.external && location.pathname === link.path; // active if route matches
return (
<li key={link.label}>
{link.external ? (
<a href={link.path} target="_blank" rel="noopener noreferrer" className={styles.externalLink}>
<a href={link.path} target="_blank" rel="noopener noreferrer" className={styles.externalLink} title={link.tooltip}>
{link.label}
<SquareArrowOutUpRight size={'1.25em'} className={styles.externalLinkIcon} />
<SquareArrowOutUpRight size="1.25em" className={styles.externalLinkIcon} title="Opens in a new tab" />
</a>
) : (
<Link to={link.path} className={isActive ? styles.activeLink : ''}>
<Link to={link.path} className={isActive ? styles.activeLink : ''} title={link.tooltip}>
{link.label}
</Link>
)}
Expand All @@ -34,12 +43,12 @@ export default function NavBar() {
});

return (
<GlassCard as="nav" className={styles.navbar}>
<GlassCard as="nav" className={styles.navbar} style={{ padding: '0.5rem 1rem' }}>
<div className={styles.logo}>
<Link to="/">Img2Num</Link>
<Link to="/" title="Go to home page">Img2Num</Link>
</div>

<button className={styles.hamburger} onClick={() => setIsOpen(!isOpen)} aria-label="Toggle menu">
<button className={styles.hamburger} onClick={() => setIsOpen(!isOpen)} aria-label="Toggle menu" title="Toggle navigation menu">
<span className={isOpen ? styles.barActive : styles.bar}></span>
<span className={isOpen ? styles.barActive : styles.bar}></span>
<span className={isOpen ? styles.barActive : styles.bar}></span>
Expand All @@ -54,4 +63,4 @@ export default function NavBar() {
)}
</GlassCard>
);
}
}
20 changes: 12 additions & 8 deletions src/pages/Credits/ContributorsCreditsCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import styles from './ContributorsCreditsCard.module.css';
import FallbackImage from '@components/FallbackImage';
import { User } from 'lucide-react';

/**
* Render a contributors card that displays GitHub avatars, usernames, and commit counts arranged into tables.
*
* The list of contributors is split into groups of 13 and each group is rendered as a separate table.
* Avatar and username link to the contributor's GitHub profile and contribution counts are shown per row.
* @returns {JSX.Element} A React element containing the contributors card.
*/
export default function ContributorsCreditsCard() {
const chunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (_, i) => arr.slice(i * size, i * size + size));
Expand All @@ -14,32 +21,29 @@ export default function ContributorsCreditsCard() {
return (
<GlassCard>
<h2>Contributors</h2>

<div className={styles.contributorsGrid}>
{tables.map((group, i) => (
<table key={i}>
<tbody>
{group.map((c) => (
<tr key={c.id}>
<td>
<a href={c.html_url} target="_blank" rel="noopener noreferrer">
<a href={c.html_url} target="_blank" rel="noopener noreferrer" title={`Open ${c.login}'s Github profile`}>
<FallbackImage
src={c.avatar_url}
fallback={<User color="var(--color-text-light)" />}
fallback={<User color={'var(--color-text-light)'} />}
alt={c.login}
width="28"
height="28"
className={styles.avatar}
style={{ borderRadius: '50%' }}
/>
</a>
</td>

<td>
<a href={c.html_url} target="_blank" rel="noopener noreferrer">
<a href={c.html_url} target="_blank" rel="noopener noreferrer" title={`Visit ${c.login}'s Github profile`}>
{c.login}
</a>
</td>

<td>{c.contributions} commits</td>
</tr>
))}
Expand All @@ -49,4 +53,4 @@ export default function ContributorsCreditsCard() {
</div>
</GlassCard>
);
}
}
12 changes: 9 additions & 3 deletions src/pages/Credits/DependencyCreditsCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import { useState, useEffect } from 'react';
import GlassCard from '@components/GlassCard';
import { useQueries } from '@tanstack/react-query';

const ONE_WEEK = 7 * 24 * 60 * 60 * 1000; // milliseconds
const ONE_WEEK = 7 * 24 * 60 * 60 * 1000; /**
* Display two cards listing project dependencies and devDependencies with their versions and project URLs.
*
* Fetches this project's package.json on mount, queries the npm registry for each dependency to obtain a repository or homepage URL (cached for one week), and renders a table row per package showing its name, the version declared in package.json, and either a link to the package's project page, "Loading..." while the registry query is in progress, or "No URL" when none is available.
*
* @returns {JSX.Element} A React element containing two GlassCard sections: "Dependencies" and "Dev Dependencies", each with a table of package name, declared version, and project URL or status.
*/

export default function DependencyCreditsCard() {
const [deps, setDeps] = useState([]);
Expand Down Expand Up @@ -63,7 +69,7 @@ export default function DependencyCreditsCard() {
{queries[index]?.isLoading ? (
'Loading...'
) : data.url ? (
<a href={data.url} target="_blank" rel="noopener noreferrer">
<a href={data.url} target="_blank" rel="noopener noreferrer" title={`Open ${name} project page`}>
{data.url}
</a>
) : (
Expand All @@ -90,4 +96,4 @@ export default function DependencyCreditsCard() {
</GlassCard>
</>
);
}
}
19 changes: 12 additions & 7 deletions src/pages/Credits/StaticCreditsCard.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import GlassCard from '@components/GlassCard';

/**
* Renders a static credits card displaying project creator, related links, and media attribution.
*
* @returns {JSX.Element} A GlassCard containing a table with the creator, links to the repository and website, and media attribution with external links.
*/
export default function StaticCreditsCard() {
return (
<GlassCard>
Expand All @@ -10,7 +15,7 @@ export default function StaticCreditsCard() {
<tr>
<td>Created by</td>
<td colSpan="2">
<a href="https://github.com/Ryan-Millard" target="_blank">
<a href="https://github.com/Ryan-Millard" target="_blank" title="Open creator's GitHub profile">
Ryan Millard
</a>
</td>
Expand All @@ -19,12 +24,12 @@ export default function StaticCreditsCard() {
<tr>
<td>Related URLs</td>
<td>
<a href="https://github.com/Ryan-Millard/Img2Num" target="_blank">
<a href="https://github.com/Ryan-Millard/Img2Num" target="_blank" title="View the Img2Num GitHub repository">
GitHub Repository
</a>
</td>
<td>
<a href="https://ryan-millard.github.io/Img2Num/" target="_blank">
<a href="https://ryan-millard.github.io/Img2Num/" target="_blank" title="Open the Img2Num website">
Website on GitHub Pages
</a>
</td>
Expand All @@ -35,15 +40,15 @@ export default function StaticCreditsCard() {
<td>Pixel Art Hedgehog</td>
<td>
By{' '}
<a href="https://opengameart.org/users/dustdfg" target="_blank">
<a href="https://opengameart.org/users/dustdfg" target="_blank" title="View artist profile on OpenGameArt">
dustdfg
</a>
, used under{' '}
<a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">
<a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank" title="View Creative Commons BY-SA 4.0 license">
CC BY-SA 4.0
</a>
. No modifications. Source:{' '}
<a href="https://opengameart.org/content/pixel-art-hedgehog" target="_blank">
<a href="https://opengameart.org/content/pixel-art-hedgehog" target="_blank" title="View asset source on OpenGameArt">
opengameart.org
</a>
</td>
Expand All @@ -52,4 +57,4 @@ export default function StaticCreditsCard() {
</table>
</GlassCard>
);
}
}