diff --git a/config.toml b/config.toml index de4bf8056..d8b66cf29 100644 --- a/config.toml +++ b/config.toml @@ -231,6 +231,12 @@ compact_tags = false # Default: "name". tag_sorting = "name" +# Show clickable tags above cards.html template (e.g. projects/) to filter the displayed items. +# Loads JS to filter. If JS is disabled, the buttons are links to the tag's page. +# Can be set at the section or config.toml level, following the hierarchy: section > config. See: https://welpo.github.io/tabi/blog/mastering-tabi-settings/#settings-hierarchy +# Default: true +enable_cards_tag_filtering = true + # Invert the order of the site title and page title in the browser tab. # Example: true => "Blog • ~/tabi", false => "~/tabi • Blog" invert_title_order = false diff --git a/content/blog/javascript/index.ca.md b/content/blog/javascript/index.ca.md index 34acfc111..e118f8f04 100644 --- a/content/blog/javascript/index.ca.md +++ b/content/blog/javascript/index.ca.md @@ -1,7 +1,7 @@ +++ title = "Sense JavaScript obligatori" date = 2023-01-06 -updated = 2024-08-28 +updated = 2024-11-16 description = "JavaScript només s'utilitza quan HTML i CSS no són suficients." [taxonomies] @@ -29,6 +29,7 @@ Les següents opcions es poden especificar per a publicacions, seccions i global - [**Diagrames de Mermaid**](@/blog/shortcodes/index.ca.md#diagrames-de-mermaid). Habilitat configurant `mermaid = true` (~2.5 MB). - [**Còpia de blocs de codi amb un sol clic**](@/blog/markdown/index.ca.md#bloc-de-codi). Habilitada configurant `copy_button = true`. (~700 bytes) - [**Mostrar ruta/URL a blocs de codi**](@/blog/shortcodes/index.ca.md#mostrar-ruta-o-url). S'activa configurant `add_src_to_code_block = true`. (~400 bytes) +- [**Filtratge per etiquetes** per a graelles de targetes](@/blog/mastering-tabi-settings/index.ca.md#filtrar-projectes) (p. ex. [projectes](@/projects/_index.ca.md)) (~2KB). S'habilita configurant `enable_cards_tag_filtering = true`. Per especificar aquestes opcions: diff --git a/content/blog/javascript/index.es.md b/content/blog/javascript/index.es.md index bbc62c79d..203bed9ac 100644 --- a/content/blog/javascript/index.es.md +++ b/content/blog/javascript/index.es.md @@ -1,7 +1,7 @@ +++ title = "Sin JavaScript obligatorio" date = 2023-01-06 -updated = 2024-08-28 +updated = 2024-11-16 description = "JavaScript solo se utiliza cuando HTML y CSS no son suficientes." [taxonomies] @@ -29,6 +29,7 @@ Las siguientes opciones pueden especificarse para publicaciones, secciones y a n - [**Diagramas de Mermaid**](@/blog/shortcodes/index.es.md#diagramas-de-mermaid). Habilitado al configurar `mermaid = true` (~2.5 MB). - [**Copia de bloques de código con un solo clic**](@/blog/markdown/index.es.md#bloque-de-codigo). Habilitado al configurar `copy_button = true` (~700 bytes). - [**Mostrar ruta/URL en bloques de código**](@/blog/shortcodes/index.es.md#mostrar-ruta-o-url). Se activa configurando `add_src_to_code_block = true`. (~400 bytes) +- [**Filtraje por etiquetas** para cuadrículas de tarjetas](@/blog/mastering-tabi-settings/index.es.md#filtrar-proyectos) (p. ej. [proyectos](@/projects/_index.es.md)) (~2KB). Habilitado al configurar `enable_cards_tag_filtering = true`. Para especificar estas opciones: diff --git a/content/blog/javascript/index.md b/content/blog/javascript/index.md index 734a9af77..14f483907 100644 --- a/content/blog/javascript/index.md +++ b/content/blog/javascript/index.md @@ -1,7 +1,7 @@ +++ title = "No mandatory JavaScript" date = 2023-01-06 -updated = 2024-08-28 +updated = 2024-11-16 description = "JavaScript is only used when HTML and CSS aren't enough." [taxonomies] @@ -29,6 +29,7 @@ The following settings can be specified for posts, sections and globally, follow - [**Mermaid diagrams**](@/blog/shortcodes/index.md#mermaid-diagrams). Enabled by setting `mermaid = true` (~2.5 MB). - [**One-click copy of code blocks**](@/blog/markdown/index.md#code-block). Enabled by setting `copy_button = true`. (~700 bytes) - [**Showing source (path or URL) in code blocks**](@/blog/shortcodes/index.md#show-source-or-path). Enabled by setting `add_src_to_code_block = true`. (~300 bytes) +- [**Tag filtering** for card grids](@/blog/mastering-tabi-settings/index.md#filtering-projects) (e.g. [projects](@/projects/_index.md)) (~2KB). Enabled by setting `enable_cards_tag_filtering = true`. To specify these settings: diff --git a/content/blog/mastering-tabi-settings/img/projects_tag_filter_dark.webp b/content/blog/mastering-tabi-settings/img/projects_tag_filter_dark.webp new file mode 100644 index 000000000..a7c9fd4b5 Binary files /dev/null and b/content/blog/mastering-tabi-settings/img/projects_tag_filter_dark.webp differ diff --git a/content/blog/mastering-tabi-settings/img/projects_tag_filter_light.webp b/content/blog/mastering-tabi-settings/img/projects_tag_filter_light.webp new file mode 100644 index 000000000..42c9c3698 Binary files /dev/null and b/content/blog/mastering-tabi-settings/img/projects_tag_filter_light.webp differ diff --git a/content/blog/mastering-tabi-settings/index.ca.md b/content/blog/mastering-tabi-settings/index.ca.md index 6f94d6b09..cbde16ce0 100644 --- a/content/blog/mastering-tabi-settings/index.ca.md +++ b/content/blog/mastering-tabi-settings/index.ca.md @@ -1,7 +1,7 @@ +++ title = "Domina la configuració de tabi: guia completa" date = 2023-09-18 -updated = 2024-11-14 +updated = 2024-11-16 description = "Descobreix les múltiples maneres en què pots personalitzar tabi." [taxonomies] @@ -391,6 +391,33 @@ Quan un usuari faci clic a la imatge o al títol d'un projecte, serà portat a l La pàgina del projecte individual es renderitza amb la plantilla predeterminada, tret que estableixis una altra, per exemple, `template = "info-page.html"`. +#### Filtrar projectes + +Si afegeixes etiquetes als teus projectes, veuràs un filtre d'etiquetes: + +{{ dual_theme_image(light_src="blog/mastering-tabi-settings/img/projects_tag_filter_light.webp", dark_src="blog/mastering-tabi-settings/img/projects_tag_filter_dark.webp", alt="Pàgina de projectes amb filtre d'etiquetes", full_width=true) }} + +El sistema de filtratge d'etiquetes utilitza millora progressiva: + +- Sense JavaScript: Les etiquetes enllacen directament a pàgines d'etiquetes dedicades (per exemple, `/tags/nom-de-l-etiqueta`). +- Amb JavaScript: Filtratge instantani, sincronització d'URL (#nom-etiqueta) i navegació amb el teclat. + +Per desactivar aquesta funció, estableix `enable_cards_tag_filtering = false` a la secció `[extra]` del fitxer `projects/_index.md` o a `config.toml`. + +{% admonition(type="tip") %} + +Per filtrar projectes per etiquetes, necessites establir etiquetes a la front matter de cada projecte. Per exemple: + +```toml +title = "nom del projecte" +weight = 40 + +[taxonomies] +tags = ["etiqueta", "etiqueta 2", "tercera etiqueta"] +``` + +{% end %} + ### Arxiu Afegir una pàgina d'arxiu és similar a afegir una pàgina de projectes. Pots crear un directori a `content/archive/`. Allà, pots crear un fitxer `_index.md` amb el següent encapçalament: diff --git a/content/blog/mastering-tabi-settings/index.es.md b/content/blog/mastering-tabi-settings/index.es.md index 6faa913b4..44ad6237c 100644 --- a/content/blog/mastering-tabi-settings/index.es.md +++ b/content/blog/mastering-tabi-settings/index.es.md @@ -1,7 +1,7 @@ +++ title = "Domina la configuración de tabi: guía completa" date = 2023-09-18 -updated = 2024-11-14 +updated = 2024-11-16 description = "Descubre las múltiples maneras en que puedes personalizar tabi." [taxonomies] @@ -391,6 +391,33 @@ Cuando un usuario haga clic en la imagen o el título de un proyecto, será llev La página del proyecto individual se renderiza con la plantilla predeterminada, a menos que establezcas otra, por ejemplo, `template = "info-page.html"`. +#### Filtrar proyectos + +Si agregas etiquetas a tus proyectos, verás un filtro de etiquetas: + +{{ dual_theme_image(light_src="blog/mastering-tabi-settings/img/projects_tag_filter_light.webp", dark_src="blog/mastering-tabi-settings/img/projects_tag_filter_dark.webp", alt="Página de proyectos con filtro de etiquetas", full_width=true) }} + +El sistema de filtrado de etiquetas utiliza mejora progresiva: + +- Sin JavaScript: Las etiquetas enlazan directamente a páginas de etiquetas dedicadas (por ejemplo, `/tags/nombre-etiqueta`). +- Con JavaScript: Filtrado instantáneo, sincronización de URL (#nombre-etiqueta) y navegación por teclado. + +Para desactivar esta función, establece `enable_cards_tag_filtering = false` en la sección `[extra]` del archivo `projects/_index.md` o en `config.toml`. + +{% admonition(type="tip") %} + +Para filtrar proyectos por etiquetas, necesitas establecer etiquetas en el front matter de cada proyecto. Por ejemplo: + +```toml +title = "nombre del proyecto" +weight = 40 + +[taxonomies] +tags = ["etiqueta uno", "etiqueta 2", "tercera etiqueta"] +``` + +{% end %} + ### Archivo Agregar una página de archivo es similar a agregar una página de proyectos. Puedes crear un directorio en `content/archive/`. Allí, puedes crear un archivo `_index.md` con el siguiente encabezado: diff --git a/content/blog/mastering-tabi-settings/index.md b/content/blog/mastering-tabi-settings/index.md index ac9c97e37..c790f33b4 100644 --- a/content/blog/mastering-tabi-settings/index.md +++ b/content/blog/mastering-tabi-settings/index.md @@ -1,7 +1,7 @@ +++ title = "Mastering tabi Settings: A Comprehensive Guide" date = 2023-09-18 -updated = 2024-11-14 +updated = 2024-11-16 description = "Discover the many ways you can customise your tabi site." [taxonomies] @@ -356,7 +356,7 @@ Clicking on this link will take you to the commit history of the post, where you ### Projects -tabi has a built-in projects template. To enable it, you can create a directory in `content/projects/`. There, you can create a `_index.md` file with the following front matter: +tabi has a built-in projects (cards) template. To enable it, you can create a directory in `content/projects/`. There, you can create a `_index.md` file with the following front matter: ```toml title = "Projects" @@ -396,6 +396,33 @@ When a user clicks on the image or title of a project, they will be taken to the The individual project's page is rendered with the default template, unless you set another one, e.g. `template = "info-page.html"`. +#### Filtering Projects + +If you add tags to your projects, you will see a tag filter: + +{{ dual_theme_image(light_src="blog/mastering-tabi-settings/img/projects_tag_filter_light.webp", dark_src="blog/mastering-tabi-settings/img/projects_tag_filter_dark.webp", alt="Projects page with tag filter", full_width=true) }} + +The tag filtering system uses progressive enhancement: + +- Without JavaScript: Tags link directly to dedicated tag pages (e.g. `/tags/tag-name`) +- With JavaScript: Instant filtering, URL syncing (#tag-name), and keyboard navigation + +To disable this feature, set `enable_cards_tag_filtering = false` in the `[extra]` section of the `projects/_index.md` file or in `config.toml`. + +{% admonition(type="tip") %} + +To filter projects by tags, you need to set tags in the front matter of each project. For example: + +```toml +title = "project name" +weight = 40 + +[taxonomies] +tags = ["tag one", "tag 2", "third tag"] +``` + +{% end %} + ### Archive Adding an archive page is similar to adding a projects page. You can create a directory in `content/archive/`. There, you can create a `_index.md` file with the following front matter: diff --git a/content/projects/doteki/doteki_logo.png b/content/projects/doteki/doteki_logo.png deleted file mode 100644 index ebef2ced9..000000000 Binary files a/content/projects/doteki/doteki_logo.png and /dev/null differ diff --git a/content/projects/doteki/doteki_logo.webp b/content/projects/doteki/doteki_logo.webp index c48c54cc3..ee76f4144 100644 Binary files a/content/projects/doteki/doteki_logo.webp and b/content/projects/doteki/doteki_logo.webp differ diff --git a/content/projects/doteki/index.ca.md b/content/projects/doteki/index.ca.md index 761a597fd..f8312c397 100644 --- a/content/projects/doteki/index.ca.md +++ b/content/projects/doteki/index.ca.md @@ -3,6 +3,9 @@ title = "dōteki" description = "Afegeix contingut dinàmic al teu perfil de GitHub amb un sistema intuïtiu de plugins." weight = 30 +[taxonomies] +tags = ["GitHub Actions", "automatització", "Python"] + [extra] local_image = "projects/doteki/doteki_logo.webp" social_media_card = "social_cards/projects_doteki.jpg" diff --git a/content/projects/doteki/index.es.md b/content/projects/doteki/index.es.md index 4e50e6c98..4e39c09bb 100644 --- a/content/projects/doteki/index.es.md +++ b/content/projects/doteki/index.es.md @@ -3,6 +3,9 @@ title = "dōteki" description = "Añade contenido dinámico a tu perfil de GitHub con un sistema intuitivo de plugins." weight = 30 +[taxonomies] +tags = ["GitHub Actions", "automatización", "Python"] + [extra] local_image = "projects/doteki/doteki_logo.webp" social_media_card = "social_cards/projects_doteki.jpg" diff --git a/content/projects/doteki/index.md b/content/projects/doteki/index.md index e8e9fec13..0e49bb0fb 100644 --- a/content/projects/doteki/index.md +++ b/content/projects/doteki/index.md @@ -3,6 +3,9 @@ title = "dōteki" description = "Add dynamic content to your GitHub profile through an intuitive plugin system." weight = 30 +[taxonomies] +tags = ["GitHub Actions", "automation", "Python"] + [extra] local_image = "projects/doteki/doteki_logo.webp" social_media_card = "social_cards/projects_doteki.jpg" diff --git a/content/projects/git-sumi/git-sumi_logo.png b/content/projects/git-sumi/git-sumi_logo.png deleted file mode 100644 index 450d71b02..000000000 Binary files a/content/projects/git-sumi/git-sumi_logo.png and /dev/null differ diff --git a/content/projects/git-sumi/git-sumi_logo.webp b/content/projects/git-sumi/git-sumi_logo.webp index d5d3ae8b1..90fd11ba6 100644 Binary files a/content/projects/git-sumi/git-sumi_logo.webp and b/content/projects/git-sumi/git-sumi_logo.webp differ diff --git a/content/projects/git-sumi/index.ca.md b/content/projects/git-sumi/index.ca.md index 8d6b4ad9a..0071df7e8 100644 --- a/content/projects/git-sumi/index.ca.md +++ b/content/projects/git-sumi/index.ca.md @@ -3,6 +3,9 @@ title = "git-sumi" description = "El linter de missatges de commit no opinat basat en Rust." weight = 10 +[taxonomies] +tags = ["Git", "Rust", "Continuous Integration", "GitHub Actions", "CLI", "automatització"] + [extra] local_image = "projects/git-sumi/git-sumi_logo.webp" social_media_card = "social_cards/projects_git-sumi.jpg" diff --git a/content/projects/git-sumi/index.es.md b/content/projects/git-sumi/index.es.md index 0f8df7d42..de25d40da 100644 --- a/content/projects/git-sumi/index.es.md +++ b/content/projects/git-sumi/index.es.md @@ -3,6 +3,9 @@ title = "git-sumi" description = "El linter de mensajes de commit no opinado basado en Rust." weight = 10 +[taxonomies] +tags = ["Git", "Rust", "Continuous Integration", "GitHub Actions", "CLI", "automatización"] + [extra] local_image = "projects/git-sumi/git-sumi_logo.webp" social_media_card = "social_cards/projects_git-sumi.jpg" diff --git a/content/projects/git-sumi/index.md b/content/projects/git-sumi/index.md index f2cfb749c..eafeb69d4 100644 --- a/content/projects/git-sumi/index.md +++ b/content/projects/git-sumi/index.md @@ -3,6 +3,9 @@ title = "git-sumi" description = "The non-opinionated Rust-based commit message linter." weight = 10 +[taxonomies] +tags = ["Git", "Rust", "Continuous Integration", "GitHub Actions", "CLI", "automation"] + [extra] local_image = "projects/git-sumi/git-sumi_logo.webp" social_media_card = "social_cards/projects_git-sumi.jpg" diff --git a/content/projects/nani/index.ca.md b/content/projects/nani/index.ca.md index 5bf23752b..abd966365 100644 --- a/content/projects/nani/index.ca.md +++ b/content/projects/nani/index.ca.md @@ -3,6 +3,9 @@ title = "nani" description = "Script Bash per crear URLs públiques a partir d'arxius o text en servidors remots." weight = 50 +[taxonomies] +tags = ["bash", "CLI"] + [extra] local_image = "projects/nani/nani_logo.webp" canonical_url = "https://osc.garden/ca/projects/tabi/" diff --git a/content/projects/nani/index.es.md b/content/projects/nani/index.es.md index edf773af8..0b338aa94 100644 --- a/content/projects/nani/index.es.md +++ b/content/projects/nani/index.es.md @@ -3,6 +3,9 @@ title = "nani" description = "Script Bash para crear URLs públicas a partir de archivos o texto en servidores remotos." weight = 50 +[taxonomies] +tags = ["bash", "CLI"] + [extra] local_image = "projects/nani/nani_logo.webp" canonical_url = "https://osc.garden/es/projects/tabi/" diff --git a/content/projects/nani/index.md b/content/projects/nani/index.md index cab154a80..437231213 100644 --- a/content/projects/nani/index.md +++ b/content/projects/nani/index.md @@ -3,6 +3,9 @@ title = "nani" description = "Bash script to create public URLs from files or text on remote servers." weight = 50 +[taxonomies] +tags = ["bash", "CLI"] + [extra] local_image = "projects/nani/nani_logo.webp" canonical_url = "https://osc.garden/projects/tabi/" diff --git a/content/projects/nani/nani_logo.webp b/content/projects/nani/nani_logo.webp index 2f301b13d..08d71755a 100644 Binary files a/content/projects/nani/nani_logo.webp and b/content/projects/nani/nani_logo.webp differ diff --git a/content/projects/ramu/index.ca.md b/content/projects/ramu/index.ca.md index 10db382b5..d5e01eee1 100644 --- a/content/projects/ramu/index.ca.md +++ b/content/projects/ramu/index.ca.md @@ -3,8 +3,11 @@ title = "ラム (ramu)" description = "Una aplicació web per practicar la lectura i comprensió auditiva de nombres en japonès." weight = 30 +[taxonomies] +tags = ["Japonès", "interactiu", "web app", "web", "PWA", "JavaScript"] + [extra] -local_image = "projects/ramu/ramu_logo.png" +local_image = "projects/ramu/ramu_logo.webp" canonical_url = "https://osc.garden/ca/projects/ramu/" social_media_card = "social_cards/projects_ramu.jpg" +++ diff --git a/content/projects/ramu/index.es.md b/content/projects/ramu/index.es.md index 25d06c7c2..7ddc526f8 100644 --- a/content/projects/ramu/index.es.md +++ b/content/projects/ramu/index.es.md @@ -3,8 +3,11 @@ title = "ラム (ramu)" description = "Una aplicación web para practicar la lectura y comprensión auditiva de números en japonés." weight = 30 +[taxonomies] +tags = ["Japonés", "interactivo", "web app", "web", "PWA", "JavaScript"] + [extra] -local_image = "projects/ramu/ramu_logo.png" +local_image = "projects/ramu/ramu_logo.webp" canonical_url = "https://osc.garden/es/projects/ramu/" social_media_card = "social_cards/projects_ramu.jpg" +++ diff --git a/content/projects/ramu/index.md b/content/projects/ramu/index.md index 3ed7e243c..d4084d6db 100644 --- a/content/projects/ramu/index.md +++ b/content/projects/ramu/index.md @@ -3,8 +3,11 @@ title = "ラム (ramu)" description = "A web app to practice reading and listening to Japanese numbers." weight = 30 +[taxonomies] +tags = ["Japanese", "interactive", "web app", "web", "PWA", "JavaScript"] + [extra] -local_image = "projects/ramu/ramu_logo.png" +local_image = "projects/ramu/ramu_logo.webp" canonical_url = "https://osc.garden/projects/ramu/" social_media_card = "social_cards/projects_ramu.jpg" +++ diff --git a/content/projects/ramu/ramu_logo.png b/content/projects/ramu/ramu_logo.png deleted file mode 100644 index 729174c74..000000000 Binary files a/content/projects/ramu/ramu_logo.png and /dev/null differ diff --git a/content/projects/ramu/ramu_logo.webp b/content/projects/ramu/ramu_logo.webp new file mode 100644 index 000000000..1eee49170 Binary files /dev/null and b/content/projects/ramu/ramu_logo.webp differ diff --git a/content/projects/streaming-royalties-calculator/index.ca.md b/content/projects/streaming-royalties-calculator/index.ca.md index 2c3ccc8f3..860c74d41 100644 --- a/content/projects/streaming-royalties-calculator/index.ca.md +++ b/content/projects/streaming-royalties-calculator/index.ca.md @@ -3,6 +3,9 @@ title = "Calculadora de royalties de streaming" description = "Una eina per calcular els royalties de streaming per a músics." weight = 45 +[taxonomies] +tags = ["música", "web app", "web", "JavaScript", "anàlisi de dades"] + [extra] local_image = "projects/streaming-royalties-calculator/streaming-royalties-calculator_logo.webp" canonical_url = "https://osc.garden/ca/projects/streaming-royalties-calculator/" diff --git a/content/projects/streaming-royalties-calculator/index.es.md b/content/projects/streaming-royalties-calculator/index.es.md index ae4d9f721..6217d9ba9 100644 --- a/content/projects/streaming-royalties-calculator/index.es.md +++ b/content/projects/streaming-royalties-calculator/index.es.md @@ -3,6 +3,9 @@ title = "Calculadora de royalties de streaming" description = "Una herramienta para calcular los royalties de streaming para músicos." weight = 45 +[taxonomies] +tags = ["música", "web app", "web", "JavaScript", "análisis de datos"] + [extra] local_image = "projects/streaming-royalties-calculator/streaming-royalties-calculator_logo.webp" canonical_url = "https://osc.garden/es/projects/streaming-royalties-calculator/" diff --git a/content/projects/streaming-royalties-calculator/index.md b/content/projects/streaming-royalties-calculator/index.md index 8aac42862..96f5c38bc 100644 --- a/content/projects/streaming-royalties-calculator/index.md +++ b/content/projects/streaming-royalties-calculator/index.md @@ -3,6 +3,9 @@ title = "Streaming Royalties Calculator" description = "A tool to calculate streaming royalties for musicians." weight = 45 +[taxonomies] +tags = ["music", "web app", "web", "JavaScript", "data analysis"] + [extra] local_image = "projects/streaming-royalties-calculator/streaming-royalties-calculator_logo.webp" canonical_url = "https://osc.garden/projects/streaming-royalties-calculator/" diff --git a/content/projects/streaming-royalties-calculator/streaming-royalties-calculator_logo.webp b/content/projects/streaming-royalties-calculator/streaming-royalties-calculator_logo.webp index 06754bfaa..19c8fe4b5 100644 Binary files a/content/projects/streaming-royalties-calculator/streaming-royalties-calculator_logo.webp and b/content/projects/streaming-royalties-calculator/streaming-royalties-calculator_logo.webp differ diff --git a/content/projects/tabi/index.ca.md b/content/projects/tabi/index.ca.md index 1f8d0d01f..64e0ea202 100644 --- a/content/projects/tabi/index.ca.md +++ b/content/projects/tabi/index.ca.md @@ -3,6 +3,9 @@ title = "tabi" description = "Un tema de Zola ràpid, lleuger i modern amb suport multilingüe." weight = 40 +[taxonomies] +tags = ["web", "JavaScript"] + [extra] local_image = "projects/tabi/tabi.webp" canonical_url = "https://osc.garden/ca/projects/tabi/" @@ -11,7 +14,7 @@ social_media_card = "social_cards/ca_projects_tabi.jpg" [**tabi**](https://github.com/welpo/tabi) és un tema modern i ric en funcionalitat per a [Zola](https://www.getzola.org/), un generador de llocs web estàtics molt ràpid. -{{ full_width_image(src="light_dark_tabi.webp", alt="Modes clar i fosc de tabi") }} +{{ full_width_image(src="https://cdn.jsdelivr.net/gh/welpo/tabi@main/light_dark_screenshot.png", alt="Modes clar i fosc de tabi") }} #### [Veure a GitHub](https://github.com/welpo/tabi) • [Demo i documentación](https://welpo.github.io/tabi/ca/) {.centered-text} diff --git a/content/projects/tabi/index.es.md b/content/projects/tabi/index.es.md index 3f2ef2803..da055e396 100644 --- a/content/projects/tabi/index.es.md +++ b/content/projects/tabi/index.es.md @@ -3,6 +3,9 @@ title = "tabi" description = "Un tema de Zola rápido, ligero y moderno con soporte multilingüe." weight = 40 +[taxonomies] +tags = ["web", "JavaScript"] + [extra] local_image = "projects/tabi/tabi.webp" canonical_url = "https://osc.garden/es/projects/tabi/" @@ -11,7 +14,7 @@ social_media_card = "social_cards/es_projects_tabi.jpg" [**tabi**](https://github.com/welpo/tabi) es un tema moderno y rico en funcionalidad para [Zola](https://www.getzola.org/), un generador de sitios web estáticos muy rápido. -{{ full_width_image(src="light_dark_tabi.webp", alt="Modos claro y oscuro de tabi") }} +{{ full_width_image(src="https://cdn.jsdelivr.net/gh/welpo/tabi@main/light_dark_screenshot.png", alt="Modos claro y oscuro de tabi") }} #### [Ver en GitHub](https://github.com/welpo/tabi) • [Demo y documentación](https://welpo.github.io/tabi/es/) {.centered-text} diff --git a/content/projects/tabi/index.md b/content/projects/tabi/index.md index e16e171ab..cf9c60bce 100644 --- a/content/projects/tabi/index.md +++ b/content/projects/tabi/index.md @@ -3,6 +3,9 @@ title = "tabi" description = "A feature-rich modern Zola theme with first-class multi-language support." weight = 40 +[taxonomies] +tags = ["web", "JavaScript"] + [extra] local_image = "projects/tabi/tabi.webp" social_media_card = "social_cards/projects_tabi.jpg" diff --git a/content/projects/tabi/tabi.webp b/content/projects/tabi/tabi.webp index 5b0f1d29c..c05d2a763 100644 Binary files a/content/projects/tabi/tabi.webp and b/content/projects/tabi/tabi.webp differ diff --git a/sass/parts/_cards.scss b/sass/parts/_cards.scss index 9a415beff..0b6c56047 100644 --- a/sass/parts/_cards.scss +++ b/sass/parts/_cards.scss @@ -1,3 +1,44 @@ +.filter-controls { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 12px; + margin-top: 1.2rem; + margin-bottom: -1rem; + padding: 0; + list-style: none; + + #all-projects-filter { + display: none; + } + + .taxonomy-item { + margin: 0; + + a { + display: inline-block; + box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; + border-radius: 1rem; + background: var(--bg-2); + padding: 0 16px; + color: var(--text-color); + font-size: 0.8rem; + text-decoration: none; + + &:hover { + background: var(--primary-color); + color: var(--hover-color); + } + + &.active { + background: var(--primary-color); + color: var(--hover-color); + } + } + } +} + .cards { display: grid; grid-template-rows: auto; @@ -27,13 +68,12 @@ padding-block-end: 24px; text-align: center; } - - .card-title { - margin-top: 0.7em; - } - .card-image { - width: 100%; + $margin: 1.6rem; + margin: $margin; + margin-bottom: $margin / 1.5; + width: calc(100% - $margin * 2); + height: auto; } .card-image-placeholder { @@ -53,4 +93,13 @@ .cards { gap: 18px; } + + .filter-controls { + gap: 8px; + margin: 18px 0; + + .taxonomy-item a { + padding: 4px 12px; + } + } } diff --git a/sass/parts/_posts_list.scss b/sass/parts/_posts_list.scss index ea7378f76..4e976c287 100644 --- a/sass/parts/_posts_list.scss +++ b/sass/parts/_posts_list.scss @@ -11,6 +11,19 @@ $padding: 2.5rem; align-items: flex-start; background-color: var(--navbar-color); padding-block: $padding; + min-width: 13.5rem; + + .thumbnail-image { + margin: 0; + margin-inline: auto; // Centred by default. + max-width: 70%; + } + + li.date + li.post-thumbnail .thumbnail-image { + // Styles for the thumbnail when there's a date above (either date or updated). + margin-inline: 0; // Since metadata is left aligned, the image looks weird when centred. + margin-block-start: 0.7rem; + } ul { margin-inline-end: 0.7rem; @@ -24,10 +37,6 @@ $padding: 2.5rem; white-space: nowrap; } - li.date { - width: 13.5rem; - } - li.draft-label { width: fit-content; line-height: 1.2rem; @@ -137,6 +146,10 @@ $padding: 2.5rem; margin-inline-end: 0.3rem; } } + + .post-thumbnail { + display: none; + } } .bloglist-content { diff --git a/static/js/filterCards.js b/static/js/filterCards.js new file mode 100644 index 000000000..a24137f45 --- /dev/null +++ b/static/js/filterCards.js @@ -0,0 +1,99 @@ +document.addEventListener('DOMContentLoaded', () => { + const cards = document.querySelectorAll('.card'); + const filterLinks = document.querySelectorAll('.filter-controls a'); + const allProjectsFilter = document.querySelector('#all-projects-filter'); + if (!cards.length || !filterLinks.length) return; + allProjectsFilter.style.display = 'block'; + + // Create a Map for O(1) lookups of links by filter value. + const linkMap = new Map( + Array.from(filterLinks).map(link => [link.dataset.filter, link]) + ); + + // Pre-process cards data for faster filtering. + const cardData = Array.from(cards).map(card => ({ + element: card, + tags: card.dataset.tags?.toLowerCase().split(',').filter(Boolean) ?? [] + })); + + function getTagSlugFromUrl(url) { + return url.split('/').filter(Boolean).pop(); + } + + function getFilterFromHash() { + if (!window.location.hash) return 'all'; + const hash = decodeURIComponent(window.location.hash.slice(1)); + const matchingLink = Array.from(filterLinks).find(link => + getTagSlugFromUrl(link.getAttribute('href')) === hash + ); + return matchingLink?.dataset.filter ?? 'all'; + } + + function setActiveFilter(filterValue, updateHash = true) { + if (updateHash) { + if (filterValue === 'all') { + history.pushState(null, '', window.location.pathname); + } else { + const activeLink = linkMap.get(filterValue); + if (activeLink) { + const tagSlug = getTagSlugFromUrl(activeLink.getAttribute('href')); + history.pushState(null, '', `#${tagSlug}`); + } + } + } + const isAll = filterValue === 'all'; + const display = isAll ? '' : 'none'; + const ariaHidden = isAll ? 'false' : 'true'; + requestAnimationFrame(() => { + filterLinks.forEach(link => { + const isActive = link.dataset.filter === filterValue; + link.classList.toggle('active', isActive); + link.setAttribute('aria-pressed', isActive); + }); + if (isAll) { + cardData.forEach(({ element }) => { + element.style.display = display; + element.setAttribute('aria-hidden', ariaHidden); + }); + } else { + cardData.forEach(({ element, tags }) => { + const shouldShow = tags.includes(filterValue); + element.style.display = shouldShow ? '' : 'none'; + element.setAttribute('aria-hidden', !shouldShow); + }); + } + }); + } + + const filterContainer = filterLinks[0].parentElement.parentElement; + filterContainer.addEventListener('click', e => { + const link = e.target.closest('a'); + if (!link) return; + e.preventDefault(); + const filterValue = link.dataset.filter; + if (filterValue) setActiveFilter(filterValue); + }); + + filterContainer.addEventListener('keydown', e => { + const link = e.target.closest('a'); + if (!link) return; + if (e.key === ' ' || e.key === 'Enter') { + e.preventDefault(); + link.click(); + } + }); + + filterLinks.forEach(link => { + link.setAttribute('role', 'button'); + link.setAttribute('aria-pressed', link.classList.contains('active')); + }); + + window.addEventListener('popstate', () => { + setActiveFilter(getFilterFromHash(), false); + }); + + const initialFilter = getFilterFromHash(); + if (initialFilter !== 'all') { + setActiveFilter(initialFilter, false); + } +}); diff --git a/static/js/filterCards.min.js b/static/js/filterCards.min.js new file mode 100644 index 000000000..b150e70f5 --- /dev/null +++ b/static/js/filterCards.min.js @@ -0,0 +1 @@ +document.addEventListener("DOMContentLoaded",()=>{var t=document.querySelectorAll(".card");const l=document.querySelectorAll(".filter-controls a");var e=document.querySelector("#all-projects-filter");if(t.length&&l.length){e.style.display="block";const s=new Map(Array.from(l).map(t=>[t.dataset.filter,t])),i=Array.from(t).map(t=>({element:t,tags:t.dataset.tags?.toLowerCase().split(",").filter(Boolean)??[]}));function o(t){return t.split("/").filter(Boolean).pop()}function a(){if(!window.location.hash)return"all";const e=decodeURIComponent(window.location.hash.slice(1));return Array.from(l).find(t=>o(t.getAttribute("href"))===e)?.dataset.filter??"all"}function r(a,t=!0){t&&("all"===a?history.pushState(null,"",window.location.pathname):(t=s.get(a))&&(t=o(t.getAttribute("href")),history.pushState(null,"","#"+t)));const e="all"===a,r=e?"":"none",n=e?"false":"true";requestAnimationFrame(()=>{l.forEach(t=>{var e=t.dataset.filter===a;t.classList.toggle("active",e),t.setAttribute("aria-pressed",e)}),e?i.forEach(({element:t})=>{t.style.display=r,t.setAttribute("aria-hidden",n)}):i.forEach(({element:t,tags:e})=>{e=e.includes(a),t.style.display=e?"":"none",t.setAttribute("aria-hidden",!e)})})}(e=l[0].parentElement.parentElement).addEventListener("click",t=>{var e=t.target.closest("a");e&&(t.preventDefault(),t=e.dataset.filter)&&r(t)}),e.addEventListener("keydown",t=>{var e=t.target.closest("a");!e||" "!==t.key&&"Enter"!==t.key||(t.preventDefault(),e.click())}),l.forEach(t=>{t.setAttribute("role","button"),t.setAttribute("aria-pressed",t.classList.contains("active"))}),window.addEventListener("popstate",()=>{r(a(),!1)}),"all"!==(t=a())&&r(t,!1)}}); diff --git a/templates/cards.html b/templates/cards.html index eae90cbeb..451f6b29b 100644 --- a/templates/cards.html +++ b/templates/cards.html @@ -18,7 +18,12 @@ {%- set show_pages = section.pages -%} {% endif -%} - {%- include "partials/cards_pages.html" -%} + {%- if macros_settings::evaluate_setting_priority(setting="enable_cards_tag_filtering", page=section, default_global_value=true) == "true" -%} + {%- include "partials/filter_card_tags.html" -%} + {%- endif -%} + + + {%- include "partials/cards_pages.html" -%} {% if paginator %} diff --git a/templates/macros/list_posts.html b/templates/macros/list_posts.html index 55a1ef751..b8de97b27 100644 --- a/templates/macros/list_posts.html +++ b/templates/macros/list_posts.html @@ -92,6 +92,25 @@ {%- endif -%} {%- endif -%} + {% if post.extra.local_image or post.extra.remote_image %} +
  • + + {% if post.extra.local_image %} + {% set meta = get_image_metadata(path=post.extra.local_image, allow_missing=true) %} + {{ post.extra.local_image }} + {% elif post.extra.remote_image %} + {{ post.extra.remote_image }} + {% endif %} + +
  • + {% endif %} + {% if post.draft %}
  • {{ macros_translate::translate(key="draft", default="DRAFT", language_strings=language_strings) }}
  • {% endif %} diff --git a/templates/page.html b/templates/page.html index 1d9929091..dedaa8b05 100644 --- a/templates/page.html +++ b/templates/page.html @@ -61,6 +61,7 @@ {% set settings_to_test = [ + "enable_cards_tag_filtering", "footnote_backlinks", "add_src_to_code_block", "force_codeblock_ltr", diff --git a/templates/partials/cards_pages.html b/templates/partials/cards_pages.html index b6045cb8e..d2128f8be 100644 --- a/templates/partials/cards_pages.html +++ b/templates/partials/cards_pages.html @@ -15,13 +15,24 @@ {% set target_url = page.extra.link_to | default(value=page.permalink) %} - -
    + {% if page.extra.local_image %} {% set meta = get_image_metadata(path=page.extra.local_image, allow_missing=true) %} - {{ page.extra.local_image }} + {{ page.extra.local_image }} {% elif page.extra.remote_image %} - {{ page.extra.remote_image }} + {{ page.extra.remote_image }} {% else %}
    {% endif %} diff --git a/templates/partials/filter_card_tags.html b/templates/partials/filter_card_tags.html new file mode 100644 index 000000000..4796fff0f --- /dev/null +++ b/templates/partials/filter_card_tags.html @@ -0,0 +1,34 @@ +{#- Collect all terms. -#} +{#- We don't use `get_taxonomy` so users aren't forced to use 'tags' -#} +{% set all_terms = [] %} +{% for page in show_pages %} + {% if page.taxonomies %} + {% for tax_name, terms in page.taxonomies %} + {% for term in terms %} + {% set_global all_terms = all_terms | concat(with=term) %} + {% endfor %} + {% endfor %} + {% endif %} +{% endfor %} + +{#- Display unique terms -#} +{%- if all_terms -%} +
    + {#- Load the script -#} + +{% endif %} diff --git a/theme.toml b/theme.toml index 9affeb083..ee4a6947e 100644 --- a/theme.toml +++ b/theme.toml @@ -188,6 +188,12 @@ compact_tags = false # Default: "name". tag_sorting = "name" +# Show clickable tags above cards.html template (e.g. projects/) to filter the displayed items. +# Loads JS to filter. If JS is disabled, the buttons are links to the tag's page. +# Can be set at the section or config.toml level, following the hierarchy: section > config. See: https://welpo.github.io/tabi/blog/mastering-tabi-settings/#settings-hierarchy +# Default: true +enable_cards_tag_filtering = true + # Invert the order of the site title and page title in the browser tab. # Example: true => "Blog • ~/tabi", false => "~/tabi • Blog" invert_title_order = false