birdclaw 0.8.3 → 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 +17 -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 +26 -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/command-context.ts +0 -17
- package/src/cli/register-analysis.ts +0 -500
- package/src/cli/register-compose.ts +0 -40
- package/src/cli/register-graph.ts +0 -132
- package/src/cli/register-inbox.ts +0 -41
- package/src/cli/register-storage.ts +0 -106
- package/src/cli-moderation.ts +0 -210
- package/src/cli.ts +0 -1616
- package/src/components/AccountSwitcher.tsx +0 -178
- package/src/components/AppNav.tsx +0 -118
- package/src/components/AvatarChip.tsx +0 -58
- package/src/components/AvatarPreload.ts +0 -149
- 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/MarkdownCitations.tsx +0 -680
- package/src/components/MarkdownViewer.tsx +0 -111
- package/src/components/ProfileAnalysisClient.ts +0 -191
- package/src/components/ProfileAnalysisStream.tsx +0 -259
- package/src/components/ProfilePreview.tsx +0 -131
- 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/links-controller.ts +0 -162
- package/src/components/links-model.ts +0 -198
- package/src/components/network-map-controller.ts +0 -84
- package/src/components/network-map-model.ts +0 -255
- package/src/components/useTimelineRouteData.ts +0 -193
- package/src/lib/account-sync-job.ts +0 -666
- package/src/lib/actions-transport.ts +0 -300
- package/src/lib/analysis-runtime.ts +0 -238
- package/src/lib/api-client.ts +0 -220
- package/src/lib/api-contracts.ts +0 -328
- package/src/lib/archive-finder.ts +0 -185
- package/src/lib/archive-import-plan.ts +0 -102
- package/src/lib/archive-import.ts +0 -2695
- package/src/lib/authored-live.ts +0 -1027
- package/src/lib/avatar-cache.ts +0 -349
- package/src/lib/backup.ts +0 -2652
- 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 -171
- package/src/lib/blocks.ts +0 -387
- package/src/lib/bookmark-sync-job.ts +0 -536
- 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/database-metrics.ts +0 -88
- package/src/lib/database-migrations.ts +0 -34
- package/src/lib/database-schema.ts +0 -312
- package/src/lib/database-writer.ts +0 -69
- package/src/lib/db.ts +0 -889
- package/src/lib/dm-read-model.ts +0 -533
- package/src/lib/dms-live.ts +0 -870
- package/src/lib/effect-runtime.ts +0 -45
- package/src/lib/follow-graph.ts +0 -1087
- 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/import-repository.ts +0 -138
- package/src/lib/inbox.ts +0 -242
- 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/live-sync-engine.ts +0 -209
- package/src/lib/live-transport-gateway.ts +0 -128
- 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 -830
- package/src/lib/mentions-export.ts +0 -147
- package/src/lib/mentions-live.ts +0 -1114
- package/src/lib/moderation-target.ts +0 -227
- package/src/lib/moderation-write.ts +0 -131
- package/src/lib/mutes-write.ts +0 -171
- 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-response-runtime.ts +0 -251
- package/src/lib/openai.ts +0 -117
- package/src/lib/paginated-sync.ts +0 -93
- package/src/lib/period-digest.ts +0 -1364
- 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 -1198
- 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 -6
- package/src/lib/query-actions.ts +0 -437
- package/src/lib/query-client.tsx +0 -47
- package/src/lib/query-read-model-shared.ts +0 -52
- package/src/lib/query-read-models.ts +0 -5
- package/src/lib/query-resource.ts +0 -41
- package/src/lib/query-status.ts +0 -164
- package/src/lib/research.ts +0 -652
- package/src/lib/runtime-services.ts +0 -20
- package/src/lib/search-discussion.ts +0 -812
- package/src/lib/seed.ts +0 -613
- package/src/lib/server-runtime-services.ts +0 -30
- package/src/lib/sqlite.ts +0 -183
- package/src/lib/streaming-ingestion.ts +0 -240
- package/src/lib/sync-cache.ts +0 -70
- package/src/lib/sync-plan.ts +0 -175
- package/src/lib/theme-transition.ts +0 -113
- package/src/lib/theme.tsx +0 -165
- package/src/lib/timeline-collections-live.ts +0 -407
- package/src/lib/timeline-live.ts +0 -302
- package/src/lib/timeline-read-model.ts +0 -1191
- 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-repository.ts +0 -156
- package/src/lib/tweet-search-live.ts +0 -462
- 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 -533
- package/src/lib/whois.ts +0 -1080
- 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 -82
- 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 -121
- package/src/routes/api/search-discussion.tsx +0 -113
- package/src/routes/api/status.tsx +0 -30
- package/src/routes/api/sync.tsx +0 -108
- package/src/routes/api/xurl-rate-limits.tsx +0 -24
- package/src/routes/blocks.tsx +0 -343
- package/src/routes/bookmarks.tsx +0 -18
- package/src/routes/data-sources.tsx +0 -249
- package/src/routes/discuss.tsx +0 -419
- package/src/routes/dms.tsx +0 -415
- package/src/routes/inbox.tsx +0 -232
- package/src/routes/index.tsx +0 -32
- package/src/routes/likes.tsx +0 -18
- package/src/routes/links.tsx +0 -631
- package/src/routes/mentions.tsx +0 -32
- package/src/routes/network-map.tsx +0 -732
- package/src/routes/profile-analyze.tsx +0 -112
- package/src/routes/profiles.$handle.tsx +0 -228
- package/src/routes/rate-limits.tsx +0 -305
- 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
package/src/lib/ui.ts
DELETED
|
@@ -1,529 +0,0 @@
|
|
|
1
|
-
export function cx(...values: Array<string | false | null | undefined>) {
|
|
2
|
-
return values.filter(Boolean).join(" ");
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export const bodyClass =
|
|
6
|
-
"min-h-screen bg-[var(--bg)] font-sans text-[var(--ink)] antialiased text-[15px] leading-[1.4]";
|
|
7
|
-
|
|
8
|
-
/* App shell — sidebar left, single feed column center, optional aside right. */
|
|
9
|
-
export const siteShellClass =
|
|
10
|
-
"mx-auto flex min-h-screen w-full max-w-[1280px] gap-0";
|
|
11
|
-
|
|
12
|
-
export const siteShellDmClass =
|
|
13
|
-
"mx-auto flex min-h-screen w-full max-w-[1280px] gap-0";
|
|
14
|
-
|
|
15
|
-
export const sidebarShellClass =
|
|
16
|
-
"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";
|
|
17
|
-
|
|
18
|
-
export const sidebarShellCompactClass =
|
|
19
|
-
"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";
|
|
20
|
-
|
|
21
|
-
export const sidebarBrandClass =
|
|
22
|
-
"flex items-center gap-2.5 px-2 py-2 text-[var(--ink)] min-[1100px]:px-3";
|
|
23
|
-
|
|
24
|
-
export const sidebarBrandMarkClass = "grid size-10 place-items-center";
|
|
25
|
-
|
|
26
|
-
export const sidebarBrandCopyClass =
|
|
27
|
-
"hidden flex-col leading-tight min-[1100px]:flex";
|
|
28
|
-
|
|
29
|
-
export const sidebarBrandCopyCompactClass = "sr-only";
|
|
30
|
-
|
|
31
|
-
export const sidebarBrandTitleClass = "text-[15px] font-bold tracking-tight";
|
|
32
|
-
|
|
33
|
-
export const sidebarBrandTaglineClass = "text-[12px] text-[var(--ink-soft)]";
|
|
34
|
-
|
|
35
|
-
export const sidebarNavClass = "mt-2 flex flex-col gap-0.5";
|
|
36
|
-
|
|
37
|
-
export const sidebarFooterClass = "flex flex-col gap-2 pb-1";
|
|
38
|
-
|
|
39
|
-
export const navLinkClass =
|
|
40
|
-
"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";
|
|
41
|
-
|
|
42
|
-
export const navLinkCompactClass =
|
|
43
|
-
"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)]";
|
|
44
|
-
|
|
45
|
-
export const navLinkActiveClass = "nav-link-active font-bold";
|
|
46
|
-
|
|
47
|
-
export const navLinkIconClass = "shrink-0";
|
|
48
|
-
|
|
49
|
-
export const navLinkLabelClass = "sr-only min-[1100px]:not-sr-only";
|
|
50
|
-
|
|
51
|
-
export const navLinkLabelCompactClass = "sr-only";
|
|
52
|
-
|
|
53
|
-
/* Main column. */
|
|
54
|
-
export const mainColumnClass =
|
|
55
|
-
"flex w-full min-w-0 max-w-[680px] flex-1 flex-col border-x border-[var(--line)] bg-[var(--bg)]";
|
|
56
|
-
|
|
57
|
-
export const mainColumnDmClass =
|
|
58
|
-
"flex w-full min-w-0 flex-1 flex-col border-x border-[var(--line)] bg-[var(--bg)]";
|
|
59
|
-
|
|
60
|
-
export const pageWrapClass = "flex w-full min-w-0 flex-1 justify-start";
|
|
61
|
-
|
|
62
|
-
/* Sticky page header at top of the main column. */
|
|
63
|
-
export const pageHeaderClass =
|
|
64
|
-
"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";
|
|
65
|
-
|
|
66
|
-
export const pageHeaderRowClass =
|
|
67
|
-
"flex items-center justify-between gap-3 px-4 pt-3 pb-2";
|
|
68
|
-
|
|
69
|
-
export const pageTitleClass = "m-0 text-[20px] font-bold tracking-tight";
|
|
70
|
-
|
|
71
|
-
export const pageSubtitleClass = "text-[13px] text-[var(--ink-soft)]";
|
|
72
|
-
|
|
73
|
-
export const pageHeaderActionsClass = "flex items-center gap-2";
|
|
74
|
-
|
|
75
|
-
/* Sticky tab strip Twitter-style. */
|
|
76
|
-
export const tabStripClass =
|
|
77
|
-
"flex w-full items-stretch border-b border-[var(--line)] overflow-x-auto";
|
|
78
|
-
|
|
79
|
-
export const tabButtonClass =
|
|
80
|
-
"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)]";
|
|
81
|
-
|
|
82
|
-
export const tabButtonActiveClass = "text-[var(--ink)] font-bold";
|
|
83
|
-
|
|
84
|
-
export const tabButtonIndicatorClass =
|
|
85
|
-
"pointer-events-none absolute bottom-0 left-1/2 h-[3px] w-12 -translate-x-1/2 rounded-full bg-[var(--accent)]";
|
|
86
|
-
|
|
87
|
-
/* Feed rows: flat, hairline divider, no boxed cards. */
|
|
88
|
-
export const feedClass = "flex flex-col";
|
|
89
|
-
|
|
90
|
-
export const feedRowClass =
|
|
91
|
-
"flex w-full gap-3 border-b border-[var(--line)] px-4 py-3 transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
92
|
-
|
|
93
|
-
export const feedRowBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
|
|
94
|
-
|
|
95
|
-
export const feedRowHeaderClass =
|
|
96
|
-
"flex min-w-0 items-center gap-1.5 text-[15px]";
|
|
97
|
-
|
|
98
|
-
export const feedRowNameClass =
|
|
99
|
-
"truncate font-bold text-[var(--ink)] hover:underline";
|
|
100
|
-
|
|
101
|
-
export const feedRowHandleClass = "truncate text-[var(--ink-soft)]";
|
|
102
|
-
|
|
103
|
-
export const feedRowDotClass = "text-[var(--ink-soft)]";
|
|
104
|
-
|
|
105
|
-
export const feedRowTimestampClass =
|
|
106
|
-
"shrink-0 text-[var(--ink-soft)] hover:underline";
|
|
107
|
-
|
|
108
|
-
export const feedRowMetaClass =
|
|
109
|
-
"flex flex-wrap items-center gap-2 text-[13px] text-[var(--ink-soft)]";
|
|
110
|
-
|
|
111
|
-
export const feedRowActionsClass =
|
|
112
|
-
"mt-2 flex max-w-md items-center justify-between text-[var(--ink-soft)]";
|
|
113
|
-
|
|
114
|
-
export const feedActionButtonClass =
|
|
115
|
-
"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";
|
|
116
|
-
|
|
117
|
-
export const feedActionLikeClass = "hover:text-[var(--like)]";
|
|
118
|
-
|
|
119
|
-
export const feedActionIconWrapClass =
|
|
120
|
-
"grid size-[34px] place-items-center rounded-full transition-colors duration-150 group-hover/action:bg-[var(--accent-soft)]";
|
|
121
|
-
|
|
122
|
-
export const feedActionIconWrapLikeClass =
|
|
123
|
-
"group-hover/action:bg-[var(--like-soft)]";
|
|
124
|
-
|
|
125
|
-
export const feedActionIconClass = "size-[18px]";
|
|
126
|
-
|
|
127
|
-
export const feedRowTextClass =
|
|
128
|
-
"whitespace-pre-wrap break-words text-[15px] leading-[1.45] text-[var(--ink)] [overflow-wrap:anywhere]";
|
|
129
|
-
|
|
130
|
-
export const feedRowBadgeClass =
|
|
131
|
-
"inline-flex items-center gap-1 rounded-full bg-[var(--accent-soft)] px-2 py-0.5 text-[12px] font-semibold text-[var(--accent)]";
|
|
132
|
-
|
|
133
|
-
export const feedRowBadgeAlertClass =
|
|
134
|
-
"bg-[var(--alert-soft)] text-[var(--alert)]";
|
|
135
|
-
|
|
136
|
-
export const feedRowBadgeNeutralClass =
|
|
137
|
-
"bg-[var(--bg-active)] text-[var(--ink-soft)]";
|
|
138
|
-
|
|
139
|
-
export const feedRowStatePillClass =
|
|
140
|
-
"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)]";
|
|
141
|
-
|
|
142
|
-
export const feedRowStatePillActiveClass =
|
|
143
|
-
"border-[color:color-mix(in_srgb,var(--accent)_35%,var(--line))] bg-[var(--accent-soft)] text-[var(--accent)]";
|
|
144
|
-
|
|
145
|
-
export const feedRowStatePillOpenClass =
|
|
146
|
-
"border-[color:color-mix(in_srgb,var(--ink-soft)_34%,var(--line))] bg-transparent text-[var(--ink-soft)]";
|
|
147
|
-
|
|
148
|
-
/* Forms / inputs. */
|
|
149
|
-
export const searchFieldShellClass =
|
|
150
|
-
"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)]";
|
|
151
|
-
|
|
152
|
-
export const searchFieldIconClass =
|
|
153
|
-
"size-[18px] text-[var(--ink-soft)] shrink-0";
|
|
154
|
-
|
|
155
|
-
export const searchFieldInputClass =
|
|
156
|
-
"min-w-0 flex-1 border-0 bg-transparent text-[14px] text-[var(--ink)] outline-none placeholder:text-[var(--ink-soft)]";
|
|
157
|
-
|
|
158
|
-
export const textFieldClass =
|
|
159
|
-
"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";
|
|
160
|
-
|
|
161
|
-
export const textFieldWideClass = "w-full";
|
|
162
|
-
|
|
163
|
-
export const textFieldShortClass = "w-[120px]";
|
|
164
|
-
|
|
165
|
-
export const selectFieldClass = cx(textFieldClass, "appearance-none pr-8");
|
|
166
|
-
|
|
167
|
-
/* Buttons. */
|
|
168
|
-
export const primaryButtonClass =
|
|
169
|
-
"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";
|
|
170
|
-
|
|
171
|
-
export const primaryButtonLargeClass =
|
|
172
|
-
"inline-flex items-center justify-center gap-1.5 rounded-full border-0 bg-[var(--accent)] px-5 py-2.5 text-[15px] 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";
|
|
173
|
-
|
|
174
|
-
export const secondaryButtonClass =
|
|
175
|
-
"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";
|
|
176
|
-
|
|
177
|
-
export const dangerButtonClass =
|
|
178
|
-
"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";
|
|
179
|
-
|
|
180
|
-
export const actionButtonClass = primaryButtonClass;
|
|
181
|
-
|
|
182
|
-
/* Legacy segmented control retained for routes that still use it (compact pill). */
|
|
183
|
-
export const segmentedClass =
|
|
184
|
-
"inline-flex shrink-0 items-center gap-1 rounded-full border border-[var(--line)] bg-[var(--bg)] p-1";
|
|
185
|
-
|
|
186
|
-
export const segmentClass =
|
|
187
|
-
"rounded-full border-0 bg-transparent px-3 py-1 text-[13px] font-medium text-[var(--ink-soft)] capitalize transition-colors duration-150";
|
|
188
|
-
|
|
189
|
-
export const segmentActiveClass = "bg-[var(--bg-active)] text-[var(--ink)]";
|
|
190
|
-
|
|
191
|
-
/* Composer (reply textarea). */
|
|
192
|
-
export const composerShellClass =
|
|
193
|
-
"mt-2 flex flex-col gap-2 border-t border-[var(--line)] pt-3";
|
|
194
|
-
|
|
195
|
-
export const composerInputClass =
|
|
196
|
-
"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)]";
|
|
197
|
-
|
|
198
|
-
export const composerBarClass = "flex items-center justify-between gap-3";
|
|
199
|
-
|
|
200
|
-
/* Empty / loading. */
|
|
201
|
-
export const emptyStateClass = "px-6 py-10 text-center text-[var(--ink-soft)]";
|
|
202
|
-
|
|
203
|
-
export const errorCopyClass =
|
|
204
|
-
"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)]";
|
|
205
|
-
|
|
206
|
-
export const statusCopyClass =
|
|
207
|
-
"mx-4 my-3 rounded-md border border-[var(--line)] bg-[var(--bg-elevated)] px-3 py-2 text-[13px] text-[var(--ink-soft)]";
|
|
208
|
-
|
|
209
|
-
/* Avatars. */
|
|
210
|
-
export const avatarChipClass =
|
|
211
|
-
"avatar-chip inline-grid size-10 shrink-0 place-items-center overflow-hidden rounded-full text-[14px] font-bold text-white";
|
|
212
|
-
|
|
213
|
-
export const avatarChipLargeClass = "avatar-chip-large size-16 text-[18px]";
|
|
214
|
-
|
|
215
|
-
export const avatarChipSmallClass = "avatar-chip-small size-8 text-[12px]";
|
|
216
|
-
|
|
217
|
-
/* Embedded tweet / link preview (rounded box, used inside feed row body). */
|
|
218
|
-
export const embeddedCardClass =
|
|
219
|
-
"mt-2 overflow-hidden rounded-2xl border border-[var(--line)] transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
220
|
-
|
|
221
|
-
export const embeddedCardBodyClass = "flex flex-col gap-2 px-3 py-2.5";
|
|
222
|
-
|
|
223
|
-
export const embeddedCardHeaderClass = "flex items-center gap-1.5 text-[14px]";
|
|
224
|
-
|
|
225
|
-
export const embeddedCardNameClass = "font-bold text-[var(--ink)] truncate";
|
|
226
|
-
|
|
227
|
-
export const embeddedCardHandleClass = "text-[var(--ink-soft)] truncate";
|
|
228
|
-
|
|
229
|
-
export const embeddedCardLabelClass =
|
|
230
|
-
"text-[12px] uppercase tracking-wide text-[var(--ink-soft)]";
|
|
231
|
-
|
|
232
|
-
export const embeddedCardCopyClass =
|
|
233
|
-
"whitespace-pre-wrap text-[14px] leading-[1.4] text-[var(--ink)] [overflow-wrap:anywhere]";
|
|
234
|
-
|
|
235
|
-
export const linkPreviewCardClass =
|
|
236
|
-
"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)]";
|
|
237
|
-
|
|
238
|
-
export const linkPreviewTitleClass =
|
|
239
|
-
"line-clamp-2 font-bold leading-tight text-[var(--ink)]";
|
|
240
|
-
|
|
241
|
-
export const linkPreviewDescClass =
|
|
242
|
-
"line-clamp-2 text-[14px] leading-snug text-[var(--ink-soft)]";
|
|
243
|
-
|
|
244
|
-
export const linkPreviewHostClass =
|
|
245
|
-
"text-[13px] text-[var(--ink-soft)] truncate";
|
|
246
|
-
|
|
247
|
-
/* DM grid. */
|
|
248
|
-
export const dmShellClass =
|
|
249
|
-
"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)]";
|
|
250
|
-
|
|
251
|
-
export const dmListClass =
|
|
252
|
-
"flex flex-col overflow-y-auto border-r border-[var(--line)]";
|
|
253
|
-
|
|
254
|
-
export const dmListItemClass =
|
|
255
|
-
"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)]";
|
|
256
|
-
|
|
257
|
-
export const dmListItemActiveClass = "bg-[var(--bg-active)]";
|
|
258
|
-
|
|
259
|
-
export const dmListBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
|
|
260
|
-
|
|
261
|
-
export const dmListHeaderClass = "flex items-center justify-between gap-2";
|
|
262
|
-
|
|
263
|
-
export const dmListNameClass =
|
|
264
|
-
"truncate text-[14px] font-bold text-[var(--ink)]";
|
|
265
|
-
|
|
266
|
-
export const dmListHandleClass = "truncate text-[13px] text-[var(--ink-soft)]";
|
|
267
|
-
|
|
268
|
-
export const dmListPreviewClass = "truncate text-[13px] text-[var(--ink-soft)]";
|
|
269
|
-
|
|
270
|
-
export const dmListTimestampClass =
|
|
271
|
-
"shrink-0 text-[12px] text-[var(--ink-soft)]";
|
|
272
|
-
|
|
273
|
-
export const dmThreadClass = "flex min-w-0 flex-col";
|
|
274
|
-
|
|
275
|
-
export const dmThreadHeaderClass =
|
|
276
|
-
"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";
|
|
277
|
-
|
|
278
|
-
export const dmThreadTitleClass = "flex items-center gap-3 min-w-0";
|
|
279
|
-
|
|
280
|
-
export const dmThreadNameClass = "truncate text-[16px] font-bold";
|
|
281
|
-
|
|
282
|
-
export const dmThreadSubtitleClass =
|
|
283
|
-
"truncate text-[13px] text-[var(--ink-soft)]";
|
|
284
|
-
|
|
285
|
-
export const dmMessagesClass =
|
|
286
|
-
"flex flex-1 flex-col gap-2 overflow-y-auto px-4 py-4";
|
|
287
|
-
|
|
288
|
-
export const dmMessageRowClass = "flex max-w-[78%] flex-col gap-1";
|
|
289
|
-
|
|
290
|
-
export const dmMessageRowOutboundClass = "self-end items-end";
|
|
291
|
-
|
|
292
|
-
export const dmMessageBubbleClass =
|
|
293
|
-
"rounded-2xl rounded-bl-md px-3.5 py-2 text-[15px] leading-[1.4]";
|
|
294
|
-
|
|
295
|
-
export const dmMessageBubbleInboundClass =
|
|
296
|
-
"bg-[var(--bg-active)] text-[var(--ink)]";
|
|
297
|
-
|
|
298
|
-
export const dmMessageBubbleOutboundClass =
|
|
299
|
-
"rounded-bl-2xl rounded-br-md bg-[var(--accent)] text-[var(--accent-text)]";
|
|
300
|
-
|
|
301
|
-
export const dmMessageMetaClass =
|
|
302
|
-
"flex items-center gap-2 text-[12px] text-[var(--ink-soft)]";
|
|
303
|
-
|
|
304
|
-
export const dmComposerShellClass =
|
|
305
|
-
"flex flex-col gap-2 border-t border-[var(--line)] px-4 py-3";
|
|
306
|
-
|
|
307
|
-
/* Profile hovercard. */
|
|
308
|
-
export const profilePreviewClass = "relative inline-flex";
|
|
309
|
-
|
|
310
|
-
export const profilePreviewTriggerClass =
|
|
311
|
-
"profile-preview-trigger inline-flex text-inherit";
|
|
312
|
-
|
|
313
|
-
export const profilePreviewCardClass =
|
|
314
|
-
"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)]";
|
|
315
|
-
|
|
316
|
-
export const profilePreviewHeaderClass = "flex items-center gap-3";
|
|
317
|
-
|
|
318
|
-
export const profilePreviewNameClass =
|
|
319
|
-
"block text-[15px] font-bold text-[var(--ink)]";
|
|
320
|
-
|
|
321
|
-
export const profilePreviewHandleClass =
|
|
322
|
-
"block text-[14px] text-[var(--ink-soft)]";
|
|
323
|
-
|
|
324
|
-
export const profilePreviewBioClass =
|
|
325
|
-
"block text-[14px] leading-[1.4] text-[var(--ink)]";
|
|
326
|
-
|
|
327
|
-
export const profilePreviewMetaClass =
|
|
328
|
-
"block text-[13px] text-[var(--ink-soft)]";
|
|
329
|
-
|
|
330
|
-
/* Rich tweet text. */
|
|
331
|
-
export const tweetLinkClass = "text-[var(--accent)] hover:underline";
|
|
332
|
-
|
|
333
|
-
export const tweetMentionClass = "text-[var(--accent)] hover:underline";
|
|
334
|
-
|
|
335
|
-
export const tweetHashtagClass = tweetMentionClass;
|
|
336
|
-
|
|
337
|
-
/* Media grid (Twitter-style with rounded corners). */
|
|
338
|
-
export function tweetMediaGridClass(count: number) {
|
|
339
|
-
const capped = Math.min(count, 4);
|
|
340
|
-
const layout =
|
|
341
|
-
count === 1
|
|
342
|
-
? "grid-cols-1"
|
|
343
|
-
: count === 3
|
|
344
|
-
? "grid-cols-[1.3fr_1fr]"
|
|
345
|
-
: count === 4
|
|
346
|
-
? "grid-cols-2 grid-rows-2"
|
|
347
|
-
: "grid-cols-2";
|
|
348
|
-
|
|
349
|
-
return cx(
|
|
350
|
-
`tweet-media-grid tweet-media-grid-${String(capped)}`,
|
|
351
|
-
"mt-2 grid gap-0.5 overflow-hidden rounded-2xl border border-[var(--line)]",
|
|
352
|
-
layout,
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
export function tweetMediaTileClass(index: number, count: number) {
|
|
357
|
-
return cx(
|
|
358
|
-
"tweet-media-tile relative block overflow-hidden border-0 bg-[var(--bg-active)] p-0 text-left",
|
|
359
|
-
count === 1 && "aspect-[16/10]",
|
|
360
|
-
count === 2 && "aspect-square",
|
|
361
|
-
count === 3 && index === 0 && "row-span-2 aspect-[3/4]",
|
|
362
|
-
count === 3 && index !== 0 && "aspect-square",
|
|
363
|
-
count === 4 && "aspect-square",
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/* Inbox / triage card. */
|
|
368
|
-
export const inboxAnalysisClass =
|
|
369
|
-
"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";
|
|
370
|
-
|
|
371
|
-
/* Block list item. */
|
|
372
|
-
export const blockRowClass =
|
|
373
|
-
"flex items-start gap-3 border-b border-[var(--line)] px-4 py-3 transition-colors duration-150 hover:bg-[var(--bg-hover)]";
|
|
374
|
-
|
|
375
|
-
export const blockRowBodyClass = "flex min-w-0 flex-1 flex-col gap-1";
|
|
376
|
-
|
|
377
|
-
/* Aside (optional right column for stats). Hidden on small screens. */
|
|
378
|
-
export const asideShellClass =
|
|
379
|
-
"sticky top-0 hidden h-screen w-[300px] shrink-0 flex-col gap-4 overflow-y-auto px-4 py-4 min-[1180px]:flex";
|
|
380
|
-
|
|
381
|
-
export const asideCardClass =
|
|
382
|
-
"rounded-2xl border border-[var(--line)] bg-[var(--bg-elevated)] p-4";
|
|
383
|
-
|
|
384
|
-
export const asideTitleClass = "text-[15px] font-bold text-[var(--ink)]";
|
|
385
|
-
|
|
386
|
-
export const asideStatRowClass =
|
|
387
|
-
"flex items-baseline justify-between border-t border-[var(--line)] py-2 first:border-t-0 first:pt-0";
|
|
388
|
-
|
|
389
|
-
export const asideStatTermClass = "text-[13px] text-[var(--ink-soft)]";
|
|
390
|
-
|
|
391
|
-
export const asideStatValueClass = "text-[14px] font-bold text-[var(--ink)]";
|
|
392
|
-
|
|
393
|
-
/* Misc legacy aliases kept for compatibility while routes/components migrate. */
|
|
394
|
-
export const eyebrowClass =
|
|
395
|
-
"text-[12px] font-semibold uppercase tracking-wide text-[var(--ink-soft)]";
|
|
396
|
-
|
|
397
|
-
export const brandMarkClass = sidebarBrandTitleClass;
|
|
398
|
-
|
|
399
|
-
export const navClass = sidebarShellClass;
|
|
400
|
-
|
|
401
|
-
export const navLinksClass = sidebarNavClass;
|
|
402
|
-
|
|
403
|
-
export const heroShellClass = "flex flex-col gap-1 px-4 pt-3 pb-2";
|
|
404
|
-
|
|
405
|
-
export const heroShellDmClass = "";
|
|
406
|
-
|
|
407
|
-
export const heroControlsClass = "flex flex-wrap items-center gap-2 px-4 py-2";
|
|
408
|
-
|
|
409
|
-
export const heroControlsDmClass = "";
|
|
410
|
-
|
|
411
|
-
export const heroControlsBlocksClass = "";
|
|
412
|
-
|
|
413
|
-
export const heroTitleClass = pageTitleClass;
|
|
414
|
-
|
|
415
|
-
export const heroCopyClass = pageSubtitleClass;
|
|
416
|
-
|
|
417
|
-
export const surfaceCardClass =
|
|
418
|
-
"rounded-2xl border border-[var(--line)] bg-[var(--bg-elevated)]";
|
|
419
|
-
|
|
420
|
-
export const contentCardClass = feedRowClass;
|
|
421
|
-
|
|
422
|
-
export const cardHeaderClass = "flex items-start justify-between gap-3";
|
|
423
|
-
|
|
424
|
-
export const cardFooterClass = "flex items-center justify-between gap-3";
|
|
425
|
-
|
|
426
|
-
export const identityBlockClass = "flex items-start gap-3";
|
|
427
|
-
|
|
428
|
-
export const identityRowClass =
|
|
429
|
-
"flex flex-wrap items-center gap-1.5 text-[15px] text-[var(--ink-soft)]";
|
|
430
|
-
|
|
431
|
-
export const metaRowClass =
|
|
432
|
-
"flex flex-wrap items-center gap-1.5 text-[13px] text-[var(--ink-soft)]";
|
|
433
|
-
|
|
434
|
-
export const mutedDotClass =
|
|
435
|
-
"inline-block size-1 shrink-0 rounded-full bg-[var(--ink-soft)]";
|
|
436
|
-
|
|
437
|
-
export const metaStackClass = "flex flex-col items-end gap-1";
|
|
438
|
-
|
|
439
|
-
export const pillClass =
|
|
440
|
-
"inline-flex items-center rounded-full px-2 py-0.5 text-[12px] font-semibold";
|
|
441
|
-
|
|
442
|
-
export const pillSoftClass = "bg-[var(--accent-soft)] text-[var(--accent)]";
|
|
443
|
-
|
|
444
|
-
export const pillAlertClass = "bg-[var(--alert-soft)] text-[var(--alert)]";
|
|
445
|
-
|
|
446
|
-
export const timestampClass = "text-[13px] text-[var(--ink-soft)]";
|
|
447
|
-
|
|
448
|
-
export const bodyCopyClass = feedRowTextClass;
|
|
449
|
-
|
|
450
|
-
export const inboxTitleClass = "text-[16px] font-bold text-[var(--ink)]";
|
|
451
|
-
|
|
452
|
-
export const metricRowClass =
|
|
453
|
-
"flex flex-wrap items-center gap-3 text-[13px] text-[var(--ink-soft)]";
|
|
454
|
-
|
|
455
|
-
export const actionRowClass = "flex items-center gap-2";
|
|
456
|
-
|
|
457
|
-
export const feedPageClass = "flex w-full min-w-0 flex-col";
|
|
458
|
-
|
|
459
|
-
export const timelineLaneClass = feedClass;
|
|
460
|
-
|
|
461
|
-
export const inboxLaneClass = feedClass;
|
|
462
|
-
|
|
463
|
-
export const dmPageClass = "flex w-full min-w-0 flex-col";
|
|
464
|
-
|
|
465
|
-
export const stackGridClass = "flex flex-col";
|
|
466
|
-
|
|
467
|
-
/* Embedded tweet legacy aliases. */
|
|
468
|
-
export const embeddedTweetCardClass = embeddedCardClass;
|
|
469
|
-
|
|
470
|
-
export const embeddedTweetLabelClass = embeddedCardLabelClass;
|
|
471
|
-
|
|
472
|
-
export const embeddedTweetHeaderClass = embeddedCardHeaderClass;
|
|
473
|
-
|
|
474
|
-
export const embeddedTweetAuthorClass = "flex flex-wrap items-center gap-1.5";
|
|
475
|
-
|
|
476
|
-
export const embeddedTweetCopyClass = embeddedCardCopyClass;
|
|
477
|
-
|
|
478
|
-
/* DM legacy aliases (still used by DmWorkspace until rewrite). */
|
|
479
|
-
export const dmGridClass = dmShellClass;
|
|
480
|
-
|
|
481
|
-
export const dmListItemNonActive = "";
|
|
482
|
-
|
|
483
|
-
export const dmListCopyClass = dmListBodyClass;
|
|
484
|
-
|
|
485
|
-
export const dmPreviewTextClass = dmListPreviewClass;
|
|
486
|
-
|
|
487
|
-
export const threadShellClass = dmThreadClass;
|
|
488
|
-
|
|
489
|
-
export const threadHeaderClass = dmThreadHeaderClass;
|
|
490
|
-
|
|
491
|
-
export const threadTitleClass = dmThreadNameClass;
|
|
492
|
-
|
|
493
|
-
export const threadSubtitleClass = dmThreadSubtitleClass;
|
|
494
|
-
|
|
495
|
-
export const threadBioClass = "text-[14px] text-[var(--ink-soft)]";
|
|
496
|
-
|
|
497
|
-
export const threadDetailColumnClass =
|
|
498
|
-
"flex flex-col gap-3 rounded-2xl border border-[var(--line)] bg-[var(--bg-elevated)] p-4";
|
|
499
|
-
|
|
500
|
-
export const threadDetailHeaderClass = "flex items-center gap-3";
|
|
501
|
-
|
|
502
|
-
export const messageStackClass = dmMessagesClass;
|
|
503
|
-
|
|
504
|
-
export const messageRowClass = dmMessageRowClass;
|
|
505
|
-
|
|
506
|
-
export const messageRowOutboundClass = dmMessageRowOutboundClass;
|
|
507
|
-
|
|
508
|
-
export const messageMetaClass = dmMessageMetaClass;
|
|
509
|
-
|
|
510
|
-
export const messageBubbleClass = dmMessageBubbleClass;
|
|
511
|
-
|
|
512
|
-
export const messageBubbleInboundClass = dmMessageBubbleInboundClass;
|
|
513
|
-
|
|
514
|
-
export const messageBubbleOutboundClass = dmMessageBubbleOutboundClass;
|
|
515
|
-
|
|
516
|
-
export const contextHandleClass = "text-[14px] text-[var(--ink-soft)]";
|
|
517
|
-
|
|
518
|
-
export const contextBioClass = "text-[14px] leading-[1.4] text-[var(--ink)]";
|
|
519
|
-
|
|
520
|
-
export const contextStatsClass = "flex flex-col gap-0";
|
|
521
|
-
|
|
522
|
-
export const contextStatRowClass =
|
|
523
|
-
"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";
|
|
524
|
-
|
|
525
|
-
export const contextStatTermClass =
|
|
526
|
-
"min-w-0 text-[13px] text-[var(--ink-soft)]";
|
|
527
|
-
|
|
528
|
-
export const contextStatValueClass =
|
|
529
|
-
"shrink-0 whitespace-nowrap text-right text-[14px] font-bold text-[var(--ink)]";
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import type { Database } from "./sqlite";
|
|
2
|
-
import type { LinkIndexItem } from "./types";
|
|
3
|
-
|
|
4
|
-
export interface UrlExpansionRecordInput {
|
|
5
|
-
url: string;
|
|
6
|
-
expandedUrl: string;
|
|
7
|
-
finalUrl: string;
|
|
8
|
-
status: "hit" | "miss" | "error";
|
|
9
|
-
title?: string | null;
|
|
10
|
-
description?: string | null;
|
|
11
|
-
imageUrl?: string | null;
|
|
12
|
-
siteName?: string | null;
|
|
13
|
-
error?: string;
|
|
14
|
-
source: string;
|
|
15
|
-
updatedAt: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function getTweetTarget(url: string) {
|
|
19
|
-
try {
|
|
20
|
-
const parsed = new URL(url);
|
|
21
|
-
const host = parsed.hostname.toLowerCase();
|
|
22
|
-
if (
|
|
23
|
-
host !== "x.com" &&
|
|
24
|
-
host !== "twitter.com" &&
|
|
25
|
-
host !== "mobile.twitter.com" &&
|
|
26
|
-
host !== "www.x.com" &&
|
|
27
|
-
host !== "www.twitter.com"
|
|
28
|
-
) {
|
|
29
|
-
return {};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
33
|
-
const statusIndex = parts.findIndex(
|
|
34
|
-
(part) => part === "status" || part === "statuses",
|
|
35
|
-
);
|
|
36
|
-
if (statusIndex === -1 || !parts[statusIndex + 1]) {
|
|
37
|
-
return {};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const tweetId = parts[statusIndex + 1]?.match(/^\d+/)?.[0];
|
|
41
|
-
const handle =
|
|
42
|
-
parts[statusIndex - 1] && parts[statusIndex - 1] !== "i"
|
|
43
|
-
? parts[statusIndex - 1]
|
|
44
|
-
: undefined;
|
|
45
|
-
return {
|
|
46
|
-
expandedTweetId: tweetId,
|
|
47
|
-
expandedHandle: handle,
|
|
48
|
-
};
|
|
49
|
-
} catch {
|
|
50
|
-
return {};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function normalizeUrlExpansionForIndex(
|
|
55
|
-
item: UrlExpansionRecordInput,
|
|
56
|
-
): LinkIndexItem {
|
|
57
|
-
const target = getTweetTarget(item.finalUrl);
|
|
58
|
-
return {
|
|
59
|
-
shortUrl: item.url,
|
|
60
|
-
expandedUrl: item.expandedUrl,
|
|
61
|
-
finalUrl: item.finalUrl,
|
|
62
|
-
status: item.status,
|
|
63
|
-
expandedTweetId: target.expandedTweetId ?? null,
|
|
64
|
-
expandedHandle: target.expandedHandle ?? null,
|
|
65
|
-
title: item.title ?? null,
|
|
66
|
-
description: item.description ?? null,
|
|
67
|
-
imageUrl: item.imageUrl ?? null,
|
|
68
|
-
siteName: item.siteName ?? null,
|
|
69
|
-
error: item.error ?? null,
|
|
70
|
-
source: item.source,
|
|
71
|
-
updatedAt: item.updatedAt,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function upsertUrlExpansion(db: Database, item: LinkIndexItem) {
|
|
76
|
-
db.prepare(`
|
|
77
|
-
insert into url_expansions (
|
|
78
|
-
short_url, expanded_url, final_url, status, expanded_tweet_id,
|
|
79
|
-
expanded_handle, title, description, image_url, site_name, error, source,
|
|
80
|
-
updated_at
|
|
81
|
-
) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
82
|
-
on conflict(short_url) do update set
|
|
83
|
-
expanded_url = excluded.expanded_url,
|
|
84
|
-
final_url = excluded.final_url,
|
|
85
|
-
status = excluded.status,
|
|
86
|
-
expanded_tweet_id = excluded.expanded_tweet_id,
|
|
87
|
-
expanded_handle = excluded.expanded_handle,
|
|
88
|
-
title = excluded.title,
|
|
89
|
-
description = excluded.description,
|
|
90
|
-
image_url = excluded.image_url,
|
|
91
|
-
site_name = excluded.site_name,
|
|
92
|
-
error = excluded.error,
|
|
93
|
-
source = excluded.source,
|
|
94
|
-
updated_at = excluded.updated_at
|
|
95
|
-
`).run(
|
|
96
|
-
item.shortUrl,
|
|
97
|
-
item.expandedUrl,
|
|
98
|
-
item.finalUrl,
|
|
99
|
-
item.status,
|
|
100
|
-
item.expandedTweetId,
|
|
101
|
-
item.expandedHandle,
|
|
102
|
-
item.title,
|
|
103
|
-
item.description,
|
|
104
|
-
item.imageUrl,
|
|
105
|
-
item.siteName,
|
|
106
|
-
item.error,
|
|
107
|
-
item.source,
|
|
108
|
-
item.updatedAt,
|
|
109
|
-
);
|
|
110
|
-
}
|