@jant/core 0.5.4 → 0.6.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/bin/commands/telegram/register-webhooks.js +93 -0
- package/dist/{app-BtNdUAqz.js → app-BIkkbVQk.js} +2252 -383
- package/dist/app-Bcr5_wZI.js +6 -0
- package/dist/client/.vite/manifest.json +3 -3
- package/dist/client/_assets/client-Bo7sKkAQ.js +274 -0
- package/dist/client/_assets/client-QHRvzZwk.css +2 -0
- package/dist/client/_assets/{client-auth-DJ_5wx9N.js → client-auth-D1jDQgbH.js} +81 -81
- package/dist/{env-CgaH9Mut.js → env-C7e2Nlnt.js} +30 -1
- package/dist/{export-CR9Megtb.js → export-Bbn86HmS.js} +1 -1
- package/dist/{github-sync-DYZq9rQp.js → github-sync-CBQPRZ8H.js} +1 -1
- package/dist/{github-sync-8Vv06aCr.js → github-sync-dXsiZa_e.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/node.js +61 -5
- package/package.json +2 -1
- package/src/__tests__/helpers/app.ts +15 -2
- package/src/app.tsx +3 -0
- package/src/client/thread-context.ts +146 -2
- package/src/client/tiptap/__tests__/link-toolbar.test.ts +1 -1
- package/src/client/tiptap/bubble-menu.ts +1 -16
- package/src/client/tiptap/extensions.ts +2 -6
- package/src/client/tiptap/link-toolbar.ts +0 -21
- package/src/client/tiptap/toolbar-mode.ts +0 -43
- package/src/db/migrations/0022_old_gressill.sql +24 -0
- package/src/db/migrations/0023_broad_terror.sql +20 -0
- package/src/db/migrations/0024_red_the_twelve.sql +3 -0
- package/src/db/migrations/0025_exotic_wendell_rand.sql +1 -0
- package/src/db/migrations/meta/0022_snapshot.json +2267 -0
- package/src/db/migrations/meta/0023_snapshot.json +2396 -0
- package/src/db/migrations/meta/0024_snapshot.json +2417 -0
- package/src/db/migrations/meta/0025_snapshot.json +2424 -0
- package/src/db/migrations/meta/_journal.json +28 -0
- package/src/db/migrations/pg/0020_bizarre_smasher.sql +24 -0
- package/src/db/migrations/pg/0021_sharp_puppet_master.sql +20 -0
- package/src/db/migrations/pg/0022_blushing_blue_shield.sql +3 -0
- package/src/db/migrations/pg/0023_organic_zemo.sql +1 -0
- package/src/db/migrations/pg/meta/0020_snapshot.json +2904 -0
- package/src/db/migrations/pg/meta/0021_snapshot.json +3060 -0
- package/src/db/migrations/pg/meta/0022_snapshot.json +3078 -0
- package/src/db/migrations/pg/meta/0023_snapshot.json +3084 -0
- package/src/db/migrations/pg/meta/_journal.json +28 -0
- package/src/db/pg/schema.ts +82 -0
- package/src/db/schema.ts +90 -0
- package/src/i18n/coverage.generated.ts +2 -2
- package/src/i18n/locales/public/en.po +8 -0
- package/src/i18n/locales/public/zh-Hans.po +8 -0
- package/src/i18n/locales/public/zh-Hant.po +8 -0
- package/src/i18n/locales/settings/en.po +135 -0
- package/src/i18n/locales/settings/en.ts +1 -1
- package/src/i18n/locales/settings/zh-Hans.po +136 -1
- package/src/i18n/locales/settings/zh-Hans.ts +1 -1
- package/src/i18n/locales/settings/zh-Hant.po +136 -1
- package/src/i18n/locales/settings/zh-Hant.ts +1 -1
- package/src/lib/__tests__/image-dimensions.test.ts +314 -0
- package/src/lib/__tests__/telegram-entities.test.ts +180 -0
- package/src/lib/__tests__/telegram-pool-webhooks.test.ts +127 -0
- package/src/lib/env.ts +45 -0
- package/src/lib/ids.ts +3 -0
- package/src/lib/image-dimensions.ts +258 -0
- package/src/lib/telegram-entities.ts +240 -0
- package/src/lib/telegram-pool-webhooks.ts +86 -0
- package/src/lib/telegram-settings-status.tsx +109 -0
- package/src/lib/telegram.ts +363 -0
- package/src/node/runtime.ts +6 -0
- package/src/routes/api/__tests__/telegram.test.ts +612 -0
- package/src/routes/api/telegram.ts +782 -0
- package/src/routes/api/upload-multipart.ts +34 -12
- package/src/routes/api/upload.ts +23 -2
- package/src/routes/dash/settings.tsx +131 -1
- package/src/routes/pages/__tests__/post-page-title.test.ts +70 -0
- package/src/routes/pages/page.tsx +3 -2
- package/src/runtime/cloudflare.ts +20 -9
- package/src/runtime/node.ts +20 -9
- package/src/runtime/site.ts +2 -1
- package/src/services/__tests__/telegram.test.ts +148 -0
- package/src/services/index.ts +9 -0
- package/src/services/telegram.ts +613 -0
- package/src/services/upload-session.ts +39 -12
- package/src/styles/tokens.css +1 -0
- package/src/styles/ui.css +116 -38
- package/src/types/app-context.ts +6 -0
- package/src/types/bindings.ts +3 -0
- package/src/types/config.ts +40 -0
- package/src/ui/dash/settings/SettingsRootContent.tsx +48 -17
- package/src/ui/dash/settings/TelegramContent.tsx +549 -0
- package/src/ui/feed/ThreadPreview.tsx +91 -38
- package/src/ui/feed/__tests__/thread-preview.test.ts +67 -5
- package/src/ui/pages/PostPage.tsx +78 -15
- package/dist/app-DLINgGBd.js +0 -6
- package/dist/client/_assets/client-BErXNT6k.css +0 -2
- package/dist/client/_assets/client-CtAgWT8i.js +0 -274
|
@@ -196,7 +196,7 @@ describe("getThreadPreviewState", () => {
|
|
|
196
196
|
expect(html).not.toContain('id="continue"');
|
|
197
197
|
});
|
|
198
198
|
|
|
199
|
-
it("
|
|
199
|
+
it("wraps ancestor context in a collapsible shell with a show-more toggle when 2+ extra items precede the latest reply", () => {
|
|
200
200
|
const html = renderWithI18n(() =>
|
|
201
201
|
ThreadPreview({
|
|
202
202
|
rootPost: createPostView({
|
|
@@ -227,10 +227,72 @@ describe("getThreadPreviewState", () => {
|
|
|
227
227
|
}),
|
|
228
228
|
);
|
|
229
229
|
|
|
230
|
-
expect(html).
|
|
231
|
-
expect(html).
|
|
232
|
-
expect(html).
|
|
233
|
-
expect(html).
|
|
230
|
+
expect(html).toContain("thread-context-shell");
|
|
231
|
+
expect(html).toContain("data-thread-context");
|
|
232
|
+
expect(html).toContain("data-collapsed");
|
|
233
|
+
expect(html).toContain("thread-context-fade");
|
|
234
|
+
expect(html).toContain("data-thread-context-toggle");
|
|
235
|
+
expect(html).toContain('aria-expanded="false"');
|
|
236
|
+
expect(html).toMatch(/data-label-more="[^"]+"/);
|
|
237
|
+
expect(html).toMatch(/data-label-less="[^"]+"/);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("still wraps a root-only preview in the shell so the cap applies to long single posts", () => {
|
|
241
|
+
// root + hero — no second/penultimate/gap. The server can't know the
|
|
242
|
+
// root's rendered height, so it always renders the shell + toggle and
|
|
243
|
+
// lets client-side measurement strip them when the root actually fits.
|
|
244
|
+
const html = renderWithI18n(() =>
|
|
245
|
+
ThreadPreview({
|
|
246
|
+
rootPost: createPostView({ bodyHtml: "<p>Root</p>" }),
|
|
247
|
+
latestReply: createPostView({
|
|
248
|
+
id: "post-2",
|
|
249
|
+
permalink: "/post-2",
|
|
250
|
+
slug: "post-2",
|
|
251
|
+
bodyHtml: "<p>Latest</p>",
|
|
252
|
+
isLastInThread: true,
|
|
253
|
+
}),
|
|
254
|
+
totalReplyCount: 1,
|
|
255
|
+
}),
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
expect(html).toContain("thread-context-shell");
|
|
259
|
+
expect(html).toContain("data-collapsed");
|
|
260
|
+
expect(html).toContain("data-thread-context-toggle");
|
|
261
|
+
expect(html).toContain("<p>Root</p>");
|
|
262
|
+
expect(html).toContain("<p>Latest</p>");
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it("renders the collapsible shell even when just one extra item precedes the latest reply", () => {
|
|
266
|
+
// root + secondReply + hero — one extra context item. The server can't
|
|
267
|
+
// measure actual height, so it renders the shell assuming overflow (the
|
|
268
|
+
// common case). Client-side JS then removes the cap + hides the toggle
|
|
269
|
+
// if the rendered content actually fits without cropping.
|
|
270
|
+
const html = renderWithI18n(() =>
|
|
271
|
+
ThreadPreview({
|
|
272
|
+
rootPost: createPostView({ bodyHtml: "<p>Root</p>" }),
|
|
273
|
+
secondReply: createPostView({
|
|
274
|
+
id: "post-2",
|
|
275
|
+
permalink: "/post-2",
|
|
276
|
+
slug: "post-2",
|
|
277
|
+
bodyHtml: "<p>Second</p>",
|
|
278
|
+
}),
|
|
279
|
+
latestReply: createPostView({
|
|
280
|
+
id: "post-3",
|
|
281
|
+
permalink: "/post-3",
|
|
282
|
+
slug: "post-3",
|
|
283
|
+
bodyHtml: "<p>Latest</p>",
|
|
284
|
+
isLastInThread: true,
|
|
285
|
+
}),
|
|
286
|
+
totalReplyCount: 2,
|
|
287
|
+
}),
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
expect(html).toContain("thread-context-shell");
|
|
291
|
+
expect(html).toContain("data-collapsed");
|
|
292
|
+
expect(html).toContain("data-thread-context-toggle");
|
|
293
|
+
expect(html).toContain("<p>Root</p>");
|
|
294
|
+
expect(html).toContain("<p>Second</p>");
|
|
295
|
+
expect(html).toContain("<p>Latest</p>");
|
|
234
296
|
});
|
|
235
297
|
|
|
236
298
|
it("points the hidden-posts gap link to the second reply so the detail page opens just above the hidden range", () => {
|
|
@@ -3,36 +3,99 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Single post view — clean, no card border, with divider footer.
|
|
5
5
|
* When `threadPosts` is provided, renders the full thread with the current
|
|
6
|
-
* post highlighted and scroll-targeted.
|
|
6
|
+
* post highlighted and scroll-targeted. Ancestors above the current post are
|
|
7
|
+
* wrapped in the same collapsible shell used on the home feed
|
|
8
|
+
* (`.thread-context-shell`), driven by the shared `thread-context.ts`
|
|
9
|
+
* client logic.
|
|
7
10
|
*/
|
|
8
11
|
|
|
12
|
+
import { msg } from "@lingui/core/macro";
|
|
9
13
|
import type { FC } from "hono/jsx";
|
|
14
|
+
import { useLingui } from "../../i18n/context.js";
|
|
10
15
|
import type { PostPageProps, PostView } from "../../types.js";
|
|
11
16
|
import { TimelineItemFromPost } from "../feed/TimelineItem.js";
|
|
12
17
|
|
|
18
|
+
const renderThreadItem = (tp: PostView, currentId: string) => {
|
|
19
|
+
const isCurrent = tp.id === currentId;
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
key={tp.id}
|
|
23
|
+
id={`post-${tp.id}`}
|
|
24
|
+
class={`thread-item thread-detail-item${isCurrent ? " thread-item-current" : ""}`}
|
|
25
|
+
{...(isCurrent ? { "data-post-current": "" } : {})}
|
|
26
|
+
>
|
|
27
|
+
<TimelineItemFromPost
|
|
28
|
+
post={tp}
|
|
29
|
+
mode="detail"
|
|
30
|
+
display={{ footer: { hideTimestamp: false } }}
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
13
36
|
const ThreadDetail: FC<{ post: PostView; threadPosts: PostView[] }> = ({
|
|
14
37
|
post,
|
|
15
38
|
threadPosts,
|
|
16
39
|
}) => {
|
|
40
|
+
const { i18n } = useLingui();
|
|
41
|
+
const showMoreLabel = i18n._(
|
|
42
|
+
msg({
|
|
43
|
+
message: "Show more",
|
|
44
|
+
comment: "@context: Expand faded thread ancestor context in the feed",
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
const showLessLabel = i18n._(
|
|
48
|
+
msg({
|
|
49
|
+
message: "Show less",
|
|
50
|
+
comment:
|
|
51
|
+
"@context: Collapse expanded thread ancestor context in the feed",
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const currentIndex = threadPosts.findIndex((tp) => tp.id === post.id);
|
|
56
|
+
const ancestors = currentIndex > 0 ? threadPosts.slice(0, currentIndex) : [];
|
|
57
|
+
const currentAndAfter =
|
|
58
|
+
currentIndex >= 0 ? threadPosts.slice(currentIndex) : threadPosts;
|
|
59
|
+
|
|
17
60
|
return (
|
|
18
61
|
<div class="thread-group thread-group-detail" data-page="post">
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
return (
|
|
62
|
+
{ancestors.length > 0 && (
|
|
63
|
+
<>
|
|
22
64
|
<div
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
{...(isCurrent ? { "data-post-current": "" } : {})}
|
|
65
|
+
class="thread-context-shell"
|
|
66
|
+
data-thread-context
|
|
67
|
+
data-collapsed=""
|
|
27
68
|
>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
mode="detail"
|
|
31
|
-
display={{ footer: { hideTimestamp: false } }}
|
|
32
|
-
/>
|
|
69
|
+
{ancestors.map((tp) => renderThreadItem(tp, post.id))}
|
|
70
|
+
<div class="thread-context-fade" aria-hidden="true" />
|
|
33
71
|
</div>
|
|
34
|
-
|
|
35
|
-
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
class="thread-context-toggle"
|
|
75
|
+
data-thread-context-toggle
|
|
76
|
+
data-label-more={showMoreLabel}
|
|
77
|
+
data-label-less={showLessLabel}
|
|
78
|
+
aria-expanded="false"
|
|
79
|
+
>
|
|
80
|
+
<span class="thread-context-toggle-label">{showMoreLabel}</span>
|
|
81
|
+
<svg
|
|
82
|
+
class="thread-context-toggle-chevron"
|
|
83
|
+
viewBox="0 0 16 16"
|
|
84
|
+
aria-hidden="true"
|
|
85
|
+
>
|
|
86
|
+
<path
|
|
87
|
+
d="M4 6l4 4 4-4"
|
|
88
|
+
fill="none"
|
|
89
|
+
stroke="currentColor"
|
|
90
|
+
stroke-width="1.5"
|
|
91
|
+
stroke-linecap="round"
|
|
92
|
+
stroke-linejoin="round"
|
|
93
|
+
/>
|
|
94
|
+
</svg>
|
|
95
|
+
</button>
|
|
96
|
+
</>
|
|
97
|
+
)}
|
|
98
|
+
{currentAndAfter.map((tp) => renderThreadItem(tp, post.id))}
|
|
36
99
|
</div>
|
|
37
100
|
);
|
|
38
101
|
};
|