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

fix: Markdown support in listings templates #11760

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
31 changes: 14 additions & 17 deletions src/resources/projects/website/listing/_filter.ejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,29 @@ const sortUi = listing['sort-ui'];
<% const sortableFields = listing.utilities.sortableFieldData(); %>
<% if (sortUi && sortableFields.length > 0) { %>
<div class="input-group input-group-sm quarto-listing-sort">
<span class="input-group-text"><i class="bi bi-sort-down"></i></span>
<select
<span class="input-group-text"><i class="bi bi-sort-down"></i></span>
<select
id="listing-<%- listing.id %>-sort"
class="form-select"
aria-label="<%- listing.utilities.localizedString("listing-page-order-by")%>"
aria-label="<%= listing.utilities.localizedString("listing-page-order-by") %>"
onChange="window['quarto-listings']['listing-<%- listing.id %>'].sort(this.options[this.selectedIndex].value, { order: this.options[this.selectedIndex].getAttribute('data-direction')})"
>
<option value="" disabled selected hidden><%- listing.utilities.localizedString("listing-page-order-by")%></option>
<option value="index" data-direction="asc"><%- listing.utilities.localizedString("listing-page-order-by-default")%></option>
<% for (const sortData of sortableFields) { %>
<option
value="<%- sortData.listingSort.field %>"
data-direction="<%- sortData.listingSort.direction %>">
<%= sortData.description %>
</option>
<% } %>
</select>
<option value="" disabled selected hidden><%= listing.utilities.localizedString("listing-page-order-by") %></option>
<option value="index" data-direction="asc"><%= listing.utilities.localizedString("listing-page-order-by-default") %></option>
<% for (const sortData of sortableFields) { %>
<option
value="<%- sortData.listingSort.field %>"
data-direction="<%- sortData.listingSort.direction %>">
<%= sortData.description %>
</option>
<% } %>
</select>
</div>


<% } %>

<% if (filterUi) { %>
<div class="input-group input-group-sm quarto-listing-filter">
<span class="input-group-text"><i class="bi bi-search"></i></span>
<input type="text" class="search form-control" placeholder="<%- listing.utilities.localizedString("listing-page-filter")%>" />
<input type="text" class="search form-control" placeholder="<%= listing.utilities.localizedString("listing-page-filter") %>" />
</div>
<% } %>
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/resources/projects/website/listing/_metadata.ejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
const categories = item.categories !== undefined ? item.categories.join(',') : undefined;
%>

