Documentación Libellus

URLs del sitio (Netlify / dominio)

  • Producción (canónica): https://marconoris.com
  • Netlify (deploys): https://marconoris.netlify.app
  • Aliases:
    • https://libellus.marconoris.com
    • https://marconoris.art

Enlaces de la bóveda de Obsidian

  • Los enlaces relativos que salen de este repo (p. ej. ../../../Lecturas/...) se reescriben automáticamente durante el build.
  • Configura el host de publicación con obsidian_publish_baseurl en _config.yml (actualmente https://lab.marconoris.com).
  • Cualquier enlace Markdown o atributo HTML href/src que empiece por ../ se reescribe hacia ese host, para que los assets exportados de la bóveda sigan funcionando en la web.
  • Documentación técnica de los plugins: OBSIDIAN-PLUGINS.md.

Cómo mantener el sitio

Checklist rápido para que todo funcione bien:

  • Front matter mínimo: layout correcto (post/page/project…), title, date, lang (es/ca/en/it…). Sin title no aparece en listados; sin lang el pager asume es.
  • Slugs/URLs: no necesitas tocarlos; el hook genera slug latinizados y permalinks por colección. Usa slug/permalink solo si quieres forzar algo distinto.
  • H1 y contenido: si el documento incluye un # (H1) en el cuerpo, los layouts inyectan el meta-info justo después de ese H1 (sin tocar el Markdown). Si no hay H1 en el cuerpo, el layout pinta un H1 de fallback con title/heading.
  • Índice (TOC): añade show_toc: true en el front matter de post o page para mostrar un índice lateral (H1/H2/H3) en pantallas anchas.
  • Paginación/pagers: el include pagination.html muestra anterior/siguiente dentro de la misma collection y lang. Si no ves pager, comprueba lang.
  • Orden en colecciones:
    • Projects: se ordenan por fecha (descendente). Si quieres posicionar manualmente, usa order y/o ajusta date.
    • Resto de colecciones: si tienen order, se ordenan por order (ascendente) y, a igualdad, por fecha descendente. Si no hay order, solo por fecha.
  • Callouts: usa sintaxis > [!tipo] Título (tip, success, warning, danger, quote, cite, question, note, links, abstract, summary, texts…). Mira /callouts-demo/ para ejemplos.
  • Autolink de URLs: cualquier http/https suelto se enlaza automáticamente en el post-render. Si necesitas desactivar en una página/post, pon autolink_urls: false en el front matter.
  • Build limpio: si cambias permalinks/slugs, borra _site y .jekyll-cache y ejecuta bundle exec jekyll build (sin incremental) para ver los cambios.
  • Documentación técnica: BIO-SITE.md.

Embeds de vídeo (YouTube/Vimeo/Bunny) y allowlist

El plugin _plugins/video_markdown_embed.rb convierte URLs de YouTube, Vimeo y Bunny Stream en iframes responsivos cuando:

  • Pegas una URL “sola” en una línea (ej. https://vimeo.com/974390692).
  • Usas sintaxis de imagen Markdown apuntando a la URL del vídeo: `<div class="video-embed video-embed--vimeo">

</div> (el texto se usa como title` del iframe).

  • Para Bunny Stream, la forma canónica es https://player.mediadelivery.net/play/<library>/<video-guid>.

Cómo funciona la allowlist

Para evitar pasar parámetros arbitrarios al embed, el plugin:

  • Lee el querystring de la URL original (lo que va tras ?).
  • Conserva solo las claves permitidas por plataforma (ALLOWED_QUERY_PARAMS), normalizando el nombre a minúsculas.
  • Descarta cualquier otro parámetro.

Allowlist actual:

  • YouTube: autoplay, controls, loop, mute, playsinline, start, end
  • Vimeo: autoplay, loop, muted, autopause, playsinline, background, dnt, title, byline, portrait, badge
  • Bunny Stream: autoplay, captions, preload, t, chromecast, disableAirplay, disableIosPlayer, showHeatmap, muted, loop, playsinline, showSpeed, rememberPosition, responsive

Además, para Vimeo el plugin añade por defecto title=0&byline=0&portrait=0&badge=0 (puedes sobrescribirlos si los pasas en la URL y están en la allowlist).

Otros iframes responsivos (mapas, álbumes, etc.)

Si necesitas embeds que no sean 16:9 (Lightroom, Mapbox, Sketchfab…), envuélvelos en .embed-frame y marca el ratio con --embed-ratio (fallback 4/3):

<div class="embed-frame" style="--embed-ratio: 4 / 3">
  <iframe src="https://…"></iframe>
</div>

El wrapper elimina el margen del iframe, hereda el radio de borde y mantiene la relación de aspecto que definas.

Para colocar varios iframes uno al lado del otro, usa .embed-grid como contenedor:

<div class="embed-grid">
  <div class="embed-frame" style="--embed-ratio: 4 / 3">
    <iframe src="https://…"></iframe>
  </div>
  <div class="embed-frame" style="--embed-ratio: 4 / 3">
    <iframe src="https://…"></iframe>
  </div>
</div>

Portadas con video de fondo

El layout cover (ver portada.md) admite video de fondo desde Vimeo, YouTube o Bunny Stream. Usa cover_video o video_cover (también vale cover_vimeo para compatibilidad) con la URL completa:

layout: cover
title: ...
cover_video: https://vimeo.com/123456789
# o https://youtu.be/abc123
# o https://player.mediadelivery.net/play/617291/d545466f-50c1-4c37-9919-8f2818c78aed
# Opcional: cover (imagen) como fallback estático

El layout ajusta parámetros para autoplay/loop/mute y oculta los controles. No hace falta width/height; el iframe se adapta a la sección hero.

Si quieres random por visita, cover_video también acepta lista (en singular):

cover_video:
  - https://vimeo.com/123456789
  - https://youtu.be/abc123

cover_videos también funciona por compatibilidad, pero cover_video es la forma recomendada.

Imágenes sociales para páginas con cover

cover sigue siendo la única propiedad de front matter para la portada principal. No hace falta añadir otra propiedad para compartir.

Cuando cover apunta a un .webp local, la social card busca automáticamente una derivada JPG en el mismo directorio con este patrón:

basename.webp -> basename.social.jpg

Ejemplos:

  • images/tizas.webp -> images/tizas.social.jpg
  • images/news/ElDorado-hor.webp -> images/news/ElDorado-hor.social.jpg

Si la derivada existe, se usa para og:image y twitter:image. Si no existe, la plantilla cae a la imagen social global por defecto.

Para generar o regenerar estas derivadas:

python3 script/generate_social_images.py --dry-run
python3 script/generate_social_images.py

El script:

  • recorre el contenido y detecta cover.webp locales referenciados
  • genera *.social.jpg a 1200x630
  • no reescribe front matter
  • no sobrescribe el .webp original

Usa --force si quieres regenerar todo aunque la derivada ya exista.

Random de cover (video)

Cuando cover_video es una lista, el layout cover puede elegir el video:

  • visit (por visita/carga de página, default)
  • session (una vez por sesión de navegador)
  • day (una vez por día, según la hora local del usuario)

Configúralo en el frontmatter con cover_video_random: visit|session|day.

Frontmatter para Jekyll

Lo mínimo que necesita cada tipo de documento para que todo funcione sin sorpresas:

  • layout: el adecuado para la colección (post, page, project, etc.).
  • title: obligatorio (sin título no sale en listados ni en Home/collections).
  • date: para ordenar (posts y colecciones); si falta, caen a orden 0 o usan updated.
  • lang: consistente (es/ca/en/it…). El pager filtra por lang y si falta asume es.

Opcional según necesidad:

  • slug/permalink: los genera el hook a partir de title, así que solo hace falta si quieres forzar algo distinto.
  • year: en projects para ordenar por año antes que por fecha.
    • order: en projects para ordenar dentro del mismo año.
    • publish: false para ocultar.
    • hide_h1: true si quieres ocultar el H1 de fallback del layout (cuando el documento no trae H1 en el cuerpo).
    • libellus_featured: true para fijar publicaciones en la home de Libellus de Libellus.
    • featured: true para incluir el documento en los bloques de destacados del index multilengua y del biosite.
    • featured_order: orden manual ascendente dentro de esos bloques. Si falta, se usa updated y luego date como fallback.
    • year_range_sort: en índices con layout: series controla cómo ordenar rangos en year (start por defecto; end usa el último año del rango).
    • external_links: lista de enlaces externos (por ejemplo VSCO/Are.na) que se renderizan al final de los layouts project/project-two-column.

      external_links:
        - label: VSCO
          url: https://vsco.co/...
        - label: Are.na
          url: https://www.are.na/...
      

Clases y estilos rápidos en Markdown (kramdown/Liquid)

  • Atributos kramdown al final de un párrafo o imagen: Texto aquí {: .project-text } o !Alt{: .img-blend }.
  • Anchos puntuales sin tocar CSS: !Alt{: style="width: 260px;" } o envolviendo: <div style="width:260px">!Alt</div>.
  • Múltiples clases o estilos: {: .project-text .resalte style="max-width: 18rem;" }.
  • Recuerda que la sintaxis va pegada al elemento anterior (sin línea en blanco) y se procesa antes que el Markdown/HTML del layout.

Portada / home

  • Home principal (index es/ca/en/it): el bloque “Destacado” (vía _includes/home-index-featured.html) mezcla site.pages y todas las colecciones, filtrando por lang y excluyendo published: false / publish: false.
  • Propiedades de selección (home principal):
    • featured: true = incluye el documento en destacados.
    • featured_order = orden manual ascendente.
    • deduplicación por translation_key (o url si falta).
    • si no hay featured_order, fallback temporal por updated desc y, si no hay updated, date desc.
  • Bloque “Studio shop” (home principal):
    • Se renderiza vía _includes/home-shop.html con datos en /_data/shop_featured.yml.
    • Por defecto muestra 4 items (2x2 en mobile, 4 columnas en desktop).
    • Apagar en una home concreta: home_shop: false en el front matter del index.md correspondiente.
    • Idiomas: cada item puede llevar lang: es|ca|en|it; si falta, aparece en todos los idiomas.
    • Labels i18n: home_shop_title (título del bloque) y home_shop_all (CTA “ver tienda”).
  • Home de Libellus: libellus_featured: true se mantiene para su bloque destacado específico.
  • Colapsar colecciones: hay un bloque collections_state comentado en _config.yml; por defecto todas quedan cerradas. Lista en open las que quieras abrir de inicio:

    collections_state:
      open:
        - posts
        - versiculi
    

    puedes listar las colecciones a ocultar sin borrarlas. Úsalo si decides implementar lógica de cierre en los listados/pagers.

Estructura recomendada (4 items por idioma, títulos localizados; URLs e imágenes pueden reutilizarse):

items:
  - title: "Obra original"
    url: "https://shop.marconoris.com/category/obra-original"
    image: "https://assets.bigcartel.com/product_images/.../foo.jpg"
    lang: es
  - title: "Original artwork"
    url: "https://shop.marconoris.com/category/obra-original"
    image: "https://assets.bigcartel.com/product_images/.../foo.jpg"
    lang: en

Campos:

  • title (texto visible)
  • url (destino en shop.marconoris.com)
  • image (URL remota o ruta local /images/...)
  • price (opcional, string)
  • lang (opcional; si falta, aparece en todos los idiomas)

Bio site (layout: biosite)

  • El layout está en _layouts/biosite.html y se usa en pages/*/bio.md.
  • Al final del bio (antes del logo de cierre) renderiza el mismo bloque de shop (_includes/home-shop.html).
  • Apagar en una bio concreta: bio_shop: false en el front matter de pages/*/bio.md.

Galerías (PhotoSwipe)

Guía rápida para usar las galerías del layout project y sus opciones:

  • Galería única “suelta” (lo básico): si solo necesitas una galería, puedes definirla directamente en el documento (sin galleries:). Con layout: project se renderiza automáticamente (a menos que uses gallery_render: manual).

    gallery_style: grid # opcional (default: grid)
    gallery:
      - src: /images/projects/mi-proyecto/01.webp
        caption: "Pie opcional"
      - src: /images/projects/mi-proyecto/02.webp
    

    o bien auto desde carpeta:

    gallery_style: masonry # opcional
    gallery_path: /images/projects/mi-proyecto/ # importante: con barra final
    gallery_caption_all: "Mi caption" # opcional
    # gallery_captions: # opcional (mapa filename -> caption)
    #   01.webp: "Pie 1"
    #   02.webp: "Pie 2"
    
  • Múltiples galerías (recomendado si quieres títulos/secciones): define galleries: como lista de bloques. Cada bloque acepta id, gallery_style (grid, masonry, collage, carousel), y gallery (lista de imágenes con src; opcionales: thumb, caption, width, height para el zoom del lightbox):

    galleries:
      - id: uno
        gallery_style: masonry
        gallery:
          - src: ../images/foo/bar.webp
            thumb: ../images/foo/bar-thumb.webp
            caption: "Título o pie"
            width: 1800
            height: 1200
    
  • Auto desde carpeta: en lugar de listar imágenes, usa gallery_path: /images/projects/mi-proyecto/ (incluye la barra final) para cargar todos los ficheros de esa carpeta (ordenados por nombre). Puedes añadir gallery_captions: para sobrescribir captions por archivo. Si quieres el mismo caption para todas las auto, usa gallery_caption_all: "Mi caption".
  • Render: por defecto (gallery_render: auto) el layout recorre galleries (o gallery/gallery_path sueltas) y pinta la galería antes del contenido.
  • Incrustar la galería en el Markdown (manual):
    1) En el front matter añade gallery_render: manual y define la galería con galleries: (o gallery:/gallery_path: si solo hay una):
       gallery_render: manual
       galleries:
         - id: swab
           gallery_style: masonry
           gallery:
             - src: ../images/news/swab.webp
               caption: "Obra en SWAB"
    

    2) En el cuerpo del .md coloca el include donde quieras que aparezca:

       {% include project-gallery.html id="swab" %}
    

    Si solo tienes una galería suelta (gallery: en front matter), no hace falta id.
    3) Títulos y descripciones de la galería: añade title: y/o description: dentro del bloque de la galería (no en el front matter principal); se muestran encima del grid/carrusel si show_meta está activo (por defecto lo está).

  • Lightbox:
  • Lightbox:
    • Por bloque (default): cada bloque lleva su propio data-pswp-gallery, el lightbox solo recorre esa galería.
    • Global por página: envuelve varias galerías en un contenedor con data-pswp-gallery="algo" y pasa skip_pswp_container=true en cada include, para que compartan el mismo lightbox:

      <div data-pswp-gallery="project-foo">
        {% include project-gallery.html id="uno" skip_pswp_container=true %}
        {% include project-gallery.html id="dos" skip_pswp_container=true %}
      </div>
      
    • Desactivar lightbox: pon lightbox: false en el bloque o en el include: `

`.

  • Columnas por breakpoint (grid y masonry): usa gallery_columns (móvil/base), gallery_columns_md (≥640px) y gallery_columns_lg (≥1024px). Ejemplo:

    gallery_columns: 1
    gallery_columns_md: 2
    gallery_columns_lg: 4
    

    Si no defines nada, se usan los valores por defecto del CSS (grid: auto-fit; masonry: 1/2/3 columnas en móvil/≥640/≥1024).

  • Notas de estilo: en masonry las imágenes no se recortan; si solo hay 1–2 imágenes se ajustan las columnas para ocupar el ancho (a menos que fijes columnas). collage usa filas fijas con spans; carousel centra y permite scroll horizontal con controles. Puedes mezclar gallery manual con gallery_path: las manuales se renderizan primero y luego las auto.

