Skip to content

Commit bd61dff

Browse files
committed
ProstDev site — Astro 5 static site (initial public history)
MuleSoft video tutorials + AI-friendly blog posts. Migrated off Wix. Builds + deploys to GitHub Pages via .github/workflows/deploy.yml. Internal Claude Code tooling + CLAUDE.md live in the private ProstDev/prostdev-internal repo, mounted at .claude/ as a submodule; root CLAUDE.md is a symlink into it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0 parents  commit bd61dff

1,491 files changed

Lines changed: 43349 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude

Submodule .claude added at a16c7a7
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
name: Check DataWeave version
2+
3+
# Watches the LIVE MuleSoft docs for a newer DataWeave version (or newly added
4+
# dw::Core functions) than the cheatsheet records, and opens/updates ONE tracking
5+
# issue when the article is out of date. It NEVER edits the article — the verbatim
6+
# sync is a human/`dataweave-reference-syncer` job (see CLAUDE.md).
7+
#
8+
# Trigger: weekly cron + manual. (MuleSoft publishes no RSS feed for releases, and
9+
# the version source is external to this repo, so a schedule is the right shape —
10+
# `push` would mostly re-check after unrelated commits. Run "Run workflow" anytime.)
11+
12+
on:
13+
schedule:
14+
- cron: '0 13 * * 1' # every Monday 13:00 UTC
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: read
19+
issues: write
20+
21+
concurrency:
22+
group: check-dataweave-version
23+
cancel-in-progress: false
24+
25+
jobs:
26+
check:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- name: Checkout
30+
uses: actions/checkout@v4
31+
32+
- name: Set up Node
33+
uses: actions/setup-node@v4
34+
with:
35+
node-version: 20
36+
37+
- name: Check cheatsheet vs. live DataWeave docs
38+
id: check
39+
run: node scripts/check-dataweave-version.mjs
40+
41+
- name: Open / update tracking issue
42+
if: steps.check.outputs.outdated == 'true'
43+
uses: actions/github-script@v7
44+
env:
45+
ISSUE_TITLE: ${{ steps.check.outputs.issue_title }}
46+
ISSUE_BODY: ${{ steps.check.outputs.issue_body }}
47+
LIVE_VERSION: ${{ steps.check.outputs.live_version }}
48+
with:
49+
script: |
50+
const { ISSUE_TITLE, ISSUE_BODY, LIVE_VERSION } = process.env;
51+
const label = 'dataweave-version';
52+
53+
// Ensure the label exists (ignore "already exists").
54+
try {
55+
await github.rest.issues.createLabel({
56+
owner: context.repo.owner, repo: context.repo.repo,
57+
name: label, color: '0e8a16',
58+
description: 'DataWeave cheatsheet out of date vs. the live docs',
59+
});
60+
} catch (e) { if (e.status !== 422) throw e; }
61+
62+
// Reuse the existing open tracking issue if there is one (don't spam a
63+
// new issue every week — update the body and ping instead).
64+
const existing = await github.paginate(github.rest.issues.listForRepo, {
65+
owner: context.repo.owner, repo: context.repo.repo,
66+
state: 'open', labels: label, per_page: 100,
67+
});
68+
69+
if (existing.length) {
70+
const issue = existing[0];
71+
await github.rest.issues.update({
72+
owner: context.repo.owner, repo: context.repo.repo,
73+
issue_number: issue.number, title: ISSUE_TITLE, body: ISSUE_BODY,
74+
});
75+
await github.rest.issues.createComment({
76+
owner: context.repo.owner, repo: context.repo.repo,
77+
issue_number: issue.number,
78+
body: `🔁 Re-checked: docs \`latest\` is at **${LIVE_VERSION}**. Details updated above.`,
79+
});
80+
core.info(`Updated existing issue #${issue.number}`);
81+
} else {
82+
const created = await github.rest.issues.create({
83+
owner: context.repo.owner, repo: context.repo.repo,
84+
title: ISSUE_TITLE, body: ISSUE_BODY, labels: [label],
85+
});
86+
core.info(`Opened issue #${created.data.number}`);
87+
}

