birdclaw 0.8.2 → 0.8.4
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/CHANGELOG.md +33 -0
- package/README.md +10 -8
- package/bin/birdclaw.mjs +4 -66
- package/dist/cli/birdclaw.js +28165 -0
- package/dist/client/assets/AvatarChip-DLoqM5xD.js +1 -0
- package/dist/client/assets/ProfilePreview-BejAuYsJ.js +1 -0
- package/dist/client/assets/SavedTimelineView-BIS7HKpp.js +1 -0
- package/dist/client/assets/SmartTimestamp-BR0-9se2.js +1 -0
- package/dist/client/assets/TimelineRouteFrame-CyGPj0eM.js +1 -0
- package/dist/client/assets/blocks-7UDKQp8H.js +1 -0
- package/dist/client/assets/bookmarks-CbBkMvXk.js +1 -0
- package/dist/client/assets/chunk-C0phanGV.js +1 -0
- package/dist/client/assets/circle-check-C_Vq3ElD.js +1 -0
- package/dist/client/assets/client-stream-contracts-ys3XhWG4.js +5 -0
- package/dist/client/assets/createLucideIcon-JV8isFFR.js +1 -0
- package/dist/client/assets/data-sources-Cm2bpNvg.js +1 -0
- package/dist/client/assets/discuss-DTjaOugw.js +1 -0
- package/dist/client/assets/dms-CGd6Eogq.js +1 -0
- package/dist/client/assets/inbox-BHlGuOy2.js +1 -0
- package/dist/client/assets/index-CEIG7S6s.js +31 -0
- package/dist/client/assets/index-bpFrQ5yG.css +1 -0
- package/dist/client/assets/likes-cLrcAQem.js +1 -0
- package/dist/client/assets/links-CM9QO1LC.js +1 -0
- package/dist/client/assets/mapbox-BxTlqXt9.js +2 -0
- package/dist/client/assets/mapbox-gl-dgf_hX3a.js +3215 -0
- package/dist/client/assets/mentions-CxKCgzIf.js +1 -0
- package/dist/client/assets/network-map-B5a3whqj.js +2 -0
- package/dist/client/assets/profile-analyze-CRtNEwlb.js +1 -0
- package/dist/client/assets/profile-hydration-client-YEtJsNTv.js +1 -0
- package/dist/client/assets/profiles._handle-C82_HoKX.js +1 -0
- package/dist/client/assets/query-client-fYu2rzRC.js +17 -0
- package/dist/client/assets/rate-limits-ScaEwdVK.js +1 -0
- package/dist/client/assets/react-dom-DHl6Ug7F.js +1 -0
- package/dist/client/assets/react-nBylq1U5.js +1 -0
- package/dist/client/assets/repeat-2-xCwHM9hD.js +1 -0
- package/dist/client/assets/routes-q7ZaW4En.js +1 -0
- package/dist/client/assets/schemas-I9r6F6ya.js +64 -0
- package/dist/client/assets/search-Dq5kYsxA.js +1 -0
- package/dist/client/assets/sparkles-CQVlvHsZ.js +1 -0
- package/dist/client/assets/styles-B8s3tt3r.css +2 -0
- package/dist/client/assets/today-CeG1O7Py.js +1 -0
- package/dist/client/assets/triangle-alert-CBL7s2pf.js +1 -0
- package/dist/client/assets/useTimelineRouteData-1HsqgvUi.js +1 -0
- package/dist/client/assets/users-CHbKlqUr.js +1 -0
- package/dist/server/assets/AvatarChip-zUDAEmjL.js +105 -0
- package/dist/server/assets/FeedState-ntW0Q2GB.js +214 -0
- package/dist/server/assets/ProfileAnalysisStream-BFvhVdhn.js +198 -0
- package/dist/server/assets/ProfilePreview-C6gAor_j.js +752 -0
- package/dist/server/assets/SavedTimelineView-BG1jnBp1.js +64 -0
- package/dist/server/assets/SmartTimestamp-DfwE1NGf.js +45 -0
- package/dist/server/assets/SyncNowButton-BOn_IBXS.js +76 -0
- package/dist/server/assets/TimelineRouteFrame-CU7ilM7U.js +85 -0
- package/dist/server/assets/TweetRichText-DhCVv1-6.js +74 -0
- package/dist/server/assets/_tanstack-start-manifest_v-C-ZRnG_n.js +148 -0
- package/dist/server/assets/account-selection-CTdFGWRk.js +44 -0
- package/dist/server/assets/blocks-C1mgGTB3.js +299 -0
- package/dist/server/assets/blocks-DSgQghqP.js +17 -0
- package/dist/server/assets/bookmarks-BJN8tykY.js +14 -0
- package/dist/server/assets/client-stream-contracts-C2xbWVjm.js +769 -0
- package/dist/server/assets/data-sources-BnA1Q94p.js +180 -0
- package/dist/server/assets/discuss-CJ1dau1j.js +15 -0
- package/dist/server/assets/discuss-QTo08NCN.js +338 -0
- package/dist/server/assets/dms-BuLj4bp8.js +368 -0
- package/dist/server/assets/dms-DAyQrVM2.js +240 -0
- package/dist/server/assets/empty-plugin-adapters-DzrEkdBF.js +5 -0
- package/dist/server/assets/inbox-CkGOaW1q.js +214 -0
- package/dist/server/assets/inbox-DpWd1EzC.js +146 -0
- package/dist/server/assets/likes-DBOAtsJU.js +14 -0
- package/dist/server/assets/links-DAhSjynu.js +240 -0
- package/dist/server/assets/links-DmH5lxHO.js +468 -0
- package/dist/server/assets/mentions-BH2MzKtB.js +26 -0
- package/dist/server/assets/network-map-D3CzRcC4.js +224 -0
- package/dist/server/assets/network-map-D5DoLOwR.js +582 -0
- package/dist/server/assets/profile-analyze-BP65PED0.js +90 -0
- package/dist/server/assets/profile-analyze-C1NoM0tV.js +9 -0
- package/dist/server/assets/profile-hydration-client-GJ4kwJS8.js +133 -0
- package/dist/server/assets/profiles._handle-DjwlN_ac.js +184 -0
- package/dist/server/assets/profiles._handle-DsLNj2Ca.js +12 -0
- package/dist/server/assets/query-client-BdauHBgd.js +923 -0
- package/dist/server/assets/rate-limits-VAr2qzYD.js +262 -0
- package/dist/server/assets/route-search-BUlQ5lGM.js +117 -0
- package/dist/server/assets/router-DqkwSPiM.js +17026 -0
- package/dist/server/assets/routes-A9c9ZhwN.js +26 -0
- package/dist/server/assets/start-FaDOTmto.js +4 -0
- package/dist/server/assets/today-B5hVM57Z.js +17 -0
- package/dist/server/assets/today-fvGiZ7ud.js +303 -0
- package/dist/server/assets/ui-qbmcMSSX.js +137 -0
- package/{src/components/useDebouncedValue.ts → dist/server/assets/useDebouncedValue-DOnA6Xcy.js} +4 -4
- package/dist/server/assets/useTimelineRouteData-27cxynxa.js +1101 -0
- package/dist/server/server.js +5520 -0
- package/package.json +27 -34
- package/playwright.config.ts +0 -35
- package/scripts/browser-perf.mjs +0 -427
- package/scripts/build-docs-site.mjs +0 -967
- package/scripts/docs-site-assets.mjs +0 -311
- package/scripts/run-vitest.mjs +0 -21
- package/scripts/sanitize-node-options.mjs +0 -23
- package/scripts/start-test-server.mjs +0 -42
- package/src/cli-moderation.ts +0 -210
- package/src/cli.ts +0 -2336
- package/src/components/AccountSwitcher.tsx +0 -186
- package/src/components/AppNav.tsx +0 -118
- package/src/components/AvatarChip.tsx +0 -58
- package/src/components/BrandMark.tsx +0 -67
- package/src/components/ConversationThread.tsx +0 -131
- package/src/components/DmWorkspace.tsx +0 -286
- package/src/components/EmbeddedTweetCard.tsx +0 -55
- package/src/components/FeedState.tsx +0 -147
- package/src/components/FloatingPreview.tsx +0 -382
- package/src/components/InboxCard.tsx +0 -152
- package/src/components/LinkPreviewCard.tsx +0 -292
- package/src/components/MarkdownViewer.tsx +0 -777
- package/src/components/ProfileAnalysisStream.tsx +0 -428
- package/src/components/ProfilePreview.tsx +0 -129
- package/src/components/SavedTimelineView.tsx +0 -155
- package/src/components/SmartTimestamp.tsx +0 -72
- package/src/components/SyncNowButton.tsx +0 -140
- package/src/components/ThemeSlider.tsx +0 -80
- package/src/components/TimelineCard.tsx +0 -533
- package/src/components/TimelineRouteFrame.tsx +0 -186
- package/src/components/TweetArticleCard.tsx +0 -66
- package/src/components/TweetMediaGrid.tsx +0 -185
- package/src/components/TweetRichText.tsx +0 -159
- package/src/components/account-selection.ts +0 -64
- package/src/components/useTimelineRouteData.ts +0 -323
- package/src/lib/account-sync-job.ts +0 -666
- package/src/lib/actions-transport.ts +0 -300
- package/src/lib/api-client.ts +0 -419
- package/src/lib/archive-finder.ts +0 -185
- package/src/lib/archive-import.ts +0 -2764
- package/src/lib/authored-live.ts +0 -1072
- package/src/lib/avatar-cache.ts +0 -349
- package/src/lib/backup.ts +0 -2741
- package/src/lib/bird-actions.ts +0 -294
- package/src/lib/bird-command.ts +0 -130
- package/src/lib/bird.ts +0 -1140
- package/src/lib/blocklist.ts +0 -136
- package/src/lib/blocks-write.ts +0 -167
- package/src/lib/blocks.ts +0 -389
- package/src/lib/bookmark-sync-job.ts +0 -536
- package/src/lib/client-cache.ts +0 -109
- package/src/lib/config.ts +0 -224
- package/src/lib/conversation-surface.ts +0 -205
- package/src/lib/data-sources.ts +0 -219
- package/src/lib/db.ts +0 -1135
- package/src/lib/dms-live.ts +0 -933
- package/src/lib/effect-runtime.ts +0 -45
- package/src/lib/follow-graph.ts +0 -1097
- package/src/lib/geocoding.ts +0 -296
- package/src/lib/http-effect.ts +0 -222
- package/src/lib/identity-search-index.ts +0 -369
- package/src/lib/inbox.ts +0 -241
- package/src/lib/link-index.ts +0 -641
- package/src/lib/link-insights.ts +0 -860
- package/src/lib/link-preview-metadata.ts +0 -754
- package/src/lib/location.ts +0 -137
- package/src/lib/media-fetch.ts +0 -860
- package/src/lib/media-includes.ts +0 -165
- package/src/lib/mention-threads-live.ts +0 -917
- package/src/lib/mentions-export.ts +0 -147
- package/src/lib/mentions-live.ts +0 -1238
- package/src/lib/moderation-target.ts +0 -216
- package/src/lib/moderation-write.ts +0 -131
- package/src/lib/mutes-write.ts +0 -167
- package/src/lib/mutes.ts +0 -84
- package/src/lib/ndjson-stream.ts +0 -106
- package/src/lib/network-map.ts +0 -382
- package/src/lib/openai.ts +0 -117
- package/src/lib/period-digest.ts +0 -1552
- package/src/lib/present.ts +0 -118
- package/src/lib/profile-affiliation-hydration.ts +0 -228
- package/src/lib/profile-affiliations.ts +0 -262
- package/src/lib/profile-analysis.ts +0 -1272
- package/src/lib/profile-bio-entities.ts +0 -318
- package/src/lib/profile-history.ts +0 -164
- package/src/lib/profile-hydration.ts +0 -180
- package/src/lib/profile-replies.ts +0 -77
- package/src/lib/profile-resolver.ts +0 -650
- package/src/lib/queries.ts +0 -2381
- package/src/lib/research.ts +0 -652
- package/src/lib/search-discussion.ts +0 -1016
- package/src/lib/seed.ts +0 -613
- package/src/lib/sqlite.ts +0 -147
- package/src/lib/sync-cache.ts +0 -65
- package/src/lib/theme-transition.ts +0 -113
- package/src/lib/theme.tsx +0 -165
- package/src/lib/timeline-collections-live.ts +0 -581
- package/src/lib/timeline-live.ts +0 -452
- package/src/lib/tweet-account-edges.ts +0 -48
- package/src/lib/tweet-lookup.ts +0 -46
- package/src/lib/tweet-render.ts +0 -430
- package/src/lib/tweet-search-live.ts +0 -566
- package/src/lib/types.ts +0 -723
- package/src/lib/ui.ts +0 -529
- package/src/lib/url-expansion-store.ts +0 -110
- package/src/lib/url-expansion.ts +0 -343
- package/src/lib/url-safety.ts +0 -220
- package/src/lib/web-sync.ts +0 -516
- package/src/lib/whois.ts +0 -1079
- package/src/lib/x-profile.ts +0 -365
- package/src/lib/x-web.ts +0 -199
- package/src/lib/xurl-rate-limits.ts +0 -267
- package/src/lib/xurl.ts +0 -1677
- package/src/routeTree.gen.ts +0 -723
- package/src/router.tsx +0 -20
- package/src/routes/__root.tsx +0 -79
- package/src/routes/api/action.tsx +0 -147
- package/src/routes/api/avatar.tsx +0 -50
- package/src/routes/api/blocks.tsx +0 -35
- package/src/routes/api/conversation.tsx +0 -45
- package/src/routes/api/data-sources.tsx +0 -24
- package/src/routes/api/inbox.tsx +0 -43
- package/src/routes/api/link-insights.tsx +0 -85
- package/src/routes/api/link-preview.tsx +0 -47
- package/src/routes/api/network-map.tsx +0 -55
- package/src/routes/api/period-digest.tsx +0 -101
- package/src/routes/api/profile-analysis.tsx +0 -97
- package/src/routes/api/profile-hydrate.tsx +0 -54
- package/src/routes/api/query.tsx +0 -115
- package/src/routes/api/search-discussion.tsx +0 -113
- package/src/routes/api/status.tsx +0 -28
- package/src/routes/api/sync.tsx +0 -105
- package/src/routes/api/xurl-rate-limits.tsx +0 -24
- package/src/routes/blocks.tsx +0 -377
- package/src/routes/bookmarks.tsx +0 -18
- package/src/routes/data-sources.tsx +0 -257
- package/src/routes/discuss.tsx +0 -419
- package/src/routes/dms.tsx +0 -432
- package/src/routes/inbox.tsx +0 -226
- package/src/routes/index.tsx +0 -32
- package/src/routes/likes.tsx +0 -18
- package/src/routes/links.tsx +0 -994
- package/src/routes/mentions.tsx +0 -32
- package/src/routes/network-map.tsx +0 -1035
- package/src/routes/profile-analyze.tsx +0 -112
- package/src/routes/profiles.$handle.tsx +0 -228
- package/src/routes/rate-limits.tsx +0 -309
- package/src/routes/today.tsx +0 -511
- package/src/styles.css +0 -257
- package/tsconfig.json +0 -29
- package/vite.config.ts +0 -29
- /package/{public → dist/client}/birdclaw-mark.png +0 -0
- /package/{public → dist/client}/favicon.ico +0 -0
- /package/{public → dist/client}/logo192.png +0 -0
- /package/{public → dist/client}/logo512.png +0 -0
- /package/{public → dist/client}/manifest.json +0 -0
- /package/{public → dist/client}/robots.txt +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { t as TimelineRouteFrame } from "./TimelineRouteFrame-CU7ilM7U.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/routes/index.tsx?tsr-split=component
|
|
4
|
+
function homeSubtitle(meta) {
|
|
5
|
+
if (!meta) return "Loading local context...";
|
|
6
|
+
return `${String(meta.stats.home)} items · ${String(meta.stats.needsReply)} waiting · ${meta.transport.statusText}`;
|
|
7
|
+
}
|
|
8
|
+
function HomeRoute() {
|
|
9
|
+
return /* @__PURE__ */ jsx(TimelineRouteFrame, {
|
|
10
|
+
emptyDetail: "Try a different filter or sync the timeline again.",
|
|
11
|
+
emptyLabel: "No posts in this view",
|
|
12
|
+
errorFallback: "Timeline unavailable",
|
|
13
|
+
errorTitle: "Could not load posts",
|
|
14
|
+
initialReplyFilter: "all",
|
|
15
|
+
loadingDetail: "Reading the local timeline store",
|
|
16
|
+
loadingLabel: "Loading posts",
|
|
17
|
+
resource: "home",
|
|
18
|
+
searchPlaceholder: "Search local timeline",
|
|
19
|
+
subtitle: homeSubtitle,
|
|
20
|
+
syncKind: "timeline",
|
|
21
|
+
syncLabel: "Sync timeline",
|
|
22
|
+
title: "Home"
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { HomeRoute as component };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
//#region node_modules/.pnpm/@tanstack+react-start@1.168.26_react-dom@19.2.7_react@19.2.7__react@19.2.7_vite@8.0.16__465b94eb4096202468ea7bb8157eb6f6/node_modules/@tanstack/react-start/dist/plugin/default-entry/start.ts
|
|
2
|
+
var startInstance = void 0;
|
|
3
|
+
//#endregion
|
|
4
|
+
export { startInstance };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "./ui-qbmcMSSX.js";
|
|
2
|
+
import "./client-stream-contracts-C2xbWVjm.js";
|
|
3
|
+
import "./profile-hydration-client-GJ4kwJS8.js";
|
|
4
|
+
import { s as validateTodaySearch } from "./route-search-BUlQ5lGM.js";
|
|
5
|
+
import "react";
|
|
6
|
+
import { createFileRoute, lazyRouteComponent } from "@tanstack/react-router";
|
|
7
|
+
import "react/jsx-runtime";
|
|
8
|
+
import "lucide-react";
|
|
9
|
+
import "@tanstack/react-query";
|
|
10
|
+
//#region src/routes/today.tsx
|
|
11
|
+
var $$splitComponentImporter = () => import("./today-fvGiZ7ud.js");
|
|
12
|
+
var Route$1 = createFileRoute("/today")({
|
|
13
|
+
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
14
|
+
validateSearch: validateTodaySearch
|
|
15
|
+
});
|
|
16
|
+
//#endregion
|
|
17
|
+
export { Route$1 as t };
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { Dt as pageSubtitleClass, Et as pageHeaderRowClass, Kt as segmentClass, Ot as pageTitleClass, Tt as pageHeaderClass, Wt as secondaryButtonClass, m as cx, q as errorCopyClass, qt as segmentedClass, wt as pageHeaderActionsClass } from "./ui-qbmcMSSX.js";
|
|
2
|
+
import { a as useNdjsonRun, n as periodDigestStreamEventSchema, o as MarkdownViewer, t as isTerminalStreamEvent } from "./client-stream-contracts-C2xbWVjm.js";
|
|
3
|
+
import { n as normalizeProfileHydrationHandle, t as hydrateProfileHandles } from "./profile-hydration-client-GJ4kwJS8.js";
|
|
4
|
+
import { s as validateTodaySearch } from "./route-search-BUlQ5lGM.js";
|
|
5
|
+
import { t as Route$1 } from "./today-B5hVM57Z.js";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { CheckCircle2, Loader2, RefreshCw, Sparkles } from "lucide-react";
|
|
9
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
10
|
+
//#region src/routes/today.tsx?tsr-split=component
|
|
11
|
+
var PROFILE_HYDRATION_LIMIT = 12;
|
|
12
|
+
var PROFILE_HYDRATION_DELAY_MS = 300;
|
|
13
|
+
var DIGEST_STATUS_MESSAGES = { 524: "Digest startup timed out at Cloudflare (524). Retry to open a new stream." };
|
|
14
|
+
var periods = [
|
|
15
|
+
{
|
|
16
|
+
value: "today",
|
|
17
|
+
label: "Today"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
value: "24h",
|
|
21
|
+
label: "24h"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
value: "yesterday",
|
|
25
|
+
label: "Yesterday"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
value: "week",
|
|
29
|
+
label: "Week"
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
function digestUrl(period, includeDms, refresh) {
|
|
33
|
+
const url = new URL("/api/period-digest", window.location.origin);
|
|
34
|
+
url.searchParams.set("period", period);
|
|
35
|
+
url.searchParams.set("includeDms", String(includeDms));
|
|
36
|
+
url.searchParams.set("maxTweets", "5000");
|
|
37
|
+
url.searchParams.set("maxLinks", "20");
|
|
38
|
+
url.searchParams.set("liveSync", "false");
|
|
39
|
+
if (refresh) url.searchParams.set("refresh", "true");
|
|
40
|
+
return url;
|
|
41
|
+
}
|
|
42
|
+
function digestStreamError(cause, phase) {
|
|
43
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
44
|
+
if (cause instanceof TypeError && /network error|failed to fetch|load failed/i.test(message)) return `Digest connection was interrupted while ${phase.toLowerCase()}. Retry to continue.`;
|
|
45
|
+
if (cause instanceof SyntaxError) return `Digest stream returned invalid data while ${phase.toLowerCase()}. Retry to continue.`;
|
|
46
|
+
return message || "Digest failed";
|
|
47
|
+
}
|
|
48
|
+
function formatCounts(context) {
|
|
49
|
+
if (!context) return "Local Twitter memory, summarized as it streams.";
|
|
50
|
+
const counts = context.counts;
|
|
51
|
+
return [
|
|
52
|
+
`${String(counts.home)} home`,
|
|
53
|
+
`${String(counts.mentions)} mentions`,
|
|
54
|
+
`${String(counts.links)} links`,
|
|
55
|
+
context.includeDms ? `${String(counts.dms)} DMs` : null
|
|
56
|
+
].filter(Boolean).join(" · ");
|
|
57
|
+
}
|
|
58
|
+
function collectProfilesForHydration(result) {
|
|
59
|
+
const handles = /* @__PURE__ */ new Set();
|
|
60
|
+
const tweetIds = /* @__PURE__ */ new Set();
|
|
61
|
+
for (const id of result.digest.sourceTweetIds) tweetIds.add(id);
|
|
62
|
+
for (const topic of result.digest.keyTopics) for (const id of topic.tweetIds) tweetIds.add(id);
|
|
63
|
+
for (const link of result.digest.notableLinks) for (const id of link.sourceTweetIds) tweetIds.add(id);
|
|
64
|
+
for (const item of result.digest.actionItems) if (item.tweetId) tweetIds.add(item.tweetId);
|
|
65
|
+
const tweetsById = new Map(result.context.tweets.flatMap((tweet) => [[tweet.id, tweet], [`tweet_${tweet.id}`, tweet]]));
|
|
66
|
+
for (const id of tweetIds) {
|
|
67
|
+
const tweet = tweetsById.get(id);
|
|
68
|
+
if (!tweet) continue;
|
|
69
|
+
const handle = normalizeProfileHydrationHandle(tweet.author);
|
|
70
|
+
if (handle) handles.add(handle);
|
|
71
|
+
}
|
|
72
|
+
for (const tweet of result.context.tweets) {
|
|
73
|
+
const handle = normalizeProfileHydrationHandle(tweet.author);
|
|
74
|
+
if (handle) handles.add(handle);
|
|
75
|
+
}
|
|
76
|
+
return [...handles];
|
|
77
|
+
}
|
|
78
|
+
function applyHydratedProfilesToContext(context, profilesByHandle) {
|
|
79
|
+
let changed = false;
|
|
80
|
+
const tweets = context.tweets.map((tweet) => {
|
|
81
|
+
const profile = profilesByHandle.get(normalizeProfileHydrationHandle(tweet.author));
|
|
82
|
+
if (!profile || profile === tweet.authorProfile) return tweet;
|
|
83
|
+
changed = true;
|
|
84
|
+
return {
|
|
85
|
+
...tweet,
|
|
86
|
+
author: profile.handle,
|
|
87
|
+
name: profile.displayName,
|
|
88
|
+
authorProfile: profile
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
return changed ? {
|
|
92
|
+
...context,
|
|
93
|
+
tweets
|
|
94
|
+
} : context;
|
|
95
|
+
}
|
|
96
|
+
function applyHydratedProfilesToResult(result, profiles) {
|
|
97
|
+
const profilesByHandle = new Map(profiles.map((profile) => [normalizeProfileHydrationHandle(profile.handle), profile]));
|
|
98
|
+
if (profilesByHandle.size === 0) return result;
|
|
99
|
+
const context = applyHydratedProfilesToContext(result.context, profilesByHandle);
|
|
100
|
+
return context === result.context ? result : {
|
|
101
|
+
...result,
|
|
102
|
+
context
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function useDigestStream(period, includeDms) {
|
|
106
|
+
const queryClient = useQueryClient();
|
|
107
|
+
const [markdown, setMarkdown] = useState("");
|
|
108
|
+
const [context, setContext] = useState(null);
|
|
109
|
+
const [result, setResult] = useState(null);
|
|
110
|
+
const [status, setStatus] = useState("Starting digest");
|
|
111
|
+
const latestStatusRef = useRef("Starting digest");
|
|
112
|
+
const onStart = useCallback(() => {
|
|
113
|
+
setMarkdown("");
|
|
114
|
+
setContext(null);
|
|
115
|
+
setResult(null);
|
|
116
|
+
setStatus("Starting digest");
|
|
117
|
+
latestStatusRef.current = "Starting digest";
|
|
118
|
+
}, []);
|
|
119
|
+
const { error, loading, run } = useNdjsonRun({
|
|
120
|
+
schema: periodDigestStreamEventSchema,
|
|
121
|
+
request: useCallback((signal, refresh) => fetch(digestUrl(period, includeDms, refresh), {
|
|
122
|
+
cache: "no-store",
|
|
123
|
+
signal
|
|
124
|
+
}), [includeDms, period]),
|
|
125
|
+
onStart,
|
|
126
|
+
onEvent: useCallback((event) => {
|
|
127
|
+
if (event.type === "status") {
|
|
128
|
+
latestStatusRef.current = event.detail ? `${event.label} · ${event.detail}` : event.label;
|
|
129
|
+
setStatus(latestStatusRef.current);
|
|
130
|
+
} else if (event.type === "start") setContext(event.context);
|
|
131
|
+
else if (event.type === "delta") {
|
|
132
|
+
latestStatusRef.current = "Streaming AI summary";
|
|
133
|
+
setStatus(latestStatusRef.current);
|
|
134
|
+
setMarkdown((current) => current + event.delta);
|
|
135
|
+
} else if (event.type === "done") {
|
|
136
|
+
setResult(event.result);
|
|
137
|
+
setContext(event.result.context);
|
|
138
|
+
setMarkdown(event.result.markdown);
|
|
139
|
+
setStatus(event.result.cached ? "Loaded cached report" : "Ready");
|
|
140
|
+
} else if (event.type === "error") throw new Error(event.error);
|
|
141
|
+
}, []),
|
|
142
|
+
onError: useCallback(() => setStatus("Digest failed"), []),
|
|
143
|
+
isTerminal: isTerminalStreamEvent,
|
|
144
|
+
errorLabel: "Digest request failed",
|
|
145
|
+
emptyBodyMessage: "Digest request failed: empty response body",
|
|
146
|
+
prematureEofError: useCallback(() => /* @__PURE__ */ new Error(`Digest connection closed while ${latestStatusRef.current.toLowerCase()}. Retry to continue.`), []),
|
|
147
|
+
formatError: useCallback((cause) => digestStreamError(cause, latestStatusRef.current), []),
|
|
148
|
+
statusMessages: DIGEST_STATUS_MESSAGES
|
|
149
|
+
});
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
run(false);
|
|
152
|
+
}, [run]);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (!result) return;
|
|
155
|
+
const handles = collectProfilesForHydration(result);
|
|
156
|
+
if (handles.length === 0) return;
|
|
157
|
+
let active = true;
|
|
158
|
+
let idleId = null;
|
|
159
|
+
const runHydration = () => {
|
|
160
|
+
hydrateProfileHandles(queryClient, handles, { limit: PROFILE_HYDRATION_LIMIT }).then((response) => {
|
|
161
|
+
if (!active) return;
|
|
162
|
+
const { profiles } = response;
|
|
163
|
+
if (profiles.length === 0) return;
|
|
164
|
+
setResult((current) => current ? applyHydratedProfilesToResult(current, profiles) : current);
|
|
165
|
+
const profilesByHandle = new Map(profiles.map((profile) => [normalizeProfileHydrationHandle(profile.handle), profile]));
|
|
166
|
+
setContext((current) => current ? applyHydratedProfilesToContext(current, profilesByHandle) : current);
|
|
167
|
+
}).catch((error) => {
|
|
168
|
+
if (!active) return;
|
|
169
|
+
console.warn("Profile hydration failed", error);
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
const timer = window.setTimeout(() => {
|
|
173
|
+
if ("requestIdleCallback" in window) idleId = window.requestIdleCallback(runHydration, { timeout: 2500 });
|
|
174
|
+
else runHydration();
|
|
175
|
+
}, PROFILE_HYDRATION_DELAY_MS);
|
|
176
|
+
return () => {
|
|
177
|
+
active = false;
|
|
178
|
+
window.clearTimeout(timer);
|
|
179
|
+
if (idleId !== null && "cancelIdleCallback" in window) window.cancelIdleCallback(idleId);
|
|
180
|
+
};
|
|
181
|
+
}, [queryClient, result]);
|
|
182
|
+
return {
|
|
183
|
+
context,
|
|
184
|
+
error,
|
|
185
|
+
loading,
|
|
186
|
+
markdown,
|
|
187
|
+
result,
|
|
188
|
+
run,
|
|
189
|
+
status
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function TodayRoute() {
|
|
193
|
+
const search = Route$1.useSearch();
|
|
194
|
+
const navigate = Route$1.useNavigate();
|
|
195
|
+
return /* @__PURE__ */ jsx(TodayRouteView, {
|
|
196
|
+
searchState: search,
|
|
197
|
+
onSearchChange: (next, options) => void navigate({
|
|
198
|
+
search: next,
|
|
199
|
+
replace: options?.replace
|
|
200
|
+
})
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function TodayRouteView({ searchState: controlledSearch, onSearchChange } = {}) {
|
|
204
|
+
const [localSearch, setLocalSearch] = useState(() => validateTodaySearch({}));
|
|
205
|
+
const searchState = controlledSearch ?? localSearch;
|
|
206
|
+
const updateSearch = (next, options) => onSearchChange ? onSearchChange(next, options) : setLocalSearch(next);
|
|
207
|
+
const { period, includeDms } = searchState;
|
|
208
|
+
const { context, error, loading, markdown, result, run, status } = useDigestStream(period, includeDms);
|
|
209
|
+
const sourceLabel = useMemo(() => formatCounts(result?.context ?? context), [context, result]);
|
|
210
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
211
|
+
className: "flex min-h-screen flex-col",
|
|
212
|
+
children: [
|
|
213
|
+
/* @__PURE__ */ jsxs("header", {
|
|
214
|
+
className: pageHeaderClass,
|
|
215
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
216
|
+
className: pageHeaderRowClass,
|
|
217
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
218
|
+
className: "min-w-0",
|
|
219
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
220
|
+
className: pageTitleClass,
|
|
221
|
+
children: "What happened"
|
|
222
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
223
|
+
className: pageSubtitleClass,
|
|
224
|
+
children: sourceLabel
|
|
225
|
+
})]
|
|
226
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
227
|
+
className: pageHeaderActionsClass,
|
|
228
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
229
|
+
type: "button",
|
|
230
|
+
className: secondaryButtonClass,
|
|
231
|
+
onClick: () => run(true),
|
|
232
|
+
disabled: loading,
|
|
233
|
+
children: [/* @__PURE__ */ jsx(RefreshCw, {
|
|
234
|
+
className: cx("size-4", loading && "animate-spin"),
|
|
235
|
+
"aria-hidden": "true"
|
|
236
|
+
}), "Refresh"]
|
|
237
|
+
})
|
|
238
|
+
})]
|
|
239
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
240
|
+
className: "flex flex-wrap items-center gap-2 px-4 pb-3",
|
|
241
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
242
|
+
className: segmentedClass,
|
|
243
|
+
"aria-label": "Digest period",
|
|
244
|
+
children: periods.map((item) => /* @__PURE__ */ jsx("button", {
|
|
245
|
+
type: "button",
|
|
246
|
+
className: cx(segmentClass, period === item.value && "bg-[var(--bg-active)] text-[var(--ink)]"),
|
|
247
|
+
onClick: () => updateSearch({
|
|
248
|
+
...searchState,
|
|
249
|
+
period: item.value
|
|
250
|
+
}),
|
|
251
|
+
children: item.label
|
|
252
|
+
}, item.value))
|
|
253
|
+
}), /* @__PURE__ */ jsxs("label", {
|
|
254
|
+
className: "inline-flex items-center gap-2 rounded-full border border-[var(--line)] px-3 py-1 text-[13px] font-medium text-[var(--ink-soft)]",
|
|
255
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
256
|
+
type: "checkbox",
|
|
257
|
+
checked: includeDms,
|
|
258
|
+
onChange: (event) => updateSearch({
|
|
259
|
+
...searchState,
|
|
260
|
+
includeDms: event.currentTarget.checked
|
|
261
|
+
})
|
|
262
|
+
}), "DMs"]
|
|
263
|
+
})]
|
|
264
|
+
})]
|
|
265
|
+
}),
|
|
266
|
+
error ? /* @__PURE__ */ jsxs("div", {
|
|
267
|
+
className: cx(errorCopyClass, "flex items-center justify-between gap-3"),
|
|
268
|
+
role: "alert",
|
|
269
|
+
children: [/* @__PURE__ */ jsx("span", { children: error }), /* @__PURE__ */ jsx("button", {
|
|
270
|
+
className: "shrink-0 font-semibold underline underline-offset-2",
|
|
271
|
+
onClick: () => run(true),
|
|
272
|
+
type: "button",
|
|
273
|
+
children: "Retry"
|
|
274
|
+
})]
|
|
275
|
+
}) : null,
|
|
276
|
+
/* @__PURE__ */ jsx("div", {
|
|
277
|
+
className: "border-b border-[var(--line)] px-4 py-2 text-[13px] text-[var(--ink-soft)]",
|
|
278
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
279
|
+
className: "inline-flex items-center gap-1",
|
|
280
|
+
children: [loading ? /* @__PURE__ */ jsx(Loader2, {
|
|
281
|
+
className: "size-4 animate-spin",
|
|
282
|
+
"aria-hidden": "true"
|
|
283
|
+
}) : markdown ? /* @__PURE__ */ jsx(CheckCircle2, {
|
|
284
|
+
className: "size-4",
|
|
285
|
+
"aria-hidden": "true"
|
|
286
|
+
}) : /* @__PURE__ */ jsx(Sparkles, {
|
|
287
|
+
className: "size-4",
|
|
288
|
+
"aria-hidden": "true"
|
|
289
|
+
}), loading ? status : result ? `${result.cached ? "Cached" : "Ready"} · ${result.context.window.label}` : error ? "Digest failed" : "Ready"]
|
|
290
|
+
})
|
|
291
|
+
}),
|
|
292
|
+
markdown ? /* @__PURE__ */ jsx(MarkdownViewer, {
|
|
293
|
+
context: result?.context ?? context,
|
|
294
|
+
markdown
|
|
295
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
296
|
+
className: "px-4 py-5 text-[14px] text-[var(--ink-soft)]",
|
|
297
|
+
children: loading ? status : error ? "No digest was generated. Retry to start a new run." : "Waiting for the first tokens..."
|
|
298
|
+
})
|
|
299
|
+
]
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
//#endregion
|
|
303
|
+
export { TodayRouteView, TodayRoute as component };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
//#region src/lib/ui.ts
|
|
2
|
+
function cx(...values) {
|
|
3
|
+
return values.filter(Boolean).join(" ");
|
|
4
|
+
}
|
|
5
|
+
var bodyClass = "min-h-screen bg-[var(--bg)] font-sans text-[var(--ink)] antialiased text-[15px] leading-[1.4]";
|
|
6
|
+
var siteShellClass = "mx-auto flex min-h-screen w-full max-w-[1280px] gap-0";
|
|
7
|
+
var sidebarShellClass = "sticky top-0 z-30 flex h-screen w-[72px] shrink-0 flex-col justify-between border-r border-[var(--line)] bg-[var(--bg)] px-2 py-3 min-[1100px]:w-[260px] min-[1100px]:px-3";
|
|
8
|
+
var sidebarShellCompactClass = "sticky top-0 z-30 flex h-screen w-[72px] shrink-0 flex-col justify-between border-r border-[var(--line)] bg-[var(--bg)] px-2 py-3";
|
|
9
|
+
var sidebarBrandClass = "flex items-center gap-2.5 px-2 py-2 text-[var(--ink)] min-[1100px]:px-3";
|
|
10
|
+
var sidebarBrandMarkClass = "grid size-10 place-items-center";
|
|
11
|
+
var sidebarBrandCopyClass = "hidden flex-col leading-tight min-[1100px]:flex";
|
|
12
|
+
var sidebarBrandCopyCompactClass = "sr-only";
|
|
13
|
+
var sidebarBrandTitleClass = "text-[15px] font-bold tracking-tight";
|
|
14
|
+
var sidebarBrandTaglineClass = "text-[12px] text-[var(--ink-soft)]";
|
|
15
|
+
var sidebarNavClass = "mt-2 flex flex-col gap-0.5";
|
|
16
|
+
var sidebarFooterClass = "flex flex-col gap-2 pb-1";
|
|
17
|
+
var navLinkClass = "nav-link group flex items-center justify-center gap-4 rounded-full px-3 py-2.5 text-[15px] text-[var(--ink)] transition-colors duration-150 hover:bg-[var(--bg-hover)] min-[1100px]:justify-start";
|
|
18
|
+
var navLinkCompactClass = "nav-link group flex items-center justify-center rounded-full px-3 py-2.5 text-[15px] text-[var(--ink)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
19
|
+
var navLinkActiveClass = "nav-link-active font-bold";
|
|
20
|
+
var navLinkIconClass = "shrink-0";
|
|
21
|
+
var navLinkLabelClass = "sr-only min-[1100px]:not-sr-only";
|
|
22
|
+
var navLinkLabelCompactClass = "sr-only";
|
|
23
|
+
var mainColumnClass = "flex w-full min-w-0 max-w-[680px] flex-1 flex-col border-x border-[var(--line)] bg-[var(--bg)]";
|
|
24
|
+
var mainColumnDmClass = "flex w-full min-w-0 flex-1 flex-col border-x border-[var(--line)] bg-[var(--bg)]";
|
|
25
|
+
var pageHeaderClass = "sticky top-0 z-20 flex flex-col gap-0 border-b border-[var(--line)] bg-[color:color-mix(in_srgb,var(--bg)_85%,transparent)] backdrop-blur";
|
|
26
|
+
var pageHeaderRowClass = "flex items-center justify-between gap-3 px-4 pt-3 pb-2";
|
|
27
|
+
var pageTitleClass = "m-0 text-[20px] font-bold tracking-tight";
|
|
28
|
+
var pageSubtitleClass = "text-[13px] text-[var(--ink-soft)]";
|
|
29
|
+
var pageHeaderActionsClass = "flex items-center gap-2";
|
|
30
|
+
var tabStripClass = "flex w-full items-stretch border-b border-[var(--line)] overflow-x-auto";
|
|
31
|
+
var tabButtonClass = "relative flex flex-1 min-w-[88px] items-center justify-center px-3 py-3.5 text-[14px] font-medium text-[var(--ink-soft)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
32
|
+
var tabButtonActiveClass = "text-[var(--ink)] font-bold";
|
|
33
|
+
var tabButtonIndicatorClass = "pointer-events-none absolute bottom-0 left-1/2 h-[3px] w-12 -translate-x-1/2 rounded-full bg-[var(--accent)]";
|
|
34
|
+
var feedClass = "flex flex-col";
|
|
35
|
+
var feedRowClass = "flex w-full gap-3 border-b border-[var(--line)] px-4 py-3 transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
36
|
+
var feedRowBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
|
|
37
|
+
var feedRowHeaderClass = "flex min-w-0 items-center gap-1.5 text-[15px]";
|
|
38
|
+
var feedRowNameClass = "truncate font-bold text-[var(--ink)] hover:underline";
|
|
39
|
+
var feedRowHandleClass = "truncate text-[var(--ink-soft)]";
|
|
40
|
+
var feedRowDotClass = "text-[var(--ink-soft)]";
|
|
41
|
+
var feedRowTimestampClass = "shrink-0 text-[var(--ink-soft)] hover:underline";
|
|
42
|
+
var feedRowActionsClass = "mt-2 flex max-w-md items-center justify-between text-[var(--ink-soft)]";
|
|
43
|
+
var feedActionButtonClass = "action-button group/action inline-flex items-center gap-1 rounded-full border-0 bg-transparent px-2 py-1 text-[13px] text-[var(--ink-soft)] transition-colors duration-150 hover:text-[var(--accent)] disabled:cursor-default disabled:opacity-55";
|
|
44
|
+
var feedActionIconWrapClass = "grid size-[34px] place-items-center rounded-full transition-colors duration-150 group-hover/action:bg-[var(--accent-soft)]";
|
|
45
|
+
var feedActionIconClass = "size-[18px]";
|
|
46
|
+
var feedRowTextClass = "whitespace-pre-wrap break-words text-[15px] leading-[1.45] text-[var(--ink)] [overflow-wrap:anywhere]";
|
|
47
|
+
var feedRowStatePillClass = "inline-flex shrink-0 items-center gap-1 rounded-full border border-[var(--line)] bg-[var(--bg-active)] px-2 py-0.5 text-[12px] font-semibold text-[var(--ink-soft)]";
|
|
48
|
+
var feedRowStatePillActiveClass = "border-[color:color-mix(in_srgb,var(--accent)_35%,var(--line))] bg-[var(--accent-soft)] text-[var(--accent)]";
|
|
49
|
+
var feedRowStatePillOpenClass = "border-[color:color-mix(in_srgb,var(--ink-soft)_34%,var(--line))] bg-transparent text-[var(--ink-soft)]";
|
|
50
|
+
var searchFieldShellClass = "flex items-center gap-2 rounded-full border border-transparent bg-[var(--bg-active)] px-4 py-2 transition-colors focus-within:border-[var(--accent)] focus-within:bg-[var(--bg)] focus-within:shadow-[0_0_0_1px_var(--accent)]";
|
|
51
|
+
var searchFieldIconClass = "size-[18px] text-[var(--ink-soft)] shrink-0";
|
|
52
|
+
var searchFieldInputClass = "min-w-0 flex-1 border-0 bg-transparent text-[14px] text-[var(--ink)] outline-none placeholder:text-[var(--ink-soft)]";
|
|
53
|
+
var textFieldClass = "w-full rounded-md border border-[var(--line)] bg-[var(--bg)] px-3 py-2 text-[14px] text-[var(--ink)] outline-none transition-colors duration-150 placeholder:text-[var(--ink-soft)] focus:border-[var(--accent)] focus:shadow-[0_0_0_1px_var(--accent)] disabled:cursor-default disabled:opacity-55";
|
|
54
|
+
var textFieldShortClass = "w-[120px]";
|
|
55
|
+
var selectFieldClass = cx(textFieldClass, "appearance-none pr-8");
|
|
56
|
+
var primaryButtonClass = "inline-flex items-center justify-center gap-1.5 rounded-full border-0 bg-[var(--accent)] px-4 py-1.5 text-[14px] font-bold text-white shadow-none transition-colors duration-150 hover:bg-[var(--accent-hover)] active:bg-[var(--accent-press)] disabled:cursor-default disabled:opacity-55";
|
|
57
|
+
var secondaryButtonClass = "inline-flex items-center justify-center gap-1.5 rounded-full border border-[var(--line-strong)] bg-transparent px-4 py-1.5 text-[14px] font-bold text-[var(--ink)] transition-colors duration-150 hover:bg-[var(--bg-hover)] disabled:cursor-default disabled:opacity-55";
|
|
58
|
+
var dangerButtonClass = "inline-flex items-center justify-center gap-1.5 rounded-full border border-[var(--alert)] bg-transparent px-4 py-1.5 text-[14px] font-bold text-[var(--alert)] transition-colors duration-150 hover:bg-[var(--alert-soft)] disabled:cursor-default disabled:opacity-55";
|
|
59
|
+
var segmentedClass = "inline-flex shrink-0 items-center gap-1 rounded-full border border-[var(--line)] bg-[var(--bg)] p-1";
|
|
60
|
+
var segmentClass = "rounded-full border-0 bg-transparent px-3 py-1 text-[13px] font-medium text-[var(--ink-soft)] capitalize transition-colors duration-150";
|
|
61
|
+
var segmentActiveClass = "bg-[var(--bg-active)] text-[var(--ink)]";
|
|
62
|
+
var composerShellClass = "mt-2 flex flex-col gap-2 border-t border-[var(--line)] pt-3";
|
|
63
|
+
var composerInputClass = "min-h-[88px] w-full resize-y rounded-md border border-[var(--line)] bg-[var(--bg)] px-3 py-2.5 text-[15px] text-[var(--ink)] outline-none transition-colors duration-150 placeholder:text-[var(--ink-soft)] focus:border-[var(--accent)] focus:shadow-[0_0_0_1px_var(--accent)]";
|
|
64
|
+
var composerBarClass = "flex items-center justify-between gap-3";
|
|
65
|
+
var emptyStateClass = "px-6 py-10 text-center text-[var(--ink-soft)]";
|
|
66
|
+
var errorCopyClass = "mx-4 my-3 whitespace-pre-wrap break-words rounded-md border border-[var(--alert)] bg-[var(--alert-soft)] px-3 py-2 text-[14px] text-[var(--alert)]";
|
|
67
|
+
var statusCopyClass = "mx-4 my-3 rounded-md border border-[var(--line)] bg-[var(--bg-elevated)] px-3 py-2 text-[13px] text-[var(--ink-soft)]";
|
|
68
|
+
var avatarChipClass = "avatar-chip inline-grid size-10 shrink-0 place-items-center overflow-hidden rounded-full text-[14px] font-bold text-white";
|
|
69
|
+
var avatarChipLargeClass = "avatar-chip-large size-16 text-[18px]";
|
|
70
|
+
var avatarChipSmallClass = "avatar-chip-small size-8 text-[12px]";
|
|
71
|
+
var embeddedCardClass = "mt-2 overflow-hidden rounded-2xl border border-[var(--line)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
72
|
+
var embeddedCardBodyClass = "flex flex-col gap-2 px-3 py-2.5";
|
|
73
|
+
var embeddedCardHeaderClass = "flex items-center gap-1.5 text-[14px]";
|
|
74
|
+
var embeddedCardNameClass = "font-bold text-[var(--ink)] truncate";
|
|
75
|
+
var embeddedCardHandleClass = "text-[var(--ink-soft)] truncate";
|
|
76
|
+
var embeddedCardLabelClass = "text-[12px] uppercase tracking-wide text-[var(--ink-soft)]";
|
|
77
|
+
var embeddedCardCopyClass = "whitespace-pre-wrap text-[14px] leading-[1.4] text-[var(--ink)] [overflow-wrap:anywhere]";
|
|
78
|
+
var linkPreviewCardClass = "group/link-preview mt-2 flex min-w-0 overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--bg-card)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
79
|
+
var linkPreviewTitleClass = "line-clamp-2 font-bold leading-tight text-[var(--ink)]";
|
|
80
|
+
var linkPreviewDescClass = "line-clamp-2 text-[14px] leading-snug text-[var(--ink-soft)]";
|
|
81
|
+
var linkPreviewHostClass = "text-[13px] text-[var(--ink-soft)] truncate";
|
|
82
|
+
var dmShellClass = "grid h-[calc(100vh-56px)] min-h-[520px] grid-cols-1 min-[960px]:grid-cols-[360px_minmax(0,1fr)] min-[1360px]:grid-cols-[400px_minmax(0,1fr)]";
|
|
83
|
+
var dmListClass = "flex flex-col overflow-y-auto border-r border-[var(--line)]";
|
|
84
|
+
var dmListItemClass = "flex w-full items-start gap-3 border-b border-[var(--line)] border-0 bg-transparent px-3 py-3 text-left transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
85
|
+
var dmListItemActiveClass = "bg-[var(--bg-active)]";
|
|
86
|
+
var dmListBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
|
|
87
|
+
var dmListHeaderClass = "flex items-center justify-between gap-2";
|
|
88
|
+
var dmListNameClass = "truncate text-[14px] font-bold text-[var(--ink)]";
|
|
89
|
+
var dmListHandleClass = "truncate text-[13px] text-[var(--ink-soft)]";
|
|
90
|
+
var dmListPreviewClass = "truncate text-[13px] text-[var(--ink-soft)]";
|
|
91
|
+
var dmListTimestampClass = "shrink-0 text-[12px] text-[var(--ink-soft)]";
|
|
92
|
+
var dmThreadClass = "flex min-w-0 flex-col";
|
|
93
|
+
var dmThreadHeaderClass = "sticky top-0 z-10 flex items-center justify-between gap-3 border-b border-[var(--line)] bg-[color:color-mix(in_srgb,var(--bg)_85%,transparent)] px-4 py-3 backdrop-blur";
|
|
94
|
+
var dmThreadTitleClass = "flex items-center gap-3 min-w-0";
|
|
95
|
+
var dmThreadNameClass = "truncate text-[16px] font-bold";
|
|
96
|
+
var dmThreadSubtitleClass = "truncate text-[13px] text-[var(--ink-soft)]";
|
|
97
|
+
var dmMessagesClass = "flex flex-1 flex-col gap-2 overflow-y-auto px-4 py-4";
|
|
98
|
+
var dmMessageRowClass = "flex max-w-[78%] flex-col gap-1";
|
|
99
|
+
var dmMessageRowOutboundClass = "self-end items-end";
|
|
100
|
+
var dmMessageBubbleClass = "rounded-2xl rounded-bl-md px-3.5 py-2 text-[15px] leading-[1.4]";
|
|
101
|
+
var dmMessageBubbleInboundClass = "bg-[var(--bg-active)] text-[var(--ink)]";
|
|
102
|
+
var dmMessageBubbleOutboundClass = "rounded-bl-2xl rounded-br-md bg-[var(--accent)] text-[var(--accent-text)]";
|
|
103
|
+
var dmMessageMetaClass = "flex items-center gap-2 text-[12px] text-[var(--ink-soft)]";
|
|
104
|
+
var dmComposerShellClass = "flex flex-col gap-2 border-t border-[var(--line)] px-4 py-3";
|
|
105
|
+
var profilePreviewClass = "relative inline-flex";
|
|
106
|
+
var profilePreviewTriggerClass = "profile-preview-trigger inline-flex text-inherit";
|
|
107
|
+
var profilePreviewCardClass = "fixed z-40 w-[280px] overflow-y-auto rounded-2xl border border-[var(--line)] bg-[var(--bg-elevated)] p-3 shadow-[0_8px_28px_var(--shadow-strong)]";
|
|
108
|
+
var profilePreviewHeaderClass = "flex items-center gap-3";
|
|
109
|
+
var profilePreviewNameClass = "block text-[15px] font-bold text-[var(--ink)]";
|
|
110
|
+
var profilePreviewHandleClass = "block text-[14px] text-[var(--ink-soft)]";
|
|
111
|
+
var profilePreviewBioClass = "block text-[14px] leading-[1.4] text-[var(--ink)]";
|
|
112
|
+
var profilePreviewMetaClass = "block text-[13px] text-[var(--ink-soft)]";
|
|
113
|
+
var tweetLinkClass = "text-[var(--accent)] hover:underline";
|
|
114
|
+
var tweetMentionClass = "text-[var(--accent)] hover:underline";
|
|
115
|
+
var tweetHashtagClass = tweetMentionClass;
|
|
116
|
+
function tweetMediaGridClass(count) {
|
|
117
|
+
const capped = Math.min(count, 4);
|
|
118
|
+
const layout = count === 1 ? "grid-cols-1" : count === 3 ? "grid-cols-[1.3fr_1fr]" : count === 4 ? "grid-cols-2 grid-rows-2" : "grid-cols-2";
|
|
119
|
+
return cx(`tweet-media-grid tweet-media-grid-${String(capped)}`, "mt-2 grid gap-0.5 overflow-hidden rounded-2xl border border-[var(--line)]", layout);
|
|
120
|
+
}
|
|
121
|
+
function tweetMediaTileClass(index, count) {
|
|
122
|
+
return cx("tweet-media-tile relative block overflow-hidden border-0 bg-[var(--bg-active)] p-0 text-left", count === 1 && "aspect-[16/10]", count === 2 && "aspect-square", count === 3 && index === 0 && "row-span-2 aspect-[3/4]", count === 3 && index !== 0 && "aspect-square", count === 4 && "aspect-square");
|
|
123
|
+
}
|
|
124
|
+
var inboxAnalysisClass = "mt-2 rounded-xl border border-[var(--line)] bg-[var(--bg-hover)] px-3 py-2.5 text-[14px] text-[var(--ink-soft)] [&_p]:mt-1 [&_p]:mb-0";
|
|
125
|
+
var blockRowClass = "flex items-start gap-3 border-b border-[var(--line)] px-4 py-3 transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
126
|
+
var blockRowBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
|
|
127
|
+
var mutedDotClass = "inline-block size-1 shrink-0 rounded-full bg-[var(--ink-soft)]";
|
|
128
|
+
var pillClass = "inline-flex items-center rounded-full px-2 py-0.5 text-[12px] font-semibold";
|
|
129
|
+
var pillSoftClass = "bg-[var(--accent-soft)] text-[var(--accent)]";
|
|
130
|
+
var pillAlertClass = "bg-[var(--alert-soft)] text-[var(--alert)]";
|
|
131
|
+
var timestampClass = "text-[13px] text-[var(--ink-soft)]";
|
|
132
|
+
var bodyCopyClass = feedRowTextClass;
|
|
133
|
+
var contextStatRowClass = "grid grid-cols-[minmax(0,1fr)_auto] items-center gap-3 border-t border-[var(--line)] py-2 first:border-t-0 first:pt-0";
|
|
134
|
+
var contextStatTermClass = "min-w-0 text-[13px] text-[var(--ink-soft)]";
|
|
135
|
+
var contextStatValueClass = "shrink-0 whitespace-nowrap text-right text-[14px] font-bold text-[var(--ink)]";
|
|
136
|
+
//#endregion
|
|
137
|
+
export { feedRowBodyClass as $, sidebarBrandTaglineClass as $t, dmMessageRowClass as A, pillClass as At, embeddedCardClass as B, profilePreviewTriggerClass as Bt, dmListNameClass as C, navLinkLabelCompactClass as Ct, dmMessageBubbleInboundClass as D, pageSubtitleClass as Dt, dmMessageBubbleClass as E, pageHeaderRowClass as Et, dmThreadHeaderClass as F, profilePreviewClass as Ft, embeddedCardNameClass as G, segmentActiveClass as Gt, embeddedCardHandleClass as H, searchFieldInputClass as Ht, dmThreadNameClass as I, profilePreviewHandleClass as It, feedActionButtonClass as J, selectFieldClass as Jt, emptyStateClass as K, segmentClass as Kt, dmThreadSubtitleClass as L, profilePreviewHeaderClass as Lt, dmMessagesClass as M, primaryButtonClass as Mt, dmShellClass as N, profilePreviewBioClass as Nt, dmMessageBubbleOutboundClass as O, pageTitleClass as Ot, dmThreadClass as P, profilePreviewCardClass as Pt, feedRowActionsClass as Q, sidebarBrandMarkClass as Qt, dmThreadTitleClass as R, profilePreviewMetaClass as Rt, dmListItemClass as S, navLinkLabelClass as St, dmListTimestampClass as T, pageHeaderClass as Tt, embeddedCardHeaderClass as U, searchFieldShellClass as Ut, embeddedCardCopyClass as V, searchFieldIconClass as Vt, embeddedCardLabelClass as W, secondaryButtonClass as Wt, feedActionIconWrapClass as X, sidebarBrandCopyClass as Xt, feedActionIconClass as Y, sidebarBrandClass as Yt, feedClass as Z, sidebarBrandCopyCompactClass as Zt, dmListBodyClass as _, tweetMediaTileClass as _n, mutedDotClass as _t, blockRowClass as a, siteShellClass as an, feedRowStatePillActiveClass as at, dmListHeaderClass as b, navLinkCompactClass as bt, composerBarClass as c, tabButtonClass as cn, feedRowTextClass as ct, contextStatRowClass as d, textFieldClass as dn, linkPreviewCardClass as dt, sidebarBrandTitleClass as en, feedRowClass as et, contextStatTermClass as f, textFieldShortClass as fn, linkPreviewDescClass as ft, dmComposerShellClass as g, tweetMediaGridClass as gn, mainColumnDmClass as gt, dangerButtonClass as h, tweetLinkClass as hn, mainColumnClass as ht, blockRowBodyClass as i, sidebarShellCompactClass as in, feedRowNameClass as it, dmMessageRowOutboundClass as j, pillSoftClass as jt, dmMessageMetaClass as k, pillAlertClass as kt, composerInputClass as l, tabButtonIndicatorClass as ln, feedRowTimestampClass as lt, cx as m, tweetHashtagClass as mn, linkPreviewTitleClass as mt, avatarChipLargeClass as n, sidebarNavClass as nn, feedRowHandleClass as nt, bodyClass as o, statusCopyClass as on, feedRowStatePillClass as ot, contextStatValueClass as p, timestampClass as pn, linkPreviewHostClass as pt, errorCopyClass as q, segmentedClass as qt, avatarChipSmallClass as r, sidebarShellClass as rn, feedRowHeaderClass as rt, bodyCopyClass as s, tabButtonActiveClass as sn, feedRowStatePillOpenClass as st, avatarChipClass as t, sidebarFooterClass as tn, feedRowDotClass as tt, composerShellClass as u, tabStripClass as un, inboxAnalysisClass as ut, dmListClass as v, tweetMentionClass as vn, navLinkActiveClass as vt, dmListPreviewClass as w, pageHeaderActionsClass as wt, dmListItemActiveClass as x, navLinkIconClass as xt, dmListHandleClass as y, navLinkClass as yt, embeddedCardBodyClass as z, profilePreviewNameClass as zt };
|
package/{src/components/useDebouncedValue.ts → dist/server/assets/useDebouncedValue-DOnA6Xcy.js}
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
//#region src/components/useDebouncedValue.ts
|
|
3
|
+
function useDebouncedValue(value, delayMs) {
|
|
4
4
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
5
|
-
|
|
6
5
|
useEffect(() => {
|
|
7
6
|
const timeout = window.setTimeout(() => setDebouncedValue(value), delayMs);
|
|
8
7
|
return () => window.clearTimeout(timeout);
|
|
9
8
|
}, [delayMs, value]);
|
|
10
|
-
|
|
11
9
|
return debouncedValue;
|
|
12
10
|
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { useDebouncedValue as t };
|