diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..535f470 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,100 @@ +name: Docs + +# Copy to .github/workflows/docs.yml. Before the first run, set the repository's +# Pages source to "GitHub Actions": Settings -> Pages -> Source, or +# `gh api -X POST repos/GeiserX//pages -f build_type=workflow` for a repo +# with no Pages yet. For a repo already publishing from a branch the API is a +# PUT, and its docs list `source.branch` and `source.path` as required, so the +# bare `-f build_type=workflow` PUT may 422: try it on CashPilot first and +# record which form worked. A deploy while the source is still a branch is +# expected to fail; that is the test that the switch happened. +# +# Never for a repo whose gh-pages branch holds a Helm chart index (index.yaml, +# artifacthub-repo.yml): Pumperly, LynxPrompt, genieacs-container, +# duplicacy-container. Those use docs-pages-helm.yml instead. +# +# Pull requests that touch the docs run the strict build, so a broken link, a +# missing page or an unreachable page fails the check instead of reaching the +# site. A push to main deploys, and only after the same build has passed. +# +# The site is published as a Pages artifact, never with `mkdocs gh-deploy`: +# no gh-pages branch, no `contents: write`, and one artifact is the whole site. +on: + push: + branches: + - main + paths: + - 'docs/**' + - 'mkdocs.yml' + - '.github/workflows/docs.yml' + # docs/index.md includes README.md: every merged entry rebuilds the site. + - 'README.md' + # docs/hooks/site.py counts DELETED.md at build time: a retirement rebuilds the site too. + - 'DELETED.md' + # Add every file a page includes with pymdownx.snippets (for example + # docker-compose.yml, .env.example): a change to it must rebuild the + # site, and a rename must fail the build. + # No paths filter on pull requests, on purpose: a check skipped by a path + # filter stays Pending and blocks the merge once it is a required check + # (repos.md step 5 makes green checks required). The build takes seconds. + pull_request: + workflow_dispatch: + +# One run at a time per ref, in push order, never cancelled. Locking only the +# deploy job is not enough: an older push whose build finishes later would +# deploy last and publish a stale site. Pull requests get their own group. +concurrency: + group: pages-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + build: + name: build (strict) + # Public repo: GitHub-hosted runners are free and unlimited here, and the + # job runs on pull requests, so it must never touch a self-hosted runner. + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # This job never pushes; a persisted token is readable by pip and every MkDocs plugin. + persist-credentials: false + + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: '3.13' + cache: pip + cache-dependency-path: docs/requirements-docs.txt + + - name: Install dependencies + run: pip install -r docs/requirements-docs.txt + + # mkdocs.yml sets `strict: true`; the flag here keeps the build strict + # even if someone removes that line. + - name: Build + run: mkdocs build --strict + + - name: Upload the site + if: github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: site + + deploy: + # Runs on push to main only, after the build job has passed. + if: github.event_name != 'pull_request' + needs: build + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + + - id: deployment + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a062424..f1820a8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,9 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + # En un PR se salta el enlace a la web de la lista: se publica al fusionar, + # así que el PR que la crea o cambia no puede comprobarla. En main sí. - uses: lycheeverse/lychee-action@v2 with: - args: --no-progress --insecure --accept 200..=403 --timeout 30 --max-retries 3 --exclude img.shields.io README.md + args: --no-progress --insecure --accept 200..=403 --timeout 30 --max-retries 3 --exclude img.shields.io ${{ github.event_name == 'pull_request' && '--exclude ^https://geiserx\.github\.io/awesome-asturies/' || '' }} README.md fail: true diff --git a/README.md b/README.md index 4a3379a..08034eb 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,10 @@ Awesome

Una selección de software open source que da soporte específico al Principado de Asturias, sus concejos, universidad e instituciones.

+

Búscalos en geiserx.github.io/awesome-asturies.

