feat: rework single post view for better content hierarchy

- Add post-type header (Reply/Like/Repost/Bookmark/Note) for titleless posts
- Add left accent border to user content on interaction posts
- Collapse AI Usage box into a compact <details> summary line
- Collapse comments section when empty, auto-open when comments exist
- Collapse webmention send form behind <details> toggle

Confab-Link: http://localhost:8080/sessions/648a550c-4f65-46be-b9a9-6b7e0fd90751
This commit is contained in:
Ricardo
2026-03-05 13:22:32 +01:00
parent be90da09e4
commit 0c6229088c
4 changed files with 146 additions and 134 deletions

View File

@@ -1,4 +1,5 @@
{# Comments section — shown on post pages before webmentions #}
{# Collapsed when empty, auto-opens when comments exist #}
{% set absoluteUrl = site.url + page.url %}
<is-land on:visible>
@@ -6,8 +7,18 @@
x-data="commentsSection('{{ absoluteUrl }}')"
x-init="init()">
<h2 class="text-xl font-bold mb-4">Comments</h2>
<details class="group" x-bind:open="comments.length > 0 || showForm">
<summary class="flex items-center justify-between cursor-pointer list-none [&::-webkit-details-marker]:hidden" @click="showForm = true">
<h2 class="text-lg font-semibold text-surface-700 dark:text-surface-300">
Comments
<span x-show="comments.length > 0" x-text="'(' + comments.length + ')'" class="text-sm font-normal" x-cloak></span>
</h2>
<svg class="w-4 h-4 text-surface-400 transition-transform group-open:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</summary>
<div class="mt-4">
{# Status messages #}
<div x-show="statusMessage" x-cloak
x-bind:class="statusType === 'error' ? 'bg-red-50 text-red-700 dark:bg-red-900/20 dark:text-red-400' :
@@ -92,5 +103,7 @@
<p class="text-sm text-surface-500">No comments yet. Be the first to share your thoughts!</p>
</template>
</div>
</div>
</details>
</section>
</is-land>

View File

@@ -175,11 +175,15 @@
</section>
{% endif %}
{# Webmention send form #}
<section class="webmention-form mt-8 p-4 bg-surface-100 dark:bg-surface-800 rounded-lg">
<h3 class="text-sm font-semibold text-surface-700 dark:text-surface-300 mb-2">
{# Webmention send form — collapsed by default #}
<details class="mt-8">
<summary class="text-sm font-semibold text-surface-600 dark:text-surface-400 cursor-pointer hover:text-surface-700 dark:hover:text-surface-300 list-none [&::-webkit-details-marker]:hidden flex items-center gap-1.5">
<svg class="w-3.5 h-3.5 transition-transform [[open]>&]:rotate-90" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
</svg>
Send a Webmention
</h3>
</summary>
<div class="mt-3 p-4 bg-surface-100 dark:bg-surface-800 rounded-lg">
<p class="text-xs text-surface-600 dark:text-surface-400 mb-3">
Have you written a response to this post? Send a webmention by entering your post URL below.
</p>
@@ -198,4 +202,5 @@
Send
</button>
</form>
</section>
</div>
</details>

View File

@@ -3,8 +3,20 @@ layout: layouts/base.njk
withBlogSidebar: true
---
<article class="h-entry post" x-data="lightbox" @keydown.window="onKeydown($event)">
{# Support both camelCase (Indiekit Eleventy preset) and underscore (legacy) property names #}
{% set bookmarkedUrl = bookmarkOf or bookmark_of %}
{% set likedUrl = likeOf or like_of %}
{% set replyTo = inReplyTo or in_reply_to %}
{% set repostedUrl = repostOf or repost_of %}
{% if title %}
<h1 class="p-name text-2xl sm:text-3xl font-bold text-surface-900 dark:text-surface-100 mb-3 sm:mb-4">{{ title }}</h1>
{% else %}
<div class="flex items-center gap-2 mb-1">
<span class="text-sm font-medium text-surface-500 dark:text-surface-400">
{% if replyTo %}&#8617; Reply{% elif likedUrl %}&#9829; Like{% elif repostedUrl %}&#9851; Repost{% elif bookmarkedUrl %}&#128278; Bookmark{% else %}&#9998; Note{% endif %}
</span>
</div>
{% endif %}
<div class="post-meta mb-4 sm:mb-6">
@@ -27,12 +39,6 @@ withBlogSidebar: true
{# Bridgy syndication content - controls what gets posted to social networks #}
{# For interaction types (bookmarks, likes, replies, reposts), include the target URL #}
{# Support both camelCase (Indiekit Eleventy preset) and underscore (legacy) property names #}
{% set bookmarkedUrl = bookmarkOf or bookmark_of %}
{% set likedUrl = likeOf or like_of %}
{% set replyTo = inReplyTo or in_reply_to %}
{% set repostedUrl = repostOf or repost_of %}
{% set bridgySummary = description or summary or (content | ogDescription(280)) %}
{% set interactionUrl = bookmarkedUrl or likedUrl or replyTo or repostedUrl %}
@@ -53,44 +59,31 @@ withBlogSidebar: true
</div>
{% endif %}
<div class="e-content prose prose-surface dark:prose-invert max-w-none">
{% set isInteraction = replyTo or likedUrl or repostedUrl or bookmarkedUrl %}
{% set hasContent = content and content | striptags | trim %}
<div class="e-content prose prose-surface dark:prose-invert max-w-none{% if isInteraction and hasContent %} border-l-[3px] border-l-accent-500 dark:border-l-accent-400 pl-4{% endif %}">
{{ content | safe }}
</div>
{# AI usage disclosure #}
{# AI usage disclosure — collapsed by default #}
{% set aiTextLevel = aiTextLevel or ai_text_level %}
{% set aiCodeLevel = aiCodeLevel or ai_code_level %}
{% set aiTools = aiTools or ai_tools %}
{% set aiDescription = aiDescription or ai_description %}
{% if aiTextLevel or aiCodeLevel or aiTools %}
<aside class="mt-6 p-4 rounded-lg bg-surface-50 dark:bg-surface-800/50 border border-surface-200 dark:border-surface-700">
<div class="flex items-center gap-2 mb-2">
<svg class="w-4 h-4 text-surface-500 dark:text-surface-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<details class="mt-4 text-xs text-surface-500 dark:text-surface-400">
<summary class="cursor-pointer hover:text-surface-600 dark:hover:text-surface-300 list-none flex items-center gap-1.5 [&::-webkit-details-marker]:hidden">
<svg class="w-3.5 h-3.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 3.104v5.714a2.25 2.25 0 01-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 014.5 0m0 0v5.714a2.25 2.25 0 00.659 1.591L19 14.5M14.25 3.104c.251.023.501.05.75.082M19 14.5l-2.47 2.47a2.25 2.25 0 01-1.59.659H9.06a2.25 2.25 0 01-1.591-.659L5 14.5m14 0V17a2 2 0 01-2 2H7a2 2 0 01-2-2v-2.5"/>
</svg>
<strong class="text-sm font-semibold text-surface-700 dark:text-surface-300">AI Usage</strong>
</div>
<div class="flex flex-wrap gap-3 text-xs text-surface-600 dark:text-surface-400">
{% if aiTextLevel %}
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded bg-surface-100 dark:bg-surface-700">
Text: {% if aiTextLevel === "0" %}None{% elif aiTextLevel === "1" %}Editorial{% elif aiTextLevel === "2" %}Co-drafted{% elif aiTextLevel === "3" %}AI-generated{% endif %}
<span>AI:
{% if aiTextLevel %}Text {% if aiTextLevel === "0" %}None{% elif aiTextLevel === "1" %}Editorial{% elif aiTextLevel === "2" %}Co-drafted{% elif aiTextLevel === "3" %}AI-generated{% endif %}{% endif %}{% if aiCodeLevel %}{% if aiTextLevel %} · {% endif %}Code {% if aiCodeLevel === "0" %}Human{% elif aiCodeLevel === "1" %}AI-assisted{% elif aiCodeLevel === "2" %}AI-generated{% endif %}{% endif %}{% if aiTools %}{% if aiTextLevel or aiCodeLevel %} · {% endif %}{{ aiTools }}{% endif %}
</span>
{% endif %}
{% if aiCodeLevel %}
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded bg-surface-100 dark:bg-surface-700">
Code: {% if aiCodeLevel === "0" %}Human{% elif aiCodeLevel === "1" %}AI-assisted{% elif aiCodeLevel === "2" %}AI-generated{% endif %}
</span>
{% endif %}
{% if aiTools %}
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded bg-surface-100 dark:bg-surface-700">
Tools: {{ aiTools }}
</span>
{% endif %}
</div>
</summary>
{% if aiDescription %}
<p class="mt-2 text-xs text-surface-500 dark:text-surface-400">{{ aiDescription }}</p>
<p class="mt-1 pl-5">{{ aiDescription }}</p>
{% endif %}
</aside>
</details>
{% endif %}
{# Rich reply context with h-cite microformat #}

View File

@@ -19,6 +19,7 @@ document.addEventListener("alpine:init", () => {
statusMessage: "",
statusType: "info",
maxLength: 2000,
showForm: false,
async init() {
await this.checkSession();