Skip to content

Release 1.7.0 - #2309

Open
catch-21 wants to merge 47 commits into
masterfrom
release-1.7.0
Open

Release 1.7.0#2309
catch-21 wants to merge 47 commits into
masterfrom
release-1.7.0

Conversation

@catch-21

@catch-21 catch-21 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

catch-21 and others added 30 commits July 17, 2026 21:36
* feat: List Layout Filter

* feat: List Layout integration WIP

* refactor(PostMain): update layout and styling for PostListMediaThumbnail and PostMainListRow components

- Adjusted the class names for better spacing and alignment in PostMainListRow.
- Updated the PostListMediaThumbnail to include overflow handling and modified image size.
- Enhanced skeleton loading state in PostMainListRowSkeleton for consistency with new styles.
- Introduced LIST_POST_MEDIA_THUMBNAIL_CLASS for better maintainability of media thumbnail styles.
- Updated tests to reflect changes in layout and styling.

* refactor(Timeline): replace PostCardSkeleton with TimelinePostSkeleton in loading components

- Updated TimelineLoading and TimelineLoadingMore components to use TimelinePostSkeleton for improved consistency in loading states.
- Adjusted layout and class names in PostMainListRowSkeleton for better spacing and alignment.

* fix(QuickReply): update textarea class for improved styling

- Changed the class of the quick reply textarea from 'text-base leading-5' to 'text-base font-medium leading-5' to enhance text appearance and maintain consistency with design standards.

* fix(PostListMediaThumbnail): prevent state updates on unmounted component

- Added a cancellation flag to avoid setting state after the component has unmounted, preventing potential memory leaks and errors.
- Updated the logic in the useEffect hook to check the cancellation flag before updating the preview source state.

* fix(CustomFeedDialog): update icon for feed layout selection

- Replaced the icon for the wide layout option from Menu to Rows2 in the CustomFeedDialog component for improved visual representation.�

* feat(PostAttachmentsImagesAndVideos): add renderTrigger prop for customizable media preview

- Introduced a new optional `renderTrigger` prop to the PostAttachmentsImagesAndVideos component, allowing for custom rendering of the media preview trigger.
- Updated the PostListMediaThumbnail component to utilize the new `renderTrigger` prop, enhancing the flexibility of media item previews.
- Refactored media item handling to support both local and remote media sources, improving the overall media management experience.

* feat(QuickReply): add layout-specific content subcomponents for list layout

  - Split QuickReply into QuickReplyDefaultContent and QuickReplyListContent
    with a shared QuickReplyComposerRow (avatar + textarea + mentions)
  - Add QuickReplyListActions: inline char count, emoji, image and Reply
    actions on the top right of the composer row in list layout
  - Add hideActionBar and inline props to PostInputExpandableSection so the
    list layout renders tags input below the content on a single wrapping row
  - Move expanded PostTagsPanel below the content row in PostMainListRow

* fix(FilterLayout): update icon for layout selection and adjust SVG structure

- Replaced the icon for the wide layout option from Menu to Rows2 in the FilterLayout component for better visual representation.
- Updated snapshot tests to reflect changes in the SVG structure and class names for consistency across different layout states.

* feat(feed): add list layout support for custom feeds

  Wire up the new PubkyAppFeedLayout.List layout (added in pubky-app-specs
  0.5.3) through feed creation, switching, and rendering.

  - Bump pubky-app-specs 0.4.4 -> 0.5.3
  - Map List layout in layoutToString so commitCreate/commitUpdate persist
    it to the homeserver (HashId-derived feed ID now resolves correctly)
  - Map List <-> LIST in pubky-app-spec-feed-mappers so switching to a list
    feed actually applies the layout instead of falling back to home layout
  - Add List option (Rows4 icon) to CustomFeedDialog layout picker
  - Use text-secondary-foreground for list row snippet and article body text
  - Add PostMainListRow tests; update PostArticle snapshot�

* fix(feed.helpers): add TODO comment for future support of Collections and Unknown StreamKind

* chore: update snapshots

* chore: update snapshots

* chore: update snapshots

* feat(PostMain): add showFullContentInListLayout prop and update PostMainListRow behavior

- Introduced `showFullContentInListLayout` prop to `PostMain` for controlling content display in list layout.
- Updated `PostMainListRow` to conditionally render full post content based on the new prop.
- Enhanced tests to verify the correct behavior of content display for both regular and reply posts.
- Adjusted related components and tests to accommodate the new functionality.

* feat(PostAttachments): implement compact size for media items

- Added a `size` prop to `PostAttachmentsImagesAndVideos` to support 'compact' and 'default' layouts.
- Updated rendering logic to apply different height classes based on the size prop.
- Enhanced tests to verify the correct application of compact media item styles.
- Adjusted `PostAttachments` and related components to pass the new size prop accordingly.

* fix(PostAttachmentsImagesAndVideos): correct item class name assignment for media items

- Updated the class name assignment logic for media items in the `PostAttachmentsImagesAndVideos` component to ensure the correct height classes are applied based on the `size` prop.
- Removed redundant variable and directly used the conditional logic in the class name assignment for clarity.

* feat(PostAttachmentsImagesAndVideos): implement list variant for media display

- Introduced a `variant` prop to `PostAttachmentsImagesAndVideos` to support list layout, allowing for a constrained grid display of media items.
- Updated rendering logic to handle the new variant, including adjustments to media item heights and the display of remaining media count.
- Enhanced tests to verify the correct application of the list variant and its behavior in rendering media items.
- Adjusted related components to pass the new variant prop accordingly.�

* feat(PostListMediaThumbnail): add video support & add tests

* refactor(TimelinePostSkeleton): fix small jump in skeleton in list

* refactor(PostAttachments): streamline media handling and enhance tests

- Introduced `usePostAttachmentsMedia` hook to centralize media attachment resolution, improving code organization and reusability.
- Updated `PostAttachments` and `PostListMediaThumbnail` components to utilize the new hook for fetching and categorizing media items.
- Refactored media item rendering logic to ensure consistent handling of local and remote attachments.
- Added tests for new helper functions to validate attachment categorization and metadata splitting.
- Adjusted related components and tests to align with the new media handling approach.

* refactor(PostMainLayoutRules): remove unused code

* feat(PostMainListRow): make collection compatible - update profile url generation - add userInfoPopOver

