Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feat(sitemap): add XML styling #221

Merged
merged 1 commit into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ tabi has a perfect score on Google's Lighthouse audit:
- [X] Support for [comments using giscus, utterances, Hyvor Talk, or Isso](https://welpo.github.io/tabi/blog/comments/).
- [X] Code syntax highlighting with colours based on [Catppuccin](https://github.com/catppuccin/catppuccin) Frappé.
- [X] [KaTeX](https://katex.org/) support for mathematical notation.
- [X] [Stylized and human readable Atom feed](https://welpo.github.io/tabi/atom.xml).
- [X] [Stylized and human readable sitemap](https://welpo.github.io/tabi/sitemap.xml).
- [X] [Mail encoding](https://welpo.github.io/tabi/blog/mastering-tabi-settings/#encoded-email) for spam protection.
- [X] All JavaScript can be [fully disabled](https://welpo.github.io/tabi/blog/javascript/).
- [X] [Customizable Table of Contents](https://welpo.github.io/tabi/blog/toc/).
Expand All @@ -40,7 +42,6 @@ tabi has a perfect score on Google's Lighthouse audit:
- [X] Responsive design.
- [X] [Projects page](https://welpo.github.io/tabi/projects/).
- [X] [Archive page](https://welpo.github.io/tabi/archive/).
- [X] [Stylized feed](https://welpo.github.io/tabi/atom.xml).
- [X] [Social links](https://welpo.github.io/tabi/blog/mastering-tabi-settings/#social-media-icons).
- [X] [Tags](https://welpo.github.io/tabi/blog/mastering-tabi-settings/#tags).

Expand Down
3 changes: 2 additions & 1 deletion content/projects/tabi/index.ca.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ social_media_card = "social_cards/ca_projects_tabi.jpg"
- Suport per a [comentaris usant giscus, utterances, Hyvor Talk o Isso](https://welpo.github.io/tabi/ca/blog/comments/).
- Tot el JavaScript es pot [deshabilitar completament](https://welpo.github.io/tabi/ca/blog/javascript/).
- [Codificació de correu](https://welpo.github.io/tabi/ca/blog/mastering-tabi-settings/#correu-electronic-codificat) per a protecció contra spam.
- [Mapa del lloc estilitzat i llegible per humans](https://welpo.github.io/tabi/sitemap.xml).
- [Capçaleres de seguretat personalitzables](https://welpo.github.io/tabi/ca/blog/security/).
- [Feed Atom estilitzat i llegible per humans](https://welpo.github.io/tabi/ca/atom.xml).
- [Enllaços de retrocés per a notes al peu](https://welpo.github.io/tabi/ca/blog/mastering-tabi-settings/#enllacos-de-retorn-a-les-notes-a-peu-de-pagina).
- [Taula de continguts personalitzable](https://welpo.github.io/tabi/ca/blog/toc/).
- [Avís de drets d'autor personalitzat](https://welpo.github.io/tabi/ca/blog/mastering-tabi-settings/#copyright).
Expand All @@ -41,7 +43,6 @@ social_media_card = "social_cards/ca_projects_tabi.jpg"
- Suport de [KaTeX](https://katex.org/).
- [Enllaços socials](https://welpo.github.io/tabi/ca/blog/mastering-tabi-settings/#icones-de-xarxes-socials).
- [Pàgina d'arxiu](https://welpo.github.io/tabi/ca/archive/).
- [Feed estilitzat](https://welpo.github.io/tabi/ca/atom.xml).
- [Etiquetes](https://welpo.github.io/tabi/ca/blog/mastering-tabi-settings/#etiquetes).

## Pràctiques de desenvolupament
Expand Down
3 changes: 2 additions & 1 deletion content/projects/tabi/index.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ social_media_card = "social_cards/es_projects_tabi.jpg"
- Soporte para [comentarios usando giscus, utterances, Hyvor Talk o Isso](https://welpo.github.io/tabi/es/blog/comments/).
- Todo el JavaScript se puede [deshabilitar completamente](https://welpo.github.io/tabi/es/blog/javascript/).
- [Codificación de correo](https://welpo.github.io/tabi/es/blog/mastering-tabi-settings/#encoded-email) para protección contra spam.
- [Mapa de sitio web estilizado y legible por humanos](https://welpo.github.io/tabi/sitemap.xml).
- [Feed de Atom estilizado y legible por humanos](https://welpo.github.io/tabi/es/atom.xml).
- [Aviso de derechos de autor personalizado](https://welpo.github.io/tabi/es/blog/mastering-tabi-settings/#copyright).
- [Cabeceras de seguridad personalizables](https://welpo.github.io/tabi/es/blog/security/).
- [Botón de copiar para bloques de código](https://welpo.github.io/tabi/es/blog/mastering-tabi-settings/#boton-de-copiar-en-bloques-de-codigo).
Expand All @@ -41,7 +43,6 @@ social_media_card = "social_cards/es_projects_tabi.jpg"
- Soporte de [KaTeX](https://katex.org/).
- [Página de archivo](https://welpo.github.io/tabi/es/archive/).
- [Enlaces sociales](https://welpo.github.io/tabi/es/blog/mastering-tabi-settings/#iconos-de-redes-sociales).
- [Feed estilizado](https://welpo.github.io/tabi/es/atom.xml).
- [Etiquetas](https://welpo.github.io/tabi/es/blog/mastering-tabi-settings/#tags).

## Prácticas de desarrollo
Expand Down
3 changes: 2 additions & 1 deletion content/projects/tabi/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ social_media_card = "social_cards/projects_tabi.jpg"
- Support for [comments using giscus, utterances, Hyvor Talk, or Isso](https://welpo.github.io/tabi/blog/comments/).
- Code syntax highlighting with colours based on [Catppuccin](https://github.com/catppuccin/catppuccin) Frappé.
- [KaTeX](https://katex.org/) support for mathematical notation.
- [Stylized and human readable Atom feed](https://welpo.github.io/tabi/atom.xml).
- [Stylized and human readable sitemap](https://welpo.github.io/tabi/sitemap.xml).
- [Mail encoding](https://welpo.github.io/tabi/blog/mastering-tabi-settings/#encoded-email) for spam protection.
- All JavaScript can be [fully disabled](https://welpo.github.io/tabi/blog/javascript/).
- [Customizable Table of Contents](https://welpo.github.io/tabi/blog/toc/).
Expand All @@ -41,7 +43,6 @@ social_media_card = "social_cards/projects_tabi.jpg"
- Responsive design.
- [Projects page](https://welpo.github.io/tabi/projects/).
- [Archive page](https://welpo.github.io/tabi/archive/).
- [Stylized feed](https://welpo.github.io/tabi/atom.xml).
- [Social links](https://welpo.github.io/tabi/blog/mastering-tabi-settings/#social-media-icons).
- [Tags](https://welpo.github.io/tabi/blog/mastering-tabi-settings/#tags).

Expand Down
12 changes: 12 additions & 0 deletions sass/parts/_misc.scss
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,15 @@ hr {
.hidden {
display: none;
}

.visually-hidden {
clip: rect(0 0 0 0);
position: absolute;
margin: -1px;
border: 0;
padding: 0;
width: 1px;
height: 1px;
overflow: hidden;
white-space: nowrap;
}
113 changes: 113 additions & 0 deletions static/js/sortTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Select the table and table headers.
var table = document.querySelector("#sitemapTable");
var headers = Array.from(table.querySelectorAll("th"));

// Create and append the live region for accessibility announcements.
var liveRegion = document.createElement('div');
liveRegion.setAttribute('aria-live', 'polite');
liveRegion.setAttribute('aria-atomic', 'true');
liveRegion.classList.add('visually-hidden');
document.body.appendChild(liveRegion);

// Initialise headers with click and keyboard listeners.
initializeHeaders();
addSortText(); // Add text for screen readers for initial sort direction.
updateSortIndicators(headers[0], 'asc'); // Set initial sort indicators.

function updateSortIndicators(header, direction) {
removeSortArrows(header);
var arrow = document.createElement('span');
arrow.classList.add('sort-arrow');
arrow.textContent = direction === 'asc' ? ' ▲' : ' ▼';
arrow.setAttribute('aria-hidden', 'true');
header.appendChild(arrow);
}

function removeSortArrows(header) {
var arrows = header.querySelectorAll('.sort-arrow');
arrows.forEach(function (arrow) {
arrow.remove();
});
}

function initializeHeaders() {
headers.forEach(function (header, index) {
header.classList.add('sortable');
header.setAttribute('tabindex', '0');
header.sortDirection = 'asc'; // Default sort direction.
var sortAttribute = index === 0 ? 'ascending' : 'none';
header.setAttribute('aria-sort', sortAttribute);
header.addEventListener("click", function () {
sortTable(index);
});
header.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
sortTable(index);
}
});
});
}

function announceSort(header, direction) {
var columnTitle = header.querySelector('.columntitle').textContent;
liveRegion.textContent = 'Column ' + columnTitle + ' is now sorted in ' + direction + ' order';
}

function sortTable(index) {
var header = headers[index];
var direction = header.sortDirection === 'asc' ? 'desc' : 'asc';
var tbody = table.querySelector("tbody");
var rows = Array.from(tbody.querySelectorAll("tr"));
sortRows(rows, index, direction);
refreshTableBody(tbody, rows);
updateHeaderAttributes(header, direction);
announceSort(header, direction === 'asc' ? 'ascending' : 'descending');
}

function sortRows(rows, index, direction) {
rows.sort(function (rowA, rowB) {
var cellA = rowA.querySelectorAll("td")[index].textContent;
var cellB = rowB.querySelectorAll("td")[index].textContent;
return direction === 'asc' ? cellA.localeCompare(cellB) : cellB.localeCompare(cellA);
});
}

function refreshTableBody(tbody, rows) {
tbody.innerHTML = ''; // Clear existing rows.
rows.forEach(function (row) {
tbody.appendChild(row);
});
}

function updateHeaderAttributes(header, direction) {
headers.forEach(function (otherHeader) {
if (otherHeader !== header) {
otherHeader.setAttribute('aria-sort', 'none');
removeSortArrows(otherHeader);
}
});
header.setAttribute('aria-sort', direction === 'asc' ? 'ascending' : 'descending');
header.sortDirection = direction;
updateSortIndicators(header, direction);
updateAnnounceText(header);
}

// Update screen reader text for sorting.
function updateAnnounceText(header) {
var span = header.querySelector('.visually-hidden');
span.textContent = 'Click to sort in ' + (header.sortDirection === 'asc' ? 'descending' : 'ascending') + ' order';
}

// Add text for screen readers regarding sort order.
function addSortText() {
headers.forEach(function (header) {
var span = document.createElement('span');
span.classList.add('visually-hidden');
span.textContent = 'Click to sort in descending order';
header.appendChild(span);
});
}

headers[0].sortDirection = 'asc';
headers[0].setAttribute('aria-sort', 'ascending');
1 change: 1 addition & 0 deletions static/js/sortTable.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions static/sitemap_style.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9">
<xsl:output method="html" encoding="UTF-8" indent="yes" />

<xsl:template match="/sitemap:urlset">
<html>
<head>
<title>Sitemap</title>
<link rel="stylesheet" href="/main.css"/>
<script src="/js/sortTable.min.js" defer="defer"></script>
</head>
<body>
<div class="full-width">
<h1>Sitemap</h1>
<p>Number of URLs: <xsl:value-of select="count(sitemap:url)"/></p>
<table id="sitemapTable" class="sitemap-table" aria-label="URLs on the site and their last modification dates">
<thead>
<tr>
<th><span class="columntitle">URL</span></th>
<th><span class="columntitle">Last modification</span></th>
</tr>
</thead>
<tbody>
<xsl:for-each select="sitemap:url">
<tr>
<td>
<a href="{sitemap:loc}">
<xsl:value-of select="sitemap:loc"/>
</a>
</td>
<td>
<xsl:value-of select="sitemap:lastmod"/>
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
12 changes: 12 additions & 0 deletions templates/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="{{ get_url(path='/sitemap_style.xsl', trailing_slash=false) | safe }}" type="text/xsl"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{%- for sitemap_entry in entries %}
<url>
<loc>{{ sitemap_entry.permalink | escape_xml | safe }}</loc>
{%- if sitemap_entry.updated %}
<lastmod>{{ sitemap_entry.updated }}</lastmod>
{%- endif %}
</url>
{%- endfor %}
</urlset>