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
16 changes: 16 additions & 0 deletions .assetsignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
node_modules
.git
.github
.husky
src
yarn.lock
package.json
package-lock.json
eslint.config.js
vitest.config.js
.stylelintrc.json
Dangerfile.js
README.md
CHANGELOG.md
wrangler.jsonc
dist/styles.min.css
22 changes: 12 additions & 10 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ jobs:
name: Lint, Test & Danger
runs-on: ubuntu-latest

permissions:
contents: read
pull-requests: write

steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -26,7 +30,7 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Lint commits (PR only)
- name: Lint commits
if: github.event_name == 'pull_request'
run: yarn ci:lint:commits

Expand All @@ -36,36 +40,34 @@ jobs:
- name: Lint SCSS
run: yarn ci:lint:scss

- name: Run tests with coverage
- name: Test
run: yarn ci:test

- name: Build CSS
- name: Build
run: yarn ci:build

- name: Danger
if: github.event_name == 'pull_request'
run: yarn danger ci
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

release:
name: Release
runs-on: ubuntu-latest
needs: ci

if: github.event_name == 'push' && github.ref == 'refs/heads/master'

permissions:
contents: write
issues: write
pull-requests: write
contents: write
issues: write
pull-requests: write

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}

- name: Setup Node
uses: actions/setup-node@v4
Expand All @@ -76,7 +78,7 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Build CSS (release artifact)
- name: Build
run: yarn build

- name: Release
Expand Down
26 changes: 26 additions & 0 deletions .stylelintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"extends": [
"stylelint-config-standard-scss"
],
"rules": {
"selector-class-pattern": null,
"scss/dollar-variable-pattern": null,
"scss/at-rule-no-unknown": true,
"scss/no-global-function-names": null,
"declaration-block-no-duplicate-properties": true,
"no-duplicate-selectors": true,
"alpha-value-notation": "number",
"color-function-notation": "legacy",
"import-notation": "string",
"property-no-vendor-prefix": null,
"declaration-block-single-line-max-declarations": null,
"no-descending-specificity": null,
"scss/double-slash-comment-empty-line-before": null,
"color-hex-length": "long",
"custom-property-empty-line-before": null,
"comment-empty-line-before": null,
"rule-empty-line-before": null,
"selector-not-notation": null,
"scss/dollar-variable-colon-space-after": null
}
}
42 changes: 15 additions & 27 deletions Dangerfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,36 @@
* Runs in CI (GitHub Actions / Vercel preview checks).
* See https://danger.systems/js/ for full API.
*/

const { danger, warn, fail, message } = require('@danger/danger')

// ── PR description ─────────────────────────────────────────────────────────

if (!danger.github.pr.body || danger.github.pr.body.trim().length < 20) {
fail('Please add a meaningful PR description (at least 20 characters).')
}

// ── PR size — keep PRs reviewable ──────────────────────────────────────────

const LINES_CHANGED =
danger.github.pr.additions + danger.github.pr.deletions

if (LINES_CHANGED > 600) {
warn(
`This PR changes **${LINES_CHANGED} lines**. Consider splitting it into ` +
'smaller, focused PRs to make review easier.',
)
}

// ── Changelog ──────────────────────────────────────────────────────────────

const hasChangelog = danger.git.modified_files.includes('CHANGELOG.md') ||
danger.git.created_files.includes('CHANGELOG.md')

if (!hasChangelog && LINES_CHANGED > 50) {
warn('No `CHANGELOG.md` update found. Consider documenting notable changes.')
}

// ── Test coverage — every JS change should have a test ─────────────────────

const changedJsFiles = danger.git.modified_files
.concat(danger.git.created_files)
.filter(function isAppJs(f) {
return f.startsWith('src/js/') && f.endsWith('.js') && !f.endsWith('.test.js')
})

const changedTestFiles = danger.git.modified_files
.concat(danger.git.created_files)
.filter(function isTestFile(f) {
return f.endsWith('.test.js')
})

