Static portfolio and admin UI hosted on GitHub Pages, with GitHub Actions used for publishing content.json.
index.htmlreads published content fromcontent.jsonadmin.htmledits local draft content in the browser- publishing triggers a GitHub Actions
workflow_dispatch - the workflow writes
content.jsonback tomain - media files are hosted in the repository under
assets/uploads/...
There is no separate backend in this version.
index.html: public portfolio pageadmin.html: GitHub Pages admin UIcontent.json: canonical published contentshared/content-utils.js: schema, validation, helpersscripts/site.js: public page logicscripts/admin.js: admin logic.github/workflows/publish-content.yml: GitHub Actions publisher.github/workflows/static.yml: GitHub Pages deployment.github/workflows/validate-content.yml: content validation
- Open
admin.htmlon GitHub Pages. - Enter a GitHub token with permission to trigger Actions workflows.
- Edit the draft locally.
- For media:
- upload files to the repo manually using Git or the GitHub web UI
- keep them under
assets/uploads/... - use repo-relative paths in the admin
- Click
Publish to GitHub. - The workflow commits
content.jsontomain. - GitHub Pages redeploys automatically.
The admin UI triggers workflow_dispatch from the browser, so the user must provide a token interactively.
Recommended scopes:
- classic PAT:
repo,workflow - fine-grained PAT:
- repository access to this repo
- Actions: read/write
- Contents: read
Do not hardcode this token in the repo or page source.
GitHub Pages cannot securely upload media files back into the repository from a static page without exposing a write credential.
So in this GitHub-only version:
- local file selection in the admin is used only to generate suggested repo paths
- the actual files must be uploaded to the repository separately
- the generated paths should match the files you add under
assets/uploads/...
Example:
- local file:
hero-shot.mp4 - suggested path:
assets/uploads/hero/hero-shot.mp4
The publish workflow receives base64-encoded content.json through workflow_dispatch.
That works well for normal portfolio metadata, but it is not a good fit for embedding large binary assets in the payload. Media stays in the repo as files for that reason.
The admin tries to infer owner/repo/branch from the GitHub Pages URL.
If you need overrides, set them before loading scripts/admin.js:
<script>
window.TR_ADMIN_CONFIG = {
repoOwner: "xnts0",
repoName: "TRStudio",
repoBranch: "main",
workflowId: "publish-content.yml"
};
</script>Run:
npm run check