Skip to content

Add schema.org LearningResource markup and individual item landing pages#40

Open
jgrethe wants to merge 4 commits intoReproNim:mainfrom
jgrethe:main
Open

Add schema.org LearningResource markup and individual item landing pages#40
jgrethe wants to merge 4 commits intoReproNim:mainfrom
jgrethe:main

Conversation

@jgrethe
Copy link
Copy Markdown

@jgrethe jgrethe commented Apr 29, 2026

Summary

  • Adds schema.org LearningResource JSON-LD markup (as an ItemList) injected into <head> on the main browse page for improved SEO and structured data
  • Adds individual item landing pages at /#/item/:id (hash routing for GitHub Pages compatibility) with per-item LearningResource JSON-LD
  • Card titles now link to the item landing page; external "Access Material" links are preserved unchanged
  • identifier field uses the item's landing page URL (e.g. https://repronim.github.io/ReproInventory/#/item/1)
  • isAccessibleForFree set to true for all items
  • Adds react-router-dom for client-side routing
  • Extracts a shared useInventoryData hook used by both pages
  • Adds workflow_dispatch trigger to the deploy workflow for manual runs

Test plan

  • Browse page loads and materials display correctly
  • Card titles link to /#/item/:id landing pages
  • "Access Material" external links open the resource URL in a new tab
  • Item landing page displays full detail for each item
  • <head> contains <script type="application/ld+json"> with schema.org markup after data loads (check DevTools Elements panel)
  • Deploy workflow can be triggered manually via Actions tab

🤖 Generated with Claude Code

jgrethe and others added 4 commits April 28, 2026 12:17
- Add schema.org/LearningResource JSON-LD (ItemList) injected into <head> on the browse page
- Add individual item landing pages at /#/item/:id with per-item JSON-LD
- Add react-router-dom with HashRouter for GitHub Pages compatibility
- Extract shared useInventoryData hook
- Card titles now link to item pages; external URL links unchanged
- identifier field uses repronim.inventory:<id> CURIE format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements routing for the ReproInventory frontend using react-router-dom, introducing a dedicated ItemPage and a useInventoryData hook for centralized data fetching. It also adds utilities to generate and inject Schema.org JSON-LD metadata for improved SEO. Feedback focuses on mitigating potential XSS vulnerabilities during script injection, ensuring type consistency for the last_updated field in the inventory data, and adopting safer TypeScript practices by avoiding the any type in catch blocks.

"@context": "https://schema.org",
...toSchemaOrgLearningResource(entry),
}
return JSON.stringify(ld)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The generated JSON-LD string is injected into a <script> tag in the document head. If any data field (such as description) contains the string </script>, it will cause the browser to prematurely terminate the script block, which can lead to broken pages or XSS vulnerabilities. Escaping the < character as \u003c prevents this issue.

Suggested change
return JSON.stringify(ld)
return JSON.stringify(ld).replace(/</g, '\\u003c')

"item": toSchemaOrgLearningResource(entry),
})),
}
return JSON.stringify(ld)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Same as above, the JSON-LD string should be escaped to prevent premature script termination if the data contains </script> sequences.

Suggested change
return JSON.stringify(ld)
return JSON.stringify(ld).replace(/</g, '\\u003c')

"Hands-on tutorial / notebooks"
],
"open_dataset": true,
"last_updated": 2026,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The last_updated field is provided as a number (2026) here, while other entries in this file use strings (e.g., "2023"). For consistency and to align with the ReproInventoryEntry interface which defines this field as a string, it should be quoted. This also ensures better compatibility with schema.org consumers that expect string values for dates.

Suggested change
"last_updated": 2026,
"last_updated": "2026",

Comment on lines +16 to +17
} catch (e: any) {
setError(e.message)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using any in a catch block is discouraged in TypeScript. It is safer to use unknown (the default in newer TS versions) and check if the error is an instance of Error before accessing the message property. This prevents potential runtime errors if something other than an Error object is thrown.

Suggested change
} catch (e: any) {
setError(e.message)
} catch (e) {
setError(e instanceof Error ? e.message : String(e))

@jgrethe
Copy link
Copy Markdown
Author

jgrethe commented Apr 29, 2026

Hi @likeajumprope - I added some functionality to ReproInventory at the SOBP hackathon on a fork - support for schema.org markup and individual landing pages for the entries so that ReproInventory can be found via Google, etc. The indivudal pages have schema.org markup as well. This is running on Github pages from my fork: https://jgrethe.github.io/ReproInventory/

To see the schema.org markup - you can inspect the head element and it is the last item (json-ld content).

Also, used this as a test scenario for working with Claude Code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant