mirror of https://github.com/theNewDynamic/gohugo-theme-ananke.git

Patrick Kollitsch
yesterday ac62781583bb6fa20da7925e1b61881a3a5f5623
chore(git): merge branch 'development'

* development:
build(vscode): update workspace configuration
feat: add edit-page shortcode for GitHub edit links (#1028)
fix: normalise GoHugo to Hugo
docs(ai): add release notes prompt
fix: various changes to workspace, testing, linting, etc.
1 files deleted
7 files modified
4 files added
777 ■■■■■ changed files
.github/dependabot.yml 6 ●●●● patch | view | raw | blame | history
.github/workflows/branch-protection.yml 52 ●●●●● patch | view | raw | blame | history
.markdownlint.jsonc 281 ●●●● patch | view | raw | blame | history
.vscode/extensions.json 15 ●●●●● patch | view | raw | blame | history
.vscode/prompts/release-notes.prompt.md 235 ●●●●● patch | view | raw | blame | history
CONTRIBUTING.md 32 ●●●●● patch | view | raw | blame | history
ananke.code-workspace 52 ●●●●● patch | view | raw | blame | history
i18n/en.toml 3 ●●●●● patch | view | raw | blame | history
layouts/_partials/edit-page.html 61 ●●●●● patch | view | raw | blame | history
layouts/_shortcodes/edit-page.html 26 ●●●●● patch | view | raw | blame | history
tests/catalog.yaml 12 ●●●● patch | view | raw | blame | history
theme.toml 2 ●●● patch | view | raw | blame | history
.github/dependabot.yml
@@ -17,7 +17,7 @@
      semver-patch-days: 4
    assignees:
      - davidsneighbour
    target-branch: maintenance
    target-branch: development
    open-pull-requests-limit: 999
    pull-request-branch-name:
      separator: /
@@ -38,7 +38,7 @@
      semver-patch-days: 4
    assignees:
      - davidsneighbour
    target-branch: maintenance
    target-branch: development
    open-pull-requests-limit: 999
    pull-request-branch-name:
      separator: /
@@ -56,7 +56,7 @@
      default-days: 7
    assignees:
      - davidsneighbour
    target-branch: maintenance
    target-branch: development
    open-pull-requests-limit: 999
    pull-request-branch-name:
      separator: /
.github/workflows/branch-protection.yml
@@ -9,7 +9,7 @@
jobs:
  validate-main-source-branch:
    name: Require staging or maintenance as source branch for main
    name: Require development as source branch for main
    runs-on: ubuntu-latest
    if: github.base_ref == 'main'
@@ -21,53 +21,7 @@
        run: |
          set -euo pipefail
          if [ "${HEAD_REF}" != "staging" ] && [ "${HEAD_REF}" != "maintenance" ]; then
            echo "::error::Pull requests into main must come from staging or maintenance. Current source branch: ${HEAD_REF}"
          if [ "${HEAD_REF}" != "development" ]; then
            echo "::error::Pull requests into main must come from development. Current source branch: ${HEAD_REF}"
            exit 1
          fi
  validate-staging-source-branch:
    name: Require development or maintenance as source branch for staging
    runs-on: ubuntu-latest
    if: github.base_ref == 'staging'
    steps:
      - name: Validate source branch
        shell: bash
        env:
          HEAD_REF: ${{ github.head_ref }}
        run: |
          set -euo pipefail
          if [ "${HEAD_REF}" != "development" ] && [ "${HEAD_REF}" != "maintenance" ]; then
            echo "::error::Pull requests into staging must come from development or maintenance. Current source branch: ${HEAD_REF}"
            exit 1
          fi
  protect-package-lock:
    name: Block package-lock.json outside maintenance
    runs-on: ubuntu-latest
    if: github.base_ref != 'maintenance'
    steps:
      - name: Check out repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
        with:
          fetch-depth: 0
          persist-credentials: false
      - name: Fail if package-lock.json changed outside maintenance
        shell: bash
        env:
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
          BASE_REF: ${{ github.base_ref }}
        run: |
          set -euo pipefail
          changed_files=$(git diff --name-only "${BASE_SHA}...${HEAD_SHA}")
          if echo "${changed_files}" | grep -Fxq "package-lock.json"; then
            echo "::error file=package-lock.json::package-lock.json may only be changed in PRs targeting maintenance. Current target branch: ${BASE_REF}"
            exit 1
          fi
.markdownlint.jsonc
@@ -1,150 +1,133 @@
{
  "$schema": "https://github.com/DavidAnson/markdownlint/blob/main/schema/markdownlint-config-schema.json",
  "$id": "https://raw.githubusercontent.com/davidsneighbour/kollitsch.dev/refs/heads/main/src/config/.markdownlint.jsonc",
  "default": true,
  "customRules": [
    "@github/markdownlint-github",
    "markdownlint-rule-relative-links",
    "markdownlint-rule-search-replace",
    "markdownlint-rule-extended-ascii",
    "markdownlint-rule-title-case-style",
    "markdownlint-rule-list-duplicates"
  ],
  // Rules
  // unlisted rules are using default settings (usually "true")
  // @see https://github.com/DavidAnson/markdownlint/#rules--aliases
  "MD001": {
    "severity": "error",
    "front_matter_title": "^\\s*title\\s*[:=]"
  },
  "MD003": {
    "style": "atx"
  },
  "MD004": {
    "style": "asterisk"
  },
  "MD005": true,
  "MD007": {
    "indent": 2
  },
  // NO limitation on line length
  "MD013": false,
  // ignored rule for closed atx headings
  "MD020": false,
  // ignored rule for closed atx headings
  "MD021": false,
  // disallow multiple headings with the same content within the same level structure
  "MD024": {
    "siblings_only": true,
    "allow_different_nesting": true
  },
  // no inline HTML elements, except for the allowed ones. in tables only the explicit allowed ones
  "MD033": {
    "allowed_elements": [
      "lite-youtube",
      "color-grid",
      "date-diff",
      "kbd"
    ],
    "table_allowed_elements": [
      "kbd"
    ]
  },
  // use consistent rule markers (`---`)
  "MD035": {
    "style": "---"
  },
  // unused header structure rule
  "MD043": false,
  // unused spelling enforcement
  "MD044": false,
  // fenced code blocks style
  "MD046": {
    "style": "fenced"
  },
  // code blocks must use backticks instead of tildes
  "MD048": {
    "style": "backtick"
  },
  // emphasis must use asterisks `*` instead of underscores `_`
  "MD049": {
    "style": "asterisk"
  },
  // strong style must use double asterisks `**` instead of double underscores `__`
  "MD050": {
    "style": "asterisk"
  },
  // links must not be auto links, all other link formats are allowed
  "MD054": {
    "autolink": false
  },
  // table pipes must be used before and after each table row
  "MD055": {
    "style": "leading_and_trailing"
  },
  // generic linktexts are prohibited
  "MD059": {
    "prohibited_texts": [
      "click here",
      "here",
      "link",
      "more"
    ]
  },
  // table style must be compact (single spaces around cell content)
  "MD060": {
    "style": "aligned"
  },
  // @see https://www.npmjs.com/package/@github/markdownlint-github
  // images should not contain default alternate texts
  "GH001": true,
  // links should not contain generic text ('click here', 'read more', etc.)
  "GH002": {
    "additional_banned_texts": [
      "Something",
      "Click here"
    ]
  },
  // no empty alt texts for images
  "GH003": true,
  // @see https://www.npmjs.com/package/markdownlint-rule-relative-links
  "relative-links": {
    "root_path": "../.."
  },
  // @see https://www.npmjs.com/package/markdownlint-rule-search-replace
  "search-replace": {
    "rules": [
      {
        "name": "ellipsis",
        "message": "Do not use three dots '...' for ellipsis.",
        "information": "https://example.com/rules/ellipsis",
        "search": "...",
        "replace": "…",
        "searchScope": "text"
      },
      {
        "name": "curly-double-quotes",
        "message": "Do not use curly double quotes.",
        "searchPattern": "/“|”/g",
        "replace": "\""
      }
    ]
  },
  // @see https://www.npmjs.com/package/markdownlint-rule-extended-ascii
  "extended-ascii": {
    "ascii-only": true
  },
  // @see https://www.npmjs.com/package/markdownlint-rule-title-case-style
  "title-case-style": {
    // letter case style to apply
    //
    // "sentence" or "title" (default: sentence)
    "case": "sentence",
    // words to ignore when applying letter case.
    //
    // string[] (default: [])
    "ignore": [
      "JavaScript"
    ],
  },
}
    "$schema": "https://github.com/DavidAnson/markdownlint/blob/main/schema/markdownlint-config-schema.json",
    "$id": "https://raw.githubusercontent.com/davidsneighbour/kollitsch.dev/refs/heads/main/src/config/.markdownlint.jsonc",
    "default": true,
    "customRules": [
        "@github/markdownlint-github",
        "markdownlint-rule-relative-links",
        "markdownlint-rule-search-replace",
        "markdownlint-rule-extended-ascii",
        "markdownlint-rule-title-case-style",
        "markdownlint-rule-list-duplicates"
    ],
    // Rules
    // unlisted rules are using default settings (usually "true")
    // @see https://github.com/DavidAnson/markdownlint/#rules--aliases
    "MD001": {
        "severity": "error",
        "front_matter_title": "^\\s*title\\s*[:=]"
    },
    "MD003": {
        "style": "atx"
    },
    "MD004": {
        "style": "asterisk"
    },
    "MD005": true,
    "MD007": {
        "indent": 2
    },
    // NO limitation on line length
    "MD013": false,
    // ignored rule for closed atx headings
    "MD020": false,
    // ignored rule for closed atx headings
    "MD021": false,
    // disallow multiple headings with the same content within the same level structure
    "MD024": {
        "siblings_only": true,
        "allow_different_nesting": true
    },
    // no inline HTML elements, except for the allowed ones. in tables only the explicit allowed ones
    "MD033": {
        "allowed_elements": ["lite-youtube", "color-grid", "date-diff", "kbd"],
        "table_allowed_elements": ["kbd"]
    },
    // use consistent rule markers (`---`)
    "MD035": {
        "style": "---"
    },
    // unused header structure rule
    "MD043": false,
    // unused spelling enforcement
    "MD044": false,
    // fenced code blocks style
    "MD046": {
        "style": "fenced"
    },
    // code blocks must use backticks instead of tildes
    "MD048": {
        "style": "backtick"
    },
    // emphasis must use asterisks `*` instead of underscores `_`
    "MD049": {
        "style": "asterisk"
    },
    // strong style must use double asterisks `**` instead of double underscores `__`
    "MD050": {
        "style": "asterisk"
    },
    // links must not be auto links, all other link formats are allowed
    "MD054": {
        "autolink": false
    },
    // table pipes must be used before and after each table row
    "MD055": {
        "style": "leading_and_trailing"
    },
    // generic linktexts are prohibited
    "MD059": {
        "prohibited_texts": ["click here", "here", "link", "more"]
    },
    // table style must be compact (single spaces around cell content)
    "MD060": {
        "style": "compact"
    },
    // @see https://www.npmjs.com/package/@github/markdownlint-github
    // images should not contain default alternate texts
    "GH001": true,
    // links should not contain generic text ('click here', 'read more', etc.)
    "GH002": {
        "additional_banned_texts": ["Something", "Click here"]
    },
    // no empty alt texts for images
    "GH003": true,
    // @see https://www.npmjs.com/package/markdownlint-rule-relative-links
    "relative-links": {
        "root_path": "../.."
    },
    // @see https://www.npmjs.com/package/markdownlint-rule-search-replace
    "search-replace": {
        "rules": [
            {
                "name": "ellipsis",
                "message": "Do not use three dots '...' for ellipsis.",
                "information": "https://example.com/rules/ellipsis",
                "search": "...",
                "replace": "…",
                "searchScope": "text"
            },
            {
                "name": "curly-double-quotes",
                "message": "Do not use curly double quotes.",
                "searchPattern": "/“|”/g",
                "replace": "\""
            }
        ]
    },
    // @see https://www.npmjs.com/package/markdownlint-rule-extended-ascii
    "extended-ascii": {
        "ascii-only": true
    },
    // @see https://www.npmjs.com/package/markdownlint-rule-title-case-style
    "title-case-style": {
        // letter case style to apply
        //
        // "sentence" or "title" (default: sentence)
        "case": "sentence",
        // words to ignore when applying letter case.
        //
        // string[] (default: [])
        "ignore": ["JavaScript"]
    }
}
.vscode/extensions.json
File was deleted
.vscode/prompts/release-notes.prompt.md
New file
@@ -0,0 +1,235 @@
---
title: Create Ananke release notes
description: Create release notes for the Ananke theme from repository changes
agent: agent
tools: ['changes', 'search/codebase', 'web/githubRepo', 'github']
---
Create release notes for the next Ananke release based on the current repository state, merged pull requests, commits, changed files, and existing changelog entries.
## Goal
Write clear, user-facing release notes for the Ananke theme.
The release notes must explain:
* what changed
* what users need to update
* whether the release contains breaking changes
* which Hugo version is required
* where users can read more
* which changelog entries belong to this release
The result must be suitable for publishing as a GitHub release note, documentation page, or changelog announcement.
The release title in GitHub will create the main H1 heading. Do not output an initial `# Release Notes` heading. Start with `## Breaking changes`.
## Required output structure
Use this exact structure:
```markdown
## Breaking changes
## Further notes
## Further reading
## Requirements
* Hugo v0.161+
## Changelog
```
Do not remove headings. If a section has no relevant content, write a short sentence stating that there are no additional notes for that section.
## Primary breaking change
The release notes must include this breaking change prominently:
```markdown
BREAKING CHANGE: Ananke is now using the latest css.Build functionality of Hugo. This means that the old SASS/SCSS pipeline is removed and you need to update your build process if you were relying on it.
```
Rewrite the wording only if it improves clarity, but keep the meaning intact.
The breaking change section must explain:
* the old SASS/SCSS pipeline has been removed
* Ananke now relies on Hugo's current `css.Build` functionality
* users with custom build scripts, asset pipelines, or theme overrides may need to update their setup
* users should check their Hugo version before upgrading
* users should review any custom SASS/SCSS overrides or imports
## Requirements
The requirements section must include:
```markdown
* Hugo v0.161+
```
If repository files indicate a more specific or newer requirement, report the conflict clearly instead of silently changing the version.
## Changelog
The changelog section must be generated from repository evidence.
First, identify the previous release tag and the new release target. If a previous release tag is not provided, use the latest reachable Git tag as the start point and `HEAD` as the end point.
Run this command from the repository root to generate the raw changelog entries:
```bash
previous_tag="${PREVIOUS_TAG:-$(git describe --tags --abbrev=0)}"
current_ref="${CURRENT_REF:-HEAD}"
repo_url="$(
  git config --get remote.origin.url |
    sed -E 's#^git@github.com:#https://github.com/#; s#\.git$##'
)"
git log "${previous_tag}..${current_ref}" \
  --date=format-local:'%Y-%m-%d %H:%M %z' \
  --pretty=format:'%H%x1f%h%x1f%s%x1f%ad%x1f%an%x1f%ae' |
  sort -r -t "$(printf '\037')" -k4,4 |
  awk -F "$(printf '\037')" -v repo_url="${repo_url}" '
    function github_user_from_email(email) {
      if (email ~ /@users\.noreply\.github\.com$/) {
        sub(/^.*\+/, "", email)
        sub(/@users\.noreply\.github\.com$/, "", email)
        return email
      }
      return ""
    }
    function escape_markdown(value) {
      gsub(/\[/, "\\[", value)
      gsub(/\]/, "\\]", value)
      return value
    }
    {
      full_hash = $1
      short_hash = $2
      title = $3
      date_time = $4
      author_name = escape_markdown($5)
      author_email = $6
      user = github_user_from_email(author_email)
      if (user != "") {
        author = "[" author_name "](https://github.com/" user ")"
      } else {
        author = author_name
      }
      printf "- [%s](%s/commit/%s) %s (%s by %s)\n", short_hash, repo_url, full_hash, title, date_time, author
    }
  '
```
The command must create one Markdown list item per commit in this format:
```markdown
* [HASH](commit-url) Title (yyyy-mm-dd HH:ii timezone by [authorname](author-profile-url))
```
Use the short commit hash as the link text and link it to the full commit URL.
Issue and pull request references in commit titles should remain in GitHub-autolinkable format, for example `#123`. Do not rewrite them into manual links unless the repository tooling provides reliable issue URLs.
Link the author name to the GitHub profile when the username can be derived reliably from a GitHub noreply email address. If no GitHub username can be derived, keep the author name as plain text.
Sort changelog entries by commit date descending.
After generating the raw commit list, review it and group or summarise items when appropriate, but preserve the raw commit list if the release note needs a complete audit trail.
Include concise bullet points grouped by type when possible:
* Breaking changes
* Features
* Fixes
* Documentation
* Internal changes
* Dependencies
* Removed or deprecated functionality
Each changelog item should be user-facing. Avoid low-level commit noise unless it affects users or maintainers.
## Further notes
Use this section to explain practical upgrade impact.
Include notes about:
* build configuration changes
* removed SASS/SCSS assumptions
* CSS processing changes
* compatibility concerns
* migration considerations
* theme customisation impact
* anything users should test after upgrading
Do not invent migration steps. If the repository does not contain enough information, add a clearly marked "Needs confirmation" bullet.
## Further reading
Add links or references to relevant documentation, for example:
* Ananke documentation pages
* Hugo `css.Build` documentation
* relevant pull requests
* relevant issues
* migration notes
* changelog files
* release comparison links
Use repository links when available. Do not invent URLs.
## Style rules
Write in clear British English.
Use direct, practical language.
Avoid marketing language.
Avoid vague phrases such as "various improvements" unless the repository evidence is also vague.
Avoid emojis.
Avoid typographic punctuation. Use plain apostrophes, quotes, hyphens, and normal punctuation.
Use Markdown only.
Use `*` for unordered list items.
Use inline code formatting for filenames, commands, config keys, function names, and Hugo features.
## Evidence rules
Base the release notes on repository evidence.
Check at least:
* recent commits
* merged pull requests
* changed files
* changelog files
* documentation updates
* configuration files
* asset pipeline files
* theme build files
* Hugo module or dependency configuration
* README or migration notes
If something is unclear, include it under a "Needs confirmation" bullet instead of guessing.
## Final output
Return only the completed release notes.
Do not include analysis, explanations, or implementation notes outside the release note document.
CONTRIBUTING.md
@@ -40,15 +40,15 @@
1. Use a compatible Hugo version (see [`config/_default/module.toml`](https://github.com/gohugo-ananke/ananke/blob/main/config/_default/module.toml) for the current state).
2. Install dependencies:
 ```bash
 npm install
 ```
```bash
npm install
```
1. Run a local preview via `npm run` instead of just calling `hugo server`:
 ```bash
 npm run server
 ```
```bash
npm run server
```
 This runs the documentation site from `site/` using contents from `docs/` with local configuration.
@@ -56,9 +56,9 @@
2. Make sure to install git hooks for linting and testing before you push changes:
 ```bash
 npm run prepare
 ```
```bash
npm run prepare
```
 This command is run automatically after `npm install` but you can run it manually to set up hooks in an existing clone or update changed hooks. It uses `simple-git-hooks` to install a commit hook that runs `lint-staged` for markdown files, which in turn runs linting tasks on staged files.
@@ -74,7 +74,6 @@
flowchart LR
 feature["feature/*, fix/*, docs/*, refactor/*"] --> development
 development --> main
 maintenance --> main
 main --> development
```
@@ -82,11 +81,10 @@
### Long-lived branches
| Branch  | Purpose  | Release role | Write policy | Merge  |
| Branch | Purpose | Release role | Write policy | Merge |
| --- | --- | --- | --- | --- |
| `main`  | Stable source of truth | releases | Protected. Only receives reviewed PRs from `staging` or `maintenance`. | Rebase |
| `main` | Stable source of truth | releases | Protected. Only receives reviewed PRs from `development`. | Rebase |
| `development` | Active development | pre-releases | Feature, fix, chore, and documentation PRs target this branch. | Squash |
| `maintenance` | Dependency maintenance  | none | Maintainer-only branch for dependency version updates. | Rebase |
### Branch naming
@@ -98,8 +96,6 @@
* `chore/<topic>`
* `refactor/<topic>`
Dependency update branches MUST target `maintenance` unless the change is part of an intentional feature branch and does not touch lock files.
After a successful rebase between those branches, push with lease:
```bash
@@ -113,9 +109,9 @@
3. Update docs for all user-facing changes.
4. Run quality checks locally:
 ```bash
 npm run lint:markdown
 ```
```bash
npm run lint:markdown
```
1. If your change affects behaviour, validate with Hugo locally (for example `hugo` or `hugo server` in the relevant project).
2. Open a pull request with:
ananke.code-workspace
New file
@@ -0,0 +1,52 @@
{
    "folders": [
        {
            "path": "."
        },
        {
            "path": "../documentation"
        },
        {
            "path": "../template-git-submod"
        },
        {
            "path": "../template-hugo-mod"
        }
    ],
    "settings": {
        "window.autoDetectColorScheme": false,
        "markdown.extension.tableFormatter.enabled": false,
        "chat.tools.terminal.autoApprove": {
            "git fetch": true,
            "git worktree": true,
            "git add": true,
            "git push": true
        },
        "markdown.extension.toc.unorderedList.marker": "*",
        "markdown.extension.toc.levels": "2..6"
    },
    "extensions": {
        "recommendations": [
            "ms-vscode.vscode-github-issue-notebooks",
            "github.vscode-pull-request-github",
            "pkief.material-icon-theme",
            "yzhang.markdown-all-in-one",
            "davidanson.vscode-markdownlint",
            "zizmor.zizmor-vscode",
            "streetsidesoftware.code-spell-checker-cspell-bundled-dictionaries",
            "budparr.language-hugo-vscode",
            "jinliming2.vscode-go-template",
            "gohugoio.gotmplfmt",
            "casualjim.gotemplate",
            "streetsidesoftware.code-spell-checker",
            "streetsidesoftware.code-spell-checker-british-english",
            "gohugoio.gotmplfmt",
            "anthropic.claude-code",
            "aaron-bond.better-comments",
            "redhat.vscode-xml",
            "redhat.vscode-yaml",
            "google.wireit",
            "dunstontc.vscode-go-syntax"
        ]
    }
}
i18n/en.toml
@@ -34,6 +34,9 @@
[send]
other = "Send"
[editPage]
other = "Improve this page on GitHub"
[since]
other = "since"
layouts/_partials/edit-page.html
New file
@@ -0,0 +1,61 @@
{{- /*
  edit-page partial
  Renders a link to edit the current page's source file on GitHub. Visitors
  without write access are offered GitHub's standard "fork and propose changes"
  flow automatically when they follow an /edit/ link, so no extra handling is
  needed here.
  This partial is the single source of truth shared by the `edit-page`
  shortcode and by any hook (for example `content-after`) that wants to render
  the link automatically.
  Accepts either a Page directly, or a map:
    - page    (required) the Page whose source file should be edited.
    - branch  (optional) overrides the configured branch for this call.
  Configuration (under params.ananke.shortcodes.edit_page):
    - repo_url     (required) Base URL of the GitHub repository, e.g.
                   "https://github.com/owner/repo". When unset nothing renders.
    - branch       The branch to edit. Defaults to "main".
    - content_dir  The directory the content lives in inside the repository.
                   Defaults to "content".
    - target       Link target. Defaults to "_blank". Set to false to open in
                   the same window.
*/ -}}
{{- $page := . -}}
{{- $branch := "" -}}
{{- if reflect.IsMap . -}}
  {{- $page = .page -}}
  {{- with .branch }}{{ $branch = . }}{{ end -}}
{{- end -}}
{{- $repoURL := "" -}}
{{- $contentDir := "content" -}}
{{- $target := "_blank" -}}
{{- with site.Params.ananke -}}
  {{- with .shortcodes -}}
    {{- with .edit_page -}}
      {{- with .repo_url }}{{ $repoURL = . }}{{ end -}}
      {{- if not $branch }}{{ $branch = .branch | compare.Default "main" }}{{ end -}}
      {{- with .content_dir }}{{ $contentDir = . }}{{ end -}}
      {{- if isset . "target" }}{{ $target = .target }}{{ end -}}
    {{- end -}}
  {{- end -}}
{{- end -}}
{{- if not $branch }}{{ $branch = "main" }}{{ end -}}
{{- with $page.File -}}
  {{- if $repoURL -}}
    {{- $filePath := strings.Replace .Path "\\" "/" -}}
    {{- $path := path.Join $contentDir $filePath -}}
    {{- $url := printf "%s/edit/%s/%s" (strings.TrimSuffix "/" $repoURL) $branch $path -}}
    {{- $rel := "" -}}
    {{- if and $target (ne $target "_self") }}{{ $rel = "noopener" }}{{ end -}}
    <a class="f6 link dim br2 ba bw1 ph3 pv2 mb2 dib navy" href="{{ $url }}"
      {{- with $target }} target="{{ . }}"{{ end -}}
      {{- with $rel }} rel="{{ . }}"{{ end }}>
      {{ T "editPage" }}
    </a>
  {{- else -}}
    {{- warnf "[ananke] the 'edit-page' partial in %q needs params.ananke.shortcodes.edit_page.repo_url to be set" .Path -}}
  {{- end -}}
{{- end -}}
layouts/_shortcodes/edit-page.html
New file
@@ -0,0 +1,26 @@
{{- /*
  edit-page shortcode
  Renders a link to edit the current page's source file on GitHub. Visitors
  without write access to the repository are automatically offered GitHub's
  standard "fork and propose changes" flow when they follow the link.
  The branch can be overridden per call:
    - positional:  {{< edit-page "development" >}}
    - named:       {{< edit-page branch="development" >}}
  All other settings are read from site configuration. See the shared
  `edit-page.html` partial for the full list of configuration options under
  params.ananke.shortcodes.edit_page.
*/ -}}
{{- $branch := "" -}}
{{- if .IsNamedParams -}}
  {{- with .Get "branch" }}{{ $branch = . }}{{ end -}}
{{- else -}}
  {{- with .Get 0 }}{{ $branch = . }}{{ end -}}
{{- end -}}
{{- with .Page.File -}}
  {{- partials.Include "edit-page.html" (dict "page" $.Page "branch" $branch) -}}
{{- else -}}
  {{- warnf "[ananke] the 'edit-page' shortcode was used on a page without a source file (%q)" $.Page.Title -}}
{{- end -}}
tests/catalog.yaml
@@ -17,6 +17,14 @@
shortcodes:
  form-contact:
    tests: ["scripts/test-hugo-quickstart.ts"] # TODO: add a dedicated form-contact test
    tests: [
      "scripts/test-hugo-quickstart.ts",
    ] # TODO: add a dedicated form-contact test
  page-index:
    tests: ["scripts/test-hugo-quickstart.ts"] # TODO: add a dedicated page-index test
    tests: [
      "scripts/test-hugo-quickstart.ts",
    ] # TODO: add a dedicated page-index test
  since:
    tests: [
      "scripts/test-hugo-quickstart.ts",
    ] # TODO: add a dedicated since test
theme.toml
@@ -1,4 +1,4 @@
name = "Ananke Gohugo Theme"
name = "Ananke Theme for Hugo"
license = "MIT"
licenselink = "https://github.com/gohugo-ananke/ananke/blob/master/LICENSE.md"
description = "A Base theme for building full featured Hugo sites"