Bloques de logos (sponsors/partners)

Para un bloque de sponsors con logos centrados usa las clases project-sponsors:

<div class="project-sponsors">
  <p class="project-sponsors__eyebrow">
    Proyecto producido con el apoyo de <strong>BCN Producció 17</strong>. En colaboración con:
  </p>
  <div class="project-sponsors__grid">
    <a class="project-sponsors__logo" href="https://lacapella.barcelona" target="_blank" rel="noopener">
      <img src="https://lab.marconoris.com/images/logos/lacapella.png" alt="La Capella">
    </a>
    <div class="project-sponsors__logo">
      <img src="/images/logos/mume.png" alt="MUME. Museu Memorial de l'Exili">
    </div>
    <div class="project-sponsors__logo">
      <img src="https://lab.marconoris.com/images/logos/598.png" alt="Mojones de los Pirineos">
    </div>
  </div>
</div>

Usa rutas relativas a tus imágenes y ajusta los alt de cada logo. Todos los logos son HTML puro para evitar problemas de parsers Markdown mezclados.

Referenciar un proyecto desde páginas/posts

  • Añade en el front matter project_ref: <translation_key-del-proyecto> (ej. project_ref: lugares-remotos).
  • En los metadatos se mostrará AÑO · Proyecto <link> (etiqueta traducida según lang). Busca el proyecto en site.proyectos por translation_key y prioriza el mismo lang; si no existe, usa el primero disponible.
  • Si quieres relacionar un contenido con una serie, usa series_ref: <translation_key-de-la-serie> (acepta string o lista). project_ref queda reservado para proyectos.

Márgenes de texto en proyectos (override desde Markdown)

En páginas con layout project, el CSS aplica en desktop (≥768px) un margen lateral a los bloques de texto dentro de .project-content:

  • Se aplica por defecto a p, ul y ol como hijos directos de .project-content.
  • Los párrafos que contienen contenido “media/interactive” (por ejemplo img, iframe) se excluyen por defecto para evitar layouts raros (los p que envuelven button no se excluyen).

Si necesitas control fino desde Markdown (kramdown), puedes añadir clases a un bloque:

  • Forzar el estilo “texto con márgenes” (aunque sea un bloque especial): {:.project-text} (también usable en series/page)
  • Quitar márgenes (ancho completo): {:.project-text--full}

Ejemplos:

Este párrafo irá con margen lateral en desktop.
{:.project-text}

- Esta lista irá a ancho completo
- (sin margen lateral)
{: .project-text--full}