+ ## Contenido @@ -122,7 +124,7 @@ For the badge (grande): ## Contribuir -Las contribuciones son bienvenidas. Lee las [directrices de contribución](contributing.md) antes de enviar un pull request. +Las contribuciones son bienvenidas. Lee las [directrices de contribución](https://github.com/GeiserX/awesome-asturies/blob/main/contributing.md) antes de enviar un pull request. ## Nota @@ -131,3 +133,4 @@ Esta lista se centra en software open source que da **soporte específico al Pri ## Descargo de responsabilidad No se aceptan proyectos relacionados con pornografía, contenido NSFW, loterías o apuestas, religión, política partidista ni cualquier otro tema controvertido. Esta lista pretende ser un recurso técnico neutral y útil para la comunidad de desarrolladores. + diff --git a/docs/hooks/site.py b/docs/hooks/site.py new file mode 100644 index 0000000..1c29c31 --- /dev/null +++ b/docs/hooks/site.py @@ -0,0 +1,92 @@ +"""MkDocs hooks for the one-page site. + +on_page_markdown replaces the `` tokens in docs/index.md with +numbers counted from README.md and DELETED.md at build time, so the home page +never states a stale figure. Entries are counted inside category sections +only: a `## Mantenedores` list of GitHub profiles is not a project. + +on_page_content adds loading="lazy" to every image except the banner, so a +page with hundreds of shields.io badges paints before they all arrive, and +fails the build if the list did not come through the include. A missing +section marker already fails the build in pymdownx.snippets (check_paths: +true raises SnippetMissingError); this check is for markers that exist but +enclose the wrong lines. +""" + +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +ENTRY = re.compile(r"^- \[[^\]]+\]\(https?://") +# DELETED.md also lists repos that no longer exist as "- `owner/repo` - reason", with no link: +# they are retired projects too and count as such. +RETIRED = re.compile(r"^- (?:\[[^\]]+\]\(https?://|`[^`]+` - )") +H2 = re.compile(r"^## (.+)$") +NOT_CATEGORIES = { + "Contenido", + "Insignia", + "Mantenedores", + "Contribuir", + "Nota", + "Descargo de responsabilidad", +} +IMG = re.compile(r"]*>") +LISTED = re.compile(r"
  • \s*", str(value)) + if " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/logo.svg b/docs/images/logo.svg new file mode 100644 index 0000000..803a5d4 --- /dev/null +++ b/docs/images/logo.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..bdb97bc --- /dev/null +++ b/docs/index.md @@ -0,0 +1,59 @@ +--- +hide: + - navigation +--- + +# Awesome Asturies { .aw-visually-hidden } + +

    + Awesome Asturies +

    + +

    + Awesome + Estrellas en GitHub + Proyectos en la lista + Último commit + Licencia CC0-1.0 +

    + +--- + +**Awesome Asturies** es una selección de proyectos open source, en categorías, que dan soporte específico al Principado de Asturias, sus concejos, universidad e instituciones. Cada entrada enlaza al repositorio y a la institución o servicio al que da soporte, y muestra sus estrellas, último commit, lenguaje y licencia. Se retiran los proyectos archivados, borrados, abandonados, sustituidos, fuera de criterio o que han dejado de funcionar; cada uno queda en [DELETED.md](https://github.com/GeiserX/awesome-asturies/blob/main/DELETED.md) con su motivo ( hasta hoy). + +
    + +- :material-format-list-bulleted: **[Explorar por categoría](#contenido)** + + --- + + De Administración y Transparencia a Vivienda y Urbanismo, pasando por Asturies, Softastur, SADEI, Gijón. El índice lateral sigue la categoría que estás leyendo. + +- :material-magnify: **[Buscar un proyecto](https://geiserx.github.io/awesome-asturies/?q=Asturies)** + + --- + + Pulsa `/` y escribe lo que necesitas: Asturies, Softastur, SADEI, Gijón. La búsqueda cubre el nombre y la descripción de todas las entradas. + +- :material-plus-box-outline: **[Proponer un proyecto](https://github.com/GeiserX/awesome-asturies/issues/new?template=anadir-proyecto.md)** + + --- + + Abre un issue con la plantilla o envía un pull request siguiendo las [directrices](https://github.com/GeiserX/awesome-asturies/blob/main/contributing.md). Solo hace falta el enlace, la descripción y la institución o servicio al que da soporte. + +- :material-shield-check-outline: **[Añade la insignia a tu proyecto](#insignia)** + + --- + + Si tu proyecto está en la lista, una insignia en tu README lo dice. Cuatro estilos, una línea de Markdown. + +
    + +## Cómo se mantiene la lista + +- Entra el software que da soporte al Principado de Asturias, no el software hecho por alguien de allí. Los criterios completos están en [contributing.md](https://github.com/GeiserX/awesome-asturies/blob/main/contributing.md). +- Un proyecto archivado se retira sin más. Uno que no lo está se retira cuando deja de funcionar, y hay que poder enseñar el fallo; la falta de commits recientes no lo retira. También salen los repos borrados o renombrados, los que su autor da por abandonados, los sustituidos por otro proyecto y los que no cumplen los criterios. +- Los proyectos retirados quedan en [DELETED.md](https://github.com/GeiserX/awesome-asturies/blob/main/DELETED.md) con su motivo, para no volver a añadirlos por error. +- La integración continua comprueba el formato, el orden alfabético y las insignias en cada cambio ([awesome-lint-extra](https://github.com/GeiserX/awesome-lint-extra)). Cada mes se revisan los enlaces rotos que encuentra lychee y cada trimestre se buscan repos recién archivados. La guía de los mantenedores es [MAINTENANCE.md](https://github.com/GeiserX/awesome-asturies/blob/main/MAINTENANCE.md). + +--8<-- "README.md:lista" diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt new file mode 100644 index 0000000..d3504c7 --- /dev/null +++ b/docs/requirements-docs.txt @@ -0,0 +1 @@ +mkdocs-material==9.7.7 diff --git a/docs/stylesheets/theme.css b/docs/stylesheets/theme.css new file mode 100644 index 0000000..d108c35 --- /dev/null +++ b/docs/stylesheets/theme.css @@ -0,0 +1,114 @@ +/* docs/stylesheets/theme.css: the site takes its two colours from the banner: + * the sky behind the wordmark and the highlight on the art. + * + * mkdocs.yml sets `primary: custom` and `accent: custom`, which means Material + * paints nothing until these variables exist. + */ +:root { + --md-primary-fg-color: #0f0f17; /* banner sky */ + --md-primary-fg-color--light: #1e1e29; + --md-primary-fg-color--dark: #0a0a0f; + --md-primary-bg-color: #ffffff; /* text on the header */ + --md-primary-bg-color--light: #c9c2b6; + + --md-accent-fg-color: #f3d27a; /* banner highlight */ + --md-accent-fg-color--transparent: #f3d27a1a; +} + +/* Dark scheme: the page body uses the banner sky too, so the header and the + page read as one surface. */ +[data-md-color-scheme="slate"] { + --md-default-bg-color: #0f0f17; + --md-code-bg-color: #1e1e29; + --md-typeset-a-color: #f3d27a; +} + +/* Light scheme: the highlight on white is too faint for body links. + #946f0d is the same hue darkened to 4.5:1 or better on white. */ +[data-md-color-scheme="default"] { + --md-typeset-a-color: #946f0d; + --md-accent-fg-color: #946f0d; +} + +/* Give the header logo a fixed size so it does not crowd the site name. */ +.md-header__button.md-logo img, +.md-header__button.md-logo svg { + height: 1.6rem; + width: 1.6rem; +} + +/* The site name, set the way banner.svg sets its wordmark: weight 700, white, + slightly tracked (0.5 to 1 on 27 to 44px, about 0.02em). + * + * Only the first topic is styled. Material puts the site name in one + * .md-header__topic and the page title in a second one, and swaps them on + * scroll. Styling both would change the page title too. + */ +.md-header__topic:first-child .md-ellipsis { + color: #ffffff; + font-weight: 700; + letter-spacing: 0.02em; +} + +/* Keep the mark and the name close, so they read as one unit. */ +.md-header__button.md-logo { + padding-right: 0.2rem; +} + +.md-header__title { + margin-left: 0.2rem; +} + +/* Buttons. + * + * Material paints .md-button in --md-primary-fg-color, the header colour. On + * the dark page that is also the page background, so a button would show as + * plain text. Outline buttons take the link colour instead. */ +.md-typeset .md-button { + color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + border-radius: 0.5rem; +} + +.md-typeset .md-button:focus, +.md-typeset .md-button:hover { + background-color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + color: #0f0f17; +} + +/* Grid cards: the border picks up the accent on hover, so the cards match + the buttons and links. */ +.md-typeset .grid.cards > ul > li, +.md-typeset .grid > .card { + border-radius: 0.5rem; +} + +.md-typeset .grid.cards > ul > li:focus-within, +.md-typeset .grid.cards > ul > li:hover, +.md-typeset .grid > .card:focus-within, +.md-typeset .grid > .card:hover { + border-color: var(--md-typeset-a-color); +} + +/* The home page keeps an H1 for search, screen readers and the browser tab. + The banner under it already shows the name, so the H1 is hidden visually. + Use it as: # Awesome Asturies { .aw-visually-hidden } */ +.md-typeset h1.aw-visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; + border: 0; +} + +/* The per-entry shields.io badges are inline images inside list items. Keep + them on the text baseline and stop a wrapped line from opening a gap. */ +.md-typeset li > a > img, +.md-typeset li > img { + vertical-align: middle; +} diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..5d5d2de --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,131 @@ +# One-page site: docs/index.md holds a short home block and then includes the +# list from README.md (section marker `lista`), so the list stays the single +# source that awesome-lint-extra governs. Never copy the list into docs/. +site_name: Awesome Asturies +site_url: https://geiserx.github.io/awesome-asturies/ +site_description: Una selección de software open source que da soporte específico al Principado de Asturias, sus concejos, universidad e instituciones. +repo_url: https://github.com/GeiserX/awesome-asturies +repo_name: GeiserX/awesome-asturies + +# A warning is a broken link, a missing page or a page nobody can reach. All of +# them fail the build, locally and in CI, so nobody has to remember --strict. +strict: true + +theme: + name: material + language: es + # Both drawn from the banner, see docs/images/logo.svg and icon.svg. + logo: images/logo.svg + favicon: images/icon.svg + # Dark first: the first palette entry is the default, and the banner is dark. + palette: + - scheme: slate + primary: custom + accent: custom + toggle: + icon: material/brightness-4 + name: Cambiar a modo claro + - scheme: default + primary: custom + accent: custom + toggle: + icon: material/brightness-7 + name: Cambiar a modo oscuro + # One page: no tabs, no sections. No edit button either, because the page + # file is a home block plus an include; entries are edited in README.md. + # toc.follow keeps the right-hand index on the category being read; + # navigation.tracking puts that category in the URL so a visitor can share a + # link to it. + features: + - navigation.top + - navigation.tracking + - toc.follow + - content.code.copy + - search.highlight + - search.suggest + - search.share + icon: + repo: fontawesome/brands/github + +# MkDocs reports most link problems as `info`, which --strict ignores. Every +# line here promotes one of them to a warning so the build fails on it. For +# this site the one that matters is links.anchors: every entry of the +# Contenido list and every card must land on a real section heading. +validation: + nav: + omitted_files: warn + not_found: warn + absolute_links: warn + links: + not_found: warn + anchors: warn + absolute_links: warn + unrecognized_links: warn + +plugins: + - search: + lang: es + +# Build-time counts for the home page, lazy loading for the badge images, and +# a check that the list really came through the include. +hooks: + - docs/hooks/site.py + +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + # docs/index.md includes README.md from the `lista` section marker. base_path + # includes the repository root; check_paths makes a renamed or missing README + # fail the build, and also a missing section marker (SnippetMissingError, + # "Snippet section lista could not be located"). The hook above is a second + # guard: it fails the build if the markers exist but enclose the wrong lines. + - pymdownx.snippets: + base_path: + - . + - docs + check_paths: true + # Material icons in the home page cards (:material-magnify: and friends). + # README.md has no :shortcode: text today; `grep -oE ':[a-z_]+:' README.md` + # must stay empty or an entry description could turn into an emoji. + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - attr_list + # Renders the home page's grid cards and the README's HTML blocks. + - md_in_html + - tables + # GitHub-style anchors keep accents (#administración-y-gobierno). The default + # slugify strips them and every accented Contenido link would miss. + # toc_depth 2: the right-hand index lists the categories only, never the + # province or island H3s some lists have under them. + - toc: + permalink: true + toc_depth: 2 + slugify: !!python/object/apply:pymdownx.slugs.slugify + kwds: + case: lower + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/GeiserX/awesome-asturies + +extra_css: + - stylesheets/theme.css + +# Files under docs/ that are not pages. MkDocs publishes every file in docs/, +# so anything that is not part of the site must be listed here. +exclude_docs: | + [A-Z]*.md + design/ + research/ + notes/ + hooks/ + requirements-docs.txt + +nav: + - Awesome Asturies: index.md