* refactor(PostAttachments): consolidate attachment categorization and enhance tests

- Merged CategorizedAttachments type definition into PostAttachments.types.ts.
- Updated PostAttachments.helpers.ts to utilize the new CategorizedAttachments type.
- Added tests for QuickReplyComposerRow and usePostAttachmentsMedia hooks to ensure functionality and coverage.
- Removed unused types from usePostAttachmentsMedia.types.ts.

* refactor(PostListMediaThumbnail): simplify props and update styling

- Removed unused className and onClick props from PostListMediaThumbnail component.
- Updated the className for the media thumbnail to ensure consistent styling.
- Adjusted usage in PostMainListRow to reflect the changes in props.

* feat(PostMainListRow): implement PostMainListRow component with skeleton and tests

- Added PostMainListRow component to display post details with user information and actions.
- Created PostMainListRowSkeleton for loading state representation.
- Implemented comprehensive tests for PostMainListRow to ensure functionality and coverage.
- Utilized various hooks for user and post details, enhancing the component's interactivity.

* fix: update import paths for PostMainListRow and related components

- Refactored import statements in TimelinePostSkeleton, PostMain, and PostMainListRow components to reflect new directory structure.
- Adjusted mock paths in tests to ensure proper component referencing.
- Improved code organization by aligning component imports with their respective directories.

* fix: article in feeds texts colors

* chore: update snapshots & tests

* refactor: moderation blurred option for moderated content in list layout

* chore: update snapshots��

* chore: update tests

---------

Co-authored-by: V <jovanovicv90@gmail.com>
Co-authored-by: Aldert <81586998+aldertnl@users.noreply.github.com>
* fix(core): harden OG metadata SSRF protection

Validate all resolved IPv4 and IPv6 addresses and enforce the same policy at socket connection time and across redirects.

Refs: #2209

* fix(core): refine OG metadata SSRF safeguards

Allow globally reachable exceptions within broad special-purpose ranges while keeping NAT64 blocked by policy.

Route guarded requests through safeFetch, preserve nested connection errors, and add a real socket-level lookup regression test.

Refs: #2209

* fix(og-metadata): keep expected failures out of Sentry

Restore warning-only fallbacks for timeout, network, and connection-time DNS failures while preserving reportable SSRF and unexpected errors.
* tests: collections e2e init

* tests: update collection e2e with latest changes

* tests: refine collections e2e

* tests: refine collections e2e more and fix snapshots

* tests: remove waitForCollectionInSection from collections e2e

* tests: add collections spec to ci

* tests: remove obsolete snapshots
* feat: make previews great again

* fix: make redirect more robust

* fix: pass url into metadata constructor

---------

Co-authored-by: V <jovanovicv90@gmail.com>
* fix(users): block unsafe profile link schemes

Centralize the safe external URL allowlist and enforce it when profile links are saved, rendered, and opened. Add regression coverage for obfuscated executable schemes and legacy stored links.\n\nRefs: #2210

* test(ui): use real dialogs in link security tests

* fix(users): address profile link review feedback

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: add homeserver check to ingest user

* ref: code review

* feat(users): ingest at profile creation and unindexed sign-in

Replace the sign-in-time ingestion with two hooks:

- ProfileApplication.commitCreate: fire PUT /v0/ingest right after
  profile.json is saved (earliest guaranteed-once moment for new users)
- BootstrapApplication.initialize: fire it when bootstrap returns
  indexed:false (covers self-hosted users who already have a profile
  and retries transient failures on every sign-in)

Drop the client-side homeserver resolution and default-HS comparison:
the ingest endpoint is idempotent, nexus already no-ops for known
users and handles primary-HS users safely, so the pkarr lookup on the
sign-in critical path bought nothing. Both calls are fire-and-forget,
nexus downtime never blocks onboarding or sign-in.

* refactor(users): centralize ingest fire-and-forget policy in service

