diff --git a/news/changelog-1.6.md b/news/changelog-1.6.md index bf90919d29..b3608f0fb8 100644 --- a/news/changelog-1.6.md +++ b/news/changelog-1.6.md @@ -80,6 +80,7 @@ All changes included in 1.6: ### Websites - ([#2671](https://github.com/quarto-dev/quarto-cli/issues/2671)): Ensure that `--output-dir` works across filesystem boundaries. +- ([#8517](https://github.com/quarto-dev/quarto-cli/issues/8571)), ([#10829](https://github.com/quarto-dev/quarto-cli/issues/10829)): Allow listing categories with non-alphanumeric characters such as apostrophes, etc. - ([#8932](https://github.com/quarto-dev/quarto-cli/issues/8932)): Escape render ids in markdown pipeline to allow special characters in sidebars/navbars, etc. - ([#10616](https://github.com/quarto-dev/quarto-cli/issues/10268)): Add a `z-index` setting to the 'back to top' button to ensure it is always visible. diff --git a/src/project/types/website/listing/website-listing-categories.ts b/src/project/types/website/listing/website-listing-categories.ts index 1da089c8c9..911aeeaca0 100644 --- a/src/project/types/website/listing/website-listing-categories.ts +++ b/src/project/types/website/listing/website-listing-categories.ts @@ -1,9 +1,8 @@ /* -* website-listing-categories.ts -* -* Copyright (C) 2020-2022 Posit Software, PBC -* -*/ + * website-listing-categories.ts + * + * Copyright (C) 2020-2022 Posit Software, PBC + */ import { Document } from "deno_dom/deno-dom-wasm-noinit.ts"; import { kListingPageCategoryAll, @@ -118,7 +117,7 @@ function categoryElement( categoryEl.classList.add("category"); categoryEl.setAttribute( "data-category", - value !== undefined ? value : category, + value !== undefined ? btoa(value) : btoa(category), ); categoryEl.innerHTML = contents; return categoryEl; diff --git a/src/project/types/website/listing/website-listing-template.ts b/src/project/types/website/listing/website-listing-template.ts index 1e6afe3740..c3e270db03 100644 --- a/src/project/types/website/listing/website-listing-template.ts +++ b/src/project/types/website/listing/website-listing-template.ts @@ -454,7 +454,8 @@ export function reshapeListing( attr["index"] = (index++).toString(); if (item.categories) { - attr["categories"] = (item.categories as string[]).join(","); + const str = (item.categories as string[]).join(","); + attr["categories"] = btoa(str); } // Add magic attributes for the sortable values diff --git a/src/resources/projects/website/listing/item-default.ejs.md b/src/resources/projects/website/listing/item-default.ejs.md index 5e5afa6dfa..d39324c671 100644 --- a/src/resources/projects/website/listing/item-default.ejs.md +++ b/src/resources/projects/website/listing/item-default.ejs.md @@ -56,7 +56,7 @@ print(`
${listing.utilities.outputLi <% if (fields.includes('categories') && item.categories) { %>
<% for (const category of item.categories) { %> -
<%= category %>
+
<%= category %>
<% } %>
<% } %> diff --git a/src/resources/projects/website/listing/item-grid.ejs.md b/src/resources/projects/website/listing/item-grid.ejs.md index 7c0c92bd65..8c2423bcd0 100644 --- a/src/resources/projects/website/listing/item-grid.ejs.md +++ b/src/resources/projects/website/listing/item-grid.ejs.md @@ -64,7 +64,7 @@ return !["title", "image", "image-alt", "date", "author", "subtitle", "descripti
<% for (const category of item.categories) { %> -
<%= category %>
+
<%= category %>
<% } %>
diff --git a/src/resources/projects/website/listing/quarto-listing.js b/src/resources/projects/website/listing/quarto-listing.js index 88d209a9cc..ac3817ac0b 100644 --- a/src/resources/projects/website/listing/quarto-listing.js +++ b/src/resources/projects/website/listing/quarto-listing.js @@ -2,6 +2,7 @@ const kProgressiveAttr = "data-src"; let categoriesLoaded = false; window.quartoListingCategory = (category) => { + category = atob(category); if (categoriesLoaded) { activateCategory(category); setCategoryHash(category); @@ -58,7 +59,7 @@ window.document.addEventListener("DOMContentLoaded", function (_event) { ); for (const categoryEl of categoryEls) { - const category = categoryEl.getAttribute("data-category"); + const category = atob(categoryEl.getAttribute("data-category")); categoryEl.onclick = () => { activateCategory(category); setCategoryHash(category); @@ -208,7 +209,7 @@ function activateCategory(category) { // Activate this category const categoryEl = window.document.querySelector( - `.quarto-listing-category .category[data-category='${category}'` + `.quarto-listing-category .category[data-category='${btoa(category)}']` ); if (categoryEl) { categoryEl.classList.add("active"); @@ -231,7 +232,7 @@ function filterListingCategory(category) { list.filter(function (item) { const itemValues = item.values(); if (itemValues.categories !== null) { - const categories = itemValues.categories.split(","); + const categories = atob(itemValues.categories).split(","); return categories.includes(category); } else { return false; diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/_quarto.yml b/tests/docs/smoke-all/2024/10/23/issue-10829/_quarto.yml new file mode 100644 index 0000000000..668e81048e --- /dev/null +++ b/tests/docs/smoke-all/2024/10/23/issue-10829/_quarto.yml @@ -0,0 +1,19 @@ +project: + type: website + +website: + title: "issue-10829" + navbar: + right: + - about.qmd + - icon: github + href: https://github.com/ + - icon: twitter + href: https://twitter.com +format: + html: + theme: cosmo + css: styles.css + + + diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/about.qmd b/tests/docs/smoke-all/2024/10/23/issue-10829/about.qmd new file mode 100644 index 0000000000..692676f768 --- /dev/null +++ b/tests/docs/smoke-all/2024/10/23/issue-10829/about.qmd @@ -0,0 +1,19 @@ +--- +title: "About" +image: profile.jpg +about: + template: jolla + links: + - icon: twitter + text: Twitter + href: https://twitter.com + - icon: linkedin + text: LinkedIn + href: https://linkedin.com + - icon: github + text: Github + href: https://github.com + +--- + +About this blog diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/index.qmd b/tests/docs/smoke-all/2024/10/23/issue-10829/index.qmd new file mode 100644 index 0000000000..a5141c7cb0 --- /dev/null +++ b/tests/docs/smoke-all/2024/10/23/issue-10829/index.qmd @@ -0,0 +1,21 @@ +--- +title: "issue-10829" +listing: + contents: posts + sort: "date desc" + type: default + categories: true + sort-ui: false + filter-ui: false +page-layout: full +title-block-banner: true +_quarto: + render-project: true + tests: + html: + ensureFileRegexMatches: + - [] + - ['{=html}'] +--- + + diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/posts/_metadata.yml b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/_metadata.yml new file mode 100644 index 0000000000..3e9dd01bc3 --- /dev/null +++ b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/_metadata.yml @@ -0,0 +1,8 @@ +# options specified here will apply to all posts in this folder + +# freeze computational output +# (see https://quarto.org/docs/projects/code-execution.html#freeze) +freeze: true + +# Enable banner style title blocks +title-block-banner: true diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/posts/post-with-code/image.jpg b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/post-with-code/image.jpg new file mode 100644 index 0000000000..3ec04c8c4e Binary files /dev/null and b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/post-with-code/image.jpg differ diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/posts/post-with-code/index.qmd b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/post-with-code/index.qmd new file mode 100644 index 0000000000..b19970f9e9 --- /dev/null +++ b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/post-with-code/index.qmd @@ -0,0 +1,9 @@ +--- +title: "Post With Code" +author: "Harlow Malloc" +date: "2024-10-23" +categories: [news, code, analysis, apos'trophe] +image: "image.jpg" +--- + +This is a post with executable code. diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/posts/welcome/index.qmd b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/welcome/index.qmd new file mode 100644 index 0000000000..40ac45f354 --- /dev/null +++ b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/welcome/index.qmd @@ -0,0 +1,12 @@ +--- +title: "Welcome To My Blog" +author: "Tristan O'Malley" +date: "2024-10-20" +categories: [news] +--- + +This is the first post in a Quarto blog. Welcome! + +![](thumbnail.jpg) + +Since this post doesn't specify an explicit `image`, the first image in the post will be used in the listing page of posts. diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/posts/welcome/thumbnail.jpg b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/welcome/thumbnail.jpg new file mode 100644 index 0000000000..8e3107c9e0 Binary files /dev/null and b/tests/docs/smoke-all/2024/10/23/issue-10829/posts/welcome/thumbnail.jpg differ diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/profile.jpg b/tests/docs/smoke-all/2024/10/23/issue-10829/profile.jpg new file mode 100644 index 0000000000..9d50b914ff Binary files /dev/null and b/tests/docs/smoke-all/2024/10/23/issue-10829/profile.jpg differ diff --git a/tests/docs/smoke-all/2024/10/23/issue-10829/styles.css b/tests/docs/smoke-all/2024/10/23/issue-10829/styles.css new file mode 100644 index 0000000000..2ddf50c7b4 --- /dev/null +++ b/tests/docs/smoke-all/2024/10/23/issue-10829/styles.css @@ -0,0 +1 @@ +/* css styles */ diff --git a/tests/integration/playwright/tests/blog-simple-blog.spec.ts b/tests/integration/playwright/tests/blog-simple-blog.spec.ts index 1240c36656..b247fe71fc 100644 --- a/tests/integration/playwright/tests/blog-simple-blog.spec.ts +++ b/tests/integration/playwright/tests/blog-simple-blog.spec.ts @@ -24,9 +24,9 @@ test('Categories link are clickable', async ({ page }) => { await page.goto('./blog/simple-blog/_site/posts/welcome/'); await page.locator('div').filter({ hasText: /^news$/ }).click(); await expect(page).toHaveURL(/_site\/index\.html#category=news$/); - await expect(page.locator('div.category[data-category="news"]')).toHaveClass(/active/); + await expect(page.locator(`div.category[data-category="${btoa('news')}"]`)).toHaveClass(/active/); await page.goto('./blog/simple-blog/_site/posts/welcome/#img-lst'); await page.locator('div').filter({ hasText: /^news$/ }).click(); await expect(page).toHaveURL(/_site\/index\.html#category=news$/); - await expect(page.locator('div.category[data-category="news"]')).toHaveClass(/active/); + await expect(page.locator(`div.category[data-category="${btoa('news')}"]`)).toHaveClass(/active/); }); \ No newline at end of file