-
Notifications
You must be signed in to change notification settings - Fork 0
Add reference links #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Created Footnotes.svelte component for displaying reference links - Added footnoteData.js with comprehensive mappings of roles to external references - Integrated footnotes into English and French homepages - Added hover interactions to display footnote details - Included references to artist portfolios, projects, and affiliated organizations - Supports both languages (EN/FR) with localized content
📝 WalkthroughWalkthroughThis pull request introduces a footnotes system by creating a new Svelte component for rendering footnotes and references, a data module providing role-based footnote content in English and French, and integrating footnote functionality into both language-specific route pages with interactive role elements. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Page as Route Page<br/>(en/fr)
participant Footnotes as Footnotes<br/>Component
participant Data as footnoteData<br/>Module
User->>Page: Hover/Focus on role span
Page->>Page: showFootnote(roleIndex)
Page->>Data: getFootnoteForRole(role, lang)
Data-->>Page: footnote object with refs
Page->>Page: Set currentFootnote state
Page->>Footnotes: Pass currentFootnote & all footnotes
Footnotes-->>User: Display footnote badge & references
User->>Page: Leave role element
Page->>Page: hideFootnote()
Page->>Page: Clear currentFootnote
Footnotes-->>User: Hide footnote display
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/routes/en/+page.svelte (1)
237-275: Add keyboard event handlers for accessibility.The interactive role spans have
role="button"andtabindex="0"but are missing keyboard event handlers. Keyboard-only users cannot activate these elements with Enter or Space keys.🔎 Proposed fix to add keyboard support
Add a helper function and wire it to the keyboard event:
function getFootnoteNumber(role) { const footnote = getFootnoteForRole(role, 'en'); return footnote ? footnote.number : null; } + + function handleKeydown(event, role) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + showFootnote(role); + } + }Then update the expanded state template:
<span class="role-text role-link" on:mouseenter={() => showFootnote(role)} on:mouseleave={hideFootnote} on:focus={() => showFootnote(role)} on:blur={hideFootnote} + on:keydown={(e) => handleKeydown(e, role)} role="button" tabindex="0" >And the collapsed state template:
<span class="role-text role-link" on:mouseenter={() => showFootnote(remainingRoles[roleIndex])} on:mouseleave={hideFootnote} on:focus={() => showFootnote(remainingRoles[roleIndex])} on:blur={hideFootnote} + on:keydown={(e) => handleKeydown(e, remainingRoles[roleIndex])} role="button" tabindex="0" >src/routes/fr/+page.svelte (1)
237-275: Add keyboard event handlers for accessibility.Similar to the English version, the interactive role spans are missing keyboard event handlers. Keyboard-only users cannot activate these elements with Enter or Space keys.
🔎 Proposed fix to add keyboard support
Add a helper function:
function getFootnoteNumber(role) { const footnote = getFootnoteForRole(role, 'fr'); return footnote ? footnote.number : null; } + + function handleKeydown(event, role) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + showFootnote(role); + } + }Then update both the expanded and collapsed state templates with
on:keydownhandlers (similar to the English version fix).
🧹 Nitpick comments (4)
src/routes/en/+page.svelte (1)
221-224: Consider memoizinggetFootnoteNumberresults.The
getFootnoteNumberfunction is called in the template for every render, which means repeated lookups of the same role-to-number mapping. For better performance, consider computing all role numbers once during initialization.🔎 Proposed optimization
Add a computed map during initialization:
let currentFootnote = null; let allFootnotes = {}; + let roleNumbers = {}; const roles = [Initialize in
onMount:// Initialize footnotes allFootnotes = getAllFootnotes('en'); + roleNumbers = roles.reduce((acc, role) => { + const footnote = getFootnoteForRole(role, 'en'); + if (footnote) acc[role] = footnote.number; + return acc; + }, {});Update the helper:
function getFootnoteNumber(role) { - const footnote = getFootnoteForRole(role, 'en'); - return footnote ? footnote.number : null; + return roleNumbers[role] || null; }src/components/Footnotes.svelte (1)
24-36: Consider sorting footnotes by number for consistent ordering.The footnotes list uses
Object.entries(footnotes)which relies on JavaScript object key ordering. While modern JavaScript maintains insertion order, explicitly sorting by the footnote number would make the ordering intention clearer and more resilient.🔎 Proposed refinement
<ol class="footnotes-list"> - {#each Object.entries(footnotes) as [number, links]} + {#each Object.entries(footnotes).sort(([a], [b]) => Number(a) - Number(b)) as [number, links]} <li id="footnote-{number}" class="footnote-item">src/lib/footnoteData.js (1)
2-321: Consider extracting data to separate JSON files.The
roleFootnotesobject contains a large amount of data (320 lines) embedded in the JavaScript module. For better maintainability and potential reusability, consider moving this data to separate JSON files (e.g.,footnotes.en.jsonandfootnotes.fr.json).This would:
- Separate data from logic
- Make it easier to update URLs and references without touching code
- Enable potential runtime loading or caching strategies
- Allow non-developers to update content more easily
🔎 Example structure
Create
src/lib/data/footnotes.en.json:{ "an intermedia artist": { "number": 1, "links": [ { "title": "Vincent Charlebois: Intermedia Artist Portfolio", "url": "https://www.vincentcharlebois.net/" } ] } }Then import in the module:
import footnotesEn from './data/footnotes.en.json'; import footnotesFr from './data/footnotes.fr.json'; export const roleFootnotes = { en: footnotesEn, fr: footnotesFr };src/routes/fr/+page.svelte (1)
248-251: Consider memoizinggetFootnoteNumberresults.Same optimization opportunity as the English version - the
getFootnoteNumberfunction is called repeatedly in the template. Consider computing all role numbers once during initialization.See the English version comment for the detailed implementation approach.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/components/Footnotes.sveltesrc/lib/footnoteData.jssrc/routes/en/+page.sveltesrc/routes/fr/+page.svelte
🔇 Additional comments (4)
src/components/Footnotes.svelte (2)
6-19: VerifycurrentFootnoteexists infootnotesobject.The condition checks
currentFootnoteis truthy andfootnotes[currentFootnote]exists, which is correct. However, ifcurrentFootnoteis set to a number that doesn't exist as a key in thefootnotesobject, the second check prevents errors.The defensive check
footnotes[currentFootnote]properly guards against undefined access.
41-55: The footnote container's fixed positioning is appropriately isolated. The only other fixed-position element in the codebase is the.skip-to-mainaccessibility link insrc/routes/+layout.svelte, which is positioned off-screen (left: -9999px) and has a higher z-index (9999), so there are no visual conflicts or layering issues.src/lib/footnoteData.js (1)
324-328: Helper function implementation is clean and defensive.The
getFootnoteForRolefunction properly handles missing language data and missing role entries by returningnull. The default parameter value forlanguageis a good practice.src/routes/fr/+page.svelte (1)
1-399: Consistent implementation across language variants.The French page implementation correctly mirrors the English version with appropriate language-specific data ('fr' parameter). This consistency makes the codebase easier to maintain.
| // Mapping of roles to their reference links | ||
| export const roleFootnotes = { | ||
| en: { | ||
| 'an intermedia artist': { | ||
| number: 1, | ||
| links: [ | ||
| { | ||
| title: 'Vincent Charlebois: Intermedia Artist Portfolio', | ||
| url: 'https://www.vincentcharlebois.net/' | ||
| }, | ||
| { | ||
| title: 'Art Souterrain Festival 2024', | ||
| url: 'https://festival2024.artsouterrain.com/en/artistes/charlebois-vincent/' | ||
| }, | ||
| { | ||
| title: 'ISEA Symposium Archives', | ||
| url: 'https://isea-archives.siggraph.org/person/vincent-charlebois/' | ||
| }, | ||
| { | ||
| title: 'Dare-Dare Gallery Event', | ||
| url: 'https://dare-dare.org/en/events/vincent-charlebois' | ||
| }, | ||
| { | ||
| title: 'Cargo Collective Portfolio', | ||
| url: 'https://cargocollective.com/tripledoublev' | ||
| } | ||
| ] | ||
| }, | ||
| 'a software developer': { | ||
| number: 2, | ||
| links: [ | ||
| { | ||
| title: 'Hypha Worker Co-operative - People', | ||
| url: 'https://hypha.coop/people/' | ||
| }, | ||
| { | ||
| title: 'Charlebois Solutions', | ||
| url: 'https://www.charlebois.solutions/' | ||
| }, | ||
| { | ||
| title: 'Personal Website', | ||
| url: 'https://vincent.charlebois.info/en/' | ||
| } | ||
| ] | ||
| }, | ||
| 'a tree planter': { | ||
| number: 3, | ||
| links: [ | ||
| { | ||
| title: 'ffforests - Fabricating Future Forests', | ||
| url: 'https://www.ffforests.xyz/v/' | ||
| }, | ||
| { | ||
| title: 'Tree Planting Instagram Highlights', | ||
| url: 'https://www.instagram.com/stories/highlights/18089075134342983/' | ||
| }, | ||
| { | ||
| title: 'Tree Planting Documentary', | ||
| url: 'https://www.youtube.com/watch?v=CO6aJd9X1Ms' | ||
| }, | ||
| { | ||
| title: 'La Fabrication de Forêts Futures - Quartier des Spectacles', | ||
| url: 'https://www.quartierdesspectacles.com/en/blog/886/la-fabrication-de-forets-futures-a-meditative-journey-into-synthetic-forests' | ||
| } | ||
| ] | ||
| }, | ||
| 'an internet explorateur': { | ||
| number: 4, | ||
| links: [ | ||
| { | ||
| title: 'dailywiki on Rhizome ArtBase', | ||
| url: 'https://rhizome.org/editorial/2023/feb/02/announcing-some-tumblrs/' | ||
| }, | ||
| { | ||
| title: 'Rhizome ArtBase Collection', | ||
| url: 'https://artbase.rhizome.org/' | ||
| } | ||
| ] | ||
| }, | ||
| 'a full-stack developer': { | ||
| number: 5, | ||
| links: [ | ||
| { | ||
| title: 'Hypha Worker Co-operative', | ||
| url: 'https://hypha.coop/' | ||
| }, | ||
| { | ||
| title: 'Charlebois Solutions', | ||
| url: 'https://www.charlebois.solutions/' | ||
| } | ||
| ] | ||
| }, | ||
| 'a performance artist': { | ||
| number: 6, | ||
| links: [ | ||
| { | ||
| title: 'Vincent Charlebois: Intermedia Artist', | ||
| url: 'https://www.vincentcharlebois.net/' | ||
| }, | ||
| { | ||
| title: 'Dare-Dare Performance', | ||
| url: 'https://dare-dare.org/en/events/vincent-charlebois' | ||
| } | ||
| ] | ||
| }, | ||
| 'a member of hypha worker co-op': { | ||
| number: 7, | ||
| links: [ | ||
| { | ||
| title: 'Hypha - People', | ||
| url: 'https://hypha.coop/people/' | ||
| }, | ||
| { | ||
| title: 'Hypha Worker Co-operative', | ||
| url: 'https://hypha.coop/' | ||
| }, | ||
| { | ||
| title: 'Hypha Governance Experiments', | ||
| url: 'https://datacommunities.ca/toolkit/hypha-worker-cooperative-governance-experiments/' | ||
| } | ||
| ] | ||
| }, | ||
| 'a cooperative technologist': { | ||
| number: 8, | ||
| links: [ | ||
| { | ||
| title: 'Hypha Worker Co-operative', | ||
| url: 'https://hypha.coop/' | ||
| }, | ||
| { | ||
| title: 'Personal Website', | ||
| url: 'https://vincent.charlebois.info/en/' | ||
| } | ||
| ] | ||
| }, | ||
| 'an artist-researcher': { | ||
| number: 9, | ||
| links: [ | ||
| { | ||
| title: 'Main Portfolio - Ecologies, Technologies', | ||
| url: 'https://www.vincentcharlebois.com/' | ||
| }, | ||
| { | ||
| title: 'Projects', | ||
| url: 'https://www.vincentcharlebois.com/projects/' | ||
| }, | ||
| { | ||
| title: 'About', | ||
| url: 'https://www.vincentcharlebois.com/about/' | ||
| }, | ||
| { | ||
| title: 'La Couleur de Montréal', | ||
| url: 'https://vincent.charlebois.info/en/couleur/' | ||
| }, | ||
| { | ||
| title: 'La Couleur de Montréal - FIFA', | ||
| url: 'https://lefifa.com/catalogue/la-couleur-de-montreal' | ||
| } | ||
| ] | ||
| } | ||
| }, | ||
| fr: { | ||
| 'un artiste intermédiatique': { | ||
| number: 1, | ||
| links: [ | ||
| { | ||
| title: 'Vincent Charlebois : Artiste intermédiatique', | ||
| url: 'https://www.vincentcharlebois.net/' | ||
| }, | ||
| { | ||
| title: 'Festival Art Souterrain 2024', | ||
| url: 'https://festival2024.artsouterrain.com/en/artistes/charlebois-vincent/' | ||
| }, | ||
| { | ||
| title: 'Archives du Symposium ISEA', | ||
| url: 'https://isea-archives.siggraph.org/person/vincent-charlebois/' | ||
| }, | ||
| { | ||
| title: 'Événement Dare-Dare', | ||
| url: 'https://dare-dare.org/en/events/vincent-charlebois' | ||
| }, | ||
| { | ||
| title: 'Portfolio Cargo Collective', | ||
| url: 'https://cargocollective.com/tripledoublev' | ||
| } | ||
| ] | ||
| }, | ||
| 'un développeur logiciel': { | ||
| number: 2, | ||
| links: [ | ||
| { | ||
| title: 'Hypha Worker Co-operative - Équipe', | ||
| url: 'https://hypha.coop/people/' | ||
| }, | ||
| { | ||
| title: 'Charlebois Solutions', | ||
| url: 'https://www.charlebois.solutions/' | ||
| }, | ||
| { | ||
| title: 'Site personnel', | ||
| url: 'https://vincent.charlebois.info/fr/' | ||
| } | ||
| ] | ||
| }, | ||
| "un planteur d'arbres": { | ||
| number: 3, | ||
| links: [ | ||
| { | ||
| title: 'ffforests - Fabrication de forêts futures', | ||
| url: 'https://www.ffforests.xyz/v/' | ||
| }, | ||
| { | ||
| title: 'Moments Instagram - Plantation', | ||
| url: 'https://www.instagram.com/stories/highlights/18089075134342983/' | ||
| }, | ||
| { | ||
| title: 'Documentaire - Plantation', | ||
| url: 'https://www.youtube.com/watch?v=CO6aJd9X1Ms' | ||
| }, | ||
| { | ||
| title: 'La Fabrication de Forêts Futures - Quartier des Spectacles', | ||
| url: 'https://www.quartierdesspectacles.com/en/blog/886/la-fabrication-de-forets-futures-a-meditative-journey-into-synthetic-forests' | ||
| } | ||
| ] | ||
| }, | ||
| "un explorateur de l'internet": { | ||
| number: 4, | ||
| links: [ | ||
| { | ||
| title: 'dailywiki sur Rhizome ArtBase', | ||
| url: 'https://rhizome.org/editorial/2023/feb/02/announcing-some-tumblrs/' | ||
| }, | ||
| { | ||
| title: 'Collection Rhizome ArtBase', | ||
| url: 'https://artbase.rhizome.org/' | ||
| } | ||
| ] | ||
| }, | ||
| 'un développeur full-stack': { | ||
| number: 5, | ||
| links: [ | ||
| { | ||
| title: 'Hypha Worker Co-operative', | ||
| url: 'https://hypha.coop/' | ||
| }, | ||
| { | ||
| title: 'Charlebois Solutions', | ||
| url: 'https://www.charlebois.solutions/' | ||
| } | ||
| ] | ||
| }, | ||
| 'un artiste performatif': { | ||
| number: 6, | ||
| links: [ | ||
| { | ||
| title: 'Vincent Charlebois : Artiste intermédiatique', | ||
| url: 'https://www.vincentcharlebois.net/' | ||
| }, | ||
| { | ||
| title: 'Performance Dare-Dare', | ||
| url: 'https://dare-dare.org/en/events/vincent-charlebois' | ||
| } | ||
| ] | ||
| }, | ||
| 'un membre de hypha worker co-op': { | ||
| number: 7, | ||
| links: [ | ||
| { | ||
| title: 'Hypha - Équipe', | ||
| url: 'https://hypha.coop/people/' | ||
| }, | ||
| { | ||
| title: 'Hypha Worker Co-operative', | ||
| url: 'https://hypha.coop/' | ||
| }, | ||
| { | ||
| title: 'Expériences de gouvernance Hypha', | ||
| url: 'https://datacommunities.ca/toolkit/hypha-worker-cooperative-governance-experiments/' | ||
| } | ||
| ] | ||
| }, | ||
| 'un technologue coopératif': { | ||
| number: 8, | ||
| links: [ | ||
| { | ||
| title: 'Hypha Worker Co-operative', | ||
| url: 'https://hypha.coop/' | ||
| }, | ||
| { | ||
| title: 'Site personnel', | ||
| url: 'https://vincent.charlebois.info/fr/' | ||
| } | ||
| ] | ||
| }, | ||
| 'un artiste-chercheur': { | ||
| number: 9, | ||
| links: [ | ||
| { | ||
| title: 'Portfolio principal - Écologies, technologies', | ||
| url: 'https://www.vincentcharlebois.com/' | ||
| }, | ||
| { | ||
| title: 'Projets', | ||
| url: 'https://www.vincentcharlebois.com/projects/' | ||
| }, | ||
| { | ||
| title: 'À propos', | ||
| url: 'https://www.vincentcharlebois.com/about/' | ||
| }, | ||
| { | ||
| title: 'La Couleur de Montréal', | ||
| url: 'https://vincent.charlebois.info/fr/couleur/' | ||
| }, | ||
| { | ||
| title: 'La Couleur de Montréal - FIFA', | ||
| url: 'https://lefifa.com/catalogue/la-couleur-de-montreal' | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Extract and check all URLs from the footnoteData.js file
echo "=== Extracting all URLs from footnoteData.js ==="
rg -oN "https?://[^\"]+" src/lib/footnoteData.js | sort -u > /tmp/urls.txt
echo -e "\n=== Checking for HTTP (non-HTTPS) URLs ==="
grep "^http://" /tmp/urls.txt || echo "All URLs use HTTPS ✓"
echo -e "\n=== List of all unique URLs ==="
cat /tmp/urls.txt
echo -e "\n=== Total unique URLs ==="
wc -l < /tmp/urls.txt
echo -e "\n=== Testing URL accessibility ==="
while read url; do
echo -n "Testing $url ... "
http_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url" 2>/dev/null)
if [ "$http_code" = "200" ] || [ "$http_code" = "301" ] || [ "$http_code" = "302" ]; then
echo "✓ HTTP $http_code"
else
echo "✗ HTTP $http_code"
fi
done < /tmp/urls.txtRepository: tripledoublev/vincentcharlebois.com
Length of output: 3101
🏁 Script executed:
#!/bin/bash
# Verify actual URL format in the source file
echo "=== Checking actual URL format in source file ==="
head -100 src/lib/footnoteData.js | grep -A 2 "url:"
echo -e "\n=== Re-extract URLs with corrected pattern ==="
# Match URLs within quotes more precisely
rg -oP "(?<=url.*?')[https://[^']+(?=')" src/lib/footnoteData.js | sort -u > /tmp/urls_corrected.txt
echo "=== Corrected unique URLs ==="
cat /tmp/urls_corrected.txt
echo -e "\n=== Testing corrected URLs for accessibility ==="
while read url; do
echo -n "Testing $url ... "
http_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url" 2>/dev/null)
if [ "$http_code" = "200" ] || [ "$http_code" = "301" ] || [ "$http_code" = "302" ]; then
echo "✓ HTTP $http_code"
elif [ "$http_code" = "403" ]; then
echo "⚠ HTTP $http_code (forbidden/blocked)"
else
echo "✗ HTTP $http_code"
fi
done < /tmp/urls_corrected.txtRepository: tripledoublev/vincentcharlebois.com
Length of output: 1628
🏁 Script executed:
#!/bin/bash
echo "=== Extracting URLs correctly using grep and sed ==="
grep -oP "url: '\K[^']+" src/lib/footnoteData.js | sort -u > /tmp/urls_clean.txt
echo "=== Cleaned unique URLs ==="
cat /tmp/urls_clean.txt
echo -e "\n=== Total unique URLs ==="
wc -l < /tmp/urls_clean.txt
echo -e "\n=== Testing URL accessibility (with proper URLs) ==="
while read url; do
echo -n "Testing $url ... "
http_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url" 2>/dev/null)
if [ "$http_code" = "200" ] || [ "$http_code" = "301" ] || [ "$http_code" = "302" ]; then
echo "✓ HTTP $http_code"
elif [ "$http_code" = "403" ]; then
echo "⚠ HTTP $http_code (forbidden)"
else
echo "✗ HTTP $http_code"
fi
done < /tmp/urls_clean.txt
echo -e "\n=== Summary of broken URLs ==="
broken_count=0
while read url; do
http_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url" 2>/dev/null)
if ! [[ "$http_code" =~ ^(200|301|302)$ ]]; then
echo " - $url (HTTP $http_code)"
((broken_count++))
fi
done < /tmp/urls_clean.txt
echo "Total broken URLs: $broken_count"Repository: tripledoublev/vincentcharlebois.com
Length of output: 3232
Fix two inaccessible URLs in footnoteData.js.
All 23 URLs use HTTPS correctly, but 2 are not currently accessible and should be verified or removed:
https://isea-archives.siggraph.org/person/vincent-charlebois/returns HTTP 404 (appears in "an intermedia artist" role)https://rhizome.org/editorial/2023/feb/02/announcing-some-tumblrs/returns HTTP 403 (appears in "an internet explorateur" role)
The remaining 21 URLs are accessible and valid (HTTP 200, 301, or 302).
footnotes component and links found by claude
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.