Source for securityslam.com, a React + Vite + TypeScript single-page app. Site settings live in src/config/site.ts. Page content lives in Markdown files under src/content/. Styling uses CSS variables from src/theme.tsx.
To report a bug or submit a change, see CONTRIBUTING.md. To report a vulnerability, see SECURITY.md. For the project's voluntary CRA (Cyber Resilience Act) readiness checklist, see CRA-READINESS.md.
Use the Node version in .nvmrc.
npm ci
npm run devOpen http://localhost:5173. make run also starts the dev server.
Other scripts:
npm run typecheckrunstsc --noEmit.npm run buildbuilds the site intodist/.npm run previewserves the builtdist/locally.
Edit src/config/site.ts. siteConfig has these keys:
siteName: sets the document title and the header logo alt text.tagline: text shown under the header logo.preregistrationUrl(optional): when set, the footer shows a pre-registration link.participatingProjectsDefaultTab(optional):"projects"or"leaderboard". Picks the default tab on content pages that list participating projects.banner(optional):{ enabled, message, storageKey }. Whenenabledis true, a dismissible banner appears at the top.storageKeyis thelocalStoragekey that remembers the dismissal.footer:copyrightTextandlinks(an array of{ href, label }).contentSections: a map of section key to{ enabled, label, inNav }. See Content sections.customNavLinks(optional): extra header links as{ path, label, children }.childrenrenders a dropdown.contactPages: an array of contact pages. See Contact pages.pastSlamReports: an array of{ href, label, description }links shown on the home page.
The header always shows a Home link. It then adds each content section where enabled is true and inNav is not false, followed by customNavLinks. A section whose path also appears in customNavLinks is not repeated.
Each key in contentSections maps to a directory under src/content/<key>/. When a section is enabled:
/<key>renders the section index. If the directory has anindex.md, its title, description, and body appear at the top./<key>/<slug>renderssrc/content/<key>/<slug>.md.- A Markdown file with a
pathin its frontmatter is also served at that path.
src/content/sections.ts loads these files. Frontmatter fields: title, description, path, hubspot, audioUrl, sectionAudio, and projects.
The library section is the exception. It has its own pages and loader. See Adding a library article.
The site currently configures three sections: slam26 (enabled), library (enabled), and blog (disabled, and src/content/blog/ does not exist yet).
contactPages is an array of:
path: URL path, such as/contact.title: page heading.description(optional): intro text above the form.hubspot(optional):{ portalId, formId, region }. When set, the page embeds that HubSpot form.formDisabled(optional): when true, the page hides the form and showsformDisabledMessageinstead.
Each entry gets its own route.
Library articles are Markdown files in src/content/library/. src/content/library.ts loads every .md file in that directory at build time.
-
Create
src/content/library/<slug>.md. The filename becomes the URL:/library/<slug>. -
Add frontmatter:
--- title: "Your article title" description: "One-line summary shown on the article card" tags: [OSPS Baseline, Helpful Tools] image: /project-logos/example.png author: Your Name, Your Organization weight: 10 --- Article body in Markdown.
titleis required. Without it the article shows "Untitled".tagsmust be a list. Tags other than badge names appear as filters on/library.imageis a path underpublic/. Put the file there first.weightis optional. Lower numbers sort first. Articles without a weight sort last, then alphabetically by title.videoUrlis optional. When set, the article embeds an MP4 video player.
-
Write the body in Markdown. The page renders it with
react-markdownandremark-gfm, so GitHub-style tables and task lists work. -
Run
npm run devand open/library/<slug>to check it.
To list an article on a badge page, add the badge name to tags, for example tags: [Chronicler]. The badge page at /library/chronicler lists every article tagged Chronicler.
Two kinds of files in this directory are not articles:
index.mdsupplies the title, description, and intro text for/library.- A file with a
badgefield in its frontmatter is a badge page. Badge pages are left out of the article list and show the badge icon frompublic/badge-icons/<badge>.png.
src/theme.tsx: defines the singleslamtheme and sets CSS variables (--gf-color-*,--gf-space-*, and others). Edit the theme object to change colors, spacing, radii, shadows, and typography.src/global.css: reset, layout, base typography,.slam-themeoverrides, and responsive rules.
src/
config/site.ts # siteConfig: identity, banner, footer, sections, nav links, contact pages
content/ # Markdown content and the loaders that read it
library/ # Library articles and badge pages
library.ts # Library loader
slam26/ # Slam26 section pages
sections.ts # Loader for every other content section
contexts/ # AudioContext for page narration
theme.tsx # Theme and CSS variables
global.css # Global layout and styles
App.tsx # Layout and config-driven routes
main.tsx # Entry; sets document title from config
components/ # Header, Footer, Banner, cards, HubSpotForm, and other shared UI
pages/ # HomePage, ContactPage, LibraryPage, LibraryArticlePage,
# SectionIndexPage, SectionItemPage
A blog, if enabled, goes through SectionIndexPage and SectionItemPage like any other content section.
Run npm run build and deploy the dist/ folder to any static host (e.g. Netlify, Vercel). For GitHub Pages, see DEPLOY.md for base path setup, the included GitHub Actions workflow, SPA routing, and optional custom domain.
- Code is licensed under the Apache License 2.0.
- Written content, the Markdown files under
src/content/library/andsrc/content/slam26/, is licensed under Creative Commons Attribution 4.0 International (CC-BY-4.0). - Third-party images, such as the project logos, sponsor logos, and maintainer photos under
public/, belong to their owners and are not covered by either license.