@meowdown/embed 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/x/index.js +4 -4
- package/dist/x/theme.css +124 -5
- package/package.json +1 -1
package/dist/x/index.js
CHANGED
|
@@ -259,14 +259,14 @@ function renderDate(post) {
|
|
|
259
259
|
|
|
260
260
|
//#endregion
|
|
261
261
|
//#region src/x/render-post.ts
|
|
262
|
-
function renderBody(post
|
|
262
|
+
function renderBody(post) {
|
|
263
263
|
const permalink = getPermalink(post);
|
|
264
264
|
return el("p", {
|
|
265
265
|
"data-body": "",
|
|
266
266
|
dir: "auto",
|
|
267
267
|
lang: post.lang || void 0
|
|
268
268
|
}, el("span", { "data-text": "" }, post.body.map((segment) => {
|
|
269
|
-
return segment.type === "link" ? renderLink(segment.text, segment.url) : segment.text.split(
|
|
269
|
+
return segment.type === "link" ? renderLink(segment.text, segment.url) : segment.text.split("\n").map((line, index) => {
|
|
270
270
|
return [index ? el("br", {}) : void 0, line];
|
|
271
271
|
});
|
|
272
272
|
})), post.truncated && permalink ? [" ", renderLink("Show more", permalink)] : void 0);
|
|
@@ -279,12 +279,12 @@ function renderQuoted(post, protocols) {
|
|
|
279
279
|
return el("article", {
|
|
280
280
|
"data-quoted": "",
|
|
281
281
|
"aria-label": "Quoted post"
|
|
282
|
-
}, renderAuthor(post.author, protocols, renderDate(post)), renderBody(post
|
|
282
|
+
}, renderAuthor(post.author, protocols, renderDate(post)), renderBody(post), renderMedia(post.media, protocols, getPermalink(post)), renderEdit(post));
|
|
283
283
|
}
|
|
284
284
|
function renderPost(post, protocols = null) {
|
|
285
285
|
const reply = post.replyTo;
|
|
286
286
|
const replyUrl = reply && /^\w{1,15}$/.test(reply.handle) && /^\d+$/.test(reply.id) ? `https://x.com/${reply.handle}/status/${reply.id}` : void 0;
|
|
287
|
-
return el("article", {}, renderAuthor(post.author, protocols, renderDate(post)), reply ? el("div", { "data-reply-to": "" }, renderLink(`Replying to @${reply.handle}`, replyUrl)) : void 0, renderBody(post), renderMedia(post.media, protocols, getPermalink(post)), post.quote ? renderQuoted(post.quote, protocols) : void 0, renderEdit(post));
|
|
287
|
+
return el("article", {}, el("div", { "data-content": "" }, renderAuthor(post.author, protocols, renderDate(post)), reply ? el("div", { "data-reply-to": "" }, renderLink(`Replying to @${reply.handle}`, replyUrl)) : void 0, renderBody(post), renderMedia(post.media, protocols, getPermalink(post)), post.quote ? renderQuoted(post.quote, protocols) : void 0, renderEdit(post)), el("details", { "data-show-more": "" }, el("summary", {})));
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
//#endregion
|
package/dist/x/theme.css
CHANGED
|
@@ -33,6 +33,24 @@
|
|
|
33
33
|
inherits: true;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
@property --meowdown-embed-max-height {
|
|
37
|
+
syntax: '*';
|
|
38
|
+
inherits: true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@property --_overflowing {
|
|
42
|
+
syntax: '<integer>';
|
|
43
|
+
inherits: true;
|
|
44
|
+
initial-value: 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@keyframes meowdown-embed-overflowing {
|
|
48
|
+
from,
|
|
49
|
+
to {
|
|
50
|
+
--_overflowing: 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
36
54
|
/*
|
|
37
55
|
* Hard reset. `all: revert` rolls every property on every box inside the card
|
|
38
56
|
* back to the user-agent default, so a host rule on `p`, `a`, `img`,
|
|
@@ -58,6 +76,7 @@
|
|
|
58
76
|
--_link: var(--meowdown-embed-link-color, #1d9bf0);
|
|
59
77
|
--_tint: color-mix(in srgb, currentColor 5%, transparent);
|
|
60
78
|
--_media-height: 7.5rem;
|
|
79
|
+
--_show-more-height: 2rem;
|
|
61
80
|
|
|
62
81
|
display: block;
|
|
63
82
|
/* As wide as the content, between 18rem and 28rem: a short text post stays
|
|
@@ -184,6 +203,111 @@
|
|
|
184
203
|
color: inherit;
|
|
185
204
|
}
|
|
186
205
|
|
|
206
|
+
/* Max height. The article is clipped to `--_body-limit`, the tallest
|
|
207
|
+
* article that keeps the card within `--meowdown-embed-max-height`. As a
|
|
208
|
+
* scroll container it has a scroll timeline only while the clip hides
|
|
209
|
+
* content, so the animation on that timeline sets `--_overflowing` exactly
|
|
210
|
+
* when the card is too tall. Then the article gives up one row, which the
|
|
211
|
+
* "Show more" toggle takes, so the whole card is exactly the limit. The
|
|
212
|
+
* toggle is anchored to the card's padding box, out of the article's clip.
|
|
213
|
+
* Browsers without scroll-driven animations show the whole card. */
|
|
214
|
+
& > article {
|
|
215
|
+
/* Room inside the clip for focus rings at the article's edges. */
|
|
216
|
+
--_clip-gutter: 4px;
|
|
217
|
+
--_body-limit: calc(
|
|
218
|
+
var(--meowdown-embed-max-height, 256px) - 2 * var(--meowdown-embed-padding, 1rem) - 2px + 2 *
|
|
219
|
+
var(--_clip-gutter)
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
& > article > [data-show-more] {
|
|
223
|
+
display: none;
|
|
224
|
+
}
|
|
225
|
+
& > article > [data-show-more] > summary {
|
|
226
|
+
display: block;
|
|
227
|
+
width: fit-content;
|
|
228
|
+
font-size: 0.9375em;
|
|
229
|
+
line-height: var(--_show-more-height);
|
|
230
|
+
color: var(--_link);
|
|
231
|
+
list-style: none;
|
|
232
|
+
cursor: pointer;
|
|
233
|
+
}
|
|
234
|
+
& > article > [data-show-more] > summary::-webkit-details-marker {
|
|
235
|
+
display: none;
|
|
236
|
+
}
|
|
237
|
+
& > article > [data-show-more] > summary::before {
|
|
238
|
+
content: 'Show more';
|
|
239
|
+
}
|
|
240
|
+
& > article > [data-show-more][open] > summary::before {
|
|
241
|
+
content: 'Show less';
|
|
242
|
+
}
|
|
243
|
+
& > article > [data-show-more] > summary:hover {
|
|
244
|
+
text-decoration: underline;
|
|
245
|
+
text-underline-offset: 0.15em;
|
|
246
|
+
}
|
|
247
|
+
& > article > [data-show-more] > summary:focus-visible {
|
|
248
|
+
outline: 2px solid var(--_link);
|
|
249
|
+
outline-offset: 2px;
|
|
250
|
+
border-radius: 4px;
|
|
251
|
+
}
|
|
252
|
+
@supports (animation-timeline: scroll()) {
|
|
253
|
+
& > article {
|
|
254
|
+
max-height: calc(var(--_body-limit) - var(--_overflowing) * var(--_show-more-height));
|
|
255
|
+
overflow: hidden;
|
|
256
|
+
padding: var(--_clip-gutter);
|
|
257
|
+
margin: calc(-1 * var(--_clip-gutter));
|
|
258
|
+
margin-block-end: calc(var(--_overflowing) * var(--_show-more-height) - var(--_clip-gutter));
|
|
259
|
+
animation: meowdown-embed-overflowing linear both;
|
|
260
|
+
animation-timeline: scroll(self);
|
|
261
|
+
}
|
|
262
|
+
/* Opened, or holding keyboard focus that the clip could hide. */
|
|
263
|
+
& > article:has(> [data-show-more][open]),
|
|
264
|
+
& > article:has(:focus-visible:not(summary)) {
|
|
265
|
+
max-height: none;
|
|
266
|
+
overflow: visible;
|
|
267
|
+
margin-block-end: calc(-1 * var(--_clip-gutter));
|
|
268
|
+
}
|
|
269
|
+
@container style(--_overflowing: 1) {
|
|
270
|
+
/* On the content, not the article: a mask on the article would also
|
|
271
|
+
* hide the toggle below it. */
|
|
272
|
+
& > article > [data-content] {
|
|
273
|
+
mask-image: linear-gradient(to bottom, #000 calc(100% - 3rem), transparent);
|
|
274
|
+
mask-size: 100%
|
|
275
|
+
calc(var(--_body-limit) - var(--_show-more-height) - 2 * var(--_clip-gutter));
|
|
276
|
+
mask-repeat: no-repeat;
|
|
277
|
+
}
|
|
278
|
+
& > article > [data-show-more] {
|
|
279
|
+
display: block;
|
|
280
|
+
position: absolute;
|
|
281
|
+
inset-inline-start: var(--meowdown-embed-padding, 1rem);
|
|
282
|
+
bottom: var(--meowdown-embed-padding, 1rem);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/* Opened, "Show less" sticks to the bottom of the scrollport until the
|
|
286
|
+
* card's end scrolls into view. */
|
|
287
|
+
& > article > [data-show-more][open] {
|
|
288
|
+
display: block;
|
|
289
|
+
position: sticky;
|
|
290
|
+
bottom: 0.75rem;
|
|
291
|
+
z-index: 1;
|
|
292
|
+
width: fit-content;
|
|
293
|
+
margin: 0.5rem auto 0;
|
|
294
|
+
}
|
|
295
|
+
& > article > [data-show-more][open] > summary {
|
|
296
|
+
padding: 0.375rem 0.875rem;
|
|
297
|
+
border: 1px solid var(--_hairline);
|
|
298
|
+
border-radius: 999px;
|
|
299
|
+
background: var(--meowdown-embed-background, Canvas);
|
|
300
|
+
box-shadow: 0 2px 8px rgb(0 0 0 / 12%);
|
|
301
|
+
font-size: 0.875em;
|
|
302
|
+
font-weight: 500;
|
|
303
|
+
line-height: normal;
|
|
304
|
+
}
|
|
305
|
+
& > article > [data-show-more][open] > summary:hover {
|
|
306
|
+
text-decoration: none;
|
|
307
|
+
background: color-mix(in srgb, var(--_link) 8%, var(--meowdown-embed-background, Canvas));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
187
311
|
/* Body */
|
|
188
312
|
& [data-reply-to] {
|
|
189
313
|
display: block;
|
|
@@ -353,11 +477,6 @@
|
|
|
353
477
|
align-self: center;
|
|
354
478
|
}
|
|
355
479
|
& [data-quoted] [data-body] {
|
|
356
|
-
display: -webkit-box;
|
|
357
|
-
-webkit-box-orient: vertical;
|
|
358
|
-
-webkit-line-clamp: 3;
|
|
359
|
-
line-clamp: 3;
|
|
360
|
-
overflow: hidden;
|
|
361
480
|
margin-block-start: 0.25rem;
|
|
362
481
|
font-size: 0.9375em;
|
|
363
482
|
}
|