.github/workflows/deploy.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
# Allow one concurrent deployment, cancel in-progress runs on new pushes.
14+
concurrency:
15+
group: pages
16+
cancel-in-progress: true
17+
18+
jobs:
19+
build:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
- name: Install, build, and upload
25+
uses: withastro/action@v4
26+
# withastro/action runs `npm ci && npm run build` (which also runs
27+
# `pagefind --site dist`) and uploads ./dist as the Pages artifact.
28+
29+
deploy:
30+
needs: build
31+
runs-on: ubuntu-latest
32+
environment:
33+
name: github-pages
34+
url: ${{ steps.deployment.outputs.page_url }}
35+
steps:
36+
- name: Deploy to GitHub Pages
37+
id: deployment
38+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# build output
2+
dist/
3+
# generated types
4+
.astro/
5+
# dependencies
6+
node_modules/
7+
# logs
8+
npm-debug.log*
9+
yarn-debug.log*
10+
yarn-error.log*
11+
pnpm-debug.log*
12+
# environment variables
13+
.env
14+
.env.production
15+
# macOS
16+
.DS_Store
17+
# jetbrains setting folder
18+
.idea/
19+
# gist-recovery scratch (regenerable; see scripts/recover-gists.mjs)
20+
gist-cache.json
21+
gist-recovery-proposals.json

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule ".claude"]
2+
path = .claude
3+
url = https://github.com/ProstDev/prostdev-internal.git

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.claude/CLAUDE.md

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# ProstDev
2+
3+
The ProstDev website — MuleSoft video tutorials and AI-friendly blog posts. Built with
4+
[Astro](https://astro.build), hosted free on GitHub Pages.
5+
6+
Replaces the previous Wix site. **Primary focus: YouTube videos.** Secondary focus:
7+
SEO/AEO-optimized blog posts that AI and search engines can read.
8+
9+
## Develop
10+
11+
```bash
12+
npm install
13+
npm run dev # http://localhost:4321
14+
```
15+
16+
```bash
17+
npm run build # astro build + pagefind (search index)
18+
npm run preview # serve the production build locally (search works here)
19+
```
20+
21+
> Search (Pagefind) only works against a built site — use `npm run build && npm run preview`,
22+
> not `npm run dev`.
23+
24+
## Add a new video
25+
26+
Edit [`src/data/videos.ts`](src/data/videos.ts):
27+
28+
1. Add a `Video` entry near the **top** of the `VIDEOS` array (newest first) with a unique
29+
`slug`, the `youtubeId`, title, description, and which `playlists` it belongs to.
30+
2. (Optional but recommended) Add a transcript at
31+
`src/content/transcripts/<youtubeId>.md` so the video is AI-readable and searchable.
32+
3. Commit & push — GitHub Actions rebuilds and deploys automatically.
33+
34+
Each video gets a page at `/video/<slug>`, a raw-markdown version at `/video/<slug>.md`, and
35+
is included in `/llms.txt` + `/llms-full.txt`.
36+
37+
## Add a blog post
38+
39+
Create `src/content/blog/<slug>.mdx` with frontmatter:
40+
41+
```yaml
42+
---
43+
title: 'Your title'
44+
description: 'One-sentence summary (used for SEO + cards).'
45+
pubDate: 2026-01-15
46+
category: Tutorials # Challenges | Tutorials | Guides | Opinion | News
47+
tags: [MuleSoft, DataWeave]
48+
youtubeId: abc123 # optional — embeds the video at the top
49+
heroImage: ./cover.png # optional
50+
draft: false # drafts are hidden in production
51+
---
52+
```
53+
54+
Posts render at `/post/<slug>` with an auto "On this page" nav, a Copy/View-as-Markdown menu,
55+
and `/post/<slug>.md` raw markdown.
56+
57+
## Machine-readable / AEO endpoints
58+
59+
- `/llms.txt` — curated index of all videos + posts ([llmstxt.org](https://llmstxt.org) format)
60+
- `/llms-full.txt` — every post body + video transcript concatenated
61+
- `/post/<slug>.md`, `/video/<slug>.md` — raw markdown per page
62+
- `/rss.xml`, `/sitemap-index.xml`, `/robots.txt`
63+
64+
## Deploy / DNS cutover
65+
66+
Pushing to `main` triggers `.github/workflows/deploy.yml`, which builds and deploys to
67+
GitHub Pages. The custom domain is set via [`public/CNAME`](public/CNAME) (`prostdev.com`).
68+
69+
**One-time setup:**
70+
71+
1. In the GitHub repo: **Settings → Pages → Source → GitHub Actions**.
72+
2. Verify the site works at the temporary `*.github.io` URL.
73+
3. **Then** update DNS at your registrar (away from Wix):
74+
- Apex `prostdev.com`: A records to GitHub Pages IPs
75+
`185.199.108.153`, `185.199.109.153`, `185.199.110.153`, `185.199.111.153`
76+
(and AAAA records for IPv6 if desired).
77+
- `www`: CNAME → `<github-username>.github.io`.
78+
4. In Settings → Pages, set the custom domain to `prostdev.com` and enable **Enforce HTTPS**.
79+
80+
Keep Wix live until the new site is verified, to avoid downtime.

astro.config.mjs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// @ts-check
2+
import { defineConfig } from 'astro/config';
3+
import mdx from '@astrojs/mdx';
4+
import sitemap from '@astrojs/sitemap';
5+
import tailwindcss from '@tailwindcss/vite';
6+
import remarkCallouts from './src/lib/remark-callouts.mjs';
7+
import rehypeTables from './src/lib/rehype-tables.mjs';
8+
import shikiCodeTitle from './src/lib/shiki-code-title.mjs';
9+
10+
// https://astro.build/config
11+
export default defineConfig({
12+
site: 'https://prostdev.com',
13+
trailingSlash: 'ignore',
14+
// This post was first migrated under a SHORTENED slug that never existed on Wix
15+
// (the live URL is the long one). Redirect the old short path to the canonical
16+
// live slug so any stale internal/SEO link doesn't 404.
17+
redirects: {
18+
'/post/getting-started-with-anypoint-code-builder':
19+
'/post/getting-started-with-anypoint-code-builder-in-vs-code-beginner-guide',
20+
},
21+
integrations: [mdx(), sitemap()],
22+
vite: {
23+
plugins: [tailwindcss()],
24+
},
25+
markdown: {
26+
// Transform GitHub alert blockquotes (`> [!NOTE]`) into styled callout boxes at build time.
27+
// See src/lib/remark-callouts.mjs + the `.callout*` styles in src/styles/global.css.
28+
remarkPlugins: [remarkCallouts],
29+
// Wrap GFM tables in a responsive scroll container + add scope="col" to headers.
30+
// See src/lib/rehype-tables.mjs + the `.table-wrap` / `.prose table` styles in global.css.
31+
rehypePlugins: [rehypeTables],
32+
shikiConfig: {
33+
themes: {
34+
light: 'github-light',
35+
dark: 'github-dark',
36+
},
37+
// DataWeave has no built-in Shiki grammar; alias to Scala for decent
38+
// highlighting of its functional/typed syntax.
39+
langAlias: {
40+
dataweave: 'scala',
41+
dwl: 'scala',
42+
},
43+
// Lift an optional `title="file.ext"` from a fence's meta onto a
44+
// `data-title` attr; CodeBlockEnhancer renders it in the header bar.
45+
transformers: [shikiCodeTitle()],
46+
wrap: true,
47+
},
48+
},
49+
});

0 commit comments

Comments
 (0)