#slugA URL-safe slug from content or a string: lowercased, every run of characters outside a–z and 0–9 collapsed to a single hyphen, with none left at either end.
#import "@rookery/core:0.1.0": ideate, slug
#show: ideate.with(
separator: heading.where(level: 2),
name: (h, labels) => "sec-" + slug(h),
)Exported for exactly that: the name function above, naming each section’s idea after its own heading, so inserting or reordering sections does not renumber every name after it.
Text that is nothing but punctuation slugs to the empty string, and the build fails rather than minting an idea under an empty name.