Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
325 commits
Select commit Hold shift + click to select a range
986b2e3
test(web-foldkit): scroll past the 2400 px render chunk in the chunki…
Makisuo Oct 7, 2026
98c8aca
feat(web-foldkit): port Slider
Makisuo Oct 7, 2026
98adcee
feat(ui-parity): fixture live events and scroll/render diagnostics
Makisuo Oct 7, 2026
8435b27
docs: S4 chat list and S2 data layer decision records
Makisuo Oct 7, 2026
457178c
wiring: chat channel route, page, sidebar and the chat-list parity area
Makisuo Oct 7, 2026
24fef4f
fix(ui-parity): reseed Math.random before the appearance remix
Makisuo Oct 7, 2026
1506c59
perf(gallery): load legacy gallery entries lazily
Makisuo Oct 7, 2026
665a116
feat(web-foldkit): port Select
Makisuo Oct 7, 2026
36c05ed
Merge fk/s4-chat-list: S4 virtualized chat list, S2 data decision, he…
Makisuo Oct 7, 2026
1b9c3ef
feat(web-foldkit): port Popover
Makisuo Oct 7, 2026
794cd38
feat(web-foldkit): port FieldValidationState and FormErrorSummary
Makisuo Oct 7, 2026
fa0b634
docs(foldkit): S2 and S4 decided, new harness gotchas
Makisuo Oct 7, 2026
98e3241
feat(web-foldkit): port ChoiceBox
Makisuo Oct 7, 2026
c2107fc
feat(web-foldkit): port Sheet
Makisuo Oct 7, 2026
47a57b8
feat(web-foldkit): port DateField, TimeField and DateInput
Makisuo Oct 7, 2026
2587314
feat(web-foldkit): port ContextMenu
Makisuo Oct 7, 2026
a5d4570
feat(web-foldkit): port InputOTP
Makisuo Oct 7, 2026
f3013ef
Merge fk/kit-forms: UI kit buttons, fields and forms with gallery parity
Makisuo Oct 7, 2026
2d5820b
feat(web-foldkit): port ComboBox
Makisuo Oct 7, 2026
a9eccef
feat(web-foldkit): port TimezoneSelect
Makisuo Oct 7, 2026
151e324
feat(web-foldkit): port CommandMenu
Makisuo Oct 7, 2026
38584da
feat(web-foldkit): port CommandMenu form pages
Makisuo Oct 7, 2026
4105193
test(ui-parity): gallery scenarios for Modal sizes and options
Makisuo Oct 7, 2026
d728d16
wiring: register the gallery-overlays scenario area
Makisuo Oct 7, 2026
60c6c2c
Merge fk/kit-overlays: UI kit overlays with gallery parity
Makisuo Oct 7, 2026
6f7eccf
docs(foldkit): S5 primitive parity record
Makisuo Oct 7, 2026
c81e120
chore(ui-parity): re-pin the legacy baseline to 6f7eccf00 (UI kit gal…
Makisuo Oct 7, 2026
f1197eb
feat(web-foldkit): Toast, a sonner port with gallery parity
Makisuo Oct 7, 2026
39395e0
refactor(web): share embed styles, code block leaves and date-fns wit…
Makisuo Oct 7, 2026
11008b7
feat(web-foldkit): tooltip trigger delay (initWithDelay)
Makisuo Oct 7, 2026
1381d17
feat(web-foldkit): message rendering modules for the chat read path
Makisuo Oct 7, 2026
9c4a54c
feat(web-foldkit): channel page read path with lookups, headers, bann…
Makisuo Oct 7, 2026
337c18d
feat(web-foldkit): Menu link items, section headers and reflectEntries
Makisuo Oct 7, 2026
674417e
feat(web-foldkit): app skeleton with all 39 routes, page registry and…
Makisuo Oct 7, 2026
e692354
Merge fk/app-skeleton: 39 routes, page registry, shell Submodel, user…
Makisuo Oct 7, 2026
9e52e32
feat(web-foldkit): menu header slot (MenuHeader before the root entries)
Makisuo Oct 7, 2026
7a0cef3
fix(web-foldkit): stuck divider follows LegendList's recalculation rule
Makisuo Oct 7, 2026
bf83a1a
feat(web-foldkit): reading overlays: hover toolbar, context and more-…
Makisuo Oct 7, 2026
df47732
refactor(web-foldkit): one interaction model for toggles, tooltips an…
Makisuo Oct 7, 2026
27c7a3d
Merge branch 'experiment-2.0' into fk/kit-followups
Makisuo Oct 7, 2026
79ad42a
feat(web-foldkit): Toast.Request, a schema-backed toast request for r…
Makisuo Oct 7, 2026
eda391b
Merge experiment-2.0 (app skeleton) into fk/chat-read
Makisuo Oct 7, 2026
4aede7b
feat(web-foldkit): port my-settings desktop page
Makisuo Oct 7, 2026
e4ec81b
fix(web-foldkit): toolbar content as a function so its tooltips and m…
Makisuo Oct 7, 2026
0e01eef
feat(web-foldkit): port my-settings linked accounts page
Makisuo Oct 7, 2026
325bd0c
feat(web-foldkit): integrations index page
Makisuo Oct 7, 2026
406bca4
feat(web-foldkit): channel settings index redirect and overview tab
Makisuo Oct 7, 2026
8b69ce0
feat(web-foldkit): notifications inbox and its category tabs
Makisuo Oct 7, 2026
852e988
Merge fk/scr-notifications: notifications inbox and category tabs
Makisuo Oct 7, 2026
430bce6
feat(web-foldkit): sheet ariaLabel and overlay attributes
Makisuo Oct 7, 2026
fd94d30
feat(web-foldkit): mobile shell with bottom nav, sidebar sheet and mo…
Makisuo Oct 7, 2026
7892ed4
feat(web-foldkit): RequestedMobileSidebar out-message and the chat he…
Makisuo Oct 7, 2026
0c01a49
feat(web-foldkit): installed apps page
Makisuo Oct 7, 2026
3f35ad9
feat(web-foldkit): port my-settings notifications page
Makisuo Oct 7, 2026
aa188e3
feat(web-foldkit): marketplace page
Makisuo Oct 7, 2026
bfb11b9
feat(web-foldkit): sign-in and sign-up pages mount Clerk's prebuilt f…
Makisuo Oct 7, 2026
34426a2
feat(web-foldkit): organization setup page mounts Clerk's CreateOrgan…
Makisuo Oct 7, 2026
9b859a0
feat(web-foldkit): select organization page, avatar initials fallback
Makisuo Oct 7, 2026
a8c4429
feat(web-foldkit): public invite join page with the onboarding brand …
Makisuo Oct 7, 2026
7aa80a5
feat(web-foldkit): channel settings mobile tab select
Makisuo Oct 7, 2026
7777404
Merge branch 'experiment-2.0' into fk/mobile-shell
Makisuo Oct 7, 2026
33b34a1
feat(web-foldkit): chat sync connections page
Makisuo Oct 7, 2026
e599e9a
feat(web-foldkit): org home member directory page
Makisuo Oct 7, 2026
16dae0c
feat(web-foldkit): your apps page
Makisuo Oct 7, 2026
4285e8f
feat(web-foldkit): port organization general settings page
Makisuo Oct 7, 2026
ab1cc6d
feat(web-foldkit): port the settings debug route redirect
Makisuo Oct 7, 2026
909c06a
feat(web-foldkit): port the connect invitations settings page
Makisuo Oct 7, 2026
4d46d8e
feat(web-foldkit): user profile page
Makisuo Oct 7, 2026
b1d1629
feat(web-foldkit): integration detail page
Makisuo Oct 7, 2026
98bed07
feat(web-foldkit): wire Mark all as read in the notifications sidebar
Makisuo Oct 7, 2026
c00dbe0
style(web-foldkit): format the channel settings overview page
Makisuo Oct 7, 2026
324325b
feat(web-foldkit): chat sync connection detail page
Makisuo Oct 7, 2026
bce583f
revert(web-foldkit): keep dialog, modal and sheet triggers unwired
Makisuo Oct 7, 2026
c36f415
feat(web-foldkit): port the pending invitations settings page
Makisuo Oct 7, 2026
0f43557
refactor(web): split panel handle styles in split-panel.styles.ts
Makisuo Oct 7, 2026
3c273b5
feat(web-foldkit): thread panel, pinned messages popover, toolbar pla…
Makisuo Oct 7, 2026
923d1f4
feat(web-foldkit): chat index channel browser page
Makisuo Oct 7, 2026
8fb646b
test(web-foldkit): integration page scenes and stories, format
Makisuo Oct 7, 2026
25abdbf
feat(web-foldkit): command palette and modal system at the root
Makisuo Oct 7, 2026
b219865
feat(web-foldkit): shell triggers for the palette and the new DM modal
Makisuo Oct 7, 2026
6bfe553
Merge fk/scr-home: org home, chat index, profile pages
Makisuo Oct 7, 2026
5d6a781
Merge fk/scr-integrations: integrations index, detail, installed, mar…
Makisuo Oct 7, 2026
dfdc6bc
feat(web-foldkit): port my-settings appearance page
Makisuo Oct 7, 2026
c49e3c2
fix(ui-parity): reject port bases on 5000 and 7000 (macOS AirPlay Rec…
Makisuo Oct 7, 2026
ae30fff
feat(web-foldkit): channel settings connect tab
Makisuo Oct 7, 2026
5bc1d65
feat(web-foldkit): port the custom emojis settings page
Makisuo Oct 7, 2026
576fe70
feat(web-foldkit): ListBox and Dropdown with gallery parity
Makisuo Oct 7, 2026
701d863
test(web-foldkit): update-loop tests for the organization settings pages
Makisuo Oct 7, 2026
5d71cc9
feat(web-foldkit): create DM and join channel modals
Makisuo Oct 7, 2026
c7bdbfd
feat(web-foldkit): port the invite, organization, section, channel an…
Makisuo Oct 7, 2026
121a56d
Merge branch 'experiment-2.0' into fk/palette-modals
Makisuo Oct 7, 2026
0a35624
Merge branch 'experiment-2.0' into fk/mobile-shell
Makisuo Oct 7, 2026
d55135f
fix(web-foldkit): measure the divider heading the rendered rows, Lege…
Makisuo Oct 7, 2026
18f149b
Merge fk/scr-org-settings: general, debug, invitations, connect invit…
Makisuo Oct 7, 2026
be29b67
refactor(web-foldkit): join card animation as its own Mount, motion k…
Makisuo Oct 7, 2026
50e9e55
feat(web-foldkit): onboarding wizard with every step, finalization an…
Makisuo Oct 7, 2026
0a3cd51
refactor(web): embed markdown parser in a framework-free module
Makisuo Oct 7, 2026
bd098d4
refactor(web-foldkit): share the embed markdown parser, renderer tabl…
Makisuo Oct 7, 2026
46e03cd
feat(web-foldkit): create-channel hint in the empty Channels section
Makisuo Oct 7, 2026
c050fa7
feat(web-foldkit): port my-settings profile page
Makisuo Oct 7, 2026
cfdae87
feat(web-foldkit): channel settings integrations tab
Makisuo Oct 7, 2026
daff27d
refactor(web-foldkit): split the chat sync connection view under 300 …
Makisuo Oct 7, 2026
77437f9
feat(web-foldkit): port the remaining modals; request schemas in a DO…
Makisuo Oct 7, 2026
c655278
feat(web-foldkit): command palette search page
Makisuo Oct 7, 2026
d1c24a2
feat(web-foldkit): toast ids and a toast on RequestedNavigation
Makisuo Oct 7, 2026
507605d
Merge fk/scr-entry: sign-in/up, onboarding, select organization, join
Makisuo Oct 7, 2026
cdabd91
feat(web-foldkit): Calendar and RangeCalendar with gallery parity
Makisuo Oct 7, 2026
bbfc7d9
Merge fk/mobile-shell
Makisuo Oct 7, 2026
2bbbdbe
Merge fk/scr-channel-sync
Makisuo Oct 7, 2026
3b79ee9
test(web-foldkit): story and scene tests for the my-settings pages
Makisuo Oct 7, 2026
c80658d
Merge fk/scr-my-settings: appearance, profile, notifications, linked …
Makisuo Oct 7, 2026
f6df679
fix(web-foldkit): chat index panels render through a top-level Tabs c…
Makisuo Oct 7, 2026
618ff4f
Merge fk/scr-home: fix empty-chat crash (Tabs renderPanel)
Makisuo Oct 7, 2026
00ff9f7
fix(web-foldkit): keep pointer release subscribed, keep a press's foc…
Makisuo Oct 7, 2026
a83f6cf
feat(web-foldkit): DatePicker with gallery parity
Makisuo Oct 7, 2026
4204a1f
Merge branch 'experiment-2.0' into fk/kit-followups
Makisuo Oct 7, 2026
1bd5d65
fix(web-foldkit): track presses on the Appearance Generate button again
Makisuo Oct 7, 2026
61dee39
feat(web-foldkit): return focus to the opener when the mobile sheet c…
Makisuo Oct 7, 2026
f2f47a1
feat(web-foldkit): sidebar channel and section menus; no partner badg…
Makisuo Oct 7, 2026
7524ff9
fix(web-foldkit): autofocus modal inputs after the portal, split the …
Makisuo Oct 7, 2026
e44d9b6
feat(web-foldkit): integrations pages open their modals
Makisuo Oct 7, 2026
e9971d7
Merge fk/mobile-shell: shared-channel badge, sidebar menus, sheet foc…
Makisuo Oct 7, 2026
b6143f3
fix(web-foldkit): round measured row heights like LegendList's update…
Makisuo Oct 7, 2026
4bd82ad
Merge experiment-2.0 (mobile shell, sidebar menus, Phase 5 pages) int…
Makisuo Oct 7, 2026
5aeece1
feat(web-foldkit): Table checkbox selection with gallery parity
Makisuo Oct 7, 2026
909b837
Merge branch 'experiment-2.0' into fk/kit-followups
Makisuo Oct 7, 2026
63dca52
feat(web-foldkit): Toast.fromIntentRequest for the root's ToastReques…
Makisuo Oct 7, 2026
d7758e2
Merge fk/chat-read: Phase 3 chat read path
Makisuo Oct 7, 2026
ea36190
Merge experiment-2.0 into fk/palette-modals
Makisuo Oct 7, 2026
01015d7
Merge fk/palette-modals: command palette, 20 modals, toast ids, hotkeys
Makisuo Oct 7, 2026
206e7a2
refactor(web-foldkit): drop the dead SignIn/SignUp container fallback
Makisuo Oct 7, 2026
c6d008d
feat(web-foldkit): share isMobile with pages
Makisuo Oct 7, 2026
4443f6d
feat(web-foldkit): RequestedCurrentUserRefresh re-runs user.me
Makisuo Oct 7, 2026
8bfcdac
refactor(web-foldkit): one db/actions runner in src/data
Makisuo Oct 7, 2026
3c9e09e
feat(web-foldkit): HazelApiClient is a resource next to HazelRpc
Makisuo Oct 7, 2026
8ad1581
feat(web-foldkit): typed search params on the routes legacy reads the…
Makisuo Oct 7, 2026
360ff86
feat(web-foldkit): editor operations for the write path, file paste
Makisuo Oct 7, 2026
2ea2f47
feat(web-foldkit): chat message actions as Commands over db/actions
Makisuo Oct 7, 2026
5bae5a6
feat(web-foldkit): composer drafts with send, edit, typing, uploads a…
Makisuo Oct 7, 2026
38791b6
feat(web-foldkit): the root owns the theme
Makisuo Oct 7, 2026
bd90d0c
feat(web-foldkit): the channel page's write path
Makisuo Oct 7, 2026
81f48e3
feat(web-foldkit): notification sounds and native notifications at th…
Makisuo Oct 7, 2026
141a0b2
feat(web-foldkit): full-page loader until user.me and the organizatio…
Makisuo Oct 7, 2026
11af2dd
feat(web-foldkit): emoji picker, a Foldkit rewrite of frimousse
Makisuo Oct 7, 2026
85cf7a8
fix(ui-parity): settle scroll, images and infinite animations before …
Makisuo Oct 7, 2026
2b71ff8
feat(ui-parity): behavioral parity, diff the backend calls of both apps
Makisuo Oct 7, 2026
08cb598
feat(ui-parity): accessibility snapshots, report ARIA tree deltas
Makisuo Oct 7, 2026
157b6f3
feat(web-foldkit): GIF picker and a shared picker popover
Makisuo Oct 7, 2026
c10b5b6
Merge fk/root-gaps: theme ownership, user refresh, typed search param…
Makisuo Oct 7, 2026
7cada85
feat(web-foldkit): capped message window with change sets; reaction p…
Makisuo Oct 7, 2026
60b8be8
Merge branch 'experiment-2.0' into fk/chat-write
Makisuo Oct 7, 2026
0b368a5
Merge fk/kit-followups: Toast, ListBox, Dropdown, Calendar, RangeCale…
Makisuo Oct 7, 2026
d0a9cec
fix(web-foldkit): chat write path on the root-gaps contract
Makisuo Oct 7, 2026
9ce0bd3
fix(web-foldkit): thread panel draft follows the open thread; menu he…
Makisuo Oct 7, 2026
ec577b7
Merge branch 'experiment-2.0' into fk/chat-write
Makisuo Oct 7, 2026
e06fe2a
fix(ui-parity): group ARIA /url lines under one role in the a11y report
Makisuo Oct 7, 2026
d17f4f4
Merge fk/chat-write
Makisuo Oct 7, 2026
14b2bbd
Merge fk/harness-hardening
Makisuo Oct 7, 2026
e0abc29
feat(web-foldkit): the root renders toasts with the kit's sonner port
Makisuo Oct 7, 2026
639aa8d
Merge fk/root-gaps: host the sonner Toast at the root
Makisuo Oct 7, 2026
db92604
fix(web-foldkit): run the chat sync modals' Discord guild and channel…
Makisuo Oct 7, 2026
4ca438b
Merge experiment-2.0 into fk/behavior-pages
Makisuo Oct 7, 2026
dc00223
feat(web-foldkit): port presence (initial status, AFK, cross-tab acti…
Makisuo Oct 7, 2026
99c99af
test(web-foldkit): story tests for the settings writes the error scen…
Makisuo Oct 7, 2026
67fd50d
feat(web-foldkit): create the Rivet actor client at boot as a managed…
Makisuo Oct 7, 2026
8ab4281
feat(web-foldkit): clear a channel's notifications when it is opened
Makisuo Oct 7, 2026
8fb6a2f
test(web-foldkit): cover clearing notifications on channel entry
Makisuo Oct 7, 2026
f254c52
fix(web-foldkit): query user.me on the join page when signed out
Makisuo Oct 7, 2026
d41179a
Merge experiment-2.0 into fk/platform-presence
Makisuo Oct 7, 2026
0654fed
Merge fk/behavior-pages: chat-sync Discord queries, write story tests
Makisuo Oct 7, 2026
129c479
Merge fk/platform-presence: presence, Rivet client, clearNotification…
Makisuo Oct 7, 2026
3982566
chore(ui-parity): re-pin the legacy baseline to 639aa8d26 (kit follow…
Makisuo Oct 7, 2026
a4311d8
fix(web-foldkit): announce in React Aria's live regions where legacy …
Makisuo Oct 7, 2026
81862dc
fix(web-foldkit): indeterminate checkboxes report checked=mixed
Makisuo Oct 7, 2026
7114292
fix(web-foldkit): name an unlabelled slider thumb and combo box listb…
Makisuo Oct 7, 2026
30bffec
fix(web-foldkit): the gallery frame renders the empty toaster region …
Makisuo Oct 7, 2026
1640ef4
Merge branch 'experiment-2.0' into fk/a11y-parity
Makisuo Oct 7, 2026
fda5ef4
refactor(web-foldkit): move the pending-button announcer out of butto…
Makisuo Oct 7, 2026
593be4d
Merge fk/a11y-parity: live regions, checked=mixed, slider and listbox…
Makisuo Oct 7, 2026
66d3d15
fix(web-foldkit): render chat rows in LegendList's containers so DOM …
Makisuo Oct 7, 2026
306ee80
fix(web-foldkit): keep the hovered message while the image viewer is …
Makisuo Oct 7, 2026
1737a5b
fix(web-foldkit): end a button's hover and focus when it disables, as…
Makisuo Oct 7, 2026
3104bf5
fix(web-foldkit): match legacy's focus-visible ring on menus and the …
Makisuo Oct 7, 2026
d26465d
test(web-foldkit): resolve the menu triggers' press-focus Mounts in t…
Makisuo Oct 7, 2026
a9a7414
Merge fk/final-polish: post-click hover, focus outlines, LegendList r…
Makisuo Oct 7, 2026
4b3d8b2
docs(foldkit): end-of-day status, open items before the cutover gate
Makisuo Oct 7, 2026
989048b
test(ui-parity): canned HTTP API responses per dataset
Makisuo Oct 8, 2026
109447e
feat(web-foldkit): port the chat sync add-connection and link-channel…
Makisuo Oct 8, 2026
71f8bd3
feat(web-foldkit): set-status emoji picker and expiry date picker
Makisuo Oct 8, 2026
52e122d
Merge fk/modal-gaps: chat-sync add-connection and link-channel modals…
Makisuo Oct 8, 2026
9b8eb1a
fix(web-foldkit): route date segment keystrokes to the active segment…
Makisuo Oct 8, 2026
8372d9d
fix(web-foldkit): calendar announcements, minimum date label and rang…
Makisuo Oct 8, 2026
faa787a
fix(web-foldkit): announce a table sort only when its description cha…
Makisuo Oct 8, 2026
1670992
Merge experiment-2.0 into fk/kit-a11y-final
Makisuo Oct 8, 2026
41c7e24
feat(ui-parity): serve link unfurls, GIFs, YouTube and the Rivet mess…
Makisuo Oct 8, 2026
5bdeb54
test(ui-parity): chat-embeds scenarios for unfurls, tweets, YouTube, …
Makisuo Oct 8, 2026
93cae9b
feat(web-foldkit): image viewer carousel on vanilla embla
Makisuo Oct 8, 2026
eacaddc
feat(web-foldkit): URL embeds and streamed AI replies in chat messages
Makisuo Oct 8, 2026
ae50b70
feat(web-foldkit): show the current user's status emoji in the user menu
Makisuo Oct 8, 2026
a539644
test(ui-parity): emoji status datasets and user menu status scenarios
Makisuo Oct 8, 2026
fc71741
Merge fk/shell-status: current-user status emoji in the shell
Makisuo Oct 8, 2026
f057965
docs(ui-parity): network and Rivet fixtures in the known gaps
Makisuo Oct 8, 2026
5a597bd
Merge fk/chat-embeds: link previews, tweets, YouTube, GIFs, embla car…
Makisuo Oct 8, 2026
1b35c02
Merge fk/kit-a11y-final: calendar labels and announcements, date fiel…
Makisuo Oct 8, 2026
6d3d55b
docs(foldkit): certification runs burndown-3 and burndown-4, remainin…
Makisuo Oct 8, 2026
7053a72
fix(web-foldkit): unlabelled date picker segment names and hidden sel…
Makisuo Oct 8, 2026
1933b28
fix(web-foldkit): disabled buttons never hover and pending buttons an…
Makisuo Oct 8, 2026
cbbb3f6
fix(web-foldkit): chat sync modals hover, autofocus and focus restore…
Makisuo Oct 8, 2026
a34d515
fix(web-foldkit): keep the hovered message while the image viewer is …
Makisuo Oct 8, 2026
59d945e
fix(web-foldkit): combo box input keeps keystrokes a deferred render …
Makisuo Oct 8, 2026
7e11227
chore(web-foldkit): upgrade foldkit to 0.167.0
Makisuo Oct 8, 2026
8ca517e
fix(web-foldkit): select trigger and options take focus like usePress
Makisuo Oct 8, 2026
c25de40
fix(web-foldkit): deterministic pending announcements and focus retur…
Makisuo Oct 8, 2026
f8a0391
Merge fk/cert-fixes: burndown-4 leftovers (date segments, pending but…
Makisuo Oct 8, 2026
b3ad992
Merge branch 'experiment-2.0' into fk/foldkit-167
Makisuo Oct 8, 2026
a941abc
test(web-foldkit): resolve the combo box typed-value Mount in the pro…
Makisuo Oct 8, 2026
c9495c9
docs(foldkit): burndown-5 certification, only accepted legacy quirks …
Makisuo Oct 8, 2026
b337904
docs(foldkit): S4b, evaluate @foldkit/ui 0.167 VirtualList for the ch…
Makisuo Oct 8, 2026
5454c2d
Merge fk/foldkit-167: Foldkit 0.167 upgrade, VirtualList evaluation (…
Makisuo Oct 8, 2026
d9acd3b
feat(ui-parity): perf suite comparing legacy and foldkit
Makisuo Oct 8, 2026
01903bf
fix(web-foldkit): keep the portaled message toolbar in a stable slot
Makisuo Oct 8, 2026
47e754c
perf(web-foldkit): drop the shell root's inset-only :has() variants
Makisuo Oct 8, 2026
edc2657
fix(web-foldkit): remount the channel page per channel
Makisuo Oct 8, 2026
41b5d97
chore(ui-parity): canned typingIndicator.delete, perf timeout screenshot
Makisuo Oct 8, 2026
58d8fdd
fix(ui-parity): perf probes for the delete modal and image viewer
Makisuo Oct 8, 2026
fedcc0f
Merge fk/perf: perf suite, hover toolbar crash, blank warm switch, pa…
Makisuo Oct 8, 2026
7d7b2e6
docs(foldkit): performance baseline and budgets
Makisuo Oct 8, 2026
fb03e23
test(web-foldkit): page test fixtures and the general settings scene
Makisuo Oct 8, 2026
114625c
test(web-foldkit): general settings Story test
Makisuo Oct 8, 2026
6525640
test(foldkit): root routing and OutMessage stories, root fixtures
Makisuo Oct 8, 2026
9b474f5
test(foldkit): root scenes for the nav rail, mobile sheet and command…
Makisuo Oct 8, 2026
1511b38
test(web-foldkit): story tests for the composer, drafts and the chann…
Makisuo Oct 8, 2026
934a94b
test(foldkit): command palette stories (pages, back stack, actions)
Makisuo Oct 8, 2026
0370a3b
test(foldkit): shell menu and sidebar sheet stories
Makisuo Oct 8, 2026
ed57a1b
test(foldkit): root modal slot scenes (open, success toast, failure, …
Makisuo Oct 8, 2026
5148459
test(foldkit): session state scenes and sign-out, mobile sidebar, sou…
Makisuo Oct 8, 2026
42ceaf2
docs(foldkit): root area review against Foldkit best practices
Makisuo Oct 8, 2026
8943127
test(web-foldkit): scene tests for the channel page and the chat index
Makisuo Oct 8, 2026
ed6582b
Merge fk/review-root: root review doc, routing/out-message/shell/pale…
Makisuo Oct 8, 2026
cc12e2a
test(web-foldkit): channel subscription gates
Makisuo Oct 8, 2026
15fe0d2
docs(foldkit): chat area review against Foldkit best practices
Makisuo Oct 8, 2026
760001a
Merge fk/review-chat: chat review doc, composer/channel/chat-index St…
Makisuo Oct 8, 2026
f0e9c33
test(web-foldkit): type-stable storyUpdate helper
Makisuo Oct 8, 2026
7e3f122
test(web-foldkit): Story and Scene tests for org settings pages
Makisuo Oct 8, 2026
6696722
test(web-foldkit): Story and Scene tests for chat sync and integrations
Makisuo Oct 8, 2026
5fac3d4
test(web-foldkit): Story and Scene tests for my-settings pages
Makisuo Oct 8, 2026
7c6c132
test(web-foldkit): Story and Scene tests for channel settings pages
Makisuo Oct 8, 2026
5d7df05
test(web-foldkit): Story and Scene tests for onboarding, home, inbox …
Makisuo Oct 8, 2026
1db2a02
docs(foldkit-review): pages review
Makisuo Oct 8, 2026
1f8c68f
Merge fk/review-pages: pages review doc, Story and Scene tests for ev…
Makisuo Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 15 additions & 0 deletions apps/web-foldkit/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/icon.svg" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Slack alternative for modern teams." />
<title>Hazel Chat</title>
</head>
<body class="bg-bg text-fg">
<div id="app"></div>
<script type="module" src="/src/entry.ts"></script>
</body>
</html>
44 changes: 44 additions & 0 deletions apps/web-foldkit/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "web-foldkit",
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"typecheck": "tsc --noEmit",
"test": "vitest run"
},
"dependencies": {
"@effect/platform-browser": "catalog:effect",
"@electric-sql/client": "1.5.28",
"@foldkit/ui": "0.167.0",
"@fontsource/inter": "^5.2.8",
"@hazel/domain": "workspace:*",
"@hazel/schema": "workspace:*",
"@tanstack/db": "0.11.3",
"effect": "catalog:effect",
"embla-carousel": "8.6.0",
"foldkit": "0.167.0",
"marked": "^17.0.4",
"prosemirror-commands": "^1.7.2",
"prosemirror-history": "^1.5.1",
"prosemirror-keymap": "^1.2.3",
"prosemirror-model": "^1.25.12",
"prosemirror-state": "^1.4.4",
"prosemirror-transform": "^1.12.2",
"prosemirror-view": "^1.42.6",
"remend": "^1.2.2",
"tailwind-merge": "^3.5.0",
"tailwind-variants": "^3.2.2"
},
"devDependencies": {
"@foldkit/devtools": "0.167.0",
"@foldkit/vite-plugin": "0.27.0",
"@tailwindcss/vite": "^4.2.1",
"tailwindcss": "^4.2.1",
"tailwindcss-react-aria-components": "^2.0.1",
"tw-animate-css": "^1.4.0",
"typescript": "^5.9.3",
"vite": "8.0.0",
"vitest": "^4.0.0"
}
}
67 changes: 67 additions & 0 deletions apps/web-foldkit/scripts/bench-s2-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { resolve } from "node:path"
import { heapStats } from "bun:jsc"
import { plugin } from "bun"

/**
* S2 benchmark: (a) the TanStack DB bridge (`page/chat/data.ts` streams over the legacy query
* builders) vs (b) a normalized store in the Model (`data/normalized-store.ts`), on the heavy
* dataset's 10k-message channel. Measures update latency for a new message and a reaction toggle,
* the initial build, heap, and the dev-mode deep-freeze cost. Run from apps/web-foldkit:
*
* bun run scripts/bench-s2-data.ts [--limits 30,300,3000,10000] [--samples 15]
*/

// `~/db/collections` would open Electric shapes; the benchmark swaps in local collections.
const BENCH_COLLECTIONS = resolve(import.meta.dir, "bench-s2/collections.ts")
plugin({
name: "bench-local-collections",
setup(build) {
build.onLoad({ filter: /apps\/web\/src\/db\/collections\.ts$/ }, () => ({
contents: `export * from ${JSON.stringify(BENCH_COLLECTIONS)}`,
loader: "ts",
}))
},
})

const args = new Map(
Bun.argv
.slice(2)
.flatMap((arg, index, all) => (arg.startsWith("--") ? [[arg.slice(2), all[index + 1] ?? ""]] : [])),
)
const limits = (args.get("limits") ?? "30,300,3000,10000").split(",").map(Number)
const samples = Number(args.get("samples") ?? "15")

const only = args.get("only")
const heapMb = () => {
Bun.gc(true)
return heapStats().heapSize / 1e6
}

// `--heap a|b`: heap held by one open channel, in a fresh process per option.
const heapOption = args.get("heap")
if (heapOption) {
await import("../../../packages/ui-parity/src/fixtures/datasets/heavy.ts")
const baseline = heapMb()
const { setupForHeap } = await import(
heapOption === "a" ? "./bench-s2/option-a.ts" : "./bench-s2/option-b.ts"
)
const retained = await setupForHeap(30)
console.log(JSON.stringify({ option: heapOption, heapMb: Math.round((heapMb() - baseline) * 10) / 10 }))
void retained
process.exit(0)
}

const results: Array<Record<string, unknown>> = []
if (only !== "b") {
const { runA } = await import("./bench-s2/option-a.ts")
for (const limit of limits)
results.push({ option: "a: TanStack DB bridge", limit, ...(await runA(limit, samples)) })
}
if (only !== "a") {
const { runB } = await import("./bench-s2/option-b.ts")
for (const limit of limits)
results.push({ option: "b: normalized store", limit, ...(await runB(limit, samples)) })
}
console.table(results)
console.log(JSON.stringify(results))
process.exit(0)
29 changes: 29 additions & 0 deletions apps/web-foldkit/scripts/bench-s2/collections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { BTreeIndex, createCollection, localOnlyCollectionOptions } from "@tanstack/db"
import { heavyDataset } from "../../../../packages/ui-parity/src/fixtures/datasets/heavy.ts"

/**
* Stand-in for `~/db/collections` in the S2 benchmark: the same collection names, seeded with the
* heavy dataset through the sync path (as Electric would), with no network.
*/

type Row = Record<string, unknown> & { readonly id: string }

const local = (id: string, rows: ReadonlyArray<Record<string, unknown>> | undefined) =>
createCollection(
localOnlyCollectionOptions<Row, string>({
id,
// Same indexing as `libs/effect-electric-db-collection` (collection.ts).
autoIndex: "eager",
defaultIndexType: BTreeIndex,
getKey: (row) => row.id,
initialData: (rows ?? []).map((row) => ({ ...row, id: String(row.id) })),
}),
)

const tables = heavyDataset.tables

export const messageCollection = local("messages", tables.messages)
export const pinnedMessageCollection = local("pinned_messages", tables.pinned_messages)
export const userCollection = local("users", tables.users)
export const messageReactionCollection = local("message_reactions", tables.message_reactions)
export const channelCollection = local("channels", tables.channels)
127 changes: 127 additions & 0 deletions apps/web-foldkit/scripts/bench-s2/option-a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { messageCollection, messageReactionCollection } from "~/db/collections"
import * as Data from "../../src/page/chat/data.ts"
import * as Page from "../../src/page/chat/page.ts"
import {
channelId,
currentUserId,
deepFreeze,
freshId,
median,
newMessageRow,
round,
subscribe,
time,
} from "./shared.ts"

/**
* Option (a): the live TanStack DB queries emit the full result on every change; the page re-derives
* its rows. `dataMs` covers the collection write through the emitted, validated Message.
*/

export const runA = async (limit: number, samples: number) => {
let constructMs = 0
const messages = subscribe(
Data.messagesStream(channelId, limit, (rows) => {
const [message, ms] = time(() => Page.Message.UpdatedMessages({ messages: rows }))
constructMs = ms
return message
}),
)
const reactions = subscribe(
Data.reactionsStream(channelId, (rows) => Page.Message.UpdatedReactions({ reactions: rows })),
)

const started = performance.now()
const firstMessages = await messages.next()
const initialDataMs = performance.now() - started
const initialConstructMs = constructMs
const firstReactions = await reactions.next()
let [page, initialUpdateMs] = time(() => {
const withMessages = Page.update(Page.init(channelId, currentUserId), firstMessages).model
return Page.update(withMessages, firstReactions).model
})
const [, initialFreezeMs] = time(() => deepFreeze(page))

const message = {
data: [] as number[],
construct: [] as number[],
update: [] as number[],
freeze: [] as number[],
}
for (let index = 0; index < samples; index++) {
const begin = performance.now()
messageCollection.insert(newMessageRow(index))
const emitted = await messages.next()
message.data.push(performance.now() - begin)
message.construct.push(constructMs)
const [next, updateMs] = time(() => Page.update(page, emitted).model)
message.update.push(updateMs)
message.freeze.push(time(() => deepFreeze(next))[1])
page = next
}

const reaction = { data: [] as number[], update: [] as number[], freeze: [] as number[] }
const target = page.messages[0]!
for (let index = 0; index < samples; index++) {
const id = freshId()
for (const write of [
() =>
messageReactionCollection.insert({
id,
messageId: target.id,
channelId,
conversationId: null,
userId: currentUserId,
emoji: "🚀",
createdAt: new Date(),
}),
() => messageReactionCollection.delete(id),
]) {
const begin = performance.now()
write()
const emitted = await reactions.next()
reaction.data.push(performance.now() - begin)
const [next, updateMs] = time(() => Page.update(page, emitted).model)
reaction.update.push(updateMs)
reaction.freeze.push(time(() => deepFreeze(next))[1])
page = next
}
}
await messages.stop()
await reactions.stop()

return {
initialMs: round(initialDataMs + initialUpdateMs),
"initial data/construct/update/freeze": [
initialDataMs,
initialConstructMs,
initialUpdateMs,
initialFreezeMs,
]
.map(round)
.join(" / "),
newMessageMs: round(median(message.data) + median(message.update)),
"msg data/construct/update/freeze": [message.data, message.construct, message.update, message.freeze]
.map(median)
.join(" / "),
reactionToggleMs: round(median(reaction.data) + median(reaction.update)),
"reaction data/update/freeze": [reaction.data, reaction.update, reaction.freeze]
.map(median)
.join(" / "),
}
}

/** Everything option (a) keeps alive for one open channel: seeded collections, live queries, the page. */
export const setupForHeap = async (limit: number) => {
const messages = subscribe(
Data.messagesStream(channelId, limit, (rows) => Page.Message.UpdatedMessages({ messages: rows })),
)
const reactions = subscribe(
Data.reactionsStream(channelId, (rows) => Page.Message.UpdatedReactions({ reactions: rows })),
)
const page = Page.update(
Page.update(Page.init(channelId, currentUserId), await messages.next()).model,
await reactions.next(),
).model
return { messages, reactions, page, collections: [messageCollection, messageReactionCollection] }
}
Loading
Loading