Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/agents/keyser.md
1 change: 1 addition & 0 deletions .claude/agents/landa.md
1 change: 1 addition & 0 deletions .claude/agents/morpheus.md
1 change: 1 addition & 0 deletions .claude/agents/oracle.md
1 change: 1 addition & 0 deletions .claude/agents/saul.md
1 change: 1 addition & 0 deletions .claude/agents/vincent.md
1 change: 1 addition & 0 deletions .claude/agents/wolf.md
1 change: 1 addition & 0 deletions .claude/commands/workflow.md
1 change: 1 addition & 0 deletions .claude/skills/brainstorming
1 change: 1 addition & 0 deletions .claude/skills/dispatching-parallel-agents
1 change: 1 addition & 0 deletions .claude/skills/executing-plans
1 change: 1 addition & 0 deletions .claude/skills/frontend-design
1 change: 1 addition & 0 deletions .claude/skills/humanizer
1 change: 1 addition & 0 deletions .claude/skills/mcp-builder
1 change: 1 addition & 0 deletions .claude/skills/productivity
1 change: 1 addition & 0 deletions .claude/skills/receiving-code-review
1 change: 1 addition & 0 deletions .claude/skills/requesting-code-review
1 change: 1 addition & 0 deletions .claude/skills/skill-creator
1 change: 1 addition & 0 deletions .claude/skills/subagent-driven-development
1 change: 1 addition & 0 deletions .claude/skills/systematic-debugging
1 change: 1 addition & 0 deletions .claude/skills/test-driven-development
1 change: 1 addition & 0 deletions .claude/skills/verification-before-completion
1 change: 1 addition & 0 deletions .claude/skills/wordpress-docker-project
1 change: 1 addition & 0 deletions .claude/skills/workflow
1 change: 1 addition & 0 deletions .claude/skills/writing-plans
1 change: 1 addition & 0 deletions .claude/skills/writing-skills
5 changes: 5 additions & 0 deletions .claude/work/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/todo.md
/scan.md
/know.md
/sdd/
/brainstorm/
1 change: 1 addition & 0 deletions .claude/workflow
Submodule workflow added at 502b04
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI

on: [push, pull_request]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
- run: npm ci
- run: make lint

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
cache: 'npm'
- run: npm ci
- run: make test
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule ".claude/workflow"]
path = .claude/workflow
url = git@github.com:nofutur3/claude-workflow.git
1 change: 1 addition & 0 deletions .opencode/agent/keyser.md
1 change: 1 addition & 0 deletions .opencode/agent/landa.md
1 change: 1 addition & 0 deletions .opencode/agent/morpheus.md
1 change: 1 addition & 0 deletions .opencode/agent/oracle.md
1 change: 1 addition & 0 deletions .opencode/agent/saul.md
1 change: 1 addition & 0 deletions .opencode/agent/vincent.md
1 change: 1 addition & 0 deletions .opencode/agent/wolf.md
7 changes: 7 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@
package.json
package-lock.json
public
.claude/workflow
.claude/skills
.claude/agents
.claude/commands
.opencode
.github/ISSUE_TEMPLATE
.github/PULL_REQUEST_TEMPLATE.md
36 changes: 36 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

happyphpdev.com is a Gatsby v3 (React 17) blog, based on the official `gatsby-starter-blog`, deployed statically to Firebase Hosting.

## Commands

