Compare commits

...

405 Commits

Author SHA1 Message Date
Samuel Newman 82e1bb4571 memoize pager view 2025-09-03 12:28:21 +03:00
Samuel Newman 42497044c9 don't put props in dep array 2025-09-02 14:37:15 +03:00
Samuel Newman ff4aecdd6c split drawer layout into own component 2025-09-02 14:37:13 +03:00
Samuel Newman b2258fb6cb Add QR code to github action (#8948) 2025-09-01 17:56:21 -07:00
Bartosz Kaszubowski 0bda727e8b Web: fix Suggested Accounts tabs end of scroll detection (#8939) 2025-09-01 03:23:41 -07:00
Samuel Newman 1c78f36a51 v1.107.0 release prep (#8938)
* yarn intl:pull

* yarn intl:extract:all
2025-08-29 08:24:43 -07:00
Samuel Newman d6dc52b6ea Improve e2e tests (#8927)
* get e2e image picker working

* verify create account actually reaches onboarding

* wait for image to actually be attached before posting

* wait until login finishes before moving on

* sign out before switch accounts then wait until logged in

* disable onboarding experiments in e2e

* add testId to handle availability checkmark

* fix too long username

* update thread muting test to reflect current behaviour

* hackfix for the british english translation

* unflake the onboarding tests

* fix curate list flow

* admit defeat on the most list one
2025-08-29 08:15:05 -07:00
Samuel Newman 541502c7ee prevent double border (#8937) 2025-08-29 07:02:28 -07:00
Samuel Newman 0114cfcfe1 fix hook being marked as async for no reason (#8932) 2025-08-29 10:36:20 +03:00
pfrazee 6172423714 Nightly source-language update 2025-08-29 02:36:45 +00:00
Samuel Newman 8a4398608a Close web mention suggestions popup on Escape (#8605)
* alf web typeahead

* fix type error

* fix escape behaviour

* change selection on hover

* rm React.

* undo random change
2025-08-28 17:03:12 -07:00
Samuel Newman 27c1058568 use Link instead of manual navigation (#8930) 2025-08-28 15:18:56 -07:00
Eric Bailey 2f2b542e5c Bump expo-image-picker to 17.0.5 (#8929)
* Bump picker, add patch for next version

* Revert "Bump picker, add patch for next version"

This reverts commit a4aab0bdcd.

* Update to latest picker@next
2025-08-28 15:14:28 -07:00
Eric Bailey 2a54781ce0 Update dev env (#8921)
* Update dev-env

* Integrate appviewDid value from dev-env

* Use correct env value to disable policy update overlay

* Remove log
2025-08-28 04:20:06 -07:00
pfrazee dcba5c4668 Nightly source-language update 2025-08-28 02:37:01 +00:00
Chenyu 7469e7306c Update birthday setting dialog (#8910)
* update birthday setting dialog

* Update src/components/dialogs/BirthDateSettings.tsx

Co-authored-by: Eric Bailey <git@esb.lol>

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-08-27 19:55:18 -05:00
surfdude29 58c2e68a24 Update FollowDialog.tsx (#8919) 2025-08-28 02:43:33 +03:00
surfdude29 01c20958c1 Add english-only-resource context and tweak labels (#8805)
* add context in VerificationsDialog.tsx

* add context in VerifierDialog.tsx

* add context in VerificationSettings.tsx

* add context in EditProfileDialog.tsx

* add context and tweak label in ChangeHandleDialog.tsx

* tweak label in ContentHider.tsx
2025-08-27 18:12:01 -05:00
jim 99722436b1 Merge pull request #8885 from internet-development/caidanw/app-1409-add-data-nosnippet-to-discover-feed
feat: prevent search engines from using Discover feed content as page descriptions
2025-08-27 14:56:40 -07:00
Caidan Williams 4a1f1efd76 refactor(feed): simplify isDiscoverFeed logic in FeedPage 2025-08-27 11:58:58 -07:00
Caidan Williams bd730db03e refactor(feed): remove NoSnippetWrapper from FeedPage in favor of dataSet attribute
Replaces NoSnippetWrapper with a dataSet prop on the root View to
control the nosnippet attribute for discover feeds. This simplifies the
component structure and improves maintainability by reducing unnecessary
wrappers.
2025-08-27 11:58:58 -07:00
Samuel Newman 8a22584a87 prevent android exposures to gate (#8916) 2025-08-27 10:12:09 -07:00
mozzius 17cbf75747 Nightly source-language update 2025-08-27 16:08:25 +00:00
Samuel Newman 8adebe6702 starter pack dialog tweaks (#8913) 2025-08-27 09:01:10 -07:00
Samuel Newman 39d460db51 Language select final tweaks (#8914)
* [APP-1303] Redesign/refactor post language select (#8884)

* Nightly source-language update

* Nightly source-language update

* [APP-1303] Redesign/refactor post language select

* update: stylesheets.create to use the latest structure

* update styles to modern structure

* update: dialog breakpoints on web and delete depricated language modals

* remove unused post languages settings dialog

* restructure Post languages dialog

* place the Dialog.Close inside the Dialog.ScrollableInner

* add: language search

* update search and language variables for clarity

* fix: memoize language state lists

* chore: add comments

* update proper colors to the background

* add back older error boundary

* add: tweaks to the mobile and web responsiveness

* add tweaks to center the container

* update labels

* update button and border

* added translation updates

* Update: text input to reuse search input

* remove unused file

* update: web breakpoints

* run eslint and prettier

---------

Co-authored-by: Elijah Seed-Arita <elijaharita@gmail.com>
Co-authored-by: Anastasiya Uraleva <anastasiya@Anastasiyas-MacBook-Pro.local>
Co-authored-by: Anastasiya Uraleva <anastasiya@Mac.localdomain>

* rm old file

* sort out styles, add FlatListFooter component

* rm cancel button in favor of search input X

* get dialog height working on iOS

* delete `DropdownButton`

* hide scroll indicators on android

* ios scroll indicator insets

* get footer sorta working on android

* change button color on press

* rm empty file

---------

Co-authored-by: Anastasiya Uraleva <anastasiyauraleva@gmail.com>
Co-authored-by: Elijah Seed-Arita <elijaharita@gmail.com>
Co-authored-by: Anastasiya Uraleva <anastasiya@Anastasiyas-MacBook-Pro.local>
Co-authored-by: Anastasiya Uraleva <anastasiya@Mac.localdomain>
2025-08-27 09:00:36 -07:00
Samuel Newman eac0290143 Add suggested follows experiment to onboarding (#8847)
* add new gated screen to onboarding

* add tab bar, adjust layout

* replace chevron with arrow

* get suggested accounts working on native

* tweaks for web

* add metrics to follow all

* rm non-functional link from card

* ensure selected interests are passed through to interests query

* fix logcontext

* followed all accounts! toast

* rm save interests function

* Update src/screens/Onboarding/StepSuggestedAccounts/index.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* use admonition

* rm comment

* Better interest tabs (#8879)

* make tabs draggable

* move tab component to own file

* rm focused state from tab, improve label

* add focus styles, remove focus when dragging

* rm log

* add arrows to tabs

* rename Tabs -> InterestTabs

* try and simplify approach

* rename ref

* Update InterestTabs.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/components/InterestTabs.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/components/ProgressGuide/FollowDialog.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/components/ProgressGuide/FollowDialog.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* add newline

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* fix flex problem

* Add value proposition screen experiment (#8898)

* add assets

* add value prop experiment

* add alt text

* add metrics

* add transitions

* add skip button

* tweak copy

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* add borderless variant for web

* rm pointer events

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Add slight delay, prevent layout shift

* Handle layout shift, add Let's Go! text

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
2025-08-27 04:17:45 -07:00
pfrazee 0617fca5ef Nightly source-language update 2025-08-27 02:36:23 +00:00
hailey a1ed59e0ee use an env var for configurable proxy header (#8863) 2025-08-26 17:13:11 -07:00
surfdude29 39c6984c6e Mark label for translation in LoggedOutCTA.tsx (#8908)
* Mark label for translation in `LoggedOutCTA.tsx`

* Update LoggedOutCTA.tsx
2025-08-26 15:09:47 -07:00
Eric Bailey 9f7c920346 Fix toast type (#8909)
* Fix confusing toast API

* Provide all exports to e2e file

* Fix first usage in Composer

* Loosen type, add Trans tag
2025-08-26 16:54:43 -05:00
Caidan Williams 6ddc268b91 feat: prevent search engines from indexing Discover feed content as page descriptions 2025-08-26 13:01:36 -07:00
Caidan Williams 0517768cd3 feat: add data-nosnippet attribute to Discover feed for SEO control 2025-08-26 13:01:36 -07:00
Bartosz Kaszubowski 0555d3623c Fix RightNav elements focus outline on web (#8788) 2025-08-26 14:43:25 -05:00
Bartosz Kaszubowski 8dcf1825ec Web: fix Edit Profile discard warning when pressing backdrop (#8824)
* Web: fix Edit Profile discard warning

* cleanup imports
2025-08-26 14:38:59 -05:00
surfdude29 c12fd4482e Discover FeedsDiscover New Feeds (#8860) 2025-08-26 14:34:34 -05:00
kindgracekind 88e6dff484 Enable show less / more buttons for third party feeds (#8672)
Co-authored-by: hailey <hailey@blueskyweb.xyz>
Co-authored-by: Hailey <me@haileyok.com>
2025-08-26 12:16:50 -07:00
Samuel Newman 98d96bd28b Modernise change password dialog (#8269)
* alf change password dialog

* rm old modal

* move dialog

* fix buttons on native

* lowercase

* fix dupe import

* Apply suggestions from code review

Thanks @surfdude29 :)

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* use primary_subtle, change web layout

* move to into non-network err, warn -> error

* error -> safeMessage

* better message than token is invalid

* cancel button native only

* move close to end of focus priority

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2025-08-26 10:50:39 -07:00
Eric Bailey dd2830ba6c Fix bad copy pasta (#8907) 2025-08-26 12:33:43 -05:00
Eric Bailey 6a16ef83f6 Fix default opengraph (#8872)
* Fix default opengraph

* Add avatar back

* Remove default og images
2025-08-26 11:32:08 -05:00
Eric Bailey 8ec20026c0 Yeah toast (#8878)
* Split out into macro component

* Add Action component

* Add fallback

* add button to view post after sending

* Dismiss toast when clicking action button

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-08-26 11:20:04 -05:00
Alex Benzer acd7211b35 Adds signup CTA tests for logged-out visitors (#8906) 2025-08-26 08:52:38 -07:00
Samuel Newman b70e5b2f38 Add verification checkmarks to embed.bsky.app (#8644)
* update vite+typescript

* update atproto api to latest, split out utils

* add checkmark to post

* add checkie to embed

* revert change to example post

* fix ext link color
2025-08-26 08:24:46 -07:00
Inbestigator 5a074fa37a Add profile link to switcher menu (#8867)
* feat(leftnav): add profile link to switcher menu

* fix: close menu on navigate
2025-08-26 08:18:40 -07:00
Eric Bailey df20ae237e Threads v2 cleanup (#8902)
* Delete root PostThread component

* Remove PostThreadItem, migrate DebugMod to use new components

* Remove other unused components

* Move PostThreadFollowBtn to new home

* Move PostThreadComposePrompt to new home

* Remove gate

* Keep naming in DebugMod

* rm v1 prefs

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-08-26 09:54:19 -05:00
surfdude29 e91a683810 Tweak SelectMediaButton error string, accessibilityHint, and comments (#8870)
* remove isNative check from accessibilityHint

* tweak grammar in error string

* prettier

* tweak comment
2025-08-26 05:58:04 -07:00
jim bc8e3ba30b Merge pull request #8806 from internet-development/binaryfiddler/starter-pack-part2
Starter pack dialog implementations
2025-08-25 23:23:20 -07:00
jim e4c5fb7de5 Merge pull request #8901 from internet-development/caidanw/app-1358-final-card-refresh
feat(ui): redesign suggested profiles 'See more' card
2025-08-25 23:19:11 -07:00
jim d1aab56982 Merge pull request #8900 from internet-development/caidanw/app-1413-clean-up-canonical-urls
feat: implement canonical URL filter to clean parameters for SEO
2025-08-25 23:07:00 -07:00
pfrazee bb1eab41c6 Nightly source-language update 2025-08-26 02:38:40 +00:00
Caidan Williams eb45154823 refactor: rename canonical filter to canonicalize_url for better clarity
- Rename filter from 'canonical' to 'canonicalize_url' to follow Pongo2
naming conventions
- Update function name from filterCanonical to filterCanonicalizeURL
- Update template usage in post.html and profile.html
- Update test function name and all references
2025-08-25 17:18:15 -07:00
Caidan Williams 2b4d32bb09 feat(ui): redesign "See more" suggested profiles card
Refactored the "See more accounts you might like" card to use ButtonIcon
and ButtonText for improved consistency and accessibility. Updated
styles for better alignment, spacing, and visual hierarchy. Navigates to
the Explore page when pressed.
2025-08-25 16:57:33 -07:00
Caidan Williams b667e8b985 refactor(feed): rename Arrow to ArrowRight for clarity 2025-08-25 16:16:55 -07:00
Samuel Newman e8cd7ab131 Remove handle suggestion gate (#8899)
* remove handle suggestion gate

* rm from list of gates
2025-08-25 16:13:54 -07:00
Caidan Williams 685650b296 test: add comprehensive coverage for canonical URL filter
- Verify clean URL passthrough behavior
- Test query parameter removal functionality
- Test fragment removal functionality
- Test combined query params and fragments handling
- Ensure graceful degradation for malformed URLs
2025-08-25 16:04:45 -07:00
Caidan Williams f9118b2729 feat: apply canonical filter to profile template URLs for SEO
Use canonical filter on requestURI in canonical link tag while preserving
original URL with parameters for og:url metadata. This provides clean
canonical URLs for search engines while maintaining full Open Graph URLs.
2025-08-25 16:04:45 -07:00
Caidan Williams 5c04c9e3e3 feat: apply canonical filter to clean URLs in post template
Uses canonical filter for canonical link tags while preserving original URLs with parameters for og:url metadata, improving SEO through proper URL canonicalization
2025-08-25 16:04:45 -07:00
Caidan Williams 60a1be6de0 feat(seo): add canonical URL filter to remove query parameters
Addresses community feedback about canonical URLs being misleading
when they include UTM parameters. The new Pongo2 filter creates
clean canonical URLs while preserving tracking parameters for
social sharing.
2025-08-25 16:04:45 -07:00
Samuel Newman f3905c574b remove root sibling parent(s??) from composer (#8897) 2025-08-25 15:30:13 -07:00
Samuel Newman 27c591f031 Fix Gif Select dialog search bar scrolling away (#8874)
* fix flatlist dialogs on web

* tweak gif select dialog, add style prop to textfield
2025-08-25 09:37:12 -07:00
Samuel Newman 7771b56a43 fix searching for phrases by replacing smart quotes (#8865) 2025-08-25 19:25:28 +03:00
Samuel Newman 3810b29fb6 ALF log screen (#8845) 2025-08-25 19:25:02 +03:00
Samuel Newman 9d77b361fe add content hider padding (#8843) 2025-08-25 19:24:48 +03:00
Samuel Newman 54f7af12ca Update DM header to match new Layout style (#8846) 2025-08-25 19:23:08 +03:00
pfrazee ecb77a9b96 Nightly source-language update 2025-08-25 02:40:42 +00:00
Samuel Newman 45825dd005 Fix alt text in media preview (#8854) 2025-08-24 14:31:42 +03:00
Samuel Newman 5e07b0c77d Skip dirty git tree check in prebuild (#8853) 2025-08-24 14:31:25 +03:00
pfrazee dddea126f4 Nightly source-language update 2025-08-24 02:42:01 +00:00
Samuel Newman ce2604d0e9 Update @mozzius/expo-dynamic-app-icon (#8834) 2025-08-24 01:18:02 +03:00
Eric Bailey c28195067f Update origin (#8889) 2025-08-23 15:33:31 -05:00
Eric Bailey 3b7b93a411 Debug (#8888)
* Swap URL

* Add debug
2025-08-23 14:45:57 -05:00
jim 99d7570818 Merge pull request #8883 from internet-development/caidanw/app-1408-add-canonical-url
feat: add canonical URLs to improve SEO
2025-08-22 19:40:11 -07:00
pfrazee 7b9bc52720 Nightly source-language update 2025-08-23 02:36:29 +00:00
Chenyu Huang f84a756691 optimize for the web 2025-08-22 17:59:54 -07:00
jim 78e1e26a2c Merge pull request #8882 from internet-development/binaryfiddler/isnetwork
wrapp failed to send feed interactions inside isNetworkError
2025-08-22 16:10:53 -07:00
Caidan Williams d8c904d1d9 feat: add canonical URL to profile template for better SEO 2025-08-22 14:42:05 -07:00
Caidan Williams 560c503aa6 feat: add canonical URL to post template for better SEO 2025-08-22 14:40:57 -07:00
Caidan Williams 5120c037d1 feat: add canonical URL to home page for SEO optimization 2025-08-22 14:39:56 -07:00
Chenyu Huang 184df9cbfe wrapp failed to send feed interactions inside isNetworkError 2025-08-22 13:28:32 -07:00
Eric Bailey 912ab1bd9b [LEG-246] Geo overlay (#8881)
* Add AgeBlockedGeo

* Add MaxMind usage text

* Add geo overlay

---------

Co-authored-by: rafael <rafael@blueskyweb.xyz>
2025-08-22 14:55:16 -05:00
surfdude29 f038ac70da rearrange translation logic (#8880) 2025-08-22 12:00:00 -07:00
jim e404ddfbcd Merge pull request #8875 from internet-development/caidan/app-1406-follow-suggestions-card-to-show-follow-back
[APP-1406] follow suggestions card to show follow back
2025-08-21 22:15:07 -07:00
pfrazee 0baa5198e0 Nightly source-language update 2025-08-22 02:38:34 +00:00
Caidan Williams 7a1adfe67c refactor: all uses of "Follow Back" to "Follow back" 2025-08-21 15:55:01 -07:00
jim af55e578b2 Merge pull request #8876 from internet-development/caidanw/app-1399-trending-videos-icon-missing
[APP-1399] trending videos icon missing
2025-08-21 15:44:14 -07:00
Caidan Williams 994003e603 fix: capitalization of "Follow back" to "Follow Back" 2025-08-21 13:53:44 -07:00
Caidan Williams 8ab49da6da refactor: replace View with Button in ViewMoreCard for consistent colors across themes
Updated ViewMoreCard to use a Button component instead of a styled View
for the 'View more' action. This improves accessibility and consistency
with other interactive elements in TrendingVideos.
2025-08-21 13:23:53 -07:00
Caidan Williams c097f68a7d refactor: extract ViewMoreCard from VideoCards component
Moved the 'View more' card logic into a separate ViewMoreCard component
for better separation of concerns and readability.

Updated imports to use named React hooks instead of React namespace. To
modernise this old component per the new guidelines.
2025-08-21 12:53:35 -07:00
Caidan Williams b1ad229771 fix: show 'Follow back' label if user is followed by profile
Updated ProfileCard.FollowButton label to display 'Follow back' when the
current user is followed by the profile being viewed.
2025-08-21 12:29:08 -07:00
Caidan eabcd9150d [APP-1357] profile header follow recommendations (#8784) 2025-08-21 21:56:17 +03:00
Chenyu Huang 962654041c fix linting, minor ui tweaks 2025-08-21 11:49:08 -07:00
pfrazee d900d0b7a7 Nightly source-language update 2025-08-21 02:38:38 +00:00
Chenyu Huang 0474a3b6f7 address feedback 2025-08-20 15:00:06 -07:00
Eric Bailey 16701392b9 [APP-1398] Fix post shadow/like shadow state when replying (#8866)
* Add optimisticReplyCount to post shadow

* Add special util

* Fix subtle bug in query cache
2025-08-20 15:21:52 -05:00
Chenyu Huang f7c05c2df4 use Dialog.InnerFlatlist 2025-08-20 12:31:12 -07:00
cirx ef7c222e1b fix typo (#8869) 2025-08-20 11:11:02 -07:00
surfdude29 9835d0fb7b tweak plural formatting (#8871) 2025-08-20 11:10:34 -07:00
pfrazee bf6e01551e Nightly source-language update 2025-08-20 02:38:26 +00:00
Chenyu Huang 68e0a78f70 loading state 2025-08-19 16:37:49 -07:00
Chenyu Huang e32f280f47 clean up onSuccess callback 2025-08-19 15:59:12 -07:00
Chenyu Huang f42b5831bb parameterize the initial profile for starter pack profile select wizard screen 2025-08-19 15:28:37 -07:00
Eric Bailey ea7f984a40 Fix isPartOfLastBranchFromDepth assignment (#8856) 2025-08-19 11:33:46 -05:00
Ridley Combs 4923786927 [Lightbox] prevent browser-default escape key behavior (#8859)
Some browsers exit fullscreen when the escape key is pressed without `preventDefault()` being called; we don't want that when we're handling the press ourselves.
2025-08-19 06:25:42 -07:00
pfrazee 48baf7277d Nightly source-language update 2025-08-19 02:39:11 +00:00
Eric Bailey 92ad887e38 Add underage notice to Moderation screen (#8868)
* Add underage notice to Moderation screen

* Incorporate suggestion

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2025-08-18 19:24:54 -05:00
Eric Bailey 122a46891a [APP-1318] SelectMediaButton (#8828)
* Integrate Sonner for toasts

* Fix animation on iOS

* Refactor API

* Update e2e file

* [APP-1318] Post composer: combine image & video buttons  (#8710)

* add: select media btn

* udpate: compose post with combined image and video support

* add: video combine button with edge cases

* add select media btn

* test: select media btn

* add: media button update

* remove unused files and update toast on android

* update: make strings shorter

* add: ValidatedVideoAsset type

* update link comments and add toast support for native and web

* rebase latest toast and update toast structure

* remove unused prop

* fix types

* undo changes to yarn.lock

* remove: support for mkv files

* update: eslint and prettier

(cherry picked from commit f69779ee130f07e1c49219b53117e3bdd1a9f81b)

* Add missing props to launchImageLibraryAsync

(cherry picked from commit 2e80ae561fd66850f787cac0aae0fa5a6980f8f5)

* Rough out new approach

(cherry picked from commit 9add225160e7e407befc73e9cdd9743a30cdf1cd)

* Comments and cleanup

(cherry picked from commit e69bd186e7335372f440c446ae6643ed0fb15db9)

* Handle native case

(cherry picked from commit 74e38acdfd9181d0557426691fcbcbf0800481ca)

* Refactor

(cherry picked from commit 68aea496db8df54dba5f58da267ad962c28ef995)

* Rename

(cherry picked from commit 8609e59ad14219e7378ee6cb9514d633ce7efc27)

* Cleanup, comments

(cherry picked from commit 6c9c98648e37257285a9c8caeb1eadcc56c81402)

* Rename

(cherry picked from commit 66e3db539d5baa41436c9e49af06e87a78e9e7e1)

* Handle selectionLimit on Android

(cherry picked from commit 251f06dd5e65a7083b810bad3d81114b2fe9ab39)

* create composer images in parallel

(cherry picked from commit 70ea79d9d76d99e9c99a7d2296caed84c718650e)

* Update toast API usage

(cherry picked from commit e370018b8ed8cdfd7675c9634058c72cb59d39de)

* Ensure once one type of media is selected, you can only select more of that type

(cherry picked from commit 1a9e6e0cdb5234667f08e3dd9107ae598941fc23)

* Remove TODO and debug code

* Add more descriptive a11y label to button

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Add back post success toast

* Include mimeType in toast error

* Remove unneeded toast

* Clarify hint

* Typo

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* allow gifs on native, just treat as images

* disable haptic toast

* allow gifs on native, treat as videos

* only do keyboard dismiss on native

* tweak pasting logic

* hide web scrubber in certain situations

* Update MaxImages translation

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Add plural formatting to a11y hint translation

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* fix suggestion

* Protect against no valid assets selected

* Handle conversion of too-big assets on web

* Reorder

* Bump expo-image-picker to include bug/perf improvements

See https://github.com/expo/expo/blob/main/packages/expo-image-picker/CHANGELOG.md#1700--2025-08-13

* Handle edge case validations

* Ok actually bump expo-image-picker

* Comment

* HEIC support Android

* Fix handling for new picker version, improve size validation

* Remove getVideoMetadata handling, no longer needed

* Handle web video duration

* Update src/view/com/composer/SelectMediaButton.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

---------

Co-authored-by: Anastasiya Uraleva <anastasiyauraleva@gmail.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-08-18 18:28:01 -05:00
Chenyu Huang 7182cd3d5e starter pack dialog flow from profileMenu 2025-08-16 19:45:43 -07:00
pfrazee cced762a7f Nightly source-language update 2025-08-16 02:39:35 +00:00
Samuel Newman 314c380fc4 don't override backspace if alt or meta key (#8855) 2025-08-15 21:41:44 +03:00
Samuel Newman f2892779da Use medium font weight in a few places (#8848)
* medium font toasts

* medium font tabs

* medium font trending pill
2025-08-15 08:33:23 -07:00
Elijah Seed-Arita 5ca665467e feat: use OP's language as recommendation when replying (#8832)
* feat: use OP's language as recommendation when replying

* fix: address nits
2025-08-15 06:16:13 -07:00
pfrazee 4e0be91cff Nightly source-language update 2025-08-15 02:43:46 +00:00
Samuel Newman a761a2e260 Update Xcode in runner to 16.4 (#8842) 2025-08-14 23:21:42 +03:00
Bartosz Kaszubowski 9440068b69 Profile back button tweaks for web (#8795)
* Profile back button tweaks

* apply review feedback - remove StyleSheet

* Update src/screens/Profile/Header/Shell.tsx

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-08-14 10:54:27 -07:00
Eric Bailey 7b2e61bf4d Integrate Sonner for toasts (#8839)
* Integrate Sonner for toasts

* Fix animation on iOS

* Refactor API

* Update e2e file
2025-08-14 09:51:40 -05:00
Samuel Newman 221623f55a Improve "replied to a post" component (#8602)
* unify component

* change bottom padding from 2px to 4px
2025-08-14 03:14:18 -07:00
pfrazee f4dca5d230 Nightly source-language update 2025-08-14 02:42:45 +00:00
Eric Bailey 80ce71283b Bump version to 1.107.0 (#8840) 2025-08-13 17:42:11 -05:00
Samuel Newman 7a334362ae [Perf - part 1] Hoist service config query (#8812) 2025-08-14 01:13:51 +03:00
Samuel Newman b2c56cbd6d Add displayName to contexts (#8814) 2025-08-14 01:12:31 +03:00
Samuel Newman 275fece3e3 [Perf - part 3] Stop every dialog control in the entire app rerendering when opening a dialog (#8815) 2025-08-14 01:11:44 +03:00
Samuel Newman eef639ea54 Preconnect to go.bsky.app (#8825)
* preconnect to go.bsky.app

* other location why not
2025-08-13 17:00:27 -05:00
Samuel Newman 36b2a87a06 Skip intl:compile if not needed (#8837)
* skip intl compile if not needed

* add intl:compile to pull request ci

* compile -> build just to match others
2025-08-13 16:58:42 -05:00
Samuel Newman f001af2fe3 stop incorrectly using suffixtext (#8352) 2025-08-14 00:39:22 +03:00
Samuel Newman d5cc19f282 run lint-native:fix (#8836) 2025-08-13 22:15:08 +03:00
Samuel Newman edd205483d Fix chat button placeholder size on profile (#8827) 2025-08-13 17:20:23 +03:00
Elijah Seed-Arita 485f7ee95b fix: don't open user profile when clicking edit button in user list (#8831) 2025-08-13 01:52:21 -07:00
Arturo Fonseca bfcdb83536 Fix deletion of composed emojis in web composer (#8829) 2025-08-13 01:20:00 -07:00
pfrazee 6cd7dc0f9a Nightly source-language update 2025-08-13 02:42:56 +00:00
Samuel Newman 338fa4dfbe remove imports from @atproto/api internals (#8403) 2025-08-12 08:52:34 -07:00
Samuel Newman bf869d9185 remove unicode ltr chars and replace with css (#8826) 2025-08-12 05:59:03 -07:00
Eric Bailey 683d7bf5a7 Translations (#8823)
* Extract en

* Pull and extract

* Pull and extract
2025-08-11 20:54:31 -05:00
Eric Bailey 44cdf32c1f Update dates (#8822) 2025-08-11 19:01:01 -05:00
Samuel Newman 86b53e7bcc set maxwidth on feed context string (#8817) 2025-08-11 18:57:32 -05:00
Samuel Newman 3ce14b0c6f filter out muted/blocked convos from share menu (#8802) 2025-08-11 18:56:46 -05:00
Samuel Newman 9dfddd3c42 add bottom border to feed headers in explore on web (#8801) 2025-08-11 18:54:28 -05:00
Samuel Newman ef171e2892 Tweak small buttons (#8818)
* set size=small buttons to `text_sm`

* change to `leading_snug`

* add gap to repost buttons

* Add medium-weight font, use for buttons (#8819)

* add medium weight inter

* add medium font to buttons

* Adjust bold weights

* Fix ref

---------

Co-authored-by: Eric Bailey <git@esb.lol>

* Align with designs

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-08-11 18:04:45 -05:00
Samuel Newman 17c5cec356 make sure admonition text doesn't touch button (#8816) 2025-08-11 18:01:32 -05:00
surfdude29 f873f3b301 Add context and comments to button text, label and title in email verification dialog (#8810)
* add context and comment for translators to button text in email verification dialog

* shorten comment

* add comment for other string

* tweak comment

* tweak again
2025-08-11 18:01:10 -05:00
Eric Bailey a3bb8cca6e Fix policy state (#8821)
* Mark completedForDevice prior to creating an account

* Mark policies as completed after initial create account step
2025-08-11 15:51:08 -05:00
Samuel Newman bb949e4f44 Fix translations on Android using PROCESS_TEXT intent (#8486)
* use intents to translate text on android

* clean up config plugins

* restore day night plugin

just to be safe

* leave a comment for why we can't open translate directly

* add todo

* fix lockfile lint
2025-08-11 08:37:39 -07:00
pfrazee 2a6172cbaf Nightly source-language update 2025-08-10 02:54:10 +00:00
jim 4d1a03b99e Merge pull request #8766 from internet-development/binaryfiddler/starter-pack
Update starter pack wizard screen
2025-08-09 00:31:09 -07:00
Chenyu Huang 52637472e6 add missing import 2025-08-08 10:15:29 -07:00
Eric Bailey 23a797cfab Captcha fixes (#8803)
* Add env to scripts

* Update var name
2025-08-08 09:57:17 -05:00
Eric Bailey 22a8b63dcf Update links (#8800) 2025-08-07 15:40:12 -07:00
Eric Bailey 2ba2d9e5b5 Pull latest translations (#8799) 2025-08-07 15:24:55 -07:00
Samuel Newman 93c4719a21 Check handle as you type (#8601)
* check handle as you type

* metrics

* add metric types

* fix overflow

* only check reserved handles for bsky.social, fix test

* change validation check name

* tweak input

* move ghosttext component to textfield

* tweak styles to try and match latest

* add suggestions

* improvements, metrics

* share logic between typeahead and next button

* Apply suggestions from code review

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* update checks, disable button if unavailable

* convert to lowercase

* fix bug with checkHandleAvailability

* add gate

* move files around to make clearer

* fix bad import

* Fix flashing next button

* Enable for TF

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Hailey <me@haileyok.com>
Co-authored-by: Eric Bailey <git@esb.lol>
2025-08-07 17:01:01 -05:00
Bartosz Kaszubowski f708e88410 Add cursor pointer to web select trigger (#8787) 2025-08-07 16:46:35 -05:00
Eric Bailey 88856b0ff7 Fix disabled primary button text color (#8796) 2025-08-07 16:44:19 -05:00
Eric Bailey 08a8324290 Fix e2e (#8794)
* Only enable policy update overlay once the actual Overlay mounts (after onboarding and all that)

* Disable policy overlay in e2e

* Add comments

* Add extra insurance

* Rm log

* Fix shared prefs test

* Fix login flows by optionally closing 'Remember password' system dialog

* Return missing testID

* Bump dev-env
2025-08-07 13:11:16 -07:00
Eric Bailey 11c9931fd2 Fix policy overlay logic (#8793)
* Only enable policy update overlay once the actual Overlay mounts (after onboarding and all that)

* Disable policy overlay in e2e

* Add comments

* Add extra insurance

* Rm log
2025-08-07 14:55:19 -05:00
hailey c0593e4979 Add device attestation to signup flow (#8757) 2025-08-07 12:33:38 -07:00
Samuel Newman 39e775a376 add border curve in neater way (#8792) 2025-08-07 11:30:49 -05:00
Bartosz Kaszubowski d84d54bae3 Fix web scrollable select unwanted overflow (#8786) 2025-08-07 09:23:01 -07:00
Samuel Newman 0a2b1fcfb8 add profile hover card to notif items (#8666) 2025-08-07 09:15:49 -07:00
Eric Bailey cb54082eda [APP-1310] Button refresh (#8758)
* Rm gradient buttons from Storybook

* TEMP move storybook button section

* Remove gradient_sky

* Remove actual defs for gradient_sky and gradient_primary

* Remove other gradient defs

* Remove gradient support entirely

* Deprecate 'variant' in favor of 'color'

* Fork base styles codepath to make variant deprecation more obvious

* Remove text styles for when no color is set, never been used

* Fork text styles codepath to make variant deprecation more obvious

* Revert temp storybook commit, remove deprecated values

* Replace remaining gradient button usage

* Update Buttons storybook section

* Update tiny styles

* Update small styles

* Update large sizes

* Ensure proper alignment of buttons in storybook

* Update button colors

* Rename negative_secondary to negative_subtle

* Remove unnecessary select()

* Update icon size and gap

* Update negative_subtle styles

* Custom button colors

* Add borderCurve
2025-08-07 11:08:31 -05:00
Samuel Newman 20ac2e2733 Only parse notifs with a reason (#8785)
* only parse notifs with a reason

* move error log to a warn, make it actually fire
2025-08-07 09:07:43 -07:00
Eric Bailey c103687d66 Toast tweaks (#8791)
* Tweak colors

* Fix e2e

* Color tweaks

* Fix alignment
2025-08-07 08:45:35 -05:00
pfrazee dbb9ff6918 Nightly source-language update 2025-08-07 02:52:42 +00:00
Anastasiya Uraleva 909ddc86e1 [APP-1365]: Ensure toast text meets a11y guidelines (#8779)
* update: toast colors for accessibility

* update: toast color codes from figma

* condense the colors to remove select calls that are unecessary

* remove unused select
2025-08-06 16:27:44 -05:00
Eric Bailey 75094f4860 [LEG-203] Add onboarding text for policy updates (#8783)
* Add onboarding text for policy updates

* Add gate, add to other case

* Update other UI cases to use Admonitions

* Th

* Update date
2025-08-06 15:16:08 -05:00
Eric Bailey 328aa2be94 [APP-1356] Policy update dialog (#8782)
* Add blocking announcement dialog feature

* WIP custom dialog

* Rework dialog and add native FocusScope

* Lock scroll on web, fix backdrop

* Add web FocusScope

* Create custom Outlet for these announcements

* Clean up FocusScope native impl

* Comments

* Some styling fixes

* Handle screen reader specifically

* Clean up state, remove Portal edits

* Reorg, rename

* Add syncing, tests

* Revert dialog updates

* Revert formatting

* Delete unused file

* Format

* Add FullWindowOverlay

* remove mmkv storage in debug btn

* Add debug code

* fix taps passing through on iOS

* Reorg

* Reorg, rename everything

* Complete policy update after signup

* Add logger

* Move context around, unmount portals on native

* Move a11y prop into FocusScope

* Remove useMemo

* Update dates

* Move debug to dev settings

* Unmount web portals until policy update completed

* UPdate dates

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-08-06 15:15:52 -05:00
Chenyu 9153474e59 Update src/screens/StarterPack/Wizard/index.tsx
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-08-06 11:41:28 -07:00
Chenyu Huang 4c8b30df19 left align header content 2025-08-06 11:24:04 -07:00
Arturo Fonseca fd37d92f85 Fix quality of first seconds of videos on web (#8761) (#8778) 2025-08-05 02:04:32 -07:00
pfrazee 53cf0b3b46 Nightly source-language update 2025-08-05 02:53:53 +00:00
Samuel Newman a5437ebbeb Fix web video ViewportObserver component (#8776)
* Revert "[APP-1083] bug fix: videos not accurately autoplaying on web (#8692)"

This reverts commit 9aa35e9fbb.

* fix overflow hidden breaking the video viewport observer
2025-08-04 10:24:53 -07:00
Samuel Newman 15bc77321b Fix android starting at notif screen (#8775)
* fix android launching at notif screen

* rm heuristic
2025-08-04 09:41:09 -07:00
Samuel Newman 7b5d11eb80 Fix video thumbnails on native (#8774) 2025-08-04 18:42:55 +03:00
kindgracekind b32568260f Add feed tuner to remove muted threads (#8773) 2025-08-04 10:27:27 -05:00
Anastasiya Uraleva 9aa35e9fbb [APP-1083] bug fix: videos not accurately autoplaying on web (#8692)
* update: auto play video on web with intersection position

* place back the threshold: 0.5

* update: optimize the intersection observer with a throttled scroll listener

---------

Co-authored-by: Anastasiya <anastasiya@Mac.localdomain>
Co-authored-by: Anastasiya <anastasiya@Anastasiyas-MacBook-Pro.local>
2025-08-04 06:17:50 -07:00
surfdude29 14e39c4aec Tweak accessibility label (#8767)
* tweak accessibility label

* change `alert` to `message` and add comment instead of context

* tweak comment
2025-08-04 03:49:35 -07:00
Chenyu Huang 73ce358052 update starter pack wizard layout 2025-08-01 11:32:14 -07:00
pfrazee 598641742e Nightly source-language update 2025-08-01 02:58:13 +00:00
jim f21478735c Merge pull request #8762 from JimmyCushnie/updates-readme-like-a-boss
Minor README improvements
2025-07-31 19:46:17 -07:00
jim 9eba567135 Merge pull request #8763 from internet-development/caidan/app-1364-fix-suggested-follows-small-web-view 2025-07-31 14:28:00 -07:00
Caidan Williams 79f365b21c fix(ui): small bug where on small web views the final card was not full height 2025-07-31 11:51:11 -07:00
Caidan Williams 8b344ca9fd fix(ui): adjust padding for ProfileGrid layout consistency
Fixes the issue of the shadow being cutoff by the overflow, now will
give proper spacing to the cards to display the shadow.
2025-07-31 11:51:11 -07:00
Jimmy Cushnie 648dda7541 README: fix verb form of CC
While both forms are used, CC'd is much more common and generally considered the correct form.
2025-07-31 13:59:29 -04:00
Jimmy Cushnie bf455f3e19 README: fix brand capitalization ("Github" -> "GitHub") 2025-07-31 13:55:13 -04:00
Jimmy Cushnie 91574f1f56 README: improve phrasing of packages mention 2025-07-31 13:52:49 -04:00
Jimmy Cushnie 3949747197 README: Use alert for the contributions note 2025-07-31 13:48:40 -04:00
Samuel Newman f4724e378d Don't animate images that will be posted as JPGs (#8760)
* don't play gifs that'll be png'd

* add media inset border

* fix unnecessary typecast

* Revert "fix unnecessary typecast"

This reverts commit 3a8bcc9277.
2025-07-31 09:47:22 -07:00
Eric Bailey e87555c481 [APP-1310] Button cleanup (#8754)
* Rm gradient buttons from Storybook

* TEMP move storybook button section

* Remove gradient_sky

* Remove actual defs for gradient_sky and gradient_primary

* Remove other gradient defs

* Remove gradient support entirely

* Deprecate 'variant' in favor of 'color'

* Fork base styles codepath to make variant deprecation more obvious

* Remove text styles for when no color is set, never been used

* Fork text styles codepath to make variant deprecation more obvious

* Revert temp storybook commit, remove deprecated values

* Replace remaining gradient button usage
2025-07-31 10:32:16 -05:00
Eric Bailey 3bcfcba6d8 Some toasts cleanup and reorg (#8748)
* Reorg

* Move animation into css file

* Update style comment

* Extract core component, use platform-specific wrappers

* Pull out platform specific styles

* Just move styles into Toast component itself

* Rename cleanup

* Update API

* Add duration optional prop

* Add some type docs

* add exp eased slide aniamtions

* Make toasts full width on mobile web

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-07-31 10:15:35 -05:00
surfdude29 33e0714948 tweak case of labels in SearchResults.tsx (#8759) 2025-07-31 06:40:39 -07:00
Eric Bailey b3d207c7b9 Make proper extension of Button more clearly defined (#8753)
* Remove unecessary color prop from SettingsList LinkItem

* Add UninheritableButtonProps to avoid misuse
2025-07-31 05:41:10 -07:00
pfrazee 85981deb31 Nightly source-language update 2025-07-31 02:51:14 +00:00
Jaz 045101286f Merge pull request #8755 from bluesky-social/echoprom_fix
fix echoprom config
2025-07-30 15:15:01 -07:00
Jaz Volpert b25677eb7f build 2025-07-30 21:42:56 +00:00
Jaz Volpert 4393a275ae fix echoprom config 2025-07-30 21:42:26 +00:00
Eric Bailey 3ff42f1595 Fix bad substitution (#8752) 2025-07-30 13:56:27 -05:00
Jaz 3dc6dcd9b9 Merge pull request #8749 from bluesky-social/go-124
Update golang toolchain to 1.24 and clean imports
2025-07-30 11:07:35 -07:00
Samuel Newman 25e60548c4 Mark old components as deprecated (#8747)
* mark a bunch of stuff as deprecated

* mark s as deprecated (serverence reference????)

* rm type import
2025-07-30 11:05:45 -07:00
hailey fade51e9eb Rework variable naming, logic for rendering chat requests (#8737) 2025-07-30 11:00:14 -07:00
Jaz Volpert 324ebdf2cb Cleanup workflows 2025-07-30 17:57:56 +00:00
Jaz Volpert ef167eaca0 build 2025-07-30 17:41:18 +00:00
Jaz Volpert 13499de325 Merge branch 'main' into go-124 2025-07-30 17:40:42 +00:00
Eric Bailey d4b23d3ab4 [APP-1173] Clean up env (#8701)
* Clean up env files

* Use new env in Sentry setup file

* Use new env in Bitdrift setup file

* Use new env in chat proxy header

* Prefix Bitdrift key with EXPO_PUBLIC

* Deprecate SENTRY_RELEASE since we use package.json now

* Use existing EXPO_PUBLIC_BUNDLE_IDENTIFIER short commit has as Sentry dist value

* Fix missing bundle identifier for Render deploys

* Deprecate SENTRY_DIST in favor of EXPO_PUBLIC_BUNDLE_IDENTIFIER

* Prefix SENTRY_DSN with EXPO_PUBLIC to match others

* Remove debugging field

* Replace NODE_ENV in places where its safe

* Self review

* Properly patch Sentry package

* Echo variables to .env in Dockerfile instead of passing to shell script

* Make sure EXPO_PUBLIC_ENV is set for web container builds

* Update IS_TESTFLIGHT to include testflight-android

* Slice bundle hash to match other platforms, needed for render.com deployments

* [APP-1331] Migrate `app-info` to new env (#8703)

* Move env files into directory with platform specific files

* Migrate usages of app-info to new env

* Fix bad import

* Update BUNDLE_DATE format comment

* Trim RENDER_GIT_COMMIT to first 7 to match --short sha

* Clarify build process env vars and ensure they are explicitly passed in

* Revert Sentry patch as a result of prev commit

* Update webpack Sentry dist value based on prev commits

* Add PACKAGE_VERSION and replace in statsig to fix conflict

* Fix render substitution syntax

* Remove invalid syntax

* Remove unnecessary testflight check

* Just use long commit hash

* Slice full hash for display in app

* Fix missing space in ios workflow

* Pass in sentry CLI env vars, align matching values

* Align on RELEASE_VERSION

* Add new env setup to missed OTA spot

* Update webpack to use same SENTRY_RELEASE var

* Just fallback to package version for Render deploys

* Remove TF check for BUNDLE_DATE

* Set EXPO_PUBLIC_ENV for bundle update

* Consistent naming "Env"

* Add comment

* Use RELEASE_VERSION instead of package.json

* Update PR comment CI
2025-07-30 12:33:40 -05:00
Austin McKinley 2d23d821d3 Update golang toolchain to 1.24 and clean imports 2025-07-30 10:28:03 -07:00
Samuel Newman db7bdae51a Convert old toast types to new ones, mark as deprecated (#8746)
* convert old types to new types

* add depreciation warning for old warnings

* rm as consts
2025-07-30 08:18:36 -07:00
Samuel Newman ee7f508717 Fix dataSet for noFeedback links (#8745)
* fix dataSet for noFeedback links

* rm memo

* rm useless spread
2025-07-30 08:17:57 -07:00
jim 7caf2922dd Merge pull request #8744 from internet-development/@APiligrim/update-toast
hot fix: imports for toast and alignment
2025-07-30 01:17:59 -07:00
Ana 18add1cff9 update type errors 2025-07-30 01:08:14 -07:00
Ana d141921abf add: prettier formating 2025-07-30 00:48:56 -07:00
Ana 315e7341bf update: lint fixes for toast.tsx 2025-07-30 00:40:34 -07:00
Ana f8781270e5 update: toast style after lint 2025-07-30 00:36:14 -07:00
Ana f472c7f540 update sorting 2025-07-30 00:25:17 -07:00
Ana 67ba92fa62 update: imports for toast 2025-07-30 00:02:03 -07:00
jim c2b8bdb33c Merge pull request #8743 from internet-development/@APiligrim/update-toast
[APP-1345] Hot fix: add toast.style file
2025-07-29 23:35:38 -07:00
Ana 61969e8dfa add: Toast.style 2025-07-29 23:28:10 -07:00
jim 658dd448d5 Merge pull request #8734 from internet-development/@APiligrim/update-toast
[APP-1345] Update Toast UI on the web and add to storybook
2025-07-29 22:51:16 -07:00
Ana 34ea6e8f34 update: toast styles that reuse consistent style 2025-07-29 22:12:36 -07:00
pfrazee 0a00e02c70 Nightly source-language update 2025-07-30 02:51:39 +00:00
Jaz 15c9835f1d Merge pull request #8740 from bluesky-social/embedr-metrics
Add metrics to embedr service
2025-07-29 18:05:15 -07:00
Austin McKinley 27c51401d2 git tidy 2025-07-29 17:54:11 -07:00
Austin McKinley 2b92697e3e switch to using DefaultServeMux, include go.mod and go.sum changes 2025-07-29 17:51:55 -07:00
jim c31b0338a1 Merge pull request #8733 from internet-development/caidan/app-1330-new-design-for-suggested-for-you-interstitial
feat: new design for "Suggested for you" interstitial
2025-07-29 17:42:30 -07:00
Caidan Williams 940e00c8cb feat(ui): add "See More Suggested Profiles" card 2025-07-29 17:37:01 -07:00
Caidan Williams 7b4ec21e3e refactor(ui): adjust border styles in ProfileGrid card 2025-07-29 17:37:01 -07:00
Caidan Williams e5457c946a feat(ui): improve suggested follow placeholder card
Now matches the same size and shape as the rendered card, which prevents
content layout shift.
2025-07-29 17:37:01 -07:00
Caidan Williams d83480cc64 refactor(ui): remove "Browse more accounts" card on mobile view 2025-07-29 17:37:01 -07:00
Caidan Williams 8dc074c477 fix(ui): profile name and description overflowing on web 2025-07-29 17:37:01 -07:00
Caidan Williams da47cd0d1b fix(ui): placeholder web size and flex grow 2025-07-29 17:37:01 -07:00
Caidan Williams ab5be5cb3f refactor(feed): wrap placeholder description placeholder in full-width view 2025-07-29 17:37:01 -07:00
Caidan Williams 22db8ed639 feat(feed): update suggested profiles link text 2025-07-29 17:37:01 -07:00
Caidan Williams 4c8d5db6a6 refactor(ui): web profile cards maxLength 4 -> 3 with flex grow 2025-07-29 17:37:01 -07:00
Caidan Williams b2fe27afe7 refactor(ui): remove "Browse more suggestions" on web in favor of "See all" 2025-07-29 17:37:01 -07:00
Caidan Williams f35dc19a48 feat(ui): update SuggestedFollowPlaceholder to match new design 2025-07-29 17:37:01 -07:00
Caidan Williams 4e507caa7c feat: update AvatarPlaceholder to take size prop 2025-07-29 17:37:01 -07:00
Caidan Williams 87f2bc5be3 feat: create NamePlaceholder component 2025-07-29 17:37:01 -07:00
Caidan Williams f58ad8e419 refactor: replace magic 6px with dynamic a.gap_md/2 2025-07-29 17:37:01 -07:00
Caidan Williams 2bf4ee5690 fix(ui): suggested profile card grid on web sm -> md 2025-07-29 17:37:01 -07:00
Caidan Williams 48f670f26a fix(ui): follow button should always be pushed to the bottom on the profile card 2025-07-29 17:37:01 -07:00
Caidan Williams 955a864245 refactor: update MOBILE_CARD_WIDTH instead of using inline width 2025-07-29 17:37:01 -07:00
Caidan Williams 0598d73617 refactor(ui): follow button and description to match design 2025-07-29 17:37:01 -07:00
Caidan Williams f478ebdeb5 refactor(ui): swap ProfileCard.NameAndHandle for ProfileCard.Name 2025-07-29 17:37:01 -07:00
Caidan Williams 205e7f0190 feat(ui): update ProfileCard.Avatar size 40 -> 88 2025-07-29 17:37:01 -07:00
Caidan Williams 3c89552e92 refactor(ui): replace ProfileCard.Header with custom View 2025-07-29 17:37:01 -07:00
Caidan Williams c93c36f6e5 feat(ui): force width on suggested profile card 2025-07-29 17:37:01 -07:00
Caidan Williams c6e7816fa7 feat(ui): update padding, border radius, and border on suggested profile card 2025-07-29 17:37:01 -07:00
Caidan Williams ff4eecc2e4 feat: update ProfileCard.Description to take style prop 2025-07-29 17:37:01 -07:00
Caidan Williams 2a6d04e6e2 feat: update ProfileCard.Avatar to take size prop 2025-07-29 17:37:01 -07:00
Caidan Williams e465c9e461 feat(ui): add dropshadow to suggested profile card 2025-07-29 17:37:01 -07:00
Caidan Williams b8a257a1c7 feat(ui): replace suggested profiles interstital icon with link "See all" 2025-07-29 17:37:01 -07:00
Caidan Williams 92e0119734 feat(ui): updated suggested profiles interstitial "Suggested for you" text color 2025-07-29 17:37:01 -07:00
Caidan Williams 287f5c0d42 feat(ui): update suggested profiles interstitial top padding 16 -> 12 2025-07-29 17:37:00 -07:00
Austin McKinley ea226da275 add metrics to embedr service 2025-07-29 17:36:58 -07:00
Elijah Seed-Arita 332dbc1bb4 fix: small profile followup fixes (#8735)
* fix: small profile followup fixes

* fix: change platform-specific compensation for profileHeaderDisplayName marginBottom to target all native

* fix: apply suggestion for consistent cross-platform profile username margin
2025-07-29 16:20:33 -05:00
Eric Bailey bc78fb224e Add comment (#8739) 2025-07-29 15:14:12 -05:00
Ana 890dee3eef update: web toast 2025-07-28 22:07:28 -07:00
Ana c13b1374d7 add: toasts to storybook 2025-07-28 20:24:57 -07:00
Eric Bailey 1504ce28e2 Fix parent read more occurring further up the tree (#8729) 2025-07-28 14:21:01 -05:00
Eric Bailey 6d0c859d8f Fix blur handling (#8730) 2025-07-28 14:20:55 -05:00
hailey 41998c59b5 Ensure preference overrides cause re-renders (#8724)
* make sure request is fetched before returning true

* Ensure preferences object skips equality checks if overridden

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-07-28 12:28:12 -05:00
pfrazee 872fe324a0 Nightly source-language update 2025-07-26 02:44:52 +00:00
hailey 810918b434 add web hook, action tweaks (#8723) 2025-07-25 12:39:43 -07:00
hailey 4d210e33cf fix type error (#8722) 2025-07-25 09:34:04 -07:00
hailey 15abdc67cf simplify logic for pull request OTAs (#8720)
* simplify logic for pull request OTAs

* just render deep link in the text

* dont download update until approved
2025-07-25 08:57:21 -07:00
hailey c6b578fe91 fix final final final (#8719) 2025-07-24 21:07:06 -07:00
pfrazee caeaff157c Nightly source-language update 2025-07-25 02:48:44 +00:00
hailey 5c2867d580 fix (#8718) 2025-07-24 17:48:54 -07:00
hailey 7f3835792e fix action (#8717) 2025-07-24 17:41:43 -07:00
hailey c37ab83823 fix action (#8716) 2025-07-24 17:21:58 -07:00
jim 26755445e3 Merge pull request #8714 from internet-development/c/app-1332-handle-autocomplete-broken-for-handles-with-hyphens
Fix some auto complete issues on mobile
2025-07-24 17:18:40 -07:00
hailey 101b3262b8 fix action (#8715) 2025-07-24 16:31:37 -07:00
hailey 1ee91d2c90 OTA deployments on PR comment action (#8713) 2025-07-24 16:23:17 -07:00
Chenyu Huang ead6862fc6 fix some auto complete issues 2025-07-24 15:58:24 -07:00
Chenyu 9e65f00c93 [APP-1157] disable searches for logged out users, prompt them to sign in (#8697) 2025-07-24 14:44:03 -07:00
jim c48f35d726 Merge pull request #8702 from internet-development/caidan/app-1328-new-trending-video-interstitial
feat(ui): new trending video design
2025-07-24 13:51:05 -07:00
rafael d1dbc4f852 Conditional workflows 2025-07-24 17:29:25 -03:00
rafael fc2fae42bd Add github workflow 2025-07-24 17:07:11 -03:00
Caidan Williams 742397bb1a fix(lint): remove unused import 2025-07-24 12:31:34 -07:00
Caidan Williams 269d70e66c feat(ui): increase the trending videos card size 2025-07-24 12:30:35 -07:00
Caidan Williams 0685de9b7f feat(ui): update TrendingVideos dismiss button style
Changed the TrendingVideos dismiss button to use solid variant and
square shape for improved visibility. Also set ButtonIcon size to "sm"
for better alignment with the new button style.
2025-07-24 12:30:35 -07:00
Caidan Williams c1d2aea885 feat(ui): remove the header icon
Replace the header's flex row with a single bold text element for
"Trending Videos", removing the Graph icon and extra container.
2025-07-24 12:30:35 -07:00
Caidan Williams 229f275246 fix(ui): adjust TrendingVideos padding and gap sizes
Reduced top padding from large to small and updated horizontal padding
handling for the TrendingVideos component. Increased card gap and snap
interval from small to medium.
2025-07-24 12:30:35 -07:00
Caidan Williams 66950a08cb feat(ui): add border to video post and trending cards
Added a border and low contrast border color to CompactVideoPostCard,
CompactVideoPostCardPlaceholder, and TrendingVideos card components for
improved visual separation.
2025-07-24 12:30:35 -07:00
Caidan Williams b89645a172 feat(ui): add shadow to video post trending cards
Added a small shadow (shadow_sm) to the CompactVideoPostCard and the
"View more" card in TrendingVideos for improved visual depth and
consistency. This enhances the card appearance and aligns with the
design system.
2025-07-24 12:30:35 -07:00
Caidan Williams 12e67f53dd fix(ui): overflow for TrendingVideos scroll container
Added overflow_hidden to the main container and set overflow_visible on
the FlatList to ensure proper display of horizontally scrolling cards.
This resolves clipping issues and improves the visual layout of trending
videos.
2025-07-24 12:30:35 -07:00
Caidan Williams ce02e4aa3d feat(atoms): add overflow_visible utility
Added the `overflow_visible` atom to the atoms utility object for
setting CSS overflow to 'visible'. This complements the existing
`overflow_hidden` atom and improves flexibility for layout styling.
2025-07-24 12:30:35 -07:00
Caidan Williams 605c50d6c7 style(ui): use larger border radius on video post card
Updated CompactVideoPostCard to use a larger border radius by replacing
rounded_md with rounded_lg.
2025-07-24 12:30:35 -07:00
Elijah Seed-Arita dff0332dd0 fix: general profile component layout fixes, and ability to disable the inset border for UserAvatar (#8711) 2025-07-24 11:22:19 -07:00
hailey f0b869aeeb fix moderation preferences for non-AA'd users (#8712) 2025-07-24 08:34:31 -07:00
jim 0610c822cf Merge pull request #8708 from internet-development/@APiligrim/chat-request-ui
[APP-1317] update: chat request ui to hide chat requests when there are no messages
2025-07-23 21:46:56 -07:00
Ana a3b188baec update: comment with a name 2025-07-23 20:01:03 -07:00
Eric Bailey 3775aeb146 If birth date is not set, ensure AA still shows (#8709) 2025-07-23 21:01:32 -05:00
Ana 8f1cd86115 update: chat request ui 2025-07-23 16:56:20 -07:00
Elijah Seed-Arita 6a7b8a279b [APP-1291] prevent GestureActionView from hijacking swipe in a direction which no actions are specified (#8705)
Co-authored-by: hailey <hailey@blueskyweb.xyz>
2025-07-23 15:19:48 -07:00
Eric Bailey 3ae3ed245b Clean up AA gate (#8707) 2025-07-23 14:32:19 -05:00
Samuel Newman 8fdcc3ee31 Replace resumeSession with getSession in the email check (#8670)
* replace resumeSession with getSession

* copy lil type tweak from the other PR

* Add partialRefreshSession to session API context, use session state to infer state further down tree

* Review

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-07-23 11:52:38 -05:00
Eric Bailey b4938bc9df Bump version (#8698) 2025-07-23 11:52:06 -05:00
Eric Bailey cf8d8b3bb9 Include app version in metrics (#8699) 2025-07-23 09:31:03 -05:00
pfrazee bbc022c0a6 Nightly source-language update 2025-07-23 02:49:16 +00:00
Caidan bbc39806fe feat(ui): remove like count from trending videos (#8689)
* feat(ui): add showLikeCount flag to CompactVideoPostCard

Introduced a showLikeCount flag to control the display of like count in
the CompactVideoPostCard component. The like count is now only shown if
both likeCount > 0 and showLikeCount are true. This allows for more
flexible UI configurations and easier toggling of like count visibility.

* fix(ui): hide gradient shadow when hiding like count

* fix(ui): increase trending video profile pic size from 20 -> 24

* fix(ui): add small drop shadow to trending video profile pic

* fix(ui): a.shadow_sm -> t.atoms.shadow_sm based on PR feedback
2025-07-22 19:16:07 -05:00
Paul Frazee 9e2b99e860 Release 1.105.0 (#8693)
* Tests fixes

* Pull latest translations
2025-07-21 20:15:29 -07:00
Chenyu fc4bf4e919 add margin between messages in the composer thread (#8691) 2025-07-21 19:49:59 -07:00
pfrazee 2a30a344b5 Nightly source-language update 2025-07-22 02:48:49 +00:00
surfdude29 4a853794dc bskyembed correct hashtag link (#8685) 2025-07-21 20:51:09 -05:00
Eric Bailey 7635a49001 introduce context for "Following" as a feed name. (#8262) (#8690)
"Following" has different translations as a name of a feed and the state of following someone in other languages like Turkish. This allows "Following" as a feed name translated correctly.

(cherry picked from commit d92a7f163ed9e28ee4ebab230758b1f00bdd9966)

Co-authored-by: Sedat Kapanoğlu <sedat@kapanoglu.com>
2025-07-21 20:49:49 -05:00
surfdude29 8ce9bdb27e tweak accessibility label (#8242) 2025-07-21 19:19:41 -05:00
surfdude29 e1a0beff7d add action context for Repost string in RepostButton.web.tsx (#8427) 2025-07-21 18:41:01 -05:00
surfdude29 e5d44923fb tweak app language names (#8436) 2025-07-21 18:40:25 -05:00
surfdude29 6d90d3c2fe remove title casing of Intl.DisplayNames language names (#8433) 2025-07-21 18:35:04 -05:00
Samuel Newman 9ebfbd0e40 Nicer error message for backend video too large error (#8596)
* nicer error message for backend video too large

* use same string for same error
2025-07-21 09:34:58 -05:00
Samuel Newman 74f7a44d71 Patch in upstream fix for video rotation on Android (#8635)
* patch in upstream fix

* build expo-image-picker from source so that patch takes
2025-07-21 09:33:59 -05:00
Samuel Newman 760b184d28 fix emoji popup scroll (#8636) 2025-07-21 09:22:35 -05:00
Samuel Newman 36fba20a01 Follow redirects for soundcloud shortlinks (#8614)
* follow redirects for soundcloud shortlinks

* clear timeout in `finally`
2025-07-21 09:18:33 -05:00
pfrazee ad16ed3096 Nightly source-language update 2025-07-19 02:43:42 +00:00
Eric Bailey 0995e81b58 Age assurance tweaks (#8671)
* Refetch state while in pending status

* Add success state to redirect, just have user close, nicer experience

* Stop refetching after pending
2025-07-18 14:21:23 -05:00
Eric Bailey 6a15679fb1 Handle missed error branch (#8663) 2025-07-18 10:19:56 -05:00
Eric Bailey 4dd9459cba Update copy (#8664) 2025-07-18 10:09:59 -05:00
Jordan Harband 95ab4fa0a1 show precise count in label/hover text (#6164) 2025-07-17 22:11:34 -07:00
Sedat Kapanoğlu cfaf741647 rename file names with colons to the common notation (#8264)
The colons in file names break Windows compatibility and prevent Bluesky from being developed on Windows. (Regression: Bluesky Git repository always shows missing files on Windows #8263)
2025-07-17 21:59:23 -07:00
pfrazee f4909e5e05 Nightly source-language update 2025-07-18 02:49:23 +00:00
Samuel Newman 08a1a806ef Fix checkmark overflow in profile card (#8612) 2025-07-17 23:03:55 +03:00
Eric Bailey 964eed54ea Age assurance fast-follows (#8656)
* Add feed banner

* Comment

* Update nux name

* Handle did error

* Hide mod settings if underage or age restricted

* Add metrics

* Remove DEV override

* Copy suggestion

* Small copy edits

* useState

* Fix bug

* Update src/components/ageAssurance/useAgeAssuranceCopy.ts

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Get rid of debug button

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2025-07-17 14:32:58 -05:00
Eric Bailey 00b017804b Fix bug where replying to grandparents re-orders thread (#8662)
* Fix bug where optimistic replies were inserted above the root post

* Rename variables for clarity
2025-07-17 13:22:09 -05:00
Samuel Newman d13a2e5f69 use push to convo mechanism (#8653) 2025-07-17 21:18:32 +03:00
Samuel Newman 2c0c9bf803 avoid handling notifs if deep link (#8657) 2025-07-17 21:18:16 +03:00
Samuel Newman 2e16ef4384 fix whitespace collapse (#8659) 2025-07-17 21:17:57 +03:00
Eric Bailey 42bfee5d9d Update copy and link in reporting flow (#8583)
* Update copy and link

* fix prettier

* Update link

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-07-17 11:01:10 -05:00
pfrazee 94a3e5bbe1 Nightly source-language update 2025-07-17 02:47:36 +00:00
Eric Bailey 1dbc331314 UI for age assurance compliance (#8652)
* Add geo prop

* Add prelim fetch

* Add geo debug

* Pass in assurance state to notifications registration

* Comments

* Bump git index

* Add some component utils, no design, gate chat

* Disable mod prefs buttons, does not yet edit mod prefs

* Add initial prompt component

* Refine logic for showing prompt

* Add send email dialog

* Hook up dialog to fake mutation

* Fix geo debug bug

* Move provider inside query provider

* Slightly better screen gater

* Ok decent fallback with isExempt

* Reorg

* Wrap prompt in new logic

* Override mod prefs

* Use real endpoints, optimistic state

* Add persistent card, add time-ago, warning to dialog

* Add comment

* No undefined query values

* Fix case in import

* Wait for AA to load before registering push

* Override prefs in all locations

* Small refactor of notifications registration

* Register push after aa state

* Add retries

* Update blocked screens UI

* Strengthen email validation

* Add intent dialog

* Do service auth for init

* Rug refreshJwt

* Update copy

* Some mobile styles, add dev mode option

* Fix links on native

* Clean up intent dialog on native

* Don't mutate existing session, only copy

* Handle email validation error from server

* Clarity is better

* Moar clear

* Fixes

* Tweaks

* Add country code

* Gate it

* Refresh state after redirect

* Re-check on window focus

* Remove todo

* Enable in dev

* Check for did match on redirect

* Add blocked state

* Add appeal dialog

* Copy tweaks

* Inset in blue well

* Nux the prompt

* Copy updates

* Refetch just in case

* Uppercase country code

* Align copy, add notice to chat screens

* Tweak copy

* Add test code

* Add debug code

* Refactor AccountCard

* Big refactor

* Delay post-feed queries instead

* Debug code

* Clean up state

* Reorg

* Clean up copy

* Comments

* Reorg

* UPdate URL

* Cleanup

* Remove todo

* Update debug code

* revert unneeded changes

* UPdate nux name

* Revert unneeded change

* Updaet storage schema

* Checkpoint: cleanup

* Checkpoint: almost there

* isLoaded -> isReady

* Rename useAgeAssurance

* isUnderage -> isDeclaredUnderage

* Decompose, add docblocks

* Refactor

* UPdate debug

* Apply suggestion from @surfdude29

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Apply suggestion from @surfdude29

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Apply suggestion from @surfdude29

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Apply suggestion from @surfdude29

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Apply suggestion from @surfdude29

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Apply suggestion from @surfdude29

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Drop including Bluesky

* Apply suggestion from @surfdude29

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Apply suggestion from @surfdude29

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Remove todo

* Gate debug

* Revert unneeded change

* Fail closed

* Comments

* Comment

* Comment

* fix prettier

* rm viewheader

* bump sdk

* prevent overlap in admonition

* add age assurance intent route

* Just meow

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

* Nix callback

* Fix spelling of dismissible lol

* Don't compare translated string

* Better KWS link labels

* Hide DMs send options in menu

* Add button

* Fix order

* Use only supported languages

* Rm button

* best-effort language mapping

* improve typing

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-07-16 13:58:07 -05:00
pfrazee 712c3ad421 Nightly source-language update 2025-07-16 02:47:16 +00:00
Samuel Newman 60c0689236 Fix navigation (#8648) 2025-07-15 15:53:52 +03:00
Samuel Newman 4ccbae7c30 Fix perf issue on web - restore pop behaviour to tabs (#8620) 2025-07-15 07:48:24 +03:00
pfrazee 1f82b1d557 Nightly source-language update 2025-07-15 02:49:31 +00:00
Jim Calabro c9c91fb113 omitempty on aa (#8647) 2025-07-14 16:22:41 -05:00
Jim Calabro 6375c54aa4 Merge pull request #8646 from bluesky-social/jc/aa
Fix Age Restriction Type
2025-07-14 16:24:53 -04:00
jcalabro 1da123b12b Fix Age Restriction Type 2025-07-14 16:21:06 -04:00
Samuel Newman b76f95c9bd bump version to v1.105 (#8616) 2025-07-14 10:03:28 -07:00
Samuel Newman 587c14bac8 fix who can reply icon (#8625) 2025-07-14 10:01:48 -07:00
Eric Bailey be75e00d21 Only show WhoCanReply on root post (#8645) 2025-07-14 11:37:23 -05:00
pfrazee 27d6de0b18 Nightly source-language update 2025-07-13 02:52:39 +00:00
Samuel Newman ff57e75b12 fix mention tab flicker (#8640) 2025-07-12 20:50:04 +03:00
Samuel Newman 0e3124a97e Filter activity notifs for muted words (#8637) 2025-07-11 08:49:59 -07:00
pfrazee 8f5a8f37af Nightly source-language update 2025-07-11 02:46:37 +00:00
Jim Calabro 3b329430ac Merge pull request #8634 from bluesky-social/jc/aaip
Detect Age Restricted Geos
2025-07-10 19:53:57 -04:00
Samuel Newman 377d80e21d Handle notifications on first load (#8629)
* add getInitialURL

* get deep linking working

* actually handle as push instead

* push to route instead of setting initial path

* pop to on top of notifications

* fix comment

* change chat-message handling

* add metrics

* don't reopen due to notif multiple times

* extract data from notification differently on android

* sorry sorry annoying naming nits, align logger

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-07-10 16:36:53 -05:00
jcalabro c2a5b3efa8 Detect Age Restricted Geos 2025-07-10 12:41:15 -04:00
pfrazee 22bda086d0 Nightly source-language update 2025-07-10 02:44:40 +00:00
Samuel Newman 07b028ee66 Fix quote+list card padding (#8623)
* fix quote padding not being pressable

* fix list padding not being pressable

* Fix unnecessary loading of feeds (#8578)

* stop layout shifts in feed loading

* don't load feed data if we already have it

* adjust styles, alf stuff

* remove unused button, massively simplify

* fix layout shifting in notifs

* use feedcard for feed post embeds

* use bold text to match other style

* use Link component rather than jank Pressable

* prevent nested anchors in notifs

* match following text size

* add space between content hider

* Better dead feed handling (#8579)

* add space between content hider

* add handling for feeds that fail to load

* cleanError, in case of network funkiness

* handle deleted lists

* split out missingfeed
2025-07-09 00:14:30 -07:00
Samuel Newman 1fcd313424 Translation update (#8624)
* pull translations

* extract all
2025-07-08 08:35:16 -07:00
Samuel Newman 9adcf5a12e specify autocap (#8619) 2025-07-08 05:35:46 -07:00
hailey 34291131b4 bump video lib (#8604) 2025-07-03 22:22:59 -07:00
Samuel Newman a9469cc111 Move NUX date (#8603) 2025-07-03 16:30:24 -07:00
Samuel Newman 1ed019bd72 specify mcemojipicker version (#8600) 2025-07-03 10:17:36 -07:00
pfrazee 42af417e8c Nightly source-language update 2025-07-03 02:43:45 +00:00
Samuel Newman dbfb9dad2f fix label for activity notifs (#8599) 2025-07-02 10:52:40 -07:00
Paul Frazee 9d44673acb Release 1.104.0 (#8595)
* Fix to navigation action after saving feeds

* Test updates

* Intl pull
2025-07-01 17:56:27 -07:00
Samuel Newman bc072570d2 Activity notification settings (#8485)
Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Co-authored-by: hailey <me@haileyok.com>
2025-07-01 14:36:04 -07:00
Samuel Newman 8f9a8ddce0 enforce border radius on default avatar (#8577) 2025-07-01 13:24:20 -07:00
Samuel Newman 9fdd98d8b4 Improve post spacing (#8589) 2025-07-01 13:24:03 -07:00
pfrazee 5f291b5ca8 Nightly source-language update 2025-07-01 02:51:03 +00:00
hailey 806d3792a9 feat: use t.gifs cdn for tenor search results (#8574) 2025-06-30 13:24:53 -07:00
Samuel Newman 5e20d5ffab Reduce composer font size (#8591) 2025-06-30 19:13:14 +03:00
pfrazee 130f795dfb Nightly source-language update 2025-06-29 02:49:46 +00:00
surfdude29 7837c8f07d tweak string in ContentLanguagesSettings.tsx (#8582) 2025-06-28 10:35:14 -05:00
pfrazee 3e76a4725e Nightly source-language update 2025-06-28 02:40:00 +00:00
Samuel Newman 9b306598cc tweak who can reply dialog (#8573) 2025-06-28 00:03:22 +03:00
Samuel Newman bde3fdaa42 Fix video aspect ratio error - "Record/embed/aspectRatio/width cannot be less than 1" (#8571) 2025-06-28 00:02:59 +03:00
pfrazee 494758da11 Nightly source-language update 2025-06-27 02:42:24 +00:00
Samuel Newman ad54ec8ef9 android paper text input padding (#8570) 2025-06-26 17:26:40 +03:00
Samuel Newman e5f9377a69 Virtualise labeler list (#8566)
* use flatlist for labeler list

* use key extractor

* dedupe `labelValues`

* add comment
2025-06-25 23:39:34 -07:00
pfrazee 954e7d2a89 Nightly source-language update 2025-06-26 02:41:44 +00:00
Eric Bailey 92ffe66ae1 Notifications registration (#8564)
* Formatting nits

* Debounce push token registration by 100ms

* Comment

* Align handling across native devices

* Clean up

* Simplify

* Use hooks

* Update import

* Comment

* Put app view DIDs in constants

* Clarify comment
2025-06-25 21:32:51 -05:00
Eric Bailey bb760400fe A few perf params for threads v2 (#8567)
Co-authored-by: Hailey <me@haileyok.com>
2025-06-25 15:23:09 -07:00
Samuel Newman ab4148dc06 fix pager back gesture (#8565) 2025-06-25 15:22:26 -07:00
Eric Bailey 929393a77a useEmail doesn't need a low stale time (#8568) 2025-06-25 17:22:03 -05:00
Eric Bailey 4c1515169a Tooltip (#8555)
* Working overlay, WIP

* Ok working with no overlay and global gesture handler

* Ok pretty good on native

* Cleanup

* Cleanup

* add animation

* add transform origin to animation

* Some a11y

* Improve colors

* Explicitly wrap gesture handler

* Add easier abstraction

* Web

* Fix animation

* Cleanup and remove provider

* Include demo for now

* Ok diff interface to avoid collapsed views

* Use dimensions hook

* Adjust overlap, clarify intent of consts

* Revert testing edits

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-06-24 22:03:23 -05:00
pfrazee cd820709b6 Nightly source-language update 2025-06-24 02:42:09 +00:00
hailey c894dda0bf disable new arch (#8561) 2025-06-23 10:11:17 -07:00
Samuel Newman c634cd9071 Upgrade prettier to 3.6 (#8558)
* upgrade prettier

* run prettier

* more files
2025-06-23 07:44:40 -07:00
pfrazee 3c92714e4e Nightly source-language update 2025-06-21 02:39:45 +00:00
Samuel Newman 25baf1f661 Allow disabling replies (#8537) 2025-06-20 22:44:53 +03:00
Samuel Newman dcbcd1bb80 simple heuristic for reducing footer height in thread (#8549) 2025-06-20 14:19:48 -05:00
Samuel Newman 92ee6260c1 Ignore common video errors (#8548) 2025-06-20 09:50:21 -07:00
Samuel Newman 9c7b330f92 Catch web browser errors (#8547)
* catch web browser errors

* use catch instead to ensure sheetWrapper works
2025-06-20 09:49:45 -07:00
Eric Bailey bc95c0e50c Don't send any debugs to Sentry (#8533)
* Don't send any debugs to Sentry

* Fix tests
2025-06-20 11:44:39 -05:00
Eric Bailey aeafb14fb4 Couple of Sentry cleanups (#8532)
* Temp ignore a couple logs

* Add debug for unknown notifications

* Nvm let's do this in Sentry

* Downgrade two DMs network related issues

* Check for network errors before sending in Convo

* Do the same for event bus

* Fix mistake
2025-06-20 09:30:52 -07:00
Samuel Newman 4c75b568df Android notification channels (#8539) 2025-06-20 11:01:55 +03:00
pfrazee 9702b210cc Nightly source-language update 2025-06-20 02:41:14 +00:00
Samuel Newman d53fdb0dda fix prefetch returning undefined (#8538) 2025-06-19 09:25:17 -07:00
pfrazee 9be3b0794c Nightly source-language update 2025-06-19 02:41:35 +00:00
Samuel Newman 77db98de65 bump keyboard dep (#8528) 2025-06-18 13:42:06 -07:00
Eric Bailey 51babe0164 Fix anchor text overflow in threads v2 (#8530) 2025-06-18 13:41:58 -07:00
Eric Bailey 04a2a227fc Revert "Move dialog outputs inside navigation context (#8511)" (#8531) 2025-06-18 13:39:58 -07:00
Samuel Newman 42510c0515 gate notification settings (#8527) 2025-06-18 13:36:37 -07:00
hailey f36776a91e switch mmkv version before android eas bundle (#8526) 2025-06-18 12:46:24 -07:00
Samuel Newman eb18b6a49a add scrollbars back on android (#8529) 2025-06-18 21:37:04 +03:00
Eric Bailey 3eaa2d9ddf Disable android new arch (#8525)
* Disable new arch in android for now

* Temporarily comment out mmkv script
2025-06-18 11:58:37 -05:00
Eric Bailey 066fd8cbf9 Fix select text color if system theme mismatches app theme (#8523) 2025-06-18 11:34:52 -05:00
Samuel Newman 06ebd2964a Fix linking to specific search results (#8520)
* fix linking to bsky.app/search?q=xyz

* add name to comment

* skip if notfound
2025-06-18 09:25:14 -07:00
Samuel Newman 3304cd0424 notif settings lexicon change (#8518) 2025-06-18 09:24:55 -07:00
Eric Bailey 32ba17a4f1 Fix anchor follow button alignment (#8522) 2025-06-18 09:24:27 -07:00
Eric Bailey f83335f110 Move dialog outputs inside navigation context (#8511)
* Move all dialogs within NavigationContent on native

* Ok leave old ModalsContainer alone for now

* Do the same on web

* Gate browser consent dialog just to be clear
2025-06-18 09:53:34 -05:00
Samuel Newman 4da86e5864 Modernise link warning dialog (#8243)
* add link warning dialog

* add copy for if sharing

* delete old modal

* get web working
2025-06-18 06:17:54 -07:00
Samuel Newman dd86402763 rearrange settings (#8519) 2025-06-18 05:19:42 -07:00
Frudrax Cheng 13d21692bf Mark translatable text in PreferenceControls.tsx (#8516)
* Update PreferenceControls.tsx

* Update PreferenceControls.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update PreferenceControls.tsx

Co-authored-by: Minseo Lee <itoupluk427@gmail.com>

* Update PreferenceControls.tsx

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Minseo Lee <itoupluk427@gmail.com>
2025-06-18 04:57:49 -07:00
Samuel Newman e672f43ec8 fix other case of promise.all misuse (#8505) 2025-06-18 04:08:44 -07:00
pfrazee afd3d2829f Nightly source-language update 2025-06-18 02:40:54 +00:00
Eric Bailey 619fa0d0bb Delete some old dialogs (#8512)
* Delete old EditProfile dialog

* Delete old email verification dialogs
2025-06-17 18:12:37 -05:00
Samuel Newman 9cf457acf8 copy tweak (#8506) 2025-06-18 00:12:59 +03:00
hailey f1f9ca9606 facepalm (#8510) 2025-06-17 13:19:07 -07:00
662 changed files with 194298 additions and 96695 deletions
+32 -5
View File
@@ -1,8 +1,35 @@
# Copy this to `.env` and `.env.test` files
# The env the app is running in e.g. development, testflight, production
EXPO_PUBLIC_ENV=development
BITDRIFT_API_KEY=
SENTRY_AUTH_TOKEN=
EXPO_PUBLIC_LOG_LEVEL=debug
EXPO_PUBLIC_LOG_DEBUG=
# This is the semver release version of the app, pulled from package.json
EXPO_PUBLIC_RELEASE_VERSION=
# This is the commit hash that the current bundle was made from.
EXPO_PUBLIC_BUNDLE_IDENTIFIER=
# Should be formatted YYMMDDHH so that it increases for each build.
EXPO_PUBLIC_BUNDLE_DATE=0
# The log level for the app's logger transports
EXPO_PUBLIC_LOG_LEVEL=debug
# Enable debug logs for specific logger instances
EXPO_PUBLIC_LOG_DEBUG=session
# Bluesky appview DID
EXPO_PUBLIC_BLUESKY_PROXY_DID=
# Chat service DID
EXPO_PUBLIC_CHAT_PROXY_DID=
#
#
# Bluesky specific values
#
#
# Sentry DSN for telemetry
EXPO_PUBLIC_SENTRY_DSN=
# Bitdrift API key. If undefined, Bitdrift will be disabled.
EXPO_PUBLIC_BITDRIFT_API_KEY=
+4
View File
@@ -34,6 +34,8 @@ module.exports = {
'P',
'Admonition',
'Admonition.Admonition',
'Toast.Action',
'AgeAssuranceAdmonition',
'Span',
],
impliedTextProps: [],
@@ -109,6 +111,8 @@ module.exports = {
'bskyembed',
'src/locale/locales/_build/',
'src/locale/locales/**/*.js',
'*.e2e.ts',
'*.e2e.tsx',
],
settings: {
componentWrapperFunctions: ['observer'],
@@ -43,12 +43,11 @@ jobs:
tags: |
type=sha,enable=true,priority=100,prefix=,suffix=,format=long
- name: Set outputs
id: vars
- name: Env
id: env
run: |
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
- name: Build and push Docker image
id: build-and-push
@@ -62,8 +61,8 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
EXPO_PUBLIC_BUNDLE_IDENTIFIER=${{ steps.vars.outputs.sha_short }}
SENTRY_DIST=${{ steps.vars.outputs.SENTRY_DIST }}
SENTRY_RELEASE=${{ steps.vars.outputs.SENTRY_RELEASE }}
EXPO_PUBLIC_ENV=production
EXPO_PUBLIC_RELEASE_VERSION=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
EXPO_PUBLIC_BUNDLE_IDENTIFIER=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_DSN=${{ secrets.SENTRY_DSN }}
@@ -3,6 +3,7 @@ on:
push:
branches:
- main
- echoprom_fix
env:
REGISTRY: ${{ secrets.AWS_ECR_REGISTRY_USEAST2_PACKAGES_REGISTRY }}
+27 -15
View File
@@ -13,6 +13,7 @@ on:
jobs:
build:
if: github.repository == 'bluesky-social/social-app'
name: Build and Submit Android
runs-on: ubuntu-latest
steps:
@@ -52,10 +53,6 @@ jobs:
distribution: 'temurin'
java-version: '17'
- name: "Use upgraded MMKV for Fabric"
run: |
sed -i 's/"react-native-mmkv": "\^2\.12\.2"/"react-native-mmkv": "^3.3.0"/' filename.txt
- name: ⚙️ Install dependencies
run: yarn install
@@ -65,23 +62,31 @@ jobs:
- name: Check for i18n compilation errors
run: if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compilation errors!\n\n"; fi
- name: ✏️ Write environment variables
# EXPO_PUBLIC_ENV is handled in eas.json
- name: Env
id: env
run: |
export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}'
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env
echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_GCP_PROJECT_ID=${{ secrets.EXPO_PUBLIC_GCP_PROJECT_ID }}" >> .env
echo "$json" > google-services.json
- name: Setup Sentry vars for build-time injection
id: sentry
run: |
echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: 🏗️ EAS Build
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p android --profile ${{ inputs.profile || 'testflight-android' }} --local --output build.aab --non-interactive
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn use-build-number-with-bump
eas build -p android
--profile ${{ inputs.profile || 'testflight-android' }}
--local --output build.aab --non-interactive
- name: ✍️ Rename Testflight bundle
if: ${{ inputs.profile != 'production' }}
@@ -143,7 +148,14 @@ jobs:
- name: 🏗️ Build Production APK
if: ${{ inputs.profile == 'production' }}
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p android --profile production-apk --local --output build.apk --non-interactive
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn use-build-number-with-bump
eas build -p android
--profile production-apk
--local --output build.apk --non-interactive
- name: 🚀 Upload Production APK Artifact
id: upload-artifact-production-apk
+19 -10
View File
@@ -13,6 +13,7 @@ on:
jobs:
build:
if: github.repository == 'bluesky-social/social-app'
name: Build and Submit iOS
runs-on: macos-15
steps:
@@ -52,7 +53,7 @@ jobs:
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.2'
xcode-version: '16.4'
- name: ☕️ Setup Cocoapods
uses: maxim-lobanov/setup-cocoapods@v1
@@ -74,22 +75,30 @@ jobs:
- name: Check for i18n compilation errors
run: if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compilation errors!\n\n"; fi
# EXPO_PUBLIC_ENV is handled in eas.json
- name: ✏️ Write environment variables
id: env
run: |
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env
echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_GCP_PROJECT_ID=${{ secrets.EXPO_PUBLIC_GCP_PROJECT_ID }}" >> .env
echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json
- name: Setup Sentry vars for build-time injection
id: sentry
run: |
echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: 🏗️ EAS Build
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p ios --profile ${{ inputs.profile || 'testflight' }} --local --output build.ipa --non-interactive
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn use-build-number-with-bump
eas build -p ios
--profile ${{ inputs.profile || 'testflight' }}
--local --output build.ipa --non-interactive
- name: 🚀 Deploy
run: eas submit -p ios --non-interactive --path build.ipa
+55 -24
View File
@@ -20,6 +20,7 @@ on:
jobs:
bundleDeploy:
if: github.repository == 'bluesky-social/social-app'
name: Bundle and Deploy EAS Update
runs-on: ubuntu-latest
concurrency:
@@ -100,25 +101,31 @@ jobs:
if: ${{ !steps.fingerprint.outputs.includes-changes }}
uses: dcarbone/install-jq-action@v2
- name: ✏️ Write environment variables
# eas.json not used here, set EXPO_PUBLIC_ENV
- name: Env
id: env
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: |
export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}'
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_ENV=${{ inputs.channel || 'testflight' }}" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env
echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_GCP_PROJECT_ID=${{ secrets.EXPO_PUBLIC_GCP_PROJECT_ID }}" >> .env
echo "$json" > google-services.json
- name: Setup Sentry vars for build-time injection
id: sentry
run: |
echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: 🏗️ Create Bundle
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} EXPO_PUBLIC_ENV="${{ inputs.channel || 'testflight' }}" yarn export
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn export
- name: 📦 Package Bundle and 🚀 Deploy
if: ${{ !steps.fingerprint.outputs.includes-changes }}
@@ -150,7 +157,7 @@ jobs:
needs: [bundleDeploy]
# Gotta check if its NOT '[]' because any md5 hash in the outputs is detected as a possible secret and won't be
# available here
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.changes-detected }}
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.changes-detected && github.repository == 'bluesky-social/social-app' }}
steps:
- name: Check for EXPO_TOKEN
run: >
@@ -204,16 +211,30 @@ jobs:
- name: 🔤 Compile translations
run: yarn intl:build
- name: ✏️ Write environment variables
# EXPO_PUBLIC_ENV is handled in eas.json
- name: Env
id: env
run: |
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env
echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_GCP_PROJECT_ID=${{ secrets.EXPO_PUBLIC_GCP_PROJECT_ID }}" >> .env
echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json
- name: 🏗️ EAS Build
run: yarn use-build-number-with-bump eas build -p ios --profile testflight --local --output build.ipa --non-interactive
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn use-build-number-with-bump
eas build -p ios
--profile testflight
--local --output build.ipa --non-interactive
- name: 🚀 Deploy
run: eas submit -p ios --non-interactive --path build.ipa
@@ -239,7 +260,7 @@ jobs:
needs: [bundleDeploy]
# Gotta check if its NOT '[]' because any md5 hash in the outputs is detected as a possible secret and won't be
# available here
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.changes-detected }}
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.changes-detected && github.repository == 'bluesky-social/social-app'}}
steps:
- name: Check for EXPO_TOKEN
@@ -275,27 +296,37 @@ jobs:
distribution: 'temurin'
java-version: '17'
- name: "Use upgraded MMKV for Fabric"
run: |
sed -i 's/"react-native-mmkv": "\^2\.12\.2"/"react-native-mmkv": "^3.3.0"/' filename.txt
- name: ⚙️ Install dependencies
run: yarn install
- name: 🔤 Compile translations
run: yarn intl:build
- name: ✏️ Write environment variables
# EXPO_PUBLIC_ENV is handled in eas.json
- name: Env
id: env
run: |
export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}'
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env
echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_GCP_PROJECT_ID=${{ secrets.EXPO_PUBLIC_GCP_PROJECT_ID }}" >> .env
echo "$json" > google-services.json
- name: 🏗️ EAS Build
run: yarn use-build-number-with-bump eas build -p android --profile testflight-android --local --output build.apk --non-interactive
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn use-build-number-with-bump
eas build -p android
--profile testflight-android
--local --output build.apk --non-interactive
- name: ⏰ Get a timestamp
id: timestamp
+209
View File
@@ -0,0 +1,209 @@
---
name: PR Comment Trigger
on:
issue_comment:
types: [created]
# Permissiosn to make comments in the pull request
permissions:
pull-requests: write
actions: write
contents: read
jobs:
handle-comment:
if: github.event.issue.pull_request
runs-on: ubuntu-latest
outputs:
should-deploy: ${{ steps.check-org.outputs.result }}
steps:
- name: Check if bot is mentioned
id: check-mention
env:
COMMENT: ${{ github.event.comment.body }}
run: |
if [[ "$COMMENT" == *"@github-actions"* ]] || \
[[ "$COMMENT" == *"github-actions[bot]"* ]]; then
bot_mentioned=true
else
bot_mentioned=false
fi
if [[ "${{ github.event.comment.body }}" == *"ota"* ]]; then
has_ota=true
else
has_ota=false
fi
if [[ "$bot_mentioned" == "true" ]] && [[ "$has_ota" == "true" ]]; then
echo "mentioned=true" >> $GITHUB_OUTPUT
else
echo "mentioned=false" >> $GITHUB_OUTPUT
fi
- name: Check organization membership
if: steps.check-mention.outputs.mentioned == 'true'
id: check-org
uses: actions/github-script@v7
with:
script: |
try {
const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.payload.comment.user.login
});
const hasAccess = ['admin', 'write'].includes(perm.permission);
console.log(`User has ${perm.permission} access`);
return hasAccess;
} catch(error) {
console.log('User has no repository access');
return false;
}
bundle-deploy:
name: Bundle and Deploy EAS Update
runs-on: ubuntu-latest
needs: [handle-comment]
if: needs.handle-comment.outputs.should-deploy == 'true'
steps:
- name: Get PR HEAD SHA
id: pr-info
uses: actions/github-script@v7
with:
script: |
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: ${{ github.event.issue.number }}
});
console.log(`PR HEAD SHA: ${pr.data.head.sha}`);
console.log(`PR HEAD REF: ${pr.data.head.ref}`);
core.setOutput('head-sha', pr.data.head.sha);
core.setOutput('head-ref', pr.data.head.ref);
- name: 💬 Drop a comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: pull-request-eas-build-${{ steps.pr-info.outputs.head-sha }}
number: ${{ github.event.issue.number }}
message: |
An OTA deployment has been requested and is now running for `${{ steps.pr-info.outputs.head-sha }}`.
[Here is some music to listen to while you wait...](https://www.youtube.com/watch?v=VBlFHuCzPgY)
---
*Generated by [PR labeler](https://github.com/expo/expo/actions/workflows/pr-labeler.yml) 🤖*
- name: Check for EXPO_TOKEN
run: >
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions"
exit 1
fi
- name: ⬇️ Checkout
uses: actions/checkout@v4
with:
ref: ${{ steps.pr-info.outputs.head-sha }}
- name: 🔧 Setup Node
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Lint check
run: yarn lint
- name: Lint lockfile
run: yarn lockfile-lint
- name: 🔤 Compile translations
run: yarn intl:build 2>&1 | tee i18n.log
- name: Check for i18n compilation errors
run: if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compilation errors!\n\n"; fi
- name: Type check
run: yarn typecheck
- name: 🔨 Setup EAS
uses: expo/expo-github-action@v8
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: ⛏️ Setup Expo
run: yarn global add eas-cli-local-build-plugin
- name: 🪛 Setup jq
uses: dcarbone/install-jq-action@v2
- name: Env
id: env
run: |
export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}'
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_ENV=testflight" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> .env
echo "EXPO_PUBLIC_RELEASE_VERSION=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "EXPO_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env
echo "EXPO_PUBLIC_BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "EXPO_PUBLIC_GCP_PROJECT_ID=${{ secrets.EXPO_PUBLIC_GCP_PROJECT_ID }}" >> .env
echo "$json" > google-services.json
- name: 🏗️ Create Bundle
run: >
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_RELEASE=${{ steps.env.outputs.EXPO_PUBLIC_RELEASE_VERSION }}
SENTRY_DIST=${{ steps.env.outputs.EXPO_PUBLIC_BUNDLE_IDENTIFIER }}
yarn export
- name: 📦 Package Bundle and 🚀 Deploy
run: yarn use-build-number bash scripts/bundleUpdate.sh
env:
DENIS_API_KEY: ${{ secrets.DENIS_API_KEY }}
CHANNEL_NAME: pull-request-${{ github.event.issue.number }}
RUNTIME_VERSION:
- name: 💬 Drop a comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: pull-request-eas-build-${{ steps.pr-info.outputs.head-sha }}
number: ${{ github.event.issue.number }}
message: |
Your requested OTA deployment was successful! You may now apply it by either scanning the QR code or opening the deep link below in your browser:
<img src="https://bsky-qr.vercel.app?channel=pull-request-${{ github.event.issue.number }}" width=300 height=300>
`bluesky://intent/apply-ota?channel=pull-request-${{ github.event.issue.number }}`
---
*Generated by [PR labeler](https://github.com/expo/expo/actions/workflows/pr-labeler.yml) 🤖*
- name: 💬 Drop a comment
uses: marocchino/sticky-pull-request-comment@v2
if: failure()
with:
header: pull-request-eas-build-${{ steps.pr-info.outputs.head-sha }}
number: ${{ github.event.issue.number }}
message: |
Your requested OTA deployment was unsuccessful. See action logs for more details.
---
*Generated by [PR labeler](https://github.com/expo/expo/actions/workflows/pr-labeler.yml) 🤖*
+2 -1
View File
@@ -50,6 +50,7 @@ jobs:
git config --global user.name "github-actions[bot]"
git merge --no-edit ${{ github.head_ref }}
yarn install
yarn intl:build
- name: 🔦 Generate stats file for PR
run: |
@@ -73,6 +74,7 @@ jobs:
if: ${{ !steps.get-base-stats.outputs.cache-hit }}
run: |
yarn install
yarn intl:build
yarn generate-webpack-stats-file
mv stats.json stats-base.json
@@ -143,4 +145,3 @@ jobs:
with:
header: fingerprint-diff
delete: true
+31
View File
@@ -0,0 +1,31 @@
name: Sync to internal repo
on:
push:
branches: [main]
jobs:
sync:
runs-on: ubuntu-latest
if: github.repository == 'bluesky-social/social-app'
steps:
- name: Checkout public repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate GitHub App Token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.SYNC_INTERNAL_APP_ID }}
private-key: ${{ secrets.SYNC_INTERNAL_PK }}
repositories: social-app-internal
- name: Push to internal repo
env:
TOKEN: ${{ steps.app-token.outputs.token }}
run: |
git config user.name "github-actions"
git config user.email "test@users.noreply.github.com"
git config --unset-all http.https://github.com/.extraheader
git remote add internal https://x-access-token:${TOKEN}@github.com/bluesky-social/social-app-internal.git
git push internal main --force
+1
View File
@@ -58,6 +58,7 @@ buck-out/
# Ruby / CocoaPods
/ios/Pods/
/vendor/bundle/
Gemfile.lock
# Testing
coverage/
+17 -14
View File
@@ -1,4 +1,4 @@
FROM golang:1.23-bullseye AS build-env
FROM golang:1.24.5-bullseye AS build-env
WORKDIR /usr/src/social-app
@@ -19,28 +19,28 @@ ENV GOARCH="amd64"
ENV CGO_ENABLED=1
ENV GOEXPERIMENT="loopvar"
# The latest git hash of the preview branch on render.com
# https://render.com/docs/docker-secrets#environment-variables-in-docker-builds
ARG RENDER_GIT_COMMIT
#
# Expo
#
ARG EXPO_PUBLIC_ENV
ENV EXPO_PUBLIC_ENV=${EXPO_PUBLIC_ENV:-development}
ARG EXPO_PUBLIC_RELEASE_VERSION
ENV EXPO_PUBLIC_RELEASE_VERSION=$EXPO_PUBLIC_RELEASE_VERSION
ARG EXPO_PUBLIC_BUNDLE_IDENTIFIER
ENV EXPO_PUBLIC_BUNDLE_IDENTIFIER=${EXPO_PUBLIC_BUNDLE_IDENTIFIER:-dev}
# The latest git hash of the preview branch on render.com
ARG RENDER_GIT_COMMIT
# If not set by GitHub workflows, we're probably in Render
ENV EXPO_PUBLIC_BUNDLE_IDENTIFIER=${EXPO_PUBLIC_BUNDLE_IDENTIFIER:-$RENDER_GIT_COMMIT}
#
# Sentry
#
ARG SENTRY_AUTH_TOKEN
ENV SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN:-unknown}
# Will fall back to package.json#version, but this is handled elsewhere
ARG SENTRY_RELEASE
ENV SENTRY_RELEASE=$SENTRY_RELEASE
ARG SENTRY_DIST
# Default to RENDER_GIT_COMMIT if not set by GitHub workflows
ENV SENTRY_DIST=${SENTRY_DIST:-$RENDER_GIT_COMMIT}
ARG SENTRY_DSN
ENV SENTRY_DSN=$SENTRY_DSN
ARG EXPO_PUBLIC_SENTRY_DSN
ENV EXPO_PUBLIC_SENTRY_DSN=$EXPO_PUBLIC_SENTRY_DSN
#
# Copy everything into the container
@@ -60,13 +60,16 @@ RUN \. "$NVM_DIR/nvm.sh" && \
nvm install $NODE_VERSION && \
nvm use $NODE_VERSION && \
echo "Using bundle identifier: $EXPO_PUBLIC_BUNDLE_IDENTIFIER" && \
echo "EXPO_PUBLIC_ENV=$EXPO_PUBLIC_ENV" >> .env && \
echo "EXPO_PUBLIC_RELEASE_VERSION=$EXPO_PUBLIC_RELEASE_VERSION" >> .env && \
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$EXPO_PUBLIC_BUNDLE_IDENTIFIER" >> .env && \
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env && \
echo "EXPO_PUBLIC_SENTRY_DSN=$EXPO_PUBLIC_SENTRY_DSN" >> .env && \
npm install --global yarn && \
yarn && \
yarn intl:build 2>&1 | tee i18n.log && \
if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compile errors!\n\n"; fi && \
EXPO_PUBLIC_BUNDLE_IDENTIFIER=$EXPO_PUBLIC_BUNDLE_IDENTIFIER EXPO_PUBLIC_BUNDLE_DATE=$() SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN SENTRY_RELEASE=$SENTRY_RELEASE SENTRY_DIST=$SENTRY_DIST SENTRY_DSN=$SENTRY_DSN yarn build-web
SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN SENTRY_RELEASE=$EXPO_PUBLIC_RELEASE_VERSION SENTRY_DIST=$EXPO_PUBLIC_BUNDLE_IDENTIFIER yarn build-web
# DEBUG
RUN find ./bskyweb/static && find ./web-build/static
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.23-bullseye AS build-env
FROM golang:1.24.5-bullseye AS build-env
WORKDIR /usr/src/social-app
+4 -3
View File
@@ -10,7 +10,7 @@ Get the app itself:
## Development Resources
This is a [React Native](https://reactnative.dev/) application, written in the TypeScript programming language. It builds on the `atproto` TypeScript packages (like [`@atproto/api`](https://www.npmjs.com/package/@atproto/api)), code for which is also open source, but in [a different git repository](https://github.com/bluesky-social/atproto).
This is a [React Native](https://reactnative.dev/) application, written in the TypeScript programming language. It builds on the `atproto` TypeScript packages (like [`@atproto/api`](https://www.npmjs.com/package/@atproto/api)), which are also open source, but in [a different git repository](https://github.com/bluesky-social/atproto).
There is a small amount of Go language source code (in `./bskyweb/`), for a web service that returns the React Native Web application.
@@ -19,7 +19,7 @@ The [Build Instructions](./docs/build.md) are a good place to get started with t
The Authenticated Transfer Protocol ("AT Protocol" or "atproto") is a decentralized social media protocol. You don't *need* to understand AT Protocol to work with this application, but it can help. Learn more at:
- [Overview and Guides](https://atproto.com/guides/overview)
- [Github Discussions](https://github.com/bluesky-social/atproto/discussions) 👈 Great place to ask questions
- [GitHub Discussions](https://github.com/bluesky-social/atproto/discussions) 👈 Great place to ask questions
- [Protocol Specifications](https://atproto.com/specs/atp)
- [Blogpost on self-authenticating data structures](https://bsky.social/about/blog/3-6-2022-a-self-authenticating-social-protocol)
@@ -27,6 +27,7 @@ The Bluesky Social application encompasses a set of schemas and APIs built in th
## Contributions
> [!NOTE]
> While we do accept contributions, we prioritize high quality issues and pull requests. Adhering to the below guidelines will ensure a more timely review.
**Rules:**
@@ -59,7 +60,7 @@ Please be sure to:
## Security disclosures
If you discover any security issues, please send an email to security@bsky.app. The email is automatically CCed to the entire team and we'll respond promptly.
If you discover any security issues, please send an email to security@bsky.app. The email is automatically CC'd to the entire team and we'll respond promptly.
## Are you a developer interested in building on atproto?
+9 -3
View File
@@ -3,20 +3,26 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: ?users
SERVER_PATH: ?users
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
# Post an image with the porn label
- assertVisible:
id: "composeFAB"
id: "composeFAB"
- tapOn:
id: "composeFAB"
- inputText: "Post with an image"
- tapOn:
id: "openGalleryBtn"
id: "openMediaBtn"
- extendedWaitUntil:
visible:
id: "selectedPhotosView"
- tapOn: "Content warnings"
- tapOn: "Porn"
- tapOn:
+18 -5
View File
@@ -3,13 +3,17 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: ?users
SERVER_PATH: ?users
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- assertVisible:
id: "composeFAB"
id: "composeFAB"
- tapOn:
id: "composeFAB"
- inputText: "Post text only"
@@ -21,7 +25,10 @@ appId: xyz.blueskyweb.app
id: "composeFAB"
- inputText: "Post with an image"
- tapOn:
id: "openGalleryBtn"
id: "openMediaBtn"
- extendedWaitUntil:
visible:
id: "selectedPhotosView"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
@@ -46,7 +53,10 @@ appId: xyz.blueskyweb.app
id: "replyBtn"
- inputText: "Reply with an image"
- tapOn:
id: "openGalleryBtn"
id: "openMediaBtn"
- extendedWaitUntil:
visible:
id: "selectedPhotosView"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
@@ -73,7 +83,10 @@ appId: xyz.blueskyweb.app
id: "quoteBtn"
- inputText: "QP with an image"
- tapOn:
id: "openGalleryBtn"
id: "openMediaBtn"
- extendedWaitUntil:
visible:
id: "selectedPhotosView"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
+7 -2
View File
@@ -28,8 +28,13 @@ appId: xyz.blueskyweb.app
- hideKeyboard
- tapOn:
id: "nextBtn"
- tapOn: "Not now"
- tapOn:
text: "Not Now"
optional: true
- inputText: "e2e-test"
- extendedWaitUntil:
visible:
id: "handleAvailableCheck"
- tapOn:
id: "nextBtn"
- assertVisible: "Give your profile a face"
+8 -6
View File
@@ -3,11 +3,14 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows&posts"
SERVER_PATH: "?users&follows&posts"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- tapOn:
label: "Create a curate list"
@@ -75,9 +78,8 @@ appId: xyz.blueskyweb.app
- tapOn:
id: "confirmBtn"
- tapOn:
label: "Create a new curatelist"
id: "e2eGotoLists"
- assertVisible:
id: "newUserListBtn"
- tapOn:
id: "newUserListBtn"
- assertVisible:
@@ -135,7 +137,7 @@ appId: xyz.blueskyweb.app
id: "e2eGotoLists"
- tapOn: "Good Ppl"
# - tapOn: "People"
- tapOn: "People"
- assertVisible: "View Bob's profile"
- tapOn:
point: "90%,43%"
@@ -146,7 +148,7 @@ appId: xyz.blueskyweb.app
- tapOn:
id: "bottomBarSearchBtn"
- tapOn: "Search for posts, users, or feeds"
- tapOn: "Search for posts, users[,]? or feeds"
- inputText: "bob"
- tapOn:
id: "searchAutoCompleteResult-bob.test"
+3 -1
View File
@@ -23,5 +23,7 @@ appId: xyz.blueskyweb.app
id: "loginPasswordInput"
- inputText: "hunter2"
- pressKey: Enter
- tapOn: "Not now"
- tapOn:
text: "Not Now"
optional: true
- assertVisible: "Following"
+10 -10
View File
@@ -3,11 +3,14 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows&labels"
SERVER_PATH: "?users&follows&labels"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
# create a modlist
- tapOn:
@@ -28,20 +31,17 @@ appId: xyz.blueskyweb.app
- assertVisible: "Muted Users"
- assertVisible: "Shhh"
- tapOn:
label: "Dropdown"
point: "71%,9%"
# DOES NOT WORK - THE BUTTON IS NOT ACCESSIBLE
# IGNORING FOR NOW, FIX THE COMPONENTS IN THE NEXT RELEASE
# BECAUSE THIS IS A LEGIT A11Y PROBLEM -sfn
- tapOn: "Subscribe to this list"
- tapOn: "Mute accounts"
- tapOn: "Mute list"
- tapOn: "Unmute"
- tapOn:
label: "Dropdown"
point: "71%,9%"
- tapOn: "Subscribe to this list"
- tapOn: "Block accounts"
- tapOn: "Block list"
- tapOn: "Unblock"
# the rest of the behaviors are tested in curate-lists.yml
# the rest of the behaviors are tested in curate-lists.yml
+10 -6
View File
@@ -3,11 +3,15 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users"
SERVER_PATH: "?users"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- tapOn:
id: "e2eStartOnboarding"
- tapOn: "Open avatar creator"
@@ -21,12 +25,12 @@ appId: xyz.blueskyweb.app
- tapOn: "Select the atom emoji as your avatar"
- tapOn: "Done"
- waitForAnimationToEnd
- tapOn: "Continue to next step"
- tapOn:
id: "onboardingContinue"
- assertVisible: "What are your interests?"
- tapOn:
label: "Tap on continue"
point: "50%,92%"
id: "onboardingContinue"
- assertVisible: "You're ready to go!"
- tapOn:
label: "Tap on Lets go"
point: "50%,92%"
id: "onboardingFinish"
- assertVisible: "Following"
+10 -6
View File
@@ -3,11 +3,15 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users"
SERVER_PATH: "?users"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- tapOn:
id: "e2eStartOnboarding"
- tapOn: "Select an avatar"
@@ -18,12 +22,12 @@ appId: xyz.blueskyweb.app
- waitForAnimationToEnd
- tapOn: "Done"
- waitForAnimationToEnd
- tapOn: "Continue to next step"
- tapOn:
id: "onboardingContinue"
- assertVisible: "What are your interests?"
- tapOn:
label: "Tap on continue"
point: "50%,92%"
id: "onboardingContinue"
- assertVisible: "You're ready to go!"
- tapOn:
label: "Tap on Lets go"
point: "50%,92%"
id: "onboardingFinish"
- assertVisible: "Following"
+4 -1
View File
@@ -3,11 +3,14 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows&posts"
SERVER_PATH: "?users&follows&posts"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- tapOn:
id: "postDropdownBtn"
+6 -4
View File
@@ -3,7 +3,7 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&posts&feeds"
SERVER_PATH: "?users&posts&feeds"
- runFlow:
file: ../setupApp.yml
- tapOn:
@@ -12,10 +12,10 @@ appId: xyz.blueskyweb.app
# Navigate to another user profile
- extendedWaitUntil:
visible:
id: "bottomBarSearchBtn"
id: "bottomBarSearchBtn"
- tapOn:
id: "bottomBarSearchBtn"
- tapOn: "Search for posts, users, or feeds"
- tapOn: "Search for posts, users[,]? or feeds"
- inputText: "b"
- tapOn:
id: "searchAutoCompleteResult-bob.test"
@@ -25,6 +25,8 @@ appId: xyz.blueskyweb.app
# Can follow/unfollow another user
- tapOn:
id: "followBtn"
- tapOn:
point: 65%,35% # dismiss the subscribe prompt
- tapOn:
id: "unfollowBtn"
@@ -36,4 +38,4 @@ appId: xyz.blueskyweb.app
- tapOn:
id: "profileHeaderDropdownBtn"
- tapOn: "Unmute Account"
- assertNotVisible: "Account Muted"
- assertNotVisible: "Account Muted"
+6 -4
View File
@@ -3,20 +3,22 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users"
SERVER_PATH: "?users"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
# Navigate to another user profile via autocomplete
- extendedWaitUntil:
visible:
id: "bottomBarSearchBtn"
- tapOn:
id: "bottomBarSearchBtn"
- assertVisible: "Search for posts, users, or feeds"
- tapOn: "Search for posts, users, or feeds"
- assertVisible: "Search for posts, users[,]? or feeds"
- tapOn: "Search for posts, users[,]? or feeds"
- inputText: "b"
- tapOn:
id: "searchAutoCompleteResult-bob.test"
- assertVisible:
id: "profileView"
+5 -1
View File
@@ -8,8 +8,12 @@ appId: xyz.blueskyweb.app
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- assertVisible:
id: "storybookBtn"
id: "storybookBtn"
- tapOn:
id: "storybookBtn"
- tapOn:
+38 -9
View File
@@ -3,13 +3,16 @@ appId: xyz.blueskyweb.app
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows"
SERVER_PATH: "?users&follows"
- runFlow:
file: ../setupApp.yml
# Login, create a thread, and log out
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
@@ -19,8 +22,13 @@ appId: xyz.blueskyweb.app
id: "composerPublishBtn"
# Login, reply to the thread, and log out
- tapOn:
id: "e2eSignOut"
- tapOn:
id: "e2eSignInBob"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- tapOn:
id: "replyBtn"
- inputText: "Reply 1"
@@ -28,8 +36,13 @@ appId: xyz.blueskyweb.app
id: "composerPublishBtn"
# Login, confirm notification exists, mute thread, and log out
- tapOn:
id: "e2eSignOut"
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- tapOn:
id: "bottomBarNotificationsBtn"
- assertVisible:
@@ -39,12 +52,17 @@ appId: xyz.blueskyweb.app
- tapOn:
id: "postDropdownBtn"
childOf:
id: "postThreadItem-by-bob.test"
id: "postThreadItem-by-bob.test"
- tapOn: "Mute thread"
# Login, reply to the thread twice, and log out
- tapOn:
id: "e2eSignOut"
- tapOn:
id: "e2eSignInBob"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- tapOn:
id: "bottomBarProfileBtn"
- tapOn:
@@ -60,24 +78,35 @@ appId: xyz.blueskyweb.app
- tapOn:
id: "composerPublishBtn"
# Login, confirm notifications dont exist, unmute the thread, confirm notifications exist
# Login, confirm notifications dont exist, unmute the thread, ~~confirm notifications exist~~
# Mute thread behaviour no longer change old notifications after muting/unmuting a thread -sfn
- tapOn:
id: "e2eSignOut"
- tapOn:
id: "e2eSignInAlice"
- extendedWaitUntil:
visible:
id: "viewHeaderHomeFeedPrefsBtn"
- tapOn:
id: "bottomBarNotificationsBtn"
- assertNotVisible:
- assertVisible: ".*Reply 1.*"
- assertNotVisible: ".*Reply 2.*"
- assertNotVisible: ".*Reply 3.*"
- assertVisible:
id: "feedItem-by-bob.test"
- tapOn:
id: "bottomBarHomeBtn"
id: "feedItem-by-bob.test"
- tapOn:
id: "postDropdownBtn"
childOf:
id: "postThreadItem-by-bob.test"
- tapOn: "Unmute thread"
- tapOn:
id: "bottomBarNotificationsBtn"
- swipe:
from:
id: "notifsFeed"
id: "notifsFeed"
direction: DOWN
- assertVisible:
id: "feedItem-by-bob.test"
- assertVisible: ".*Reply 1.*"
- assertNotVisible: ".*Reply 2.*"
- assertNotVisible: ".*Reply 3.*"
+23 -14
View File
@@ -1,7 +1,7 @@
import {createServer as createHTTPServer} from 'node:http'
import {parse} from 'node:url'
import {createServer, TestPDS} from '../jest/test-pds'
import {createServer, type TestPDS} from '../jest/test-pds'
async function main() {
let server: TestPDS
@@ -181,10 +181,10 @@ async function main() {
'warn-profile',
'warn-posts',
'muted-account',
'muted-by-list-account',
'muted-by-list-acc',
'blocking-account',
'blockedby-account',
'mutual-block-account',
'mutual-block-acc',
]) {
await server.mocker.createUser(user)
await server.mocker.follow('alice', user)
@@ -411,16 +411,16 @@ async function main() {
await server.mocker.addToMuteList(
'alice',
list,
server.mocker.users['muted-by-list-account'].did,
server.mocker.users['muted-by-list-acc'].did,
)
await server.mocker.createPost('muted-by-list-account', 'muted post')
await server.mocker.createPost('muted-by-list-acc', 'muted post')
await server.mocker.createQuotePost(
'muted-by-list-account',
'muted-by-list-acc',
'account quote post',
anchorPost,
)
await server.mocker.createReply(
'muted-by-list-account',
'muted-by-list-acc',
'account reply',
anchorPost,
)
@@ -470,16 +470,16 @@ async function main() {
)
await server.mocker.createPost(
'mutual-block-account',
'mutual-block-acc',
'mutual-block post',
)
await server.mocker.createQuotePost(
'mutual-block-account',
'mutual-block-acc',
'mutual-block quote post',
anchorPost,
)
await server.mocker.createReply(
'mutual-block-account',
'mutual-block-acc',
'mutual-block reply',
anchorPost,
)
@@ -488,15 +488,15 @@ async function main() {
repo: server.mocker.users.alice.did,
},
{
subject: server.mocker.users['mutual-block-account'].did,
subject: server.mocker.users['mutual-block-acc'].did,
createdAt: new Date().toISOString(),
},
)
await server.mocker.users[
'mutual-block-account'
'mutual-block-acc'
].agent.app.bsky.graph.block.create(
{
repo: server.mocker.users['mutual-block-account'].did,
repo: server.mocker.users['mutual-block-acc'].did,
},
{
subject: server.mocker.users.alice.did,
@@ -509,7 +509,16 @@ async function main() {
}
}
console.log('Ready')
return res.writeHead(200).end(server.pdsUrl)
return res
.writeHead(200, {
'content-type': 'application/json',
})
.end(
JSON.stringify({
pdsUrl: server.pdsUrl,
appviewDid: server.appviewDid,
}),
)
} catch (e) {
console.error('Error!', e)
return res.writeHead(500).end()
+5
View File
@@ -11,3 +11,8 @@ appId: xyz.blueskyweb.app
- swipe:
from: "Bluesky"
direction: DOWN
- tapOn:
id: e2eProxyHeaderInput
- inputText: ${output.result}
- pressKey: Enter
- hideKeyboard
+5 -2
View File
@@ -1,5 +1,8 @@
// eslint-disable-next-line
http.post('http://localhost:1986/' + SERVER_PATH, {
// eslint-disable-next-line no-undef
var res = http.post('http://localhost:1986/' + SERVER_PATH, {
headers: {'Content-Type': 'text/plain'},
body: '',
})
// eslint-disable-next-line no-undef
output.result = json(res.body).appviewDid
+6 -5
View File
@@ -1,7 +1,8 @@
import React, {ReactNode} from 'react'
import {View, ScrollView, Modal, FlatList, TextInput} from 'react-native'
import React, {type ReactNode} from 'react'
import {FlatList, Modal, ScrollView, TextInput, View} from 'react-native'
const BottomSheetModalContext = React.createContext(null)
BottomSheetModalContext.displayName = 'BottomSheetModalContext'
const BottomSheetModalProvider = (props: any) => {
return <BottomSheetModalContext.Provider {...props} value={{}} />
@@ -47,13 +48,13 @@ export {useBottomSheetInternal}
export {useBottomSheetDynamicSnapPoints}
export {
BottomSheetModalProvider,
BottomSheetBackdrop,
BottomSheetFlatList,
BottomSheetFooter,
BottomSheetHandle,
BottomSheetModal,
BottomSheetFooter,
BottomSheetModalProvider,
BottomSheetScrollView,
BottomSheetFlatList,
BottomSheetTextInput,
}
+16
View File
@@ -6,6 +6,7 @@ import {
createStarterPackLinkFromAndroidReferrer,
parseStarterPackUri,
} from '#/lib/strings/starter-pack'
import {tenorUrlToBskyGifUrl} from '#/state/queries/tenor'
import {cleanError} from '../../src/lib/strings/errors'
import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles'
import {enforceLen} from '../../src/lib/strings/helpers'
@@ -997,3 +998,18 @@ describe('createStarterPackGooglePlayUri', () => {
expect(createStarterPackGooglePlayUri(undefined, 'rkey')).toEqual(null)
})
})
describe('tenorUrlToBskyGifUrl', () => {
const inputs = [
'https://media.tenor.com/someID_AAAAC/someName.gif',
'https://media.tenor.com/someID/someName.gif',
]
it.each(inputs)(
'returns url with t.gifs.bsky.app as hostname for input url',
input => {
const out = tenorUrlToBskyGifUrl(input)
expect(out.startsWith('https://t.gifs.bsky.app/')).toEqual(true)
},
)
})
+5 -5
View File
@@ -1,4 +1,4 @@
import {IsValidHandle, validateServiceHandle} from '#/lib/strings/handles'
import {type IsValidHandle, validateServiceHandle} from '#/lib/strings/handles'
describe('handle validation', () => {
const valid = [
@@ -18,17 +18,17 @@ describe('handle validation', () => {
})
const invalid = [
['al', 'bsky.social', 'frontLength'],
['al', 'bsky.social', 'frontLengthNotTooShort'],
['-alice', 'bsky.social', 'hyphenStartOrEnd'],
['alice-', 'bsky.social', 'hyphenStartOrEnd'],
['%%%', 'bsky.social', 'handleChars'],
['1234567890123456789', 'bsky.social', 'frontLength'],
['1234567890123456789', 'bsky.social', 'frontLengthNotTooLong'],
[
'1234567890123456789',
'my-custom-pds-with-long-name.social',
'frontLength',
'frontLengthNotTooLong',
],
['al', 'my-custom-pds-with-long-name.social', 'frontLength'],
['al', 'my-custom-pds-with-long-name.social', 'frontLengthNotTooShort'],
['a'.repeat(300), 'toolong.com', 'totalLength'],
] satisfies [string, string, keyof IsValidHandle][]
it.each(invalid)(
@@ -32,6 +32,7 @@ describe('getMentionAt', () => {
['@alice hello', 7, undefined],
['alice@alice', 0, undefined],
['alice@alice', 6, undefined],
['hello @alice-com goodbye', 8, 'alice-com'],
]
it.each(cases)(
@@ -72,6 +73,7 @@ describe('insertMentionAt', () => {
['@alice hello', 7, '@alice hello'],
['alice@alice', 0, 'alice@alice'],
['alice@alice', 6, 'alice@alice'],
['hello @alice-com goodbye', 10, 'hello @alice.com goodbye'],
]
it.each(cases)(
+13 -11
View File
@@ -26,12 +26,7 @@ module.exports = function (_config) {
...(IS_DEV || IS_TESTFLIGHT ? [] : []),
]
const UPDATES_CHANNEL = IS_TESTFLIGHT
? 'testflight'
: IS_PRODUCTION
? 'production'
: undefined
const UPDATES_ENABLED = !!UPDATES_CHANNEL
const UPDATES_ENABLED = IS_TESTFLIGHT || IS_PRODUCTION
const USE_SENTRY = Boolean(process.env.SENTRY_AUTH_TOKEN)
@@ -190,7 +185,6 @@ module.exports = function (_config) {
}
: undefined,
checkAutomatically: 'NEVER',
channel: UPDATES_CHANNEL,
},
plugins: [
'expo-video',
@@ -219,7 +213,7 @@ module.exports = function (_config) {
compileSdkVersion: 35,
targetSdkVersion: 35,
buildToolsVersion: '35.0.0',
newArchEnabled: true,
newArchEnabled: false,
},
},
],
@@ -240,8 +234,9 @@ module.exports = function (_config) {
],
'./plugins/starterPackAppClipExtension/withStarterPackAppClip.js',
'./plugins/withGradleJVMHeapSizeIncrease.js',
'./plugins/withAndroidManifestPlugin.js',
'./plugins/withAndroidManifestLargeHeapPlugin.js',
'./plugins/withAndroidManifestFCMIconPlugin.js',
'./plugins/withAndroidManifestIntentQueriesPlugin.js',
'./plugins/withAndroidStylesAccentColorPlugin.js',
'./plugins/withAndroidDayNightThemePlugin.js',
'./plugins/withAndroidNoJitpackPlugin.js',
@@ -256,10 +251,12 @@ module.exports = function (_config) {
// Android only
'./assets/fonts/inter/Inter-Regular.otf',
'./assets/fonts/inter/Inter-Italic.otf',
'./assets/fonts/inter/Inter-Medium.otf',
'./assets/fonts/inter/Inter-MediumItalic.otf',
'./assets/fonts/inter/Inter-SemiBold.otf',
'./assets/fonts/inter/Inter-SemiBoldItalic.otf',
'./assets/fonts/inter/Inter-ExtraBold.otf',
'./assets/fonts/inter/Inter-ExtraBoldItalic.otf',
'./assets/fonts/inter/Inter-Bold.otf',
'./assets/fonts/inter/Inter-BoldItalic.otf',
],
},
],
@@ -306,6 +303,11 @@ module.exports = function (_config) {
android: './assets/app-icons/android_icon_default_dark.png',
prerendered: true,
},
next: {
ios: './assets/app-icons/icon_default_next.png',
android: './assets/app-icons/icon_default_next.png',
prerendered: true,
},
/**
* Bluesky+ core set
Binary file not shown.

After

Width:  |  Height:  |  Size: 486 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M15.793 10.293a1 1 0 0 1 1.338-.068l.076.068 3.293 3.293a2 2 0 0 1 .138 2.677l-.138.151-3.293 3.293a1 1 0 1 1-1.414-1.414L18.086 16H8a5 5 0 0 1-5-5V5a1 1 0 0 1 2 0v6a3 3 0 0 0 3 3h10.086l-2.293-2.293-.068-.076a1 1 0 0 1 .068-1.338Z"/></svg>

After

Width:  |  Height:  |  Size: 334 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M12 2a1 1 0 0 1 0 2 5.85 5.85 0 0 0-5.802 5.08L5.143 17h13.715l-.382-2.868-.01-.102a1 1 0 0 1 1.973-.262l.02.1.532 4a1 1 0 0 1-.99 1.132h-3.357c-.905 1.747-2.606 3-4.644 3s-3.74-1.253-4.643-3H4a1 1 0 0 1-.991-1.132l1.207-9.053A7.85 7.85 0 0 1 12 2ZM9.78 19c.61.637 1.397 1 2.22 1s1.611-.363 2.22-1H9.78ZM17 2.5a1 1 0 0 1 1 1V6h2.5a1 1 0 0 1 0 2H18v2.5a1 1 0 0 1-2 0V8h-2.5a1 1 0 1 1 0-2H16V3.5a1 1 0 0 1 1-1Z"/></svg>

After

Width:  |  Height:  |  Size: 511 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M12 2a7.854 7.854 0 0 1 7.784 6.815l1.207 9.053a1 1 0 0 1-.99 1.132h-3.354c-.904 1.748-2.608 3-4.647 3-2.038 0-3.742-1.252-4.646-3H4a1.002 1.002 0 0 1-.991-1.132l1.207-9.053A7.85 7.85 0 0 1 12 2ZM9.78 19c.608.637 1.398 1 2.221 1s1.613-.363 2.222-1H9.779ZM3.193 2.104a1 1 0 0 1 1.53 1.288A9.5 9.5 0 0 0 2.72 7.464a1 1 0 0 1-1.954-.427 11.46 11.46 0 0 1 2.428-4.933Zm16.205-.122a1 1 0 0 1 1.409.122 11.5 11.5 0 0 1 2.429 4.933 1 1 0 0 1-1.954.427 9.5 9.5 0 0 0-2.006-4.072 1 1 0 0 1 .122-1.41Z"/></svg>

After

Width:  |  Height:  |  Size: 594 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16ZM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

+10 -9
View File
@@ -6,24 +6,25 @@
"dev": "vite",
"build": "tsc && vite build",
"build-snippet": "tsc --project tsconfig.snippet.json",
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src"
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@atproto/api": "0.13.6",
"@preact/preset-vite": "^2.8.2",
"@vitejs/plugin-legacy": "^5.3.2",
"preact": "^10.4.8",
"terser": "^5.30.3"
"@atproto/api": "^0.15.25",
"preact": "^10.4.8"
},
"devDependencies": {
"@preact/preset-vite": "^2.10.2",
"@vitejs/plugin-legacy": "^7.0.0",
"autoprefixer": "^10.4.19",
"eslint": "^8.19.0",
"eslint-config-preact": "^1.3.0",
"eslint-plugin-simple-import-sort": "^12.0.0",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.3",
"typescript": "^5.5.4",
"vite": "^5.2.8",
"vite-tsconfig-paths": "^4.3.2"
"terser": "^5.43.1",
"typescript": "^5.8.3",
"vite": "^7.0.4",
"vite-tsconfig-paths": "^5.1.4"
}
}
+1 -1
View File
@@ -49,7 +49,7 @@ export function Container({
}
}}>
{href && <Link href={href} />}
<div className="flex-1 px-4 pt-3 pb-2.5">{children}</div>
<div className="flex-1 px-4 pt-3 pb-2.5 max-w-full">{children}</div>
</div>
)
}
+31 -9
View File
@@ -17,8 +17,11 @@ import infoIcon from '../../assets/circleInfo_stroke2_corner0_rounded.svg'
import playIcon from '../../assets/play_filled_corner2_rounded.svg'
import starterPackIcon from '../../assets/starterPack.svg'
import {CONTENT_LABELS, labelsToInfo} from '../labels'
import {getRkey} from '../utils'
import * as bsky from '../types/bsky'
import {getRkey} from '../util/rkey'
import {getVerificationState} from '../util/verification-state'
import {Link} from './link'
import {VerificationCheck} from './verification-check'
export function Embed({
content,
@@ -75,23 +78,35 @@ export function Embed({
CONTENT_LABELS.includes(label.val),
)
const verification = getVerificationState({profile: record.author})
return (
<Link
href={`/profile/${record.author.did}/post/${getRkey(record)}`}
className="transition-colors hover:bg-neutral-100 dark:hover:bg-slate-700 border dark:border-slate-600 rounded-xl p-2 gap-1.5 w-full flex flex-col">
<div className="flex gap-1.5 items-center">
<div className="w-4 h-4 overflow-hidden rounded-full bg-neutral-300 dark:bg-slate-700 shrink-0">
<div className="w-4 h-4 rounded-full bg-neutral-300 dark:bg-slate-700 shrink-0">
<img
className="rounded-full"
src={record.author.avatar}
style={isAuthorLabeled ? {filter: 'blur(1.5px)'} : undefined}
/>
</div>
<p className="line-clamp-1 text-sm">
<span className="font-bold">{record.author.displayName}</span>
<span className="text-textLight dark:text-textDimmed ml-1">
<div className="flex flex-1 items-center shrink min-w-0 min-h-0">
<p className="block text-sm shrink-0 font-bold max-w-[70%] line-clamp-1">
{record.author.displayName?.trim() || record.author.handle}
</p>
{verification.isVerified && (
<VerificationCheck
className="ml-[3px] mt-px shrink-0 self-center"
verifier={verification.role === 'verifier'}
size={12}
/>
)}
<p className="block line-clamp-1 text-sm text-textLight dark:text-textDimmed shrink-[10] ml-1">
@{record.author.handle}
</span>
</p>
</p>
</div>
</div>
{text && <p className="text-sm">{text}</p>}
{record.embeds?.map(embed => (
@@ -404,7 +419,12 @@ function StarterPackEmbed({
}: {
content: AppBskyGraphDefs.StarterPackViewBasic
}) {
if (!AppBskyGraphStarterpack.isRecord(content.record)) {
if (
!bsky.dangerousIsType<AppBskyGraphStarterpack.Record>(
content.record,
AppBskyGraphStarterpack.isRecord,
)
) {
return null
}
@@ -443,7 +463,9 @@ function StarterPackEmbed({
}
// from #/lib/strings/starter-pack.ts
function getStarterPackImage(starterPack: AppBskyGraphDefs.StarterPackView) {
function getStarterPackImage(
starterPack: AppBskyGraphDefs.StarterPackViewBasic,
) {
const rkey = getRkey({uri: starterPack.uri})
return `https://ogcard.cdn.bsky.app/start/${starterPack.creator.did}/${rkey}`
}
+37 -15
View File
@@ -11,10 +11,15 @@ import likeIcon from '../../assets/heart2_filled_stroke2_corner0_rounded.svg'
import logo from '../../assets/logo.svg'
import repostIcon from '../../assets/repost_stroke2_corner2_rounded.svg'
import {CONTENT_LABELS} from '../labels'
import {getRkey, niceDate, prettyNumber} from '../utils'
import * as bsky from '../types/bsky'
import {niceDate} from '../util/nice-date'
import {prettyNumber} from '../util/pretty-number'
import {getRkey} from '../util/rkey'
import {getVerificationState} from '../util/verification-state'
import {Container} from './container'
import {Embed} from './embed'
import {Link} from './link'
import {VerificationCheck} from './verification-check'
interface Props {
thread: AppBskyFeedDefs.ThreadViewPost
@@ -28,16 +33,25 @@ export function Post({thread}: Props) {
)
let record: AppBskyFeedPost.Record | null = null
if (AppBskyFeedPost.isRecord(post.record)) {
if (
bsky.dangerousIsType<AppBskyFeedPost.Record>(
post.record,
AppBskyFeedPost.isRecord,
)
) {
record = post.record
}
const verification = getVerificationState({profile: post.author})
const href = `/profile/${post.author.did}/post/${getRkey(post)}`
return (
<Container href={href}>
<div className="flex-1 flex-col flex gap-2" lang={record?.langs?.[0]}>
<div className="flex gap-2.5 items-center cursor-pointer">
<Link href={`/profile/${post.author.did}`} className="rounded-full">
<div className="flex gap-2.5 items-center cursor-pointer w-full max-w-full">
<Link
href={`/profile/${post.author.did}`}
className="rounded-full shrink-0">
<div className="w-10 h-10 overflow-hidden rounded-full bg-neutral-300 dark:bg-slate-700 shrink-0">
<img
src={post.author.avatar}
@@ -45,19 +59,27 @@ export function Post({thread}: Props) {
/>
</div>
</Link>
<div>
<div className="flex flex-1 flex-col min-w-0">
<div className="flex flex-1 items-center">
<Link
href={`/profile/${post.author.did}`}
className="block font-bold text-[17px] leading-5 line-clamp-1 hover:underline underline-offset-2 text-ellipsis decoration-2">
{post.author.displayName?.trim() || post.author.handle}
</Link>
{verification.isVerified && (
<VerificationCheck
className="pl-[3px] mt-px shrink-0"
verifier={verification.role === 'verifier'}
size={15}
/>
)}
</div>
<Link
href={`/profile/${post.author.did}`}
className="font-bold text-[17px] leading-5 line-clamp-1 hover:underline underline-offset-2 decoration-2">
<p>{post.author.displayName}</p>
</Link>
<Link
href={`/profile/${post.author.did}`}
className="text-[15px] text-textLight dark:text-textDimmed hover:underline line-clamp-1">
<p>@{post.author.handle}</p>
className="block text-[15px] text-textLight dark:text-textDimmed hover:underline line-clamp-1">
@{post.author.handle}
</Link>
</div>
<div className="flex-1" />
<Link
href={href}
className="transition-transform hover:scale-110 shrink-0 self-start">
@@ -133,7 +155,7 @@ function PostContent({record}: {record: AppBskyFeedPost.Record | null}) {
<Link
key={counter}
href={segment.link.uri}
className="text-blue-400 hover:underline"
className="text-blue-500 hover:underline"
disableTracking={
!segment.link.uri.startsWith('https://bsky.app') &&
!segment.link.uri.startsWith('https://go.bsky.app')
@@ -160,7 +182,7 @@ function PostContent({record}: {record: AppBskyFeedPost.Record | null}) {
richText.push(
<Link
key={counter}
href={`/tag/${segment.tag.tag}`}
href={`/hashtag/${segment.tag.tag}`}
className="text-blue-500 hover:underline">
{segment.text}
</Link>,
@@ -0,0 +1,56 @@
import {h} from 'preact'
type IconProps = {
size: number
className?: string
}
export function VerificationCheck({
verifier,
...rest
}: {verifier: boolean} & IconProps) {
return verifier ? <VerifierCheck {...rest} /> : <VerifiedCheck {...rest} />
}
export function VerifiedCheck({size, className}: IconProps) {
return (
<svg
fill="none"
viewBox="0 0 24 24"
width={size}
height={size}
className={className}>
<circle cx="12" cy="12" r="11.5" fill="hsl(211, 99%, 53%)" />
<path
fill="#fff"
fillRule="evenodd"
clipRule="evenodd"
d="M17.659 8.175a1.361 1.361 0 0 1 0 1.925l-6.224 6.223a1.361 1.361 0 0 1-1.925 0L6.4 13.212a1.361 1.361 0 0 1 1.925-1.925l2.149 2.148 5.26-5.26a1.361 1.361 0 0 1 1.925 0Z"
/>
</svg>
)
}
export function VerifierCheck({size, className}: IconProps) {
return (
<svg
fill="none"
viewBox="0 0 24 24"
width={size}
height={size}
className={className}>
<path
fill="hsl(211, 99%, 53%)"
fillRule="evenodd"
clipRule="evenodd"
d="M8.792 1.615a4.154 4.154 0 0 1 6.416 0 4.154 4.154 0 0 0 3.146 1.515 4.154 4.154 0 0 1 4 5.017 4.154 4.154 0 0 0 .777 3.404 4.154 4.154 0 0 1-1.427 6.255 4.153 4.153 0 0 0-2.177 2.73 4.154 4.154 0 0 1-5.781 2.784 4.154 4.154 0 0 0-3.492 0 4.154 4.154 0 0 1-5.78-2.784 4.154 4.154 0 0 0-2.178-2.73A4.154 4.154 0 0 1 .87 11.551a4.154 4.154 0 0 0 .776-3.404A4.154 4.154 0 0 1 5.646 3.13a4.154 4.154 0 0 0 3.146-1.515Z"
/>
<path
fill="#fff"
fillRule="evenodd"
clipRule="evenodd"
d="M17.861 8.26a1.438 1.438 0 0 1 0 2.033l-6.571 6.571a1.437 1.437 0 0 1-2.033 0L5.97 13.58a1.438 1.438 0 0 1 2.033-2.033l2.27 2.269 5.554-5.555a1.437 1.437 0 0 1 2.033 0Z"
/>
</svg>
)
}
+10 -3
View File
@@ -14,9 +14,11 @@ import {
import {Container} from '../components/container'
import {Link} from '../components/link'
import {Post} from '../components/post'
import {niceDate} from '../utils'
import * as bsky from '../types/bsky'
import {niceDate} from '../util/nice-date'
const DEFAULT_POST = 'https://bsky.app/profile/emilyliu.me/post/3jzn6g7ixgq2y'
const DEFAULT_POST =
'https://bsky.app/profile/did:plc:vjug55kidv6sye7ykr5faxxn/post/3jzn6g7ixgq2y'
const DEFAULT_URI =
'at://did:plc:vjug55kidv6sye7ykr5faxxn/app.bsky.feed.post/3jzn6g7ixgq2y'
@@ -222,7 +224,12 @@ function Snippet({
const snippet = useMemo(() => {
const record = thread.post.record
if (!AppBskyFeedPost.isRecord(record)) {
if (
!bsky.dangerousIsType<AppBskyFeedPost.Record>(
record,
AppBskyFeedPost.isRecord,
)
) {
return ''
}
+1 -1
View File
@@ -8,7 +8,7 @@ import {applyTheme, initSystemColorMode} from '../color-mode'
import {Container} from '../components/container'
import {Link} from '../components/link'
import {Post} from '../components/post'
import {getRkey} from '../utils'
import {getRkey} from '../util/rkey'
const root = document.getElementById('app')
if (!root) throw new Error('No root element')
+49
View File
@@ -0,0 +1,49 @@
import {ValidationResult} from '@atproto/lexicon'
export * as profile from './profile'
/**
* Fast type checking without full schema validation, for use with data we
* trust, or for non-critical path use cases. Why? Our SDK's `is*` identity
* utils do not assert the type of the entire object, only the `$type` string.
*
* For full validation of the object schema, use the `validate` export from
* this file.
*
* Usage:
* ```ts
* import * as bsky from '#/types/bsky'
*
* if (bsky.dangerousIsType<AppBskyFeedPost.Record>(item, AppBskyFeedPost.isRecord)) {
* // `item` has type `$Typed<AppBskyFeedPost.Record>` here
* }
* ```
*/
export function dangerousIsType<R extends {$type?: string}>(
record: unknown,
identity: <V>(v: V) => v is V & {$type: NonNullable<R['$type']>},
): record is R {
return identity(record)
}
/**
* Fully validates the object schema, which has a performance cost.
*
* For faster checks with data we trust, like that from our app view, use the
* `dangerousIsType` export from this same file.
*
* Usage:
* ```ts
* import * as bsky from '#/types/bsky'
*
* if (bsky.validate(item, AppBskyFeedPost.validateRecord)) {
* // `item` has type `$Typed<AppBskyFeedPost.Record>` here
* }
* ```
*/
export function validate<R extends {$type?: string}>(
record: unknown,
validator: (v: unknown) => ValidationResult<R>,
): record is R {
return validator(record).success
}
+10
View File
@@ -0,0 +1,10 @@
import {type AppBskyActorDefs, type ChatBskyActorDefs} from '@atproto/api'
/**
* Matches any profile view exported by our SDK
*/
export type AnyProfileView =
| AppBskyActorDefs.ProfileViewBasic
| AppBskyActorDefs.ProfileView
| AppBskyActorDefs.ProfileViewDetailed
| ChatBskyActorDefs.ProfileViewBasic
+11
View File
@@ -0,0 +1,11 @@
export function niceDate(date: number | string | Date) {
const d = new Date(date)
return `${d.toLocaleDateString('en-us', {
year: 'numeric',
month: 'short',
day: 'numeric',
})} at ${d.toLocaleTimeString(undefined, {
hour: 'numeric',
minute: '2-digit',
})}`
}
+152
View File
@@ -0,0 +1,152 @@
/**
* This file is a copy of what exists in the social-app
*/
import {
AppBskyEmbedExternal,
AppBskyEmbedImages,
AppBskyEmbedRecord,
AppBskyEmbedRecordWithMedia,
AppBskyEmbedVideo,
AppBskyFeedDefs,
AppBskyGraphDefs,
AppBskyLabelerDefs,
} from '@atproto/api'
export type Embed =
| {
type: 'post'
view: AppBskyEmbedRecord.ViewRecord
}
| {
type: 'post_not_found'
view: AppBskyEmbedRecord.ViewNotFound
}
| {
type: 'post_blocked'
view: AppBskyEmbedRecord.ViewBlocked
}
| {
type: 'post_detached'
view: AppBskyEmbedRecord.ViewDetached
}
| {
type: 'feed'
view: AppBskyFeedDefs.GeneratorView
}
| {
type: 'list'
view: AppBskyGraphDefs.ListView
}
| {
type: 'labeler'
view: AppBskyLabelerDefs.LabelerView
}
| {
type: 'starter_pack'
view: AppBskyGraphDefs.StarterPackViewBasic
}
| {
type: 'images'
view: AppBskyEmbedImages.View
}
| {
type: 'link'
view: AppBskyEmbedExternal.View
}
| {
type: 'video'
view: AppBskyEmbedVideo.View
}
| {
type: 'post_with_media'
view: Embed
media: Embed
}
| {
type: 'unknown'
view: null
}
export type EmbedType<T extends Embed['type']> = Extract<Embed, {type: T}>
export function parseEmbedRecordView({record}: AppBskyEmbedRecord.View): Embed {
if (AppBskyEmbedRecord.isViewRecord(record)) {
return {
type: 'post',
view: record,
}
} else if (AppBskyEmbedRecord.isViewNotFound(record)) {
return {
type: 'post_not_found',
view: record,
}
} else if (AppBskyEmbedRecord.isViewBlocked(record)) {
return {
type: 'post_blocked',
view: record,
}
} else if (AppBskyEmbedRecord.isViewDetached(record)) {
return {
type: 'post_detached',
view: record,
}
} else if (AppBskyFeedDefs.isGeneratorView(record)) {
return {
type: 'feed',
view: record,
}
} else if (AppBskyGraphDefs.isListView(record)) {
return {
type: 'list',
view: record,
}
} else if (AppBskyLabelerDefs.isLabelerView(record)) {
return {
type: 'labeler',
view: record,
}
} else if (AppBskyGraphDefs.isStarterPackViewBasic(record)) {
return {
type: 'starter_pack',
view: record,
}
} else {
return {
type: 'unknown',
view: null,
}
}
}
export function parseEmbed(embed: AppBskyFeedDefs.PostView['embed']): Embed {
if (AppBskyEmbedImages.isView(embed)) {
return {
type: 'images',
view: embed,
}
} else if (AppBskyEmbedExternal.isView(embed)) {
return {
type: 'link',
view: embed,
}
} else if (AppBskyEmbedVideo.isView(embed)) {
return {
type: 'video',
view: embed,
}
} else if (AppBskyEmbedRecord.isView(embed)) {
return parseEmbedRecordView(embed)
} else if (AppBskyEmbedRecordWithMedia.isView(embed)) {
return {
type: 'post_with_media',
view: parseEmbedRecordView(embed.record),
media: parseEmbed(embed.media),
}
} else {
return {
type: 'unknown',
view: null,
}
}
}
+9
View File
@@ -0,0 +1,9 @@
const formatter = new Intl.NumberFormat('en-US', {
notation: 'compact',
maximumFractionDigits: 1,
roundingMode: 'trunc',
})
export function prettyNumber(number: number) {
return formatter.format(number)
}
+6
View File
@@ -0,0 +1,6 @@
import {AtUri} from '@atproto/api'
export function getRkey({uri}: {uri: string}): string {
const at = new AtUri(uri)
return at.rkey
}
+31
View File
@@ -0,0 +1,31 @@
import * as bsky from '../types/bsky'
export type VerificationState = {
role: 'default' | 'verifier'
isVerified: boolean
}
export function getVerificationState({
profile,
}: {
profile?: bsky.profile.AnyProfileView
}): VerificationState {
if (!profile || !profile.verification) {
return {
role: 'default',
isVerified: false,
}
}
const {verifiedStatus, trustedVerifierStatus} = profile.verification
const isVerifiedUser = ['valid', 'invalid'].includes(verifiedStatus)
const isVerifierUser = ['valid', 'invalid'].includes(trustedVerifierStatus)
const isVerified =
(isVerifiedUser && verifiedStatus === 'valid') ||
(isVerifierUser && trustedVerifierStatus === 'valid')
return {
role: isVerifierUser ? 'verifier' : 'default',
isVerified,
}
}
-28
View File
@@ -1,28 +0,0 @@
import {AtUri} from '@atproto/api'
export function niceDate(date: number | string | Date) {
const d = new Date(date)
return `${d.toLocaleDateString('en-us', {
year: 'numeric',
month: 'short',
day: 'numeric',
})} at ${d.toLocaleTimeString(undefined, {
hour: 'numeric',
minute: '2-digit',
})}`
}
export function getRkey({uri}: {uri: string}): string {
const at = new AtUri(uri)
return at.rkey
}
const formatter = new Intl.NumberFormat('en-US', {
notation: 'compact',
maximumFractionDigits: 1,
roundingMode: 'trunc',
})
export function prettyNumber(number: number) {
return formatter.format(number)
}
+1 -3
View File
@@ -1,9 +1,7 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
darkMode: ['variant', [
'&:is(.dark *):not(:is(.dark .light *))',
]],
darkMode: ['variant', ['&:is(.dark *):not(:is(.dark .light *))']],
theme: {
extend: {
colors: {
+2 -2
View File
@@ -10,7 +10,7 @@
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
@@ -19,5 +19,5 @@
"jsxFragmentFactory": "Fragment",
"downlevelIteration": true
},
"include": ["src", "snippet", "vite.config.ts"]
"include": ["src", "snippet", "vite.config.ts", "*.config.cjs", ".eslintrc.cjs"]
}
-1
View File
@@ -1,4 +1,3 @@
{
"compilerOptions": {
"target": "ES5",
+1192 -1220
View File
File diff suppressed because it is too large Load Diff
+11 -8
View File
@@ -1,27 +1,30 @@
import assert from 'assert'
import {
Kysely,
KyselyPlugin,
type KyselyPlugin,
Migrator,
PluginTransformQueryArgs,
PluginTransformResultArgs,
type PluginTransformQueryArgs,
type PluginTransformResultArgs,
PostgresDialect,
QueryResult,
RootOperationNode,
UnknownRow,
type QueryResult,
type RootOperationNode,
type UnknownRow,
} from 'kysely'
import {default as Pg} from 'pg'
import {dbLogger as log} from '../logger.js'
import {default as migrations} from './migrations/index.js'
import {DbMigrationProvider} from './migrations/provider.js'
import {DbSchema} from './schema.js'
import {type DbSchema} from './schema.js'
export class Database {
migrator: Migrator
destroyed = false
constructor(public db: Kysely<DbSchema>, public cfg: PgConfig) {
constructor(
public db: Kysely<DbSchema>,
public cfg: PgConfig,
) {
this.migrator = new Migrator({
db,
migrationTableSchema: cfg.schema,
+7 -4
View File
@@ -1,11 +1,11 @@
import events from 'node:events'
import http from 'node:http'
import type http from 'node:http'
import cors from 'cors'
import express from 'express'
import {createHttpTerminator, HttpTerminator} from 'http-terminator'
import {createHttpTerminator, type HttpTerminator} from 'http-terminator'
import {Config} from './config.js'
import {type Config} from './config.js'
import {AppContext} from './context.js'
import {default as routes, errorHandler} from './routes/index.js'
@@ -17,7 +17,10 @@ export class LinkService {
public server?: http.Server
private terminator?: HttpTerminator
constructor(public app: express.Application, public ctx: AppContext) {}
constructor(
public app: express.Application,
public ctx: AppContext,
) {}
static async create(cfg: Config): Promise<LinkService> {
let app = express()
+7 -4
View File
@@ -1,10 +1,10 @@
import events from 'node:events'
import http from 'node:http'
import type http from 'node:http'
import express from 'express'
import {createHttpTerminator, HttpTerminator} from 'http-terminator'
import {createHttpTerminator, type HttpTerminator} from 'http-terminator'
import {Config} from './config.js'
import {type Config} from './config.js'
import {AppContext} from './context.js'
import {default as routes, errorHandler} from './routes/index.js'
@@ -15,7 +15,10 @@ export class CardService {
public server?: http.Server
private terminator?: HttpTerminator
constructor(public app: express.Application, public ctx: AppContext) {}
constructor(
public app: express.Application,
public ctx: AppContext,
) {}
static async create(cfg: Config): Promise<CardService> {
let app = express()
+28
View File
@@ -0,0 +1,28 @@
package main
import (
"net/url"
"github.com/flosch/pongo2/v6"
)
func init() {
pongo2.RegisterFilter("canonicalize_url", filterCanonicalizeURL)
}
func filterCanonicalizeURL(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
urlStr := in.String()
parsedURL, err := url.Parse(urlStr)
if err != nil {
// If parsing fails, return the original URL
return in, nil
}
// Remove query parameters and fragment
parsedURL.RawQuery = ""
parsedURL.Fragment = ""
// Return the cleaned URL
return pongo2.AsValue(parsedURL.String()), nil
}
+61
View File
@@ -0,0 +1,61 @@
package main
import (
"testing"
"github.com/flosch/pongo2/v6"
)
func TestCanonicalizeURLFilter(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "clean URL",
input: "https://bsky.app/profile/user",
expected: "https://bsky.app/profile/user",
},
{
name: "URL with query params",
input: "https://bsky.app/profile/user?utm_source=test",
expected: "https://bsky.app/profile/user",
},
{
name: "URL with multiple params",
input: "https://bsky.app/profile/user?utm_source=twitter&utm_campaign=test",
expected: "https://bsky.app/profile/user",
},
{
name: "URL with fragment",
input: "https://bsky.app/profile/user#section",
expected: "https://bsky.app/profile/user",
},
{
name: "URL with both params and fragment",
input: "https://bsky.app/profile/user?param=1#section",
expected: "https://bsky.app/profile/user",
},
{
name: "malformed URL",
input: "not-a-url",
expected: "not-a-url", // Should return original on error
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
inputValue := pongo2.AsValue(tt.input)
result, err := filterCanonicalizeURL(inputValue, nil)
if err != nil {
t.Errorf("filterCanonicalizeURL() error = %v", err)
return
}
if result.String() != tt.expected {
t.Errorf("filterCanonicalizeURL() = %v, want %v", result.String(), tt.expected)
}
})
}
}
+7 -1
View File
@@ -258,6 +258,7 @@ func serve(cctx *cli.Context) error {
e.GET("/feeds", server.WebGeneric)
e.GET("/notifications", server.WebGeneric)
e.GET("/notifications/settings", server.WebGeneric)
e.GET("/notifications/activity", server.WebGeneric)
e.GET("/lists", server.WebGeneric)
e.GET("/moderation", server.WebGeneric)
e.GET("/moderation/modlists", server.WebGeneric)
@@ -275,6 +276,7 @@ func serve(cctx *cli.Context) error {
e.GET("/settings/appearance", server.WebGeneric)
e.GET("/settings/account", server.WebGeneric)
e.GET("/settings/privacy-and-security", server.WebGeneric)
e.GET("/settings/privacy-and-security/activity", server.WebGeneric)
e.GET("/settings/content-and-media", server.WebGeneric)
e.GET("/settings/interests", server.WebGeneric)
e.GET("/settings/about", server.WebGeneric)
@@ -300,6 +302,7 @@ func serve(cctx *cli.Context) error {
e.GET("/support/copyright", server.WebGeneric)
e.GET("/intent/compose", server.WebGeneric)
e.GET("/intent/verify-email", server.WebGeneric)
e.GET("/intent/age-assurance", server.WebGeneric)
e.GET("/messages", server.WebGeneric)
e.GET("/messages/:conversation", server.WebGeneric)
@@ -601,9 +604,12 @@ type IPCCRequest struct {
IP string `json:"ip"`
}
type IPCCResponse struct {
CC string `json:"countryCode"`
CC string `json:"countryCode"`
AgeRestrictedGeo bool `json:"isAgeRestrictedGeo,omitempty"`
AgeBlockedGeo bool `json:"isAgeBlockedGeo,omitempty"`
}
// This product includes GeoLite2 Data created by MaxMind, available from https://www.maxmind.com.
func (srv *Server) WebIpCC(c echo.Context) error {
realIP := c.RealIP()
addr, err := netip.ParseAddr(realIP)
+7
View File
@@ -46,6 +46,13 @@ func run(args []string) {
Value: ":8100",
EnvVars: []string{"HTTP_ADDRESS"},
},
&cli.StringFlag{
Name: "metrics-address",
Usage: "Specify the local IP/port to bind the metrics server to",
Required: false,
Value: ":9090",
EnvVars: []string{"METRICS_HTTP_ADDRESS"},
},
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug mode",
+44 -9
View File
@@ -13,29 +13,36 @@ import (
"syscall"
"time"
_ "net/http/pprof"
"github.com/bluesky-social/indigo/atproto/identity"
"github.com/bluesky-social/indigo/util/cliutil"
"github.com/bluesky-social/indigo/xrpc"
"github.com/bluesky-social/social-app/bskyweb"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/labstack/echo-contrib/echoprometheus"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/klauspost/compress/gzhttp"
"github.com/klauspost/compress/gzip"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/urfave/cli/v2"
)
type Server struct {
echo *echo.Echo
httpd *http.Server
xrpcc *xrpc.Client
dir identity.Directory
echo *echo.Echo
httpd *http.Server
metricsHttpd *http.Server
xrpcc *xrpc.Client
dir identity.Directory
}
func serve(cctx *cli.Context) error {
debug := cctx.Bool("debug")
httpAddress := cctx.String("http-address")
appviewHost := cctx.String("appview-host")
metricsAddress := cctx.String("metrics-address")
// Echo
e := echo.New()
@@ -65,13 +72,28 @@ func serve(cctx *cli.Context) error {
return err
}
metricsMux := http.DefaultServeMux
metricsMux.Handle("/metrics", promhttp.Handler())
metricsHttpd := &http.Server{
Addr: metricsAddress,
Handler: metricsMux,
}
go func() {
if err := metricsHttpd.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Error("failed to start metrics server", "error", err)
}
}()
//
// server
//
server := &Server{
echo: e,
xrpcc: xrpcc,
dir: identity.DefaultDirectory(),
echo: e,
xrpcc: xrpcc,
dir: identity.DefaultDirectory(),
metricsHttpd: metricsHttpd,
}
// Create the HTTP server.
@@ -132,6 +154,14 @@ func serve(cctx *cli.Context) error {
RedirectCode: http.StatusFound,
}))
echoprom := echoprometheus.NewMiddlewareWithConfig(
echoprometheus.MiddlewareConfig{
DoNotUseRequestPathFor404: true,
},
)
e.Use(echoprom)
//
// configure routes
//
@@ -220,6 +250,11 @@ func (srv *Server) Shutdown() error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Shutdown metrics server too
if srv.metricsHttpd != nil {
srv.metricsHttpd.Shutdown(ctx)
}
return srv.httpd.Shutdown(ctx)
}
+21 -22
View File
@@ -1,24 +1,26 @@
module github.com/bluesky-social/social-app/bskyweb
go 1.23
toolchain go1.23.4
go 1.24.5
require (
github.com/bluesky-social/indigo v0.0.0-20250605010711-db9bb60025dc
github.com/bluesky-social/indigo v0.0.0-20250729223159-573ae927246a
github.com/flosch/pongo2/v6 v6.0.0
github.com/ipfs/go-log v1.0.5
github.com/joho/godotenv v1.5.1
github.com/klauspost/compress v1.17.3
github.com/labstack/echo/v4 v4.11.3
github.com/klauspost/compress v1.18.0
github.com/labstack/echo-contrib v0.17.4
github.com/labstack/echo/v4 v4.13.4
github.com/prometheus/client_golang v1.22.0
github.com/urfave/cli/v2 v2.25.7
)
require github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
github.com/carlmjohnson/versioninfo v0.22.5 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -26,7 +28,6 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
@@ -52,17 +53,16 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/labstack/gommon v0.4.1 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/jwx/v2 v2.0.12 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
@@ -73,10 +73,9 @@ require (
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/orandin/slog-gorm v1.3.2 // indirect
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
@@ -94,14 +93,14 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.27.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/protobuf v1.33.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gorm.io/driver/postgres v1.5.7 // indirect
gorm.io/driver/sqlite v1.5.5 // indirect
gorm.io/gorm v1.25.9 // indirect
+44 -44
View File
@@ -2,14 +2,14 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bluesky-social/indigo v0.0.0-20250605010711-db9bb60025dc h1:chbGD59Cn1mw07kbq9Uvb8WUFIr1dcoL5TOhT+I9bV4=
github.com/bluesky-social/indigo v0.0.0-20250605010711-db9bb60025dc/go.mod h1:ovyxp8AMO1Hoe838vMJUbqHTZaAR8ABM3g3TXu+A5Ng=
github.com/bluesky-social/indigo v0.0.0-20250729223159-573ae927246a h1:S12KN45uIkRglMHC8PqD/Vsz0+u3KbIaBF/6rit8/Pg=
github.com/bluesky-social/indigo v0.0.0-20250729223159-573ae927246a/go.mod h1:0XUyOCRtL4/OiyeqMTmr6RlVHQMDgw3LS7CfibuZR5Q=
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc=
github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@@ -33,10 +33,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -102,8 +100,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -113,10 +111,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.11.3 h1:Upyu3olaqSHkCjs1EJJwQ3WId8b8b1hxbogyommKktM=
github.com/labstack/echo/v4 v4.11.3/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws=
github.com/labstack/gommon v0.4.1 h1:gqEff0p/hTENGMABzezPoPSRtIh1Cvw0ueMOe0/dfOk=
github.com/labstack/gommon v0.4.1/go.mod h1:TyTrpPqxR5KMk8LKVtLmfMjeQ5FEkBYdxLYPw/WfrOM=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/labstack/echo-contrib v0.17.4 h1:g5mfsrJfJTKv+F5uNKCyrjLK7js+ZW6HTjg4FnDxxgk=
github.com/labstack/echo-contrib v0.17.4/go.mod h1:9O7ZPAHUeMGTOAfg80YqQduHzt0CzLak36PZRldYrZ0=
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
@@ -130,16 +132,13 @@ github.com/lestrrat-go/jwx/v2 v2.0.12/go.mod h1:Mq4KN1mM7bp+5z/W5HS8aCNs5RKZ911G
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
@@ -154,6 +153,8 @@ github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7B
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/orandin/slog-gorm v1.3.2 h1:C0lKDQPAx/pF+8K2HL7bdShPwOEJpPM0Bn80zTzxU1g=
@@ -163,14 +164,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
@@ -197,8 +198,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
@@ -252,8 +253,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -271,16 +272,16 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -292,13 +293,12 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -310,10 +310,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -332,8 +332,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+2
View File
@@ -8,6 +8,7 @@
Preconnect to essential domains
-->
<link rel="preconnect" href="https://bsky.social">
<link rel="preconnect" href="https://go.bsky.app">
<title>{%- block head_title -%}Bluesky{%- endblock -%}</title>
<!-- Hello Humans! API docs at https://atproto.com -->
@@ -94,6 +95,7 @@
<meta name="application-name" content="Bluesky">
<meta name="generator" content="bskyweb">
<meta property="og:site_name" content="Bluesky Social" />
<meta name="twitter:site" content="@bluesky" />
<link type="application/activity+json" href="" />
{% block html_head_extra -%}{%- endblock %}
+1 -1
View File
@@ -12,11 +12,11 @@
<meta property="og:url" content="https://bsky.app" />
<meta name="twitter:url" content="https://bsky.app" />
<link rel="canonical" href="https://bsky.app" />
<meta property="og:image" content="https://bsky.app/static/social-card-default-gradient.png" />
<meta property="twitter:image" content="https://bsky.app/static/social-card-default-gradient.png" />
<meta name="twitter:site" content="@bluesky" />
<meta name="twitter:card" content="summary_large_image" />
{%- endblock %}
+5 -1
View File
@@ -14,6 +14,7 @@
<meta property="profile:username" content="{{ profileView.Handle }}">
{%- if requestURI %}
<meta property="og:url" content="{{ requestURI }}">
<link rel="canonical" href="{{ requestURI|canonicalize_url }}" />
{% endif -%}
{%- if postView.Author.DisplayName %}
<meta property="og:title" content="{{ postView.Author.DisplayName }} (@{{ postView.Author.Handle }})">
@@ -23,15 +24,18 @@
{%- if postText %}
<meta name="description" content="{{ postText }}">
<meta property="og:description" content="{{ postText }}">
<meta property="twitter:description" content="{{ postText }}">
{% endif -%}
{%- if imgThumbUrls %}
{% for imgThumbUrl in imgThumbUrls %}
<meta property="og:image" content="{{ imgThumbUrl }}">
<meta property="twitter:image" content="{{ imgThumbUrl }}">
{% endfor %}
<meta name="twitter:card" content="summary_large_image">
{%- elif postView.Author.Avatar %}
{# Don't use avatar image in cards; usually looks bad #}
<meta name="twitter:card" content="summary">
<meta property="og:image" content="{{ postView.Author.Avatar }}">
<meta property="twitter:image" content="{{ postView.Author.Avatar }}">
{% endif %}
<meta name="twitter:label1" content="Posted At">
<meta name="twitter:value1" content="{{ postView.IndexedAt }}">
+1
View File
@@ -15,6 +15,7 @@
<meta property="profile:username" content="{{ profileView.Handle }}">
{%- if requestURI %}
<meta property="og:url" content="{{ requestURI }}">
<link rel="canonical" href="{{ requestURI|canonicalize_url }}" />
{% endif -%}
{%- if profileView.DisplayName %}
<meta property="og:title" content="{{ profileView.DisplayName }} (@{{ profileView.Handle }})">
+2 -2
View File
@@ -89,9 +89,9 @@ If you change `SENTRY_AUTH_TOKEN`, you need to do `yarn prebuild` before running
### Adding bitdrift
Adding bitdirft is NOT required. You can keep `BITDRIFT_API_KEY=` in `.env` which will avoid initializing bitdrift during startup.
Adding bitdrift is NOT required. You can keep `EXPO_PUBLIC_BITDRIFT_API_KEY=` in `.env` which will avoid initializing bitdrift during startup.
However, if you're a part of the Bluesky team and want to enable bitdrift, fill in `BITDRIFT_API_KEY` in your `.env` to enable bitdrift.
However, if you're a part of the Bluesky team and want to enable bitdrift, fill in `EXPO_PUBLIC_BITDRIFT_API_KEY` in your `.env` to enable bitdrift.
### Adding and Updating Locales
+3 -1
View File
@@ -1,5 +1,5 @@
import {AtUri, BskyAgent} from '@atproto/api'
import {TestBsky, TestNetwork} from '@atproto/dev-env'
import {type TestBsky, TestNetwork} from '@atproto/dev-env'
import fs from 'fs'
import net from 'net'
import path from 'path'
@@ -13,6 +13,7 @@ export interface TestUser {
}
export interface TestPDS {
appviewDid: string
pdsUrl: string
mocker: Mocker
close: () => Promise<void>
@@ -112,6 +113,7 @@ export async function createServer(
)
return {
appviewDid: testNet.bsky.serverDid,
pdsUrl,
mocker: new Mocker(testNet, pdsUrl, pic),
async close() {
+7 -7
View File
@@ -43,7 +43,7 @@ class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDele
let payload = try? JSONDecoder().decode(WebViewActionPayload.self, from: data) else {
return
}
switch payload.action {
case .present:
self.presentAppStoreOverlay()
@@ -65,18 +65,18 @@ class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDele
guard let url = navigationAction.request.url else {
return .allow
}
// Store the previous one to compare later, but only set starterPackUrl when we find the right one
prevUrl = url
// pathComponents starts with "/" as the first component, then each path name. so...
// ["/", "start", "name", "rkey"]
if isStarterPackUrl(url){
if isStarterPackUrl(url) {
self.starterPackUrl = url
}
return .allow
}
func isStarterPackUrl(_ url: URL) -> Bool {
var host: String?
if #available(iOS 16.0, *) {
@@ -84,11 +84,11 @@ class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDele
} else {
host = url.host
}
switch host {
case "bsky.app":
if url.pathComponents.count == 4,
(url.pathComponents[1] == "start" || url.pathComponents[1] == "starter-pack") {
url.pathComponents[1] == "start" || url.pathComponents[1] == "starter-pack" {
return true
}
return false
@@ -19,7 +19,6 @@ import expo.modules.kotlin.AppContext
import expo.modules.kotlin.viewevent.EventDispatcher
import expo.modules.kotlin.views.ExpoView
class BottomSheetView(
context: Context,
appContext: AppContext,
@@ -31,12 +30,14 @@ class BottomSheetView(
private lateinit var dialogRootViewGroup: DialogRootViewGroup
private var eventDispatcher: EventDispatcher? = null
private val rawScreenHeight = context.resources.displayMetrics.heightPixels.toFloat()
private val rawScreenHeight =
context.resources.displayMetrics.heightPixels
.toFloat()
private val safeScreenHeight = (rawScreenHeight - getNavigationBarHeight()).toFloat()
private fun getNavigationBarHeight(): Int {
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
return if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else 0
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
return if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else 0
}
private val onAttemptDismiss by EventDispatcher()
@@ -45,7 +46,7 @@ class BottomSheetView(
// Props
var disableDrag = false
set (value) {
set(value) {
field = value
this.setDraggable(!value)
}
@@ -157,8 +158,8 @@ class BottomSheetView(
// Presentation
private fun getHalfExpandedRatio(contentHeight: Float): Float {
return when {
private fun getHalfExpandedRatio(contentHeight: Float): Float =
when {
// Full height sheets
contentHeight >= safeScreenHeight -> 0.99f
// Medium height sheets (>50% but <100%)
@@ -168,7 +169,6 @@ class BottomSheetView(
else ->
this.clampRatio(this.getTargetHeight() / rawScreenHeight)
}
}
private fun present() {
if (this.isOpen || this.isOpening || this.isClosing) return
@@ -139,7 +139,10 @@ class DialogRootViewGroup(
return super.onHoverEvent(event)
}
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
override fun onChildStartedNativeGesture(
childView: View?,
ev: MotionEvent,
) {
eventDispatcher?.let { jSTouchDispatcher.onChildStartedNativeGesture(ev, it) }
jSPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher)
}
@@ -5,6 +5,7 @@ import {createPortalGroup_INTERNAL} from './lib/Portal'
type PortalContext = React.ElementType<{children: React.ReactNode}>
export const Context = React.createContext({} as PortalContext)
Context.displayName = 'BottomSheetPortalContext'
export const useBottomSheetPortal_INTERNAL = () => React.useContext(Context)
+1
View File
@@ -18,6 +18,7 @@ export function createPortalGroup_INTERNAL() {
append: () => {},
remove: () => {},
})
Context.displayName = 'BottomSheetPortalContext'
function Provider(props: React.PropsWithChildren<{}>) {
const map = React.useRef<ComponentMap>({})
@@ -15,6 +15,8 @@ class BackgroundNotificationHandler(
if (remoteMessage.data["reason"] == "chat-message") {
mutateWithChatMessage(remoteMessage)
} else {
mutateWithOtherReason(remoteMessage)
}
notifInterface.showMessage(remoteMessage)
@@ -39,4 +41,17 @@ class BackgroundNotificationHandler(
// TODO - Remove this once we have more backend capability
remoteMessage.data["badge"] = null
}
private fun mutateWithOtherReason(remoteMessage: RemoteMessage) {
// If oreo or higher
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
// If one of "like", "repost", "follow", "mention", "reply", "quote", "like-via-repost", "repost-via-repost", "subscribed-post"
// assign to it's eponymous channel. otherwise do nothing, let expo handle it
when (remoteMessage.data["reason"]) {
"like", "repost", "follow", "mention", "reply", "quote", "like-via-repost", "repost-via-repost", "subscribed-post" -> {
remoteMessage.data["channelId"] = remoteMessage.data["reason"]
}
}
}
}
}
@@ -16,8 +16,8 @@ import expo.modules.kotlin.viewevent.EventDispatcher
import expo.modules.kotlin.views.ExpoView
class GifView(
context: Context,
appContext: AppContext,
context: Context,
appContext: AppContext,
) : ExpoView(context, appContext) {
// Events
private val onPlayerStateChange by EventDispatcher()
@@ -82,65 +82,65 @@ class GifView(
}
this.webpRequest =
glide.load(source)
.diskCacheStrategy(DiskCacheStrategy.DATA)
.skipMemoryCache(false)
.listener(
object : RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
placeholderRequest?.let { glide.clear(it) }
return false
}
glide
.load(source)
.diskCacheStrategy(DiskCacheStrategy.DATA)
.skipMemoryCache(false)
.listener(
object : RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean,
): Boolean {
placeholderRequest?.let { glide.clear(it) }
return false
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean = true
}
)
.into(this.imageView)
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>,
isFirstResource: Boolean,
): Boolean = true
},
).into(this.imageView)
if (this.imageView.drawable == null || this.imageView.drawable !is Animatable) {
this.placeholderRequest =
glide.load(placeholderSource)
.diskCacheStrategy(DiskCacheStrategy.DATA)
// Let's not bloat the memory cache with placeholders
.skipMemoryCache(true)
.listener(
object : RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
// Incase this request finishes after the webp, let's just not set
// the drawable. This shouldn't happen because the request should
// get cancelled
if (imageView.drawable == null) {
imageView.setImageDrawable(resource)
}
return true
}
glide
.load(placeholderSource)
.diskCacheStrategy(DiskCacheStrategy.DATA)
// Let's not bloat the memory cache with placeholders
.skipMemoryCache(true)
.listener(
object : RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean,
): Boolean {
// Incase this request finishes after the webp, let's just not set
// the drawable. This shouldn't happen because the request should
// get cancelled
if (imageView.drawable == null) {
imageView.setImageDrawable(resource)
}
return true
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean = true
},
)
.submit()
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>,
isFirstResource: Boolean,
): Boolean = true
},
).submit()
}
}
@@ -174,10 +174,10 @@ class GifView(
fun firePlayerStateChange() {
onPlayerStateChange(
mapOf(
"isPlaying" to this.isPlaying,
"isLoaded" to this.isLoaded,
),
mapOf(
"isPlaying" to this.isPlaying,
"isLoaded" to this.isLoaded,
),
)
}
@@ -5,11 +5,12 @@ import expo.modules.kotlin.modules.ModuleDefinition
import java.net.URL
class EmojiPickerModule : Module() {
override fun definition() = ModuleDefinition {
Name("EmojiPicker")
override fun definition() =
ModuleDefinition {
Name("EmojiPicker")
View(EmojiPickerModuleView::class) {
Events("onEmojiSelected")
}
View(EmojiPickerModuleView::class) {
Events("onEmojiSelected")
}
}
}
@@ -8,33 +8,35 @@ import expo.modules.kotlin.AppContext
import expo.modules.kotlin.viewevent.EventDispatcher
import expo.modules.kotlin.views.ExpoView
@SuppressLint("ViewConstructor")
class EmojiPickerModuleView(context: Context, appContext: AppContext) :
ExpoView(context, appContext) {
private var emojiView: EmojiPickerView = EmojiPickerView(context)
private val onEmojiSelected by EventDispatcher()
class EmojiPickerModuleView(
context: Context,
appContext: AppContext,
) : ExpoView(context, appContext) {
private var emojiView: EmojiPickerView = EmojiPickerView(context)
private val onEmojiSelected by EventDispatcher()
init {
setupView()
init {
setupView()
}
private fun setupView() {
addView(
emojiView,
LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT,
),
)
emojiView.setOnEmojiPickedListener { emoji ->
onEmojiSelected(mapOf("emoji" to emoji.emoji))
}
}
private fun setupView() {
addView(
emojiView, LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
)
)
emojiView.setOnEmojiPickedListener { emoji ->
onEmojiSelected(mapOf("emoji" to emoji.emoji))
}
}
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
removeView(emojiView)
setupView()
}
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
removeView(emojiView)
setupView()
}
}

Some files were not shown because too many files have changed in this diff Show More