changedJsFiles.forEach(function checkTestCoverage(file) {
const base = file.replace(/\.js$/, '')
const hasTest = changedTestFiles.some(function matchesTest(t) {
Expand All @@ -58,9 +44,7 @@ changedJsFiles.forEach(function checkTestCoverage(file) {
'Please add or update tests.')
}
})

// ── No console.log in source ────────────────────────────────────────────────

danger.git.modified_files
.concat(danger.git.created_files)
.filter(function isSourceJs(f) {
Expand All @@ -72,46 +56,50 @@ danger.git.modified_files
warn(`\`${file}\` contains \`console.log\`. Remove before merging.`)
}
})

// ── dist/ must be rebuilt if SCSS changed ──────────────────────────────────

const scssChanged = danger.git.modified_files
.concat(danger.git.created_files)
.some(function isScss(f) { return f.startsWith('src/scss/') })

const distChanged = danger.git.modified_files
.concat(danger.git.created_files)
.some(function isDist(f) { return f.startsWith('dist/') })

if (scssChanged && !distChanged) {
fail(
'SCSS files were changed but `dist/styles.css` was not updated. ' +
'Run `yarn build:scss` and commit the result.',
)
}

// ── Lockfile consistency ────────────────────────────────────────────────────

const packageChanged = danger.git.modified_files.includes('package.json')
const lockfileChanged = danger.git.modified_files.includes('yarn.lock')

if (packageChanged && !lockfileChanged) {
warn(
'`package.json` changed but `yarn.lock` was not updated. ' +
'Run `yarn install` and commit `yarn.lock`.',
)
}

// ── No direct pushes to main ────────────────────────────────────────────────

if (danger.github.pr.base.ref === 'main' &&
danger.github.pr.head.ref === 'main') {
fail('Direct pushes to `main` are not allowed. Please use a feature branch.')
}

// ── Summary ─────────────────────────────────────────────────────────────────

message(
`📊 **PR stats:** +${danger.github.pr.additions} / -${danger.github.pr.deletions} lines ` +
`across ${danger.github.pr.changed_files} file(s).`,
)
// ── Conventional commit format on PR title ─────────────────────────────────
// semantic-release reads commit messages — squash-merge PRs use the PR title
// as the commit message, so it must follow Conventional Commits format.
const CONVENTIONAL_PATTERN =
/^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.+\))?!?: .{1,100}$/
if (!CONVENTIONAL_PATTERN.test(danger.github.pr.title)) {
fail(
`PR title \`${danger.github.pr.title}\` does not follow ` +
'[Conventional Commits](https://www.conventionalcommits.org/) format.\n\n' +
'Expected: `type(scope): description` — e.g. `feat: add reverb section` ' +
'or `fix(tooltip): clamp position on narrow screens`.\n\n' +
'This is required because the PR title becomes the squash-merge commit ' +
'message that **semantic-release** uses to determine the version bump.',
)
}
72 changes: 1 addition & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,6 @@ All genre-specific content is togglable via the filter bar (Metal / Jazz / Rock

---

## Stack

- **HTML5** — semantic, no framework
- **SCSS** — compiled to `dist/`, no runtime dependency
- **Vanilla JS ES modules** — native `type="module"`, no bundler
- **Vitest** — unit tests for all JS modules
- **ESLint** — no semicolons, named functions, JSDoc enforcement
- **Stylelint** — SCSS standard config
- **Husky + lint-staged** — pre-commit linting, pre-push tests
- **Danger** — automated PR hygiene checks

---

## Requirements

- Node ≥ 20
Expand All @@ -59,7 +46,7 @@ npx serve .
## Build

```bash
yarn build # compiles SCSS → dist/styles.css (compressed)
yarn build
```

`dist/styles.css` is committed and ready to deploy. No build step needed on the server.
Expand Down Expand Up @@ -95,60 +82,3 @@ Rules enforced:
- No `console.log` in source files

---

## Git hooks (Husky)

| Hook | What runs |
|------|-----------|
| `pre-commit` | `lint-staged` — ESLint + Stylelint on staged files only, plus related Vitest tests |
| `pre-push` | Full `yarn test` suite |

Hooks are in `.husky/`. They are installed automatically when you run `yarn install` (via the `prepare` script).

---

## Danger (CI PR checks)

`Dangerfile.js` runs in CI on every PR and enforces:

- PR must have a description ≥ 20 characters (fail)
- PRs > 600 lines get a size warning
- SCSS changes must include a `dist/` update (fail)
- `package.json` changes must update `yarn.lock`
- Modified source JS files must have corresponding test updates
- No `console.log` in source files
- Direct `main → main` pushes are blocked

To wire it up in GitHub Actions, add a `DANGER_GITHUB_API_TOKEN` secret and include `yarn danger` in your CI workflow.

---

## Deploy to Vercel

1. Push to GitHub
2. Import in Vercel — set **Output Directory** to `.` (root), no build command
3. Done — CSS is pre-compiled

Or via CLI:

```bash
vercel --prod
```

---

## Customise

**Ko-fi link** — find `id="kofi-link"` in `index.html` and replace the `href`.

**Genre content** — add `genre-metal`, `genre-jazz`, or `genre-rock` classes to any `.drum-block` to control filter visibility.

**Tooltips** — any element with `class="tt" data-tip="..."` gets the hover/tap tooltip automatically.

**Adding a glossary term** — edit the `TERMS` array in `src/js/glossary.js`. Each entry is `{ term, cat, def }`.

---

## License

MIT — use freely, credit appreciated.
4 changes: 2 additions & 2 deletions dist/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -892,8 +892,8 @@ body.genre-rock .genre-jazz {
--bg2: #111113;
--bg3: #18181b;
--text: #e8e8e8;
--text2: #888;
--text3: #555;
--text2: #888888;
--text3: #555555;
--accent: #e8ff47;
--cut: #ff5555;
--boost: #47ff8a;
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ <h1 class="hero-title">Glossary</h1>
MixRef — a cheatsheet for when your ears lie to you.
</p>
<a
href="https://ko-fi.com/yourusername"
href="https://ko-fi.com/oslavdevelopment"
target="_blank"
rel="noopener noreferrer"
class="kofi-btn"
Expand Down
Loading
Loading