diff --git a/.github/workflows/smoke.yaml b/.github/workflows/smoke.yaml index 543c758094..1e0ddac0a0 100644 --- a/.github/workflows/smoke.yaml +++ b/.github/workflows/smoke.yaml @@ -41,7 +41,7 @@ jobs: - name: Setup workspace run: | - npm install + npm run install:all -- --omit=optional mkdir -p tmp && cd tmp && npm init -y shell: bash diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a0353797e5..4d6bf9f0c1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -12,7 +12,7 @@ on: workflow_dispatch: permissions: contents: read - + jobs: build: runs-on: ${{ matrix.os }} @@ -29,7 +29,7 @@ jobs: cache: npm cache-dependency-path: package.json - - run: npm install --omit=optional + - run: npm run install:all -- --omit=optional - if: runner.os != 'Windows' run: npm run ci:test diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml index 815713234f..f43acfd026 100644 --- a/.markdownlint-cli2.yaml +++ b/.markdownlint-cli2.yaml @@ -5,9 +5,9 @@ customRules: globs: - '!docsy.dev/**' - - '!layouts/**' - '!node_modules/**' - '!public/**' + - '!theme/layouts/**' - '!tmp/**' - 'docsy.dev/content/en/blog/**/*.md' - 'docsy.dev/content/en/docs/_index.md' diff --git a/.prettierignore b/.prettierignore index 6734cdc088..4bd02016e6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,14 +2,14 @@ # gotcha is that once a _directory_ is ignored, it's content cannot be # unignored. -# Ignore all _files_ under assets -/assets/**/*.* +# Ignore all _files_ under the theme's assets +/theme/assets/**/*.* # Selectively unignore some files -!/assets/scss/main.scss -!/assets/scss/td/**/* +!/theme/assets/scss/main.scss +!/theme/assets/scss/td/**/* # These files are derived from other sources, # don't Prettify them: -/assets/scss/td/_variables_forward.scss -/assets/scss/td/chroma/**/* +/theme/assets/scss/td/_variables_forward.scss +/theme/assets/scss/td/chroma/**/* diff --git a/.vscode/cspell.json b/.vscode/cspell.json index d93b3f15b8..812a3bc0cc 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -20,6 +20,8 @@ "docsy", "Docsy", "errorf", + "fontawesome", + "fortawesome", "Gantt", "getenv", "GLFM", @@ -37,8 +39,11 @@ "nguyen", "nvmrc", "Occitan", + "onedark", "pageinfo", "pexels", + "prereq", + "prereqs", "quang", "readfile", "refcache", diff --git a/docsy.dev/config/_default/hugo.yaml b/docsy.dev/config/_default/hugo.yaml index 2070b83b0c..ea7ef89c12 100644 --- a/docsy.dev/config/_default/hugo.yaml +++ b/docsy.dev/config/_default/hugo.yaml @@ -2,7 +2,7 @@ # # baseURL moved to be after params title: Docsy -theme: [docsy] +theme: [docsy/theme] enableRobotsTXT: true enableGitInfo: true enableEmoji: true diff --git a/docsy.dev/netlify.toml b/docsy.dev/netlify.toml index 3203eac02b..759ddaac82 100644 --- a/docsy.dev/netlify.toml +++ b/docsy.dev/netlify.toml @@ -5,14 +5,15 @@ [build] publish = "docsy.dev/public" -command = "scripts/_install.sh && npm run build:preview" +command = "npm run install:all && npm run build:preview" [build.environment] GO_VERSION = "1.25.5" -HUGO_THEME = "repo" +# Netlify clones into a dir named "repo"; the theme lives in repo's theme/ subdir. +HUGO_THEME = "repo/theme" [context.production] -command = "scripts/_install.sh && npm run build:production" +command = "npm run install:all && npm run build:production" [context.doc-rooted.environment] TD_BUILD_CTX = "doc-rooted" diff --git a/docsy.dev/package.json b/docsy.dev/package.json index b2d799a7e1..a5be52813d 100644 --- a/docsy.dev/package.json +++ b/docsy.dev/package.json @@ -13,6 +13,7 @@ "_hugo-dev": "cross-env npm run _hugo -- -e \"${TD_BUILD_CTX:-dev}\" -DFE --printPathWarnings", "_hugo": "hugo --cleanDestinationDir --logLevel info --themesDir ../..", "_postbuild": "npm run _check:links--warn", + "_install-theme-deps": "npm install ../theme --install-links --no-save && rm -rf node_modules/theme", "_serve": "npm run _hugo-dev -- serve --disableFastRender --renderToMemory", "build:preview": "cross-env npm run _hugo-dev -- --minify --baseURL \"${DEPLOY_PRIME_URL:-http://localhost}\"", "build:production": "npm run _hugo -- --minify", @@ -23,9 +24,11 @@ "clean": "rm -Rf public", "fix:format": "npm run _check:format -- --write", "fix": "npm run fix:format && npm run prune:refcache", + "install:all": "npm install -C .. && npm install", "make:public": "git init -b main public", "postbuild:preview": "npm run _postbuild", "postbuild:production": "npm run _postbuild", + "postinstall": "npm run _install-theme-deps", "precheck:links:all": "npm run build", "precheck:links": "npm run build", "prepare-disabled": "cd .. && npm install", @@ -39,6 +42,7 @@ "update:md-goldens": "node tests/md-output/update-goldens.mjs", "update:packages": "npx npm-check-updates -u" }, + "dependencies-note": "Dependencies installed from ../theme; see postinstall script", "devDependencies": { "afdocs": "^0.9.2", "autoprefixer": "^10.4.27", diff --git a/docsy.dev/scripts/_install.sh b/docsy.dev/scripts/_install.sh deleted file mode 100755 index a321ce24ed..0000000000 --- a/docsy.dev/scripts/_install.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# -# Private script used by CI/CD workflows to install NPM packages necessary for -# the website and theme. -# -# Since docsy.dev is a workspace of the Docsy repo root, we only need to install -# the Docsy repo root dependencies. That will automatically install the -# dependencies for docsy.dev. - -set -euo pipefail - -# IMPORTANT: this script must be run from the docsy.dev directory. Validate this: -if [[ $(basename "$PWD") != "docsy.dev" ]]; then - echo "Error: _install.sh script run from the wrong directory. Run it from the docsy.dev directory." >&2 - exit 1 -fi - -# Change to repo root and verify we're in the correct location - -cd .. || { - echo "Error: Failed to change to parent directory" >&2 - exit 1 -} - -if [ ! -f package.json ] || [ ! -d docsy.dev ]; then - echo "Error: Parent directory is not the repo root" >&2 - echo "Run _install.sh from the docsy.dev directory." >&2 - echo "You are currently in $(pwd)" >&2 - exit 1 -fi - -echo "Installing NPM packages for Docsy website and theme..." -exec npm install - -# cSpell:ignore docsy diff --git a/docsy.dev/scripts/install-hugo.sh b/docsy.dev/scripts/install-hugo.sh index eb1a80710a..caaff9b47c 100755 --- a/docsy.dev/scripts/install-hugo.sh +++ b/docsy.dev/scripts/install-hugo.sh @@ -1,6 +1,8 @@ #!/bin/bash # -# Install the hugo-extended NPM package if not already present. +# Install the hugo-extended NPM package if not already present either from the +# canonical source or from the chalin fork. The fork version is used when a Hugo +# version hasn't yet landed on `hugo-extended` as an NPM package. set -e @@ -14,5 +16,3 @@ if ! npm ls hugo-extended; then npm install --save-exact -D chalin/hugo-extended#v$_HUGO_EXTENDED_VERS --omit=optional fi fi - -# cSpell:ignore chalin diff --git a/package.json b/package.json index e9137f52be..80ddb938b8 100644 --- a/package.json +++ b/package.json @@ -4,27 +4,28 @@ "repository": "github:google/docsy", "homepage": "https://www.docsy.dev", "license": "Apache-2.0", + "workspaces-todo": "TODO: try adding theme later once all phases of repo reorg are complete", "workspaces": [ - "docsy.dev" ], "scripts": { "__spv": "node scripts/set-package-version/index.mjs", "_check:afdocs": "npm run -s -C docsy.dev _check:afdocs", - "_check:format": "npx prettier --check assets *.md i18n scripts tasks", + "_check:format": "npx prettier --check theme/assets *.md theme/i18n scripts tasks tests", "_check:links": "npm run -C docsy.dev _check:links", "_check:markdown": "npx markdownlint-cli2", "_commit:public": "npm run -C docsy.dev _commit:public", - "_cp:bs-rfs": "bash -c 'cp node_modules/bootstrap/scss/vendor/*.scss assets/_vendor/bootstrap/scss/'", + "_cp:bs-rfs": "bash -c 'cp node_modules/bootstrap/scss/vendor/*.scss theme/assets/_vendor/bootstrap/scss/'", "_cp:bs-scrollspy": "perl scripts/scrollspy-patch/extract-method.pl", "_diff:check": "git diff --name-only --exit-code", "_gen-chroma-styles": "bash -c scripts/gen-chroma-styles.sh", "_mkdir:hugo-mod": "node scripts/mkdirp-hugo-mod.js ..", "_prepare:scrollspy-patch": "npm run _cp:bs-scrollspy && bash scripts/scrollspy-patch/apply-patch.sh && perl scripts/scrollspy-patch/update-patch-js.pl", - "_prepare": "npm run _cp:bs-rfs && npm run _prepare:scrollspy-patch && npm run _refresh-forward-sass-var && npm run _gen-chroma-styles && npm run get:hugo-modules", + "_prepare": "npm run _sync:theme-deps && npm run _cp:bs-rfs && npm run _prepare:scrollspy-patch && npm run _refresh-forward-sass-var && npm run _gen-chroma-styles && npm run get:hugo-modules", "_refresh-forward-sass-var": "bash -c scripts/refresh-sass-variables.pl", "_serve": "npm run -C docsy.dev _serve --", "_spv:example": "echo TBC - npm run -s __spv docsy.dev/config/example/params.yaml --", "_spv": "npm run -s __spv docsy.dev/config/*/params.yaml --", + "_sync:theme-deps": "node scripts/sync-theme-deps.mjs", "build": "npm run -C docsy.dev build --", "check:afdocs:dev": "npm run -s _check:afdocs -- http://localhost:1313 | tee docsy.dev/content/en/docs/content/agent-support/afdocs-scorecard.txt", "check:format": "npm list prettier && npm run _check:format || (echo '[help] Run: npm run fix:format'; exit 1)", @@ -43,10 +44,11 @@ "fix:markdown": "npm run check:markdown -- --fix", "fix": "npm run fix:format && npm run fix:markdown && npm run -C docsy.dev fix", "get:hugo-modules": "node scripts/getHugoModules/index.mjs", + "install:all": "npm run docsy.dev-install && npm install", "post-update": "echo; echo 'IMPORTANT! Run the following in case the ScrollSpy patch needs to be updated:\n npm run _prepare'; echo", "postinstall": "npm run _mkdir:hugo-mod", - "postupdate:dep": "npm run -s post-update", - "postupdate:packages": "npm run -s post-update", + "postupdate:dep": "npm run _sync:theme-deps && npm run -s post-update", + "postupdate:packages": "npm run _sync:theme-deps && npm run -s post-update", "prune:refcache": "npm run -C docsy.dev prune:refcache --", "seq": "bash -c 'for cmd in \"$@\"; do npm run $cmd || exit 1; done' - ", "serve": "npm run -C docsy.dev serve --", @@ -55,10 +57,12 @@ "set:version:example": "cd ../docsy-example && node ../docsy/scripts/set-package-version/index.mjs", "set:version:git-info": "npm run -s _spv -- --version \"$(scripts/get-build-id.sh)\"", "set:version": "npm run -s _spv --", + "test:smoke": "node tests/smoke.test.mjs --branch main", "test:tooling": "node --test 'scripts/**/*.test.mjs'", "test:website": "npm run -C docsy.dev test", "test": "npm run fix-and-test", "update:dep": "npm install --save-exact @fortawesome/fontawesome-free@latest bootstrap@latest", + "update:packages:not-hugo": "npm run update:packages -- -x hugo-extended", "update:packages": "npx npm-check-updates -x @fortawesome/fontawesome-free -u && npm run -C docsy.dev update:packages", "zzz": "echo 'This is just a placeholder that is the last script in this script collection.'" }, @@ -79,5 +83,5 @@ "engines": { "node": ">=24" }, - "spelling": "cSpell:ignore afdocs docsy hugo fortawesome fontawesome onedark -" + "spelling": "cSpell:ignore -" } diff --git a/scripts/_gen-chroma-style.sh b/scripts/_gen-chroma-style.sh index 2ebfa7018a..fb9446b6af 100755 --- a/scripts/_gen-chroma-style.sh +++ b/scripts/_gen-chroma-style.sh @@ -4,9 +4,10 @@ set -eo pipefail -HUGO="npx hugo" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +HUGO="node $SCRIPT_DIR/run-hugo.mjs" CHROMA_STYLE= -DEST_DIR=assets/scss/td/chroma +DEST_DIR=theme/assets/scss/td/chroma DEST_FILE= DEST_PATH=/dev/null # Set in process_CLI_args diff --git a/scripts/getHugoModules/index.mjs b/scripts/getHugoModules/index.mjs index 45bc79af50..d72b516932 100644 --- a/scripts/getHugoModules/index.mjs +++ b/scripts/getHugoModules/index.mjs @@ -2,12 +2,15 @@ // It gets dependency versions from `package.json`. import fs from 'fs'; +import path from 'path'; import { execSync } from 'child_process'; +const SCRIPT_DIR = path.join(process.cwd(), 'scripts'); const packageJson = readPackageJson(); let exitStatus = 0; const exit = () => process.exit(exitStatus); +const hugoCmd = () => `node ${SCRIPT_DIR}/run-hugo.mjs`; function getHugoModule(npmPkgNm, hugoModuleRefAtV) { try { @@ -21,9 +24,9 @@ function getHugoModule(npmPkgNm, hugoModuleRefAtV) { throw new Error(msg); } - const command = `npx hugo mod get ${hugoModuleRefAtV}${pkgVers}`; - console.log(`> ${command}`); - const output = execSync(command); + const command = `${hugoCmd()} mod get ${hugoModuleRefAtV}${pkgVers}`; + console.log(`> (cd theme && ${command})`); + const output = execSync(command, { cwd: 'theme' }); console.log(output.toString()); } catch (error) { console.error(`ERROR: ${error.message}\n`); diff --git a/scripts/make-site.sh b/scripts/make-site.sh index 59330c1071..6d8c66bc69 100755 --- a/scripts/make-site.sh +++ b/scripts/make-site.sh @@ -2,13 +2,15 @@ # cSpell:ignore autoprefixer docsy postcss themesdir github oneline set -eo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + DEPS="autoprefixer postcss-cli" DOCSY_REPO_DEFAULT="google/docsy" DOCSY_REPO=$DOCSY_REPO_DEFAULT DOCSY_VERS="" DOCSY_SRC="NPM" FORCE_DELETE=false -: ${HUGO:=npx hugo} +: "${HUGO:=node $SCRIPT_DIR/run-hugo.mjs}" SITE_NAME="test-site" THEMESDIR="node_modules" VERBOSE=1 @@ -118,7 +120,7 @@ function set_up_and_cd_into_site() { if [[ "$DOCSY_SRC" == HUGO* ]]; then _set_up_site_using_hugo_modules else - echo "theme: docsy" >> hugo.yaml + echo "theme: docsy/theme" >> hugo.yaml echo "themesDir: $THEMESDIR" >> hugo.yaml fi } @@ -128,7 +130,8 @@ function _set_up_site_using_hugo_modules() { # : ${user_name:=$USER} # : ${user_name:="me"} - HUGO_MOD_WITH_VERS=$DOCSY_REPO + # TOF: Docsy theme lives in the `theme/` subfolder of the Docsy repo. + HUGO_MOD_WITH_VERS="$DOCSY_REPO/theme" if [[ -n $DOCSY_VERS ]]; then HUGO_MOD_WITH_VERS+="@$DOCSY_VERS" fi @@ -158,11 +161,11 @@ function _set_up_site_using_hugo_modules() { git log --oneline -$DEPTH && \ if [[ -n $SWITCH_NEEDED ]]; then git switch --detach $DOCSY_VERS; fi \ ) - echo "replace github.com/$DOCSY_REPO_DEFAULT => ./tmp/docsy" >> go.mod - eval "$HUGO mod get github.com/$DOCSY_REPO_DEFAULT" $OUTPUT_REDIRECT + echo "replace github.com/$DOCSY_REPO_DEFAULT/theme => ./tmp/docsy/theme" >> go.mod + eval "$HUGO mod get github.com/$DOCSY_REPO_DEFAULT/theme" $OUTPUT_REDIRECT fi - echo "module: {proxy: direct, hugoVersion: {extended: true}, imports: [{path: github.com/$DOCSY_REPO_DEFAULT, disable: false}]}" >> hugo.yaml + echo "module: {proxy: direct, hugoVersion: {extended: true}, imports: [{path: github.com/$DOCSY_REPO_DEFAULT/theme, disable: false}]}" >> hugo.yaml } function main() { @@ -177,7 +180,7 @@ function main() { echo "[INFO] Getting Docsy as NPM package '$NPM_PKG'" DEPS+=" $NPM_PKG" elif [[ "$DOCSY_SRC" == "LOCAL" ]]; then - echo "[INFO] Getting Docsy through a local directory '$THEMESDIR" + echo "[INFO] Getting Docsy through a local directory '$THEMESDIR'" fi [[ $VERBOSE ]] && set -x diff --git a/scripts/mkdirp-hugo-mod.js b/scripts/mkdirp-hugo-mod.js index 25a27d1ae1..b8d402656c 100644 --- a/scripts/mkdirp-hugo-mod.js +++ b/scripts/mkdirp-hugo-mod.js @@ -24,7 +24,9 @@ console.log( // ... // ) function extractModulePaths() { - const goModPath = path.join(__dirname, '..', 'go.mod'); + // go.mod lives in theme/ as of the TOF refactor; this script remains at the + // repo root's scripts/ so its callers (root postinstall) need no path change. + const goModPath = path.join(__dirname, '..', 'theme', 'go.mod'); let directories = []; try { diff --git a/scripts/refresh-sass-variables.pl b/scripts/refresh-sass-variables.pl index eabf9ce719..5da49bbd6b 100755 --- a/scripts/refresh-sass-variables.pl +++ b/scripts/refresh-sass-variables.pl @@ -4,7 +4,7 @@ use warnings; my $bootstrap_vars = "node_modules/bootstrap/scss/_variables.scss"; -my $forward_vars = "assets/scss/td/_variables_forward.scss"; +my $forward_vars = "theme/assets/scss/td/_variables_forward.scss"; die "File not found: $bootstrap_vars\n" unless -f $bootstrap_vars; die "File not found: $forward_vars\n" unless -f $forward_vars; diff --git a/scripts/run-hugo.mjs b/scripts/run-hugo.mjs new file mode 100644 index 0000000000..1148943dda --- /dev/null +++ b/scripts/run-hugo.mjs @@ -0,0 +1,49 @@ +#!/usr/bin/env node +// Resolve the installed `hugo-extended` and exec it with the forwarded args. +// Reuses docsy.dev's install (the repo's single hugo-extended declaration, +// version-pinned via package.json `config.hugo_version`) rather than `npx hugo`. +// Cross-OS: runs the package's Node bin wrapper, not a POSIX symlink / Win shim. + +import { spawnSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; + +const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '..', +); +const searchBases = [path.join(repoRoot, 'docsy.dev'), repoRoot]; + +function resolveHugoBin() { + for (const base of searchBases) { + // By node_modules path, not require.resolve('hugo-extended/package.json'): + // the package's `exports` blocks that (ERR_PACKAGE_PATH_NOT_EXPORTED). + const pkgDir = path.join(base, 'node_modules', 'hugo-extended'); + const pkgJson = path.join(pkgDir, 'package.json'); + if (!existsSync(pkgJson)) continue; + const { bin } = JSON.parse(readFileSync(pkgJson, 'utf8')); + const rel = typeof bin === 'string' ? bin : bin?.hugo; + if (rel) return path.join(pkgDir, rel); + } + return null; +} + +const hugoBin = resolveHugoBin(); +if (!hugoBin) { + console.error( + '[run-hugo] hugo-extended not found — run `npm run install:all` first.', + ); + process.exit(127); +} + +const { status, error } = spawnSync( + process.execPath, + [hugoBin, ...process.argv.slice(2)], + { stdio: 'inherit' }, +); +if (error) { + console.error(`[run-hugo] ${error.message}`); + process.exit(1); +} +process.exit(status ?? 1); diff --git a/scripts/scrollspy-patch/README.md b/scripts/scrollspy-patch/README.md index f9a8d68264..bbc9e5ee7e 100644 --- a/scripts/scrollspy-patch/README.md +++ b/scripts/scrollspy-patch/README.md @@ -8,20 +8,20 @@ method as the METHOD. - `node_modules/bootstrap/js/src/scrollspy.js`: the SOURCE_FILE containing the METHOD to be patched. -- `assets/js/scrollspy-patch.js`: code that patches the METHOD at runtime +- `theme/assets/js/scrollspy-patch.js`: code that patches the METHOD at runtime (RUNTIME_PATCHER_JS). Everything described here is in support of creating this file from the original Bootstrap SOURCE_FILE. Intermediate files used to simplify the process of creating the RUNTIME_PATCHER_JS file, and detecting when the METHOD code has changed: -- `assets/_cache/bootstrap/scrollspy-method.js`: the METHOD function source - extracted from SOURCE_FILE (METHOD_SOURCE_FILE) -- `assets/_cache/bootstrap/method.patch`: standard patch used to create our - patched METHOD code; it is in standard unified diff format (generated by +- `theme/assets/_cache/bootstrap/scrollspy-method.js`: the METHOD function + source extracted from SOURCE_FILE (METHOD_SOURCE_FILE) +- `theme/assets/_cache/bootstrap/method.patch`: standard patch used to create + our patched METHOD code; it is in standard unified diff format (generated by `diff -u` and applied by the standard `patch` command). -- `assets/_cache/bootstrap/scrollspy-method-patched.js` - the METHOD function - patched. +- `theme/assets/_cache/bootstrap/scrollspy-method-patched.js` - the METHOD + function patched. ## Scripts @@ -29,11 +29,11 @@ RUNTIME_PATCHER_JS file, and detecting when the METHOD code has changed: METHOD_SOURCE_FILE file. - `apply-patch.sh` - Applies the patch using the standard `patch` command and saves the patched method to `scrollspy-method-patched.js` -- `update-patch-js.pl` - Updates `assets/js/scrollspy-patch.js` with the patched - method from `scrollspy-method-patched.js` +- `update-patch-js.pl` - Updates `theme/assets/js/scrollspy-patch.js` with the + patched method from `scrollspy-method-patched.js` -The patch file `method.patch` is stored in `assets/_cache/bootstrap/` alongside -the cached method file. +The patch file `method.patch` is stored in `theme/assets/_cache/bootstrap/` +alongside the cached method file. ## Workflow @@ -42,11 +42,11 @@ the cached method file. The `_prepare:scrollspy-patch` script (called by `_prepare`) automatically: 1. Extracts the method from Bootstrap (`_cp:bs-scrollspy`) - writes to - `assets/_cache/bootstrap/scrollspy-method.js` + `theme/assets/_cache/bootstrap/scrollspy-method.js` 2. Applies the patch (`apply-patch.sh`) - writes patched method to - `assets/_cache/bootstrap/scrollspy-method-patched.js` -3. Updates `assets/js/scrollspy-patch.js` (`update-patch-js.pl`) - syncs the - patched method body into the runtime patch file + `theme/assets/_cache/bootstrap/scrollspy-method-patched.js` +3. Updates `theme/assets/js/scrollspy-patch.js` (`update-patch-js.pl`) - syncs + the patched method body into the runtime patch file The `ci:prepare` script calls `_prepare` and `_diff:check` to ensure no unexpected changes occurred. If the cached method source, patched result, or @@ -71,7 +71,7 @@ When the METHOD code has changed: - Manually regenerate the patch file by running: ```bash - cd assets/_cache/bootstrap && + cd theme/assets/_cache/bootstrap && diff -u scrollspy-method.js scrollspy-method-patched.js > method.patch ``` diff --git a/scripts/scrollspy-patch/apply-patch.sh b/scripts/scrollspy-patch/apply-patch.sh index 249880f12c..205c0376c6 100755 --- a/scripts/scrollspy-patch/apply-patch.sh +++ b/scripts/scrollspy-patch/apply-patch.sh @@ -11,7 +11,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" -CACHE_DIR="$PROJECT_ROOT/assets/_cache/bootstrap" +CACHE_DIR="$PROJECT_ROOT/theme/assets/_cache/bootstrap" CACHED_METHOD_FILE="$CACHE_DIR/scrollspy-method.js" PATCH_FILE="$CACHE_DIR/method.patch" PATCHED_DEST_FILE="$CACHE_DIR/scrollspy-method-patched.js" diff --git a/scripts/scrollspy-patch/extract-method.pl b/scripts/scrollspy-patch/extract-method.pl index 81a3489706..6e618c6ba2 100755 --- a/scripts/scrollspy-patch/extract-method.pl +++ b/scripts/scrollspy-patch/extract-method.pl @@ -15,7 +15,7 @@ my $PROJECT_ROOT = dirname(dirname($SCRIPT_DIR)); my $BOOTSTRAP_SOURCE = "$PROJECT_ROOT/node_modules/bootstrap/js/src/scrollspy.js"; -my $CACHED_METHOD_FILE = "$PROJECT_ROOT/assets/_cache/bootstrap/scrollspy-method.js"; +my $CACHED_METHOD_FILE = "$PROJECT_ROOT/theme/assets/_cache/bootstrap/scrollspy-method.js"; # Check if Bootstrap source exists unless (-f $BOOTSTRAP_SOURCE) { diff --git a/scripts/scrollspy-patch/update-patch-js.pl b/scripts/scrollspy-patch/update-patch-js.pl index da1da85254..c613d382f3 100755 --- a/scripts/scrollspy-patch/update-patch-js.pl +++ b/scripts/scrollspy-patch/update-patch-js.pl @@ -1,7 +1,7 @@ #!/usr/bin/env perl # -# Updates assets/js/scrollspy-patch.js with the patched method from -# assets/_cache/bootstrap/scrollspy-method-patched.js +# Updates theme/assets/js/scrollspy-patch.js with the patched method from +# theme/assets/_cache/bootstrap/scrollspy-method-patched.js # # cSpell:ignore scrollspy @@ -13,8 +13,8 @@ my $SCRIPT_DIR = dirname(abs_path(__FILE__)); my $PROJECT_ROOT = dirname(dirname($SCRIPT_DIR)); -my $PATCHED_METHOD_FILE = "$PROJECT_ROOT/assets/_cache/bootstrap/scrollspy-method-patched.js"; -my $PATCH_JS_FILE = "$PROJECT_ROOT/assets/js/scrollspy-patch.js"; +my $PATCHED_METHOD_FILE = "$PROJECT_ROOT/theme/assets/_cache/bootstrap/scrollspy-method-patched.js"; +my $PATCH_JS_FILE = "$PROJECT_ROOT/theme/assets/js/scrollspy-patch.js"; sub main { # Check if patched method file exists diff --git a/scripts/sync-theme-deps.mjs b/scripts/sync-theme-deps.mjs new file mode 100644 index 0000000000..4f173913c2 --- /dev/null +++ b/scripts/sync-theme-deps.mjs @@ -0,0 +1,103 @@ +#!/usr/bin/env node +// @ts-check +/** + * Mirror the root package.json's `dependencies` versions into + * theme/package.json's `dependencies`. Idempotent. + * + * The root manifest is the canonical source of truth for theme runtime + * dependency versions (bootstrap, @fortawesome/fontawesome-free, …). The + * theme/package.json carries the same list so that consumers of theme/ as a + * file/tarball (notably docsy.dev's `_install-theme-deps` postinstall, which + * runs `npm install ../theme --install-links`) see the right versions. + * + * Wired into `_prepare`, `postupdate:dep`, and `postupdate:packages` so it + * runs whenever maintainers refresh deps. Maintainers may also invoke it + * directly: `npm run _sync:theme-deps`. + * + * Behavior: + * - For each key in theme/package.json's `dependencies`, adopt the version + * declared in the root package.json (if root declares it). + * - Keys present in theme but not in root → warning, no change. + * - Keys present in root but not in theme → warning, no change. (Theme's + * dep set is curated by hand; we only sync versions.) + * - If nothing changes, the script is a no-op and writes nothing. + */ + +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const ROOT_PKG = path.join(ROOT, 'package.json'); +const THEME_PKG = path.join(ROOT, 'theme', 'package.json'); + +function readJson(p) { + return JSON.parse(fs.readFileSync(p, 'utf8')); +} + +function writeJson(p, data) { + fs.writeFileSync(p, JSON.stringify(data, null, 2) + '\n', 'utf8'); +} + +/** + * @param {object} [io] + * @param {() => any} [io.readRoot] + * @param {() => any} [io.readTheme] + * @param {(data: any) => void} [io.writeTheme] + * @param {{ log: (s: string) => void, warn: (s: string) => void }} [io.logger] + * @returns {{ changed: boolean, changes: {name: string, from: string, to: string}[], onlyInTheme: string[], onlyInRoot: string[] }} + */ +export function syncThemeDeps({ + readRoot = () => readJson(ROOT_PKG), + readTheme = () => readJson(THEME_PKG), + writeTheme = (data) => writeJson(THEME_PKG, data), + logger = console, +} = {}) { + const root = readRoot(); + const theme = readTheme(); + const rootDeps = root.dependencies || {}; + const themeDeps = { ...(theme.dependencies || {}) }; + + const changes = []; + const onlyInTheme = []; + + for (const name of Object.keys(themeDeps)) { + if (!(name in rootDeps)) { + onlyInTheme.push(name); + continue; + } + if (themeDeps[name] !== rootDeps[name]) { + changes.push({ name, from: themeDeps[name], to: rootDeps[name] }); + themeDeps[name] = rootDeps[name]; + } + } + + const onlyInRoot = Object.keys(rootDeps).filter((k) => !(k in themeDeps)); + + if (onlyInTheme.length) { + logger.warn( + `sync-theme-deps: warning: theme/package.json declares deps not in root: ${onlyInTheme.join(', ')}`, + ); + } + if (onlyInRoot.length) { + logger.warn( + `sync-theme-deps: warning: root package.json has deps not in theme: ${onlyInRoot.join(', ')}`, + ); + } + + if (changes.length === 0) { + logger.log('sync-theme-deps: theme/package.json already in sync'); + return { changed: false, changes, onlyInTheme, onlyInRoot }; + } + + theme.dependencies = themeDeps; + writeTheme(theme); + for (const c of changes) { + logger.log(`sync-theme-deps: ${c.name} ${c.from} → ${c.to}`); + } + return { changed: true, changes, onlyInTheme, onlyInRoot }; +} + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + syncThemeDeps(); +} diff --git a/scripts/sync-theme-deps.test.mjs b/scripts/sync-theme-deps.test.mjs new file mode 100644 index 0000000000..2486012014 --- /dev/null +++ b/scripts/sync-theme-deps.test.mjs @@ -0,0 +1,101 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; + +import { syncThemeDeps } from './sync-theme-deps.mjs'; + +const nullLogger = { + log() {}, + warn() {}, +}; + +function inMemoryIo({ rootDeps, themeDeps }) { + const root = { name: 'docsy', dependencies: { ...rootDeps } }; + const theme = { name: 'theme', dependencies: { ...themeDeps } }; + let written; + return { + io: { + readRoot: () => root, + readTheme: () => theme, + writeTheme: (data) => { + written = JSON.parse(JSON.stringify(data)); + }, + logger: nullLogger, + }, + getWritten: () => written, + }; +} + +test('no-op when versions already match', () => { + const { io, getWritten } = inMemoryIo({ + rootDeps: { bootstrap: '5.3.8', '@fortawesome/fontawesome-free': '6.7.2' }, + themeDeps: { bootstrap: '5.3.8', '@fortawesome/fontawesome-free': '6.7.2' }, + }); + const result = syncThemeDeps(io); + assert.equal(result.changed, false); + assert.deepEqual(result.changes, []); + assert.equal(getWritten(), undefined); +}); + +test('updates a single drifting version', () => { + const { io, getWritten } = inMemoryIo({ + rootDeps: { bootstrap: '5.3.9', '@fortawesome/fontawesome-free': '6.7.2' }, + themeDeps: { bootstrap: '5.3.8', '@fortawesome/fontawesome-free': '6.7.2' }, + }); + const result = syncThemeDeps(io); + assert.equal(result.changed, true); + assert.deepEqual(result.changes, [ + { name: 'bootstrap', from: '5.3.8', to: '5.3.9' }, + ]); + assert.equal(getWritten().dependencies.bootstrap, '5.3.9'); + assert.equal( + getWritten().dependencies['@fortawesome/fontawesome-free'], + '6.7.2', + ); +}); + +test('updates multiple drifting versions in one pass', () => { + const { io, getWritten } = inMemoryIo({ + rootDeps: { bootstrap: '5.3.9', '@fortawesome/fontawesome-free': '6.8.0' }, + themeDeps: { bootstrap: '5.3.8', '@fortawesome/fontawesome-free': '6.7.2' }, + }); + const result = syncThemeDeps(io); + assert.equal(result.changed, true); + assert.equal(result.changes.length, 2); + assert.equal(getWritten().dependencies.bootstrap, '5.3.9'); + assert.equal( + getWritten().dependencies['@fortawesome/fontawesome-free'], + '6.8.0', + ); +}); + +test('warns and does not write for theme-only deps', () => { + const warnings = []; + const { io } = inMemoryIo({ + rootDeps: { bootstrap: '5.3.8' }, + themeDeps: { bootstrap: '5.3.8', 'theme-only-thing': '1.0.0' }, + }); + io.logger = { + log() {}, + warn: (s) => warnings.push(s), + }; + const result = syncThemeDeps(io); + assert.equal(result.changed, false); + assert.deepEqual(result.onlyInTheme, ['theme-only-thing']); + assert.ok(warnings.some((w) => w.includes('theme-only-thing'))); +}); + +test('warns and does not add for root-only deps', () => { + const warnings = []; + const { io } = inMemoryIo({ + rootDeps: { bootstrap: '5.3.8', 'root-only-dev-helper': '2.0.0' }, + themeDeps: { bootstrap: '5.3.8' }, + }); + io.logger = { + log() {}, + warn: (s) => warnings.push(s), + }; + const result = syncThemeDeps(io); + assert.equal(result.changed, false); + assert.deepEqual(result.onlyInRoot, ['root-only-dev-helper']); + assert.ok(warnings.some((w) => w.includes('root-only-dev-helper'))); +}); diff --git a/tasks/0.16/repo-reorg/README.md b/tasks/0.16/repo-reorg/README.md new file mode 100644 index 0000000000..681d71a1c1 --- /dev/null +++ b/tasks/0.16/repo-reorg/README.md @@ -0,0 +1,66 @@ +--- +title: TOF (0.16 repo reorg) — index +date: 2026-05-24 +issue: https://github.com/google/docsy/issues/2617 +--- + +Planning materials for the **Theme-Only Folder (TOF)** refactor in Docsy 0.16. +Upstream tracking: issue [#2617][]. + +This work is split across phases, and submitted via multiple PRs over the +task-working branch `task/repo-reorg-2026-05`. + +## Reviewer hot path + +For release-facing review, start with: + +1. [theme-only-folder.plan.md][plan] for the intended end state. +2. [spike-notes.md][spike] "Migration snippets for Phase 5" for the final user + migration text. +3. This README's status table for what is done and what remains. + +Use [theme-only-folder.execution.md][exec] only when phase sequencing or a +specific status decision matters. + +## In this folder + +| File | Purpose | +| -------------------------------------- | -------------------------------------------------------------------------------------- | +| [theme-only-folder.plan.md][plan] | Design contract: end state, package boundary, acceptance criteria, non-goals. | +| [theme-only-folder.execution.md][exec] | Sequencing roadmap: Phases 0–5, with per-phase exit criteria and status notes. | +| [spike-notes.md][spike] | Living log of the compatibility spike (commands, consumer-config edits, observations). | +| [monorepo-extra-analysis.md][analysis] | Earlier analysis that informed the spike and shaped TOF; retained for context. | + +[plan]: ./theme-only-folder.plan.md +[exec]: ./theme-only-folder.execution.md +[spike]: ./spike-notes.md +[analysis]: ./monorepo-extra-analysis.md +[#2617]: https://github.com/google/docsy/issues/2617 +[#2640]: https://github.com/google/docsy/pull/2640 + +## Status at a glance + +Updated 2026-05-25. Per-phase detail (with exit criteria) lives in the +[execution plan][exec]. **Phases 2 and 3 are now iterated as a pair** (like 0 +and 1): a local-only smoke pass does not close Phase 2 until the same matrix is +green in CI. + +| Phase | Status | +| ------------------------------------ | --------------------------------------------------------------- | +| 0 — structural move | Done — landed on task branch | +| 1 — `docsy.dev` consumes TOF | Done — local + Netlify deploy preview green ([#2640][]) | +| 2 — local smoke tests (CI emulation) | Done — CI smoke matrix green ([#2640][]) | +| 3 — GitHub CI | Done — run-hugo + install:all; full CI matrix green ([#2640][]) | +| 4 — `docsy-example` | In progress — (a) sibling-repo test done; (b)/(c) pending | +| 5 — docs and release notes | Pending | + +Next concrete steps, in order: + +1. **Phase 4 (active):** + - (a) local `docsy-example` test against the sibling theme repo — **done**. + - (b) merge the task branch to `main` via a PR (the canonical move lands). + - (c) final `docsy-example` config + test against Docsy from `main`. +2. Phase 5: update the get-started "clone" docs for the new non-module setup + procedure recorded in [spike-notes][spike] Phase 2, plus changelog/blog. +3. Later: formalize the smoke matrix as a local Vitest/TS harness — see the + execution plan's "Local test harness" section. diff --git a/tasks/0.16/repo-reorg/monorepo-extra-analysis.md b/tasks/0.16/repo-reorg/monorepo-extra-analysis.md new file mode 100644 index 0000000000..a4fa56d82c --- /dev/null +++ b/tasks/0.16/repo-reorg/monorepo-extra-analysis.md @@ -0,0 +1,228 @@ +--- +title: Extra analysis for the theme-subfolder monorepo plan +date: 2026-05-20 +status: draft +issue: https://github.com/google/docsy/issues/2617 +companion: ./theme-only-folder.plan.md +cSpell:ignore: webfonts cutover bikeshedding +--- + +## About This Doc + +Companion notes to [theme-only-folder.plan.md][plan]. This doc collects concrete +pitfalls, open questions, and acceptance-criteria additions found while +reviewing the plan against the current repo. The parent plan should stay lean; +this doc is the working scratchpad and reviewer reference. + +[plan]: ./theme-only-folder.plan.md + +## TL;DR + +The plan is well-framed. The one decision that will make or break 0.16 is **how +a non-module NPM install resolves theme files when the canonical layout sits +under `theme/`**. That answer drives `go.mod` location, mount math, smoke tests, +release notes, and the user-facing migration story. + +Strong recommendation: do a **compatibility spike** on a feature branch before +merging the move. Build the website, the example site, and the +`scripts/make-site.sh` smoke matrix against the new layout first. + +## Top Issues + +### 1. The non-module NPM install path is under-specified + +Today, sites using `themesDir: node_modules` plus `theme: docsy` expect Hugo to +find `node_modules/docsy/{assets,layouts,i18n,static}/` directly. If those move +into `theme/`, the same install puts them at `node_modules/docsy/theme/...`. +Hugo's non-module theme loader does not transparently understand the deeper +shape; mounts declared in `theme/hugo.yaml` do not help here because non-module +themes are loaded against the consuming site's config. + +Pick one and write it into the plan: + +- **(a) Root stays the theme root for NPM consumers.** Root `package.json` + remains `name: "docsy"`. The "canonical files live in `theme/`" statement + becomes a code-organization claim, with the root layout exposed via facades, + symlinks, or mounts so the public install shape does not change. +- **(b) Document a one-line config edit** for non-module users + (`theme: docsy/theme` or a `themesDir` adjustment). Breaks "no config change + for module users beyond the usual version update" only for non-module users. +- **(c) Drop non-module install support.** Out of scope per the current + non-goals. + +Preferred: (a). It is the only option compatible with the existing compatibility +promise. + +### 2. Only one `go.mod` is meaningful + +The proposed shape diagram shows both a root `go.mod` and a `theme/go.mod`. For +a given module path on a given branch, Go resolves to a single `go.mod`. Two +`go.mod` files only make sense if you intend two import paths +(`github.com/google/docsy` and `github.com/google/docsy/theme`), which +contradicts the compatibility goal. + +Action: drop `theme/go.mod` and `theme/go.sum` from the proposed shape, or +annotate them as "only if a second public module path is introduced". + +The same applies to `hugo.yaml`: be explicit about which file Hugo reads in each +install mode (module, NPM non-module, classic non-module clone) and which file +is the canonical source. + +### 3. The `../../node_modules/...` mount math will shift + +The root `hugo.yaml` contains: + +```49:64:hugo.yaml + # Mounts for projects using Docsy as an NPM package. The source path prefix + # "../.." moves out of themes/docsy so that Docsy can find its dependencies. + - source: ../../node_modules/bootstrap + target: assets/vendor/bootstrap + - source: ../../node_modules/@fortawesome/fontawesome-free + target: assets/vendor/Font-Awesome + - source: ../../node_modules/@fortawesome/fontawesome-free/webfonts + target: static/webfonts + # Mounts for module installations, + # needed to work around a known bug in Go's module management. + - source: assets/_vendor/bootstrap/scss + target: assets/vendor/bootstrap/scss/vendor +``` + +`../..` is counted from the theme root. If the consumer-visible theme root is +deeper after the move (for example `node_modules/docsy/theme/`), the escape may +need to be `../../../`. The same goes for Hugo module cache paths. Validate with +a real consuming site before merging. + +### 4. The `postinstall` lifecycle story is the live one + +Current root `package.json` has: + +```json +"postinstall": "npm run _mkdir:hugo-mod" +``` + +It runs on every consumer `npm install`. The script reads `go.mod` via +`path.join(__dirname, '..', 'go.mod')`. After the move, decide: + +- Where the script lives (with the theme package). +- Whether its `go.mod` path lookup is still correct. +- Whether it should run at all in the chosen install shape. + +Codify the maintainer-only `_prepare` (underscore) convention in the acceptance +criteria: + +> Installing Docsy from NPM or GitHub does not execute `_prepare`, `_cp:bs-rfs`, +> `_prepare:scrollspy-patch`, `_gen-chroma-styles`, or `get:hugo-modules`. + +### 5. Generated, committed artifacts have hard-coded paths + +These files are generated and committed today. Their generators encode the +paths: + +- `assets/_vendor/bootstrap/scss/*.scss` (from `_cp:bs-rfs`) +- `assets/_cache/bootstrap/scrollspy-method.js*` (from the scrollspy patch flow) +- Chroma styles (from `_gen-chroma-styles`) +- `go.sum` (from `get:hugo-modules`) + +After the move, update the generators in `scripts/` and +`scripts/scrollspy-patch/` to write to the new paths, and keep `_diff:check` +working in CI. + +### 6. Smoke matrix must cover the new layout end-to-end + +`scripts/make-site.sh` exercises NPM and `HUGO_MODULE` installs on Windows and +Ubuntu. Add to acceptance criteria: + +> The existing smoke matrix (NPM x HUGO_MODULE x Windows x Ubuntu) passes +> against the new layout **without changes** to the consuming-site config. If +> any change is required, the exact diff is documented in the release notes. + +Also touch `docsy.dev/package.json`: + +```json +"_hugo": "hugo --cleanDestinationDir --logLevel info --themesDir ../.." +``` + +That `--themesDir ../..` assumption becomes wrong after the move. + +## Smaller Things Worth Adding + +### `docsy-example` is a first-class consumer + +Build `docsy-example` against the new layout on a branch and confirm the +smallest possible `go.mod`/`hugo.yaml` change. Ideally zero. Add a Work-Area +bullet for it. + +### Branch-model impact during the cutover + +After the move lands on `main`, every cherry-pick from `main` to `release` for a +0.15.x patch conflicts on most paths. Plan for it: + +- Land the move **early** in 0.16 so the release branch settles. +- Either freeze 0.15.x patch acceptance after a date, or accept the cherry-pick + overhead. +- The existing `git merge -s ours release` ancestry-recording trick matters more + post-move; keep it on schedule. + +### Pre-decide repo-vs-package boundaries for ambiguous files + +To avoid review bikeshedding: + +- `postcss.config.js` (root): historically for consumer sites; most consumers + ship their own. Suggest moving into `docsy.dev/` or deleting if unused there, + plus a documented snippet in the user guide. +- `Dockerfile`, `docker-compose.yaml`: repo dev tooling, stay at root. +- `.editorconfig`, `.prettierrc.json`, `.markdownlint*.yaml`, `.nvmrc`, + `.gitattributes`, `.gitignore`: repo level, stay at root. +- `images/` at the root: clarify whether these are theme assets (move) or repo + marketing (stay). + +### Tests and goldens scope for 0.16 + +Either say "tests stay under `docsy.dev/tests/` for now; a top-level `tests/` +workspace is deferred", or explicitly create the top-level slot. Avoid the +in-between. + +### Node `engines` for the installed theme + +Root currently declares `engines.node >= 24`. That is a maintainer constraint +that should not be imposed on every consumer. Set `engines.node` on the +installed theme package deliberately, ideally as loose as practical or omitted. + +### State the repo-split non-goal explicitly + +People will ask. One line in Non-Goals: + +> The theme stays in the same git repo for 0.16. A separate-repo split, if any, +> is out of scope. + +### Release-note size as a design check + +If the user-facing migration text grows past a short section in the 0.16 release +blog, take it as a signal the compatibility design is not done yet. + +## Suggested Plan Edits + +- Update the Proposed Shape diagram so it shows only the canonical `go.mod` and + `hugo.yaml` (root, per the chosen answer in #1 and #2). +- Add a Compatibility Spike subsection that names the three install modes (Hugo + module, NPM from GitHub, classic non-module theme), states the consumer's + expected layout for each, and commits to validating all three on a feature + branch before the canonical move. +- Expand the Compatibility table with rows for "NPM install command the consumer + types" and "Hugo `theme:` value the consumer uses", with their preserved + values, so "no config change" is unambiguous. +- Add the acceptance-criteria additions above (postinstall scope, smoke matrix, + generator paths). + +## Validation Checklist (Pre-Merge) + +- [ ] `docsy.dev` builds locally against the new layout. +- [ ] `make-site.sh -s NPM` passes against a PR branch of the new layout. +- [ ] `make-site.sh -s HUGO_MODULE` passes against a PR branch. +- [ ] `docsy-example` builds with no `hugo.yaml`/`go.mod` change beyond the + usual version update. +- [ ] `_diff:check` is clean after `_prepare` runs at the new paths. +- [ ] No `_prepare`/`postinstall` work runs in consumer installs. +- [ ] Release-blog upgrade section fits in one short section. + + diff --git a/tasks/0.16/repo-reorg/spike-notes.md b/tasks/0.16/repo-reorg/spike-notes.md new file mode 100644 index 0000000000..691c0c796c --- /dev/null +++ b/tasks/0.16/repo-reorg/spike-notes.md @@ -0,0 +1,444 @@ +--- +title: TOF compatibility spike notes +date: 2026-05-21 +status: in-progress +companion: ./theme-only-folder.execution.md +cSpell:ignore: fontawesome themesdir devdeps +--- + +## About + +Living log of the TOF compatibility spike. Records the exact consumer-facing +config edits, the maintainer-side changes that made them possible, and any +observations. Read by the release-notes drafting work in Phase 5. + +## Migration snippets for Phase 5 + +Use this section as the release-facing source of truth. The rest of this file is +the engineering record behind these snippets. + +### Hugo module + +Before: + +```yaml +module: + imports: + - path: github.com/google/docsy +``` + +After: + +```yaml +module: + imports: + - path: github.com/google/docsy/theme +``` + +Upgrade command: + +```sh +hugo mod get github.com/google/docsy/theme@ +hugo mod tidy +``` + +### NPM from GitHub + +Before: + +```yaml +theme: docsy +themesDir: node_modules +``` + +After: + +```yaml +theme: docsy/theme +themesDir: node_modules +``` + +Install command shape is unchanged except for the Docsy version: + +```sh +npm install --save-dev google/docsy#semver: --omit=peer +``` + +### Clone or Git submodule + +Before: + +```yaml +theme: docsy +``` + +After: + +```yaml +theme: docsy/theme +``` + +Setup commands after TOF: + +```sh +cd themes +git clone -b https://github.com/google/docsy +(cd docsy/theme && npm install) +(cd docsy && node scripts/mkdirp-hugo-mod.js ..) +cd .. +npm install --save-dev autoprefixer postcss-cli +``` + +For a Git submodule install, keep the existing submodule workflow but run the +same `docsy/theme` npm install and `mkdirp-hugo-mod.js` commands after updating +the submodule. + +## Repo state at start of spike + +- Branch: `chalin-m24-monorepo-2026-0520` +- Hugo version: 0.157.0 +- Starting layout: theme files at repo root; `docsy.dev/` is the website + workspace; repo root carries theme runtime deps + repo-wide maintainer + tooling. + +## Repo layout after Phase 0 (current) + +```text +. +├── theme/ # canonical theme tree (assets, layouts, i18n, +│ # static, hugo.yaml, theme.toml, go.mod, go.sum) +│ └── package.json # private mirror of theme runtime deps +├── docsy.dev/ # website; its own node_modules +├── scripts/ # maintainer scripts (chroma, scrollspy patch, +│ # sync-theme-deps.mjs, …) +├── tasks/ +└── package.json # canonical for theme runtime deps + repo-wide + # maintainer tooling (Prettier, mdl, cSpell dict) +``` + +Key invariants of the current implementation: + +- The repo root `package.json` is the **single source of truth** for theme + runtime dependency versions. `theme/package.json` is a private mirror + (`"private": true`) kept aligned by `scripts/sync-theme-deps.mjs`. +- No npm workspaces are declared at the repo root yet; the `workspaces` array is + intentionally empty (with a `workspaces-todo` comment marker). `docsy.dev`'s + `_install-theme-deps` postinstall handles the cross-folder install instead. +- `theme/hugo.yaml` uses the canonical `node_modules/` mount form. The + legacy `../../node_modules/*` escape mounts were dropped. + +## Phase 1: `docsy.dev` (Hugo, classic themesDir + theme) + +### Consumer-side change + +```diff +# docsy.dev/config/_default/hugo.yaml +-theme: [docsy] ++theme: [docsy/theme] +``` + +That is the entire consumer-facing edit for `docsy.dev`'s use of Docsy. The +`_hugo --themesDir ../..` setting in `docsy.dev/package.json` was unchanged. +**Result: one-line change.** + +### Maintainer-side changes (Phase 0 + 1 combined) + +The following were necessary to land the consumer-side one-line change. Captured +here for traceability; they are not user-facing. + +- `git mv` of canonical theme files into `theme/`: `assets`, `i18n`, `images`, + `layouts`, `static`, `hugo.yaml`, `theme.toml`, `go.mod`, `go.sum`. +- `theme/go.mod` `module` declaration changed to + `github.com/google/docsy/theme`. +- `theme/hugo.yaml`: the legacy `../../node_modules/*` escape mounts were + dropped. Hugo's `nodeModulesRoot` helper (`modules/collect.go`, see Hugo issue + #14083) normalises both `node_modules/X` and `../../node_modules/X` to the + same form and then performs a dual lookup — first under the theme directory, + then under the consumer site's working directory. The escape form is pure + backwards compatibility for pre-existing configs; under TOF the simple + `node_modules/X` mount is canonical and covers both cases. +- `theme/package.json` created as a **private mirror** (`"private": true`) of + the root's theme runtime deps (`bootstrap`, `@fortawesome/fontawesome-free`). + Kept aligned with the root by `scripts/sync-theme-deps.mjs`. +- `scripts/sync-theme-deps.mjs` added (with `scripts/sync-theme-deps.test.mjs` + picked up by `test:tooling`). Wired into `_prepare`, `postupdate:dep`, and + `postupdate:packages`. A maintainer can also invoke it directly: + `npm run _sync:theme-deps`. +- Repo-root `package.json` script paths updated to point at the new theme + locations: `_check:format` now globs `theme/assets *.md theme/i18n …`, + `_cp:bs-rfs` writes to `theme/assets/_vendor/bootstrap/scss/`, etc. + `mkdirp-hugo-mod.js`, `_gen-chroma-style.sh`, `refresh-sass-variables.pl`, + `scrollspy-patch/*`, `getHugoModules/index.mjs`, and `make-site.sh` similarly + updated. +- `.prettierignore` updated from `/assets/...` to `/theme/assets/...` so the + same files are skipped as before. `.markdownlint-cli2.yaml`'s `!layouts/**` + glob updated to `!theme/layouts/**`. +- `docsy.dev/package.json` gained `_install-theme-deps`: + `npm install ../theme --install-links --no-save && rm -rf node_modules/theme`, + wired in as a `postinstall`. The `--install-links` flag tells npm to treat the + local `../theme` package as a tarball, which has the side effect of installing + `theme/`'s declared runtime deps (Bootstrap, Font Awesome) into + `docsy.dev/node_modules/`. The `rm -rf` line then drops the now-redundant copy + of the theme tree itself. +- `docsy.dev/scripts/_install.sh` removed. `docsy.dev/package.json` gained + `install:all` (`npm install -C .. && npm install`). Netlify runs + `npm run install:all && npm run build:preview` (and `build:production` in + production) per `docsy.dev/netlify.toml`. + +### Observations + +- **Hugo's mount-source validation for themes/modules** rejects sources + containing `..` segments unless they match a special-cased prefix. The only + special-cased prefix is `../../node_modules/` (kept for backwards + compatibility with pre-Hugo-0.152 configs). Deepening to + `../../../node_modules/` is **not** recognised and falls through to the + `filepath.IsLocal` rejection. Relevant code: `nodeModulesRoot` in + `modules/collect.go`; see Hugo issue #14083. +- **The simple `node_modules/X` mount form is canonical under TOF.** After + normalisation, Hugo tries the source first relative to the theme directory and + then relative to the consumer site's working directory. This dual lookup is + what the escape form was buying; under TOF we spell it the modern way. Net + effect: the `../../node_modules/*` block in `theme/hugo.yaml` was redundant + and could be dropped. +- **Hugo module `imports:` alone is not sufficient** to replace the local + `node_modules/*` mounts when the theme is loaded via classic + `themesDir + theme` (which `docsy.dev` does today). SCSS resolution failed + without the local mounts even though `imports:` was configured. +- **npm workspaces were tried and abandoned for this PR.** Variants were + explored (root with `["docsy.dev"]`, with `["theme", "docsy.dev"]`, and with + `[]`). Each variant had a trade-off between hoisting behaviour and the + cross-folder install of theme runtime deps into `docsy.dev/node_modules/`. The + shipped design declares `workspaces: []` (with a `workspaces-todo` comment + marker for the follow-on plan) and relies on `docsy.dev`'s + `_install-theme-deps` postinstall for the cross-folder hand-off. +- **`hugo-extended` continues to live in `docsy.dev/devDependencies`.** No + change from the pre-TOF layout. The maintainer-tooling-folder reorganisation + considered during the spike was deferred to a follow-on plan. + +### Status + +**Phase 1 exit criterion met for local build.** `docsy.dev` builds locally from +`theme/` with the one-line consumer config change (223 EN pages, 218 FR pages) +**and** with no symlinks anywhere. The build chain works with this maintainer +setup: + +```sh +npm install # repo-root deps (theme runtime + maintainer tools) +npm run docsy.dev-install # docsy.dev deps (site build + hugo-extended); + # postinstall runs _install-theme-deps +npm run build # green +``` + +The second half of the Phase 1 exit criterion — a green Netlify deploy preview — +is confirmed on [#2640](https://github.com/google/docsy/pull/2640). + +### Note: `docsy.dev` is a distinct (sibling-folder) install shape + +`docsy.dev` consumes Docsy as an **in-repo sibling folder**, which is a fourth +shape beyond the three smoke modes (NPM, Hugo module, non-module clone): + +- **Theme access:** Hugo runs from `docsy.dev/` with `--themesDir ../..` (the + parent of the repo) and `theme: [docsy/theme]`, so `docsy/theme` re-descends + into the sibling `theme/` of the same repo. (Relies on the repo dir being + named `docsy`.) +- **Theme deps:** `docsy.dev`'s `postinstall` → `_install-theme-deps` + (`npm install ../theme --install-links --no-save && rm -rf node_modules/theme`) + installs the theme's runtime deps into `docsy.dev/node_modules/`, where Hugo's + `node_modules/bootstrap` mount resolves via the consumer-cwd lookup. +- **Module placeholders:** the theme's `imports:` resolve to the empty + `github.com/...` dirs the repo-root `npm install` postinstall creates at `..` + (the parent of the repo), which is exactly where `--themesDir ../..` looks. + +This shape is **already exercised** every time the `docsy.dev` site builds (it +is the Phase 1 exit criterion), so it is covered — just not in the `node:test` +smoke driver. For now it is treated as a maintainer/in-repo shape. It could +later be surfaced and documented as a supported **power-user** consumer setup +(and, if so, get its own smoke case); deferred until we decide to document it as +such. + +## Phase 2: local smoke tests (CI emulation) + +Ran all three install modes locally against the integration branch +(`google/docsy@task/repo-reorg-2026-05`). Each mode built a runnable site with +full styling (the compiled `main.min.css` is ~370 KB and the Font Awesome +`webfonts/` are emitted, confirming the Bootstrap + Font Awesome SCSS resolved — +not just an empty CSS shell). + +Local-run detail: `make-site.sh` defaults `HUGO` to `node scripts/run-hugo.mjs` +(see Phase 3), which resolves `docsy.dev`'s extended Hugo — so a local run needs +no manual Hugo setup beyond `npm run install:all` (an explicit `HUGO=` export +still overrides it). + +### Result matrix + +| # | Install mode | Consumer config edit (the one line) | Builds? | Result | +| --- | ---------------- | ----------------------------------------------------------------- | ------- | ---------------------------------------------------------- | +| 1 | Hugo module | import path `github.com/google/docsy` → `…/docsy/theme` | ✅ | one-line change | +| 2 | NPM (GitHub) | `theme: docsy` → `theme: docsy/theme` (`themesDir: node_modules`) | ✅ | one-line change | +| 3 | Non-module clone | `theme: docsy` → `theme: docsy/theme` | ✅ | one-line config; setup procedure gained a step (see below) | + +### Mode 2 — NPM (GitHub) + +```sh +mkdir -p tmp && cd tmp +# CI does: ../scripts/make-site.sh -s NPM -r $PR_REPO -v $BRANCH +../scripts/make-site.sh -s NPM -r google/docsy -v task/repo-reorg-2026-05 +``` + +The consumer-facing edit is the single `theme:` line. Under the hood: +`npm install` of the GitHub package lands the whole repo at +`node_modules/docsy/`, so `theme: docsy/theme` + `themesDir: node_modules` +resolves the theme at `node_modules/docsy/theme/`. The root `postinstall` +(`_mkdir:hugo-mod`) ran in the installed package and created the empty +Hugo-module placeholder dirs `node_modules/github.com/twbs/bootstrap` and +`node_modules/github.com/FortAwesome/Font-Awesome` (the documented "NPM install +side-effect"), so the theme's `imports:` resolve; the real SCSS comes from the +`node_modules/bootstrap` / `node_modules/@fortawesome/fontawesome-free` mounts +(brought in as deps of the `docsy` package). `mkdirp-hugo-mod.js` already reads +`theme/go.mod`, so no change was needed there. **Result: one-line change.** + +### Mode 1 — Hugo module + +```sh +cd tmp +# CI does: ../scripts/make-site.sh -s HUGO_MODULE -r $PR_REPO -v $BRANCH +../scripts/make-site.sh -s HUGO_MODULE -r google/docsy -v task/repo-reorg-2026-05 +``` + +The consumer-facing edit is the module import path gaining the `/theme` suffix: + +```diff + module: + imports: +- - path: github.com/google/docsy ++ - path: github.com/google/docsy/theme +``` + +Bootstrap and Font Awesome are supplied by the theme's own Hugo-module +`imports:` (`github.com/twbs/bootstrap`, `github.com/FortAwesome/Font-Awesome`), +so no `node_modules` are needed in this mode. With `-r google/docsy` (the +canonical module path) `make-site.sh` runs +`hugo mod get github.com/google/docsy/theme@` directly. (For a fork whose +branch lives off the canonical path, it instead clones the fork and writes a +`replace … => ./tmp/docsy/theme` directive — a harness mechanism, not part of +the user-facing migration.) **Result: one-line change.** + +### Mode 3 — non-module clone into `themes/docsy/` + +The Hugo **config** edit is one line (`theme: docsy` → `theme: docsy/theme`), +and the clone still lands at `themes/docsy/`. But the **setup procedure** +changed versus pre-TOF and needs a doc update in Phase 5. Exact working flow +(run from the site root; site created with `hugo new site --format yaml`): + +```sh +# 1. Clone the theme (whole repo) into themes/docsy +cd themes +git clone -b https://github.com/google/docsy +# 2. Install the theme's runtime deps INTO the theme/ subfolder +(cd docsy/theme && npm install) +# 3. Create the empty Hugo-module placeholder dirs under themesDir (themes/) +(cd docsy && node scripts/mkdirp-hugo-mod.js ..) +cd .. +# 4. PostCSS at the site root (unchanged prerequisite) +npm install --save-dev autoprefixer postcss-cli +# 5. config: theme: docsy/theme +``` + +Why steps 2 and 3 are now separate (pre-TOF, a single +`cd themes/docsy && npm install` did both): + +- The theme root Hugo sees is now `themes/docsy/theme/`, one level deeper. + Hugo's `node_modules/bootstrap` mount is resolved theme-dir-relative first, so + the deps must be installed at `themes/docsy/theme/node_modules/`. Verified: + with the deps one level up at `themes/docsy/node_modules/` the build fails + with + `File to import not found or unreadable: ../../vendor/bootstrap/scss/functions`; + moving them into `themes/docsy/theme/node_modules/` fixes it. +- `theme/package.json` is a script-less private mirror (no `postinstall`), by + design (acceptance criteria: "No other lifecycle scripts"). So the empty + `github.com/...` placeholder dirs that the root `postinstall` used to create + must now be generated explicitly with `mkdirp-hugo-mod.js` (step 3), which + writes them under `themesDir` (`themes/github.com/...`) where Hugo looks up + the theme's `imports:` for a non-module site. + +**Result: one-line config change ✅, builds ✅** (8 pages, ~370 KB CSS, webfonts +emitted). The config promise holds. The get-started "clone" docs (Option 2 in +`other-options.md`) need the updated multi-step install above — tracked for +Phase 5. No design change is required for the move to land; the clone path works +as documented here. + +### Phase 2 exit criterion — met (with Phase 3) + +All three install modes build with the same Hugo-resolution mechanism CI uses +(`run-hugo.mjs`, no `HUGO` override), and the CI smoke matrix is green (see +Phase 3). The earlier local-only passes had relied on an ad-hoc `HUGO` override, +which masked the CI gap that `run-hugo.mjs` + `install:all` then closed — so +Phases 2 and 3 closed together, as the same install matrix on two surfaces. +Standing follow-up for Phase 5: get-started clone docs. + +## Phase 3: GitHub CI — resolved (decision E); CI matrix green + +**Symptom:** the smoke matrix (`smoke.yaml`) fails on both OSes because the +throwaway site cannot find a Hugo executable. + +**Root cause:** `docsy.dev` used to be an npm **workspace**, so root +`npm install` hoisted `hugo-extended` (declared in `docsy.dev/devDependencies`) +up into the repo-root `node_modules/.bin/`. The smoke test runs `make-site.sh` +from `tmp/`, and its default `npx hugo` walks _up_ the tree, resolving +`repo-root/node_modules/.bin/hugo`. Under TOF, `workspaces: []`, so root +`npm install` no longer pulls `docsy.dev`'s deps — `hugo-extended` is gone from +root `node_modules`, and `npx hugo` resolves nothing. + +**Solution options under discussion** (constraints: single source of truth for +the Hugo version — `package.json` `config.hugo_version`; and ideally a mechanism +reusable by the planned local test harness across the dev's own OS): + +- **A. Restore workspace hoisting** (`workspaces: ["docsy.dev"]`). Smallest diff + but reopens the deferred `workspaces-todo` trade-off. +- **B. Declare `hugo-extended` at the repo root** (pinned to + `config.hugo_version`). Duplicates the declaration the plan keeps only in + `docsy.dev`. +- **C. Smoke site installs its own Hugo** + (`npm i hugo-extended@` into the throwaway site). Most + faithful to a real consumer; identical in CI and the local harness on any OS. + Adds an install per run; `make-site.sh` must read the version. +- **D. Job-level setup action** (`peaceiris/actions-hugo`, extended). Fast and + standard but CI-only — does not help the local harness. +- **E. Pass `HUGO` from an installed binary** (the local workaround). Reuses + `docsy.dev`'s single declaration but makes the consumer smoke test reach into + `docsy.dev`. + +**Decision: E, made cross-OS.** Added `scripts/run-hugo.mjs` — a Node helper +that locates an installed `hugo-extended` (searching `docsy.dev/node_modules` +first, then the repo root) and execs its `dist/cli.mjs` bin wrapper via the +current `node`. It is portable by construction: it relies on Node plus +`hugo-extended`'s own JS wrapper to pick the platform binary, so there is no +dependency on POSIX symlinks or Windows `.cmd`/`.ps1` shims. The Hugo _version_ +stays single-sourced — the helper runs whatever `docsy.dev` installed, which is +pinned via `package.json` `config.hugo_version` (currently 0.157.0). + +`make-site.sh` now defaults to it: `: "${HUGO:=node $SCRIPT_DIR/run-hugo.mjs}"` +(an explicit `HUGO=` export still wins, e.g. `HUGO='npx hugo'`). + +Implementation notes: + +- Resolve the package by its `node_modules/hugo-extended` path, **not** + `require.resolve('hugo-extended/package.json')` — the latter is blocked by the + package's `exports` map (`ERR_PACKAGE_PATH_NOT_EXPORTED`). +- Verified locally (macOS) with **no `HUGO` override**: `make-site.sh -s NPM` + and `-s HUGO_MODULE` against `google/docsy@task/repo-reorg-2026-05` both build + green (369 KB `main.min.css` each); `node scripts/run-hugo.mjs version` + reports extended 0.157.0 from any cwd. + +**CI step — done; matrix green.** The helper reuses `docsy.dev`'s +`hugo-extended`, but `smoke.yaml`'s setup previously ran only root +`npm install`. Added an `install:all` root script +(`npm run docsy.dev-install && npm install` — `docsy.dev-install` first so +`test.yaml`'s `install:all -- --omit=optional` applies the flag to the final +root `npm install`) and switched the smoke job's "Setup workspace" step to +`npm run install:all`, so `docsy.dev` (and its `hugo-extended`) is installed +before `make-site.sh`. Chose `install:all` over a lighter targeted install — +consistency across jobs and a useful onboarding command outweigh the few seconds +saved. **Confirmed on CI** ([#2640](https://github.com/google/docsy/pull/2640)): +`test` (build) and `smoke` (new-site NPM + HUGO_MODULE) pass on ubuntu-latest +and windows-latest, plus a green Netlify deploy preview. diff --git a/tasks/0.16/repo-reorg/theme-only-folder.execution.md b/tasks/0.16/repo-reorg/theme-only-folder.execution.md new file mode 100644 index 0000000000..602eccf053 --- /dev/null +++ b/tasks/0.16/repo-reorg/theme-only-folder.execution.md @@ -0,0 +1,239 @@ +--- +title: TOF execution plan (compatibility spike work) +date: 2026-05-21 +status: draft +companion: ./theme-only-folder.plan.md +issue: https://github.com/google/docsy/issues/2617 +cSpell:ignore: fontawesome +--- + +## About this doc + +Very-high-level execution roadmap for the [TOF plan][plan]. It defines the order +of operations for the compatibility spike work and the canonical move, broken +into phases that are independently checkable and, where practical, independently +mergeable. + +The plan itself is the design contract. This doc is purely about sequencing. For +a bird's-eye view of where we are and what's next, see the folder +[README][readme]. + +[plan]: ./theme-only-folder.plan.md +[readme]: ./README.md + +## Working principles + +- **Incremental as far as practical.** Phase 0 (the structural move) is + unavoidably large. Phases 1+ are surgical and validate one consumer surface at + a time. +- **Phases 0 and 1 are intertwined in practice.** Expect to cycle between moving + files (Phase 0) and trying the `docsy.dev` build (Phase 1) until both exit + criteria are met. Treat them as a tight loop, not two sequential blocks. +- **Phases 2 and 3 are a pair, too.** Local smoke (Phase 2) and CI smoke + (Phase 3) validate the _same_ install matrix on two surfaces. A local-only + green does **not** close Phase 2 if it relies on environment fixups (e.g. an + ad-hoc `HUGO` override) that CI does not have. Iterate them as one loop until + the same matrix passes both locally and in CI. +- **Single feature branch through Phases 0–3.** All consumer-surface validation + runs against the same tree. Merge to `main` only after Phase 3 passes. +- **Running spike notes** live at `tasks/0.16/repo-reorg/spike-notes.md`. They + accumulate the exact per-install-mode commands and confirmed config edits. The + release-note migration snippets are read out of this file at Phase 5. +- **One-line promise.** The TOF plan promises a single-line consumer config edit + per install mode. If any phase shows the migration growing past that, halt and + iterate on the design before continuing. + +## Phases + +### Phase 0: structural move + +The bulk-change phase. Done in a single feature branch, ideally one PR (or a +small stack) so the move is reviewable as a unit. + +- Create `theme/` and move the canonical theme files into it (`assets`, `i18n`, + `images`, `layouts`, `static`, `hugo.yaml`, `theme.toml`, `go.mod`, `go.sum`). +- Update `theme/go.mod` `module` declaration to `github.com/google/docsy/theme`. +- Drop the legacy `../../node_modules/*` escape mounts from `theme/hugo.yaml`; + keep only the canonical `node_modules/` form. +- Update generators and patch scripts under `scripts/` to read/write under + `theme/` (`mkdirp-hugo-mod.js`, `_gen-chroma-style.sh`, + `refresh-sass-variables.pl`, `scrollspy-patch/*`, `getHugoModules/`, + `make-site.sh`). Update root `package.json` script globs accordingly. +- Add `theme/package.json` as a private mirror of root's theme deps, plus + `scripts/sync-theme-deps.mjs` and the hook wiring (`_prepare`, + `postupdate:dep`, `postupdate:packages`). +- Confirm `_prepare` (and downstream `ci:prepare`) succeeds against the new + paths and `_diff:check` is clean. + +Exit criterion: file move is clean; `_prepare` + `_diff:check` pass; no consumer +surface validated yet. + +Status (2026-05-25): **exit criterion met — landed on task branch.** The +structural move plus the `_prepare` / `_diff:check` regression check have all +landed on `task/repo-reorg-2026-05`. + +### Phase 1: `docsy.dev` consumes TOF + +Make Docsy's primary end-to-end test (the website) build against the new layout. +This is the most informative single check. + +- Update `docsy.dev` config to use the new theme path (`theme: [docsy/theme]`). +- Add the `_install-theme-deps` postinstall to `docsy.dev/package.json` so theme + runtime deps land in `docsy.dev/node_modules/` (consumer-cwd lookup). +- Build `docsy.dev` locally. Iterate on TOF if anything in the build chain + surprises. +- Record the exact before/after config change and any maintainer-workflow + observations in `tasks/0.16/repo-reorg/spike-notes.md`. +- Confirm Netlify deploy previews work from the spike branch + (`docsy.dev/netlify.toml`: `npm run install:all && npm run build:preview`, and + the production variant; `docsy.dev`'s `install:all` installs the repo root + then `docsy.dev`). + +Exit criterion: `docsy.dev` builds locally and on Netlify against the spike +branch. + +Status (2026-05-25): **exit criterion met.** `docsy.dev` builds from `theme/` +with the one-line `theme: [docsy/theme]` consumer config change and no symlinks +anywhere (223 EN + 218 FR pages), and the Netlify deploy preview is green on +[#2640][]. Netlify uses `npm run install:all && npm run build:preview` (and +`build:production` in production); `docsy.dev`'s `install:all` installs the repo +root then `docsy.dev` (workspaces are empty). + +### Phase 2: local smoke tests (CI emulation) + +Emulate locally what GitHub Actions will eventually run, one install mode at a +time. + +- Update `scripts/make-site.sh` for the new install paths. +- Run `make-site.sh -s NPM`. Confirm the one-line user edit; record in spike + notes. +- Run `make-site.sh -s HUGO_MODULE`. Confirm; record. +- Validate non-module theme install: `hugo new site` + `git clone` Docsy into + `themes/docsy/`. Confirm; record. + +Exit criterion (paired with Phase 3): all three install modes build with the +_same_ Hugo-resolution mechanism CI uses, and the spike-notes matrix is complete +with exact one-line edits. A local-only pass that relies on an ad-hoc `HUGO` +override does not count. + +Status (2026-05-25): **exit criterion met.** All three install modes build with +the same Hugo-resolution mechanism CI uses (`run-hugo.mjs`, no `HUGO` override), +and the CI smoke matrix is green ([#2640][]). Earlier local-only runs had masked +a gap — they set `HUGO` explicitly, while CI's `npx hugo` found nothing once +`docsy.dev` stopped being a workspace (so `hugo-extended` was no longer hoisted +to the repo root). Closing that gap is exactly what `run-hugo.mjs` + +`install:all` do (Phase 3). The non-module-clone setup-step follow-up for Phase +5 still stands. + +[spike-notes]: ./spike-notes.md + +### Phase 3: GitHub CI + +Lift Phase 2 into Actions on the same branch. Paired with Phase 2 (see Working +principles). + +- **Resolve Hugo availability on the runner.** Root cause: `docsy.dev` is no + longer an npm workspace, so root `npm install` no longer hoists + `hugo-extended` into the repo-root `node_modules/.bin/` where the smoke test's + `npx hugo` resolved it. **Decided: option E, made cross-OS** — + `scripts/run-hugo.mjs` reuses `docsy.dev`'s installed `hugo-extended` (version + single-sourced via `config.hugo_version`) and is now the `make-site.sh` + default; verified locally for NPM + HUGO_MODULE. See [spike-notes][] Phase 3. +- **Make `hugo-extended` available to the smoke job** (done): added an + `install:all` root script (`npm run docsy.dev-install && npm install`) and + switched `smoke.yaml`'s "Setup workspace" step to `npm run install:all`, so + `docsy.dev`'s `hugo-extended` is installed where `run-hugo.mjs` looks. + (`docsy.dev-install` runs first so `test.yaml`'s + `install:all -- --omit=optional` lands the flag on the final root + `npm install`.) Chose `install:all` over a lean targeted install for + consistency + onboarding value. +- Update `.github/workflows/smoke.yaml` and `.github/workflows/test.yaml` for + the new paths (done). +- Push the branch and watch the Windows + Ubuntu matrix go green (done). + +Exit criterion: full CI matrix green on the spike branch (which also closes +Phase 2). **Decision gate to merge to `main`.** If everything above held, the +canonical move lands. + +Status (2026-05-25): **exit criterion met — CI matrix green ([#2640][]).** Both +`test` (build; ubuntu + windows) and `smoke` (new-site NPM + HUGO_MODULE; ubuntu + +- windows) pass, and the Netlify deploy preview is green. The merge gate is + satisfied. + +### Phase 4: `docsy-example` + +Coordinated work in the `docsy-example` repo that bumps the import path to the +TOF layout. Three parts, in order: + +- **(a) Local sibling-repo test (done):** build `docsy-example` against this + branch's `theme/` via the local sibling-folder setup, to catch breakage before + the canonical move lands. +- **(b) Merge the task branch to `main`** via a PR. The canonical move lands. +- **(c) Final `docsy-example` config + test against `main`:** bump the + `docsy-example` import path / `theme:` value to the released `google/docsy` + layout and confirm a clean build (and its own smoke checks) against `main`. + +Exit criterion: `docsy-example` builds against released Docsy from `main` with +only the documented one-line config edit, and passes its own smoke checks. + +Status (2026-05-25): (a) done; (b) pending PR; (c) pending (b). + +### Phase 5: docs and release notes + +The user-facing payload, derived from the spike notes. + +- Update get-started pages with the new theme path / import path. +- Update the changelog and release blog post; the migration section reads the + exact snippets out of `spike-notes.md`. +- Update `README.md` if it references the old install shape. + +Exit criterion: a reviewer who has not seen the design conversation can upgrade +to 0.16 by following only the release notes. + +## Local test harness + +**Seed (done):** `tests/smoke.test.mjs`, run via `npm run test:smoke`. It uses +Node's built-in test runner (node:test) — **no new deps** — to drive the three +install modes on the developer's own OS and assert each produces a real, +fully-styled site — a rendered home page that links the exact compiled +stylesheet (> 100 KB), plus a generated sitemap — not just a zero exit. It +covers what the CI smoke matrix runs (NPM, HUGO_MODULE) **plus** the non-module +clone, which CI does not exercise. Target repo/branch via `--repo` / `--branch` +(defaults: `google/docsy`, `main`; the `test:smoke` npm script also passes +`--branch main`). During TOF rollout on a task branch: +`npm run test:smoke -- --branch task/repo-reorg-2026-05`. Prereq: +`npm run install:all` (for `hugo-extended`). Deliberately kept out of +`test:tooling` / CI `ci:post` (slow, network-bound). + +**Later (not started):** + +- Upgrade the seed to a **Vitest** harness with all code in **TypeScript + executed directly under Node** (no separate compile step). The `node:test` + `describe`/`test` shape maps closely onto Vitest, so the seed is the migration + starting point, not throwaway. +- Possibly add a 4th smoke case for the `docsy.dev` **sibling-folder** shape + (`--themesDir ../..`) if/when it is surfaced as a documented power-user setup + — see [spike-notes][] Phase 1. It is already exercised by the `docsy.dev` + build, so this is optional coverage, not a gap. + +Both are follow-ons to TOF, not part of the move. + +## Out of scope (this plan) + +See the plan's [What this plan does not change][plan-defer] section for the +canonical list of deferred work. + +[plan-defer]: ./theme-only-folder.plan.md#tof-repo-layout + +## Tracking + +- Parent issue: [#2617][]. Keep a phase checklist there (or sub-issues, if the + team prefers) so progress is visible. +- Spike notes: `tasks/0.16/repo-reorg/spike-notes.md`, grown through Phases 1–3. +- The first spike branch (the Phase 0 structural move, + `chalin-m24-monorepo-2026-0520`) has merged. Phases 2–3 continue on a + follow-up branch atop it. Phases 4–5 land as separate PRs against `main`. + +[#2617]: https://github.com/google/docsy/issues/2617 +[#2640]: https://github.com/google/docsy/pull/2640 diff --git a/tasks/0.16/repo-reorg/theme-only-folder.plan.md b/tasks/0.16/repo-reorg/theme-only-folder.plan.md new file mode 100644 index 0000000000..26e17cfbd9 --- /dev/null +++ b/tasks/0.16/repo-reorg/theme-only-folder.plan.md @@ -0,0 +1,267 @@ +--- +title: Theme-Only Folder (TOF) plan for 0.16 +date: 2026-05-21 +status: draft +issue: https://github.com/google/docsy/issues/2617 +cSpell:ignore: postupdate +--- + +## About this plan + +Keep this document lean and readable for a junior developer. It describes the +intended end state, key boundaries, and acceptance criteria — not every command. +Add detail only when it prevents a likely mistake or clarifies a compatibility +decision. + +## Motivation + +The Docsy theme currently lives at the repo root, entangled with website +tooling, repo-wide tooling, and release tooling. The result is an install shape +that needs ongoing repair: + +- The root `hugo.yaml` carries `../..` escape mounts to reach the consumer's + `node_modules`, plus a vendored-Bootstrap-SCSS mount to work around a Go + modules bug. +- A `postinstall` script runs on every consumer install to create empty + Hugo-module directories outside the package. +- A scrollspy-patch toolchain must be applied during maintenance before the + theme is usable, with generated artifacts committed to keep consumers off the + toolchain. +- The root `package.json` mixes theme runtime dependencies with repo-wide + formatting, link-checking, and other tooling. + +Each of these exists because the canonical theme tree, the maintainer toolchain, +and the consumer-visible install shape are all the same tree. The fix is +structural: give the theme its own folder so the theme tree, the maintainer +toolchain, and the published shape can each evolve on their own timeline. + +Issue [#2617][] follows up [#2436][] and asks for the theme to live in its own +folder. + +[#2617]: https://github.com/google/docsy/issues/2617 +[#2436]: https://github.com/google/docsy/issues/2436 + +## Goal: theme-only folder (TOF) + +Move the canonical Docsy theme into a folder named `theme/`, whose contents are +**only** what a consuming site needs from Docsy. + +We expect this to be a structural change with one consumer-facing edit per +install mode. It trades a small documented migration for a clean, predictable +install shape. Mapping the four [Motivation](#motivation) workarounds to this +PR: + +| Workaround | This PR | +| ----------------------------------------- | ------------------- | +| `../../node_modules/*` escape mounts | **Fixed** | +| `postinstall` mkdirp helper | Kept; deferred | +| `_prepare` scrollspy + vendored SCSS | Kept; deferred | +| Root `package.json` mixes theme + tooling | Partially; deferred | + +"Partially" because `theme/package.json` now declares the theme runtime deps (as +a synced mirror), giving us a clean boundary to push the rest of the cleanup +through. The thin-shim refactor that fully separates the manifests is +[scoped out](#tof-repo-layout) and lives in a follow-on plan. + +## TOF repo layout + +```text +. +├── theme/ +│ ├── assets/ +│ ├── i18n/ +│ ├── images/ # theme images only +│ ├── layouts/ +│ ├── static/ +│ ├── hugo.yaml # canonical theme config (mounts, mediaTypes, outputFormats) +│ ├── theme.toml # canonical +│ ├── go.mod # module path: github.com/google/docsy/theme +│ ├── go.sum +│ └── package.json # private mirror of theme runtime deps (see below) +├── docsy.dev/ # website; its own node_modules for the site build +├── scripts/ # maintainer scripts (scrollspy patch, sync-theme-deps, …) +├── tasks/ +└── package.json # repo root: canonical for theme runtime deps + repo-wide tooling +``` + +Key properties: + +- `theme/` is what Hugo module resolves to. GitHub-NPM still ships the full repo + (see below). +- The repo root `package.json` is the **single source of truth** for theme + runtime dependency versions and continues to host repo-wide maintainer tooling + (Prettier, markdownlint, cSpell French dict). The `theme/` `package.json` is a + small **private mirror** so that file/tarball installs of `theme/` (notably + `docsy.dev`'s postinstall — see [Maintainer workflow](#maintainer-workflow)) + see the right versions. +- The mirror is kept in sync by `scripts/sync-theme-deps.mjs` (run by + `_prepare`, `postupdate:dep`, and `postupdate:packages`). Maintainers should + not edit `theme/package.json`'s `dependencies` by hand. +- Theme-only configuration moved to `theme/`: `hugo.yaml`, `theme.toml`, + `go.mod`/`go.sum`. The `theme/go.mod` module path becomes + `github.com/google/docsy/theme`. +- The mounts inside `theme/hugo.yaml` are spelled the canonical way: + `node_modules/`. Hugo's loader does a theme-local-first, then + consumer-cwd lookup, so the legacy `../../node_modules/*` escape form is no + longer needed and is removed. +- Generated artifacts (vendored Bootstrap SCSS, scrollspy patch output, chroma + styles, `go.sum`) continue to be committed under `theme/` so consumers never + run the generators. + +What this plan **does not** change (deferred to a follow-on plan): + +- The repo root keeps `devDependencies` for repo-wide maintainer tooling and + keeps `bootstrap` + `@fortawesome/fontawesome-free` as runtime deps. There is + no `files` whitelist yet and no thin-shim refactor. +- There is no dedicated `_dev/` (or similar) maintainer-orchestration folder + yet. Maintainers continue to work from the repo root. +- NPM-registry publication remains future work; the immediate consumer surface + is the existing GitHub-NPM install path. + +## User-facing migration + +TOF accepts one documented one-line config change per install mode in exchange +for a clean install shape. The exact migration text comes from the +[Compatibility spike](#compatibility-spike); the table below shows the shape of +the change. + +| Install mode | What the user edits | +| ---------------- | ----------------------------------------------------------------------- | +| Hugo module | Module import path gains a `/theme` suffix | +| NPM (GitHub) | Hugo `theme:` value gains a `/theme` suffix (or equivalent `themesDir`) | +| Non-module theme | Hugo `theme:` value gains a `/theme` suffix | + +The release-note migration section pairs each install mode with its exact +before/after snippet, derived from the spike. There should be exactly **one +line** to change per install mode. If any mode requires more, iterate on TOF +before merging. + +## Compatibility spike + +Before the move lands on `main`, validate TOF on a feature branch. The three +documented install modes below must each build a runnable site from the branch +with at most a one-line consumer config change. + +The values in the table are the working hypothesis to be confirmed by the spike. + +| # | Install mode | Consumer command (example) | Consumer config after TOF | Theme location Hugo reads | +| --- | ---------------- | -------------------------------------------------- | --------------------------------------------------------- | --------------------------- | +| 1 | Hugo module | `hugo mod get github.com/google/docsy/theme@` | `module.imports: [{path: github.com/google/docsy/theme}]` | Hugo module cache | +| 2 | NPM (GitHub) | `npm install github:google/docsy#` | `theme: docsy/theme`, `themesDir: node_modules` | `node_modules/docsy/theme/` | +| 3 | Non-module theme | `git clone` into `themes/docsy/` | `theme: docsy/theme` | `themes/docsy/theme/` | + +Validation harness, all run against the spike branch: + +- `docsy.dev` builds locally and in CI using the TOF Hugo module path. +- `docsy-example` builds against the branch with the one-line module update. +- `scripts/make-site.sh -s NPM` and `-s HUGO_MODULE` pass on Windows and Ubuntu + after the smoke script is updated for the new path. +- A minimal `hugo new site` with Docsy cloned into `themes/docsy/` builds with + the one-line `theme:` edit. + +For each mode, record in `tasks/0.16/repo-reorg/spike-notes.md`: the exact +commands used, the exact one-line config edit, and whether the result is +"one-line change" or "needs more design". Any "needs more design" result blocks +the merge until the design is iterated. + +For the order in which Phase 0 (move) and Phases 1–5 (consumer validation, +release) are run, see the [execution plan][exec]. + +[exec]: ./theme-only-folder.execution.md + +## Package boundary + +Each `package.json` carries a clearly-scoped set of dependencies. The three +manifests are: + +| File | Role | Notable contents | +| -------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| `package.json` (repo root) | Canonical theme deps + repo-wide maintainer tools | `bootstrap`, `@fortawesome/fontawesome-free`; `prettier`, `markdownlint-cli2`, markdownlint rule plugins, `@cspell/dict-fr-fr`; `postinstall` | +| `theme/package.json` | Private mirror of theme runtime deps | Same `dependencies` as root (kept in sync by `sync-theme-deps.mjs`); `"private": true` | +| `docsy.dev/package.json` | Website's site-build / site-tooling | `autoprefixer`, `postcss-cli`, `cross-env`, `rtlcss`, `afdocs`, `netlify-cli`, `npm-check-updates`, `hugo-extended`; `_install-theme-deps` hook | + +Keep docs-site, CI, release, formatting, link-checking, and test-only +dependencies out of `theme/package.json`. + +## Maintainer workflow + +The lead maintainer (and other contributors) coordinate theme and website +changes from the repo root. `docsy.dev` is Docsy's primary end-to-end test of +theme changes, so coordinated edits across both happen daily. + +Orchestration commands continue to run from the repo root: + +```sh +npm run install:all # repo root deps + docsy.dev (incl. hugo-extended) +npm run build # builds docsy.dev against theme/ +npm run serve # docsy.dev dev server with live reload +npm run check # repo-wide format + markdown checks +npm run fix # auto-fix +npm run test:smoke # local NPM / Hugo-module / non-module-clone smoke +``` + +`docsy.dev`'s `postinstall` runs `_install-theme-deps` (see +`docsy.dev/package.json`), which creates `theme/`'s declared runtime deps into +`docsy.dev/node_modules/` so Hugo's consumer-cwd lookup finds them during the +build. The mechanics (`--install-links` flag and the cleanup line) are recorded +in [spike-notes][]. + +[spike-notes]: ./spike-notes.md + +## Tooling versions + +Each shared tool has exactly one declaration in the repo: + +- `hugo-extended` lives in `docsy.dev/devDependencies`. The `hugo` binary lands + at `docsy.dev/node_modules/.bin/hugo` after `npm run docsy.dev-install` and is + invoked by `docsy.dev`'s `_hugo` scripts. Bumping the Hugo version is a single + edit (see `scripts/set-hugo-version.mjs`). +- `prettier`, `markdownlint-cli2`, the markdownlint rule plugins, and + `@cspell/dict-fr-fr` live in the **repo-root** `devDependencies` because they + are run from the repo root. +- Site-build tools (`autoprefixer`, `postcss-cli`, `cross-env`, `rtlcss`) and + site-tooling (`afdocs`, `netlify-cli`, `npm-check-updates`) live in + `docsy.dev/devDependencies` because that is where they are used. +- Theme runtime deps (`bootstrap`, `@fortawesome/fontawesome-free`) live in the + repo-root `dependencies` and are mirrored into `theme/package.json` by + `scripts/sync-theme-deps.mjs`. + +## Test boundary + +The new layout leaves room for a larger test suite — HTML goldens, screenshot +goldens, browser-based checks — without bloating the installed theme package. +Test fixtures, generated goldens, and test-only dependencies live in +`docsy.dev/` (current) or a repo-level `tests/` folder (future). Root commands +make the suite easy for maintainers to run; theme users never install the test +toolchain. + +## Acceptance criteria + +- The [Compatibility spike](#compatibility-spike) has been run for all three + install modes on a feature branch, and its results are recorded, before the + canonical move merges to `main`. +- `docsy.dev` builds from `theme/`. +- A new site can use Docsy as a Hugo module with the documented one-line config + change. +- A new site can use Docsy through the GitHub/NPM install path with the + documented one-line config change. +- Non-module theme usage works with the documented one-line config change. +- `theme/package.json` contains only theme runtime dependencies (mirrored from + root) and is marked `"private": true`. No other lifecycle scripts. +- All generated theme assets (vendored Bootstrap SCSS, scrollspy patch output, + chroma styles, `go.sum`) are committed under `theme/`. +- CI and smoke tests pass against the new layout on Windows and Ubuntu. +- Release notes include the exact before/after migration snippet for each + install mode. + +## Non-goals + +- Do not split the theme into core/extras or community packages in this change. + TOF makes that possible later but does not require it. +- Do not redesign theme behavior or visual styling. +- Do not upgrade Bootstrap or Font Awesome as part of this migration unless the + normal dependency update process calls for it. +- Do not ship a root-facade compatibility shim to preserve the current Hugo + module path. The cost of carrying a fragile facade outweighs the value of "no + config change" for one release. +- Do not change the Hugo theme name (`docsy`). diff --git a/tests/smoke.test.mjs b/tests/smoke.test.mjs new file mode 100644 index 0000000000..131ca877a5 --- /dev/null +++ b/tests/smoke.test.mjs @@ -0,0 +1,215 @@ +// Smoke tests: builds a Docsy-based site three ways and asserts each produces a +// real, fully-styled site (not merely a zero exit code). +// +// Uses Node's built-in test runner (node:test) — no extra test deps. +// +// Run: npm run test:smoke +// Assumes: npm run install:all (provides hugo-extended for run-hugo.mjs) +// Target: defaults to repo "google/docsy", branch "main"; override with +// flags, e.g. npm run test:smoke -- --repo my-fork/docsy --branch wip +// +// NOTE: slow and network-bound (npm + Hugo fetch from GitHub). Deliberately +// kept OUT of `test:tooling` / CI `ci:post`, which must stay fast and offline. + +import { test, before } from 'node:test'; +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { + appendFileSync, + existsSync, + mkdirSync, + readFileSync, + readdirSync, + rmSync, + statSync, + writeSync, +} from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; + +const repoRoot = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '..', +); +const TMP = path.join(repoRoot, 'tmp'); +const MAKE_SITE = path.join(repoRoot, 'scripts', 'make-site.sh'); +const RUN_HUGO = path.join(repoRoot, 'scripts', 'run-hugo.mjs'); + +// Read a `--name value` or `--name=value` CLI flag (after the `--` that npm +// forwards), falling back to a default. Last occurrence wins, so a flag passed +// on the command line overrides one baked into the `test:smoke` npm script. +function arg(name, fallback) { + let value = fallback; + for (let i = 2; i < process.argv.length; i++) { + const a = process.argv[i]; + if (a === `--${name}`) value = process.argv[i + 1] ?? value; + else if (a.startsWith(`--${name}=`)) value = a.slice(name.length + 3); + } + return value; +} + +const REPO = arg('repo', 'google/docsy'); +const BRANCH = arg('branch', 'main'); +const TARGET = `repo "${REPO}", branch "${BRANCH}"`; + +// Run a command; surface its output only on failure. +function run(cmd, args, opts = {}) { + const r = spawnSync(cmd, args, { encoding: 'utf8', ...opts }); + if (r.status !== 0) { + process.stderr.write( + `\n$ ${cmd} ${args.join(' ')}\n${r.stdout ?? ''}${r.stderr ?? ''}\n`, + ); + } + return r; +} + +function hugo(args, opts = {}) { + return run('node', [RUN_HUGO, ...args], opts); +} + +// Stream a progress line via fd 2 directly: node:test buffers a test's console +// output until the test finishes, which would otherwise hide progress mid-build. +function progress(msg) { + writeSync(2, `[smoke] ${msg}\n`); +} + +// Assert a real, fully-styled build (not just a zero exit): a non-trivial +// compiled stylesheet that the home page actually links, plus a sitemap. +function assertBuilt(name) { + const pub = path.join(TMP, name, 'public'); + + const scssDir = path.join(pub, 'scss'); + const mainCss = existsSync(scssDir) + ? readdirSync(scssDir).find((f) => /^main\.min.*\.css$/.test(f)) + : undefined; + assert.ok(mainCss, 'compiled main.min.*.css exists'); + assert.ok( + statSync(path.join(scssDir, mainCss)).size > 100_000, + 'compiled CSS is non-trivial (> 100 KB)', + ); + + const indexHtml = readFileSync(path.join(pub, 'index.html'), 'utf8'); + assert.match( + indexHtml, + /[^<]+<\/title>/, + 'index.html has a rendered <title>', + ); + assert.ok( + indexHtml.includes(mainCss), + 'index.html links the compiled stylesheet', + ); + + const sitemap = readFileSync(path.join(pub, 'sitemap.xml'), 'utf8'); + assert.match(sitemap, /<urlset/, 'sitemap.xml is a <urlset>'); + assert.match( + sitemap, + /<loc>https?:\/\/[^<]+<\/loc>/, + 'sitemap.xml lists a page URL', + ); +} + +before(() => { + if (!existsSync(TMP)) mkdirSync(TMP); + progress(`Target — ${TARGET} (override with --repo / --branch)`); + const v = hugo(['version']); + assert.match( + v.stdout ?? '', + /extended/, + 'extended Hugo not found — run `npm run install:all` first', + ); +}); + +// --- make-site.sh modes (mirror the CI smoke matrix) ----------------------- +for (const src of ['NPM', 'HUGO_MODULE']) { + test(`make-site.sh -s ${src}`, () => { + const name = `smoke-${src.toLowerCase()}`; + progress(`${src}: make-site (npm/Hugo fetch + build) — ${TARGET}…`); + const r = run( + 'bash', + [MAKE_SITE, '-s', src, '-r', REPO, '-v', BRANCH, '-f', '-n', name], + { cwd: TMP }, + ); + assert.equal(r.status, 0, `${src} site build exited 0`); + assertBuilt(name); + progress(`${src}: ok`); + }); +} + +// --- non-module clone into themes/docsy/ (no CI smoke coverage otherwise) --- +test('non-module clone into themes/docsy', () => { + const name = 'smoke-clone'; + const site = path.join(TMP, name); + rmSync(site, { recursive: true, force: true }); + + progress('clone: hugo new site…'); + assert.equal( + hugo(['new', 'site', '--format', 'yaml', '--quiet', site], { cwd: TMP }) + .status, + 0, + 'hugo new site', + ); + const themesDocsy = path.join(site, 'themes', 'docsy'); + progress(`clone: git clone ${TARGET} into themes/docsy…`); + assert.equal( + run('git', [ + 'clone', + '-b', + BRANCH, + '--depth', + '1', + `https://github.com/${REPO}`, + themesDocsy, + ]).status, + 0, + 'git clone theme into themes/docsy', + ); + + // Theme deps must sit at themes/docsy/theme/ — the theme-dir-relative + // node_modules the `node_modules/bootstrap` mount resolves against. + progress('clone: npm install theme deps (themes/docsy/theme)…'); + assert.equal( + run('npm', ['install', '--no-audit', '--no-fund'], { + cwd: path.join(themesDocsy, 'theme'), + }).status, + 0, + 'install theme deps in themes/docsy/theme', + ); + + // theme/package.json has no postinstall, so create the empty Hugo-module + // placeholder dirs explicitly, under themesDir (themes/). + progress('clone: generate empty Hugo-module placeholder dirs…'); + assert.equal( + run('node', [path.join('scripts', 'mkdirp-hugo-mod.js'), '..'], { + cwd: themesDocsy, + }).status, + 0, + 'create empty Hugo-module dirs under themes/', + ); + + // PostCSS at the site root: a non-module install prerequisite. + progress('clone: npm install postcss at site root…'); + assert.equal(run('npm', ['init', '-y'], { cwd: site }).status, 0, 'npm init'); + assert.equal( + run( + 'npm', + [ + 'install', + '--save-dev', + '--no-audit', + '--no-fund', + 'autoprefixer', + 'postcss-cli', + ], + { cwd: site }, + ).status, + 0, + 'install postcss at site root', + ); + + // The one-line consumer config change. + appendFileSync(path.join(site, 'hugo.yaml'), '\ntheme: docsy/theme\n'); + progress('clone: hugo build…'); + assert.equal(hugo([], { cwd: site }).status, 0, 'hugo build'); + assertBuilt(name); + progress('clone: ok'); +}); diff --git a/assets/_cache/README.md b/theme/assets/_cache/README.md similarity index 100% rename from assets/_cache/README.md rename to theme/assets/_cache/README.md diff --git a/assets/_cache/bootstrap/method.patch b/theme/assets/_cache/bootstrap/method.patch similarity index 100% rename from assets/_cache/bootstrap/method.patch rename to theme/assets/_cache/bootstrap/method.patch diff --git a/assets/_cache/bootstrap/scrollspy-method-patched.js b/theme/assets/_cache/bootstrap/scrollspy-method-patched.js similarity index 100% rename from assets/_cache/bootstrap/scrollspy-method-patched.js rename to theme/assets/_cache/bootstrap/scrollspy-method-patched.js diff --git a/assets/_cache/bootstrap/scrollspy-method.js b/theme/assets/_cache/bootstrap/scrollspy-method.js similarity index 100% rename from assets/_cache/bootstrap/scrollspy-method.js rename to theme/assets/_cache/bootstrap/scrollspy-method.js diff --git a/assets/_vendor/README.md b/theme/assets/_vendor/README.md similarity index 97% rename from assets/_vendor/README.md rename to theme/assets/_vendor/README.md index 0639d8d2bd..184f9cf427 100644 --- a/assets/_vendor/README.md +++ b/theme/assets/_vendor/README.md @@ -1,8 +1,8 @@ -This `_vendor` folder exists to work around a known bug in Go’s module -management. For details, see - -- <https://github.com/golang/go/issues/37397> -- <https://github.com/golang/go/issues/71785> - -DO NOT EDIT or manually override the files in this folder. They are -automatically synchronized at installation time. +This `_vendor` folder exists to work around a known bug in Go’s module +management. For details, see + +- <https://github.com/golang/go/issues/37397> +- <https://github.com/golang/go/issues/71785> + +DO NOT EDIT or manually override the files in this folder. They are +automatically synchronized at installation time. diff --git a/assets/_vendor/bootstrap/scss/_rfs.scss b/theme/assets/_vendor/bootstrap/scss/_rfs.scss similarity index 100% rename from assets/_vendor/bootstrap/scss/_rfs.scss rename to theme/assets/_vendor/bootstrap/scss/_rfs.scss diff --git a/assets/icons/logo.png b/theme/assets/icons/logo.png similarity index 100% rename from assets/icons/logo.png rename to theme/assets/icons/logo.png diff --git a/assets/icons/logo.svg b/theme/assets/icons/logo.svg similarity index 100% rename from assets/icons/logo.svg rename to theme/assets/icons/logo.svg diff --git a/assets/js/base.js b/theme/assets/js/base.js similarity index 100% rename from assets/js/base.js rename to theme/assets/js/base.js diff --git a/assets/js/click-to-copy.js b/theme/assets/js/click-to-copy.js similarity index 100% rename from assets/js/click-to-copy.js rename to theme/assets/js/click-to-copy.js diff --git a/assets/js/dark-mode.js b/theme/assets/js/dark-mode.js similarity index 100% rename from assets/js/dark-mode.js rename to theme/assets/js/dark-mode.js diff --git a/assets/js/drawio.js b/theme/assets/js/drawio.js similarity index 100% rename from assets/js/drawio.js rename to theme/assets/js/drawio.js diff --git a/assets/js/markmap.js b/theme/assets/js/markmap.js similarity index 100% rename from assets/js/markmap.js rename to theme/assets/js/markmap.js diff --git a/assets/js/offline-search.js b/theme/assets/js/offline-search.js similarity index 100% rename from assets/js/offline-search.js rename to theme/assets/js/offline-search.js diff --git a/assets/js/plantuml.js b/theme/assets/js/plantuml.js similarity index 100% rename from assets/js/plantuml.js rename to theme/assets/js/plantuml.js diff --git a/assets/js/scrollspy-patch.js b/theme/assets/js/scrollspy-patch.js similarity index 100% rename from assets/js/scrollspy-patch.js rename to theme/assets/js/scrollspy-patch.js diff --git a/assets/js/search.js b/theme/assets/js/search.js similarity index 100% rename from assets/js/search.js rename to theme/assets/js/search.js diff --git a/assets/json/offline-search-index.json b/theme/assets/json/offline-search-index.json similarity index 100% rename from assets/json/offline-search-index.json rename to theme/assets/json/offline-search-index.json diff --git a/assets/scss/_styles_project.scss b/theme/assets/scss/_styles_project.scss similarity index 100% rename from assets/scss/_styles_project.scss rename to theme/assets/scss/_styles_project.scss diff --git a/assets/scss/_variables_project.scss b/theme/assets/scss/_variables_project.scss similarity index 100% rename from assets/scss/_variables_project.scss rename to theme/assets/scss/_variables_project.scss diff --git a/assets/scss/_variables_project_after_bs.scss b/theme/assets/scss/_variables_project_after_bs.scss similarity index 100% rename from assets/scss/_variables_project_after_bs.scss rename to theme/assets/scss/_variables_project_after_bs.scss diff --git a/assets/scss/main.scss b/theme/assets/scss/main.scss similarity index 100% rename from assets/scss/main.scss rename to theme/assets/scss/main.scss diff --git a/assets/scss/td/_alerts.scss b/theme/assets/scss/td/_alerts.scss similarity index 100% rename from assets/scss/td/_alerts.scss rename to theme/assets/scss/td/_alerts.scss diff --git a/assets/scss/td/_blog.scss b/theme/assets/scss/td/_blog.scss similarity index 100% rename from assets/scss/td/_blog.scss rename to theme/assets/scss/td/_blog.scss diff --git a/assets/scss/td/_boxes.scss b/theme/assets/scss/td/_boxes.scss similarity index 100% rename from assets/scss/td/_boxes.scss rename to theme/assets/scss/td/_boxes.scss diff --git a/assets/scss/td/_breadcrumb.scss b/theme/assets/scss/td/_breadcrumb.scss similarity index 100% rename from assets/scss/td/_breadcrumb.scss rename to theme/assets/scss/td/_breadcrumb.scss diff --git a/assets/scss/td/_code-dark.scss b/theme/assets/scss/td/_code-dark.scss similarity index 100% rename from assets/scss/td/_code-dark.scss rename to theme/assets/scss/td/_code-dark.scss diff --git a/assets/scss/td/_code.scss b/theme/assets/scss/td/_code.scss similarity index 100% rename from assets/scss/td/_code.scss rename to theme/assets/scss/td/_code.scss diff --git a/assets/scss/td/_color-adjustments-dark.scss b/theme/assets/scss/td/_color-adjustments-dark.scss similarity index 100% rename from assets/scss/td/_color-adjustments-dark.scss rename to theme/assets/scss/td/_color-adjustments-dark.scss diff --git a/assets/scss/td/_colors.scss b/theme/assets/scss/td/_colors.scss similarity index 100% rename from assets/scss/td/_colors.scss rename to theme/assets/scss/td/_colors.scss diff --git a/assets/scss/td/_content.scss b/theme/assets/scss/td/_content.scss similarity index 100% rename from assets/scss/td/_content.scss rename to theme/assets/scss/td/_content.scss diff --git a/assets/scss/td/_drawio.scss b/theme/assets/scss/td/_drawio.scss similarity index 100% rename from assets/scss/td/_drawio.scss rename to theme/assets/scss/td/_drawio.scss diff --git a/assets/scss/td/_footer.scss b/theme/assets/scss/td/_footer.scss similarity index 100% rename from assets/scss/td/_footer.scss rename to theme/assets/scss/td/_footer.scss diff --git a/assets/scss/td/_gcs-search-dark.scss b/theme/assets/scss/td/_gcs-search-dark.scss similarity index 100% rename from assets/scss/td/_gcs-search-dark.scss rename to theme/assets/scss/td/_gcs-search-dark.scss diff --git a/assets/scss/td/_main-container.scss b/theme/assets/scss/td/_main-container.scss similarity index 100% rename from assets/scss/td/_main-container.scss rename to theme/assets/scss/td/_main-container.scss diff --git a/assets/scss/td/_main.scss b/theme/assets/scss/td/_main.scss similarity index 100% rename from assets/scss/td/_main.scss rename to theme/assets/scss/td/_main.scss diff --git a/assets/scss/td/_nav.scss b/theme/assets/scss/td/_nav.scss similarity index 100% rename from assets/scss/td/_nav.scss rename to theme/assets/scss/td/_nav.scss diff --git a/assets/scss/td/_navbar-mobile-scroll.scss b/theme/assets/scss/td/_navbar-mobile-scroll.scss similarity index 100% rename from assets/scss/td/_navbar-mobile-scroll.scss rename to theme/assets/scss/td/_navbar-mobile-scroll.scss diff --git a/assets/scss/td/_pageinfo.scss b/theme/assets/scss/td/_pageinfo.scss similarity index 100% rename from assets/scss/td/_pageinfo.scss rename to theme/assets/scss/td/_pageinfo.scss diff --git a/assets/scss/td/_scroll.scss b/theme/assets/scss/td/_scroll.scss similarity index 100% rename from assets/scss/td/_scroll.scss rename to theme/assets/scss/td/_scroll.scss diff --git a/assets/scss/td/_search.scss b/theme/assets/scss/td/_search.scss similarity index 100% rename from assets/scss/td/_search.scss rename to theme/assets/scss/td/_search.scss diff --git a/assets/scss/td/_section-index.scss b/theme/assets/scss/td/_section-index.scss similarity index 100% rename from assets/scss/td/_section-index.scss rename to theme/assets/scss/td/_section-index.scss diff --git a/assets/scss/td/_shortcodes.scss b/theme/assets/scss/td/_shortcodes.scss similarity index 100% rename from assets/scss/td/_shortcodes.scss rename to theme/assets/scss/td/_shortcodes.scss diff --git a/assets/scss/td/_sidebar-toc.scss b/theme/assets/scss/td/_sidebar-toc.scss similarity index 100% rename from assets/scss/td/_sidebar-toc.scss rename to theme/assets/scss/td/_sidebar-toc.scss diff --git a/assets/scss/td/_sidebar-tree.scss b/theme/assets/scss/td/_sidebar-tree.scss similarity index 100% rename from assets/scss/td/_sidebar-tree.scss rename to theme/assets/scss/td/_sidebar-tree.scss diff --git a/assets/scss/td/_swagger.scss b/theme/assets/scss/td/_swagger.scss similarity index 100% rename from assets/scss/td/_swagger.scss rename to theme/assets/scss/td/_swagger.scss diff --git a/assets/scss/td/_table.scss b/theme/assets/scss/td/_table.scss similarity index 100% rename from assets/scss/td/_table.scss rename to theme/assets/scss/td/_table.scss diff --git a/assets/scss/td/_taxonomy.scss b/theme/assets/scss/td/_taxonomy.scss similarity index 100% rename from assets/scss/td/_taxonomy.scss rename to theme/assets/scss/td/_taxonomy.scss diff --git a/assets/scss/td/_variables.scss b/theme/assets/scss/td/_variables.scss similarity index 100% rename from assets/scss/td/_variables.scss rename to theme/assets/scss/td/_variables.scss diff --git a/assets/scss/td/_variables_forward.scss b/theme/assets/scss/td/_variables_forward.scss similarity index 100% rename from assets/scss/td/_variables_forward.scss rename to theme/assets/scss/td/_variables_forward.scss diff --git a/assets/scss/td/blocks/_blocks.scss b/theme/assets/scss/td/blocks/_blocks.scss similarity index 100% rename from assets/scss/td/blocks/_blocks.scss rename to theme/assets/scss/td/blocks/_blocks.scss diff --git a/assets/scss/td/blocks/_cover.scss b/theme/assets/scss/td/blocks/_cover.scss similarity index 100% rename from assets/scss/td/blocks/_cover.scss rename to theme/assets/scss/td/blocks/_cover.scss diff --git a/assets/scss/td/chroma/_dark.scss b/theme/assets/scss/td/chroma/_dark.scss similarity index 100% rename from assets/scss/td/chroma/_dark.scss rename to theme/assets/scss/td/chroma/_dark.scss diff --git a/assets/scss/td/chroma/_light.scss b/theme/assets/scss/td/chroma/_light.scss similarity index 100% rename from assets/scss/td/chroma/_light.scss rename to theme/assets/scss/td/chroma/_light.scss diff --git a/assets/scss/td/extra/_bs-defaults.scss b/theme/assets/scss/td/extra/_bs-defaults.scss similarity index 100% rename from assets/scss/td/extra/_bs-defaults.scss rename to theme/assets/scss/td/extra/_bs-defaults.scss diff --git a/assets/scss/td/extra/_buttons.scss b/theme/assets/scss/td/extra/_buttons.scss similarity index 100% rename from assets/scss/td/extra/_buttons.scss rename to theme/assets/scss/td/extra/_buttons.scss diff --git a/assets/scss/td/extra/_index.scss b/theme/assets/scss/td/extra/_index.scss similarity index 100% rename from assets/scss/td/extra/_index.scss rename to theme/assets/scss/td/extra/_index.scss diff --git a/assets/scss/td/extra/_main-container.scss b/theme/assets/scss/td/extra/_main-container.scss similarity index 100% rename from assets/scss/td/extra/_main-container.scss rename to theme/assets/scss/td/extra/_main-container.scss diff --git a/assets/scss/td/extra/_navbar.scss b/theme/assets/scss/td/extra/_navbar.scss similarity index 100% rename from assets/scss/td/extra/_navbar.scss rename to theme/assets/scss/td/extra/_navbar.scss diff --git a/assets/scss/td/shortcodes/cards-pane.scss b/theme/assets/scss/td/shortcodes/cards-pane.scss similarity index 100% rename from assets/scss/td/shortcodes/cards-pane.scss rename to theme/assets/scss/td/shortcodes/cards-pane.scss diff --git a/assets/scss/td/shortcodes/tabbed-pane.scss b/theme/assets/scss/td/shortcodes/tabbed-pane.scss similarity index 100% rename from assets/scss/td/shortcodes/tabbed-pane.scss rename to theme/assets/scss/td/shortcodes/tabbed-pane.scss diff --git a/assets/scss/td/support/_bootstrap_vers_test.scss b/theme/assets/scss/td/support/_bootstrap_vers_test.scss similarity index 100% rename from assets/scss/td/support/_bootstrap_vers_test.scss rename to theme/assets/scss/td/support/_bootstrap_vers_test.scss diff --git a/assets/scss/td/support/_mixins.scss b/theme/assets/scss/td/support/_mixins.scss similarity index 100% rename from assets/scss/td/support/_mixins.scss rename to theme/assets/scss/td/support/_mixins.scss diff --git a/assets/scss/td/support/_rtl.scss b/theme/assets/scss/td/support/_rtl.scss similarity index 100% rename from assets/scss/td/support/_rtl.scss rename to theme/assets/scss/td/support/_rtl.scss diff --git a/assets/scss/td/support/_utilities.scss b/theme/assets/scss/td/support/_utilities.scss similarity index 100% rename from assets/scss/td/support/_utilities.scss rename to theme/assets/scss/td/support/_utilities.scss diff --git a/assets/stubs/new-page-template.md b/theme/assets/stubs/new-page-template.md similarity index 100% rename from assets/stubs/new-page-template.md rename to theme/assets/stubs/new-page-template.md diff --git a/go.mod b/theme/go.mod similarity index 85% rename from go.mod rename to theme/go.mod index 13b0459726..c17a1c4a9c 100644 --- a/go.mod +++ b/theme/go.mod @@ -1,4 +1,4 @@ -module github.com/google/docsy +module github.com/google/docsy/theme go 1.12 diff --git a/go.sum b/theme/go.sum similarity index 100% rename from go.sum rename to theme/go.sum diff --git a/hugo.yaml b/theme/hugo.yaml similarity index 76% rename from hugo.yaml rename to theme/hugo.yaml index 423e9bf7e7..905f92dfb4 100644 --- a/hugo.yaml +++ b/theme/hugo.yaml @@ -49,16 +49,6 @@ module: target: static - source: node_modules/@fortawesome/fontawesome-free/webfonts target: static/webfonts - # Mounts for projects using Docsy as an NPM package. The source path prefix - # "../.." moves out of themes/docsy so that Docsy can find its dependencies. - - source: ../../node_modules/bootstrap - target: assets/vendor/bootstrap - - source: ../../node_modules/@fortawesome/fontawesome-free - target: assets/vendor/Font-Awesome - - source: ../../node_modules/@fortawesome/fontawesome-free/webfonts - target: static/webfonts - # Mounts for module installations, - # needed to work around a known bug in Go’s module management. - source: assets/_vendor/bootstrap/scss target: assets/vendor/bootstrap/scss/vendor imports: diff --git a/i18n/ar.yaml b/theme/i18n/ar.yaml similarity index 100% rename from i18n/ar.yaml rename to theme/i18n/ar.yaml diff --git a/i18n/az.yaml b/theme/i18n/az.yaml similarity index 100% rename from i18n/az.yaml rename to theme/i18n/az.yaml diff --git a/i18n/bg.yaml b/theme/i18n/bg.yaml similarity index 100% rename from i18n/bg.yaml rename to theme/i18n/bg.yaml diff --git a/i18n/bn.yaml b/theme/i18n/bn.yaml similarity index 100% rename from i18n/bn.yaml rename to theme/i18n/bn.yaml diff --git a/i18n/de.yaml b/theme/i18n/de.yaml similarity index 100% rename from i18n/de.yaml rename to theme/i18n/de.yaml diff --git a/i18n/en.yaml b/theme/i18n/en.yaml similarity index 100% rename from i18n/en.yaml rename to theme/i18n/en.yaml diff --git a/i18n/es.yaml b/theme/i18n/es.yaml similarity index 100% rename from i18n/es.yaml rename to theme/i18n/es.yaml diff --git a/i18n/et.yaml b/theme/i18n/et.yaml similarity index 100% rename from i18n/et.yaml rename to theme/i18n/et.yaml diff --git a/i18n/fa.yaml b/theme/i18n/fa.yaml similarity index 100% rename from i18n/fa.yaml rename to theme/i18n/fa.yaml diff --git a/i18n/fi.yaml b/theme/i18n/fi.yaml similarity index 100% rename from i18n/fi.yaml rename to theme/i18n/fi.yaml diff --git a/i18n/fr.yaml b/theme/i18n/fr.yaml similarity index 100% rename from i18n/fr.yaml rename to theme/i18n/fr.yaml diff --git a/i18n/he.yaml b/theme/i18n/he.yaml similarity index 100% rename from i18n/he.yaml rename to theme/i18n/he.yaml diff --git a/i18n/hi.yaml b/theme/i18n/hi.yaml similarity index 100% rename from i18n/hi.yaml rename to theme/i18n/hi.yaml diff --git a/i18n/hu.yaml b/theme/i18n/hu.yaml similarity index 100% rename from i18n/hu.yaml rename to theme/i18n/hu.yaml diff --git a/i18n/it.yaml b/theme/i18n/it.yaml similarity index 100% rename from i18n/it.yaml rename to theme/i18n/it.yaml diff --git a/i18n/ja.yaml b/theme/i18n/ja.yaml similarity index 100% rename from i18n/ja.yaml rename to theme/i18n/ja.yaml diff --git a/i18n/ko.yaml b/theme/i18n/ko.yaml similarity index 100% rename from i18n/ko.yaml rename to theme/i18n/ko.yaml diff --git a/i18n/nl.yaml b/theme/i18n/nl.yaml similarity index 100% rename from i18n/nl.yaml rename to theme/i18n/nl.yaml diff --git a/i18n/no.yaml b/theme/i18n/no.yaml similarity index 100% rename from i18n/no.yaml rename to theme/i18n/no.yaml diff --git a/i18n/oc.yaml b/theme/i18n/oc.yaml similarity index 100% rename from i18n/oc.yaml rename to theme/i18n/oc.yaml diff --git a/i18n/pl.yaml b/theme/i18n/pl.yaml similarity index 100% rename from i18n/pl.yaml rename to theme/i18n/pl.yaml diff --git a/i18n/pt-br.yaml b/theme/i18n/pt-br.yaml similarity index 100% rename from i18n/pt-br.yaml rename to theme/i18n/pt-br.yaml diff --git a/i18n/ro.yaml b/theme/i18n/ro.yaml similarity index 100% rename from i18n/ro.yaml rename to theme/i18n/ro.yaml diff --git a/i18n/ru.yaml b/theme/i18n/ru.yaml similarity index 100% rename from i18n/ru.yaml rename to theme/i18n/ru.yaml diff --git a/i18n/sr-cyrl.yaml b/theme/i18n/sr-cyrl.yaml similarity index 100% rename from i18n/sr-cyrl.yaml rename to theme/i18n/sr-cyrl.yaml diff --git a/i18n/sr-latn.yaml b/theme/i18n/sr-latn.yaml similarity index 100% rename from i18n/sr-latn.yaml rename to theme/i18n/sr-latn.yaml diff --git a/i18n/sv.yaml b/theme/i18n/sv.yaml similarity index 100% rename from i18n/sv.yaml rename to theme/i18n/sv.yaml diff --git a/i18n/tr.yaml b/theme/i18n/tr.yaml similarity index 100% rename from i18n/tr.yaml rename to theme/i18n/tr.yaml diff --git a/i18n/uk.yaml b/theme/i18n/uk.yaml similarity index 100% rename from i18n/uk.yaml rename to theme/i18n/uk.yaml diff --git a/i18n/zh-cn.yaml b/theme/i18n/zh-cn.yaml similarity index 100% rename from i18n/zh-cn.yaml rename to theme/i18n/zh-cn.yaml diff --git a/i18n/zh-tw.yaml b/theme/i18n/zh-tw.yaml similarity index 100% rename from i18n/zh-tw.yaml rename to theme/i18n/zh-tw.yaml diff --git a/images/screenshot.png b/theme/images/screenshot.png similarity index 100% rename from images/screenshot.png rename to theme/images/screenshot.png diff --git a/images/tn.png b/theme/images/tn.png similarity index 100% rename from images/tn.png rename to theme/images/tn.png diff --git a/layouts/404.html b/theme/layouts/404.html similarity index 100% rename from layouts/404.html rename to theme/layouts/404.html diff --git a/layouts/_markup/render-blockquote-alert.html b/theme/layouts/_markup/render-blockquote-alert.html similarity index 100% rename from layouts/_markup/render-blockquote-alert.html rename to theme/layouts/_markup/render-blockquote-alert.html diff --git a/layouts/_markup/render-codeblock-chem.html b/theme/layouts/_markup/render-codeblock-chem.html similarity index 100% rename from layouts/_markup/render-codeblock-chem.html rename to theme/layouts/_markup/render-codeblock-chem.html diff --git a/layouts/_markup/render-codeblock-math.html b/theme/layouts/_markup/render-codeblock-math.html similarity index 100% rename from layouts/_markup/render-codeblock-math.html rename to theme/layouts/_markup/render-codeblock-math.html diff --git a/layouts/_markup/render-codeblock-mermaid.html b/theme/layouts/_markup/render-codeblock-mermaid.html similarity index 100% rename from layouts/_markup/render-codeblock-mermaid.html rename to theme/layouts/_markup/render-codeblock-mermaid.html diff --git a/layouts/_partials/breadcrumb.html b/theme/layouts/_partials/breadcrumb.html similarity index 100% rename from layouts/_partials/breadcrumb.html rename to theme/layouts/_partials/breadcrumb.html diff --git a/layouts/_partials/community_links.html b/theme/layouts/_partials/community_links.html similarity index 100% rename from layouts/_partials/community_links.html rename to theme/layouts/_partials/community_links.html diff --git a/layouts/_partials/dark-mode-config.html b/theme/layouts/_partials/dark-mode-config.html similarity index 100% rename from layouts/_partials/dark-mode-config.html rename to theme/layouts/_partials/dark-mode-config.html diff --git a/layouts/_partials/disqus-comment.html b/theme/layouts/_partials/disqus-comment.html similarity index 100% rename from layouts/_partials/disqus-comment.html rename to theme/layouts/_partials/disqus-comment.html diff --git a/layouts/_partials/favicons.html b/theme/layouts/_partials/favicons.html similarity index 100% rename from layouts/_partials/favicons.html rename to theme/layouts/_partials/favicons.html diff --git a/layouts/_partials/featured-image.html b/theme/layouts/_partials/featured-image.html similarity index 100% rename from layouts/_partials/featured-image.html rename to theme/layouts/_partials/featured-image.html diff --git a/layouts/_partials/feedback.html b/theme/layouts/_partials/feedback.html similarity index 100% rename from layouts/_partials/feedback.html rename to theme/layouts/_partials/feedback.html diff --git a/layouts/_partials/footer.html b/theme/layouts/_partials/footer.html similarity index 100% rename from layouts/_partials/footer.html rename to theme/layouts/_partials/footer.html diff --git a/layouts/_partials/footer/center.html b/theme/layouts/_partials/footer/center.html similarity index 100% rename from layouts/_partials/footer/center.html rename to theme/layouts/_partials/footer/center.html diff --git a/layouts/_partials/footer/copyright.html b/theme/layouts/_partials/footer/copyright.html similarity index 100% rename from layouts/_partials/footer/copyright.html rename to theme/layouts/_partials/footer/copyright.html diff --git a/layouts/_partials/footer/left.html b/theme/layouts/_partials/footer/left.html similarity index 100% rename from layouts/_partials/footer/left.html rename to theme/layouts/_partials/footer/left.html diff --git a/layouts/_partials/footer/links.html b/theme/layouts/_partials/footer/links.html similarity index 100% rename from layouts/_partials/footer/links.html rename to theme/layouts/_partials/footer/links.html diff --git a/layouts/_partials/footer/right.html b/theme/layouts/_partials/footer/right.html similarity index 100% rename from layouts/_partials/footer/right.html rename to theme/layouts/_partials/footer/right.html diff --git a/layouts/_partials/head-css.html b/theme/layouts/_partials/head-css.html similarity index 100% rename from layouts/_partials/head-css.html rename to theme/layouts/_partials/head-css.html diff --git a/layouts/_partials/head.html b/theme/layouts/_partials/head.html similarity index 100% rename from layouts/_partials/head.html rename to theme/layouts/_partials/head.html diff --git a/layouts/_partials/hooks/body-end.html b/theme/layouts/_partials/hooks/body-end.html similarity index 100% rename from layouts/_partials/hooks/body-end.html rename to theme/layouts/_partials/hooks/body-end.html diff --git a/layouts/_partials/hooks/head-end.html b/theme/layouts/_partials/hooks/head-end.html similarity index 100% rename from layouts/_partials/hooks/head-end.html rename to theme/layouts/_partials/hooks/head-end.html diff --git a/layouts/_partials/navbar-lang-selector.html b/theme/layouts/_partials/navbar-lang-selector.html similarity index 100% rename from layouts/_partials/navbar-lang-selector.html rename to theme/layouts/_partials/navbar-lang-selector.html diff --git a/layouts/_partials/navbar-version-selector.html b/theme/layouts/_partials/navbar-version-selector.html similarity index 100% rename from layouts/_partials/navbar-version-selector.html rename to theme/layouts/_partials/navbar-version-selector.html diff --git a/layouts/_partials/navbar.html b/theme/layouts/_partials/navbar.html similarity index 100% rename from layouts/_partials/navbar.html rename to theme/layouts/_partials/navbar.html diff --git a/layouts/_partials/outputformat.html b/theme/layouts/_partials/outputformat.html similarity index 100% rename from layouts/_partials/outputformat.html rename to theme/layouts/_partials/outputformat.html diff --git a/layouts/_partials/page-description.html b/theme/layouts/_partials/page-description.html similarity index 100% rename from layouts/_partials/page-description.html rename to theme/layouts/_partials/page-description.html diff --git a/layouts/_partials/page-meta-lastmod.html b/theme/layouts/_partials/page-meta-lastmod.html similarity index 100% rename from layouts/_partials/page-meta-lastmod.html rename to theme/layouts/_partials/page-meta-lastmod.html diff --git a/layouts/_partials/page-meta-links.html b/theme/layouts/_partials/page-meta-links.html similarity index 100% rename from layouts/_partials/page-meta-links.html rename to theme/layouts/_partials/page-meta-links.html diff --git a/layouts/_partials/pager.html b/theme/layouts/_partials/pager.html similarity index 100% rename from layouts/_partials/pager.html rename to theme/layouts/_partials/pager.html diff --git a/layouts/_partials/print/content-blog.html b/theme/layouts/_partials/print/content-blog.html similarity index 100% rename from layouts/_partials/print/content-blog.html rename to theme/layouts/_partials/print/content-blog.html diff --git a/layouts/_partials/print/content.html b/theme/layouts/_partials/print/content.html similarity index 100% rename from layouts/_partials/print/content.html rename to theme/layouts/_partials/print/content.html diff --git a/layouts/_partials/print/page-heading.html b/theme/layouts/_partials/print/page-heading.html similarity index 100% rename from layouts/_partials/print/page-heading.html rename to theme/layouts/_partials/print/page-heading.html diff --git a/layouts/_partials/print/render.html b/theme/layouts/_partials/print/render.html similarity index 100% rename from layouts/_partials/print/render.html rename to theme/layouts/_partials/print/render.html diff --git a/layouts/_partials/print/toc-li-blog.html b/theme/layouts/_partials/print/toc-li-blog.html similarity index 100% rename from layouts/_partials/print/toc-li-blog.html rename to theme/layouts/_partials/print/toc-li-blog.html diff --git a/layouts/_partials/print/toc-li.html b/theme/layouts/_partials/print/toc-li.html similarity index 100% rename from layouts/_partials/print/toc-li.html rename to theme/layouts/_partials/print/toc-li.html diff --git a/layouts/_partials/reading-time.html b/theme/layouts/_partials/reading-time.html similarity index 100% rename from layouts/_partials/reading-time.html rename to theme/layouts/_partials/reading-time.html diff --git a/layouts/_partials/scripts.html b/theme/layouts/_partials/scripts.html similarity index 100% rename from layouts/_partials/scripts.html rename to theme/layouts/_partials/scripts.html diff --git a/layouts/_partials/scripts/katex.html b/theme/layouts/_partials/scripts/katex.html similarity index 100% rename from layouts/_partials/scripts/katex.html rename to theme/layouts/_partials/scripts/katex.html diff --git a/layouts/_partials/scripts/math.html b/theme/layouts/_partials/scripts/math.html similarity index 100% rename from layouts/_partials/scripts/math.html rename to theme/layouts/_partials/scripts/math.html diff --git a/layouts/_partials/scripts/mermaid.html b/theme/layouts/_partials/scripts/mermaid.html similarity index 100% rename from layouts/_partials/scripts/mermaid.html rename to theme/layouts/_partials/scripts/mermaid.html diff --git a/layouts/_partials/search-input.html b/theme/layouts/_partials/search-input.html similarity index 100% rename from layouts/_partials/search-input.html rename to theme/layouts/_partials/search-input.html diff --git a/layouts/_partials/section-index.html b/theme/layouts/_partials/section-index.html similarity index 100% rename from layouts/_partials/section-index.html rename to theme/layouts/_partials/section-index.html diff --git a/layouts/_partials/sidebar-tree.html b/theme/layouts/_partials/sidebar-tree.html similarity index 100% rename from layouts/_partials/sidebar-tree.html rename to theme/layouts/_partials/sidebar-tree.html diff --git a/layouts/_partials/sidebar.html b/theme/layouts/_partials/sidebar.html similarity index 100% rename from layouts/_partials/sidebar.html rename to theme/layouts/_partials/sidebar.html diff --git a/layouts/_partials/taxonomy_terms_article.html b/theme/layouts/_partials/taxonomy_terms_article.html similarity index 100% rename from layouts/_partials/taxonomy_terms_article.html rename to theme/layouts/_partials/taxonomy_terms_article.html diff --git a/layouts/_partials/taxonomy_terms_article_wrapper.html b/theme/layouts/_partials/taxonomy_terms_article_wrapper.html similarity index 100% rename from layouts/_partials/taxonomy_terms_article_wrapper.html rename to theme/layouts/_partials/taxonomy_terms_article_wrapper.html diff --git a/layouts/_partials/taxonomy_terms_cloud.html b/theme/layouts/_partials/taxonomy_terms_cloud.html similarity index 100% rename from layouts/_partials/taxonomy_terms_cloud.html rename to theme/layouts/_partials/taxonomy_terms_cloud.html diff --git a/layouts/_partials/taxonomy_terms_clouds.html b/theme/layouts/_partials/taxonomy_terms_clouds.html similarity index 100% rename from layouts/_partials/taxonomy_terms_clouds.html rename to theme/layouts/_partials/taxonomy_terms_clouds.html diff --git a/layouts/_partials/td/render-heading.html b/theme/layouts/_partials/td/render-heading.html similarity index 100% rename from layouts/_partials/td/render-heading.html rename to theme/layouts/_partials/td/render-heading.html diff --git a/layouts/_partials/td/scrollspy-attr.txt b/theme/layouts/_partials/td/scrollspy-attr.txt similarity index 100% rename from layouts/_partials/td/scrollspy-attr.txt rename to theme/layouts/_partials/td/scrollspy-attr.txt diff --git a/layouts/_partials/theme-toggler.html b/theme/layouts/_partials/theme-toggler.html similarity index 100% rename from layouts/_partials/theme-toggler.html rename to theme/layouts/_partials/theme-toggler.html diff --git a/layouts/_partials/toc.html b/theme/layouts/_partials/toc.html similarity index 100% rename from layouts/_partials/toc.html rename to theme/layouts/_partials/toc.html diff --git a/layouts/_partials/version-banner.html b/theme/layouts/_partials/version-banner.html similarity index 100% rename from layouts/_partials/version-banner.html rename to theme/layouts/_partials/version-banner.html diff --git a/layouts/_shortcodes/_param.html b/theme/layouts/_shortcodes/_param.html similarity index 100% rename from layouts/_shortcodes/_param.html rename to theme/layouts/_shortcodes/_param.html diff --git a/layouts/_shortcodes/alert.html b/theme/layouts/_shortcodes/alert.html similarity index 100% rename from layouts/_shortcodes/alert.html rename to theme/layouts/_shortcodes/alert.html diff --git a/layouts/_shortcodes/blocks/cover.html b/theme/layouts/_shortcodes/blocks/cover.html similarity index 100% rename from layouts/_shortcodes/blocks/cover.html rename to theme/layouts/_shortcodes/blocks/cover.html diff --git a/layouts/_shortcodes/blocks/feature.html b/theme/layouts/_shortcodes/blocks/feature.html similarity index 100% rename from layouts/_shortcodes/blocks/feature.html rename to theme/layouts/_shortcodes/blocks/feature.html diff --git a/layouts/_shortcodes/blocks/lead.html b/theme/layouts/_shortcodes/blocks/lead.html similarity index 100% rename from layouts/_shortcodes/blocks/lead.html rename to theme/layouts/_shortcodes/blocks/lead.html diff --git a/layouts/_shortcodes/blocks/link-down.html b/theme/layouts/_shortcodes/blocks/link-down.html similarity index 100% rename from layouts/_shortcodes/blocks/link-down.html rename to theme/layouts/_shortcodes/blocks/link-down.html diff --git a/layouts/_shortcodes/blocks/section.html b/theme/layouts/_shortcodes/blocks/section.html similarity index 100% rename from layouts/_shortcodes/blocks/section.html rename to theme/layouts/_shortcodes/blocks/section.html diff --git a/layouts/_shortcodes/card.html b/theme/layouts/_shortcodes/card.html similarity index 100% rename from layouts/_shortcodes/card.html rename to theme/layouts/_shortcodes/card.html diff --git a/layouts/_shortcodes/cardpane.html b/theme/layouts/_shortcodes/cardpane.html similarity index 100% rename from layouts/_shortcodes/cardpane.html rename to theme/layouts/_shortcodes/cardpane.html diff --git a/layouts/_shortcodes/comment.html b/theme/layouts/_shortcodes/comment.html similarity index 100% rename from layouts/_shortcodes/comment.html rename to theme/layouts/_shortcodes/comment.html diff --git a/layouts/_shortcodes/conditional-text.html b/theme/layouts/_shortcodes/conditional-text.html similarity index 100% rename from layouts/_shortcodes/conditional-text.html rename to theme/layouts/_shortcodes/conditional-text.html diff --git a/layouts/_shortcodes/iframe.html b/theme/layouts/_shortcodes/iframe.html similarity index 100% rename from layouts/_shortcodes/iframe.html rename to theme/layouts/_shortcodes/iframe.html diff --git a/layouts/_shortcodes/imgproc.html b/theme/layouts/_shortcodes/imgproc.html similarity index 100% rename from layouts/_shortcodes/imgproc.html rename to theme/layouts/_shortcodes/imgproc.html diff --git a/layouts/_shortcodes/pageinfo.html b/theme/layouts/_shortcodes/pageinfo.html similarity index 100% rename from layouts/_shortcodes/pageinfo.html rename to theme/layouts/_shortcodes/pageinfo.html diff --git a/layouts/_shortcodes/readfile.html b/theme/layouts/_shortcodes/readfile.html similarity index 100% rename from layouts/_shortcodes/readfile.html rename to theme/layouts/_shortcodes/readfile.html diff --git a/layouts/_shortcodes/redoc.html b/theme/layouts/_shortcodes/redoc.html similarity index 100% rename from layouts/_shortcodes/redoc.html rename to theme/layouts/_shortcodes/redoc.html diff --git a/layouts/_shortcodes/swaggerui.html b/theme/layouts/_shortcodes/swaggerui.html similarity index 100% rename from layouts/_shortcodes/swaggerui.html rename to theme/layouts/_shortcodes/swaggerui.html diff --git a/layouts/_shortcodes/tab.html b/theme/layouts/_shortcodes/tab.html similarity index 100% rename from layouts/_shortcodes/tab.html rename to theme/layouts/_shortcodes/tab.html diff --git a/layouts/_shortcodes/tabpane.html b/theme/layouts/_shortcodes/tabpane.html similarity index 100% rename from layouts/_shortcodes/tabpane.html rename to theme/layouts/_shortcodes/tabpane.html diff --git a/layouts/_shortcodes/td/site-build-info/netlify.md b/theme/layouts/_shortcodes/td/site-build-info/netlify.md similarity index 100% rename from layouts/_shortcodes/td/site-build-info/netlify.md rename to theme/layouts/_shortcodes/td/site-build-info/netlify.md diff --git a/layouts/_td-content-after-header.html b/theme/layouts/_td-content-after-header.html similarity index 100% rename from layouts/_td-content-after-header.html rename to theme/layouts/_td-content-after-header.html diff --git a/layouts/_td-content.html b/theme/layouts/_td-content.html similarity index 100% rename from layouts/_td-content.html rename to theme/layouts/_td-content.html diff --git a/layouts/all.html b/theme/layouts/all.html similarity index 100% rename from layouts/all.html rename to theme/layouts/all.html diff --git a/layouts/all.md b/theme/layouts/all.md similarity index 100% rename from layouts/all.md rename to theme/layouts/all.md diff --git a/layouts/baseof.html b/theme/layouts/baseof.html similarity index 100% rename from layouts/baseof.html rename to theme/layouts/baseof.html diff --git a/layouts/blog/_td-content.html b/theme/layouts/blog/_td-content.html similarity index 100% rename from layouts/blog/_td-content.html rename to theme/layouts/blog/_td-content.html diff --git a/layouts/blog/baseof.html b/theme/layouts/blog/baseof.html similarity index 100% rename from layouts/blog/baseof.html rename to theme/layouts/blog/baseof.html diff --git a/layouts/blog/baseof.print.html b/theme/layouts/blog/baseof.print.html similarity index 100% rename from layouts/blog/baseof.print.html rename to theme/layouts/blog/baseof.print.html diff --git a/layouts/blog/list.html b/theme/layouts/blog/list.html similarity index 100% rename from layouts/blog/list.html rename to theme/layouts/blog/list.html diff --git a/layouts/blog/section.print.html b/theme/layouts/blog/section.print.html similarity index 100% rename from layouts/blog/section.print.html rename to theme/layouts/blog/section.print.html diff --git a/layouts/blog/single.html b/theme/layouts/blog/single.html similarity index 100% rename from layouts/blog/single.html rename to theme/layouts/blog/single.html diff --git a/layouts/community/list.html b/theme/layouts/community/list.html similarity index 100% rename from layouts/community/list.html rename to theme/layouts/community/list.html diff --git a/layouts/docs/baseof.html b/theme/layouts/docs/baseof.html similarity index 100% rename from layouts/docs/baseof.html rename to theme/layouts/docs/baseof.html diff --git a/layouts/docs/baseof.print.html b/theme/layouts/docs/baseof.print.html similarity index 100% rename from layouts/docs/baseof.print.html rename to theme/layouts/docs/baseof.print.html diff --git a/layouts/docs/list.html b/theme/layouts/docs/list.html similarity index 100% rename from layouts/docs/list.html rename to theme/layouts/docs/list.html diff --git a/layouts/docs/list.print.html b/theme/layouts/docs/list.print.html similarity index 100% rename from layouts/docs/list.print.html rename to theme/layouts/docs/list.print.html diff --git a/layouts/docs/single.html b/theme/layouts/docs/single.html similarity index 100% rename from layouts/docs/single.html rename to theme/layouts/docs/single.html diff --git a/layouts/index.llms.txt b/theme/layouts/index.llms.txt similarity index 100% rename from layouts/index.llms.txt rename to theme/layouts/index.llms.txt diff --git a/layouts/search.html b/theme/layouts/search.html similarity index 100% rename from layouts/search.html rename to theme/layouts/search.html diff --git a/layouts/swagger/baseof.html b/theme/layouts/swagger/baseof.html similarity index 100% rename from layouts/swagger/baseof.html rename to theme/layouts/swagger/baseof.html diff --git a/layouts/swagger/list.html b/theme/layouts/swagger/list.html similarity index 100% rename from layouts/swagger/list.html rename to theme/layouts/swagger/list.html diff --git a/layouts/swagger/single.html b/theme/layouts/swagger/single.html similarity index 100% rename from layouts/swagger/single.html rename to theme/layouts/swagger/single.html diff --git a/layouts/taxonomy.html b/theme/layouts/taxonomy.html similarity index 100% rename from layouts/taxonomy.html rename to theme/layouts/taxonomy.html diff --git a/layouts/term.html b/theme/layouts/term.html similarity index 100% rename from layouts/term.html rename to theme/layouts/term.html diff --git a/theme/package.json b/theme/package.json new file mode 100644 index 0000000000..980c7279fa --- /dev/null +++ b/theme/package.json @@ -0,0 +1,14 @@ +{ + "name": "theme", + "version": "0.15.1-dev+002-over-main-ce9942b8", + "description": "Internal folder for the Docsy theme files", + "repository": "github:google/docsy", + "homepage": "https://www.docsy.dev", + "license": "Apache-2.0", + "private": true, + "dependencies-note": "DO NOT EDIT directly; versions are synced from the root package.json by scripts/sync-theme-deps.mjs (run via `npm run _sync:theme-deps`).", + "dependencies": { + "@fortawesome/fontawesome-free": "6.7.2", + "bootstrap": "5.3.8" + } +} diff --git a/static/css/prism.css b/theme/static/css/prism.css similarity index 100% rename from static/css/prism.css rename to theme/static/css/prism.css diff --git a/static/favicons/android-144x144.png b/theme/static/favicons/android-144x144.png similarity index 100% rename from static/favicons/android-144x144.png rename to theme/static/favicons/android-144x144.png diff --git a/static/favicons/android-192x192.png b/theme/static/favicons/android-192x192.png similarity index 100% rename from static/favicons/android-192x192.png rename to theme/static/favicons/android-192x192.png diff --git a/static/favicons/android-36x36.png b/theme/static/favicons/android-36x36.png similarity index 100% rename from static/favicons/android-36x36.png rename to theme/static/favicons/android-36x36.png diff --git a/static/favicons/android-48x48.png b/theme/static/favicons/android-48x48.png similarity index 100% rename from static/favicons/android-48x48.png rename to theme/static/favicons/android-48x48.png diff --git a/static/favicons/android-72x72.png b/theme/static/favicons/android-72x72.png similarity index 100% rename from static/favicons/android-72x72.png rename to theme/static/favicons/android-72x72.png diff --git a/static/favicons/android-96x96.png b/theme/static/favicons/android-96x96.png similarity index 100% rename from static/favicons/android-96x96.png rename to theme/static/favicons/android-96x96.png diff --git a/static/favicons/apple-touch-icon-180x180.png b/theme/static/favicons/apple-touch-icon-180x180.png similarity index 100% rename from static/favicons/apple-touch-icon-180x180.png rename to theme/static/favicons/apple-touch-icon-180x180.png diff --git a/static/favicons/favicon-1024.png b/theme/static/favicons/favicon-1024.png similarity index 100% rename from static/favicons/favicon-1024.png rename to theme/static/favicons/favicon-1024.png diff --git a/static/favicons/favicon-16x16.png b/theme/static/favicons/favicon-16x16.png similarity index 100% rename from static/favicons/favicon-16x16.png rename to theme/static/favicons/favicon-16x16.png diff --git a/static/favicons/favicon-256.png b/theme/static/favicons/favicon-256.png similarity index 100% rename from static/favicons/favicon-256.png rename to theme/static/favicons/favicon-256.png diff --git a/static/favicons/favicon-32x32.png b/theme/static/favicons/favicon-32x32.png similarity index 100% rename from static/favicons/favicon-32x32.png rename to theme/static/favicons/favicon-32x32.png diff --git a/static/favicons/favicon.ico b/theme/static/favicons/favicon.ico similarity index 100% rename from static/favicons/favicon.ico rename to theme/static/favicons/favicon.ico diff --git a/static/favicons/pwa-192x192.png b/theme/static/favicons/pwa-192x192.png similarity index 100% rename from static/favicons/pwa-192x192.png rename to theme/static/favicons/pwa-192x192.png diff --git a/static/favicons/pwa-512x512.png b/theme/static/favicons/pwa-512x512.png similarity index 100% rename from static/favicons/pwa-512x512.png rename to theme/static/favicons/pwa-512x512.png diff --git a/static/favicons/tile150x150.png b/theme/static/favicons/tile150x150.png similarity index 100% rename from static/favicons/tile150x150.png rename to theme/static/favicons/tile150x150.png diff --git a/static/favicons/tile310x150.png b/theme/static/favicons/tile310x150.png similarity index 100% rename from static/favicons/tile310x150.png rename to theme/static/favicons/tile310x150.png diff --git a/static/favicons/tile310x310.png b/theme/static/favicons/tile310x310.png similarity index 100% rename from static/favicons/tile310x310.png rename to theme/static/favicons/tile310x310.png diff --git a/static/favicons/tile70x70.png b/theme/static/favicons/tile70x70.png similarity index 100% rename from static/favicons/tile70x70.png rename to theme/static/favicons/tile70x70.png diff --git a/static/js/deflate.js b/theme/static/js/deflate.js similarity index 100% rename from static/js/deflate.js rename to theme/static/js/deflate.js diff --git a/static/js/prism.js b/theme/static/js/prism.js similarity index 100% rename from static/js/prism.js rename to theme/static/js/prism.js diff --git a/static/js/tabpane-persist.js b/theme/static/js/tabpane-persist.js similarity index 100% rename from static/js/tabpane-persist.js rename to theme/static/js/tabpane-persist.js diff --git a/theme.toml b/theme/theme.toml similarity index 100% rename from theme.toml rename to theme/theme.toml