Merge remote-tracking branch 'origin/main' into samuel/value-prop-pager
* origin/main: (28 commits) fix android admonition flex collapse issue (#9120) Keep the screen awake on the video feed (#9146) Add accessibilityRole to single images (#9148) Fix chat request buttons not moving with swipe gesture (#9155) fix hider alignment in thread (#9168) move aspect ratio to atom (#9171) fix background colors (#9174) Placeholder style tweaks (#9107) Tweak greens (#9177) add 10% sample rate to sentry (#9182) Ship activation experiments (#9170) Add validation to threadgate records, check for max hidden replies (#9178) Nightly source-language update reply button in feeds opens thread (#9143) Fix language prompt text wrap issue (#9175) Auto-select search results tab (#9159) fix: copy-paste mistake and more idiomatic structured data format fix: show both DisplayName and Handle in google structured data (or only Handle if DisplayName not set) [16KB] use 16kb-compatible fork of react-native-mmkv (#9150) nit ...
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
## Run / Test
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
cd bskyembed
|
||||
yarn
|
||||
```
|
||||
|
||||
Run the dev server:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
You can see the embed homepage at http://localhost:5173
|
||||
|
||||
### Testbed
|
||||
|
||||
In another terminal window, run the snippet dev script:
|
||||
|
||||
```bash
|
||||
yarn dev-snippet
|
||||
```
|
||||
|
||||
You can then see the testbed page at http://localhost:5173/test
|
||||
@@ -4,6 +4,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev-snippet": "tsc --project tsconfig.snippet.json && serve -s dist -p 3000 -n",
|
||||
"build": "tsc && vite build",
|
||||
"build-snippet": "tsc --project tsconfig.snippet.json",
|
||||
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src",
|
||||
@@ -21,6 +22,7 @@
|
||||
"eslint-config-preact": "^1.3.0",
|
||||
"eslint-plugin-simple-import-sort": "^12.0.0",
|
||||
"postcss": "^8.4.38",
|
||||
"serve": "^14.2.5",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"terser": "^5.43.1",
|
||||
"typescript": "^5.8.3",
|
||||
|
||||
@@ -3,9 +3,19 @@ interface Window {
|
||||
bluesky: {
|
||||
scan: (element?: Pick<Element, 'querySelectorAll'>) => void
|
||||
}
|
||||
BSKY_DEV_EMBED_URL?: string
|
||||
}
|
||||
|
||||
const EMBED_URL = 'https://embed.bsky.app'
|
||||
/**
|
||||
* Allow url to be overwritten during development
|
||||
*/
|
||||
const IS_DEV =
|
||||
window.location.protocol === 'file:' ||
|
||||
window.location.hostname === 'localhost'
|
||||
const EMBED_URL =
|
||||
IS_DEV && window.BSKY_DEV_EMBED_URL
|
||||
? window.BSKY_DEV_EMBED_URL
|
||||
: 'https://embed.bsky.app'
|
||||
|
||||
window.bluesky = window.bluesky || {
|
||||
scan,
|
||||
|
||||
@@ -330,7 +330,7 @@ function ExternalEmbed({
|
||||
{content.external.thumb && (
|
||||
<img
|
||||
src={content.external.thumb}
|
||||
className="aspect-[1.91/1] object-cover"
|
||||
className="aspect-[1200/630] object-cover"
|
||||
/>
|
||||
)}
|
||||
<div className="py-3 px-4">
|
||||
@@ -435,7 +435,7 @@ function StarterPackEmbed({
|
||||
<Link
|
||||
href={starterPackHref}
|
||||
className="w-full rounded-xl overflow-hidden border dark:border-slate-600 flex flex-col items-stretch">
|
||||
<img src={imageUri} className="aspect-[1.91/1] object-cover" />
|
||||
<img src={imageUri} className="aspect-[1200/630] object-cover" />
|
||||
<div className="py-3 px-4">
|
||||
<div className="flex space-x-2 items-center">
|
||||
<img src={starterPackIcon} className="w-10 h-10" />
|
||||
|
||||
+1054
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,40 @@
|
||||
import fs from 'node:fs'
|
||||
import {resolve} from 'node:path'
|
||||
|
||||
import preact from '@preact/preset-vite'
|
||||
import legacy from '@vitejs/plugin-legacy'
|
||||
import type {UserConfig} from 'vite'
|
||||
import type {Plugin, UserConfig} from 'vite'
|
||||
import paths from 'vite-tsconfig-paths'
|
||||
|
||||
/**
|
||||
* World's hackiest router, for dev only. Serves `/post.html` to requests that start with `/embed/`
|
||||
*/
|
||||
function devOnlyRouter(): Plugin {
|
||||
return {
|
||||
name: 'embed-to-post-html',
|
||||
configureServer(server) {
|
||||
server.middlewares.use((req, res, next) => {
|
||||
const url = req.url || ''
|
||||
if (!url.startsWith('/embed/')) return next()
|
||||
|
||||
const html = fs.readFileSync(
|
||||
resolve(process.cwd(), 'post.html'),
|
||||
'utf8',
|
||||
)
|
||||
|
||||
server
|
||||
.transformIndexHtml(url, html)
|
||||
.then(transformed => {
|
||||
res.statusCode = 200
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
res.end(transformed)
|
||||
})
|
||||
.catch(next)
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const config: UserConfig = {
|
||||
plugins: [
|
||||
preact(),
|
||||
@@ -12,6 +42,7 @@ const config: UserConfig = {
|
||||
legacy({
|
||||
targets: ['defaults', 'not IE 11'],
|
||||
}),
|
||||
devOnlyRouter(),
|
||||
],
|
||||
build: {
|
||||
assetsDir: 'static',
|
||||
|
||||
+376
-5
@@ -1447,6 +1447,11 @@
|
||||
regenerator-runtime "^0.14.1"
|
||||
systemjs "^6.15.1"
|
||||
|
||||
"@zeit/schemas@2.36.0":
|
||||
version "2.36.0"
|
||||
resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.36.0.tgz#7a1b53f4091e18d0b404873ea3e3c83589c765f2"
|
||||
integrity sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==
|
||||
|
||||
acorn-jsx@^5.3.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||
@@ -1462,6 +1467,16 @@ acorn@^8.9.0:
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
|
||||
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
|
||||
|
||||
ajv@8.12.0:
|
||||
version "8.12.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
|
||||
integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.1"
|
||||
json-schema-traverse "^1.0.0"
|
||||
require-from-string "^2.0.2"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
ajv@^6.12.4:
|
||||
version "6.12.6"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||
@@ -1472,6 +1487,13 @@ ajv@^6.12.4:
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
ansi-align@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59"
|
||||
integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==
|
||||
dependencies:
|
||||
string-width "^4.1.0"
|
||||
|
||||
ansi-regex@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
|
||||
@@ -1507,7 +1529,12 @@ anymatch@~3.1.2:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
arg@^5.0.2:
|
||||
arch@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
|
||||
integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
|
||||
|
||||
arg@5.0.2, arg@^5.0.2:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
|
||||
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
|
||||
@@ -1684,6 +1711,20 @@ boolbase@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
|
||||
|
||||
boxen@7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32"
|
||||
integrity sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==
|
||||
dependencies:
|
||||
ansi-align "^3.0.1"
|
||||
camelcase "^7.0.0"
|
||||
chalk "^5.0.1"
|
||||
cli-boxes "^3.0.0"
|
||||
string-width "^5.1.2"
|
||||
type-fest "^2.13.0"
|
||||
widest-line "^4.0.1"
|
||||
wrap-ansi "^8.0.1"
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
@@ -1738,6 +1779,16 @@ buffer-from@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
|
||||
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==
|
||||
|
||||
bytes@3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||
|
||||
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
||||
@@ -1759,6 +1810,11 @@ camelcase-css@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
|
||||
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
|
||||
|
||||
camelcase@^7.0.0:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048"
|
||||
integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==
|
||||
|
||||
caniuse-lite@^1.0.30001524:
|
||||
version "1.0.30001606"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz#b4d5f67ab0746a3b8b5b6d1f06e39c51beb39a9e"
|
||||
@@ -1769,7 +1825,19 @@ caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.300017
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz#22e9706422ad37aa50556af8c10e40e2d93a8b85"
|
||||
integrity sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==
|
||||
|
||||
chalk@^4.0.0:
|
||||
chalk-template@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b"
|
||||
integrity sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==
|
||||
dependencies:
|
||||
chalk "^4.1.2"
|
||||
|
||||
chalk@5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6"
|
||||
integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==
|
||||
|
||||
chalk@^4.0.0, chalk@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
@@ -1777,6 +1845,11 @@ chalk@^4.0.0:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
chalk@^5.0.1:
|
||||
version "5.6.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea"
|
||||
integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==
|
||||
|
||||
chokidar@^3.5.3:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
|
||||
@@ -1792,6 +1865,20 @@ chokidar@^3.5.3:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
cli-boxes@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145"
|
||||
integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==
|
||||
|
||||
clipboardy@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092"
|
||||
integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==
|
||||
dependencies:
|
||||
arch "^2.2.0"
|
||||
execa "^5.1.1"
|
||||
is-wsl "^2.2.0"
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
|
||||
@@ -1814,11 +1901,36 @@ commander@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
|
||||
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
|
||||
|
||||
compressible@~2.0.18:
|
||||
version "2.0.18"
|
||||
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
|
||||
integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
|
||||
dependencies:
|
||||
mime-db ">= 1.43.0 < 2"
|
||||
|
||||
compression@1.8.1:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/compression/-/compression-1.8.1.tgz#4a45d909ac16509195a9a28bd91094889c180d79"
|
||||
integrity sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
compressible "~2.0.18"
|
||||
debug "2.6.9"
|
||||
negotiator "~0.6.4"
|
||||
on-headers "~1.1.0"
|
||||
safe-buffer "5.2.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
content-disposition@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||
integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==
|
||||
|
||||
convert-source-map@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
|
||||
@@ -1845,6 +1957,15 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
cross-spawn@^7.0.3:
|
||||
version "7.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
css-select@^5.1.0:
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.2.2.tgz#01b6e8d163637bb2dd6c982ca4ed65863682786e"
|
||||
@@ -1893,6 +2014,13 @@ data-view-byte-offset@^1.0.0:
|
||||
es-errors "^1.3.0"
|
||||
is-data-view "^1.0.1"
|
||||
|
||||
debug@2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@^4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b"
|
||||
@@ -1907,6 +2035,11 @@ debug@^4.3.2:
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
deep-extend@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||
|
||||
deep-is@^0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
||||
@@ -2356,6 +2489,21 @@ esutils@^2.0.2:
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||
|
||||
execa@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
|
||||
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.3"
|
||||
get-stream "^6.0.0"
|
||||
human-signals "^2.1.0"
|
||||
is-stream "^2.0.0"
|
||||
merge-stream "^2.0.0"
|
||||
npm-run-path "^4.0.1"
|
||||
onetime "^5.1.2"
|
||||
signal-exit "^3.0.3"
|
||||
strip-final-newline "^2.0.0"
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
@@ -2496,6 +2644,11 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@
|
||||
has-symbols "^1.0.3"
|
||||
hasown "^2.0.0"
|
||||
|
||||
get-stream@^6.0.0:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
|
||||
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
|
||||
|
||||
get-symbol-description@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5"
|
||||
@@ -2631,6 +2784,11 @@ he@1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
human-signals@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
|
||||
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
|
||||
|
||||
ignore@^5.2.0:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
|
||||
@@ -2662,6 +2820,11 @@ inherits@2:
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
ini@~1.3.0:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
|
||||
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
|
||||
|
||||
internal-slot@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802"
|
||||
@@ -2741,6 +2904,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5:
|
||||
dependencies:
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-docker@^2.0.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
|
||||
integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
|
||||
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
@@ -2799,6 +2967,11 @@ is-path-inside@^3.0.3:
|
||||
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
|
||||
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
|
||||
|
||||
is-port-reachable@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d"
|
||||
integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==
|
||||
|
||||
is-regex@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
|
||||
@@ -2819,6 +2992,11 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3:
|
||||
dependencies:
|
||||
call-bind "^1.0.7"
|
||||
|
||||
is-stream@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
|
||||
integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
|
||||
|
||||
is-string@^1.0.5, is-string@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
|
||||
@@ -2860,6 +3038,13 @@ is-weakset@^2.0.3:
|
||||
call-bind "^1.0.7"
|
||||
get-intrinsic "^1.2.4"
|
||||
|
||||
is-wsl@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
|
||||
integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
|
||||
dependencies:
|
||||
is-docker "^2.0.0"
|
||||
|
||||
isarray@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
|
||||
@@ -2932,6 +3117,11 @@ json-schema-traverse@^0.4.1:
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
||||
|
||||
json-schema-traverse@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
|
||||
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
|
||||
|
||||
json-stable-stringify-without-jsonify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
|
||||
@@ -3047,6 +3237,11 @@ meow@^13.0.0:
|
||||
resolved "https://registry.yarnpkg.com/meow/-/meow-13.2.0.tgz#6b7d63f913f984063b3cc261b6e8800c4cd3474f"
|
||||
integrity sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
|
||||
|
||||
merge2@^1.3.0, merge2@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||
@@ -3060,7 +3255,29 @@ micromatch@^4.0.4, micromatch@^4.0.5:
|
||||
braces "^3.0.2"
|
||||
picomatch "^2.3.1"
|
||||
|
||||
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
"mime-db@>= 1.43.0 < 2":
|
||||
version "1.54.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
|
||||
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
|
||||
|
||||
mime-db@~1.33.0:
|
||||
version "1.33.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
|
||||
integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==
|
||||
|
||||
mime-types@2.1.18:
|
||||
version "2.1.18"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
|
||||
integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==
|
||||
dependencies:
|
||||
mime-db "~1.33.0"
|
||||
|
||||
mimic-fn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||
|
||||
minimatch@3.1.2, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
@@ -3074,11 +3291,21 @@ minimatch@^9.0.1:
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimist@^1.2.0:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||
|
||||
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4:
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
|
||||
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
@@ -3118,6 +3345,11 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||
|
||||
negotiator@~0.6.4:
|
||||
version "0.6.4"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7"
|
||||
integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==
|
||||
|
||||
node-html-parser@^6.1.12:
|
||||
version "6.1.13"
|
||||
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-6.1.13.tgz#a1df799b83df5c6743fcd92740ba14682083b7e4"
|
||||
@@ -3141,6 +3373,13 @@ normalize-range@^0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
|
||||
|
||||
npm-run-path@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
|
||||
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
|
||||
dependencies:
|
||||
path-key "^3.0.0"
|
||||
|
||||
nth-check@^2.0.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
|
||||
@@ -3215,6 +3454,11 @@ object.values@^1.1.6, object.values@^1.1.7:
|
||||
define-properties "^1.2.1"
|
||||
es-object-atoms "^1.0.0"
|
||||
|
||||
on-headers@~1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.1.0.tgz#59da4f91c45f5f989c6e4bcedc5a3b0aed70ff65"
|
||||
integrity sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
@@ -3222,6 +3466,13 @@ once@^1.3.0:
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
onetime@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
|
||||
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
|
||||
dependencies:
|
||||
mimic-fn "^2.1.0"
|
||||
|
||||
optionator@^0.9.3:
|
||||
version "0.9.3"
|
||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64"
|
||||
@@ -3265,7 +3516,12 @@ path-is-absolute@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
|
||||
|
||||
path-key@^3.1.0:
|
||||
path-is-inside@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
|
||||
integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==
|
||||
|
||||
path-key@^3.0.0, path-key@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
@@ -3283,6 +3539,11 @@ path-scurry@^1.10.2:
|
||||
lru-cache "^10.2.0"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
||||
path-to-regexp@3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.3.0.tgz#f7f31d32e8518c2660862b644414b6d5c63a611b"
|
||||
integrity sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==
|
||||
|
||||
path-type@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||
@@ -3409,6 +3670,21 @@ queue-microtask@^1.2.2:
|
||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||
|
||||
range-parser@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
|
||||
integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==
|
||||
|
||||
rc@^1.0.1, rc@^1.1.6:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||
dependencies:
|
||||
deep-extend "^0.6.0"
|
||||
ini "~1.3.0"
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
react-is@^16.13.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
@@ -3480,6 +3756,21 @@ regexpu-core@^6.2.0:
|
||||
unicode-match-property-ecmascript "^2.0.0"
|
||||
unicode-match-property-value-ecmascript "^2.1.0"
|
||||
|
||||
registry-auth-token@3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20"
|
||||
integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==
|
||||
dependencies:
|
||||
rc "^1.1.6"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
registry-url@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
|
||||
integrity sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==
|
||||
dependencies:
|
||||
rc "^1.0.1"
|
||||
|
||||
regjsgen@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab"
|
||||
@@ -3492,6 +3783,11 @@ regjsparser@^0.12.0:
|
||||
dependencies:
|
||||
jsesc "~3.0.2"
|
||||
|
||||
require-from-string@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
|
||||
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
|
||||
|
||||
resolve-from@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||
@@ -3582,6 +3878,11 @@ safe-array-concat@^1.1.2:
|
||||
has-symbols "^1.0.3"
|
||||
isarray "^2.0.5"
|
||||
|
||||
safe-buffer@5.2.1, safe-buffer@^5.0.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safe-regex-test@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377"
|
||||
@@ -3603,6 +3904,36 @@ semver@^7.3.7, semver@^7.5.4:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
serve-handler@6.1.6:
|
||||
version "6.1.6"
|
||||
resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.6.tgz#50803c1d3e947cd4a341d617f8209b22bd76cfa1"
|
||||
integrity sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==
|
||||
dependencies:
|
||||
bytes "3.0.0"
|
||||
content-disposition "0.5.2"
|
||||
mime-types "2.1.18"
|
||||
minimatch "3.1.2"
|
||||
path-is-inside "1.0.2"
|
||||
path-to-regexp "3.3.0"
|
||||
range-parser "1.2.0"
|
||||
|
||||
serve@^14.2.5:
|
||||
version "14.2.5"
|
||||
resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.5.tgz#569e333b99a484b3a6d25acce4a569c8c4f96373"
|
||||
integrity sha512-Qn/qMkzCcMFVPb60E/hQy+iRLpiU8PamOfOSYoAHmmF+fFFmpPpqa6Oci2iWYpTdOUM3VF+TINud7CfbQnsZbA==
|
||||
dependencies:
|
||||
"@zeit/schemas" "2.36.0"
|
||||
ajv "8.12.0"
|
||||
arg "5.0.2"
|
||||
boxen "7.0.0"
|
||||
chalk "5.0.1"
|
||||
chalk-template "0.4.0"
|
||||
clipboardy "3.0.0"
|
||||
compression "1.8.1"
|
||||
is-port-reachable "4.0.0"
|
||||
serve-handler "6.1.6"
|
||||
update-check "1.5.4"
|
||||
|
||||
set-function-length@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
|
||||
@@ -3647,6 +3978,11 @@ side-channel@^1.0.4, side-channel@^1.0.6:
|
||||
get-intrinsic "^1.2.4"
|
||||
object-inspect "^1.13.1"
|
||||
|
||||
signal-exit@^3.0.3:
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
|
||||
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
|
||||
|
||||
signal-exit@^4.0.1:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
|
||||
@@ -3791,11 +4127,21 @@ strip-ansi@^7.0.1:
|
||||
dependencies:
|
||||
ansi-regex "^6.0.1"
|
||||
|
||||
strip-final-newline@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
|
||||
|
||||
strip-json-comments@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||
|
||||
strip-json-comments@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
|
||||
|
||||
sucrase@^3.32.0:
|
||||
version "3.35.0"
|
||||
resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
|
||||
@@ -3937,6 +4283,11 @@ type-fest@^0.20.2:
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
|
||||
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
||||
|
||||
type-fest@^2.13.0:
|
||||
version "2.19.0"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
|
||||
integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==
|
||||
|
||||
typed-array-buffer@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3"
|
||||
@@ -4034,6 +4385,14 @@ update-browserslist-db@^1.0.13, update-browserslist-db@^1.1.3:
|
||||
escalade "^3.2.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
update-check@1.5.4:
|
||||
version "1.5.4"
|
||||
resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.4.tgz#5b508e259558f1ad7dbc8b4b0457d4c9d28c8743"
|
||||
integrity sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==
|
||||
dependencies:
|
||||
registry-auth-token "3.3.2"
|
||||
registry-url "3.1.0"
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
||||
@@ -4046,6 +4405,11 @@ util-deprecate@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
|
||||
|
||||
vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
|
||||
|
||||
vite-prerender-plugin@^0.5.3:
|
||||
version "0.5.11"
|
||||
resolved "https://registry.yarnpkg.com/vite-prerender-plugin/-/vite-prerender-plugin-0.5.11.tgz#83e4f29e03269dceb763fb5ec2376dcc502aa79f"
|
||||
@@ -4138,6 +4502,13 @@ which@^2.0.1:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
widest-line@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2"
|
||||
integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==
|
||||
dependencies:
|
||||
string-width "^5.0.1"
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
@@ -4147,7 +4518,7 @@ which@^2.0.1:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^8.1.0:
|
||||
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||
integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
|
||||
|
||||
@@ -458,6 +458,18 @@ func (srv *Server) WebHome(c echo.Context) error {
|
||||
return c.Render(http.StatusOK, "home.html", data)
|
||||
}
|
||||
|
||||
// Posts that include these labels will not have embeds passed to the metadata
|
||||
// template.
|
||||
var hideEmbedLabels = map[string]bool{
|
||||
"nudity": true,
|
||||
"porn": true,
|
||||
"sexual": true,
|
||||
"sexual-figurative": true,
|
||||
"graphic-media": true,
|
||||
"self-harm": true,
|
||||
"sensitive": true,
|
||||
}
|
||||
|
||||
func (srv *Server) WebPost(c echo.Context) error {
|
||||
ctx := c.Request().Context()
|
||||
data := srv.NewTemplateContext()
|
||||
@@ -512,19 +524,15 @@ func (srv *Server) WebPost(c echo.Context) error {
|
||||
postView := tpv.Thread.FeedDefs_ThreadViewPost.Post
|
||||
data["postView"] = postView
|
||||
data["requestURI"] = fmt.Sprintf("https://%s%s", req.Host, req.URL.Path)
|
||||
if postView.Embed != nil {
|
||||
if postView.Embed.EmbedImages_View != nil {
|
||||
var thumbUrls []string
|
||||
for i := range postView.Embed.EmbedImages_View.Images {
|
||||
thumbUrls = append(thumbUrls, postView.Embed.EmbedImages_View.Images[i].Thumb)
|
||||
}
|
||||
data["imgThumbUrls"] = thumbUrls
|
||||
} else if postView.Embed.EmbedRecordWithMedia_View != nil && postView.Embed.EmbedRecordWithMedia_View.Media != nil && postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View != nil {
|
||||
var thumbUrls []string
|
||||
for i := range postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View.Images {
|
||||
thumbUrls = append(thumbUrls, postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View.Images[i].Thumb)
|
||||
}
|
||||
data["imgThumbUrls"] = thumbUrls
|
||||
|
||||
// If any undesirable labels are set, the embed will not be included in
|
||||
// metadata
|
||||
isEmbedHidden := false
|
||||
for _, label := range postView.Labels {
|
||||
isNeg := label.Neg != nil && *label.Neg
|
||||
if hideEmbedLabels[label.Val] && !isNeg {
|
||||
isEmbedHidden = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,6 +540,34 @@ func (srv *Server) WebPost(c echo.Context) error {
|
||||
postRecord, ok := postView.Record.Val.(*appbsky.FeedPost)
|
||||
if ok {
|
||||
data["postText"] = ExpandPostText(postRecord)
|
||||
|
||||
if !isEmbedHidden && postRecord.Labels != nil && postRecord.Labels.LabelDefs_SelfLabels != nil {
|
||||
for _, label := range postRecord.Labels.LabelDefs_SelfLabels.Values {
|
||||
if hideEmbedLabels[label.Val] {
|
||||
isEmbedHidden = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if postView.Embed != nil && !isEmbedHidden {
|
||||
hasImages := postView.Embed.EmbedImages_View != nil
|
||||
hasMedia := postView.Embed.EmbedRecordWithMedia_View != nil && postView.Embed.EmbedRecordWithMedia_View.Media != nil && postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View != nil
|
||||
|
||||
if hasImages {
|
||||
var thumbUrls []string
|
||||
for i := range postView.Embed.EmbedImages_View.Images {
|
||||
thumbUrls = append(thumbUrls, postView.Embed.EmbedImages_View.Images[i].Thumb)
|
||||
}
|
||||
data["imgThumbUrls"] = thumbUrls
|
||||
} else if hasMedia {
|
||||
var thumbUrls []string
|
||||
for i := range postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View.Images {
|
||||
thumbUrls = append(thumbUrls, postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View.Images[i].Thumb)
|
||||
}
|
||||
data["imgThumbUrls"] = thumbUrls
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,12 @@
|
||||
"@type": "DiscussionForumPosting",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
{%- if postView.Author.DisplayName %}
|
||||
"name": "{{ postView.Author.DisplayName }}",
|
||||
"alternateName": "@{{ postView.Author.Handle }}",
|
||||
{% else %}
|
||||
"name": "@{{ postView.Author.Handle }}",
|
||||
{% endif -%}
|
||||
"url": "https://bsky.app/profile/{{ postView.Author.Handle }}"
|
||||
},
|
||||
{%- if postText %}
|
||||
|
||||
@@ -59,8 +59,12 @@
|
||||
"dateCreated": "{{ profileView.CreatedAt }}",
|
||||
"mainEntity": {
|
||||
"@type": "Person",
|
||||
{%- if profileView.DisplayName %}
|
||||
"name": "{{ profileView.DisplayName }}",
|
||||
"alternateName": "@{{ profileView.Handle }}",
|
||||
{% else %}
|
||||
"name": "@{{ profileView.Handle }}",
|
||||
{% endif -%}
|
||||
"identifier": "{{ profileView.Did }}",
|
||||
"description": "{{ profileView.Description }}",
|
||||
"image": "{{ profileView.Avatar }}",
|
||||
|
||||
+2
-1
@@ -145,6 +145,7 @@
|
||||
"expo-image-manipulator": "~14.0.7",
|
||||
"expo-image-picker": "~17.0.8",
|
||||
"expo-intent-launcher": "~13.0.7",
|
||||
"expo-keep-awake": "^15.0.7",
|
||||
"expo-linear-gradient": "~15.0.7",
|
||||
"expo-linking": "~8.0.8",
|
||||
"expo-localization": "~17.0.7",
|
||||
@@ -192,7 +193,7 @@
|
||||
"react-native-gesture-handler": "~2.28.0",
|
||||
"react-native-get-random-values": "~1.11.0",
|
||||
"react-native-keyboard-controller": "1.18.5",
|
||||
"react-native-mmkv": "^2.12.2",
|
||||
"@bsky.app/react-native-mmkv": "2.12.5",
|
||||
"react-native-pager-view": "6.8.0",
|
||||
"react-native-progress": "bluesky-social/react-native-progress",
|
||||
"react-native-qrcode-styled": "^0.3.3",
|
||||
|
||||
@@ -0,0 +1,516 @@
|
||||
diff --git a/node_modules/react-native-compressor/android/build.gradle b/node_modules/react-native-compressor/android/build.gradle
|
||||
index 5071139..84bee34 100644
|
||||
--- a/node_modules/react-native-compressor/android/build.gradle
|
||||
+++ b/node_modules/react-native-compressor/android/build.gradle
|
||||
@@ -115,7 +115,6 @@ dependencies {
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
|
||||
implementation 'org.mp4parser:isoparser:1.9.56'
|
||||
- implementation 'com.github.banketree:AndroidLame-kotlin:v0.0.1'
|
||||
implementation 'javazoom:jlayer:1.0.1'
|
||||
}
|
||||
|
||||
diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt
|
||||
deleted file mode 100644
|
||||
index 9292d3e..0000000
|
||||
--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt
|
||||
+++ /dev/null
|
||||
@@ -1,264 +0,0 @@
|
||||
-package com.reactnativecompressor.Audio
|
||||
-
|
||||
-
|
||||
-import android.annotation.SuppressLint
|
||||
-import com.facebook.react.bridge.Promise
|
||||
-import com.facebook.react.bridge.ReactApplicationContext
|
||||
-import com.facebook.react.bridge.ReadableMap
|
||||
-import com.naman14.androidlame.LameBuilder
|
||||
-import com.naman14.androidlame.WaveReader
|
||||
-import com.reactnativecompressor.Utils.MediaCache
|
||||
-import com.reactnativecompressor.Utils.Utils
|
||||
-import com.reactnativecompressor.Utils.Utils.addLog
|
||||
-import javazoom.jl.converter.Converter
|
||||
-import javazoom.jl.decoder.JavaLayerException
|
||||
-import java.io.BufferedOutputStream
|
||||
-import java.io.File
|
||||
-import java.io.FileNotFoundException
|
||||
-import java.io.FileOutputStream
|
||||
-import java.io.IOException
|
||||
-
|
||||
-class AudioCompressor {
|
||||
- companion object {
|
||||
- val TAG="AudioMain"
|
||||
- private const val OUTPUT_STREAM_BUFFER = 8192
|
||||
-
|
||||
- var outputStream: BufferedOutputStream? = null
|
||||
- var waveReader: WaveReader? = null
|
||||
- @JvmStatic
|
||||
- fun CompressAudio(
|
||||
- fileUrl: String,
|
||||
- optionMap: ReadableMap,
|
||||
- context: ReactApplicationContext,
|
||||
- promise: Promise,
|
||||
- ) {
|
||||
- val realPath = Utils.getRealPath(fileUrl, context)
|
||||
- var _fileUrl=realPath
|
||||
- val filePathWithoutFileUri = realPath!!.replace("file://", "")
|
||||
- try {
|
||||
- var wavPath=filePathWithoutFileUri;
|
||||
- var isNonWav:Boolean=false
|
||||
- if (fileUrl.endsWith(".mp4", ignoreCase = true))
|
||||
- {
|
||||
- addLog("mp4 file found")
|
||||
- val mp3Path= Utils.generateCacheFilePath("mp3", context)
|
||||
- AudioExtractor().genVideoUsingMuxer(fileUrl, mp3Path, -1, -1, true, false)
|
||||
- _fileUrl=Utils.slashifyFilePath(mp3Path)
|
||||
- wavPath= Utils.generateCacheFilePath("wav", context)
|
||||
- try {
|
||||
- val converter = Converter()
|
||||
- converter.convert(mp3Path, wavPath)
|
||||
- } catch (e: JavaLayerException) {
|
||||
- addLog("JavaLayerException error"+e.localizedMessage)
|
||||
- e.printStackTrace();
|
||||
- }
|
||||
- isNonWav=true
|
||||
- }
|
||||
- else if (!fileUrl.endsWith(".wav", ignoreCase = true))
|
||||
- {
|
||||
- addLog("non wav file found")
|
||||
- wavPath= Utils.generateCacheFilePath("wav", context)
|
||||
- try {
|
||||
- val converter = Converter()
|
||||
- converter.convert(filePathWithoutFileUri, wavPath)
|
||||
- } catch (e: JavaLayerException) {
|
||||
- addLog("JavaLayerException error"+e.localizedMessage)
|
||||
- e.printStackTrace();
|
||||
- }
|
||||
- isNonWav=true
|
||||
- }
|
||||
-
|
||||
-
|
||||
- autoCompressHelper(wavPath,filePathWithoutFileUri, optionMap,context) { mp3Path, finished ->
|
||||
- if (finished) {
|
||||
- val returnableFilePath:String="file://$mp3Path"
|
||||
- addLog("finished: " + returnableFilePath)
|
||||
- MediaCache.removeCompletedImagePath(fileUrl)
|
||||
- if(isNonWav)
|
||||
- {
|
||||
- File(wavPath).delete()
|
||||
- }
|
||||
- promise.resolve(returnableFilePath)
|
||||
- } else {
|
||||
- addLog("error: "+mp3Path)
|
||||
- promise.resolve(_fileUrl)
|
||||
- }
|
||||
- }
|
||||
- } catch (e: Exception) {
|
||||
- promise.resolve(_fileUrl)
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- @SuppressLint("WrongConstant")
|
||||
- private fun autoCompressHelper(
|
||||
- fileUrl: String,
|
||||
- actualFileUrl: String,
|
||||
- optionMap: ReadableMap,
|
||||
- context: ReactApplicationContext,
|
||||
- completeCallback: (String, Boolean) -> Unit
|
||||
- ) {
|
||||
-
|
||||
- val options = AudioHelper.fromMap(optionMap)
|
||||
- val quality = options.quality
|
||||
-
|
||||
- var isCompletedCallbackTriggered:Boolean=false
|
||||
- try {
|
||||
- var mp3Path = Utils.generateCacheFilePath("mp3", context)
|
||||
- val input = File(fileUrl)
|
||||
- val output = File(mp3Path)
|
||||
-
|
||||
- val CHUNK_SIZE = 8192
|
||||
- addLog("Initialising wav reader")
|
||||
-
|
||||
- waveReader = WaveReader(input)
|
||||
-
|
||||
- try {
|
||||
- waveReader!!.openWave()
|
||||
- } catch (e: IOException) {
|
||||
- e.printStackTrace()
|
||||
- }
|
||||
-
|
||||
- addLog("Intitialising encoder")
|
||||
-
|
||||
-
|
||||
- // for bitrate
|
||||
- var audioBitrate:Int
|
||||
- if(options.bitrate != -1)
|
||||
- {
|
||||
- audioBitrate= options.bitrate/1000
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- audioBitrate=AudioHelper.getDestinationBitrateByQuality(actualFileUrl, quality!!)
|
||||
- Utils.addLog("dest bitrate: $audioBitrate")
|
||||
- }
|
||||
-
|
||||
- var androidLame = LameBuilder();
|
||||
- androidLame.setOutBitrate(audioBitrate)
|
||||
-
|
||||
- // for channels
|
||||
- var audioChannels:Int
|
||||
- if(options.channels != -1){
|
||||
- audioChannels= options.channels!!
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- audioChannels=waveReader!!.channels
|
||||
- }
|
||||
- androidLame.setOutChannels(audioChannels)
|
||||
-
|
||||
- // for sample rate
|
||||
- androidLame.setInSampleRate(waveReader!!.sampleRate)
|
||||
- var audioSampleRate:Int
|
||||
- if(options.samplerate != -1){
|
||||
- audioSampleRate= options.samplerate!!
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- audioSampleRate=waveReader!!.sampleRate
|
||||
- }
|
||||
- androidLame.setOutSampleRate(audioSampleRate)
|
||||
- val androidLameBuild=androidLame.build()
|
||||
-
|
||||
- try {
|
||||
- outputStream = BufferedOutputStream(FileOutputStream(output), OUTPUT_STREAM_BUFFER)
|
||||
- } catch (e: FileNotFoundException) {
|
||||
- e.printStackTrace()
|
||||
- }
|
||||
-
|
||||
- var bytesRead = 0
|
||||
-
|
||||
- val buffer_l = ShortArray(CHUNK_SIZE)
|
||||
- val buffer_r = ShortArray(CHUNK_SIZE)
|
||||
- val mp3Buf = ByteArray(CHUNK_SIZE)
|
||||
-
|
||||
- val channels = waveReader!!.channels
|
||||
-
|
||||
- addLog("started encoding")
|
||||
- while (true) {
|
||||
- try {
|
||||
- if (channels == 2) {
|
||||
-
|
||||
- bytesRead = waveReader!!.read(buffer_l, buffer_r, CHUNK_SIZE)
|
||||
- addLog("bytes read=$bytesRead")
|
||||
-
|
||||
- if (bytesRead > 0) {
|
||||
-
|
||||
- var bytesEncoded = 0
|
||||
- bytesEncoded = androidLameBuild.encode(buffer_l, buffer_r, bytesRead, mp3Buf)
|
||||
- addLog("bytes encoded=$bytesEncoded")
|
||||
-
|
||||
- if (bytesEncoded > 0) {
|
||||
- try {
|
||||
- addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes")
|
||||
- outputStream!!.write(mp3Buf, 0, bytesEncoded)
|
||||
- } catch (e: IOException) {
|
||||
- e.printStackTrace()
|
||||
- }
|
||||
-
|
||||
- }
|
||||
-
|
||||
- } else
|
||||
- break
|
||||
- } else {
|
||||
-
|
||||
- bytesRead = waveReader!!.read(buffer_l, CHUNK_SIZE)
|
||||
- addLog("bytes read=$bytesRead")
|
||||
-
|
||||
- if (bytesRead > 0) {
|
||||
- var bytesEncoded = 0
|
||||
-
|
||||
- bytesEncoded = androidLameBuild.encode(buffer_l, buffer_l, bytesRead, mp3Buf)
|
||||
- addLog("bytes encoded=$bytesEncoded")
|
||||
-
|
||||
- if (bytesEncoded > 0) {
|
||||
- try {
|
||||
- addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes")
|
||||
- outputStream!!.write(mp3Buf, 0, bytesEncoded)
|
||||
- } catch (e: IOException) {
|
||||
- e.printStackTrace()
|
||||
- }
|
||||
-
|
||||
- }
|
||||
-
|
||||
- } else
|
||||
- break
|
||||
- }
|
||||
-
|
||||
-
|
||||
- } catch (e: IOException) {
|
||||
- e.printStackTrace()
|
||||
- }
|
||||
-
|
||||
- }
|
||||
-
|
||||
- addLog("flushing final mp3buffer")
|
||||
- val outputMp3buf = androidLameBuild.flush(mp3Buf)
|
||||
- addLog("flushed $outputMp3buf bytes")
|
||||
- if (outputMp3buf > 0) {
|
||||
- try {
|
||||
- addLog("writing final mp3buffer to outputstream")
|
||||
- outputStream!!.write(mp3Buf, 0, outputMp3buf)
|
||||
- addLog("closing output stream")
|
||||
- outputStream!!.close()
|
||||
- completeCallback(output.absolutePath, true)
|
||||
- isCompletedCallbackTriggered=true
|
||||
- } catch (e: IOException) {
|
||||
- completeCallback(e.localizedMessage, false)
|
||||
- e.printStackTrace()
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- } catch (e: IOException) {
|
||||
- completeCallback(e.localizedMessage, false)
|
||||
- }
|
||||
- if(!isCompletedCallbackTriggered)
|
||||
- {
|
||||
- completeCallback("something went wrong", false)
|
||||
- }
|
||||
- }
|
||||
-
|
||||
-
|
||||
-
|
||||
- }
|
||||
-}
|
||||
diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt
|
||||
deleted file mode 100644
|
||||
index c655182..0000000
|
||||
--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt
|
||||
+++ /dev/null
|
||||
@@ -1,112 +0,0 @@
|
||||
-package com.reactnativecompressor.Audio
|
||||
-
|
||||
-import android.annotation.SuppressLint
|
||||
-import android.media.MediaCodec
|
||||
-import android.media.MediaExtractor
|
||||
-import android.media.MediaFormat
|
||||
-import android.media.MediaMetadataRetriever
|
||||
-import android.media.MediaMuxer
|
||||
-import android.util.Log
|
||||
-import java.io.IOException
|
||||
-import java.nio.ByteBuffer
|
||||
-
|
||||
-
|
||||
-class AudioExtractor {
|
||||
- /**
|
||||
- * @param srcPath the path of source video file.
|
||||
- * @param dstPath the path of destination video file.
|
||||
- * @param startMs starting time in milliseconds for trimming. Set to
|
||||
- * negative if starting from beginning.
|
||||
- * @param endMs end time for trimming in milliseconds. Set to negative if
|
||||
- * no trimming at the end.
|
||||
- * @param useAudio true if keep the audio track from the source.
|
||||
- * @param useVideo true if keep the video track from the source.
|
||||
- * @throws IOException
|
||||
- */
|
||||
- @SuppressLint("NewApi", "WrongConstant")
|
||||
- @Throws(IOException::class)
|
||||
- fun genVideoUsingMuxer(srcPath: String?, dstPath: String?, startMs: Int, endMs: Int, useAudio: Boolean, useVideo: Boolean) {
|
||||
- // Set up MediaExtractor to read from the source.
|
||||
- val extractor = MediaExtractor()
|
||||
- extractor.setDataSource(srcPath!!)
|
||||
- val trackCount = extractor.trackCount
|
||||
- // Set up MediaMuxer for the destination.
|
||||
- val muxer: MediaMuxer
|
||||
- muxer = MediaMuxer(dstPath!!, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
|
||||
- // Set up the tracks and retrieve the max buffer size for selected
|
||||
- // tracks.
|
||||
- val indexMap = HashMap<Int, Int>(trackCount)
|
||||
- var bufferSize = -1
|
||||
- for (i in 0 until trackCount) {
|
||||
- val format = extractor.getTrackFormat(i)
|
||||
- val mime = format.getString(MediaFormat.KEY_MIME)
|
||||
- var selectCurrentTrack = false
|
||||
- if (mime!!.startsWith("audio/") && useAudio) {
|
||||
- selectCurrentTrack = true
|
||||
- } else if (mime.startsWith("video/") && useVideo) {
|
||||
- selectCurrentTrack = true
|
||||
- }
|
||||
- if (selectCurrentTrack) {
|
||||
- extractor.selectTrack(i)
|
||||
- val dstIndex = muxer.addTrack(format)
|
||||
- indexMap[i] = dstIndex
|
||||
- if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
|
||||
- val newSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
|
||||
- bufferSize = if (newSize > bufferSize) newSize else bufferSize
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- if (bufferSize < 0) {
|
||||
- bufferSize = DEFAULT_BUFFER_SIZE
|
||||
- }
|
||||
- // Set up the orientation and starting time for extractor.
|
||||
- val retrieverSrc = MediaMetadataRetriever()
|
||||
- retrieverSrc.setDataSource(srcPath)
|
||||
- val degreesString = retrieverSrc.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)
|
||||
- if (degreesString != null) {
|
||||
- val degrees = degreesString.toInt()
|
||||
- if (degrees >= 0) {
|
||||
- muxer.setOrientationHint(degrees)
|
||||
- }
|
||||
- }
|
||||
- if (startMs > 0) {
|
||||
- extractor.seekTo((startMs * 1000).toLong(), MediaExtractor.SEEK_TO_CLOSEST_SYNC)
|
||||
- }
|
||||
- // Copy the samples from MediaExtractor to MediaMuxer. We will loop
|
||||
- // for copying each sample and stop when we get to the end of the source
|
||||
- // file or exceed the end time of the trimming.
|
||||
- val offset = 0
|
||||
- var trackIndex = -1
|
||||
- val dstBuf = ByteBuffer.allocate(bufferSize)
|
||||
- val bufferInfo = MediaCodec.BufferInfo()
|
||||
- muxer.start()
|
||||
- while (true) {
|
||||
- bufferInfo.offset = offset
|
||||
- bufferInfo.size = extractor.readSampleData(dstBuf, offset)
|
||||
- if (bufferInfo.size < 0) {
|
||||
- Log.d(TAG, "Saw input EOS.")
|
||||
- bufferInfo.size = 0
|
||||
- break
|
||||
- } else {
|
||||
- bufferInfo.presentationTimeUs = extractor.sampleTime
|
||||
- if (endMs > 0 && bufferInfo.presentationTimeUs > endMs * 1000) {
|
||||
- Log.d(TAG, "The current sample is over the trim end time.")
|
||||
- break
|
||||
- } else {
|
||||
- bufferInfo.flags = extractor.sampleFlags
|
||||
- trackIndex = extractor.sampleTrackIndex
|
||||
- muxer.writeSampleData(indexMap[trackIndex]!!, dstBuf, bufferInfo)
|
||||
- extractor.advance()
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- muxer.stop()
|
||||
- muxer.release()
|
||||
- return
|
||||
- }
|
||||
-
|
||||
- companion object {
|
||||
- private const val DEFAULT_BUFFER_SIZE = 1 * 1024 * 1024
|
||||
- private const val TAG = "AudioExtractorDecoder"
|
||||
- }
|
||||
-}
|
||||
diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt
|
||||
deleted file mode 100644
|
||||
index 42040b4..0000000
|
||||
--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt
|
||||
+++ /dev/null
|
||||
@@ -1,72 +0,0 @@
|
||||
-package com.reactnativecompressor.Audio
|
||||
-
|
||||
-import android.media.MediaExtractor
|
||||
-import android.media.MediaFormat
|
||||
-import com.facebook.react.bridge.ReadableMap
|
||||
-import com.reactnativecompressor.Utils.Utils
|
||||
-import java.io.File
|
||||
-import java.io.IOException
|
||||
-
|
||||
-
|
||||
-class AudioHelper {
|
||||
-
|
||||
- var quality: String? = "medium"
|
||||
- var bitrate: Int = -1
|
||||
- var samplerate: Int = -1
|
||||
- var channels: Int = -1
|
||||
- var progressDivider: Int? = 0
|
||||
-
|
||||
- companion object {
|
||||
- fun fromMap(map: ReadableMap): AudioHelper {
|
||||
- val options = AudioHelper()
|
||||
- val iterator = map.keySetIterator()
|
||||
- while (iterator.hasNextKey()) {
|
||||
- val key = iterator.nextKey()
|
||||
- when (key) {
|
||||
- "quality" -> options.quality = map.getString(key)
|
||||
- "bitrate" -> {
|
||||
- val bitrate = map.getInt(key)
|
||||
- options.bitrate = if (bitrate > 320000 || bitrate < 64000) 64000 else bitrate
|
||||
- }
|
||||
- "samplerate" -> options.samplerate = map.getInt(key)
|
||||
- "channels" -> options.channels = map.getInt(key)
|
||||
- }
|
||||
- }
|
||||
- return options
|
||||
- }
|
||||
-
|
||||
-
|
||||
- fun getAudioBitrate(path: String): Int {
|
||||
- val file = File(path)
|
||||
- val fileSize = file.length() * 8 // size in bits
|
||||
-
|
||||
- val mex = MediaExtractor()
|
||||
- try {
|
||||
- mex.setDataSource(path)
|
||||
- } catch (e: IOException) {
|
||||
- e.printStackTrace()
|
||||
- }
|
||||
-
|
||||
- val mf = mex.getTrackFormat(0)
|
||||
- val durationUs = mf.getLong(MediaFormat.KEY_DURATION)
|
||||
- val durationSec = durationUs / 1_000_000.0 // convert duration to seconds
|
||||
-
|
||||
- return (fileSize / durationSec).toInt()/1000 // bitrate in bits per second
|
||||
- }
|
||||
- fun getDestinationBitrateByQuality(path: String, quality: String): Int {
|
||||
- val originalBitrate = getAudioBitrate(path)
|
||||
- var destinationBitrate = originalBitrate
|
||||
- Utils.addLog("source bitrate: $originalBitrate")
|
||||
-
|
||||
- when (quality.lowercase()) {
|
||||
- "low" -> destinationBitrate = maxOf(64, (originalBitrate * 0.3).toInt())
|
||||
- "medium" -> destinationBitrate = (originalBitrate * 0.5).toInt()
|
||||
- "high" -> destinationBitrate = minOf(320, (originalBitrate * 0.7).toInt())
|
||||
- else -> Utils.addLog("Invalid quality level. Please enter 'low', 'medium', or 'high'.")
|
||||
- }
|
||||
-
|
||||
- return destinationBitrate
|
||||
- }
|
||||
-
|
||||
- }
|
||||
-}
|
||||
diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt
|
||||
index 446d4fb..f021909 100644
|
||||
--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt
|
||||
+++ b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt
|
||||
@@ -11,7 +11,9 @@ class AudioMain(private val reactContext: ReactApplicationContext) {
|
||||
promise: Promise) {
|
||||
try {
|
||||
|
||||
- AudioCompressor.CompressAudio(fileUrl,optionMap,reactContext,promise)
|
||||
+ // Skip compression on Android to avoid libandroidlame dependency
|
||||
+ // Return the original file URL without compression
|
||||
+ promise.resolve(fileUrl)
|
||||
} catch (ex: Exception) {
|
||||
promise.reject(ex)
|
||||
}
|
||||
diff --git a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt
|
||||
index c14b727..1198908 100644
|
||||
--- a/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt
|
||||
+++ b/node_modules/react-native-compressor/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt
|
||||
@@ -7,7 +7,6 @@ import android.provider.OpenableColumns
|
||||
import android.util.Log
|
||||
import com.facebook.react.bridge.Promise
|
||||
import com.facebook.react.bridge.ReactApplicationContext
|
||||
-import com.reactnativecompressor.Audio.AudioCompressor
|
||||
import com.reactnativecompressor.Video.VideoCompressor.CompressionListener
|
||||
import com.reactnativecompressor.Video.VideoCompressor.VideoCompressorClass
|
||||
import java.io.FileNotFoundException
|
||||
@@ -152,10 +151,6 @@ object Utils {
|
||||
}
|
||||
}
|
||||
|
||||
- fun addLog(log: String) {
|
||||
- Log.d(AudioCompressor.TAG, log)
|
||||
- }
|
||||
-
|
||||
val exifAttributes = arrayOf(
|
||||
"FNumber",
|
||||
"ApertureValue",
|
||||
@@ -0,0 +1,5 @@
|
||||
# react-native-compressor
|
||||
|
||||
Patch file taken from https://github.com/numandev1/react-native-compressor/pull/355#issuecomment-3180870738
|
||||
|
||||
This patch removes the audio compression feature on Android from the library. This is because `libandroidlame.so`, the native dependency, does not support 16kb page sizes, and the Play Store has made this mandatory as of 1st Nov 2025.
|
||||
@@ -0,0 +1,22 @@
|
||||
diff --git a/node_modules/sonner-native/lib/commonjs/toast.js b/node_modules/sonner-native/lib/commonjs/toast.js
|
||||
index 121816a..0c3c7bd 100644
|
||||
--- a/node_modules/sonner-native/lib/commonjs/toast.js
|
||||
+++ b/node_modules/sonner-native/lib/commonjs/toast.js
|
||||
@@ -264,7 +264,7 @@ const Toast = exports.Toast = /*#__PURE__*/React.forwardRef(({
|
||||
...toastSwipeHandlerProps,
|
||||
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
|
||||
entering: entering,
|
||||
- exiting: exiting,
|
||||
+ exiting: _reactNative.Platform.OS === 'android' ? undefined : exiting,
|
||||
children: jsx
|
||||
})
|
||||
});
|
||||
@@ -274,7 +274,7 @@ const Toast = exports.Toast = /*#__PURE__*/React.forwardRef(({
|
||||
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
|
||||
style: [unstyled ? undefined : elevationStyle, defaultStyles.toast, toastStyleCtx, styles?.toast, style, wiggleAnimationStyle],
|
||||
entering: entering,
|
||||
- exiting: exiting,
|
||||
+ exiting: _reactNative.Platform.OS === 'android' ? undefined : exiting,
|
||||
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
||||
style: [defaultStyles.toastContent, toastContentStyleCtx, styles?.toastContent],
|
||||
children: [promiseOptions || variant === 'loading' ? 'loading' in icons ? icons.loading : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {}) : icon ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
||||
@@ -0,0 +1,3 @@
|
||||
# sonner-native+0.21.0.patch
|
||||
|
||||
Removes Reanimated exit layout animations from the toasts. This was causing crashes if the toast was hidden while you were scrolling a flatlist.
|
||||
+12
-1
@@ -1,6 +1,7 @@
|
||||
import {type StyleProp, type ViewStyle} from 'react-native'
|
||||
import {atoms as baseAtoms} from '@bsky.app/alf'
|
||||
|
||||
import {CARD_ASPECT_RATIO} from '#/lib/constants'
|
||||
import {native, platform, web} from '#/alf/util/platform'
|
||||
import * as Layout from '#/components/Layout'
|
||||
|
||||
@@ -31,6 +32,16 @@ export const atoms = {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
|
||||
/**
|
||||
* Aspect ratios
|
||||
*/
|
||||
aspect_square: {
|
||||
aspectRatio: 1,
|
||||
},
|
||||
aspect_card: {
|
||||
aspectRatio: CARD_ASPECT_RATIO,
|
||||
},
|
||||
|
||||
/*
|
||||
* Transition
|
||||
*/
|
||||
@@ -67,7 +78,7 @@ export const atoms = {
|
||||
}),
|
||||
|
||||
/*
|
||||
* Animaations
|
||||
* Animations
|
||||
*/
|
||||
fade_in: web({
|
||||
animation: 'fadeIn ease-out 0.15s',
|
||||
|
||||
@@ -172,7 +172,7 @@ function AccountItem({
|
||||
</View>
|
||||
|
||||
{isCurrentAccount ? (
|
||||
<Check size="sm" style={[{color: t.palette.positive_600}]} />
|
||||
<Check size="sm" style={[{color: t.palette.positive_500}]} />
|
||||
) : (
|
||||
<Chevron size="sm" style={[t.atoms.text]} />
|
||||
)}
|
||||
|
||||
@@ -87,7 +87,7 @@ export function Row({
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
return (
|
||||
<View style={[a.flex_1, a.flex_row, a.align_start, a.gap_sm, style]}>
|
||||
<View style={[a.w_full, a.flex_row, a.align_start, a.gap_sm, style]}>
|
||||
{children}
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -258,7 +258,7 @@ export function InterestTabs({
|
||||
t.atoms.border_contrast_low,
|
||||
t.atoms.bg,
|
||||
a.h_full,
|
||||
{aspectRatio: 1},
|
||||
a.aspect_square,
|
||||
a.rounded_full,
|
||||
]}>
|
||||
<ButtonIcon icon={ArrowLeft} />
|
||||
@@ -292,7 +292,7 @@ export function InterestTabs({
|
||||
t.atoms.border_contrast_low,
|
||||
t.atoms.bg,
|
||||
a.h_full,
|
||||
{aspectRatio: 1},
|
||||
a.aspect_square,
|
||||
a.rounded_full,
|
||||
]}>
|
||||
<ButtonIcon icon={ArrowRight} />
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import {useId} from 'react'
|
||||
import {useKeepAwake} from 'expo-keep-awake'
|
||||
import {useIsFocused} from '@react-navigation/native'
|
||||
|
||||
/**
|
||||
* Stops the screen from sleeping. Only applies to the current screen.
|
||||
*
|
||||
* Note: Expo keeps the screen permanently awake when in dev mode, so
|
||||
* you'll only see this do anything when in production.
|
||||
*
|
||||
* @platform ios, android
|
||||
*/
|
||||
export function KeepAwake({enabled = true}) {
|
||||
const isFocused = useIsFocused()
|
||||
if (enabled && isFocused) {
|
||||
return <KeepAwakeInner />
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function KeepAwakeInner() {
|
||||
const id = useId()
|
||||
// if you don't pass an explicit ID, any `useKeepAwake` hook unmounting disables them all.
|
||||
// very strange behaviour, but easily fixed by passing a unique ID -sfn
|
||||
useKeepAwake(id)
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function KeepAwake() {
|
||||
return null
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import {View, type ViewStyle} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {type Gate} from '#/lib/statsig/gates'
|
||||
import {useGate} from '#/lib/statsig/statsig'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||
import {Logo} from '#/view/icons/Logo'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
interface LoggedOutCTAProps {
|
||||
style?: ViewStyle
|
||||
gateName: Gate
|
||||
}
|
||||
|
||||
export function LoggedOutCTA({style, gateName}: LoggedOutCTAProps) {
|
||||
const {hasSession} = useSession()
|
||||
const {requestSwitchToAccount} = useLoggedOutViewControls()
|
||||
const gate = useGate()
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
|
||||
// Only show for logged-out users on web
|
||||
if (hasSession || !isWeb) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Check gate at the last possible moment to avoid counting users as exposed when they won't see the element
|
||||
if (!gate(gateName)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[a.pb_md, style]}>
|
||||
<View
|
||||
style={[
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
a.justify_between,
|
||||
a.px_lg,
|
||||
a.py_md,
|
||||
a.rounded_md,
|
||||
a.mb_xs,
|
||||
t.atoms.bg_contrast_25,
|
||||
]}>
|
||||
<View style={[a.flex_row, a.align_center, a.flex_1, a.pr_md]}>
|
||||
<Logo width={30} style={[a.mr_md]} />
|
||||
<View style={[a.flex_1]}>
|
||||
<Text style={[a.text_lg, a.font_semi_bold, a.leading_snug]}>
|
||||
<Trans>Join Bluesky</Trans>
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
a.text_md,
|
||||
a.font_medium,
|
||||
a.leading_snug,
|
||||
t.atoms.text_contrast_medium,
|
||||
]}>
|
||||
<Trans>The open social network.</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Button
|
||||
onPress={() => {
|
||||
requestSwitchToAccount({requestedAccount: 'new'})
|
||||
}}
|
||||
label={_(msg`Create account`)}
|
||||
size="small"
|
||||
variant="solid"
|
||||
color="primary">
|
||||
<ButtonText>
|
||||
<Trans>Create account</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ export function ImageItem({
|
||||
}) {
|
||||
const t = useTheme()
|
||||
return (
|
||||
<View style={[a.relative, a.flex_1, {aspectRatio: 1, maxWidth: 100}]}>
|
||||
<View style={[a.relative, a.flex_1, a.aspect_square, {maxWidth: 100}]}>
|
||||
<Image
|
||||
key={thumbnail}
|
||||
source={{uri: thumbnail}}
|
||||
@@ -131,7 +131,8 @@ export function VideoItem({
|
||||
style={[
|
||||
{backgroundColor: 'black'},
|
||||
a.flex_1,
|
||||
{aspectRatio: 1, maxWidth: 100},
|
||||
a.aspect_square,
|
||||
{maxWidth: 100},
|
||||
a.justify_center,
|
||||
a.align_center,
|
||||
]}>
|
||||
|
||||
@@ -97,9 +97,7 @@ export const ExternalEmbed = ({
|
||||
]}>
|
||||
{imageUri && !embedPlayerParams ? (
|
||||
<Image
|
||||
style={{
|
||||
aspectRatio: 1.91,
|
||||
}}
|
||||
style={[a.aspect_card]}
|
||||
source={{uri: imageUri}}
|
||||
accessibilityIgnoresInvertColors
|
||||
/>
|
||||
|
||||
@@ -46,7 +46,12 @@ import {
|
||||
useProfileBlockMutationQueue,
|
||||
useProfileMuteMutationQueue,
|
||||
} from '#/state/queries/profile'
|
||||
import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate'
|
||||
import {
|
||||
InvalidInteractionSettingsError,
|
||||
MAX_HIDDEN_REPLIES,
|
||||
MaxHiddenRepliesError,
|
||||
useToggleReplyVisibilityMutation,
|
||||
} from '#/state/queries/threadgate'
|
||||
import {useRequireAuth, useSession} from '#/state/session'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
@@ -339,10 +344,30 @@ let PostMenuItems = ({
|
||||
: _(msg({message: 'Reply visibility updated', context: 'toast'})),
|
||||
)
|
||||
} catch (e: any) {
|
||||
Toast.show(
|
||||
_(msg({message: 'Updating reply visibility failed', context: 'toast'})),
|
||||
)
|
||||
logger.error(`Failed to ${action} reply`, {safeMessage: e.message})
|
||||
if (e instanceof MaxHiddenRepliesError) {
|
||||
Toast.show(
|
||||
_(
|
||||
msg({
|
||||
message: `You can hide a maximum of ${MAX_HIDDEN_REPLIES} replies.`,
|
||||
context: 'toast',
|
||||
}),
|
||||
),
|
||||
)
|
||||
} else if (e instanceof InvalidInteractionSettingsError) {
|
||||
Toast.show(
|
||||
_(msg({message: 'Invalid interaction settings.', context: 'toast'})),
|
||||
)
|
||||
} else {
|
||||
Toast.show(
|
||||
_(
|
||||
msg({
|
||||
message: 'Updating reply visibility failed',
|
||||
context: 'toast',
|
||||
}),
|
||||
),
|
||||
)
|
||||
logger.error(`Failed to ${action} reply`, {safeMessage: e.message})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ let RepostButton = ({
|
||||
<PostControlButton
|
||||
testID="repostBtn"
|
||||
active={isReposted}
|
||||
activeColor={t.palette.positive_600}
|
||||
activeColor={t.palette.positive_500}
|
||||
big={big}
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
|
||||
@@ -47,7 +47,7 @@ export const RepostButton = ({
|
||||
<PostControlButton
|
||||
testID="repostBtn"
|
||||
active={isReposted}
|
||||
activeColor={t.palette.positive_600}
|
||||
activeColor={t.palette.positive_500}
|
||||
label={props.accessibilityLabel}
|
||||
big={big}
|
||||
{...props}>
|
||||
@@ -100,7 +100,7 @@ export const RepostButton = ({
|
||||
<PostControlButton
|
||||
onPress={() => requireAuth(() => {})}
|
||||
active={isReposted}
|
||||
activeColor={t.palette.positive_600}
|
||||
activeColor={t.palette.positive_500}
|
||||
label={_(msg`Repost or quote post`)}
|
||||
big={big}>
|
||||
<PostControlButtonIcon icon={Repost} />
|
||||
|
||||
@@ -136,7 +136,9 @@ let ShareMenuItems = ({
|
||||
{hideInPWI && (
|
||||
<Menu.Group>
|
||||
<Menu.ContainerItem>
|
||||
<Admonition type="warning" style={[a.flex_1, a.border_0, a.p_0]}>
|
||||
<Admonition
|
||||
type="warning"
|
||||
style={[a.flex_1, a.border_0, a.p_0, a.bg_transparent]}>
|
||||
<Trans>This post is only visible to logged-in users.</Trans>
|
||||
</Admonition>
|
||||
</Menu.ContainerItem>
|
||||
|
||||
@@ -210,7 +210,7 @@ let PostControls = ({
|
||||
a.flex_1,
|
||||
a.align_start,
|
||||
{marginLeft: big ? -2 : -6},
|
||||
replyDisabled ? {opacity: 0.5} : undefined,
|
||||
replyDisabled ? {opacity: 0.6} : undefined,
|
||||
]}>
|
||||
<PostControlButton
|
||||
testID="replyBtn"
|
||||
|
||||
@@ -32,7 +32,7 @@ export function Text({blend, style}: TextStyleProp & SkeletonProps) {
|
||||
<View
|
||||
style={[
|
||||
a.rounded_md,
|
||||
t.atoms.bg_contrast_25,
|
||||
t.atoms.bg_contrast_50,
|
||||
{
|
||||
height: lineHeight * 0.7,
|
||||
opacity: blend ? 0.6 : 1,
|
||||
@@ -57,7 +57,7 @@ export function Circle({
|
||||
a.justify_center,
|
||||
a.align_center,
|
||||
a.rounded_full,
|
||||
t.atoms.bg_contrast_25,
|
||||
t.atoms.bg_contrast_50,
|
||||
{
|
||||
width: size,
|
||||
height: size,
|
||||
@@ -80,7 +80,7 @@ export function Pill({
|
||||
<View
|
||||
style={[
|
||||
a.rounded_full,
|
||||
t.atoms.bg_contrast_25,
|
||||
t.atoms.bg_contrast_50,
|
||||
{
|
||||
width: size * 1.618,
|
||||
height: size,
|
||||
|
||||
@@ -91,8 +91,8 @@ function ShareDialogInner({
|
||||
source={{uri: imageUrl}}
|
||||
style={[
|
||||
a.rounded_sm,
|
||||
a.aspect_card,
|
||||
{
|
||||
aspectRatio: 1200 / 630,
|
||||
transform: [{scale: gtMobile ? 0.85 : 1}],
|
||||
marginTop: gtMobile ? -20 : 0,
|
||||
},
|
||||
|
||||
@@ -191,7 +191,7 @@ export function Embed({
|
||||
<Link starterPack={starterPack}>
|
||||
<Image
|
||||
source={imageUri}
|
||||
style={[a.w_full, {aspectRatio: 1.91}]}
|
||||
style={[a.w_full, a.aspect_card]}
|
||||
accessibilityIgnoresInvertColors={true}
|
||||
/>
|
||||
<View style={[a.px_sm, a.py_md]}>
|
||||
|
||||
@@ -159,7 +159,7 @@ export function Inner({}: {optimisticState?: AgeAssuranceRedirectDialogState}) {
|
||||
a.pt_lg,
|
||||
a.pb_md,
|
||||
]}>
|
||||
<SuccessIcon size="sm" fill={t.palette.positive_600} />
|
||||
<SuccessIcon size="sm" fill={t.palette.positive_500} />
|
||||
<Text style={[a.text_xl, a.font_bold]}>
|
||||
<Trans>Success</Trans>
|
||||
</Text>
|
||||
|
||||
@@ -281,7 +281,7 @@ export function Update(_props: ScreenProps<ScreenID.Update>) {
|
||||
<Divider />
|
||||
<View style={[a.gap_sm]}>
|
||||
<View style={[a.flex_row, a.gap_sm, a.align_center]}>
|
||||
<Check fill={t.palette.positive_600} size="xs" />
|
||||
<Check fill={t.palette.positive_500} size="xs" />
|
||||
<Text style={[a.text_md, a.font_bold]}>
|
||||
<Trans>Success!</Trans>
|
||||
</Text>
|
||||
|
||||
@@ -176,7 +176,7 @@ export function Verify({config, showScreen}: ScreenProps<ScreenID.Verify>) {
|
||||
<View style={[a.gap_sm]}>
|
||||
<Text style={[a.text_xl, a.font_bold]}>
|
||||
<Span style={{top: 1}}>
|
||||
<Check size="sm" fill={t.palette.positive_600} />
|
||||
<Check size="sm" fill={t.palette.positive_500} />
|
||||
</Span>
|
||||
{' '}
|
||||
<Trans>Email verification complete!</Trans>
|
||||
@@ -202,7 +202,7 @@ export function Verify({config, showScreen}: ScreenProps<ScreenID.Verify>) {
|
||||
state.mutationStatus === 'success' ? (
|
||||
<>
|
||||
<Span style={{top: 1}}>
|
||||
<Check size="sm" fill={t.palette.positive_600} />
|
||||
<Check size="sm" fill={t.palette.positive_500} />
|
||||
</Span>
|
||||
{' '}
|
||||
<Trans>Email sent!</Trans>
|
||||
|
||||
@@ -300,7 +300,8 @@ export function GifPreview({
|
||||
a.flex_1,
|
||||
a.mb_sm,
|
||||
a.rounded_sm,
|
||||
{aspectRatio: 1, opacity: pressed ? 0.8 : 1},
|
||||
a.aspect_card,
|
||||
{opacity: pressed ? 0.8 : 1},
|
||||
t.atoms.bg_contrast_25,
|
||||
]}
|
||||
source={{
|
||||
|
||||
@@ -102,7 +102,7 @@ export function LiveStatus({
|
||||
style={[
|
||||
t.atoms.bg_contrast_25,
|
||||
a.w_full,
|
||||
{aspectRatio: 1.91},
|
||||
a.aspect_card,
|
||||
android([
|
||||
a.overflow_hidden,
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ interface Props extends ComponentProps<typeof Link> {
|
||||
modui: ModerationUI
|
||||
profile: AppBskyActorDefs.ProfileViewBasic
|
||||
interpretFilterAsBlur?: boolean
|
||||
hiderStyle?: StyleProp<ViewStyle>
|
||||
}
|
||||
|
||||
export function PostHider({
|
||||
@@ -42,6 +43,7 @@ export function PostHider({
|
||||
disabled,
|
||||
modui,
|
||||
style,
|
||||
hiderStyle,
|
||||
children,
|
||||
iconSize,
|
||||
iconStyles,
|
||||
@@ -100,6 +102,7 @@ export function PostHider({
|
||||
},
|
||||
override ? {paddingBottom: 0} : undefined,
|
||||
t.atoms.bg,
|
||||
hiderStyle,
|
||||
]}>
|
||||
<ModerationDetailsDialog control={control} modcause={blur} />
|
||||
<Pressable
|
||||
|
||||
Vendored
+2
-2
@@ -21,12 +21,12 @@ export const ENV: string = process.env.EXPO_PUBLIC_ENV
|
||||
export const IS_TESTFLIGHT = ENV === 'testflight'
|
||||
|
||||
/**
|
||||
* Indicates whether the app is __DEV__
|
||||
* Indicates whether the app is `__DEV__`
|
||||
*/
|
||||
export const IS_DEV = __DEV__
|
||||
|
||||
/**
|
||||
* Indicates whether the app is __DEV__ or TestFlight
|
||||
* Indicates whether the app is `__DEV__` or TestFlight
|
||||
*/
|
||||
export const IS_INTERNAL = IS_DEV || IS_TESTFLIGHT
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ export const EMBED_SERVICE = 'https://embed.bsky.app'
|
||||
export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js`
|
||||
export const BSKY_DOWNLOAD_URL = 'https://bsky.app/download'
|
||||
export const STARTER_PACK_MAX_SIZE = 150
|
||||
export const CARD_ASPECT_RATIO = 1200 / 630
|
||||
|
||||
// HACK
|
||||
// Yes, this is exactly what it looks like. It's a hard-coded constant
|
||||
|
||||
@@ -62,7 +62,10 @@ export async function getLinkMeta(
|
||||
likelyType,
|
||||
url,
|
||||
}
|
||||
if (likelyType !== LikelyType.HTML) {
|
||||
const htmlExemptedHostnames: string[] = ['storage.courtlistener.com']
|
||||
const isExemptedFromHtmlCheck = htmlExemptedHostnames.includes(urlp.hostname)
|
||||
// Skip early return only for hosts exempted from the HTML check
|
||||
if (likelyType !== LikelyType.HTML && !isExemptedFromHtmlCheck) {
|
||||
return meta
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ export type CommonNavigatorParams = {
|
||||
InterestsSettings: undefined
|
||||
AboutSettings: undefined
|
||||
AppIconSettings: undefined
|
||||
Search: {q?: string}
|
||||
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||
Hashtag: {tag: string; author?: string}
|
||||
Topic: {topic: string}
|
||||
MessagesConversation: {conversation: string; embed?: string; accept?: true}
|
||||
@@ -102,7 +102,7 @@ export type HomeTabNavigatorParams = CommonNavigatorParams & {
|
||||
}
|
||||
|
||||
export type SearchTabNavigatorParams = CommonNavigatorParams & {
|
||||
Search: {q?: string}
|
||||
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||
}
|
||||
|
||||
export type NotificationsTabNavigatorParams = CommonNavigatorParams & {
|
||||
@@ -119,7 +119,7 @@ export type MessagesTabNavigatorParams = CommonNavigatorParams & {
|
||||
|
||||
export type FlatNavigatorParams = CommonNavigatorParams & {
|
||||
Home: undefined
|
||||
Search: {q?: string}
|
||||
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||
Feeds: undefined
|
||||
Notifications: undefined
|
||||
Messages: {pushToConversation?: string; animation?: 'push' | 'pop'}
|
||||
@@ -129,7 +129,7 @@ export type AllNavigatorParams = CommonNavigatorParams & {
|
||||
HomeTab: undefined
|
||||
Home: undefined
|
||||
SearchTab: undefined
|
||||
Search: {q?: string}
|
||||
Search: {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||
Feeds: undefined
|
||||
NotificationsTab: undefined
|
||||
Notifications: undefined
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
export type Gate =
|
||||
// Keep this alphabetic please.
|
||||
| 'alt_share_icon'
|
||||
| 'cta_above_post_heading'
|
||||
| 'cta_above_post_replies'
|
||||
| 'debug_show_feedcontext'
|
||||
| 'debug_subscriptions'
|
||||
| 'disable_onboarding_policy_update_notice'
|
||||
| 'explore_show_suggested_feeds'
|
||||
| 'feed_reply_button_open_thread'
|
||||
| 'old_postonboarding'
|
||||
| 'onboarding_add_video_feed'
|
||||
| 'onboarding_suggested_accounts'
|
||||
| 'onboarding_value_prop'
|
||||
| 'post_follow_profile_suggested_accounts'
|
||||
| 'remove_show_latest_button'
|
||||
| 'test_gate_1'
|
||||
| 'test_gate_2'
|
||||
| 'welcome_modal'
|
||||
|
||||
+121
-121
@@ -124,7 +124,7 @@ msgstr ""
|
||||
msgid "{0, plural, other {# people have}} used this starter pack!"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:356
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:360
|
||||
msgid "{0, plural, other {+# more}}"
|
||||
msgstr ""
|
||||
|
||||
@@ -493,7 +493,7 @@ msgstr ""
|
||||
msgid "<0>{date}</0> at {time}"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/SearchResults.tsx:255
|
||||
#: src/screens/Search/SearchResults.tsx:257
|
||||
msgid "<0>Sign in</0><1> or </1><2>create an account</2><3> </3><4>to search for news, sports, politics, and everything else happening on Bluesky.</4>"
|
||||
msgstr ""
|
||||
|
||||
@@ -568,7 +568,7 @@ msgstr ""
|
||||
msgid "Accept Request"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/composer/select-language/SuggestedLanguage.tsx:179
|
||||
#: src/view/com/composer/select-language/SuggestedLanguage.tsx:178
|
||||
msgid "Accept this language suggestion"
|
||||
msgstr ""
|
||||
|
||||
@@ -592,18 +592,18 @@ msgstr ""
|
||||
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:361
|
||||
#: src/screens/Messages/components/RequestButtons.tsx:91
|
||||
#: src/view/com/profile/ProfileMenu.tsx:161
|
||||
#: src/view/com/profile/ProfileMenu.tsx:166
|
||||
msgctxt "toast"
|
||||
msgid "Account blocked"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:174
|
||||
#: src/view/com/profile/ProfileMenu.tsx:179
|
||||
msgctxt "toast"
|
||||
msgid "Account followed"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:384
|
||||
#: src/view/com/profile/ProfileMenu.tsx:137
|
||||
#: src/view/com/profile/ProfileMenu.tsx:142
|
||||
msgctxt "toast"
|
||||
msgid "Account muted"
|
||||
msgstr ""
|
||||
@@ -626,18 +626,18 @@ msgid "Account removed from quick access"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:132
|
||||
#: src/view/com/profile/ProfileMenu.tsx:151
|
||||
#: src/view/com/profile/ProfileMenu.tsx:156
|
||||
msgctxt "toast"
|
||||
msgid "Account unblocked"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:186
|
||||
#: src/view/com/profile/ProfileMenu.tsx:191
|
||||
msgctxt "toast"
|
||||
msgid "Account unfollowed"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:374
|
||||
#: src/view/com/profile/ProfileMenu.tsx:127
|
||||
#: src/view/com/profile/ProfileMenu.tsx:132
|
||||
msgctxt "toast"
|
||||
msgid "Account unmuted"
|
||||
msgstr ""
|
||||
@@ -658,8 +658,8 @@ msgstr ""
|
||||
|
||||
#: src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx:169
|
||||
#: src/components/dialogs/MutedWords.tsx:333
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:370
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:376
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:374
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:380
|
||||
#: src/view/com/modals/UserAddRemoveLists.tsx:235
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
@@ -668,7 +668,7 @@ msgstr ""
|
||||
msgid "Add {0} more to continue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:61
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:62
|
||||
msgid "Add {displayName} to starter pack"
|
||||
msgstr ""
|
||||
|
||||
@@ -785,8 +785,8 @@ msgstr ""
|
||||
msgid "Add this feed to your feeds"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:317
|
||||
#: src/view/com/profile/ProfileMenu.tsx:320
|
||||
#: src/view/com/profile/ProfileMenu.tsx:322
|
||||
#: src/view/com/profile/ProfileMenu.tsx:325
|
||||
msgid "Add to lists"
|
||||
msgstr ""
|
||||
|
||||
@@ -794,9 +794,9 @@ msgstr ""
|
||||
msgid "Add to saved posts"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:175
|
||||
#: src/view/com/profile/ProfileMenu.tsx:308
|
||||
#: src/view/com/profile/ProfileMenu.tsx:311
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:176
|
||||
#: src/view/com/profile/ProfileMenu.tsx:313
|
||||
#: src/view/com/profile/ProfileMenu.tsx:316
|
||||
msgid "Add to starter packs"
|
||||
msgstr ""
|
||||
|
||||
@@ -809,7 +809,7 @@ msgstr ""
|
||||
msgid "Added to list"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:257
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:258
|
||||
msgid "Added to starter pack"
|
||||
msgstr ""
|
||||
|
||||
@@ -1311,7 +1311,7 @@ msgstr ""
|
||||
msgid "Before creating a post or replying, you must first verify your email."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:70
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:71
|
||||
#: src/components/StarterPack/ProfileStarterPacks.tsx:231
|
||||
#: src/components/StarterPack/ProfileStarterPacks.tsx:241
|
||||
msgid "Before creating a starter pack, you must first verify your email."
|
||||
@@ -1351,7 +1351,7 @@ msgstr ""
|
||||
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:760
|
||||
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:328
|
||||
#: src/view/com/profile/ProfileMenu.tsx:490
|
||||
#: src/view/com/profile/ProfileMenu.tsx:495
|
||||
msgid "Block"
|
||||
msgstr ""
|
||||
|
||||
@@ -1361,13 +1361,13 @@ msgstr ""
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:647
|
||||
#: src/screens/Messages/components/RequestButtons.tsx:144
|
||||
#: src/screens/Messages/components/RequestButtons.tsx:146
|
||||
#: src/view/com/profile/ProfileMenu.tsx:396
|
||||
#: src/view/com/profile/ProfileMenu.tsx:403
|
||||
#: src/view/com/profile/ProfileMenu.tsx:401
|
||||
#: src/view/com/profile/ProfileMenu.tsx:408
|
||||
msgid "Block account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:755
|
||||
#: src/view/com/profile/ProfileMenu.tsx:473
|
||||
#: src/view/com/profile/ProfileMenu.tsx:478
|
||||
msgid "Block Account?"
|
||||
msgstr ""
|
||||
|
||||
@@ -1419,7 +1419,7 @@ msgid "Blocked Accounts"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:757
|
||||
#: src/view/com/profile/ProfileMenu.tsx:485
|
||||
#: src/view/com/profile/ProfileMenu.tsx:490
|
||||
msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
|
||||
msgstr ""
|
||||
|
||||
@@ -1435,7 +1435,7 @@ msgstr ""
|
||||
msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:482
|
||||
#: src/view/com/profile/ProfileMenu.tsx:487
|
||||
msgid "Blocking will not prevent labels from being applied on your account, but it will stop this account from replying in your threads or interacting with you."
|
||||
msgstr ""
|
||||
|
||||
@@ -1564,7 +1564,7 @@ msgstr ""
|
||||
#: src/components/LabelingServiceCard/index.tsx:62
|
||||
#: src/components/moderation/ReportDialog/index.tsx:686
|
||||
#: src/screens/Search/components/StarterPackCard.tsx:106
|
||||
#: src/screens/Search/Explore.tsx:930
|
||||
#: src/screens/Search/Explore.tsx:940
|
||||
msgid "By {0}"
|
||||
msgstr ""
|
||||
|
||||
@@ -1620,7 +1620,7 @@ msgstr ""
|
||||
#: src/screens/Deactivated.tsx:158
|
||||
#: src/screens/Profile/Header/EditProfileDialog.tsx:218
|
||||
#: src/screens/Profile/Header/EditProfileDialog.tsx:226
|
||||
#: src/screens/Search/Shell.tsx:349
|
||||
#: src/screens/Search/Shell.tsx:369
|
||||
#: src/screens/Settings/AppIconSettings/index.tsx:44
|
||||
#: src/screens/Settings/AppIconSettings/index.tsx:230
|
||||
#: src/screens/Settings/components/ChangeHandleDialog.tsx:78
|
||||
@@ -1657,7 +1657,7 @@ msgstr ""
|
||||
msgid "Cancel reactivation and sign out"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/Shell.tsx:341
|
||||
#: src/screens/Search/Shell.tsx:361
|
||||
msgid "Cancel search"
|
||||
msgstr ""
|
||||
|
||||
@@ -1920,7 +1920,7 @@ msgstr ""
|
||||
#: src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx:178
|
||||
#: src/components/dialogs/nuxs/InitialVerificationAnnouncement.tsx:187
|
||||
#: src/components/dialogs/SearchablePeopleList.tsx:295
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:178
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:179
|
||||
#: src/components/dms/EmojiPopup.android.tsx:58
|
||||
#: src/components/dms/ReportDialog.tsx:387
|
||||
#: src/components/dms/ReportDialog.tsx:396
|
||||
@@ -1968,7 +1968,7 @@ msgstr ""
|
||||
msgid "Close dialog"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/shell/index.web.tsx:110
|
||||
#: src/view/shell/index.web.tsx:107
|
||||
msgid "Close drawer menu"
|
||||
msgstr ""
|
||||
|
||||
@@ -2281,8 +2281,8 @@ msgstr ""
|
||||
msgid "Copy App Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:433
|
||||
#: src/view/com/profile/ProfileMenu.tsx:436
|
||||
#: src/view/com/profile/ProfileMenu.tsx:438
|
||||
#: src/view/com/profile/ProfileMenu.tsx:441
|
||||
msgid "Copy at:// URI"
|
||||
msgstr ""
|
||||
|
||||
@@ -2297,8 +2297,8 @@ msgid "Copy code"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Settings/components/ChangeHandleDialog.tsx:501
|
||||
#: src/view/com/profile/ProfileMenu.tsx:442
|
||||
#: src/view/com/profile/ProfileMenu.tsx:445
|
||||
#: src/view/com/profile/ProfileMenu.tsx:447
|
||||
#: src/view/com/profile/ProfileMenu.tsx:450
|
||||
msgid "Copy DID"
|
||||
msgstr ""
|
||||
|
||||
@@ -2327,8 +2327,8 @@ msgstr ""
|
||||
msgid "Copy link to post"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:246
|
||||
#: src/view/com/profile/ProfileMenu.tsx:257
|
||||
#: src/view/com/profile/ProfileMenu.tsx:251
|
||||
#: src/view/com/profile/ProfileMenu.tsx:262
|
||||
msgid "Copy link to profile"
|
||||
msgstr ""
|
||||
|
||||
@@ -2411,8 +2411,8 @@ msgstr ""
|
||||
|
||||
#. Text on button to create a new starter pack
|
||||
#. Text on button to create a new starter pack
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:111
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:200
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:112
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:201
|
||||
#: src/components/StarterPack/ProfileStarterPacks.tsx:296
|
||||
msgid "Create"
|
||||
msgstr ""
|
||||
@@ -2452,7 +2452,7 @@ msgstr ""
|
||||
|
||||
#: src/components/dialogs/Signin.tsx:86
|
||||
#: src/components/dialogs/Signin.tsx:88
|
||||
#: src/screens/Search/SearchResults.tsx:266
|
||||
#: src/screens/Search/SearchResults.tsx:268
|
||||
msgid "Create an account"
|
||||
msgstr ""
|
||||
|
||||
@@ -2483,8 +2483,8 @@ msgstr ""
|
||||
msgid "Create report for {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:106
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:195
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:107
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:196
|
||||
msgid "Create starter pack"
|
||||
msgstr ""
|
||||
|
||||
@@ -2518,7 +2518,7 @@ msgstr ""
|
||||
msgid "Customize who can interact with this post."
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Onboarding/Layout.tsx:60
|
||||
#: src/screens/Onboarding/Layout.tsx:61
|
||||
msgid "Customizes your Bluesky experience"
|
||||
msgstr ""
|
||||
|
||||
@@ -2981,8 +2981,8 @@ msgstr ""
|
||||
msgid "Edit list details"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:329
|
||||
#: src/view/com/profile/ProfileMenu.tsx:335
|
||||
#: src/view/com/profile/ProfileMenu.tsx:334
|
||||
#: src/view/com/profile/ProfileMenu.tsx:340
|
||||
msgid "Edit live status"
|
||||
msgstr ""
|
||||
|
||||
@@ -3252,7 +3252,7 @@ msgstr ""
|
||||
msgid "Error:"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/SearchResults.tsx:144
|
||||
#: src/screens/Search/SearchResults.tsx:146
|
||||
msgid "Error: {error}"
|
||||
msgstr ""
|
||||
|
||||
@@ -3365,7 +3365,7 @@ msgid "Explicit sexual images."
|
||||
msgstr ""
|
||||
|
||||
#: src/Navigation.tsx:759
|
||||
#: src/screens/Search/Shell.tsx:307
|
||||
#: src/screens/Search/Shell.tsx:327
|
||||
#: src/view/shell/desktop/LeftNav.tsx:690
|
||||
#: src/view/shell/Drawer.tsx:414
|
||||
msgid "Explore"
|
||||
@@ -3415,7 +3415,7 @@ msgstr ""
|
||||
msgid "Failed to add emoji reaction"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:269
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:270
|
||||
msgid "Failed to add to starter pack"
|
||||
msgstr ""
|
||||
|
||||
@@ -3521,7 +3521,7 @@ msgstr ""
|
||||
msgid "Failed to remove emoji reaction"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:288
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:289
|
||||
msgid "Failed to remove from starter pack"
|
||||
msgstr ""
|
||||
|
||||
@@ -3625,7 +3625,7 @@ msgstr ""
|
||||
msgid "Feed menu"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:57
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:58
|
||||
msgid "Feed toggle"
|
||||
msgstr ""
|
||||
|
||||
@@ -3647,7 +3647,7 @@ msgstr ""
|
||||
|
||||
#: src/Navigation.tsx:574
|
||||
#: src/screens/SavedFeeds.tsx:108
|
||||
#: src/screens/Search/SearchResults.tsx:73
|
||||
#: src/screens/Search/SearchResults.tsx:75
|
||||
#: src/screens/StarterPack/StarterPackScreen.tsx:190
|
||||
#: src/view/screens/Feeds.tsx:511
|
||||
#: src/view/screens/Profile.tsx:230
|
||||
@@ -3719,7 +3719,7 @@ msgstr ""
|
||||
msgid "Find people to follow"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/Shell.tsx:475
|
||||
#: src/screens/Search/Shell.tsx:525
|
||||
msgid "Find posts, users, and feeds on Bluesky"
|
||||
msgstr ""
|
||||
|
||||
@@ -3787,8 +3787,8 @@ msgstr ""
|
||||
msgid "Follow 7 accounts"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:287
|
||||
#: src/view/com/profile/ProfileMenu.tsx:298
|
||||
#: src/view/com/profile/ProfileMenu.tsx:292
|
||||
#: src/view/com/profile/ProfileMenu.tsx:303
|
||||
msgid "Follow account"
|
||||
msgstr ""
|
||||
|
||||
@@ -3958,7 +3958,7 @@ msgstr ""
|
||||
msgid "From @{sanitizedAuthor}"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/posts/PostFeedItem.tsx:327
|
||||
#: src/view/com/posts/PostFeedItem.tsx:345
|
||||
msgctxt "from-feed"
|
||||
msgid "From <0/>"
|
||||
msgstr ""
|
||||
@@ -4079,8 +4079,8 @@ msgstr ""
|
||||
#: src/components/dms/ReportDialog.tsx:197
|
||||
#: src/components/ReportDialog/SelectReportOptionView.tsx:81
|
||||
#: src/components/ReportDialog/SubmitView.tsx:110
|
||||
#: src/screens/Onboarding/Layout.tsx:120
|
||||
#: src/screens/Onboarding/Layout.tsx:213
|
||||
#: src/screens/Onboarding/Layout.tsx:121
|
||||
#: src/screens/Onboarding/Layout.tsx:214
|
||||
#: src/screens/Signup/BackNextButtons.tsx:35
|
||||
msgid "Go back to previous step"
|
||||
msgstr ""
|
||||
@@ -4099,8 +4099,8 @@ msgstr ""
|
||||
msgid "Go Home"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:330
|
||||
#: src/view/com/profile/ProfileMenu.tsx:337
|
||||
#: src/view/com/profile/ProfileMenu.tsx:335
|
||||
#: src/view/com/profile/ProfileMenu.tsx:342
|
||||
msgid "Go live"
|
||||
msgstr ""
|
||||
|
||||
@@ -4693,7 +4693,7 @@ msgid "Last initiated just now"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Hashtag.tsx:95
|
||||
#: src/screens/Search/SearchResults.tsx:57
|
||||
#: src/screens/Search/SearchResults.tsx:59
|
||||
#: src/screens/Topic.tsx:77
|
||||
msgid "Latest"
|
||||
msgstr ""
|
||||
@@ -5272,8 +5272,8 @@ msgid "More languages..."
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/ProfileList/components/MoreOptionsMenu.tsx:149
|
||||
#: src/view/com/profile/ProfileMenu.tsx:223
|
||||
#: src/view/com/profile/ProfileMenu.tsx:229
|
||||
#: src/view/com/profile/ProfileMenu.tsx:228
|
||||
#: src/view/com/profile/ProfileMenu.tsx:234
|
||||
msgid "More options"
|
||||
msgstr ""
|
||||
|
||||
@@ -5306,8 +5306,8 @@ msgstr ""
|
||||
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:628
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:634
|
||||
#: src/view/com/profile/ProfileMenu.tsx:375
|
||||
#: src/view/com/profile/ProfileMenu.tsx:382
|
||||
#: src/view/com/profile/ProfileMenu.tsx:380
|
||||
#: src/view/com/profile/ProfileMenu.tsx:387
|
||||
msgid "Mute account"
|
||||
msgstr ""
|
||||
|
||||
@@ -5548,7 +5548,7 @@ msgstr ""
|
||||
msgid "New posts from {firstAuthorName} and {additionalAuthorsCount, plural, one {{formattedAuthorsCount} other} other {{formattedAuthorsCount} others}}"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:192
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:193
|
||||
msgid "New starter pack"
|
||||
msgstr ""
|
||||
|
||||
@@ -5685,7 +5685,7 @@ msgstr ""
|
||||
msgid "No results"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/Explore.tsx:787
|
||||
#: src/screens/Search/Explore.tsx:797
|
||||
msgid "No results for \"{0}\"."
|
||||
msgstr ""
|
||||
|
||||
@@ -5697,13 +5697,13 @@ msgstr ""
|
||||
msgid "No results found for \"{query}\""
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/SearchResults.tsx:311
|
||||
#: src/screens/Search/SearchResults.tsx:347
|
||||
#: src/screens/Search/SearchResults.tsx:392
|
||||
#: src/screens/Search/SearchResults.tsx:313
|
||||
#: src/screens/Search/SearchResults.tsx:349
|
||||
#: src/screens/Search/SearchResults.tsx:394
|
||||
msgid "No results found for {query}"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/Explore.tsx:791
|
||||
#: src/screens/Search/Explore.tsx:801
|
||||
msgid "No results."
|
||||
msgstr ""
|
||||
|
||||
@@ -5758,7 +5758,7 @@ msgstr ""
|
||||
msgid "Not in Mississippi?"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:497
|
||||
#: src/view/com/profile/ProfileMenu.tsx:502
|
||||
msgid "Note about sharing"
|
||||
msgstr ""
|
||||
|
||||
@@ -6200,7 +6200,7 @@ msgid "Pause video"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/ProfileList/index.tsx:166
|
||||
#: src/screens/Search/SearchResults.tsx:67
|
||||
#: src/screens/Search/SearchResults.tsx:69
|
||||
#: src/screens/StarterPack/StarterPackScreen.tsx:189
|
||||
msgid "People"
|
||||
msgstr ""
|
||||
@@ -6222,7 +6222,7 @@ msgstr ""
|
||||
msgid "Permission to access your photo library was denied. Please enable it in your system settings."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:57
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:58
|
||||
msgid "Person toggle"
|
||||
msgstr ""
|
||||
|
||||
@@ -6263,7 +6263,7 @@ msgstr ""
|
||||
msgid "Pin to your profile"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/posts/PostFeedItem.tsx:408
|
||||
#: src/view/com/posts/PostFeedItem.tsx:426
|
||||
msgid "Pinned"
|
||||
msgstr ""
|
||||
|
||||
@@ -6881,11 +6881,11 @@ msgstr ""
|
||||
|
||||
#: src/components/dialogs/lists/ListAddRemoveUsersDialog.tsx:171
|
||||
#: src/components/dialogs/MutedWords.tsx:443
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:370
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:376
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:374
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:380
|
||||
#: src/components/FeedCard.tsx:343
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:104
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:111
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:105
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:112
|
||||
#: src/screens/Bookmarks/index.tsx:255
|
||||
#: src/screens/Settings/Settings.tsx:664
|
||||
#: src/view/com/modals/UserAddRemoveLists.tsx:235
|
||||
@@ -6893,7 +6893,7 @@ msgstr ""
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:60
|
||||
#: src/components/StarterPack/Wizard/WizardListCard.tsx:61
|
||||
msgid "Remove {displayName} from starter pack"
|
||||
msgstr ""
|
||||
|
||||
@@ -6996,8 +6996,8 @@ msgstr ""
|
||||
|
||||
#: src/components/verification/VerificationRemovePrompt.tsx:46
|
||||
#: src/components/verification/VerificationsDialog.tsx:252
|
||||
#: src/view/com/profile/ProfileMenu.tsx:348
|
||||
#: src/view/com/profile/ProfileMenu.tsx:351
|
||||
#: src/view/com/profile/ProfileMenu.tsx:353
|
||||
#: src/view/com/profile/ProfileMenu.tsx:356
|
||||
msgid "Remove verification"
|
||||
msgstr ""
|
||||
|
||||
@@ -7027,7 +7027,7 @@ msgstr ""
|
||||
msgid "Removed from saved posts"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:276
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:277
|
||||
msgid "Removed from starter pack"
|
||||
msgstr ""
|
||||
|
||||
@@ -7135,8 +7135,8 @@ msgstr ""
|
||||
msgid "Report"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:415
|
||||
#: src/view/com/profile/ProfileMenu.tsx:418
|
||||
#: src/view/com/profile/ProfileMenu.tsx:420
|
||||
#: src/view/com/profile/ProfileMenu.tsx:423
|
||||
msgid "Report account"
|
||||
msgstr ""
|
||||
|
||||
@@ -7246,16 +7246,16 @@ msgstr ""
|
||||
msgid "Reposted By"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/posts/PostFeedItem.tsx:348
|
||||
#: src/view/com/posts/PostFeedItem.tsx:366
|
||||
msgid "Reposted by {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/posts/PostFeedItem.tsx:367
|
||||
#: src/view/com/posts/PostFeedItem.tsx:385
|
||||
msgid "Reposted by <0><1/></0>"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/posts/PostFeedItem.tsx:346
|
||||
#: src/view/com/posts/PostFeedItem.tsx:365
|
||||
#: src/view/com/posts/PostFeedItem.tsx:364
|
||||
#: src/view/com/posts/PostFeedItem.tsx:383
|
||||
msgid "Reposted by you"
|
||||
msgstr ""
|
||||
|
||||
@@ -7500,8 +7500,8 @@ msgstr ""
|
||||
#: src/components/dialogs/SearchablePeopleList.tsx:514
|
||||
#: src/components/forms/SearchInput.tsx:34
|
||||
#: src/components/forms/SearchInput.tsx:36
|
||||
#: src/screens/Search/Shell.tsx:307
|
||||
#: src/screens/Search/Shell.tsx:463
|
||||
#: src/screens/Search/Shell.tsx:327
|
||||
#: src/screens/Search/Shell.tsx:513
|
||||
#: src/view/shell/bottom-bar/BottomBar.tsx:198
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
@@ -7549,7 +7549,7 @@ msgstr ""
|
||||
msgid "Search for more feeds"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/Shell.tsx:334
|
||||
#: src/screens/Search/Shell.tsx:354
|
||||
msgid "Search for posts, users, or feeds"
|
||||
msgstr ""
|
||||
|
||||
@@ -7557,7 +7557,7 @@ msgstr ""
|
||||
msgid "Search GIFs"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/SearchResults.tsx:253
|
||||
#: src/screens/Search/SearchResults.tsx:255
|
||||
msgid "Search is currently unavailable when logged out"
|
||||
msgstr ""
|
||||
|
||||
@@ -7570,8 +7570,8 @@ msgstr ""
|
||||
msgid "Search my posts"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:266
|
||||
#: src/view/com/profile/ProfileMenu.tsx:269
|
||||
#: src/view/com/profile/ProfileMenu.tsx:271
|
||||
#: src/view/com/profile/ProfileMenu.tsx:274
|
||||
msgid "Search posts"
|
||||
msgstr ""
|
||||
|
||||
@@ -7861,7 +7861,7 @@ msgstr ""
|
||||
msgid "Set new password"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Onboarding/Layout.tsx:49
|
||||
#: src/screens/Onboarding/Layout.tsx:50
|
||||
msgid "Set up your account"
|
||||
msgstr ""
|
||||
|
||||
@@ -7953,7 +7953,7 @@ msgstr ""
|
||||
msgid "Share a fun fact!"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:502
|
||||
#: src/view/com/profile/ProfileMenu.tsx:507
|
||||
msgid "Share anyway"
|
||||
msgstr ""
|
||||
|
||||
@@ -8001,8 +8001,8 @@ msgstr ""
|
||||
#: src/screens/ProfileList/components/MoreOptionsMenu.tsx:171
|
||||
#: src/screens/StarterPack/StarterPackScreen.tsx:615
|
||||
#: src/screens/StarterPack/StarterPackScreen.tsx:623
|
||||
#: src/view/com/profile/ProfileMenu.tsx:246
|
||||
#: src/view/com/profile/ProfileMenu.tsx:259
|
||||
#: src/view/com/profile/ProfileMenu.tsx:251
|
||||
#: src/view/com/profile/ProfileMenu.tsx:264
|
||||
msgid "Share via..."
|
||||
msgstr ""
|
||||
|
||||
@@ -8132,7 +8132,7 @@ msgstr ""
|
||||
#: src/screens/Login/index.tsx:136
|
||||
#: src/screens/Login/index.tsx:157
|
||||
#: src/screens/Login/LoginForm.tsx:181
|
||||
#: src/screens/Search/SearchResults.tsx:258
|
||||
#: src/screens/Search/SearchResults.tsx:260
|
||||
#: src/view/com/auth/SplashScreen.tsx:81
|
||||
#: src/view/com/auth/SplashScreen.tsx:89
|
||||
#: src/view/com/auth/SplashScreen.web.tsx:127
|
||||
@@ -8684,7 +8684,7 @@ msgid "That's everything!"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:324
|
||||
#: src/view/com/profile/ProfileMenu.tsx:478
|
||||
#: src/view/com/profile/ProfileMenu.tsx:483
|
||||
msgid "The account will be able to interact with you after unblocking."
|
||||
msgstr ""
|
||||
|
||||
@@ -8820,7 +8820,7 @@ msgstr ""
|
||||
msgid "There was an issue fetching notifications. Tap here to try again."
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/Explore.tsx:986
|
||||
#: src/screens/Search/Explore.tsx:996
|
||||
#: src/view/com/posts/PostFeed.tsx:709
|
||||
msgid "There was an issue fetching posts. Tap here to try again."
|
||||
msgstr ""
|
||||
@@ -8865,12 +8865,12 @@ msgstr ""
|
||||
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:101
|
||||
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:123
|
||||
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:136
|
||||
#: src/view/com/profile/ProfileMenu.tsx:131
|
||||
#: src/view/com/profile/ProfileMenu.tsx:141
|
||||
#: src/view/com/profile/ProfileMenu.tsx:155
|
||||
#: src/view/com/profile/ProfileMenu.tsx:165
|
||||
#: src/view/com/profile/ProfileMenu.tsx:178
|
||||
#: src/view/com/profile/ProfileMenu.tsx:190
|
||||
#: src/view/com/profile/ProfileMenu.tsx:136
|
||||
#: src/view/com/profile/ProfileMenu.tsx:146
|
||||
#: src/view/com/profile/ProfileMenu.tsx:160
|
||||
#: src/view/com/profile/ProfileMenu.tsx:170
|
||||
#: src/view/com/profile/ProfileMenu.tsx:183
|
||||
#: src/view/com/profile/ProfileMenu.tsx:195
|
||||
msgid "There was an issue! {0}"
|
||||
msgstr ""
|
||||
|
||||
@@ -9073,7 +9073,7 @@ msgstr ""
|
||||
msgid "This post's author has disabled quote posts."
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:499
|
||||
#: src/view/com/profile/ProfileMenu.tsx:504
|
||||
msgid "This profile is only visible to logged-in users. It won't be visible to people who aren't signed in."
|
||||
msgstr ""
|
||||
|
||||
@@ -9199,7 +9199,7 @@ msgid "Toggles the sound"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Hashtag.tsx:84
|
||||
#: src/screens/Search/SearchResults.tsx:47
|
||||
#: src/screens/Search/SearchResults.tsx:49
|
||||
#: src/screens/Topic.tsx:71
|
||||
msgid "Top"
|
||||
msgstr ""
|
||||
@@ -9312,7 +9312,7 @@ msgstr ""
|
||||
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:328
|
||||
#: src/screens/ProfileList/components/Header.tsx:171
|
||||
#: src/screens/ProfileList/components/Header.tsx:178
|
||||
#: src/view/com/profile/ProfileMenu.tsx:490
|
||||
#: src/view/com/profile/ProfileMenu.tsx:495
|
||||
msgid "Unblock"
|
||||
msgstr ""
|
||||
|
||||
@@ -9323,13 +9323,13 @@ msgstr ""
|
||||
|
||||
#: src/components/dms/ConvoMenu.tsx:247
|
||||
#: src/components/dms/ConvoMenu.tsx:250
|
||||
#: src/view/com/profile/ProfileMenu.tsx:395
|
||||
#: src/view/com/profile/ProfileMenu.tsx:401
|
||||
#: src/view/com/profile/ProfileMenu.tsx:400
|
||||
#: src/view/com/profile/ProfileMenu.tsx:406
|
||||
msgid "Unblock account"
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:322
|
||||
#: src/view/com/profile/ProfileMenu.tsx:472
|
||||
#: src/view/com/profile/ProfileMenu.tsx:477
|
||||
msgid "Unblock Account?"
|
||||
msgstr ""
|
||||
|
||||
@@ -9362,8 +9362,8 @@ msgstr ""
|
||||
msgid "Unfollow {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/profile/ProfileMenu.tsx:286
|
||||
#: src/view/com/profile/ProfileMenu.tsx:296
|
||||
#: src/view/com/profile/ProfileMenu.tsx:291
|
||||
#: src/view/com/profile/ProfileMenu.tsx:301
|
||||
msgid "Unfollow account"
|
||||
msgstr ""
|
||||
|
||||
@@ -9410,8 +9410,8 @@ msgstr ""
|
||||
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:627
|
||||
#: src/components/PostControls/PostMenu/PostMenuItems.tsx:633
|
||||
#: src/view/com/profile/ProfileMenu.tsx:374
|
||||
#: src/view/com/profile/ProfileMenu.tsx:380
|
||||
#: src/view/com/profile/ProfileMenu.tsx:379
|
||||
#: src/view/com/profile/ProfileMenu.tsx:385
|
||||
msgid "Unmute account"
|
||||
msgstr ""
|
||||
|
||||
@@ -9734,8 +9734,8 @@ msgstr ""
|
||||
|
||||
#: src/components/verification/VerificationCreatePrompt.tsx:84
|
||||
#: src/components/verification/VerificationCreatePrompt.tsx:86
|
||||
#: src/view/com/profile/ProfileMenu.tsx:358
|
||||
#: src/view/com/profile/ProfileMenu.tsx:361
|
||||
#: src/view/com/profile/ProfileMenu.tsx:363
|
||||
#: src/view/com/profile/ProfileMenu.tsx:366
|
||||
msgid "Verify account"
|
||||
msgstr ""
|
||||
|
||||
@@ -10143,7 +10143,7 @@ msgstr ""
|
||||
msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: src/screens/Search/SearchResults.tsx:285
|
||||
#: src/screens/Search/SearchResults.tsx:287
|
||||
msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
|
||||
msgstr ""
|
||||
|
||||
@@ -10299,7 +10299,7 @@ msgstr ""
|
||||
msgid "www.mylivestream.tv"
|
||||
msgstr ""
|
||||
|
||||
#: src/view/com/composer/select-language/SuggestedLanguage.tsx:181
|
||||
#: src/view/com/composer/select-language/SuggestedLanguage.tsx:180
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
@@ -10512,7 +10512,7 @@ msgstr ""
|
||||
msgid "You have no lists."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:100
|
||||
#: src/components/dialogs/StarterPackDialog.tsx:101
|
||||
msgid "You have no starter packs."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -29,4 +29,5 @@ init({
|
||||
* @see https://docs.sentry.io/platforms/react-native/configuration/options/#attach-stacktrace
|
||||
*/
|
||||
attachStacktrace: false,
|
||||
sampleRate: env.IS_INTERNAL ? 1.0 : 0.1,
|
||||
})
|
||||
|
||||
@@ -42,11 +42,14 @@ import {Trash_Stroke2_Corner0_Rounded} from '#/components/icons/Trash'
|
||||
import {Link} from '#/components/Link'
|
||||
import {useMenuControl} from '#/components/Menu'
|
||||
import {PostAlerts} from '#/components/moderation/PostAlerts'
|
||||
import {createPortalGroup} from '#/components/Portal'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export const ChatListItemPortal = createPortalGroup()
|
||||
|
||||
export let ChatListItem = ({
|
||||
convo,
|
||||
showMenu = true,
|
||||
@@ -331,200 +334,215 @@ function ChatListItemReady({
|
||||
const hasUnread = convo.unreadCount > 0 && !isDeletedAccount
|
||||
|
||||
return (
|
||||
<GestureActionView actions={actions}>
|
||||
<View
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
// @ts-expect-error web only
|
||||
onFocus={onFocus}
|
||||
onBlur={onMouseLeave}
|
||||
style={[a.relative, t.atoms.bg]}>
|
||||
<ChatListItemPortal.Provider>
|
||||
<GestureActionView actions={actions}>
|
||||
<View
|
||||
style={[
|
||||
a.z_10,
|
||||
a.absolute,
|
||||
{top: tokens.space.md, left: tokens.space.lg},
|
||||
]}>
|
||||
<PreviewableUserAvatar
|
||||
profile={profile}
|
||||
size={52}
|
||||
moderation={moderation.ui('avatar')}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Link
|
||||
to={`/messages/${convo.id}`}
|
||||
label={displayName}
|
||||
accessibilityHint={
|
||||
!isDeletedAccount
|
||||
? _(msg`Go to conversation with ${profile.handle}`)
|
||||
: _(
|
||||
msg`This conversation is with a deleted or a deactivated account. Press for options`,
|
||||
)
|
||||
}
|
||||
accessibilityActions={
|
||||
isNative
|
||||
? [
|
||||
{name: 'magicTap', label: _(msg`Open conversation options`)},
|
||||
{name: 'longpress', label: _(msg`Open conversation options`)},
|
||||
]
|
||||
: undefined
|
||||
}
|
||||
onPress={onPress}
|
||||
onLongPress={isNative ? onLongPress : undefined}
|
||||
onAccessibilityAction={onLongPress}>
|
||||
{({hovered, pressed, focused}) => (
|
||||
<View
|
||||
style={[
|
||||
a.flex_row,
|
||||
isDeletedAccount ? a.align_center : a.align_start,
|
||||
a.flex_1,
|
||||
a.px_lg,
|
||||
a.py_md,
|
||||
a.gap_md,
|
||||
(hovered || pressed || focused) && t.atoms.bg_contrast_25,
|
||||
]}>
|
||||
{/* Avatar goes here */}
|
||||
<View style={{width: 52, height: 52}} />
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
// @ts-expect-error web only
|
||||
onFocus={onFocus}
|
||||
onBlur={onMouseLeave}
|
||||
style={[a.relative, t.atoms.bg]}>
|
||||
<View
|
||||
style={[
|
||||
a.z_10,
|
||||
a.absolute,
|
||||
{top: tokens.space.md, left: tokens.space.lg},
|
||||
]}>
|
||||
<PreviewableUserAvatar
|
||||
profile={profile}
|
||||
size={52}
|
||||
moderation={moderation.ui('avatar')}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Link
|
||||
to={`/messages/${convo.id}`}
|
||||
label={displayName}
|
||||
accessibilityHint={
|
||||
!isDeletedAccount
|
||||
? _(msg`Go to conversation with ${profile.handle}`)
|
||||
: _(
|
||||
msg`This conversation is with a deleted or a deactivated account. Press for options`,
|
||||
)
|
||||
}
|
||||
accessibilityActions={
|
||||
isNative
|
||||
? [
|
||||
{
|
||||
name: 'magicTap',
|
||||
label: _(msg`Open conversation options`),
|
||||
},
|
||||
{
|
||||
name: 'longpress',
|
||||
label: _(msg`Open conversation options`),
|
||||
},
|
||||
]
|
||||
: undefined
|
||||
}
|
||||
onPress={onPress}
|
||||
onLongPress={isNative ? onLongPress : undefined}
|
||||
onAccessibilityAction={onLongPress}>
|
||||
{({hovered, pressed, focused}) => (
|
||||
<View
|
||||
style={[a.flex_1, a.justify_center, web({paddingRight: 45})]}>
|
||||
<View style={[a.w_full, a.flex_row, a.align_end, a.pb_2xs]}>
|
||||
<View style={[a.flex_shrink]}>
|
||||
style={[
|
||||
a.flex_row,
|
||||
isDeletedAccount ? a.align_center : a.align_start,
|
||||
a.flex_1,
|
||||
a.px_lg,
|
||||
a.py_md,
|
||||
a.gap_md,
|
||||
(hovered || pressed || focused) && t.atoms.bg_contrast_25,
|
||||
]}>
|
||||
{/* Avatar goes here */}
|
||||
<View style={{width: 52, height: 52}} />
|
||||
|
||||
<View
|
||||
style={[a.flex_1, a.justify_center, web({paddingRight: 45})]}>
|
||||
<View style={[a.w_full, a.flex_row, a.align_end, a.pb_2xs]}>
|
||||
<View style={[a.flex_shrink]}>
|
||||
<Text
|
||||
emoji
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
a.text_md,
|
||||
t.atoms.text,
|
||||
a.font_semi_bold,
|
||||
{lineHeight: 21},
|
||||
isDimStyle && t.atoms.text_contrast_medium,
|
||||
]}>
|
||||
{displayName}
|
||||
</Text>
|
||||
</View>
|
||||
{verification.showBadge && (
|
||||
<View style={[a.pl_xs, a.self_center]}>
|
||||
<VerificationCheck
|
||||
width={14}
|
||||
verifier={verification.role === 'verifier'}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{lastMessageSentAt && (
|
||||
<View style={[a.pl_xs]}>
|
||||
<TimeElapsed timestamp={lastMessageSentAt}>
|
||||
{({timeElapsed}) => (
|
||||
<Text
|
||||
style={[
|
||||
a.text_sm,
|
||||
{lineHeight: 21},
|
||||
t.atoms.text_contrast_medium,
|
||||
web({whiteSpace: 'preserve nowrap'}),
|
||||
]}>
|
||||
· {timeElapsed}
|
||||
</Text>
|
||||
)}
|
||||
</TimeElapsed>
|
||||
</View>
|
||||
)}
|
||||
{(convo.muted || moderation.blocked) && (
|
||||
<Text
|
||||
style={[
|
||||
a.text_sm,
|
||||
{lineHeight: 21},
|
||||
t.atoms.text_contrast_medium,
|
||||
web({whiteSpace: 'preserve nowrap'}),
|
||||
]}>
|
||||
{' '}
|
||||
·{' '}
|
||||
<BellStroke
|
||||
size="xs"
|
||||
style={[t.atoms.text_contrast_medium]}
|
||||
/>
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{!isDeletedAccount && (
|
||||
<Text
|
||||
emoji
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
a.text_md,
|
||||
t.atoms.text,
|
||||
a.font_semi_bold,
|
||||
{lineHeight: 21},
|
||||
isDimStyle && t.atoms.text_contrast_medium,
|
||||
]}>
|
||||
{displayName}
|
||||
</Text>
|
||||
</View>
|
||||
{verification.showBadge && (
|
||||
<View style={[a.pl_xs, a.self_center]}>
|
||||
<VerificationCheck
|
||||
width={14}
|
||||
verifier={verification.role === 'verifier'}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{lastMessageSentAt && (
|
||||
<View style={[a.pl_xs]}>
|
||||
<TimeElapsed timestamp={lastMessageSentAt}>
|
||||
{({timeElapsed}) => (
|
||||
<Text
|
||||
style={[
|
||||
a.text_sm,
|
||||
{lineHeight: 21},
|
||||
t.atoms.text_contrast_medium,
|
||||
web({whiteSpace: 'preserve nowrap'}),
|
||||
]}>
|
||||
· {timeElapsed}
|
||||
</Text>
|
||||
)}
|
||||
</TimeElapsed>
|
||||
</View>
|
||||
)}
|
||||
{(convo.muted || moderation.blocked) && (
|
||||
<Text
|
||||
style={[
|
||||
a.text_sm,
|
||||
{lineHeight: 21},
|
||||
t.atoms.text_contrast_medium,
|
||||
web({whiteSpace: 'preserve nowrap'}),
|
||||
a.pb_xs,
|
||||
]}>
|
||||
{' '}
|
||||
·{' '}
|
||||
<BellStroke
|
||||
size="xs"
|
||||
style={[t.atoms.text_contrast_medium]}
|
||||
/>
|
||||
@{profile.handle}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Text
|
||||
emoji
|
||||
numberOfLines={2}
|
||||
style={[
|
||||
a.text_sm,
|
||||
a.leading_snug,
|
||||
hasUnread ? a.font_semi_bold : t.atoms.text_contrast_high,
|
||||
isDimStyle && t.atoms.text_contrast_medium,
|
||||
]}>
|
||||
{lastMessage}
|
||||
</Text>
|
||||
|
||||
<PostAlerts
|
||||
modui={moderation.ui('contentList')}
|
||||
size="lg"
|
||||
style={[a.pt_xs]}
|
||||
/>
|
||||
|
||||
{children}
|
||||
</View>
|
||||
|
||||
{!isDeletedAccount && (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[a.text_sm, t.atoms.text_contrast_medium, a.pb_xs]}>
|
||||
@{profile.handle}
|
||||
</Text>
|
||||
{hasUnread && (
|
||||
<View
|
||||
style={[
|
||||
a.absolute,
|
||||
a.rounded_full,
|
||||
{
|
||||
backgroundColor: isDimStyle
|
||||
? t.palette.contrast_200
|
||||
: t.palette.primary_500,
|
||||
height: 7,
|
||||
width: 7,
|
||||
top: 15,
|
||||
right: 12,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Text
|
||||
emoji
|
||||
numberOfLines={2}
|
||||
style={[
|
||||
a.text_sm,
|
||||
a.leading_snug,
|
||||
hasUnread ? a.font_semi_bold : t.atoms.text_contrast_high,
|
||||
isDimStyle && t.atoms.text_contrast_medium,
|
||||
]}>
|
||||
{lastMessage}
|
||||
</Text>
|
||||
|
||||
<PostAlerts
|
||||
modui={moderation.ui('contentList')}
|
||||
size="lg"
|
||||
style={[a.pt_xs]}
|
||||
/>
|
||||
|
||||
{children}
|
||||
</View>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
{hasUnread && (
|
||||
<View
|
||||
style={[
|
||||
a.absolute,
|
||||
a.rounded_full,
|
||||
{
|
||||
backgroundColor: isDimStyle
|
||||
? t.palette.contrast_200
|
||||
: t.palette.primary_500,
|
||||
height: 7,
|
||||
width: 7,
|
||||
top: 15,
|
||||
right: 12,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<ChatListItemPortal.Outlet />
|
||||
|
||||
{showMenu && (
|
||||
<ConvoMenu
|
||||
convo={convo}
|
||||
profile={profile}
|
||||
control={menuControl}
|
||||
currentScreen="list"
|
||||
showMarkAsRead={convo.unreadCount > 0}
|
||||
hideTrigger={isNative}
|
||||
blockInfo={blockInfo}
|
||||
style={[
|
||||
a.absolute,
|
||||
a.h_full,
|
||||
a.self_end,
|
||||
a.justify_center,
|
||||
{
|
||||
right: tokens.space.lg,
|
||||
opacity:
|
||||
!gtMobile || showActions || menuControl.isOpen ? 1 : 0,
|
||||
},
|
||||
]}
|
||||
latestReportableMessage={latestReportableMessage}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
{showMenu && (
|
||||
<ConvoMenu
|
||||
convo={convo}
|
||||
profile={profile}
|
||||
control={menuControl}
|
||||
<LeaveConvoPrompt
|
||||
control={leaveConvoControl}
|
||||
convoId={convo.id}
|
||||
currentScreen="list"
|
||||
showMarkAsRead={convo.unreadCount > 0}
|
||||
hideTrigger={isNative}
|
||||
blockInfo={blockInfo}
|
||||
style={[
|
||||
a.absolute,
|
||||
a.h_full,
|
||||
a.self_end,
|
||||
a.justify_center,
|
||||
{
|
||||
right: tokens.space.lg,
|
||||
opacity: !gtMobile || showActions || menuControl.isOpen ? 1 : 0,
|
||||
},
|
||||
]}
|
||||
latestReportableMessage={latestReportableMessage}
|
||||
/>
|
||||
)}
|
||||
<LeaveConvoPrompt
|
||||
control={leaveConvoControl}
|
||||
convoId={convo.id}
|
||||
currentScreen="list"
|
||||
/>
|
||||
</View>
|
||||
</GestureActionView>
|
||||
</View>
|
||||
</GestureActionView>
|
||||
</ChatListItemPortal.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export function ChatStatusInfo({convoState}: {convoState: ActiveConvoStates}) {
|
||||
label={_(msg`Block or report`)}
|
||||
convo={convoState.convo}
|
||||
profile={otherUser}
|
||||
color="negative"
|
||||
color="negative_subtle"
|
||||
size="small"
|
||||
currentScreen="conversation"
|
||||
/>
|
||||
@@ -70,8 +70,7 @@ export function ChatStatusInfo({convoState}: {convoState: ActiveConvoStates}) {
|
||||
<AcceptChatButton
|
||||
onAcceptConvo={onAcceptChat}
|
||||
convo={convoState.convo}
|
||||
color="primary"
|
||||
variant="outline"
|
||||
color="primary_subtle"
|
||||
size="small"
|
||||
currentScreen="conversation"
|
||||
/>
|
||||
|
||||
@@ -36,7 +36,6 @@ export function RejectMenu({
|
||||
convo,
|
||||
profile,
|
||||
size = 'tiny',
|
||||
variant = 'outline',
|
||||
color = 'secondary',
|
||||
label,
|
||||
showDeleteConvo,
|
||||
@@ -117,7 +116,6 @@ export function RejectMenu({
|
||||
label={triggerProps.accessibilityLabel}
|
||||
style={[a.flex_1]}
|
||||
color={color}
|
||||
variant={variant}
|
||||
size={size}>
|
||||
<ButtonText>
|
||||
{label || (
|
||||
@@ -129,7 +127,7 @@ export function RejectMenu({
|
||||
</Button>
|
||||
)}
|
||||
</Menu.Trigger>
|
||||
<Menu.Outer>
|
||||
<Menu.Outer showCancel>
|
||||
<Menu.Group>
|
||||
{showDeleteConvo && (
|
||||
<Menu.Item
|
||||
@@ -181,7 +179,6 @@ export function RejectMenu({
|
||||
export function AcceptChatButton({
|
||||
convo,
|
||||
size = 'tiny',
|
||||
variant = 'solid',
|
||||
color = 'secondary_inverted',
|
||||
label,
|
||||
currentScreen,
|
||||
@@ -248,7 +245,6 @@ export function AcceptChatButton({
|
||||
{...props}
|
||||
label={label || _(msg`Accept chat request`)}
|
||||
size={size}
|
||||
variant={variant}
|
||||
color={color}
|
||||
style={a.flex_1}
|
||||
onPress={onPressAccept}>
|
||||
@@ -266,7 +262,6 @@ export function AcceptChatButton({
|
||||
export function DeleteChatButton({
|
||||
convo,
|
||||
size = 'tiny',
|
||||
variant = 'outline',
|
||||
color = 'secondary',
|
||||
label,
|
||||
currentScreen,
|
||||
@@ -315,7 +310,6 @@ export function DeleteChatButton({
|
||||
<Button
|
||||
label={label || _(msg`Delete chat`)}
|
||||
size={size}
|
||||
variant={variant}
|
||||
color={color}
|
||||
style={a.flex_1}
|
||||
onPress={onPressDelete}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {useSession} from '#/state/session'
|
||||
import {atoms as a, tokens} from '#/alf'
|
||||
import {KnownFollowers} from '#/components/KnownFollowers'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {ChatListItem} from './ChatListItem'
|
||||
import {ChatListItem, ChatListItemPortal} from './ChatListItem'
|
||||
import {AcceptChatButton, DeleteChatButton, RejectMenu} from './RequestButtons'
|
||||
|
||||
export function RequestListItem({convo}: {convo: ChatBskyConvoDefs.ConvoView}) {
|
||||
@@ -42,37 +42,40 @@ export function RequestListItem({convo}: {convo: ChatBskyConvoDefs.ConvoView}) {
|
||||
<Trans comment="Accept a chat request">Accept Request</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
{/* then, this gets absolutely positioned on top of the spacer */}
|
||||
<ChatListItemPortal.Portal>
|
||||
<View
|
||||
style={[
|
||||
a.absolute,
|
||||
a.pr_md,
|
||||
a.w_full,
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
a.gap_sm,
|
||||
{
|
||||
bottom: tokens.space.md,
|
||||
paddingLeft: tokens.space.lg + 52 + tokens.space.md,
|
||||
},
|
||||
]}>
|
||||
{!isDeletedAccount ? (
|
||||
<>
|
||||
<AcceptChatButton convo={convo} currentScreen="list" />
|
||||
<RejectMenu
|
||||
convo={convo}
|
||||
profile={otherUser}
|
||||
showDeleteConvo
|
||||
currentScreen="list"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<DeleteChatButton convo={convo} currentScreen="list" />
|
||||
<View style={a.flex_1} />
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</ChatListItemPortal.Portal>
|
||||
</ChatListItem>
|
||||
<View
|
||||
style={[
|
||||
a.absolute,
|
||||
a.pr_md,
|
||||
a.w_full,
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
a.gap_sm,
|
||||
{
|
||||
bottom: tokens.space.md,
|
||||
paddingLeft: tokens.space.lg + 52 + tokens.space.md,
|
||||
},
|
||||
]}>
|
||||
{!isDeletedAccount ? (
|
||||
<>
|
||||
<AcceptChatButton convo={convo} currentScreen="list" />
|
||||
<RejectMenu
|
||||
convo={convo}
|
||||
profile={otherUser}
|
||||
showDeleteConvo
|
||||
currentScreen="list"
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<DeleteChatButton convo={convo} currentScreen="list" />
|
||||
<View style={a.flex_1} />
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ function Page({
|
||||
]}>
|
||||
<Image
|
||||
source={image}
|
||||
style={[a.w_full, {aspectRatio: 1}]}
|
||||
style={[a.w_full, a.aspect_square]}
|
||||
alt={alt}
|
||||
accessibilityIgnoresInvertColors={false} // I guess we do need it to blend into the background
|
||||
/>
|
||||
|
||||
@@ -2,7 +2,6 @@ import {useMemo, useReducer} from 'react'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useGate} from '#/lib/statsig/statsig'
|
||||
import {
|
||||
Layout,
|
||||
OnboardingControls,
|
||||
@@ -13,21 +12,19 @@ import {StepFinished} from '#/screens/Onboarding/StepFinished'
|
||||
import {StepInterests} from '#/screens/Onboarding/StepInterests'
|
||||
import {StepProfile} from '#/screens/Onboarding/StepProfile'
|
||||
import {Portal} from '#/components/Portal'
|
||||
import {ENV} from '#/env'
|
||||
import {StepSuggestedAccounts} from './StepSuggestedAccounts'
|
||||
|
||||
export function Onboarding() {
|
||||
const {_} = useLingui()
|
||||
const gate = useGate()
|
||||
const showValueProp = ENV !== 'e2e' && gate('onboarding_value_prop')
|
||||
const showSuggestedAccounts =
|
||||
ENV !== 'e2e' && gate('onboarding_suggested_accounts')
|
||||
|
||||
const [state, dispatch] = useReducer(reducer, {
|
||||
...initialState,
|
||||
totalSteps: showSuggestedAccounts ? 4 : 3,
|
||||
totalSteps: 4,
|
||||
experiments: {
|
||||
onboarding_suggested_accounts: showSuggestedAccounts,
|
||||
onboarding_value_prop: showValueProp,
|
||||
// let's leave this flag logic in for now to avoid rebase churn
|
||||
// TODO: remove this flag logic once we've finished with all experiments -sfn
|
||||
onboarding_suggested_accounts: true,
|
||||
onboarding_value_prop: true,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -39,13 +39,12 @@ import {
|
||||
OUTER_SPACE,
|
||||
REPLY_LINE_WIDTH,
|
||||
} from '#/screens/PostThread/const'
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {colors} from '#/components/Admonition'
|
||||
import {Button} from '#/components/Button'
|
||||
import {CalendarClock_Stroke2_Corner0_Rounded as CalendarClockIcon} from '#/components/icons/CalendarClock'
|
||||
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
|
||||
import {InlineLinkText, Link} from '#/components/Link'
|
||||
import {LoggedOutCTA} from '#/components/LoggedOutCTA'
|
||||
import {ContentHider} from '#/components/moderation/ContentHider'
|
||||
import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe'
|
||||
import {PostAlerts} from '#/components/moderation/PostAlerts'
|
||||
@@ -180,7 +179,6 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
||||
const {_} = useLingui()
|
||||
const {openComposer} = useOpenComposer()
|
||||
const {currentAccount, hasSession} = useSession()
|
||||
const {gtTablet} = useBreakpoints()
|
||||
const feedFeedback = useFeedFeedback(postSource?.feedSourceInfo, hasSession)
|
||||
const formatPostStatCount = useFormatPostStatCount()
|
||||
|
||||
@@ -315,8 +313,6 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({
|
||||
},
|
||||
isRoot && [a.pt_lg],
|
||||
]}>
|
||||
{/* Show CTA for logged-out visitors - hide on desktop and check gate */}
|
||||
{!gtTablet && <LoggedOutCTA gateName="cta_above_post_heading" />}
|
||||
<View style={[a.flex_row, a.gap_md, a.pb_md]}>
|
||||
<View collapsable={false}>
|
||||
<PreviewableUserAvatar
|
||||
|
||||
@@ -132,9 +132,7 @@ const ThreadItemPostOuterWrapper = memo(function ThreadItemPostOuterWrapper({
|
||||
<View
|
||||
style={[
|
||||
showTopBorder && [a.border_t, t.atoms.border_contrast_low],
|
||||
{
|
||||
paddingHorizontal: OUTER_SPACE,
|
||||
},
|
||||
{paddingHorizontal: OUTER_SPACE},
|
||||
// If there's no next child, add a little padding to bottom
|
||||
!item.ui.showChildReplyLine &&
|
||||
!item.ui.precedesChildReadMore && {
|
||||
@@ -255,8 +253,9 @@ const ThreadItemPostInner = memo(function ThreadItemPostInner({
|
||||
href={postHref}
|
||||
disabled={overrides?.moderation === true}
|
||||
modui={moderation.ui('contentList')}
|
||||
hiderStyle={[a.pl_0, a.pr_2xs, a.bg_transparent]}
|
||||
iconSize={LINEAR_AVI_WIDTH}
|
||||
iconStyles={{marginLeft: 2, marginRight: 2}}
|
||||
iconStyles={[a.mr_xs]}
|
||||
profile={post.author}
|
||||
interpretFilterAsBlur>
|
||||
<ThreadItemPostParentReplyLine item={item} />
|
||||
|
||||
@@ -38,7 +38,6 @@ import {
|
||||
import {atoms as a, native, platform, useBreakpoints, web} from '#/alf'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {ListFooter} from '#/components/Lists'
|
||||
import {LoggedOutCTA} from '#/components/LoggedOutCTA'
|
||||
|
||||
const PARENT_CHUNK_SIZE = 5
|
||||
const CHILDREN_CHUNK_SIZE = 50
|
||||
@@ -410,8 +409,6 @@ export function PostThread({uri}: {uri: string}) {
|
||||
onPostSuccess={optimisticOnPostReply}
|
||||
postSource={anchorPostSource}
|
||||
/>
|
||||
{/* Show CTA for logged-out visitors */}
|
||||
<LoggedOutCTA style={a.px_lg} gateName="cta_above_post_replies" />
|
||||
</View>
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -726,7 +726,12 @@ export function Explore({
|
||||
<ModuleHeader.SearchButton
|
||||
{...item.searchButton}
|
||||
onPress={() =>
|
||||
focusSearchInput(item.searchButton?.tab || 'user')
|
||||
focusSearchInput(
|
||||
(item.searchButton?.tab || 'user') as
|
||||
| 'user'
|
||||
| 'profile'
|
||||
| 'feed',
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
@@ -743,7 +748,12 @@ export function Explore({
|
||||
<ModuleHeader.SearchButton
|
||||
{...item.searchButton}
|
||||
onPress={() =>
|
||||
focusSearchInput(item.searchButton?.tab || 'user')
|
||||
focusSearchInput(
|
||||
(item.searchButton?.tab || 'user') as
|
||||
| 'user'
|
||||
| 'profile'
|
||||
| 'feed',
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -30,12 +30,14 @@ let SearchResults = ({
|
||||
activeTab,
|
||||
onPageSelected,
|
||||
headerHeight,
|
||||
initialPage = 0,
|
||||
}: {
|
||||
query: string
|
||||
queryWithParams: string
|
||||
activeTab: number
|
||||
onPageSelected: (page: number) => void
|
||||
headerHeight: number
|
||||
initialPage?: number
|
||||
}): React.ReactNode => {
|
||||
const {_} = useLingui()
|
||||
|
||||
@@ -89,7 +91,7 @@ let SearchResults = ({
|
||||
<TabBar items={sections.map(section => section.title)} {...props} />
|
||||
</Layout.Center>
|
||||
)}
|
||||
initialPage={0}>
|
||||
initialPage={initialPage}>
|
||||
{sections.map((section, i) => (
|
||||
<View key={i}>{section.component}</View>
|
||||
))}
|
||||
|
||||
@@ -190,15 +190,19 @@ export function SearchScreenShell({
|
||||
setShowAutocomplete(false)
|
||||
if (isWeb) {
|
||||
// Empty params resets the URL to be /search rather than /search?q=
|
||||
|
||||
const {q: _q, ...parameters} = (route.params ?? {}) as {
|
||||
// Also clear the tab parameter
|
||||
const {
|
||||
q: _q,
|
||||
tab: _tab,
|
||||
...parameters
|
||||
} = (route.params ?? {}) as {
|
||||
[key: string]: string
|
||||
}
|
||||
// @ts-expect-error route is not typesafe
|
||||
navigation.replace(route.name, parameters)
|
||||
} else {
|
||||
setSearchText('')
|
||||
navigation.setParams({q: ''})
|
||||
navigation.setParams({q: '', tab: undefined})
|
||||
}
|
||||
}, [setShowAutocomplete, setSearchText, navigation, route.params, route.name])
|
||||
|
||||
@@ -236,15 +240,19 @@ export function SearchScreenShell({
|
||||
const onSoftReset = useCallback(() => {
|
||||
if (isWeb) {
|
||||
// Empty params resets the URL to be /search rather than /search?q=
|
||||
|
||||
const {q: _q, ...parameters} = (route.params ?? {}) as {
|
||||
// Also clear the tab parameter when soft resetting
|
||||
const {
|
||||
q: _q,
|
||||
tab: _tab,
|
||||
...parameters
|
||||
} = (route.params ?? {}) as {
|
||||
[key: string]: string
|
||||
}
|
||||
// @ts-expect-error route is not typesafe
|
||||
navigation.replace(route.name, parameters)
|
||||
} else {
|
||||
setSearchText('')
|
||||
navigation.setParams({q: ''})
|
||||
navigation.setParams({q: '', tab: undefined})
|
||||
textInput.current?.focus()
|
||||
}
|
||||
}, [navigation, route])
|
||||
@@ -268,9 +276,21 @@ export function SearchScreenShell({
|
||||
}
|
||||
}, [setShowAutocomplete])
|
||||
|
||||
const focusSearchInput = useCallback(() => {
|
||||
textInput.current?.focus()
|
||||
}, [])
|
||||
const focusSearchInput = useCallback(
|
||||
(tab?: 'user' | 'profile' | 'feed') => {
|
||||
textInput.current?.focus()
|
||||
|
||||
// If a tab is specified, set the tab parameter
|
||||
if (tab) {
|
||||
if (isWeb) {
|
||||
navigation.setParams({...route.params, tab})
|
||||
} else {
|
||||
navigation.setParams({tab})
|
||||
}
|
||||
}
|
||||
},
|
||||
[navigation, route],
|
||||
)
|
||||
|
||||
const showHeader = !gtMobile || navButton !== 'menu'
|
||||
|
||||
@@ -421,13 +441,42 @@ let SearchScreenInner = ({
|
||||
query: string
|
||||
queryWithParams: string
|
||||
headerHeight: number
|
||||
focusSearchInput: () => void
|
||||
focusSearchInput: (tab?: 'user' | 'profile' | 'feed') => void
|
||||
}): React.ReactNode => {
|
||||
const t = useTheme()
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {hasSession} = useSession()
|
||||
const {gtTablet} = useBreakpoints()
|
||||
const [activeTab, setActiveTab] = useState(0)
|
||||
const route = useRoute()
|
||||
|
||||
// Get tab parameter from route params
|
||||
const tabParam = (
|
||||
route.params as {q?: string; tab?: 'user' | 'profile' | 'feed'}
|
||||
)?.tab
|
||||
|
||||
// Map tab parameter to tab index
|
||||
const getInitialTabIndex = useCallback(() => {
|
||||
if (!tabParam) return 0
|
||||
switch (tabParam) {
|
||||
case 'user':
|
||||
case 'profile':
|
||||
return 2 // People tab
|
||||
case 'feed':
|
||||
return 3 // Feeds tab
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}, [tabParam])
|
||||
|
||||
const [activeTab, setActiveTab] = useState(getInitialTabIndex())
|
||||
|
||||
// Update activeTab when tabParam changes
|
||||
useLayoutEffect(() => {
|
||||
const newTabIndex = getInitialTabIndex()
|
||||
if (newTabIndex !== activeTab) {
|
||||
setActiveTab(newTabIndex)
|
||||
}
|
||||
}, [tabParam, activeTab, getInitialTabIndex])
|
||||
|
||||
const onPageSelected = useCallback(
|
||||
(index: number) => {
|
||||
@@ -444,6 +493,7 @@ let SearchScreenInner = ({
|
||||
activeTab={activeTab}
|
||||
headerHeight={headerHeight}
|
||||
onPageSelected={onPageSelected}
|
||||
initialPage={activeTab}
|
||||
/>
|
||||
) : hasSession ? (
|
||||
<Explore focusSearchInput={focusSearchInput} headerHeight={headerHeight} />
|
||||
|
||||
@@ -194,7 +194,7 @@ function TrendingIndicator({type}: {type: TrendingIndicatorType | 'skeleton'}) {
|
||||
case 'new': {
|
||||
Icon = TrendingIcon
|
||||
text = _(msg`New`)
|
||||
color = t.palette.positive_700
|
||||
color = t.palette.positive_600
|
||||
backgroundColor = t.palette.positive_50
|
||||
break
|
||||
}
|
||||
|
||||
@@ -195,7 +195,6 @@ function CreateDialogInner({passwords}: {passwords: string[]}) {
|
||||
value={data.password}
|
||||
label={_(msg`Copy App Password`)}
|
||||
size="large"
|
||||
variant="solid"
|
||||
color="secondary">
|
||||
<ButtonText>{data.password}</ButtonText>
|
||||
<ButtonIcon icon={CopyIcon} />
|
||||
|
||||
@@ -428,10 +428,10 @@ function OwnHandlePage({goToServiceHandle}: {goToServiceHandle: () => void}) {
|
||||
</Text>
|
||||
<View style={[a.py_xs]}>
|
||||
<CopyButton
|
||||
variant="solid"
|
||||
color="secondary"
|
||||
value="_atproto"
|
||||
label={_(msg`Copy host`)}
|
||||
style={[a.bg_transparent]}
|
||||
hoverStyle={[a.bg_transparent]}
|
||||
hitSlop={HITSLOP_10}>
|
||||
<Text style={[a.text_md, a.flex_1]}>_atproto</Text>
|
||||
@@ -449,10 +449,10 @@ function OwnHandlePage({goToServiceHandle}: {goToServiceHandle: () => void}) {
|
||||
</Text>
|
||||
<View style={[a.py_xs]}>
|
||||
<CopyButton
|
||||
variant="solid"
|
||||
color="secondary"
|
||||
value={'did=' + currentAccount?.did}
|
||||
label={_(msg`Copy TXT record value`)}
|
||||
style={[a.bg_transparent]}
|
||||
hoverStyle={[a.bg_transparent]}
|
||||
hitSlop={HITSLOP_10}>
|
||||
<Text style={[a.text_md, a.flex_1]}>
|
||||
@@ -636,7 +636,7 @@ function SuccessMessage({text}: {text: string}) {
|
||||
a.rounded_full,
|
||||
a.align_center,
|
||||
a.justify_center,
|
||||
{backgroundColor: t.palette.positive_600},
|
||||
{backgroundColor: t.palette.positive_500},
|
||||
]}>
|
||||
<CheckIcon fill={t.palette.white} size="xs" />
|
||||
</View>
|
||||
|
||||
@@ -58,9 +58,9 @@ export function CopyButton({
|
||||
pointerEvents="none">
|
||||
<Text
|
||||
style={[
|
||||
a.font_semi_bold,
|
||||
a.font_medium,
|
||||
a.text_right,
|
||||
a.text_md,
|
||||
a.text_sm,
|
||||
t.atoms.text_contrast_high,
|
||||
]}>
|
||||
<Trans>Copied!</Trans>
|
||||
|
||||
@@ -169,7 +169,7 @@ export function StepHandle() {
|
||||
{isHandleAvailable?.available && (
|
||||
<CheckIcon
|
||||
testID="handleAvailableCheck"
|
||||
style={[{color: t.palette.positive_600}, a.z_20]}
|
||||
style={[{color: t.palette.positive_500}, a.z_20]}
|
||||
/>
|
||||
)}
|
||||
</TextField.Root>
|
||||
|
||||
@@ -93,6 +93,7 @@ import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/i
|
||||
import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
|
||||
import {EyeSlash_Stroke2_Corner0_Rounded as Eye} from '#/components/icons/EyeSlash'
|
||||
import {Leaf_Stroke2_Corner0_Rounded as LeafIcon} from '#/components/icons/Leaf'
|
||||
import {KeepAwake} from '#/components/KeepAwake'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {Link} from '#/components/Link'
|
||||
import {ListFooter} from '#/components/Lists'
|
||||
@@ -150,6 +151,7 @@ export function VideoFeed({}: NativeStackScreenProps<
|
||||
return (
|
||||
<ThemeProvider theme="dark">
|
||||
<Layout.Screen noInsetTop style={{backgroundColor: 'black'}}>
|
||||
<KeepAwake />
|
||||
<SystemBars style={{statusBar: 'light', navigationBar: 'light'}} />
|
||||
<View
|
||||
style={[
|
||||
|
||||
@@ -25,6 +25,11 @@ import * as bsky from '#/types/bsky'
|
||||
export * from '#/state/queries/threadgate/types'
|
||||
export * from '#/state/queries/threadgate/util'
|
||||
|
||||
/**
|
||||
* Must match the threadgate lexicon record definition.
|
||||
*/
|
||||
export const MAX_HIDDEN_REPLIES = 300
|
||||
|
||||
export const threadgateRecordQueryKeyRoot = 'threadgate-record'
|
||||
export const createThreadgateRecordQueryKey = (uri: string) => [
|
||||
threadgateRecordQueryKeyRoot,
|
||||
@@ -205,6 +210,7 @@ export async function upsertThreadgate(
|
||||
})
|
||||
const next = await callback(prev)
|
||||
if (!next) return
|
||||
validateThreadgateRecordOrThrow(next)
|
||||
await writeThreadgateRecord({
|
||||
agent,
|
||||
postUri,
|
||||
@@ -358,3 +364,31 @@ export function useToggleReplyVisibilityMutation() {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export class MaxHiddenRepliesError extends Error {
|
||||
constructor(message?: string) {
|
||||
super(message || 'Maximum number of hidden replies reached')
|
||||
this.name = 'MaxHiddenRepliesError'
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidInteractionSettingsError extends Error {
|
||||
constructor(message?: string) {
|
||||
super(message || 'Invalid interaction settings')
|
||||
this.name = 'InvalidInteractionSettingsError'
|
||||
}
|
||||
}
|
||||
|
||||
export function validateThreadgateRecordOrThrow(
|
||||
record: AppBskyFeedThreadgate.Record,
|
||||
) {
|
||||
const result = AppBskyFeedThreadgate.validateRecord(record)
|
||||
|
||||
if (result.success) {
|
||||
if ((result.value.hiddenReplies?.length ?? 0) > MAX_HIDDEN_REPLIES) {
|
||||
throw new MaxHiddenRepliesError()
|
||||
}
|
||||
} else {
|
||||
throw new InvalidInteractionSettingsError()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import {beforeEach, expect, jest, test} from '@jest/globals'
|
||||
|
||||
import {Storage} from '#/storage'
|
||||
|
||||
jest.mock('react-native-mmkv', () => ({
|
||||
jest.mock('@bsky.app/react-native-mmkv', () => ({
|
||||
MMKV: class MMKVMock {
|
||||
_store = new Map()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useCallback, useEffect, useState} from 'react'
|
||||
import {MMKV} from 'react-native-mmkv'
|
||||
import {MMKV} from '@bsky.app/react-native-mmkv'
|
||||
|
||||
import {type Account, type Device} from '#/storage/schema'
|
||||
|
||||
|
||||
@@ -162,7 +162,6 @@ function LanguageSuggestionButton({
|
||||
<View style={[a.flex_1]}>
|
||||
<Text
|
||||
style={[
|
||||
a.flex_1,
|
||||
a.leading_snug,
|
||||
{
|
||||
maxWidth: 400,
|
||||
|
||||
@@ -307,7 +307,7 @@ let NotificationFeedItem = ({
|
||||
) : (
|
||||
<Trans>{firstAuthorLink} reposted your post</Trans>
|
||||
)
|
||||
icon = <RepostIcon size="xl" style={{color: t.palette.positive_600}} />
|
||||
icon = <RepostIcon size="xl" style={{color: t.palette.positive_500}} />
|
||||
} else if (item.type === 'follow') {
|
||||
let isFollowBack = false
|
||||
|
||||
@@ -519,7 +519,7 @@ let NotificationFeedItem = ({
|
||||
) : (
|
||||
<Trans>{firstAuthorLink} reposted your repost</Trans>
|
||||
)
|
||||
icon = <RepostIcon size="xl" style={{color: t.palette.positive_600}} />
|
||||
icon = <RepostIcon size="xl" style={{color: t.palette.positive_500}} />
|
||||
} else if (item.type === 'subscribed-post') {
|
||||
const postsCount = 1 + (item.additional?.length || 0)
|
||||
a11yLabel = hasMultipleAuthors
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
@@ -19,6 +20,8 @@ import {MAX_POST_LINES} from '#/lib/constants'
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {useGate} from '#/lib/statsig/statsig'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {countLines} from '#/lib/strings/helpers'
|
||||
@@ -167,35 +170,50 @@ let FeedItemInner = ({
|
||||
}): React.ReactNode => {
|
||||
const queryClient = useQueryClient()
|
||||
const {openComposer} = useOpenComposer()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const pal = usePalette('default')
|
||||
const gate = useGate()
|
||||
const {_} = useLingui()
|
||||
|
||||
const [hover, setHover] = useState(false)
|
||||
|
||||
const href = useMemo(() => {
|
||||
const [href, rkey] = useMemo(() => {
|
||||
const urip = new AtUri(post.uri)
|
||||
return makeProfileLink(post.author, 'post', urip.rkey)
|
||||
return [makeProfileLink(post.author, 'post', urip.rkey), urip.rkey]
|
||||
}, [post.uri, post.author])
|
||||
const {sendInteraction, feedSourceInfo} = useFeedFeedbackContext()
|
||||
|
||||
const onPressReply = () => {
|
||||
sendInteraction({
|
||||
item: post.uri,
|
||||
event: 'app.bsky.feed.defs#interactionReply',
|
||||
feedContext,
|
||||
reqId,
|
||||
})
|
||||
openComposer({
|
||||
replyTo: {
|
||||
uri: post.uri,
|
||||
cid: post.cid,
|
||||
text: record.text || '',
|
||||
author: post.author,
|
||||
embed: post.embed,
|
||||
moderation,
|
||||
langs: record.langs,
|
||||
},
|
||||
})
|
||||
if (gate('feed_reply_button_open_thread')) {
|
||||
sendInteraction({
|
||||
item: post.uri,
|
||||
event: 'app.bsky.feed.defs#clickthroughItem',
|
||||
feedContext,
|
||||
reqId,
|
||||
})
|
||||
navigation.navigate('PostThread', {
|
||||
name: post.author.did,
|
||||
rkey,
|
||||
})
|
||||
} else {
|
||||
sendInteraction({
|
||||
item: post.uri,
|
||||
event: 'app.bsky.feed.defs#interactionReply',
|
||||
feedContext,
|
||||
reqId,
|
||||
})
|
||||
openComposer({
|
||||
replyTo: {
|
||||
uri: post.uri,
|
||||
cid: post.cid,
|
||||
text: record.text || '',
|
||||
author: post.author,
|
||||
embed: post.embed,
|
||||
moderation,
|
||||
langs: record.langs,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onOpenAuthor = () => {
|
||||
|
||||
@@ -7,10 +7,8 @@ import {
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {s} from '#/lib/styles'
|
||||
import {useTheme} from '#/lib/ThemeContext'
|
||||
import {atoms as a, useTheme as useTheme_NEW} from '#/alf'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble'
|
||||
import {
|
||||
Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled,
|
||||
@@ -27,7 +25,7 @@ export function LoadingPlaceholder({
|
||||
height: DimensionValue | undefined
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const theme = useTheme()
|
||||
const t = useTheme()
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
@@ -35,7 +33,7 @@ export function LoadingPlaceholder({
|
||||
{
|
||||
width,
|
||||
height,
|
||||
backgroundColor: theme.palette.default.backgroundLight,
|
||||
backgroundColor: t.palette.contrast_50,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
@@ -48,10 +46,9 @@ export function PostLoadingPlaceholder({
|
||||
}: {
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const t = useTheme_NEW()
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
return (
|
||||
<View style={[styles.post, pal.view, style]}>
|
||||
<View style={[styles.post, style]}>
|
||||
<LoadingPlaceholder
|
||||
width={42}
|
||||
height={42}
|
||||
@@ -137,14 +134,11 @@ export function NotificationLoadingPlaceholder({
|
||||
}: {
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
return (
|
||||
<View style={[styles.notification, pal.view, style]}>
|
||||
<View style={[styles.notification, style]}>
|
||||
<View style={[{width: 60}, a.align_end, a.pr_sm, a.pt_2xs]}>
|
||||
<HeartIconFilled
|
||||
size="xl"
|
||||
style={{color: pal.colors.backgroundLight}}
|
||||
/>
|
||||
<HeartIconFilled size="xl" style={{color: t.palette.contrast_50}} />
|
||||
</View>
|
||||
<View style={{flex: 1}}>
|
||||
<View style={[a.flex_row, s.mb10]}>
|
||||
@@ -184,9 +178,8 @@ export function ProfileCardLoadingPlaceholder({
|
||||
}: {
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<View style={[styles.profileCard, pal.view, style]}>
|
||||
<View style={[styles.profileCard, style]}>
|
||||
<LoadingPlaceholder
|
||||
width={40}
|
||||
height={40}
|
||||
@@ -228,7 +221,7 @@ export function FeedLoadingPlaceholder({
|
||||
showTopBorder?: boolean
|
||||
showLowerPlaceholder?: boolean
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
@@ -236,10 +229,10 @@ export function FeedLoadingPlaceholder({
|
||||
padding: 16,
|
||||
borderTopWidth: showTopBorder ? StyleSheet.hairlineWidth : 0,
|
||||
},
|
||||
pal.border,
|
||||
t.atoms.border_contrast_low,
|
||||
style,
|
||||
]}>
|
||||
<View style={[pal.view, {flexDirection: 'row'}]}>
|
||||
<View style={[{flexDirection: 'row'}]}>
|
||||
<LoadingPlaceholder
|
||||
width={36}
|
||||
height={36}
|
||||
@@ -282,7 +275,7 @@ export function ChatListItemLoadingPlaceholder({
|
||||
}: {
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const t = useTheme_NEW()
|
||||
const t = useTheme()
|
||||
const random = useMemo(() => Math.random(), [])
|
||||
return (
|
||||
<View style={[a.flex_row, a.gap_md, a.px_lg, a.mt_lg, t.atoms.bg, style]}>
|
||||
|
||||
@@ -204,6 +204,7 @@ export function AutoSizedImage({
|
||||
// alt here is what screen readers actually use
|
||||
accessibilityLabel={image.alt}
|
||||
accessibilityHint={_(msg`Views full image`)}
|
||||
accessibilityRole="button"
|
||||
style={[
|
||||
a.w_full,
|
||||
a.rounded_md,
|
||||
@@ -226,6 +227,7 @@ export function AutoSizedImage({
|
||||
// alt here is what screen readers actually use
|
||||
accessibilityLabel={image.alt}
|
||||
accessibilityHint={_(msg`Views full image`)}
|
||||
accessibilityRole="button"
|
||||
style={[a.h_full]}>
|
||||
{contents}
|
||||
</Pressable>
|
||||
|
||||
@@ -67,7 +67,7 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
|
||||
const containerRefs = [containerRef1, containerRef2]
|
||||
return (
|
||||
<View style={[a.flex_1, a.flex_row, gap]}>
|
||||
<View style={[a.flex_1, {aspectRatio: 1}]}>
|
||||
<View style={[a.flex_1, a.aspect_square]}>
|
||||
<GalleryItem
|
||||
{...props}
|
||||
index={0}
|
||||
@@ -76,7 +76,7 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
|
||||
thumbDimsRef={thumbDimsRef}
|
||||
/>
|
||||
</View>
|
||||
<View style={[a.flex_1, {aspectRatio: 1}]}>
|
||||
<View style={[a.flex_1, a.aspect_square]}>
|
||||
<GalleryItem
|
||||
{...props}
|
||||
index={1}
|
||||
@@ -93,7 +93,7 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
|
||||
const containerRefs = [containerRef1, containerRef2, containerRef3]
|
||||
return (
|
||||
<View style={[a.flex_1, a.flex_row, gap]}>
|
||||
<View style={[a.flex_1, {aspectRatio: 1}]}>
|
||||
<View style={[a.flex_1, a.aspect_square]}>
|
||||
<GalleryItem
|
||||
{...props}
|
||||
index={0}
|
||||
@@ -102,7 +102,7 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
|
||||
thumbDimsRef={thumbDimsRef}
|
||||
/>
|
||||
</View>
|
||||
<View style={[a.flex_1, {aspectRatio: 1}, gap]}>
|
||||
<View style={[a.flex_1, a.aspect_square, gap]}>
|
||||
<View style={[a.flex_1]}>
|
||||
<GalleryItem
|
||||
{...props}
|
||||
|
||||
@@ -8,7 +8,6 @@ import {RemoveScrollBar} from 'react-remove-scroll-bar'
|
||||
import {useIntentHandler} from '#/lib/hooks/useIntentHandler'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {useGate} from '#/lib/statsig/statsig'
|
||||
import {useGeolocationStatus} from '#/state/geolocation'
|
||||
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
||||
import {useComposerKeyboardShortcut} from '#/state/shell/composer/useComposerKeyboardShortcut'
|
||||
@@ -46,7 +45,6 @@ function ShellInner() {
|
||||
const [showDrawerDelayedExit, setShowDrawerDelayedExit] = useState(showDrawer)
|
||||
const {state: policyUpdateState} = usePolicyUpdateContext()
|
||||
const welcomeModalControl = useWelcomeModal()
|
||||
const gate = useGate()
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (showDrawer !== showDrawerDelayedExit) {
|
||||
@@ -85,8 +83,7 @@ function ShellInner() {
|
||||
<LinkWarningDialog />
|
||||
<Lightbox />
|
||||
|
||||
{/* Show welcome modal if the gate is enabled */}
|
||||
{welcomeModalControl.isOpen && gate('welcome_modal') && (
|
||||
{welcomeModalControl.isOpen && (
|
||||
<WelcomeModal control={welcomeModalControl} />
|
||||
)}
|
||||
|
||||
|
||||
@@ -3685,6 +3685,11 @@
|
||||
dependencies:
|
||||
react-responsive "^10.0.1"
|
||||
|
||||
"@bsky.app/react-native-mmkv@2.12.5":
|
||||
version "2.12.5"
|
||||
resolved "https://registry.yarnpkg.com/@bsky.app/react-native-mmkv/-/react-native-mmkv-2.12.5.tgz#eb17d31a6158c74393f617a1763ac223ff3f83a6"
|
||||
integrity sha512-3vUz1nQY1DiKIPAWRkpp5ZGxH5f2G6Ui0UuQuEYjYv81xx1qFcSzS9KQ2sHcOKYdkOM9amWV2Q8TQCxt1lrAHg==
|
||||
|
||||
"@bufbuild/protobuf@^1.5.0":
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-1.7.0.tgz#cecddc8162a231642b410bc7b99309cd5969733c"
|
||||
@@ -11292,7 +11297,7 @@ expo-json-utils@~0.15.0:
|
||||
resolved "https://registry.yarnpkg.com/expo-json-utils/-/expo-json-utils-0.15.0.tgz#6723574814b9e6b0a90e4e23662be76123ab6ae9"
|
||||
integrity sha512-duRT6oGl80IDzH2LD2yEFWNwGIC2WkozsB6HF3cDYNoNNdUvFk6uN3YiwsTsqVM/D0z6LEAQ01/SlYvN+Fw0JQ==
|
||||
|
||||
expo-keep-awake@~15.0.7:
|
||||
expo-keep-awake@^15.0.7, expo-keep-awake@~15.0.7:
|
||||
version "15.0.7"
|
||||
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-15.0.7.tgz#4eada556e1cca6c9c2e5aa39478fd01816cd0bc9"
|
||||
integrity sha512-CgBNcWVPnrIVII5G54QDqoE125l+zmqR4HR8q+MQaCfHet+dYpS5vX5zii/RMayzGN4jPgA4XYIQ28ePKFjHoA==
|
||||
@@ -17065,11 +17070,6 @@ react-native-keyboard-controller@1.18.5:
|
||||
dependencies:
|
||||
react-native-is-edge-to-edge "^1.2.1"
|
||||
|
||||
react-native-mmkv@^2.12.2:
|
||||
version "2.12.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native-mmkv/-/react-native-mmkv-2.12.2.tgz#4bba0f5f04e2cf222494cce3a9794ba6a4894dee"
|
||||
integrity sha512-6058Aq0p57chPrUutLGe9fYoiDVDNMU2PKV+lLFUJ3GhoHvUrLdsS1PDSCLr00yqzL4WJQ7TTzH+V8cpyrNcfg==
|
||||
|
||||
react-native-pager-view@6.8.0:
|
||||
version "6.8.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.8.0.tgz#5bac05203d911bf9bf039d47db41b1313dbd1a7a"
|
||||
|
||||
Reference in New Issue
Block a user