Files
indiekit-endpoint-activitypub/assets/reader-links.css
Ricardo 5ff3197493 feat: add internal AP link resolution and OpenGraph card unfurling (v1.1.14)
Reader now resolves ActivityPub links internally instead of navigating
to external instances. Actor links open the profile view, post links
open a new post detail view with thread context (parent chain + replies).

External links in post content get rich preview cards (title, description,
image, favicon) fetched via unfurl.js at ingest time with fire-and-forget
async processing and concurrency limiting.

New files: post-detail controller, og-unfurl module, lookup-cache,
link preview template/CSS, client-side link interception JS.
Includes SSRF protection for OG fetching and GoToSocial URL support.
2026-02-21 18:32:12 +01:00

152 lines
2.9 KiB
CSS

/**
* OpenGraph link preview cards and AP link interception
* Styles for link preview cards in the ActivityPub reader
*/
/* Link preview container */
.ap-link-previews {
margin-top: var(--space-m);
display: flex;
flex-direction: column;
gap: var(--space-s);
}
/* Individual link preview card */
.ap-link-preview {
display: flex;
overflow: hidden;
border-radius: var(--border-radius-small);
border: 1px solid var(--color-neutral-lighter);
background-color: var(--color-offset);
text-decoration: none;
color: inherit;
transition: border-color 0.2s ease;
}
.ap-link-preview:hover {
border-color: var(--color-primary);
}
/* Text content area (left side) */
.ap-link-preview__text {
flex: 1;
padding: var(--space-s);
min-width: 0; /* Enable text truncation */
}
.ap-link-preview__title {
font-weight: 600;
font-size: 0.875rem;
color: var(--color-on-background);
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ap-link-preview__desc {
font-size: 0.75rem;
color: var(--color-on-offset);
margin: var(--space-xs) 0 0;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.ap-link-preview__domain {
font-size: 0.75rem;
color: var(--color-neutral);
margin: var(--space-s) 0 0;
display: flex;
align-items: center;
gap: 0.25rem;
}
.ap-link-preview__favicon {
width: 1rem;
height: 1rem;
display: inline-block;
}
/* Image area (right side) */
.ap-link-preview__image {
flex-shrink: 0;
width: 6rem;
height: 6rem;
}
.ap-link-preview__image img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Responsive - larger images on desktop */
@media (min-width: 640px) {
.ap-link-preview__image {
width: 8rem;
height: 8rem;
}
.ap-link-preview__title {
font-size: 1rem;
}
.ap-link-preview__desc {
font-size: 0.875rem;
}
}
/* Post detail thread view */
.ap-post-detail__back {
margin-bottom: var(--space-m);
}
.ap-post-detail__back-link {
font-size: 0.875rem;
color: var(--color-primary);
text-decoration: none;
}
.ap-post-detail__back-link:hover {
text-decoration: underline;
}
.ap-post-detail__section-title {
font-size: 0.875rem;
font-weight: 600;
color: var(--color-neutral);
text-transform: uppercase;
letter-spacing: 0.05em;
margin: var(--space-l) 0 var(--space-s);
padding-bottom: var(--space-xs);
border-bottom: 1px solid var(--color-neutral-lighter);
}
.ap-post-detail__main {
margin: var(--space-m) 0;
}
.ap-post-detail__parents,
.ap-post-detail__replies {
margin: var(--space-m) 0;
}
.ap-post-detail__parent-item,
.ap-post-detail__reply-item {
margin-bottom: var(--space-s);
}
/* Thread connector line between parent posts */
.ap-post-detail__parents .ap-post-detail__parent-item {
position: relative;
padding-left: var(--space-m);
border-left: 2px solid var(--color-neutral-lighter);
}
/* Main post highlight */
.ap-post-detail__main .ap-card {
border-left-width: 3px;
}