Personal portfolio and technical knowledge base for Kristina Haynes (DevOps Engineer & Full Stack Developer).
Built with Docusaurus 3.9.2, React 19, deployed to GitHub Pages at kristina.codes.
npm start # Local dev server (http://localhost:3000/)
npm run build # Build static site to /build/
npm run serve # Serve built site locally
npm run deploy # Deploy to GitHub Pages (gh-pages branch)
npm run clear # Clear Docusaurus cache
npm run lint # Run all linters (JS + Markdown)
npm run lint:js # ESLint — src/, docusaurus.config.js, sidebars.js
npm run lint:md # markdownlint — docs/**/*.md, blog/**/*.md, *.mdsrc/
data/ # Data sources — add projects/experience here, not inline in pages
pages/ # Custom React pages (projects/, experience.js, index.js)
components/ # Reusable React components
css/custom.css # Global styles (portfolio-section, tech-badge, timeline-item)
docs/ # Technical knowledge base (auto-generates sidebar via sidebars.js)
blog/ # Blog posts with frontmatter metadata
static/ # Static assets (images, resume PDF)
Content is based on the GoF book and Head First Design Patterns. Java is the implementation language for all examples.
Patterns are organized by two axes:
- Purpose:
creational/,structural/,behavioral/ - Scope: class patterns (inheritance-based, fixed at compile time) vs object patterns (composition-based, configurable at runtime)
The four class-scope patterns are: Factory Method, Adapter (class variant), Template Method, Interpreter. All others are object patterns. See class-and-object-patterns.md for details.
When adding a new pattern page, add it to both its category index.md and the quick-reference table in docs/design-patterns/index.md.
- Place Markdown files under
docs/<category>/ - Each category folder must have an
index.md(Docusaurus requires it for navigation) - Sidebar is auto-generated from directory structure (
sidebars.js) - Use frontmatter:
title,sidebar_position, optionallydescription
- Filename format:
YYYY-MM-DD-slug.md - Required frontmatter:
title,authors(fromblog/authors.yml),tags(fromblog/tags.yml) - Authors and tags must be pre-registered in their respective YAML files
- Do not use
<url>autolink syntax — Docusaurus parses all.mdfiles through MDX, which treats<...>as JSX. Use[text](url)instead (also enforced by markdownlint MD034)
- Edit
src/data/projects.js— do not hardcode project data in page components - Mark key projects with
featured: trueto appear on the homepage - Tech stack uses string array; displayed as badges via CSS class
tech-badge
- Edit
src/data/experience.js— same data-driven pattern as projects
- Prefer CSS modules (
.module.css) for component-scoped styles - Global portfolio styles live in
src/css/custom.css - Key CSS classes:
.portfolio-section,.tech-badge,.timeline-item,.tech-stack - Docusaurus theme variables are customized via
--ifm-*CSS variables incustom.css
- Prettier enforced: single quotes, trailing commas (es5), 80-char prose wrap
- Run
npx prettier --write .before committing (respects.prettierignore) - File naming: kebab-case for all files and directories
Run npm run lint after editing JS or Markdown files. Husky runs lint-staged automatically on git commit.
ESLint (eslint.config.mjs) — covers src/, docusaurus.config.js, sidebars.js:
eslint:recommended+eslint-plugin-react+eslint-plugin-react-hooksreact/prop-typesandreact/react-in-jsx-scopeare disabled (no TypeScript, React 17+ JSX transform)- Escape apostrophes and quotes in JSX text with HTML entities (
',") — raw'and"in JSX text content triggerreact/no-unescaped-entities
markdownlint (.markdownlint.json) — covers docs/**/*.md, blog/**/*.md, *.md:
- MD012 — no multiple consecutive blank lines
- MD034 — no bare URLs (use
<url>or[text](url)) - MD047 — files must end with a single newline
- MD056 — table column counts must be consistent (escape
|in table cells as\|) - Disabled: MD013 (line length), MD022 (blanks around headings), MD024 (duplicate headings), MD025 (single H1), MD026 (trailing punctuation), MD029 (ordered list prefix), MD031 (blanks around fences), MD032 (blanks around lists), MD033 (inline HTML), MD036 (emphasis as heading), MD040 (fenced code language), MD041 (first-line heading), MD060 (table column style)
- Base URL is
/— all internal absolute links start with/docs/...,/blog/..., etc. - Broken links are configured to throw build errors (
onBrokenLinks: 'throw') - Cross-directory doc links (e.g. from
behavioral/todesign-patterns/) must use absolute paths like/docs/design-patterns/class-and-object-patterns— relative../links do not resolve correctly inside admonition blocks withtrailingSlash: true trailingSlash: trueis set — do not remove this. Without it, category index pages (e.g.docs/cloud/aws/index.md) are served without a trailing slash, causing relative links like./cloudformationto resolve one level too high (e.g./docs/cloud/cloudformationinstead of/docs/cloud/aws/cloudformation)- Static file links in navbar/footer config must use full absolute URLs (e.g.
https://kristina.codes/files/resume.pdf), NOT root-relative paths like/files/resume.pdf. Docusaurus processes navbarhrefvalues throughuseBaseUrlwithforcePrependBaseUrl, andtrailingSlash: truecauses it to append a trailing slash — turning/files/resume.pdfinto/files/resume.pdf/(broken). Full URLs with a protocol are treated as external and left unchanged. React page<a href>tags are unaffected and can safely use root-relative paths. - Syntax highlighting uses GitHub theme (light) and Dracula (dark)
- MDX is supported in both docs and blog — React components can be embedded in Markdown
- Mermaid diagrams are enabled via
@docusaurus/theme-mermaid— use fenced```mermaidblocks in any Markdown file
- Target:
https://kristina.codes - Custom domain configured via
static/CNAME - Branch:
gh-pages(auto-managed bynpm run deploy) - The
static/.nojekyllfile disables Jekyll — do not remove it