Review feedback (#2077): the never-block policy is a property of the
ingest endpoint, not of each caller. NexusBootstrapService.ingest now
never rejects and documents the rationale once; both application call
sites drop their duplicated catch and comment. The non-throwing
contract is proven at the service level instead of per caller.

---------

Co-authored-by: SHAcollision <cotyleron@proton.me>
Co-authored-by: secondl1ght <85003930+secondl1ght@users.noreply.github.com>
* fix: skip stream cursor pagination and refactor

* docs: update

* refactor: keep collectionContent controller-free for application-layer
use

* fix: harden end of nexus stream scenario
… with weeks (#2240)

* feat: add years support to useRelativeTime, fix tests and weird cases with weeks

* refactor(NotificationItem): replace formatNotificationTime with RelativeTimestamp component and enhance tooltip functionality

- Removed the formatNotificationTime utility and integrated the RelativeTimestamp component for displaying notification timestamps.
- Updated tests to reflect changes in tooltip behavior, ensuring it shows exact dates on hover and does not display on mobile.
- Adjusted snapshots to capture new rendering behavior for mobile and desktop views.

* refactor(notifications profile): streamline timestamp display and enhance tooltip functionality

- Replaced the existing timestamp display logic in PostHeaderTimestamp with the new RelativeTimestamp component for improved code clarity and functionality.
- Updated tooltip behavior to show exact timestamps on hover for desktop users while ensuring it does not display on mobile.
- Added comprehensive tests for the RelativeTimestamp component, including tooltip visibility based on device type.
- Adjusted existing tests in NotificationItem to reflect the new timestamp handling and updated snapshots accordingly.

* fix: four week months shorten years

* feat: enhance timestamp components with mobile responsiveness

- Added `isMobile` prop to `RelativeTimestamp` and `PostHeaderTimestamp` components to handle mobile-specific rendering.
- Updated tests for `RelativeTimestamp` and `NotificationItem` to accommodate the new `isMobile` prop.
- Refactored `NotificationsList` to share viewport state across notification items, improving performance and consistency.�

* refactor: update typography tracking for timestamp and notification components

- Changed tracking property from a fixed value to 'tracking-widest' for improved text spacing in PostHeaderTimestamp and NotificationItem components.
- Updated corresponding snapshot tests to reflect the new styling changes.

* chore: update snapshots & tests

---------

Co-authored-by: V <jovanovicv90@gmail.com>
* feat(collections): add configurable grid and list layouts

Add creator-selected Grid/List defaults and temporary viewer overrides
for collection pages. Persist layout data through create, edit, and
membership updates, with a Grid fallback for older collections.

Render collection items through layout-aware timeline views, keep loading
skeletons stable, preserve collection-specific empty states and add-content
controls, and propagate List context when opening individual posts.

Keep post dialogs independent from feed layout and hide inline reply
threads for saved collection posts while retaining full discussions on
dedicated post pages.

Update the Pubky specs integration, translations, unit and snapshot tests,
and Cypress coverage for the complete collection layout flow.

Refs: #2208

* fix(posts): keep collection layout overrides temporary

Resolve post layout through one route-aware hook so the shell, content, and sidebar stay in sync. Update temporary layout changes with replace while preserving the global home preference and Back navigation.

* fix(posts): use home layout on single post pages

Remove route-scoped layout query overrides so post navigation and layout controls share the persisted Home preference. Collection Grid/List behavior remains local to collections.

* Fix merge conflict remnant.

* Fix review comments.
* tests: add collections notification e2e

* tests: add multiple notification e2e
* feat(ui): update auth brand illustrations to Pubky v2 (#1902)

Replace signup/backup/join brand plates with Handoff v25 assets, add the enter-code padlock graphic, and migrate join modal SVGs to WebP.

* fix(ui): align enter-phone step with Figma Handoff v25

Use the phone-number brand plate on the SMS entry step and update title/subtitle copy to match Create account - SMS.

* fix(ui): align onboarding brand-image spacing with Figma

* fix(ui): align sign-in and signed-out screens with Figma

* fix(ui): align SMS code, scan QR, and signed-out header with Figma

Add the missing SMS hint line, restore the scan illustration card layout,
swap logout header socials for Learn/Explore, and refresh stale snapshots
that were failing CI.

* fix(ui): re-export backup note and folder plates from Figma

Replace opaque, poorly cropped note/folder WebPs with the transparent
Illustrations Pubky v2 assets from the backup-method dialog component.

* fix(ui): align auth screens with Figma layouts

Centralize illustrated and QR card layout overrides, update onboarding copy and spacing, and refresh focused tests and snapshots.

Refs: #1902
- Updated the Image component mock to accept an optional className prop for better styling flexibility.
- Added a new test case to verify the rendering of the cover image with a 16:9 aspect ratio and appropriate classes.
- Adjusted the PostArticleDetail component to apply new styling classes to the cover image for improved visual presentation.
- Updated snapshots to reflect the changes in the cover image rendering.

Co-authored-by: secondl1ght <85003930+secondl1ght@users.noreply.github.com>
* fix(onboarding): accept Argentina mobiles missing trunk 9

Normalize +54 numbers that omit the international mobile trunk digit so Send Code enables, send E.164 to Homegate, and show inline validation feedback when still invalid.

* fix(onboarding): show phone errors only after send attempt

Keep Send Code enabled for invalid numbers, surface validation feedback on submit, and associate the error with aria-describedby.
* feat(vrt): add VRT harness with Home feed baseline

Vitest browser-mode setup with deterministic fixtures and mocks.
Home covers desktop + mobile.

* fix(vrt): repoint TooltipProvider import to concrete module

The @/atoms barrel was removed on dev (#1760); update vrt.tsx to import from @/atoms/Tooltip/Tooltip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(vrt): address Greptile feedback and regenerate baselines

- Hoist QueryClient instantiation to renderForVRT so it's not re-created on every React render of VRTProviders.
- Remove inert 'use client' directive (no effect in Vitest browser mode).
- Regenerate Home feed baselines to match post-merge rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(test): scope default test runs to the unit project

CI runs `vitest run` without a project filter, which loaded both `unit` and `vrt` projects and tried to launch Chromium via Playwright on Linux runners that don't have the browsers installed. Pin the CI command and the default `npm test` scripts to `--project unit`; VRT remains opt-in via `npm run test:vrt`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(vrt): align Home test with shared feeds layout

* chore: sort imports per lint rules

* fix(vrt): pin import order to avoid Vitest hoisting TDZ (Temporal Dead Zone — "Cannot access __vi_import_3__ before initialization")

* fix(deps): sync package-lock.json with package.json

* fix: always hide scrollbar in VRT so it doesn't sometimes hide depending on OS system settings

* chore: add linux VRT snapshots

* test(vrt): add Firefox + Safari instances (#1935)

* test(vrt): add Firefox + WebKit instances

Run VRT in three browsers instead of just Chromium to catch
engine-specific rendering differences. WebKit covers Safari's
rendering engine.

* test: add linux VRT snapshots for firefox and webkit

---------

Co-authored-by: James Browning <jamesbrowning91@gmail.com>

* test(vrt): move Home VRT to src/test/vrt/feed and refresh mobile baselines

Home's VRT renders a full page (Header + ContentLayout + Home), not just the
Home template, so move it out of the component folder into a dedicated
src/test/vrt/feed/ tree (with its __screenshots__) and switch the relative
Home import to the @/templates alias.

Regenerate the mobile darwin baselines, which had drifted from the current
render on the same machine; desktop and linux baselines are unchanged.

* test(vrt): render real artwork deterministically in VRT screenshots

Mock next/image to a plain <img> in the VRT setup: the vitest browser runtime
has no Next image optimizer server, so the `/_next/image?url=...` endpoint 404s
and every image renders as a broken-image box (cross-OS-flaky glyph + wrong
layout). The mock forwards only DOM-valid props, resolves static-import `{src}`
objects, and reproduces `fill` layout, so screenshots show the real assets.
Mocking next/image to a plain <img> is the pattern Vercel recommends for tests
(vercel/next.js discussion #32325).

Also await img.decode() for every image in the rendered tree before capturing,
so a screenshot never fires before an image paints (a failed/pending decode is
ignored so a broken src can't hang the test).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(vrt): add onboarding VRT suites and harness docs

Add visual regression suites for the onboarding pages (Install, Human,
PublicKey, BackupPage, OnboardingScanPage, Profile) under src/test/vrt/onboarding,
each rendered with <Header /> like the real app. Pin every dynamic source
(invite code, mobile-auth URL, auth/public-route state) so the QR matrix and
step bar render identically on every run and OS.

Document the harness, determinism rules, the can't-capture-tall-pages limitation,
the sub-pixel seam artifact, and the baseline-update workflow in
docs/visual-regression-testing.md.

Skip three mobile tests whose current render is a known UI bug, so no broken
baseline is committed: Profile Finish-button overflow (#1975), backup-method
button layout (#1976), and the leftover Share button (#1977). Re-enable each and
generate its baseline once the bug is fixed.

* test(vrt): add linux screenshots

* tests: add CI workflow for VRT to guard PR

* tests: add playwright browser caching to VRT workflow

* tests: configure VRT workflow to save playwright browser cache even on failure

* test(vrt): use facehash for all avatars, disable their animation, and update mac screenshots

* test(vrt): update linux screenshots

* test(vrt): remove trigger on PR, only trigger for dev and master branch

* test(vrt): add vrt-update-baselines workflow

* tests: add 0.1% tolerance to vrt tests and more clarification in docs

* tests: increase timeout for vrt for webkit on linux

* test(vrt): regenerate baselines

* chore: change vrt-update-baselines.yml to use Github API for signing commit

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: James Browning <jamesbrowning91@gmail.com>
Co-authored-by: James <74595920+catch-21@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Use useEnrichedTags in ProfileTagged so compact hashfaces show
username initials instead of falling back to the pubky character.

Fixes #2264

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* tests: VRT: Landing page (/)

* test(vrt): regenerate baselines 2026-07-29T19:46:14Z

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
… visibility (#2204)

* refactor(PostArticleDetail): restructure layout and improve tag panel visibility

* Adjust layout structure in PostArticleDetail for better organization.
* Introduce a new container for the title, header, and actions bar.
* Ensure the PostTagsPanel is displayed correctly for both desktop and mobile views.
* Update SinglePostContent to conditionally render the PostPageHeader based on article type.

* chore: update snapshots��

* test(PostArticleDetail): add layout tests for stacked and wide modes

- Introduced tests to verify the default stacked columns layout and the wide layout behavior of the PostArticleDetail component.
- Updated snapshots to reflect the new layout rendering in wide mode.
- Reset home store state before each test to ensure consistent layout testing.

* refactor: code review�

---------

Co-authored-by: Taehwa Kim <hadeath03@gmail.com>
* tests: VRT: Search — empty state (/search)

* tests: VRT: Search — tagged results

* tests: VRT: Search — profile results

* test(vrt): regenerate baselines 2026-07-30T10:12:59Z

* test(vrt): regenerate baselines 2026-07-30T11:04:43Z

* tests: fix search result usernames

* tests: fix search result tagged posts

* tests: harden VRT wait on images to be ready

* test(vrt): regenerate baselines 2026-07-30T12:05:57Z

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat: in app url rich post embeds

* refactor: use shared same domain helper

* test: update coverage
…oss breakpoints (#2278)

* feat(Dialog): add centered prop for consistent dialog positioning across breakpoints

- Introduced a new `centered` prop to the Dialog component, allowing dialogs to be centered on all screen sizes, including mobile.
- Updated styling to accommodate the centered layout, ensuring proper margins and animations based on the `centered` state.
- Adjusted the PostAttachmentsImagesAndVideos component to utilize the new `centered` prop for media previews.

This enhancement improves the user experience by providing a more consistent dialog presentation across devices.�

* fix(PostAttachmentsImagesAndVideos): update responsive class for better layout handling

- Changed the `xsm:max-w-dvw` class to `xsm:max-w-full` in the PostAttachmentsImagesAndVideos component and its snapshots to ensure proper responsiveness across different screen sizes.
- This adjustment enhances the layout consistency for media previews on smaller devices.
* feat(#2185): unify PostInput design across layouts

  Align QuickReply with PostInput so every layout/dialog shares one composer
  structure: PostHeader on top, textarea, tags, then a single action bar row.

  - QuickReply now renders PostHeader (avatar + name + pubky) instead of a bare
    avatar in the composer row; drops the per-layout avatar sizing
  - Character count moves to PostHeader and only shows while expanded
  - Tag chips move into PostInputTags so they render next to the tag input
  - PostInputActionBar is always one row; drops `characterLimit`/`separateActions`
  - PostInputExpandableSection drops `inline`/`hideActionBar`/`className`
  - Delete QuickReplyListActions — the list layout uses the shared action bar
  - QuickReply textarea gets `maxLength` to cap input at the post limit

  Snapshots and tests updated.

* feat: enhance PostHeader and QuickReply components

- Added a test for rendering a real post when the author profile query settles without details in PostHeader.
- Updated PostHeader to render regardless of user details availability, ensuring the avatar and character counter are displayed correctly.
- Modified QuickReply to consolidate content rendering into a single QuickReplyContent component, removing the now obsolete QuickReplyListContent.
- Adjusted QuickReplyComposerRow to simplify layout and removed the trailing prop.
- Updated styles in PostInput for consistent padding across layouts.

Snapshots and tests have been updated accordingly.�

* chore: update tests

* chore: update snapshots & tests

* feat(QuickReply): add fallback avatar for logged-out users and clean up tests

- Implemented a fallback avatar rendering for users who are not logged in.
- Updated the QuickReplyContent component to conditionally display the AvatarWithFallback.
- Added a test case to verify the fallback avatar functionality.
- Removed outdated test case related to character limit passing to PostHeader.

* fix(PostHeader, QuickReply): minor adjustments to loading state and layout

- Added a blank line for better readability in PostHeader component.
- Updated QuickReply component layout to use a consistent flex-row structure for the container.

* chore: update snapshots & tests

* refactor(QuickReply): update layout to use conditional flex direction

- Modified the QuickReply component to conditionally apply flex direction based on authentication status, enhancing layout responsiveness.
- Updated corresponding snapshots to reflect the layout changes.

---------

Co-authored-by: Taehwa Kim <hadeath03@gmail.com>
)

* fix(#1990): show tags applied by the user in user list stat counts

User list tag counts (Active Users sidebar, Hot page, Who to Follow,
profile connections) displayed inbound tag counts (tags received on the
user's profile/posts). Tagging is an outbound user action, so the stat
now reads Nexus counts.tagged (tags applied by the user), which the
local write path already keeps updated optimistically.

Refs: #1990

* chore(ui): remove unused FollowerItem molecule
* tests: VRT: Hot page (/hot)

* tests: increase VRT test timeout and add per-image load timeout

* tests: remove comment from vitest.config.ts

* test(vrt): regenerate baselines 2026-08-03T16:10:43Z

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…eds (#2247)

* [WoT V1] Reach sidebar UI and profile tag selector (#2154)

* Add reach variants and profile tag filters

* fix(ui): tighten profile tag selector behavior

* test(core): align user active stream expectation

* fix(ui): collapse inactive profile tags filter and align limit input

Address PR review feedback on the Reach profile tag selector:
- Collapse the whole tags block (chips + input) with a 300ms
  grid-rows transition when reach is All/Me, keeping the last
  selected tags rendered during the exit animation
- Keep the at-limit "5 tags max" input the same width as the tag
  chips (w-32) by removing the TagInput w-40 expansion
- Render the red limit copy at full opacity
- Hide the emoji selector when the tag limit is reached

* [WoT V1]  Wire cache-safe wot_domain streams and Nexus params (#2156)

* Add reach variants and profile tag filters

* fix(ui): tighten profile tag selector behavior

* test(core): align user active stream expectation

* feat(core): wire cache-safe wot_domain streams and Nexus params

Build deterministic wot_domain stream IDs from home profile tags, refactor
breakDownStreamId to named fields, and request depth/domain_tags from Nexus.
Includes strict depth parsing and reach narrowing after profile-tag gating.

* fix(core): return false from matchesFilters for Me reach

Me streams use author-based ids, so matchesFilters can never match the
sorting:source:kind shape; guard instead of throwing on valid store state.

* fix(ui): collapse inactive profile tags filter and align limit input

Address PR review feedback on the Reach profile tag selector:
- Collapse the whole tags block (chips + input) with a 300ms
  grid-rows transition when reach is All/Me, keeping the last
  selected tags rendered during the exit animation
- Keep the at-limit "5 tags max" input the same width as the tag
  chips (w-32) by removing the TagInput w-40 expansion
- Render the red limit copy at full opacity
- Hide the emoji selector when the tag limit is reached

* fix(core): gate prepends by stream kind

parseStreamId only understands 3-segment ids, so postKindBelongsToStream
accepted every kind for wot_domain, tag, and author-kind streams, letting
wrong-kind posts prepend into kind-filtered feeds. Extract the kind via a
canonical model-layer getPostStreamKind parser instead.

* [WoT V1] Add Network, Me, and profile tags to custom feeds (#2191)

* Add reach variants and profile tag filters

* fix(ui): tighten profile tag selector behavior

* test(core): align user active stream expectation

* feat(core): wire cache-safe wot_domain streams and Nexus params

Build deterministic wot_domain stream IDs from home profile tags, refactor
breakDownStreamId to named fields, and request depth/domain_tags from Nexus.
Includes strict depth parsing and reach narrowing after profile-tag gating.

* fix(core): return false from matchesFilters for Me reach

Me streams use author-based ids, so matchesFilters can never match the
sorting:source:kind shape; guard instead of throwing on valid store state.

* fix(ui): collapse inactive profile tags filter and align limit input

Address PR review feedback on the Reach profile tag selector:
- Collapse the whole tags block (chips + input) with a 300ms
  grid-rows transition when reach is All/Me, keeping the last
  selected tags rendered during the exit animation
- Keep the at-limit "5 tags max" input the same width as the tag
  chips (w-32) by removing the TagInput w-40 expansion
- Render the red limit copy at full opacity
- Hide the emoji selector when the tag limit is reached

* feat(feeds): add Network, Me, and profile tags to custom feeds

Extend the custom-feed dialog with Wot (Network) and Me reaches and a
separate profile-tag selector using pubky-app-specs@0.6.1 domain_tags.

- Persist domain_tags through controller, normalizer, application,
  local model, homeserver JSON, bootstrap, and edit migration
- Replay exact []-vs-absent serialization during bootstrap so foreign
  feed HashIds are preserved; canonicalize lazily on first user edit
- Add sorting-aware author stream IDs for Me feeds and an optional
  sixth post-tag segment on wot_domain streams; send tags and
  domain_tags together for combined feeds
- Share one profile-tag reach capability policy between Home and
  custom feeds so #2150 enables Me with a single flip
- Gate unsupported reaches in the dialog, skip-and-log unsupported
  remote feeds, and show labeled read-only tag groups in feed filters

Refs: #2190

* fix(ui): align custom feed tag sections with design

Refs: #2190

* test(feeds): document foreign Followers reach rendering as policy

Rendering feeds with reaches this client cannot author (e.g. Followers)
is deliberate interop behavior for homeserver-stored, portable feeds,
not an accident of the buildFeedStreamId refactor. Add a policy comment
in useCustomStreamId and move the Followers test out of the mapping
failures section into an explicit interop-policy section.

Refs: #2191 (review)

* [WoT V1] Enable Me profile-tag domain feeds at depth 0 (#2231)

* Add reach variants and profile tag filters

* fix(ui): tighten profile tag selector behavior

* test(core): align user active stream expectation

* feat(core): wire cache-safe wot_domain streams and Nexus params

Build deterministic wot_domain stream IDs from home profile tags, refactor
breakDownStreamId to named fields, and request depth/domain_tags from Nexus.
Includes strict depth parsing and reach narrowing after profile-tag gating.

* fix(core): return false from matchesFilters for Me reach

Me streams use author-based ids, so matchesFilters can never match the
sorting:source:kind shape; guard instead of throwing on valid store state.

* fix(ui): collapse inactive profile tags filter and align limit input

Address PR review feedback on the Reach profile tag selector:
- Collapse the whole tags block (chips + input) with a 300ms
  grid-rows transition when reach is All/Me, keeping the last
  selected tags rendered during the exit animation
- Keep the at-limit "5 tags max" input the same width as the tag
  chips (w-32) by removing the TagInput w-40 expansion
- Render the red limit copy at full opacity
- Hide the emoji selector when the tag limit is reached

* feat(feeds): add Network, Me, and profile tags to custom feeds

Extend the custom-feed dialog with Wot (Network) and Me reaches and a
separate profile-tag selector using pubky-app-specs@0.6.1 domain_tags.

- Persist domain_tags through controller, normalizer, application,
  local model, homeserver JSON, bootstrap, and edit migration
- Replay exact []-vs-absent serialization during bootstrap so foreign
  feed HashIds are preserved; canonicalize lazily on first user edit
- Add sorting-aware author stream IDs for Me feeds and an optional
  sixth post-tag segment on wot_domain streams; send tags and
  domain_tags together for combined feeds
- Share one profile-tag reach capability policy between Home and
  custom feeds so #2150 enables Me with a single flip
- Gate unsupported reaches in the dialog, skip-and-log unsupported
  remote feeds, and show labeled read-only tag groups in feed filters

Refs: #2190

* fix(ui): align custom feed tag sections with design

Refs: #2190

* feat(feeds): enable Me profile-tag domain feeds at depth 0

pubky/pubky-nexus#982 depth-0 support is live on staging, so Me +
profile tags now maps to source=wot_domain&depth=0 (authors the
observer directly tagged).

Changes:
- Widen WotDomainDepth to 0|1|2 and accept '0' in the stream-id parser
- Fix truthy depth check that silently dropped depth 0 from requests
- Add 'me' to the shared profile-tag reach policy (Home + custom feeds)
- Map REACH.ME to depth 0 in Home and replace the custom-feed depth
  ternary with an exhaustive typed map
- Remove the now-dead isProfileTagGatedReach helper
- Flip gating tests; add depth-0 build/parse/serialization coverage
  and bootstrap admission for remote Me profile-tag feeds

Refs: #2150

* fix(feeds): avoid module-scope enum access in depth map

Suites that partially mock pubky-app-specs do not export
PubkyAppFeedReach, so evaluating the depth map at import time crashed
unrelated tests (migration, bootstrap, auth). Move the map inside a
function like the other enum maps in feed.helpers.ts, keeping the
exhaustive satisfies check.

Refs: #2150

* refactor(feeds): key wot_domain depth map by config supported set

Derive the custom-feed depth map keys from the exported
ProfileTagSupportedReach union in config/feed.ts instead of a
hand-maintained pubky-app-specs enum union. The guard already narrows
the reach string, so the cast is gone and adding a reach to
PROFILE_TAG_SUPPORTED_REACHES without a depth decision now fails
compilation, as the PR description claims. String keys also mean no
enum access at module scope, so partially mocked test suites stay safe.
Cross-reference both depth maps so retuning stays in sync.

Refs: #2231 (comment)

* feat(ui): explain profile tag effect by selected reach

Add a desktop-only right-side tooltip on the Home Reach profile tag
input so users understand what the tags do for Network, Following,
Friends, and Me. Friends uses the honest Following copy because V1
sends the same depth-1 trust set for both.

* fix(ui): show profile tag tooltip below the input

Prefer bottom placement over right so the tooltip sits under the
Reach sidebar profile tag field.

* [WoT V1] Restructure profile-tag filtering as Tagged as reach (#2260)

* revert(ui): remove per-reach profile tag tooltips

Replace the temporary reach-specific explanation with the standalone Tagged-as feed treatment tracked in #2258.

* feat(core): persist standalone Tagged-as home state

Gate Home stream resolution on auth and persisted-state hydration, migrate existing selections, and apply the fresh-user My network default without overriding user input.\n\nResolve active Tagged-as feeds as depth-2 wot_domain streams while retaining wider custom-feed depth support for compatibility.\n\nRefs: #2258

* feat(ui): add standalone Tagged-as reach

Add the standalone Home and custom-feed Reach option, embedded profile-tag editor, localized headline, and Visual-layout persistent header.\n\nPreserve legacy custom domain feeds on rename-only edits while converting new Tagged-as feeds to wot/depth 2.\n\nRefs: #2258

* refactor(core): tighten Tagged-as component contracts

Remove obsolete Reach and radio-group extension APIs, replace the Home stream resolver's positional arguments with named options, and scope persistent timeline headers to Home feeds.\n\nRefs: #2258

* fix(ui): match Tagged-as headline color

Use the muted foreground token specified by the Figma headline style.\n\nRefs: #2258

* fix(ui): align Tagged-as copy and custom feed fields

Match the Figma headline wording and quotes, and render custom-feed profile tags only when Tagged as is selected.\n\nRefs: #2258

* fix(ui): align Tagged-as reach with effective feed

Keep the highlighted Reach synchronized with the stream while the empty Tagged-as editor remains open, and prevent signed-out All clicks from suppressing the post-signup default.

Show legacy custom-feed profile tags read-only in edit mode and remove the unused legacy LeftSidebar implementation.

Refs: #2258

* test(vrt): align Home fixtures with WoT state

Build the Home VRT filter state from the production defaults, mark hydration complete, and keep custom-feed fixtures aligned with the domain tag model. Complete the mocked Home action surface and refresh the macOS Home baselines.

Refs: #2247

* test(vrt): regenerate baselines 2026-07-30T21:36:45Z

* fix(wot): address integration review findings

* test(vrt): regenerate baselines 2026-08-03T20:18:32Z

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: secondl1ght <85003930+secondl1ght@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* feat(posts): remove deleted and missing posts from saved feeds

Add a Remove action on unavailable post cards (author-deleted and
not-found) in owned collections and bookmarks:

- Gate removal on collection ownership / authenticated bookmark access
  (useRemoveDeletedPost); on homeserver sync failure, verify settled
  local state to decide between rollback and keeping the card removed.
- Hide cards optimistically through an explicit commit/rollback
  transaction (removePostsOptimistically) that preserves ordering and
  collection skip offsets while pending, and shrinks the consumed
  offset when a committed removal shrinks the backend collection.
- Make bookmark writes local-first (IndexedDB before homeserver sync)
  so failure reconciliation reads settled local state; when only the
  sync fails, keep the card removed and warn instead of erroring.
- Offer the same Remove flow in the visual mosaic layout, and move
  keyboard focus to the adjacent feed card before the removed card
  unmounts (focusAdjacentGridItem), skipping disabled or hidden
  targets.
- Unify PostDeleted/PostMissing into one PostUnavailable molecule with
  shared UI and distinct copy and data-cy hooks.

Closes #2102

* fix(posts): harden removal failure handling and offset accounting

Address review findings on the unavailable-post Remove flow:

- Re-apply committed-removal skip-offset decrements when a stream fetch
  is in flight: the fetch derives its absolute cursor from the offset
  captured at request start, so decrements landing mid-flight were
  silently discarded and each later page skipped one live row.
- Treat a missing or tombstoned collection as unverifiable in the
  removal failure path instead of misreading the NOT_FOUND no-op as a
  committed removal; the card now rolls back with an error toast
  instead of vanishing behind a false "removed on this device" message.
- Reconcile the bookmark toggle against local state after a failed
  toggle: local-first deletes can commit before homeserver sync fails,
  so the button now mirrors the bookmarks feed and warns that only the
  sync failed. Document BookmarkApplication's actual failure contract.
The PostHeaderUserInfo root container doubles as the UserInfoPopover
hover target. #2113 made it `w-full` so long display names could
truncate, which also stretched the hover (and username link) target
across the entire header row — hovering the empty space next to the
timestamp opened the popover.

Switch the container and the username link to `w-fit max-w-full` so
they hug their content when the name is short and still fall back to
the available width (and truncate) when it is long.

Closes: #2303
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

URL: https://pubky-app-pr-2309-fzxmjul7ya-oa.a.run.app

pubky-app-pr-23096937d11

Nirzhuk and others added 15 commits August 6, 2026 11:03
…erent content unfocus and focus (#2285)

* feat(posts): Post Input Improvement with animations - Related to different content unfocus and focus

* fix(PostHeader): update user details handling in tests and component logic

- Refactored the test case to clarify fallback behavior when user details are null.
- Adjusted the component logic to treat null as a valid state for provided user details, ensuring correct user detail fetching.
- Updated assertions in tests to reflect changes in user detail handling.

* feat: support for list layout correctly

* test(vrt): regenerate baselines 2026-08-04T03:53:59Z

* refactor: enhance PostThreadConnector and QuickReply components with unified motion handling

- Added a `style` prop to PostThreadConnector for custom styling.
- Refactored QuickReply and PostInput components to utilize new motion utilities for consistent height transitions and dissolve effects.
- Introduced `getComposerHeightTransition` and `getComposerDissolveVariants` functions to centralize animation logic.
- Updated tests and snapshots to reflect changes in transition handling and component structure.

* refactor: streamline PostInput component and update styling for list layout

- Removed unused placeholder constants from PostInput.constants.ts.
- Refactored PostInput to utilize a new useElementHeight hook for height measurement.
- Updated PostInput styles to apply consistent typography based on layout type.
- Adjusted tests and snapshots to reflect changes in component structure and styling.
- Removed the usesWidePostInput function as its logic is now integrated into the layout handling.

* test: update PostInput tests and snapshots for textarea styling changes

- Modified test assertions to reflect updated class names for the textarea, ensuring it now includes 'w-full' for proper styling.
- Adjusted snapshots to match the new layout and styling of the PostInput component, including changes to flex properties and item alignment.

* feat: enhance MentionPopover with anchor positioning and portal rendering

- Introduced an anchorRef prop to the MentionPopover component to position the popover relative to a specified textarea.
- Updated the popover's rendering to use a portal, allowing it to escape clipping ancestors and maintain visibility.
- Adjusted styles to use fixed positioning for the popover, ensuring it displays correctly in various layouts.
- Updated tests and snapshots to reflect the new rendering behavior and anchor positioning.

* fix: adjust gap classes and post input header size for improved layout

- Updated GAP_CLASS_BY_HEADER_SIZE to reduce gaps for normal, large, and extraLarge sizes.
- Changed POST_INPUT_HEADER_SIZE_BY_TAGS_LAYOUT to set the 'side' layout to extraLarge for better alignment.

* chore: update snapshots�

* chore: update snapshots & tests�

* fix: update PostArticleDetail component and tests to use 'extraLarge' size

- Changed the size attribute for PostHeader from 'large' to 'extraLarge' in the PostArticleDetail component.
- Updated corresponding tests and snapshots to reflect this change.

* fix: update QuickReply component and tests for padding adjustments

- Changed padding from 'p-12' to 'p-6' in the QuickReply component to maintain a compact layout.
- Updated corresponding tests and snapshots to reflect the new padding behavior and ensure consistency across layouts.
- Refactored height measurement logic in useElementHeight hook for improved performance and accuracy.

* fix: improve PostInput height handling and add tests for expanded state

- Enhanced PostInput component to maintain auto height for forced-expanded dialog composer after measuring content.
- Updated height transition logic to account for measured state content height.
- Added a new test case to verify the auto height behavior when the dialog is expanded.
- Refactored QuickReply component to align height transition logic with the new measurement approach.

* fix: update PostThreadConnector and MentionPopover for improved styling and functionality

- Refactored PostThreadConnector to apply custom styles for dialog-reply connectors, enhancing visual consistency.
- Removed unnecessary className prop from PostThreadConnector, simplifying the component's API.
- Enhanced MentionPopover to reposition correctly when the anchor resizes, improving user experience.
- Updated tests for both components to reflect these changes and ensure proper functionality.

* fix: enhance PostInput and QuickReply components for improved height handling and avatar display

- Updated PostInput to utilize a new useComposerHeightAnimation hook for better height management during expansion and collapse.
- Refactored QuickReply to incorporate dynamic avatar sizing based on layout, ensuring consistent display across different states.
- Added tests to verify the new height animation behavior and avatar size adjustments, enhancing overall component reliability.
- Adjusted MentionPopover to accept a more generic anchorRef type for broader compatibility.�

* refactor(tests): update PostHeaderUserInfo tests for improved layout handling

- Adjusted class names in tests to ensure proper width constraints for user info and username link, enhancing layout consistency.
- Updated test descriptions for clarity on functionality regarding popover hover targets and username link truncation.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(ui): allow emoji picker scroll without prior click (#1871)

* fix(ui): update tests
Remove the Language section from Settings and all non-English
translation files while keeping the i18n infrastructure (next-intl,
providers, translation calls) in place so languages can be added
back later.

- Drop the /settings/language route, Language template, and
  LanguageSelector organism
- Always resolve the locale to 'en'; stop reading the locale cookie
- Remove the language field from the settings store and homeserver
  settings.json; legacy language fields from older clients are
  ignored safely in both directions
- Clear the now-unused locale cookie exclusion on logout

Closes: #2145
* feat(ui): move quick reply below original post

Refs: #1839

* fix(ui): match quick reply collapsed state to Figma

Render the top-level reply prompt as the minimal avatar and placeholder row in Column and Wide layouts while preserving the existing expanded composer behavior.\n\nRefs: #1839

* test(vrt): regenerate baselines 2026-08-05T05:03:52Z

* fix(ui): align quick reply thread connector

Overlay the connector across the composer card so it no longer inflates the reply row or leaves the terminal curve below the card.\n\nRefs: #1839

* test(vrt): regenerate baselines 2026-08-05T05:27:19Z

* fix(ui): terminate replies during expansion

Make the final visible reply terminal while expand-all hides the more-replies control, preventing a transient dangling connector.\n\nRefs: #1839

* refactor(ui): describe quick reply behavior

Keep implementation comments and test names focused on runtime intent instead of design-tool provenance.\n\nRefs: #1839

* test(vrt): regenerate baselines 2026-08-07T03:07:29Z

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* tests: VRT: Collections overview

* tests: VRT: Single collection — grid/list/visual layouts & Bookmarks collection

* test(vrt): regenerate baselines 2026-08-03T19:26:50Z

* test(vrt): regenerate baselines 2026-08-03T19:26:52Z

* tests: add collection background, correct number of tags for grid cards, more visual layout posts, remove mobile tests for List and Visual layout

* tests: smaller vrt images for collection backgrounds

* tests: increase vrt timeout to accomodate slow webkit on linux with many images

* test(vrt): regenerate baselines 2026-08-03T20:33:13Z

* tests: add background image to single-collection vrt and move vrt images out of public dir

* test(vrt): regenerate baselines 2026-08-03T21:01:50Z

* tests: remove vrt baselines for single collection list/visual layouts on mobile

* tests: ensure wait for collection background image before vrt snapshot

* test: remove waitForSingleCollectionCoverReady for vrt

* tests: add 'isolate' class to Collection Hero to ensure background images are shown by every (headless) browser

* test(vrt): regenerate baselines 2026-08-03T22:17:04Z

* tests: add comments and see to other review feedback

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: V <jovanovicv90@gmail.com>
* feat: reorder posts in collections

* test(ui): regenerate CollectionHero reorder-active snapshot after dev merge

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: V <jovanovicv90@gmail.com>
* fix(ui): enable arrow keys on media carousel open

Focus the carousel when the lightbox opens so left/right arrows work
immediately, update the slide counter on select, and suppress focus
outlines on media tiles and videos.

Closes #1775

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ui): restore focus-visible ring on media controls

Address Greptile feedback by using the design-system focus-visible ring
on carousel, video, and image tiles instead of suppressing all focus
indication.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(ui): cover lightbox autofocus with real Radix Dialog

Move carousel open-focus coverage out of the mocked Dialog suite into a
dedicated test that exercises Radix onOpenAutoFocus, per component-testing
rules that Radix primitives must not be mocked.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ui): drop focus ring on lightbox carousel container

Keyboard interaction lit the design-system focus-visible ring around the
whole lightbox carousel (QA report on #2311). Suppress it on the carousel
container only; tiles, videos, and nav buttons keep their focus rings.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…) (#2307)

The Share action on the Your pubky card was a v20 design leftover; the
current design keeps only Copy to clipboard. Remove the button, its
handleShare logic, the now-orphaned share lib (shareWithFallback), and
the unused onboarding.pubky share* i18n keys across all locales.
…#2313)

* refactor(i18n): remove i18n infrastructure and inline US English copy

Second part of the two-step i18n removal (#2305, follows #2145). Deletes
next-intl and all localization infrastructure and inlines the US English
copy at every call site, preserving rendered output byte-for-byte.

- Inline ~965 plain/interpolated translations via a deterministic
  ts-morph codemod sourcing strings from messages/en.json; convert rich
  text to JSX, ICU plurals to explicit singular/plural logic, t.raw to a
  typed constant, useFormatter to native Intl with en-US, and
  translation-key maps to constants holding final copy
- Convert translation-backed zod schemas and shared helpers
  (image size-limit toasts, password strength) to direct messages
- Remove src/i18n/, messages/, IntlProvider, the next-intl Next.js
  plugin, the global and per-test next-intl mocks, and the VRT harness
  provider; drop next-intl and the direct @swc/helpers dependency
- Render the document with fixed lang="en-US" dir="ltr"; keep
  force-dynamic and the raw runtime-config script first in <body>;
  hardcode the Plausible event-locale pageview prop to en-US
- Rewrite test assertions from mock-echoed translation keys to the
  actual rendered US English copy
- Fix a latent fallback that rendered the nonexistent key
  profile.actions.loading instead of "Loading..."
- Ignore local tooling worktrees in eslint and vitest configs so they
  no longer contaminate repo-wide runs

* docs(migrations): add conflict-resolution guide for the i18n removal

Playbook for rebasing open branches onto dev after #2313: pattern-by-
pattern resolutions with real before/after examples, commands to recover
the deleted messages/en.json catalog, and a residue sweep plus
verification checklist. Indexed in docs/README.md under Migrations.

---------

Co-authored-by: Orlando Goncalves <orlando.goncalves@gmail.com>
* tests: rename collections list test, improve comments, and fix it to pass

* tests: fix notification e2e

* tests: harden wait for recovery file to download before moving in Cypress E2E

* tests: wait for all notifications to be indexed for multiple notifications E2E

* tests: rewrite renameFile function to poll for file before attempting to rename

* tests: harden multi notif E2E test
…on (#2320)

Portrait photos from phone cameras store sensor-native landscape pixels
plus an EXIF orientation tag. The decode-time resize computed its target
from the raw SOF dimensions while createImageBitmap applied the EXIF
rotation, so 90-degree-rotated photos were squeezed into swapped-aspect
frames and the distorted pixels were uploaded to the homeserver.

Swap the resize target for orientations 5-8 via a JPEG EXIF orientation
parser, re-decode without resizing when the returned bitmap does not
match the requested dimensions, and skip decode-time resizing for WebP
that flags EXIF in VP8X. Consolidate the duplicated RIFF chunk and JPEG
segment walkers into shared helpers.

Verified against the original Galaxy A16 report photo (orientation 6).

Refs: #2268

Co-authored-by: secondl1ght <85003930+secondl1ght@users.noreply.github.com>
@catch-21
catch-21 marked this pull request as ready for review August 11, 2026 12:57
@greptile-apps

greptile-apps Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review (1047 files, 100 file limit).

* test: reenable skipped mobile vrt

* test(vrt): regenerate baselines 2026-08-11T13:00:50Z

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants