Skip to content

Commit 823245f

Browse files
Projects: rename SecureTrain card, add images, restructure sections
- Rename SecureTrain Gamification to Crypto compliance - Add screenshots to Crypto compliance and BJJ Move Graph cards - Rename Open source section to Open source projects I founded - Pull in other session changes: projects split, CI workflow, prettier/cspell/lychee configs, homepage + GitHubStats tweaks - Gitignore the nested OWASP CheatSheetSeries clone Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 38f8013 commit 823245f

14 files changed

Lines changed: 495 additions & 71 deletions

File tree

.github/workflows/ci.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches-ignore:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
workflow_dispatch:
11+
12+
concurrency:
13+
group: ci-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
typecheck:
18+
name: Typecheck
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
- uses: actions/setup-node@v4
23+
with:
24+
node-version: 20
25+
cache: npm
26+
- run: npm ci
27+
- run: npm run typecheck
28+
29+
build:
30+
name: Build (catches internal broken links)
31+
runs-on: ubuntu-latest
32+
steps:
33+
- uses: actions/checkout@v4
34+
- uses: actions/setup-node@v4
35+
with:
36+
node-version: 20
37+
cache: npm
38+
- run: npm ci
39+
- run: npm run build
40+
- name: Upload build artifact
41+
uses: actions/upload-artifact@v4
42+
with:
43+
name: build
44+
path: build
45+
retention-days: 1
46+
47+
spellcheck:
48+
name: Spellcheck (cspell)
49+
runs-on: ubuntu-latest
50+
steps:
51+
- uses: actions/checkout@v4
52+
- uses: actions/setup-node@v4
53+
with:
54+
node-version: 20
55+
- name: Run cspell
56+
run: npx --yes cspell@8 "**/*.{md,mdx,ts,tsx}" --no-progress --gitignore
57+
58+
linkcheck:
59+
name: External link check (lychee)
60+
runs-on: ubuntu-latest
61+
needs: build
62+
steps:
63+
- uses: actions/checkout@v4
64+
- name: Download build artifact
65+
uses: actions/download-artifact@v4
66+
with:
67+
name: build
68+
path: build
69+
- name: Lychee link check
70+
uses: lycheeverse/lychee-action@v2
71+
with:
72+
args: >-
73+
--config ./lychee.toml
74+
--no-progress
75+
'./build/**/*.html'
76+
'./**/*.md'
77+
'./**/*.mdx'
78+
fail: true
79+
80+
format:
81+
name: Format check (prettier)
82+
runs-on: ubuntu-latest
83+
steps:
84+
- uses: actions/checkout@v4
85+
- uses: actions/setup-node@v4
86+
with:
87+
node-version: 20
88+
- name: Run prettier
89+
run: npx --yes prettier@3 --check "src/**/*.{ts,tsx,css}" "docs/**/*.{md,mdx}" "blog/**/*.{md,mdx}"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Dependencies
22
/node_modules
33

4+
# Nested clones (OWASP CheatSheetSeries etc.)
5+
/CheatSheetSeries
6+
47
# Production
58
/build
69

.prettierignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules
2+
build
3+
.docusaurus
4+
static
5+
scraped_css
6+
CheatSheetSeries
7+
package-lock.json
8+
*.svg

.prettierrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"singleQuote": true,
3+
"trailingComma": "all",
4+
"printWidth": 100,
5+
"semi": true,
6+
"arrowParens": "avoid"
7+
}

cspell.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"version": "0.2",
3+
"language": "en-GB,en",
4+
"ignorePaths": [
5+
"node_modules",
6+
"build",
7+
".docusaurus",
8+
"static",
9+
"scraped_css",
10+
"CheatSheetSeries",
11+
"package-lock.json",
12+
"*.svg"
13+
],
14+
"words": [
15+
"franrob",
16+
"Docusaurus",
17+
"Mixpanel",
18+
"autocapture",
19+
"Supabase",
20+
"gamification",
21+
"Gibraltar",
22+
"GFSC",
23+
"iGaming",
24+
"DLT",
25+
"Neo4j",
26+
"Redpanda",
27+
"opentelemetry",
28+
"semconv",
29+
"OWASP",
30+
"BOLA",
31+
"Koinju",
32+
"cspell",
33+
"lychee",
34+
"Vite",
35+
"Vercel",
36+
"Turborepo",
37+
"codemod",
38+
"codemods",
39+
"shadcn",
40+
"dapp",
41+
"repo",
42+
"repos",
43+
"franrob-projects",
44+
"Fran",
45+
"Roberts"
46+
]
47+
}

docusaurus.config.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ mixpanel.init('f668a74691e1d95e8f4e2665a0486185', {
8181
},
8282
navbar: {
8383
title: 'About me',
84+
hideOnScroll: false,
8485
items: [
8586
{
86-
type: 'docSidebar',
87-
sidebarId: 'tutorialSidebar',
88-
position: 'left',
87+
to: '/docs/intro',
8988
label: 'About work',
89+
position: 'left',
9090
},
9191
{
9292
to: '/projects',
@@ -103,6 +103,16 @@ mixpanel.init('f668a74691e1d95e8f4e2665a0486185', {
103103
label: 'GitHub',
104104
position: 'right',
105105
},
106+
{
107+
href: 'https://linkedin.com/in/francis-roberts-5850b396',
108+
label: 'LinkedIn',
109+
position: 'right',
110+
},
111+
{
112+
href: 'mailto:francis@fantasyfruitsatlife.com',
113+
label: 'Email',
114+
position: 'right',
115+
},
106116
],
107117
},
108118
prism: {

lychee.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
max_redirects = 5
2+
max_retries = 2
3+
retry_wait_time = 2
4+
timeout = 20
5+
6+
accept = ["200", "206", "429"]
7+
8+
exclude = [
9+
"^https?://localhost",
10+
"^https?://127\\.0\\.0\\.1",
11+
"^https?://(www\\.)?linkedin\\.com",
12+
"^https?://(www\\.)?x\\.com",
13+
"^https?://(www\\.)?twitter\\.com",
14+
"^mailto:",
15+
]
16+
17+
exclude_path = [
18+
"node_modules",
19+
".docusaurus",
20+
"CheatSheetSeries",
21+
"scraped_css",
22+
]
23+
24+
cache = true
25+
max_cache_age = "1d"

src/components/GitHubStats.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,14 @@ const GitHubStats = () => {
115115
margin: '0 auto'
116116
}}>
117117
{contributions.slice(-365).map((day, i) => (
118-
<div
119-
key={i}
118+
<div
119+
key={i}
120+
title={`${day.count} contributions on ${day.date}`}
120121
style={{
121122
backgroundColor: getContributionColor(day.count),
122123
width: '10px',
123124
height: '10px',
124125
borderRadius: '2px',
125-
title: `${day.count} contributions on ${day.date}`
126126
}}
127127
/>
128128
))}

src/css/custom.css

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ body {
9898
font-smoothing: antialiased;
9999
-webkit-font-smoothing: antialiased;
100100
-moz-osx-font-smoothing: grayscale;
101+
overflow-x: hidden;
102+
max-width: 100%;
103+
}
104+
105+
img {
106+
max-width: 100%;
101107
}
102108

103109
/* Typography - Supabase style headings */
@@ -368,6 +374,102 @@ main {
368374
}
369375
}
370376

377+
/* Mobile: ensure the navbar hamburger + menu work and tighten spacing */
378+
@media (max-width: 996px) {
379+
.navbar {
380+
padding: 0 4px;
381+
}
382+
383+
.navbar__inner {
384+
padding: 0 12px;
385+
}
386+
387+
.navbar__brand {
388+
margin-right: 0;
389+
}
390+
391+
main {
392+
padding: 0;
393+
}
394+
395+
/* Expansive mobile drawer */
396+
.navbar-sidebar {
397+
width: 100vw;
398+
max-width: 100vw;
399+
background: linear-gradient(180deg, #0f0f0f 0%, #0a0a0a 100%);
400+
border-right: 1px solid rgba(64, 215, 124, 0.15);
401+
}
402+
403+
.navbar-sidebar__brand {
404+
background: rgba(64, 215, 124, 0.05);
405+
border-bottom: 1px solid rgba(64, 215, 124, 0.15);
406+
padding: 1.25rem 1.5rem;
407+
min-height: 64px;
408+
}
409+
410+
.navbar-sidebar__brand .navbar__title {
411+
font-size: 1.25rem;
412+
font-weight: 600;
413+
color: var(--ifm-color-content);
414+
letter-spacing: -0.01em;
415+
}
416+
417+
.navbar-sidebar__close {
418+
color: var(--ifm-color-primary);
419+
}
420+
421+
.navbar-sidebar__items {
422+
padding: 0.5rem 0;
423+
}
424+
425+
.navbar-sidebar__item {
426+
padding: 0.5rem 0.75rem;
427+
}
428+
429+
.navbar-sidebar .menu__list {
430+
padding: 0;
431+
}
432+
433+
.navbar-sidebar .menu__list-item {
434+
margin: 0.25rem 0;
435+
}
436+
437+
.navbar-sidebar .menu__link {
438+
display: flex;
439+
align-items: center;
440+
font-size: 1rem;
441+
font-weight: 500;
442+
padding: 1rem 1.25rem;
443+
border-radius: 12px;
444+
color: var(--ifm-color-content);
445+
background: rgba(64, 215, 124, 0.04);
446+
border: 1px solid rgba(64, 215, 124, 0.08);
447+
transition: all 0.15s ease;
448+
}
449+
450+
.navbar-sidebar .menu__link:hover,
451+
.navbar-sidebar .menu__link--active {
452+
background: rgba(64, 215, 124, 0.1);
453+
border-color: rgba(64, 215, 124, 0.25);
454+
color: var(--ifm-color-primary);
455+
}
456+
457+
.navbar-sidebar .menu__link--sublist::after {
458+
background-color: var(--ifm-color-primary);
459+
}
460+
461+
/* Back button on secondary views */
462+
.navbar-sidebar__back {
463+
margin: 0.75rem 1rem;
464+
padding: 0.75rem 1rem;
465+
border-radius: 8px;
466+
background: rgba(64, 215, 124, 0.06);
467+
border: 1px solid rgba(64, 215, 124, 0.15);
468+
font-weight: 500;
469+
color: var(--ifm-color-primary);
470+
}
471+
}
472+
371473
/* Blog list: cover images are mostly small logos, don't upscale them */
372474
.blog-list-page article img:not(.avatar__photo),
373475
.blog-wrapper.blog-list-page article img:not(.avatar__photo) {

0 commit comments

Comments
 (0)