131 lines
5.9 KiB
Text
131 lines
5.9 KiB
Text
#!/usr/bin/env nu
|
|
|
|
# Register a new Slidev deck as a site page.
|
|
#
|
|
# The projection REPLACES a page's body and PRESERVES its frontmatter — so the page has to exist
|
|
# first, and it must carry title, slug, thumbnail and og_image. That is the one thing the
|
|
# projection cannot invent, and the one step nobody remembers: without it, `just decks` fails with
|
|
# "la página de destino no tiene frontmatter; no la sobrescribo a ciegas".
|
|
#
|
|
# This scaffolds those pages and prints the decks.ncl entry to add. It deliberately does NOT edit
|
|
# decks.ncl: that file is the manifest a human curates (which deck, which slugs, which language),
|
|
# and a script that rewrites a manifest is a script that decides what should be published.
|
|
#
|
|
# Usage (from outreach/):
|
|
# nu scripts/decks/new-deck.nu rustikon.md rustikon-why-i-needed-rust \
|
|
# --title-es "Rustikon: por qué necesité Rust" --slug-es rustikon-por-que-necesite-rust \
|
|
# --title-en "Rustikon: Why I Needed Rust" --slug-en rustikon-why-i-needed-rust
|
|
|
|
def outreach [] { $env.FILE_PWD | path dirname | path dirname }
|
|
|
|
def main [
|
|
source: string # the Slidev md, relative to outreach/presentation/
|
|
id: string # the deck id: file name of the pages, and the asset dir
|
|
--title-es: string = "" # omite el par title/slug de un idioma y ese idioma NO tendrá página
|
|
--slug-es: string = ""
|
|
--title-en: string = ""
|
|
--slug-en: string = ""
|
|
--source-en: string = "" # fuente PROPIA de la página EN cuando el deck es bilingüe nativo
|
|
# (dos charlas reales, no una traducción): p. ej. rustikon.md (EN)
|
|
# + rustikon_es.md (ES). Omítelo si una sola fuente sirve ambos idiomas.
|
|
--date: string = "" # ISO; defaults to today
|
|
--author: string = "Jesús Pérez"
|
|
] {
|
|
let src = [(outreach) "presentation" $source] | path join
|
|
if not ($src | path exists) { error make { msg: $"no existe el deck: ($src)" } }
|
|
|
|
# A separate EN source must exist and must actually differ — a page's `source` equal to the
|
|
# deck's is just noise in the manifest, and a non-existent one fails the projection later, so
|
|
# catch both here where the message can name the file.
|
|
if (not ($source_en | is-empty)) {
|
|
let esrc = [(outreach) "presentation" $source_en] | path join
|
|
if not ($esrc | path exists) { error make { msg: $"no existe la fuente EN: ($esrc)" } }
|
|
if ($source_en == $source) { error make { msg: "--source-en es igual a la fuente del deck; omítelo" } }
|
|
}
|
|
|
|
let when = if ($date | is-empty) { (date now | format date "%Y-%m-%d") } else { $date }
|
|
|
|
# `source` per page: EN uses --source-en when given, otherwise the deck's own. Only a source
|
|
# that DIFFERS from the deck default is emitted in the manifest below.
|
|
let pages = [
|
|
{ lang: "es", title: $title_es, slug: $slug_es, source: $source }
|
|
{ lang: "en", title: $title_en, slug: $slug_en, source: (if ($source_en | is-empty) { $source } else { $source_en }) }
|
|
]
|
|
|
|
# A language with no title/slug gets NO page. A deck that exists only in Spanish must not have
|
|
# an English URL serving Spanish slides: a page that lies about its language is worse than a
|
|
# page that does not exist.
|
|
let wanted = ($pages | where {|p| not (($p.title | is-empty) or ($p.slug | is-empty)) })
|
|
if ($wanted | is-empty) { error make { msg: "necesitas al menos --title-es/--slug-es o --title-en/--slug-en" } }
|
|
|
|
# The URL category is localized (decks.ncl `category`): ES → presentaciones, EN → decks. The
|
|
# loader resolves the body by {lang}/{category}/{id}.md, so BOTH the directory and the
|
|
# frontmatter category must be the localized value, or the ES page 404s.
|
|
let cat = (^nickel export --format json ([(outreach) "scripts" "decks" "decks.ncl"] | path join)
|
|
| from json | get category)
|
|
|
|
for p in $wanted {
|
|
let category = ($cat | get $p.lang)
|
|
let dir = [(outreach) "site" "site" "content" "resources" $p.lang $category] | path join
|
|
let file = [$dir $"($id).md"] | path join
|
|
if ($file | path exists) {
|
|
print $"(ansi yellow)ya existe, no lo toco: ($file)(ansi reset)"
|
|
continue
|
|
}
|
|
mkdir $dir
|
|
# Only the frontmatter. The body is the projection's, and it is fenced by its own markers —
|
|
# anything written here below the frontmatter would be overwritten on the first `just decks`.
|
|
$"---
|
|
id: \"($id)\"
|
|
title: \"($p.title)\"
|
|
slug: \"($p.slug)\"
|
|
subtitle: \"\"
|
|
excerpt: \"\"
|
|
|
|
author: \"($author)\"
|
|
date: \"($when)\"
|
|
published: true
|
|
featured: false
|
|
|
|
category: \"($category)\"
|
|
tags: [\"ontoref\", \"slides\"]
|
|
|
|
# Card + share image. The webp carousel is no longer the CONTENT — the slides carry real text
|
|
# now — but slide 0 still makes the best thumbnail.
|
|
thumbnail: \"/images/decks/($id)/0.webp\"
|
|
image_url: \"/images/decks/($id)/0.webp\"
|
|
og_image: \"/images/og/decks-($id)-0.png\"
|
|
|
|
sort_order: 1
|
|
---
|
|
" | save --force $file
|
|
print $"(ansi green)creada:(ansi reset) ($file)"
|
|
}
|
|
|
|
# Emit `source = …` per page ONLY where it differs from the deck default — that is exactly the
|
|
# bilingual-native case (rustikon.md + rustikon_es.md), and it is the line deck-new used to make
|
|
# you add by hand.
|
|
let entries = ($wanted | each {|p|
|
|
if ($p.source == $source) {
|
|
$" { lang = \"($p.lang)\", slug = \"($p.slug)\" },"
|
|
} else {
|
|
$" { lang = \"($p.lang)\", slug = \"($p.slug)\", source = \"($p.source)\" },"
|
|
}
|
|
} | str join "\n")
|
|
print $"
|
|
(ansi cyan)Añade esta entrada a scripts/decks/decks.ncl(ansi reset) — el manifiesto lo curas tú,
|
|
no un script: qué deck se publica, con qué slug y en qué idioma es una decisión, no un derivado.
|
|
|
|
{
|
|
source = \"($source)\",
|
|
id = \"($id)\",
|
|
pages = [
|
|
($entries)
|
|
],
|
|
},
|
|
|
|
(ansi cyan)Y luego:(ansi reset)
|
|
just decks # build + captura + proyección + puertas de artefacto
|
|
just decks-served # las puertas sobre la PÁGINA servida
|
|
"
|
|
}
|