- `npm ci` — install dependencies from `package-lock.json` (note: it's `npm ci`, the built-in npm command, not `npm run ci` — no `ci` script exists in `package.json` despite readme.md/AGENTS.md saying otherwise)
- `npm run develop` (alias: `npm start`) — start the dev server at http://localhost:8000
- `npm run docker-develop` — dev server bound to `0.0.0.0` (used inside Docker)
- `npm run build` — production build into `public/`
- `npm run serve` — serve the built `public/` locally
- `npm run clean` — clear Gatsby's `.cache/` and `public/` (fixes most stale-data/GraphQL-schema build issues)
- `npm run format` — Prettier write across `**/*.{js,jsx,ts,tsx,json,md}` (see `.prettierrc`/`.prettierignore`)
- `npm run deploy` — `gatsby build --prefix-links && firebase deploy`
- `npm test` — currently a stub that always exits 1 (no test suite exists yet)

Docker: `docker compose up -d` builds from `docker/node/Dockerfile` and runs `npm run docker-develop`, publishing on `${PORT:-8000}` with UID/GID/PORT from `.env` (see `.env.example`).

There is a `.github/workflows/deploy-to-firebase.yml` CI job that also runs `npm run lint` and `npm run typecheck` and pushes to Firebase on `main` — those two scripts don't exist in `package.json` yet, so the workflow (currently modified/uncommitted) will fail until they're added.

## Architecture

- **Content-driven routing**: `gatsby-node.js` queries all `MarkdownRemark` nodes under `content/blog/**` (sourced via `gatsby-source-filesystem`, configured in `gatsby-config.js`) and calls `createPage` for each post using the `src/templates/blog-post.js` template, passing `previousPostId`/`nextPostId` context for prev/next navigation. `onCreateNode` derives each post's URL slug from its file path via `createFilePath`. Categories and tags get their own generated pages via `gatsby-plugin-categories` / `gatsby-plugin-tags`, using `src/templates/category.js` and `src/templates/tag.js` respectively — driven by the `category`/`tags` frontmatter fields.
- **Posts** live at `content/blog/<year>/<month>/<slug>/index.md`, each with frontmatter (`title`, `date`, `description`, `category`, `tags`) plus co-located images referenced by relative path (processed by `gatsby-remark-images` / `gatsby-plugin-sharp`).
- **Schema customization**: `gatsby-node.js`'s `createSchemaCustomization` explicitly types `SiteSiteMetadata`, `MarkdownRemark.frontmatter`, and `.fields` so GraphQL queries don't error out when `content/blog` is empty or frontmatter fields are missing.
- **Layout composition**: every page/template wraps content in `src/layouts/base.js`, which renders a sidebar (`Bio`) + main content column (Bootstrap-based `.container`/`.row`/`.col-*` grid) and a shared `Footer`. `src/components/seo.js` handles per-page `<head>` metadata via `react-helmet`.
- **Styling**: Bootstrap 5 + custom Sass (`src/styles/global.scss`, `src/styles/variables.scss`) via `gatsby-plugin-sass`, plus `src/normalize.css`/`src/style.css`.
- **Mixed JS/TS**: most of the codebase is plain `.js`, but a couple of files (`src/pages/using-typescript.tsx`, `src/components/support.tsx`) are `.tsx`. There is no `tsconfig.json` or TypeScript type-checking configured yet — Gatsby transpiles TS/TSX out of the box but nothing enforces types.
- **Feed/manifest**: `gatsby-plugin-feed` generates `/rss.xml` from all `MarkdownRemark` nodes; `gatsby-plugin-manifest` configures the PWA manifest (site name, icon, theme colors).
- **Deployment target**: `firebase.json`/`.firebaserc` point at Firebase project `happyphpdev-com`, serving the `public/` build output.

@.claude/workflow/CLAUDE.md
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.PHONY: lint test

lint:
npx prettier --check "src/**/*.{js,jsx,ts,tsx}" "gatsby-*.js"

test:
@echo "No test suite configured yet (see 'npm test' stub in package.json)."
25 changes: 25 additions & 0 deletions opencode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "https://opencode.ai/config.json",
"instructions": [
".claude/workflow/CLAUDE.md",
".claude/workflow/AGENTS.md",
".claude/workflow/rules/*.md"
],
"skills": {
"paths": [".claude/workflow/skills"]
},
"provider": {
"local": {
"npm": "@ai-sdk/openai-compatible",
"name": "Local Ollama (via LiteLLM)",
"options": {
"baseURL": "http://litellm.dev.local:8888/v1"
},
"models": {
"local-opus": { "name": "local-opus (deepseek-r1:14b)" },
"local-sonnet": { "name": "local-sonnet (qwen2.5-coder:14b)" },
"local-haiku": { "name": "local-haiku (qwen2.5-coder:7b)" }
}
}
}
}
22 changes: 11 additions & 11 deletions src/components/bio.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,21 @@ const Bio = () => {
<div className="bio">
<div className="avatar">
<StaticImage
className="bio-avatar"
layout="fixed"
formats={["AUTO", "WEBP", "AVIF"]}
src="../images/profile-pic.png"
width={128}
height={128}
quality={95}
alt="Profile picture"
className="bio-avatar"
layout="fixed"
formats={["AUTO", "WEBP", "AVIF"]}
src="../images/profile-pic.png"
width={128}
height={128}
quality={95}
alt="Profile picture"
/>
</div>
<div className="summary">
{author?.name && (
<p>
Written by <strong>{author.name}</strong> {author?.summary || null}
</p>
<p>
Written by <strong>{author.name}</strong> {author?.summary || null}
</p>
)}
</div>
</div>
Expand Down
16 changes: 8 additions & 8 deletions src/components/build-date.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import * as React from "react"

function getDate() {
const today = new Date();
const month = today.getMonth() + 1;
const year = today.getFullYear();
const date = today.getDate();
return `${date}/${month}/${year}`;
const today = new Date()
const month = today.getMonth() + 1
const year = today.getFullYear()
const date = today.getDate()
return `${date}/${month}/${year}`
}
const BuildDate = () => {
const currentDate = getDate();
const currentDate = getDate()

return (<span>{currentDate}</span>)
return <span>{currentDate}</span>
}

export default BuildDate;
export default BuildDate
8 changes: 3 additions & 5 deletions src/components/footer.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React from "react"
import BuildDate from "./build-date";
import BuildDate from "./build-date"

const Footer = () => (
<footer className="footer mt-auto text-center">
<p className="text-muted">
This is static page generated by{" "}
<a href="https://www.gatsbyjs.com">Gatsby.js</a>, built at{" "}
<BuildDate /> using{" "}
<a href="https://github.com/">Github</a>'s pipelines and hosted by{" "}
<a href="https://www.gatsbyjs.com">Gatsby.js</a>, built at <BuildDate />{" "}
using <a href="https://github.com/">Github</a>'s pipelines and hosted by{" "}
<a href="https://firebase.google.com/">Firebase</a>. Created by{" "}
<a href="https://www.vyvazil.cz">Jakub Vyvazil</a>.
</p>
</footer>
)


export default Footer
8 changes: 2 additions & 6 deletions src/components/support.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import * as React from "react"

const Support: any = ({
const Support: any = ({}) => <div>Implement</div>

}) => (
<div>Implement</div>
)

export default Support;
export default Support
18 changes: 9 additions & 9 deletions src/layouts/base.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from "react"
import { Link } from "gatsby"
import Footer from "./../components/footer"
import Bio from "../components/bio";
import Bio from "../components/bio"

const Base = ({ location, title, children }) => {
const rootPath = `${__PATH_PREFIX__}/`
Expand All @@ -25,15 +25,15 @@ const Base = ({ location, title, children }) => {
return (
<div className="global-wrapper container" data-is-root-path={isRootPath}>
<div className="row">
<div className="col-2" id="sidebar">
<header className="global-header">{header}</header>
<Bio></Bio>
</div>
<main className="col-10" id="content">
{children}
</main>
<div className="col-2" id="sidebar">
<header className="global-header">{header}</header>
<Bio></Bio>
</div>
<main className="col-10" id="content">
{children}
</main>
</div>
<Footer></Footer>
<Footer></Footer>
</div>
)
}
Expand Down
Loading