diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ece298..b9b36c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,12 +16,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add missing translation strings for author separator and conjunctions.
- Add shortcode for Mastodon post embedding.
- Add support for Fuse.js search (#101).
+- Add support for preview cards in comments.
- Add the ability to set video attributes via shortcode.
### Changed
- **[BREAKING]** Rename `nav-bg` CSS variable to `glass-bg`.
- **[BREAKING]** Rename the visually hidden `hidden` class to `visually-hidden`. `hidden` is now used to completely hide the elements, including screen readers.
+- Add default width/height to the `icon` class.
+- Improve the look of threads in comments.
- Make `emoji` class available outside of comments.
- Make the code and styling for article cards much cleaner.
- Make the shortcodes code much cleaner.
@@ -35,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Fix article cards missing a focus outline.
+- Fix hover state of custom emojis in comments.
+- Fix hover state of the "Load Comments" button.
- Fix navbar mods having broken border radius.
## [5.4.0](https://codeberg.org/daudix/duckquill/compare/v5.3.2...v5.4.0)
diff --git a/content/blog/the-quill-of-duck/index.md b/content/blog/the-quill-of-duck/index.md
index cc0b0d6..826c15a 100644
--- a/content/blog/the-quill-of-duck/index.md
+++ b/content/blog/the-quill-of-duck/index.md
@@ -31,6 +31,10 @@ disclaimer = """
# user = "cassidy"
# id = "112774854109302186"
#
+# Thread with preview cards
+# host = "mastodon.blaede.family"
+# user = "cassidy"
+# id = "110669429936617026"
# Post on GoToSocial
#
# host = "alpha.polymaths.social"
diff --git a/sass/_alerts.scss b/sass/_alerts.scss
index 685dd8f..ac6eb92 100644
--- a/sass/_alerts.scss
+++ b/sass/_alerts.scss
@@ -81,8 +81,6 @@ blockquote {
.icon {
vertical-align: -0.125em;
margin-inline-end: 0.25rem;
- width: 1rem;
- height: 1rem;
}
}
}
diff --git a/sass/_article-list.scss b/sass/_article-list.scss
index e476cdc..7bf1bdc 100644
--- a/sass/_article-list.scss
+++ b/sass/_article-list.scss
@@ -330,8 +330,6 @@
.icon {
vertical-align: -0.125em;
margin-inline-end: 0.25rem;
- width: 1rem;
- height: 1rem;
}
}
@@ -371,8 +369,6 @@
.icon {
transition: var(--transition);
- width: 1rem;
- height: 1rem;
:root[dir*="rtl"] & {
transform: scaleX(-1);
diff --git a/sass/_article.scss b/sass/_article.scss
index 2123740..e610c5d 100644
--- a/sass/_article.scss
+++ b/sass/_article.scss
@@ -96,8 +96,6 @@
.icon {
transition: var(--transition);
- width: 1rem;
- height: 1rem;
}
}
diff --git a/sass/_buttons.scss b/sass/_buttons.scss
index 76e1c91..7a1cf83 100644
--- a/sass/_buttons.scss
+++ b/sass/_buttons.scss
@@ -13,6 +13,19 @@ button.inline-button {
appearance: none;
cursor: pointer;
border: none;
+
+ &:disabled {
+ cursor: not-allowed;
+
+ &:hover {
+ background-color: var(--fg-muted-1);
+ color: var(--fg-muted-5);
+ }
+
+ &:active {
+ transform: none;
+ }
+ }
}
a.inline-button,
diff --git a/sass/_comments.scss b/sass/_comments.scss
index 18474fd..f536481 100644
--- a/sass/_comments.scss
+++ b/sass/_comments.scss
@@ -25,30 +25,21 @@
gap: 0.25rem;
margin-block-start: 2rem;
- #load-comments {
+ #load-comments:disabled {
--shimmer: rgb(from var(--accent-color) r g b / calc(var(--color-opacity) * 2));
+ animation: loading-shimmer var(--transition-long) ease-in-out alternate infinite;
+ transition: none;
background-image: linear-gradient(to right, var(--fg-muted-1) 50%, var(--shimmer) 75%, var(--fg-muted-1) 100%);
background-size: 200%;
background-color: transparent;
- &:disabled {
- animation: loading-shimmer var(--transition-long) ease-in-out alternate infinite;
- transition: none;
- cursor: not-allowed;
+ &:hover {
+ background-color: transparent;
+ }
- &:hover {
- background-color: transparent;
- color: var(--fg-muted-5);
- }
-
- &:active {
- transform: none;
- }
-
- @keyframes loading-shimmer {
- to {
- background-position-x: -200%;
- }
+ @keyframes loading-shimmer {
+ to {
+ background-position-x: -200%;
}
}
}
@@ -84,6 +75,16 @@
border-radius: 0.25rem;
border-inline-start: 0.25rem solid var(--fg-muted-2);
padding-inline-start: 1rem;
+
+ &:has(+ .comment-reply) {
+ border-end-start-radius: 0;
+ }
+
+ & + .comment-reply {
+ margin-block-start: -2rem;
+ border-start-start-radius: 0;
+ padding-block-start: 2rem;
+ }
}
.avatar-link {
@@ -140,7 +141,7 @@
&.op {
background-color: var(--accent-color-alpha);
- padding-inline-start: 0.625rem;
+ padding-inline-start: 0.4375rem;
color: var(--accent-color);
&:hover {
@@ -153,17 +154,18 @@
}
&::before {
- --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'%3E%3Cpath d='m1 7 3 3 7-8' style='fill:none;stroke:%23000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none'/%3E%3C/svg%3E");
+ // --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'%3E%3Cpath d='m1 7 3 3 7-8' style='fill:none;stroke:%23000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none'/%3E%3C/svg%3E");
+ --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cpath d='M5.21 1.27A3.7 3.7 0 0 1 8 0c1.113 0 2.11.492 2.79 1.27a3.68 3.68 0 0 1 2.866 1.074A3.68 3.68 0 0 1 14.73 5.21C15.54 5.914 16 6.93 16 8s-.46 2.086-1.27 2.79a3.68 3.68 0 0 1-1.074 2.866 3.68 3.68 0 0 1-2.867 1.074C10.086 15.54 9.07 16 8 16s-2.086-.46-2.79-1.27a3.68 3.68 0 0 1-2.866-1.074A3.68 3.68 0 0 1 1.27 10.79 3.7 3.7 0 0 1 0 8c0-1.113.492-2.11 1.27-2.79a3.68 3.68 0 0 1 1.074-2.866A3.68 3.68 0 0 1 5.21 1.27m5.75 5.242a.613.613 0 0 0-.437-.98.61.61 0 0 0-.562.265L7.305 9.512 5.973 8.18a.616.616 0 0 0-.868.87l1.844 1.845a.61.61 0 0 0 .485.18.63.63 0 0 0 .453-.255zm0 0'/%3E%3C/svg%3E");
-webkit-mask-image: var(--icon);
display: inline-block;
- vertical-align: -0.0625rem;
+ vertical-align: -0.1875rem;
mask-image: var(--icon);
mask-size: cover;
transition: var(--transition);
margin-inline-end: 0.25rem;
background-color: var(--accent-color);
- width: 0.75rem;
- height: 0.75rem;
+ width: 1rem;
+ height: 1rem;
content: "";
}
@@ -245,6 +247,57 @@
}
}
+ .card {
+ transition: var(--transition);
+ margin-block-start: 1rem;
+ box-shadow: var(--edge-highlight);
+ border-radius: var(--rounded-corner);
+ background-color: var(--fg-muted-1);
+ width: min(calc(var(--container-width) / 2), 100%);
+ overflow: hidden;
+ font-weight: normal;
+ text-decoration: none;
+
+ &:hover {
+ background-color: var(--fg-muted-2);
+ }
+
+ &:active {
+ transform: var(--active);
+ }
+
+ figure {
+ display: flex;
+ flex-direction: row;
+ margin: 0;
+
+ img {
+ margin: 0;
+ box-shadow: none;
+ border-radius: 0;
+ width: min(calc(var(--container-width) / 4), 50%);
+ }
+
+ figcaption {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 0.5rem;
+ padding: 1rem;
+ color: var(--fg-color);
+ font-size: var(--font-size-medium);
+ text-align: start;
+
+ p {
+ margin-block-start: 0.25rem;
+ margin-block-end: 0;
+ color: var(--fg-muted-5);
+ font-size: var(--font-size-small);
+ }
+ }
+ }
+ }
+
footer {
display: flex;
grid-area: interactions;
@@ -257,6 +310,7 @@
border-radius: 999px;
background-color: transparent;
padding: 0.5rem 0.75rem;
+ padding-inline-start: 0.625rem;
line-height: 1;
font-variant-numeric: tabular-nums;
text-decoration: none;
@@ -265,8 +319,6 @@
vertical-align: -0.125em;
transition: var(--transition-longer);
margin-inline-end: 0.25rem;
- width: 1rem;
- height: 1rem;
}
&:hover {
diff --git a/sass/_emoji.scss b/sass/_emoji.scss
index d7194ad..73840c0 100644
--- a/sass/_emoji.scss
+++ b/sass/_emoji.scss
@@ -1,9 +1,12 @@
.emoji {
- all: unset;
display: inline-block;
- vertical-align: middle;
+ vertical-align: bottom;
transition: var(--transition);
cursor: zoom-in;
+ margin: 0;
+ box-shadow: none;
+ border-radius: 0;
+ background-color: transparent;
width: 1.5em;
height: 1.5em;
diff --git a/sass/_icon.scss b/sass/_icon.scss
index 0ccbd84..77e40fd 100644
--- a/sass/_icon.scss
+++ b/sass/_icon.scss
@@ -2,6 +2,8 @@ i.icon {
display: inline-block;
mask-size: cover;
background-color: currentColor;
+ width: 1rem;
+ height: 1rem;
font-style: normal;
font-variant: normal;
line-height: 0;
diff --git a/sass/_media.scss b/sass/_media.scss
index 8db5d7e..d8d6f70 100644
--- a/sass/_media.scss
+++ b/sass/_media.scss
@@ -104,7 +104,7 @@ video {
img {
transition: var(--transition-longer);
- &:not(.no-hover, .full-bleed, [src*="#no-hover"], [src*="#full-bleed"]) {
+ &:not(.no-hover, .full-bleed, [src*="#no-hover"], [src*="#full-bleed"], .emoji) {
cursor: zoom-in;
&:hover {
diff --git a/sass/_nav.scss b/sass/_nav.scss
index 83e4ecd..15dbf76 100644
--- a/sass/_nav.scss
+++ b/sass/_nav.scss
@@ -123,8 +123,6 @@
mask-image: var(--icon);
transition: var(--transition);
margin-inline-end: 0.25rem;
- width: 1rem;
- height: 1rem;
}
}
@@ -169,8 +167,6 @@
.icon {
vertical-align: -0.125em;
transition: var(--transition);
- width: 1rem;
- height: 1rem;
}
}
diff --git a/sass/_pre-container.scss b/sass/_pre-container.scss
index becf6b4..d0628b8 100644
--- a/sass/_pre-container.scss
+++ b/sass/_pre-container.scss
@@ -55,8 +55,6 @@
-webkit-mask-image: var(--icon);
mask-image: var(--icon);
transition: var(--transition);
- width: 1rem;
- height: 1rem;
:root[dir*="rtl"] & {
transform: scaleX(-1);
diff --git a/sass/_statements.scss b/sass/_statements.scss
index b9679eb..fcb2087 100644
--- a/sass/_statements.scss
+++ b/sass/_statements.scss
@@ -25,8 +25,6 @@
.icon {
margin-inline-end: 0.375rem;
- width: 1rem;
- height: 1rem;
}
}
diff --git a/static/comments.js b/static/comments.js
index 99d752c..e0b5ba0 100644
--- a/static/comments.js
+++ b/static/comments.js
@@ -105,6 +105,12 @@ function loadComments() {
status.content = emojify(status.content, status.emojis);
+ let comment = document.createElement("article");
+ comment.id = `comment-${status.id}`;
+ comment.className = isReply ? "comment comment-reply" : "comment";
+ comment.setAttribute("itemprop", "comment");
+ comment.setAttribute("itemtype", "http://schema.org/Comment");
+
let avatarSource = document.createElement("source");
avatarSource.setAttribute(
"srcset",
@@ -143,6 +149,7 @@ function loadComments() {
`${viewProfileText} @${status.account.username}@${instance}`
);
avatar.appendChild(avatarPicture);
+ comment.appendChild(avatar);
let instanceBadge = document.createElement("a");
instanceBadge.className = "instance";
@@ -164,6 +171,7 @@ function loadComments() {
header.className = "author";
header.appendChild(display);
header.appendChild(instanceBadge);
+ comment.appendChild(header);
let permalink = document.createElement("a");
permalink.setAttribute("href", status.url);
@@ -181,10 +189,12 @@ function loadComments() {
timestamp.setAttribute("datetime", status.created_at);
timestamp.appendChild(permalink);
permalink.classList.add("external");
+ comment.appendChild(timestamp);
let main = document.createElement("main");
main.setAttribute("itemprop", "text");
main.innerHTML = status.content;
+ comment.appendChild(main);
let attachments = status.media_attachments;
let SUPPORTED_MEDIA = ["image", "video", "gifv", "audio"];
@@ -267,6 +277,8 @@ function loadComments() {
media.appendChild(mediaLink);
}
});
+
+ comment.appendChild(media);
}
let interactions = document.createElement("footer");
@@ -292,25 +304,41 @@ function loadComments() {
faves.appendChild(favesIcon);
faves.insertAdjacentHTML('beforeend', ` ${status.favourites_count}`);
interactions.appendChild(faves);
-
- let comment = document.createElement("article");
- comment.id = `comment-${status.id}`;
- comment.className = isReply ? "comment comment-reply" : "comment";
- comment.setAttribute("itemprop", "comment");
- comment.setAttribute("itemtype", "http://schema.org/Comment");
- comment.appendChild(avatar);
- comment.appendChild(header);
- comment.appendChild(timestamp);
- comment.appendChild(main);
- if (
- attachments &&
- Array.isArray(attachments) &&
- attachments.length > 0
- ) {
- comment.appendChild(media);
- }
comment.appendChild(interactions);
+ if (status.card != null) {
+ let cardFigure = document.createElement("figure");
+
+ if (status.card.image != null) {
+ let cardImg = document.createElement("img");
+ cardImg.setAttribute("src", status.card.image);
+ cardImg.classList.add("no-hover");
+ cardFigure.appendChild(cardImg);
+ }
+
+ let cardCaption = document.createElement("figcaption");
+
+ let cardTitle = document.createElement("strong");
+ cardTitle.innerHTML = status.card.title;
+ cardCaption.appendChild(cardTitle);
+
+ if (status.card.description != null && status.card.description.length > 0) {
+ let cardDescription = document.createElement("p");
+ cardDescription.innerHTML = status.card.description;
+ cardCaption.appendChild(cardDescription);
+ }
+
+ cardFigure.appendChild(cardCaption);
+
+ let card = document.createElement("a");
+ card.className = "card";
+ card.setAttribute("href", status.card.url);
+ card.setAttribute("rel", relAttributes);
+ card.appendChild(cardFigure);
+
+ comment.appendChild(card);
+ }
+
if (op === true) {
comment.classList.add("op");
diff --git a/templates/article.html b/templates/article.html
index 1d2da16..19f813d 100644
--- a/templates/article.html
+++ b/templates/article.html
@@ -135,62 +135,7 @@
{%- if page.extra.comments.id -%}
- {%- if page.extra.comments.host -%}
- {%- set host = page.extra.comments.host -%}
- {%- else -%}
- {%- set host = config.extra.comments.host -%}
- {%- endif -%}
-
- {%- if page.extra.comments.user -%}
- {%- set user = page.extra.comments.user -%}
- {%- else %}
- {%- set user = config.extra.comments.user -%}
- {%- endif -%}
-
- {%- set id = page.extra.comments.id -%}
-
- {%- set date_locale = macros_translate::translate(key="date_locale", default="en-US", language_strings=language_strings) | replace(from="_", to="-") -%}
-
- {{ rel_attributes }}
- {{ host }}
- {{ user }}
- {{ id }}
- {{ date_locale }}
- {{ macros_translate::translate(key='loading', default='Loading', language_strings=language_strings) }}…
- {{ macros_translate::translate(key='reload', default='Reload', language_strings=language_strings) }}
- {{ macros_translate::translate(key="view_profile", default="View Profile At", language_strings=language_strings) }}
- {{ macros_translate::translate(key="view_comment", default="View Comment At", language_strings=language_strings) }}
- {{ macros_translate::translate(key="boosts_from", default="Boosts from $INSTANCE", language_strings=language_strings) }}
- {{ macros_translate::translate(key="faves_from", default="Favorites from $INSTANCE", language_strings=language_strings) }}
-
- {{ macros_translate::translate(key='no_comments', default='No Comments yet :/', language_strings=language_strings) }}
-
- {{ rel_attributes }}
+{{ host }}
+{{ user }}
+{{ id }}
+{{ date_locale }}
+{{ macros_translate::translate(key='loading', default='Loading', language_strings=language_strings) }}…
+{{ macros_translate::translate(key='reload', default='Reload', language_strings=language_strings) }}
+{{ macros_translate::translate(key="view_profile", default="View Profile At", language_strings=language_strings) }}
+{{ macros_translate::translate(key="view_comment", default="View Comment At", language_strings=language_strings) }}
+{{ macros_translate::translate(key="boosts_from", default="Boosts from $INSTANCE", language_strings=language_strings) }}
+{{ macros_translate::translate(key="faves_from", default="Favorites from $INSTANCE", language_strings=language_strings) }}
+
+{{ macros_translate::translate(key='no_comments', default='No Comments yet :/', language_strings=language_strings) }}
+
+{%- if page.extra.comments.uri -%}
+ {%- set uri = page.extra.comments.uri -%}
+
+{%- endif -%}
+
+ {{ macros_translate::translate(key="comments_description", default="You can comment on this blog post by publicly replying to this post using a Mastodon or other ActivityPub/Fediverse account. Known non-private replies are displayed below.", language_strings=language_strings) }}
+ {%- endif -%}
+
{{ macros_translate::translate(key="comments", default="Comments", language_strings=language_strings) }}
+
{{ macros_translate::translate(key="comments", default="Comments", language_strings=language_strings) }}
-{{ macros_translate::translate(key="comments_description", default="You can comment on this blog post by publicly replying to this post using a Mastodon or other ActivityPub/Fediverse account. Known non-private replies are displayed below.", language_strings=language_strings) }}
-