block page URLs by category not filesystem

This commit is contained in:
Loren Norman 2025-07-24 12:40:27 -04:00
parent 38a850cdd7
commit 25ec0db569
7 changed files with 64 additions and 27 deletions

View file

@ -24,14 +24,13 @@ export default defineConfig({
},
editLink: {
text: "Suggest an edit to this page",
// runs on the frontend, must be a pure function!
pattern: ({ filePath }) => {
pattern: ({ filePath, frontmatter }) => {
// special handling for block pages
if(filePath.match(/^blocks\//)) {
// docs come from the js, md is not the true source
const jsPath = filePath.replace(/.md$/, '.js')
// and we want to link to the main branch, not docs
return `https://github.com/adafruit/io-actions/edit/main/app/${jsPath}`
// block pages have their source paths in their frontmatter
return `https://github.com/adafruit/io-actions/edit/main/app/blocks/${frontmatter.definitionPath}`
}
return `https://github.com/adafruit/io-actions/edit/main/docs/${filePath}`

View file

@ -36,7 +36,7 @@ const
await exportTo("docs", definitions, exportItem => {
exportItem.sidebar("blocks/_blocks_sidebar.json")
exportItem.blockPages(block => `blocks/${block.definitionPath.replace(/.js$/, '.md')}`)
exportItem.blockPages()
// exportItem.blockExamples(block => "blocks/${block.definitionPath}/examples.json")
})
},

View file

@ -4,6 +4,8 @@ import BlockExporter from "#src/exporters/block_exporter.js"
import { niceTemplate } from '#src/util.js'
const UNCATEGORIZED_PATH = "uncategorized"
class BlockDefinition {
definitionSet = null
@ -51,6 +53,42 @@ class BlockDefinition {
: [])
}
getPrimaryCategory() {
const categories = this.getCategories()
// doesn't appear in a category
if(!categories.length) {
// why specify a primary? warn
if(this.primaryCategory) {
console.warn(`Warning [${this.type}]: No category found, but did have "primaryCategory" key: "${this.primaryCategory}"`)
}
return UNCATEGORIZED_PATH
}
const firstCategoryName = categories[0].name
// appears in multiple categories
if(categories.length > 1) {
// doesn't specify a primary! this is bad, unsure what menu and URL it will fall under, warn
if(!this.primaryCategory) {
console.warn(`Warning [${this.type}]: Multiple categories but no "primaryCategory" declaration, using "${firstCategoryName}"`)
} else {
return this.primaryCategory
}
}
return firstCategoryName
}
documentationPath() {
const
blockMdFilename = this.definitionPath.split("/").at(-1).replace(/.js$/, '.md'),
primaryCategory = this.getPrimaryCategory()
return `blocks/${primaryCategory}/${blockMdFilename}`.toLowerCase()
}
toBlocklyJSON() {
return BlockExporter.export(this)
}

View file

@ -33,6 +33,7 @@ export default definition =>
`---
title: "Block: ${definition.name}"
editLink: true
definitionPath: ${ definition.definitionPath }
---
# Block: ${ renderBlockTitle(definition) }

View file

@ -1,6 +1,6 @@
import { mkdirSync, writeFileSync } from 'fs'
import { dirname } from 'path'
import { forEach } from 'lodash-es'
import { forEach, identity, pickBy } from 'lodash-es'
import toBlockMarkdown from "#src/docs/render_block.js"
@ -18,14 +18,13 @@ export default class BlockPageExporter {
const
options = {
toFile: false,
filenameFunc: null,
filenameFunc: blockDef => blockDef.documentationPath(),
...givenOptions
}
forEach(this.definitionSet.blocks, blockDefinition => {
const
docPath = options.filenameFunc?.(blockDefinition)
|| blockDefinition.definitionPath.replace(/.js$/, '.md'),
docPath = options.filenameFunc(blockDefinition),
fullPath = `${this.destination}/${docPath}`
mkdirSync(dirname(fullPath), { recursive: true })
@ -34,6 +33,11 @@ export default class BlockPageExporter {
}
exportToFile = (filenameFunc, toFile=true) => {
this.export({ toFile, filenameFunc })
const exportOptions = {
toFile,
// no filenameFunc if absent/falsy
...pickBy({ filenameFunc }, identity)
}
this.export(exportOptions)
}
}

View file

@ -1,15 +1,17 @@
const
// TODO: rely on project configuration for docs site location
DOCS_BLOCKS_ROOT = "https://adafruit.github.io/io-actions/blocks",
DOCS_BLOCKS_ROOT = "https://adafruit.github.io/io-actions",
processHelp = definition => {
if (!definition.definitionPath) { return {} }
const thisBlockPredicate = definition.definitionPath.slice(0, -3)
const
// location of the markdown, without the .md extension
thisBlockPredicate = definition.documentationPath().slice(0, -3),
// build the full URL
helpUrl = `${DOCS_BLOCKS_ROOT}/${thisBlockPredicate}`
return {
helpUrl: `${DOCS_BLOCKS_ROOT}/${thisBlockPredicate}`
}
return { helpUrl }
}
export default processHelp

View file

@ -29,17 +29,10 @@ export default class SidebarExporter {
forEach(this.definitionSet.blocks, blockDefinition => {
// skip disabled blocks
if(blockDefinition.disabled) { return }
const docPath = blockDefinition.definitionPath.replace(/.js$/, '.md')
const
blockSidebarPath = `/blocks/${docPath.slice(0, -3)}`,
sidebarEntry = {
text: blockDefinition.name,
link: blockSidebarPath
}
const sidebarEntry = {
text: blockDefinition.name,
link: blockDefinition.documentationPath()
}
// add links to each sidebar category we're a part of
forEach(blockDefinition.getCategories(), category => {