<div class="quarto-listing-item-metadata" style-"display:none;">
```{=html}
<div class="quarto-listing-item-metadata" style="display:none;">
<span class="original-value" data-original-value="${itemNumber}" style="display:none;"></span>
<% if (categories !== undefined) { %><span class="categories" data-categories="${categories}" style="display:none;"></span><% } %>
</div>
```
6 changes: 3 additions & 3 deletions src/resources/projects/website/listing/_pagination.ejs.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div class="listing-no-matching d-none"><%- listing.utilities.localizedString("listing-page-no-matches")%></div>
<% if (listing["page-size"] < items.length) { %>
```{=html}
<div class="listing-no-matching d-none"><%= listing.utilities.localizedString("listing-page-no-matches") %></div>
<% if (listing["page-size"] < items.length) { %>
<nav id="<%- listing.id %>-pagination" class="listing-pagination" aria-label="Page Navigation">
<ul class="pagination"></ul>
</nav>
```
<% } %>
```
86 changes: 68 additions & 18 deletions src/resources/projects/website/listing/item-default.ejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,44 +31,94 @@ return value;

let value = readField(item, field);
if (value !== undefined) {
print(`<div class="metadata-value listing-${field}">${listing.utilities.outputLink(item, field, value)}</div>`);
print(`<div class="metadata-value listing-${field}">${listing.utilities.outputLink(item, field, value)}</div>`);
}
}
%>

<div class="quarto-post image-<%= imageAlign %>" <%= listing.utilities.metadataAttrs(item) %>>
::: {.quarto-post .image-<%= imageAlign %> <%= listing.utilities.metadataAttrs(item) %>}
mcanouil marked this conversation as resolved.
Show resolved Hide resolved

<% if (fields.includes('image')) { %>
<div class="thumbnail">
<a href="<%- item.path %>" class="no-external">

```{=html}
<div class="thumbnail"><a href="<%- item.path %>" class="no-external">
<% if (item.image) { %>
<%= listing.utilities.img(itemNumber, item.image, "thumbnail-image", item['image-alt'], item['image-lazy-loading'] ?? listing['image-lazy-loading']) %>
<% } else { %>
<%= listing.utilities.imgPlaceholder(listing.id, itemNumber, item.outputHref) %>
<% } %>
</a>
</div>
</a></div>
```

<% } %>
<div class="body">

::: {.body}

<% if (fields.includes('title')) { %>
<h3 class="no-anchor listing-title"><a href="<%- item.path %>" class="no-external"><%= item.title %></a></h3>
<% if (fields.includes('subtitle')) { %>
<div class="listing-subtitle"><a href="<%- item.path %>" class="no-external"><%= item.subtitle %></a></div>
Comment on lines 58 to 60
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No raw block to avoid <p> being added.

<% } %>
<% if (fields.includes('categories') && item.categories) { %>
<% } %>

<% if (fields.includes('categories') && item.categories) { %>

```{=html}
<div class="listing-categories">
<% for (const category of item.categories) { %>
<div class="listing-category" onclick="window.quartoListingCategory('<%=utils.b64encode(category)%>'); return false;"><%= category %></div>
<div class="listing-category" onclick="window.quartoListingCategory('<%= utils.b64encode(category) %>'); return false;"><%= category %></div>
<% } %>
</div>
<% } %>
```

<% } %>

<% if (fields.includes('description')) { %>
<div class="delink listing-description"><a href="<%- item.path %>" class="no-external"><%= item.description %></a></div>

```{=html}
<div class="delink listing-description"><a href="<%- item.path %>" class="no-external">
```

<%= item.description %>

```{=html}
</a></div>
```

<% } %>
</div>
<div class="metadata"><a href="<%- item.path %>" class="no-external">
<% if (fields.includes('date') && item.date) { %><div class="listing-date"><%= item.date %></div><% } %>
<% if (fields.includes('author') && item.author) { %><div class="listing-author"><%= item.author %></div><% } %>
<% if (fields.includes('reading-time') && item['reading-time']) { %> <div class="listing-reading-time"><%= item['reading-time'] %></div> <% } %>

:::

::: {.metadata}

```{=html}
<a href="<%- item.path %>" class="no-external">
```

<% if (fields.includes('date') && item.date) { %>
<div class="listing-date"><%= item.date %></div>
<% } %>

<% if (fields.includes('author') && item.author) { %>
<div class="listing-author"><%= item.author %></div>
<% } %>
Comment on lines +98 to +104
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No raw block to avoid <p> being added.


<% if (fields.includes('reading-time') && item['reading-time']) { %>

```{=html}
<div class="listing-reading-time"><%= item['reading-time'] %></div>
```

<% } %>

<% for (const field of otherFields) { %>
<% outputMetadata(item, field) %><% } %></a></div>
<% outputMetadata(item, field) %>
<% } %>

</div>
```{=html}
</a>
```

:::

:::
120 changes: 92 additions & 28 deletions src/resources/projects/website/listing/item-grid.ejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,83 +37,147 @@ return !["title", "image", "image-alt", "date", "author", "subtitle", "descripti
});
%>

<div class="g-col-1" <%= listing.utilities.metadataAttrs(item) %>>
::: {.g-col-1 <%= listing.utilities.metadataAttrs(item) %> }
mcanouil marked this conversation as resolved.
Show resolved Hide resolved

```{=html}
<a href="<%- item.path %>" class="quarto-grid-link">
<div class="quarto-grid-item card h-100 <%-`card-${align}`%><%= hideBorders ? ' borderless' : '' %>">
<div class="quarto-grid-item card h-100 <%= `card-${align}` %><%= hideBorders ? ' borderless' : '' %>">
```

<% if (fields.includes('image')) { %>

<% if (item.image) { %>

```{=html}
<p class="card-img-top">
<%= listing.utilities.img(itemNumber, item.image, "thumbnail-image card-img", item['image-alt'], item['image-lazy-loading'] ?? listing['image-lazy-loading']) %>
</p>
```

<% } else { %>

```{=html}
<%= listing.utilities.imgPlaceholder(listing.id, itemNumber, item.outputHref) %>
<% } %>
```

<% } %>
<% } %>

<% if (showField('title') || showField('subtitle') || showField('description') || showField('author') || showField('date') || otherFields.length > 0) { %>

<div class="card-body post-contents">
<% if (showField('title')) { %><h5 class="no-anchor card-title listing-title"><%= item.title %></h5><% } %>
<% if (showField('subtitle')) { %><div class="card-subtitle listing-subtitle"><%= item.subtitle %></div><% } %>
<% if (showField('reading-time')) { %><div class="listing-reading-time card-text text-muted"><%= item['reading-time'] %></div> <% } %>
::: {.card-body .post-contents}

<% if (showField('title')) { %>
<h5 class="no-anchor card-title listing-title"><%= item.title %></h5>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No raw block to avoid <p> being added.

<% } %>

<% if (showField('subtitle')) { %>
<div class="card-subtitle listing-subtitle"><%= item.subtitle %></div>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No raw block to avoid <p> being added.

<% } %>

<% if (showField('reading-time')) { %>

```{=html}
<div class="listing-reading-time card-text text-muted"><%= item['reading-time'] %></div>
```

<% } %>

<% if (fields.includes('categories') && item.categories) { %>

```{=html}
<div class="listing-categories">
<% for (const category of item.categories) { %>
<div class="listing-category" onclick="window.quartoListingCategory('<%=utils.b64encode(category)%>'); return false;"><%= category %></div>
<% } %>
<% for (const category of item.categories) { %>
<div class="listing-category" onclick="window.quartoListingCategory('<%= utils.b64encode(category ) %>'); return false;"><%= category %></div>
<% } %>
</div>
```

<% } %>

<% if (showField('description')) { %>

<div class="card-text listing-description delink"><%= item.description %></div>
```{=html}
<div class="card-text listing-description delink">
```

<%= item.description %>

```{=html}
</div>
```

<% } %>
<%

<%
const flexJustify = showField('author') && showField('date') ? "justify" : showField('author') ? "start" : "end";
%>

<% if (showField('author') || showField('date')) { %>
<div class="card-attribution card-text-small <%-flexJustify%>">
<% if (showField('author')) { %><div class="listing-author"><%= item.author %></div><% } %>
<% if (showField('date')) { %><div class="listing-date"><%= item.date %></div><% } %>

```{=html}
<div class="card-attribution card-text-small <%- flexJustify %>">
```

<% if (showField('author')) { %>
<div class="listing-author"><%= item.author %></div>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No raw block to avoid <p> being added.

<% } %>

<% if (showField('date')) { %>
<div class="listing-date"><%= item.date %></div>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No raw block to avoid <p> being added.

<% } %>

```{=html}
</div>
```

<% } %>

<% if (otherFields.length > 0) { %>

```{=html}
<table class="card-other-values">
<% for (const field of otherFields) {
let value = readField(item, field);
<% for (const field of otherFields) {
let value = readField(item, field);
%>
<tr>
<td><%= listing.utilities.fieldName(field) %></td>
<td class="<%-field%>"><%= listing.utilities.outputLink(item, field, value) %></td>
<td class="<%- field %>"><%= listing.utilities.outputLink(item, field, value) %></td>
</tr>
<% } %>
</table>
```
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No markdown supports in metadata with this.
Splitting this to allow markdown for listing.utilities.fieldName(field) and listing.utilities.outputLink(item, field, value) will lead to <p> being added.

Copy link
Collaborator Author

@mcanouil mcanouil Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency until there is a decision, I switched to using raw blocks except for the lines with the variables to allow markdown.

9c43d63

This means, there is still inline HTML.


<% } %>

</div>
:::
<% } %>

<% if (fields.includes('filename') || fields.includes('file-modified')) { %>

<div class="card-footer">
::: {.card-footer}

<% if (fields.includes('filename')) { %>
<div class="card-filename listing-filename">
<%= item.filename ? item.filename : "&nbsp;" %>
</div>

```{=html}
<div class="card-filename listing-filename"><%= item.filename ? item.filename : "&nbsp;" %></div>
```

<% } %>

<% if (fields.includes('file-modified')) { %>
<div class="card-file-modified listing-file-modified">
<%= item['file-modified'] ? item['file-modified'] : "&nbsp;"%>
</div>

```{=html}
<div class="card-file-modified listing-file-modified"><%= item['file-modified'] ? item['file-modified'] : "&nbsp;" %></div>
```

<% } %>
</div>

:::
<% } %>
</div></a></div>

```{=html}
</div></a>
```

:::
6 changes: 3 additions & 3 deletions src/resources/projects/website/listing/listing-default.ejs.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
:::{.list .quarto-listing-default}
``````{=html}
::: {.list .quarto-listing-default}

<% for (const item of items) { %>
<% partial('item-default.ejs.md', {listing, item, utils }) %>
<% } %>
``````

:::
6 changes: 3 additions & 3 deletions src/resources/projects/website/listing/listing-grid.ejs.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
const cols = listing['grid-columns'];
%>

:::{.list .grid .quarto-listing-cols-<%=cols%>}
```{=html}
::: {.list .grid .quarto-listing-cols-<%= cols %>}

<% for (const item of items) { %>
<% partial('item-grid.ejs.md', {listing, item, utils }) %>
<% } %>
```

:::
Loading
Loading