Merge remote-tracking branch 'origin/main' into mod-auth

* origin/main: (21 commits)
  Add border to menu on web (#5439)
  Add eslint rule to fix imports without the `#/` path alias (#5175)
  [Neue] Parallel font loading on web (#5411)
  Adjust toggle components sizing (#5408)
  [Neue] Copy and spacing tweaks (#5428)
  [Neue] Ligatures & composer (#5427)
  Remove expo/vector-icons from EditImage modal (#5422)
  Revert provider stacking changes (#5423)
  Fix ext embeds in DMs (#5419)
  Fix font loading on web (#5412)
  [Neue] Base (#5395)
  Update sentry sourcemaps upload (#5409)
  Fix for undefined ref on hot reload on web (#5407)
  remove expo-sentry (#5405)
  Revert unneeded changes to `expo-modules-core` patch (#5393)
  Temporary Sentry hack patch for iOS 18 (#5400)
  Make it work with Xcode 16 (#5386)
  Fix border radius on avatars (#5392)
  Make like animation on web same speed as mobile (#5391)
  Pre-fill alt text with 10-million card post (#5389)
  ...
This commit is contained in:
Eric Bailey
2024-09-20 10:30:26 -05:00
96 changed files with 1577 additions and 604 deletions
+1
View File
@@ -33,6 +33,7 @@ module.exports = {
],
'bsky-internal/use-exact-imports': 'error',
'bsky-internal/use-typed-gates': 'error',
'bsky-internal/use-prefixed-imports': 'warn',
'simple-import-sort/imports': [
'warn',
{
+36 -2
View File
@@ -55,6 +55,7 @@ module.exports = function (config) {
: undefined
const UPDATES_ENABLED = !!UPDATES_CHANNEL
const USE_SENTRY = Boolean(process.env.SENTRY_AUTH_TOKEN)
const SENTRY_DIST = `${PLATFORM}.${VERSION}.${IS_TESTFLIGHT ? 'tf' : ''}${
IS_DEV ? 'dev' : ''
}`
@@ -186,7 +187,15 @@ module.exports = function (config) {
},
plugins: [
'expo-localization',
Boolean(process.env.SENTRY_AUTH_TOKEN) && 'sentry-expo',
USE_SENTRY && [
'@sentry/react-native/expo',
{
organization: 'blueskyweb',
project: 'react-native',
release: VERSION,
dist: SENTRY_DIST,
},
],
[
'expo-build-properties',
{
@@ -221,6 +230,31 @@ module.exports = function (config) {
'./plugins/shareExtension/withShareExtensions.js',
'./plugins/notificationsExtension/withNotificationsExtension.js',
'./plugins/withAppDelegateReferrer.js',
[
'expo-font',
{
fonts: [
// './assets/fonts/inter/Inter-Thin.otf',
// './assets/fonts/inter/Inter-ThinItalic.otf',
// './assets/fonts/inter/Inter-ExtraLight.otf',
// './assets/fonts/inter/Inter-ExtraLightItalic.otf',
// './assets/fonts/inter/Inter-Light.otf',
// './assets/fonts/inter/Inter-LightItalic.otf',
'./assets/fonts/inter/Inter-Regular.otf',
'./assets/fonts/inter/Inter-Italic.otf',
'./assets/fonts/inter/Inter-Medium.otf',
'./assets/fonts/inter/Inter-MediumItalic.otf',
'./assets/fonts/inter/Inter-SemiBold.otf',
'./assets/fonts/inter/Inter-SemiBoldItalic.otf',
'./assets/fonts/inter/Inter-Bold.otf',
'./assets/fonts/inter/Inter-BoldItalic.otf',
'./assets/fonts/inter/Inter-ExtraBold.otf',
'./assets/fonts/inter/Inter-ExtraBoldItalic.otf',
'./assets/fonts/inter/Inter-Black.otf',
'./assets/fonts/inter/Inter-BlackItalic.otf',
],
},
],
].filter(Boolean),
extra: {
eas: {
@@ -263,7 +297,7 @@ module.exports = function (config) {
* @see https://docs.expo.dev/guides/using-sentry/#app-configuration
*/
{
file: 'sentry-expo/upload-sourcemaps',
file: './postHooks/uploadSentrySourcemapsPostHook',
config: {
organization: 'blueskyweb',
project: 'react-native',
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 1v14h14V5H5Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 229 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M4 2c0-.552.41-1 .917-1h14.666c.507 0 .917.448.917 1v20c0 .552-.41 1-.917 1H4.917C4.41 23 4 22.552 4 22V2Zm1.833 1v18h12.834V3H5.833Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 276 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M2 20.5c-.552 0-1-.41-1-.917V4.917C1 4.41 1.448 4 2 4h20c.552 0 1 .41 1 .917v14.666c0 .507-.448.917-1 .917H2Zm1-1.833h18V5.833H3v12.834Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 279 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M4 21a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5v2H5v14h4v2H4Zm9-20v22h-2V1h2Zm7.707 2.293A1 1 0 0 1 21 4v1h-2V3h1a1 1 0 0 1 .707.293ZM19 7h2v2h-2V7Zm0 4h2v2h-2v-2Zm0 4h2v2h-2v-2Zm0 4h2v1a1 1 0 0 1-1 1h-1v-2Zm-2 0v2h-2v-2h2ZM15 5h2V3h-2v2Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 371 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v5h-2V5H5v4H3V4Zm20 9H1v-2h22v2Zm-2.293 7.707A1 1 0 0 1 20 21h-1v-2h2v1a1 1 0 0 1-.293.707ZM17 19v2h-2v-2h2Zm-4 0v2h-2v-2h2Zm-4 0v2H7v-2h2Zm-4 0v2H4a1 1 0 0 1-1-1v-1h2Zm0-2H3v-2h2v2Zm14-2v2h2v-2h-2Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 376 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M9 5a1 1 0 0 1 1-1h12a1 1 0 1 1 0 2h-5v14a1 1 0 1 1-2 0V6h-5a1 1 0 0 1-1-1Zm-3.073 7v8a1 1 0 1 0 2 0v-8H12a1 1 0 1 0 0-2H6.971a1.015 1.015 0 0 0-.089 0H2a1 1 0 1 0 0 2h3.927Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 317 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3.65 17.247c-.242.832-.632 1.178-1.325 1.178-.814 0-1.325-.476-1.325-1.23 0-.216.06-.51.173-.831L4.586 7.07c.364-1.014.979-1.482 1.966-1.482 1.022 0 1.629.45 2.001 1.473l3.43 9.303c.121.337.165.571.165.831 0 .72-.546 1.23-1.308 1.23-.736 0-1.126-.338-1.36-1.152l-.658-1.975H4.309l-.658 1.95ZM6.5 8.152l-1.62 5.12h3.335l-1.654-5.12H6.5Zm13.005 8.688c-.52.988-1.68 1.568-2.84 1.568-1.768 0-3.11-1.144-3.11-2.815 0-1.69 1.299-2.668 3.62-2.807l2.34-.138v-.615c0-.867-.607-1.369-1.56-1.369-.771 0-1.239.251-1.802.979-.277.312-.597.468-1.004.468-.615 0-1.057-.399-1.057-.97 0-.2.043-.382.13-.572.433-1.109 1.923-1.793 3.845-1.793 2.383 0 3.933 1.23 3.933 3.1v5.293c0 .84-.511 1.273-1.23 1.273-.684 0-1.16-.38-1.213-1.126v-.476h-.052Zm-3.43-1.386c0 .693.572 1.126 1.42 1.126 1.11 0 2.02-.719 2.02-1.723v-.676l-1.959.121c-.944.07-1.48.494-1.48 1.152Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 986 B

+5
View File
@@ -210,6 +210,11 @@ func serve(cctx *cli.Context) error {
maxAge = 7 * (60 * 60 * 24) // 1 week
}
// fonts can be cached for a year
if strings.HasSuffix(path, ".otf") {
maxAge = 365 * (60 * 60 * 24) // 1 year
}
c.Response().Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", maxAge))
return next(c)
}
+98 -1
View File
@@ -13,7 +13,105 @@
<!-- Hello Humans! API docs at https://atproto.com -->
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Regular.1f5ed03b6dd9fd1f9982.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Italic.95778eb0c75dc956257e.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Medium.296aa2d65964269836b3.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-MediumItalic.0e57e17a6311368e2114.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-SemiBold.2277990330981b8409bb.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-SemiBoldItalic.f62fea3df3a521d6c8a7.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Bold.8d330503e1d034ad68de.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-BoldItalic.bb17e63f9baa0d861a20.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-ExtraBold.ff2581a193bf6b7e0b06.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-ExtraBoldItalic.0e50b40728d24d40fdf4.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Black.66e9a87f1c921e844ed4.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-BlackItalic.27b9f0ad06fd13a7b9da.otf">
<style>
@font-face {
font-family: "Inter-Regular";
src: local("Inter-Regular"), url(/static/media/Inter-Regular.1f5ed03b6dd9fd1f9982.otf) format("font/otf");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-Italic";
src: local("Inter-Italic"), url(/static/media/Inter-Italic.95778eb0c75dc956257e.otf) format("font/otf");
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-Medium";
src: local("Inter-Medium"), url(/static/media/Inter-Medium.296aa2d65964269836b3.otf) format("font/otf");
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-MediumItalic";
src: local("Inter-MediumItalic"), url(/static/media/Inter-MediumItalic.0e57e17a6311368e2114.otf) format("font/otf");
font-weight: 500;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-SemiBold";
src: local("Inter-SemiBold"), url(/static/media/Inter-SemiBold.2277990330981b8409bb.otf) format("font/otf");
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-SemiBoldItalic";
src: local("Inter-SemiBoldItalic"), url(/static/media/Inter-SemiBoldItalic.f62fea3df3a521d6c8a7.otf) format("font/otf");
font-weight: 600;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-Bold";
src: local("Inter-Bold"), url(/static/media/Inter-Bold.8d330503e1d034ad68de.otf) format("font/otf");
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-BoldItalic";
src: local("Inter-BoldItalic"), url(/static/media/Inter-BoldItalic.bb17e63f9baa0d861a20.otf) format("font/otf");
font-weight: 700;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-ExtraBold";
src: local("Inter-ExtraBold"), url(/static/media/Inter-ExtraBold.ff2581a193bf6b7e0b06.otf) format("font/otf");
font-weight: 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-ExtraBoldItalic";
src: local("Inter-ExtraBoldItalic"), url(/static/media/Inter-ExtraBoldItalic.0e50b40728d24d40fdf4.otf) format("font/otf");
font-weight: 800;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-Black";
src: local("Inter-Black"), url(/static/media/Inter-Black.66e9a87f1c921e844ed4.otf) format("font/otf");
font-weight: 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-BlackItalic";
src: local("Inter-BlackItalic"), url(/static/media/Inter-BlackItalic.27b9f0ad06fd13a7b9da.otf) format("font/otf");
font-weight: 900;
font-style: italic;
font-display: swap;
}
/**
* Extend the react-native-web reset:
* https://github.com/necolas/react-native-web/blob/master/packages/react-native-web/src/exports/StyleSheet/initialRules.js
@@ -149,7 +247,6 @@
/* ProseMirror */
.ProseMirror {
font: 18px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif;
min-height: 140px;
}
.ProseMirror-dark {
+1
View File
@@ -5,5 +5,6 @@ module.exports = {
'avoid-unwrapped-text': require('./avoid-unwrapped-text'),
'use-exact-imports': require('./use-exact-imports'),
'use-typed-gates': require('./use-typed-gates'),
'use-prefixed-imports': require('./use-prefixed-imports'),
},
}
+4 -4
View File
@@ -1,4 +1,3 @@
/* eslint-disable bsky-internal/use-exact-imports */
const BANNED_IMPORTS = [
'@fortawesome/free-regular-svg-icons',
'@fortawesome/free-solid-svg-icons',
@@ -6,11 +5,12 @@ const BANNED_IMPORTS = [
exports.create = function create(context) {
return {
Literal(node) {
if (typeof node.value !== 'string') {
ImportDeclaration(node) {
const source = node.source
if (typeof source.value !== 'string') {
return
}
if (BANNED_IMPORTS.includes(node.value)) {
if (BANNED_IMPORTS.includes(source.value)) {
context.report({
node,
message:
+39
View File
@@ -0,0 +1,39 @@
const BANNED_IMPORT_PREFIXES = [
'alf/',
'components/',
'lib/',
'locale/',
'logger/',
'platform/',
'state/',
'storage/',
'view/',
]
module.exports = {
meta: {
type: 'suggestion',
fixable: 'code',
},
create(context) {
return {
ImportDeclaration(node) {
const source = node.source
if (typeof source.value !== 'string') {
return
}
if (
BANNED_IMPORT_PREFIXES.some(banned => source.value.startsWith(banned))
) {
context.report({
node: source,
message: `Use '#/${source.value}'`,
fix(fixer) {
return fixer.replaceText(source, `'#/${source.value}'`)
},
})
}
},
}
},
}
+4 -4
View File
@@ -15,7 +15,7 @@
"web": "expo start --web",
"use-build-number": "./scripts/useBuildNumberEnv.sh",
"use-build-number-with-bump": "./scripts/useBuildNumberEnvWithBump.sh",
"build-web": "expo export:web && node ./scripts/post-web-build.js && cp -v ./web-build/static/js/*.* ./bskyweb/static/js/ && cp -v ./web-build/static/media/*.png ./bskyweb/static/media/",
"build-web": "expo export:web && node ./scripts/post-web-build.js && cp -v ./web-build/static/js/*.* ./bskyweb/static/js/ && cp -v ./web-build/static/media/* ./bskyweb/static/media/",
"build-all": "yarn intl:build && yarn use-build-number-with-bump eas build --platform all",
"build-ios": "yarn use-build-number-with-bump eas build -p ios",
"build-android": "yarn use-build-number-with-bump eas build -p android",
@@ -85,7 +85,7 @@
"@segment/analytics-react": "^1.0.0-rc1",
"@segment/analytics-react-native": "^2.10.1",
"@segment/sovran-react-native": "^0.4.5",
"@sentry/react-native": "5.5.0",
"@sentry/react-native": "5.32.0",
"@tamagui/focus-scope": "^1.84.1",
"@tanstack/query-async-storage-persister": "^5.25.0",
"@tanstack/react-query": "^5.8.1",
@@ -124,6 +124,7 @@
"expo-dev-client": "^4.0.14",
"expo-device": "~6.0.2",
"expo-file-system": "^17.0.1",
"expo-font": "~12.0.10",
"expo-haptics": "^13.0.1",
"expo-image": "~1.12.9",
"expo-image-manipulator": "^12.0.5",
@@ -177,7 +178,7 @@
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "~2.16.2",
"react-native-get-random-values": "~1.11.0",
"react-native-image-crop-picker": "0.40.3",
"react-native-image-crop-picker": "0.41.2",
"react-native-ios-context-menu": "^1.15.3",
"react-native-keyboard-controller": "^1.12.1",
"react-native-mmkv": "^2.12.2",
@@ -200,7 +201,6 @@
"react-responsive": "^9.0.2",
"react-textarea-autosize": "^8.5.3",
"rn-fetch-blob": "^0.12.0",
"sentry-expo": "~7.0.1",
"statsig-react-native-expo": "^4.6.1",
"tippy.js": "^6.3.7",
"tlds": "^1.234.0",
+36
View File
@@ -0,0 +1,36 @@
diff --git a/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js b/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
index 7e0b4cd..177454c 100644
--- a/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
+++ b/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
@@ -3,6 +3,8 @@ import { LogBox } from 'react-native';
* This is a workaround for using fetch on RN, this is a known issue in react-native and only generates a warning.
*/
export function ignoreRequireCycleLogs() {
- LogBox.ignoreLogs(['Require cycle:']);
+ try {
+ LogBox.ignoreLogs(['Require cycle:']);
+ } catch (e) {}
}
//# sourceMappingURL=ignorerequirecyclelogs.js.map
\ No newline at end of file
diff --git a/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js b/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js
index 0f244f2..ae7dfb3 100755
--- a/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js
+++ b/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js
@@ -174,6 +174,7 @@ if (!outputDir) {
process.exit(1);
}
+const otherArgs = process.argv.slice(3);
const files = getAssetPathsSync(outputDir);
const groupedAssets = groupAssets(files);
@@ -195,7 +196,7 @@ for (const [assetGroupName, assets] of Object.entries(groupedAssets)) {
const isHermes = assets.find(asset => asset.endsWith('.hbc'));
const windowsCallback = process.platform === "win32" ? 'node ' : '';
- execSync(`${windowsCallback}${sentryCliBin} sourcemaps upload ${isHermes ? '--debug-id-reference' : ''} ${assets.join(' ')}`, {
+ execSync(`${windowsCallback}${sentryCliBin} sourcemaps upload ${isHermes ? '--debug-id-reference' : ''} ${assets.join(' ')} ${otherArgs.join(' ')}`, {
env: {
...process.env,
[SENTRY_PROJECT]: sentryProject,
-15
View File
@@ -1,15 +0,0 @@
diff --git a/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js b/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
index 7e0b4cd..177454c 100644
--- a/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
+++ b/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
@@ -3,6 +3,8 @@ import { LogBox } from 'react-native';
* This is a workaround for using fetch on RN, this is a known issue in react-native and only generates a warning.
*/
export function ignoreRequireCycleLogs() {
- LogBox.ignoreLogs(['Require cycle:']);
+ try {
+ LogBox.ignoreLogs(['Require cycle:']);
+ } catch (e) {}
}
//# sourceMappingURL=ignorerequirecyclelogs.js.map
\ No newline at end of file
-25
View File
@@ -12,28 +12,3 @@ index bb74e80..0aa0202 100644
Map<String, Object> constants = new HashMap<>(3);
constants.put(MODULES_CONSTANTS_KEY, new HashMap<>());
diff --git a/node_modules/expo-modules-core/build/uuid/uuid.js b/node_modules/expo-modules-core/build/uuid/uuid.js
index 109d3fe..c421931 100644
--- a/node_modules/expo-modules-core/build/uuid/uuid.js
+++ b/node_modules/expo-modules-core/build/uuid/uuid.js
@@ -1,5 +1,7 @@
import bytesToUuid from './lib/bytesToUuid';
import { Uuidv5Namespace } from './uuid.types';
+import { ensureNativeModulesAreInstalled } from '../ensureNativeModulesAreInstalled';
+ensureNativeModulesAreInstalled();
const nativeUuidv4 = globalThis?.expo?.uuidv4;
const nativeUuidv5 = globalThis?.expo?.uuidv5;
function uuidv4() {
diff --git a/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift b/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
index ee2268a..4851b67 100644
--- a/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
+++ b/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
@@ -173,7 +173,7 @@ public final class SharedObjectRegistry {
}
internal func clear() {
- Self.lockQueue.async {
+ Self.lockQueue.sync {
self.pairs.removeAll()
}
}
@@ -0,0 +1,34 @@
const exec = require('child_process').execSync
const SENTRY_AUTH_TOKEN = process.env.SENTRY_AUTH_TOKEN
module.exports = ({config}) => {
if (!SENTRY_AUTH_TOKEN) {
console.log(
'SENTRY_AUTH_TOKEN environment variable must be set to upload sourcemaps. Skipping.',
)
return
}
const org = config.organization
const project = config.project
const release = config.release
const dist = config.dist
if (!org || !project || !release || !dist) {
console.log(
'"organization", "project", "release", and "dist" must be set in the hook config to upload sourcemaps. Skipping.',
)
return
}
try {
console.log('Uploading sourcemaps to Sentry...')
exec(
`node node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps dist --url https://sentry.io/ -o ${org} -p ${project} -r ${release} -d ${dist}`,
)
console.log('Sourcemaps uploaded to Sentry.')
} catch (e) {
console.error('Error uploading sourcemaps to Sentry:', e)
}
}
+1 -1
View File
@@ -143,8 +143,8 @@ function InnerApp() {
</MessagesProvider>
</StatsigProvider>
</QueryProvider>
<ToastContainer />
</React.Fragment>
<ToastContainer />
</ActiveVideoProvider>
</VideoVolumeProvider>
</RootSiblingParent>
+11 -14
View File
@@ -225,43 +225,43 @@ export const atoms = {
},
text_2xs: {
fontSize: tokens.fontSize._2xs,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_xs: {
fontSize: tokens.fontSize.xs,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_sm: {
fontSize: tokens.fontSize.sm,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_md: {
fontSize: tokens.fontSize.md,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_lg: {
fontSize: tokens.fontSize.lg,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_xl: {
fontSize: tokens.fontSize.xl,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_2xl: {
fontSize: tokens.fontSize._2xl,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_3xl: {
fontSize: tokens.fontSize._3xl,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_4xl: {
fontSize: tokens.fontSize._4xl,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
text_5xl: {
fontSize: tokens.fontSize._5xl,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
leading_tight: {
lineHeight: 1.15,
@@ -273,10 +273,7 @@ export const atoms = {
lineHeight: 1.5,
},
tracking_normal: {
letterSpacing: 0,
},
tracking_wide: {
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
},
font_normal: {
fontWeight: tokens.fontWeight.normal,
+118
View File
@@ -0,0 +1,118 @@
import {useFonts as defaultUseFonts} from 'expo-font'
import {isWeb} from '#/platform/detection'
import {Device, device} from '#/storage'
const FAMILIES = `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif`
const factor = 0.0625 // 1 - (15/16)
const fontScaleMultipliers: Record<Device['fontScale'], number> = {
'-2': 1 - factor * 3,
'-1': 1 - factor * 2,
'0': 1 - factor * 1, // default
'1': 1,
'2': 1 + factor * 1,
}
export function computeFontScaleMultiplier(scale: Device['fontScale']) {
return fontScaleMultipliers[scale]
}
export function getFontScale() {
return device.get(['fontScale']) ?? '0'
}
export function setFontScale(fontScale: Device['fontScale']) {
device.set(['fontScale'], fontScale)
}
export function getFontFamily() {
return device.get(['fontFamily']) || 'theme'
}
export function setFontFamily(fontFamily: Device['fontFamily']) {
device.set(['fontFamily'], fontFamily)
}
/*
* IMPORTANT: This is unused. Expo statically extracts these fonts, but we load
* them manually so that we can parallelize the loading along with the JS
* bundle.
*
* See `#/alf/util/useFonts` for the actually used hooks.
*
* All used fonts MUST be configured here. Unused fonts are commented out, but
* the files are there if we need them.
*/
export function DO_NOT_USE() {
return defaultUseFonts({
// 'Inter-Thin': require('../../assets/fonts/inter/Inter-Thin.otf'),
// 'Inter-ThinItalic': require('../../assets/fonts/inter/Inter-ThinItalic.otf'),
// 'Inter-ExtraLight': require('../../assets/fonts/inter/Inter-ExtraLight.otf'),
// 'Inter-ExtraLightItalic': require('../../assets/fonts/inter/Inter-ExtraLightItalic.otf'),
// 'Inter-Light': require('../../assets/fonts/inter/Inter-Light.otf'),
// 'Inter-LightItalic': require('../../assets/fonts/inter/Inter-LightItalic.otf'),
'Inter-Regular': require('../../assets/fonts/inter/Inter-Regular.otf'),
'Inter-Italic': require('../../assets/fonts/inter/Inter-Italic.otf'),
'Inter-Medium': require('../../assets/fonts/inter/Inter-Medium.otf'),
'Inter-MediumItalic': require('../../assets/fonts/inter/Inter-MediumItalic.otf'),
'Inter-SemiBold': require('../../assets/fonts/inter/Inter-SemiBold.otf'),
'Inter-SemiBoldItalic': require('../../assets/fonts/inter/Inter-SemiBoldItalic.otf'),
'Inter-Bold': require('../../assets/fonts/inter/Inter-Bold.otf'),
'Inter-BoldItalic': require('../../assets/fonts/inter/Inter-BoldItalic.otf'),
'Inter-ExtraBold': require('../../assets/fonts/inter/Inter-ExtraBold.otf'),
'Inter-ExtraBoldItalic': require('../../assets/fonts/inter/Inter-ExtraBoldItalic.otf'),
'Inter-Black': require('../../assets/fonts/inter/Inter-Black.otf'),
'Inter-BlackItalic': require('../../assets/fonts/inter/Inter-BlackItalic.otf'),
})
}
/*
* Unused fonts are commented out, but the files are there if we need them.
*/
export function applyFonts(
style: Record<string, any>,
fontFamily: 'system' | 'theme',
) {
if (fontFamily === 'theme') {
style.fontFamily =
{
// '100': 'Inter-Thin',
// '200': 'Inter-ExtraLight',
// '300': 'Inter-Light',
'100': 'Inter-Regular',
'200': 'Inter-Regular',
'300': 'Inter-Regular',
'400': 'Inter-Regular',
'500': 'Inter-Medium',
'600': 'Inter-SemiBold',
'700': 'Inter-Bold',
'800': 'Inter-ExtraBold',
'900': 'Inter-Black',
}[style.fontWeight as string] || 'Inter-Regular'
if (style.fontStyle === 'italic') {
if (style.fontFamily === 'Inter-Regular') {
style.fontFamily = 'Inter-Italic'
} else {
style.fontFamily += 'Italic'
}
}
// fallback families only supported on web
if (isWeb) {
style.fontFamily += `, ${FAMILIES}`
}
} else {
// fallback families only supported on web
if (isWeb) {
style.fontFamily = style.fontFamily || FAMILIES
}
}
/**
* Disable contextual ligatures
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant}
*/
style.fontVariant = ['no-contextual']
}
+89 -12
View File
@@ -1,25 +1,47 @@
import React from 'react'
import {useMediaQuery} from 'react-responsive'
import {
computeFontScaleMultiplier,
getFontFamily,
getFontScale,
setFontFamily as persistFontFamily,
setFontScale as persistFontScale,
} from '#/alf/fonts'
import {createThemes, defaultTheme} from '#/alf/themes'
import {Theme, ThemeName} from '#/alf/types'
import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
import {Device} from '#/storage'
export {atoms} from '#/alf/atoms'
export * from '#/alf/fonts'
export * as tokens from '#/alf/tokens'
export * from '#/alf/types'
export * from '#/alf/util/flatten'
export * from '#/alf/util/platform'
export * from '#/alf/util/themeSelector'
/*
* Context
*/
export const Context = React.createContext<{
export type Alf = {
themeName: ThemeName
theme: Theme
themes: ReturnType<typeof createThemes>
}>({
fonts: {
scale: Exclude<Device['fontScale'], undefined>
scaleMultiplier: number
family: Device['fontFamily']
setFontScale: (fontScale: Exclude<Device['fontScale'], undefined>) => void
setFontFamily: (fontFamily: Device['fontFamily']) => void
}
/**
* Feature flags or other gated options
*/
flags: {}
}
/*
* Context
*/
export const Context = React.createContext<Alf>({
themeName: 'light',
theme: defaultTheme,
themes: createThemes({
@@ -29,12 +51,48 @@ export const Context = React.createContext<{
positive: GREEN_HUE,
},
}),
fonts: {
scale: getFontScale(),
scaleMultiplier: computeFontScaleMultiplier(getFontScale()),
family: getFontFamily(),
setFontScale: () => {},
setFontFamily: () => {},
},
flags: {},
})
export function ThemeProvider({
children,
theme: themeName,
}: React.PropsWithChildren<{theme: ThemeName}>) {
const [fontScale, setFontScale] = React.useState<Alf['fonts']['scale']>(() =>
getFontScale(),
)
const [fontScaleMultiplier, setFontScaleMultiplier] = React.useState(() =>
computeFontScaleMultiplier(fontScale),
)
const setFontScaleAndPersist = React.useCallback<
Alf['fonts']['setFontScale']
>(
fontScale => {
setFontScale(fontScale)
persistFontScale(fontScale)
setFontScaleMultiplier(computeFontScaleMultiplier(fontScale))
},
[setFontScale],
)
const [fontFamily, setFontFamily] = React.useState<Alf['fonts']['family']>(
() => getFontFamily(),
)
const setFontFamilyAndPersist = React.useCallback<
Alf['fonts']['setFontFamily']
>(
fontFamily => {
setFontFamily(fontFamily)
persistFontFamily(fontFamily)
},
[setFontFamily],
)
const themes = React.useMemo(() => {
return createThemes({
hues: {
@@ -44,28 +102,47 @@ export function ThemeProvider({
},
})
}, [])
const theme = themes[themeName]
return (
<Context.Provider
value={React.useMemo(
value={React.useMemo<Alf>(
() => ({
themes,
themeName: themeName,
theme: theme,
theme: themes[themeName],
fonts: {
scale: fontScale,
scaleMultiplier: fontScaleMultiplier,
family: fontFamily,
setFontScale: setFontScaleAndPersist,
setFontFamily: setFontFamilyAndPersist,
},
flags: {},
}),
[theme, themeName, themes],
[
themeName,
themes,
fontScale,
setFontScaleAndPersist,
fontFamily,
setFontFamilyAndPersist,
fontScaleMultiplier,
],
)}>
{children}
</Context.Provider>
)
}
export function useAlf() {
return React.useContext(Context)
}
export function useTheme(theme?: ThemeName) {
const ctx = React.useContext(Context)
const alf = useAlf()
return React.useMemo(() => {
return theme ? ctx.themes[theme] : ctx.theme
}, [theme, ctx])
return theme ? alf.themes[theme] : alf.theme
}, [theme, alf])
}
export function useBreakpoints() {
+4
View File
@@ -1,3 +1,7 @@
import {Platform} from 'react-native'
export const TRACKING = Platform.OS === 'android' ? 0.1 : 0
export const color = {
temp_purple: 'rgb(105 0 255)',
temp_purple_dark: 'rgb(83 0 202)',
+2 -10
View File
@@ -7,7 +7,6 @@ import {
PressableProps,
StyleProp,
StyleSheet,
Text,
TextProps,
TextStyle,
View,
@@ -17,7 +16,7 @@ import {LinearGradient} from 'expo-linear-gradient'
import {android, atoms as a, flatten, select, tokens, useTheme} from '#/alf'
import {Props as SVGIconProps} from '#/components/icons/common'
import {normalizeTextStyles} from '#/components/Typography'
import {Text} from '#/components/Typography'
export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'gradient'
export type ButtonColor =
@@ -635,14 +634,7 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) {
const textStyles = useSharedButtonTextStyles()
return (
<Text
{...rest}
style={normalizeTextStyles([
a.font_bold,
a.text_center,
textStyles,
style,
])}>
<Text {...rest} style={[a.font_bold, a.text_center, textStyles, style]}>
{children}
</Text>
)
+1
View File
@@ -37,6 +37,7 @@ import {Portal} from '#/components/Portal'
export {useDialogContext, useDialogControl} from '#/components/Dialog/context'
export * from '#/components/Dialog/types'
export * from '#/components/Dialog/utils'
// @ts-ignore
export const Input = createInput(BottomSheetTextInput)
+1
View File
@@ -27,6 +27,7 @@ import {Portal} from '#/components/Portal'
export {useDialogContext, useDialogControl} from '#/components/Dialog/context'
export * from '#/components/Dialog/types'
export * from '#/components/Dialog/utils'
export {Input} from '#/components/forms/TextField'
const stopPropagation = (e: any) => e.stopPropagation()
+18
View File
@@ -0,0 +1,18 @@
import React from 'react'
import {DialogControlProps} from '#/components/Dialog/types'
export function useAutoOpen(control: DialogControlProps, showTimeout?: number) {
React.useEffect(() => {
if (showTimeout) {
const timeout = setTimeout(() => {
control.open()
}, showTimeout)
return () => {
clearTimeout(timeout)
}
} else {
control.open()
}
}, [control, showTimeout])
}
+2
View File
@@ -179,8 +179,10 @@ export function Outer({
style={[
a.rounded_sm,
a.p_xs,
a.border,
t.name === 'light' ? t.atoms.bg : t.atoms.bg_contrast_25,
t.atoms.shadow_md,
t.atoms.border_contrast_low,
style,
]}>
{children}
+21 -5
View File
@@ -3,7 +3,7 @@ import {StyleProp, TextProps as RNTextProps, TextStyle} from 'react-native'
import {UITextView} from 'react-native-uitextview'
import {isNative} from '#/platform/detection'
import {atoms, flatten, useTheme, web} from '#/alf'
import {Alf, applyFonts, atoms, flatten, useAlf, useTheme, web} from '#/alf'
export type TextProps = RNTextProps & {
/**
@@ -34,19 +34,30 @@ export function leading<
* If the `lineHeight` value is > 2, we assume it's an absolute value and
* returns it as-is.
*/
export function normalizeTextStyles(styles: StyleProp<TextStyle>) {
export function normalizeTextStyles(
styles: StyleProp<TextStyle>,
{
fontScale,
fontFamily,
}: {
fontScale: number
fontFamily: Alf['fonts']['family']
} & Pick<Alf, 'flags'>,
) {
const s = flatten(styles)
// should always be defined on these components
const fontSize = s.fontSize || atoms.text_md.fontSize
s.fontSize = (s.fontSize || atoms.text_md.fontSize) * fontScale
if (s?.lineHeight) {
if (s.lineHeight !== 0 && s.lineHeight <= 2) {
s.lineHeight = Math.round(fontSize * s.lineHeight)
s.lineHeight = Math.round(s.fontSize * s.lineHeight)
}
} else if (!isNative) {
s.lineHeight = s.fontSize
}
applyFonts(s, fontFamily)
return s
}
@@ -54,8 +65,13 @@ export function normalizeTextStyles(styles: StyleProp<TextStyle>) {
* Our main text component. Use this most of the time.
*/
export function Text({style, selectable, ...rest}: TextProps) {
const {fonts, flags} = useAlf()
const t = useTheme()
const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)])
const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)], {
fontScale: fonts.scaleMultiplier,
fontFamily: fonts.family,
flags,
})
return <UITextView selectable={selectable} uiTextView style={s} {...rest} />
}
@@ -0,0 +1,118 @@
import React from 'react'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {AppearanceToggleButtonGroup} from '#/screens/Settings/AppearanceSettings'
import {atoms as a, useAlf, useTheme} from '#/alf'
import * as Dialog from '#/components/Dialog'
import {useNuxDialogContext} from '#/components/dialogs/nuxs'
import {Divider} from '#/components/Divider'
import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize'
import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase'
import {Text} from '#/components/Typography'
export function NeueTypography() {
const t = useTheme()
const {_} = useLingui()
const nuxDialogs = useNuxDialogContext()
const control = Dialog.useDialogControl()
const {fonts} = useAlf()
Dialog.useAutoOpen(control, 3e3)
const onClose = React.useCallback(() => {
nuxDialogs.dismissActiveNux()
}, [nuxDialogs])
const onChangeFontFamily = React.useCallback(
(values: string[]) => {
const next = values[0] === 'system' ? 'system' : 'theme'
fonts.setFontFamily(next)
},
[fonts],
)
const onChangeFontScale = React.useCallback(
(values: string[]) => {
const next = values[0] || ('0' as any)
fonts.setFontScale(next)
},
[fonts],
)
return (
<Dialog.Outer control={control} onClose={onClose}>
<Dialog.Handle />
<Dialog.ScrollableInner label={_(msg`Introducing new font settings`)}>
<View style={[a.gap_xl]}>
<View style={[a.gap_md]}>
<Text style={[a.text_3xl, {fontWeight: '900'}]}>
<Trans>New font settings </Trans>
</Text>
<Text style={[a.text_lg, a.leading_snug, {maxWidth: 400}]}>
<Trans>
We're introducing a new theme font, along with adjustable font
sizing.
</Trans>
</Text>
<Text
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
<Trans>
You can adjust these in your Appearance Settings later.
</Trans>
</Text>
</View>
<Divider />
<View style={[a.gap_lg]}>
<AppearanceToggleButtonGroup
title={_(msg`Font`)}
description={_(
msg`For the best experience, we recommend using the theme font.`,
)}
icon={Aa}
items={[
{
label: _(msg`System`),
name: 'system',
},
{
label: _(msg`Theme`),
name: 'theme',
},
]}
values={[fonts.family]}
onChange={onChangeFontFamily}
/>
<AppearanceToggleButtonGroup
title={_(msg`Font size`)}
icon={TextSize}
items={[
{
label: _(msg`Smaller`),
name: '-1',
},
{
label: _(msg`Default`),
name: '0',
},
{
label: _(msg`Larger`),
name: '1',
},
]}
values={[fonts.scale]}
onChange={onChangeFontScale}
/>
</View>
</View>
<Dialog.Close />
</Dialog.ScrollableInner>
</Dialog.Outer>
)
}
@@ -197,6 +197,27 @@ export function TenMillionInner({
const isLoadingData = isProfileLoading || !moderation || !profile
const isLoadingImage = !uri
const displayName = React.useMemo(() => {
if (!profile || !moderation) return ''
return sanitizeDisplayName(
profile.displayName || sanitizeHandle(profile.handle),
moderation.ui('displayName'),
)
}, [profile, moderation])
const handle = React.useMemo(() => {
if (!profile) return ''
return sanitizeHandle(profile.handle, '@')
}, [profile])
const joinedDate = React.useMemo(() => {
if (!profile || !profile.createdAt) return ''
const date = i18n.date(profile.createdAt, {
month: 'short',
day: 'numeric',
year: 'numeric',
})
return date
}, [i18n, profile])
const error: string = React.useMemo(() => {
if (profileError) {
return _(
@@ -235,19 +256,34 @@ export function TenMillionInner({
msg`Bluesky now has over 10 million users, and I was #${i18n.number(
userNumber,
)}!`,
), // TODO
),
imageUris: [
{
uri,
width: WIDTH,
height: HEIGHT,
altText: _(
msg`A virtual certificate with text "Celebrating 10M users on Bluesky, #${i18n.number(
userNumber,
)}, ${displayName} ${handle}, joined on ${joinedDate}"`,
),
},
],
})
}, 1e3)
})
}
}, [_, i18n, control, openComposer, uri, userNumber])
}, [
_,
i18n,
control,
openComposer,
uri,
userNumber,
displayName,
handle,
joinedDate,
])
const onNativeShare = React.useCallback(() => {
if (uri) {
control.close(() => {
@@ -490,11 +526,7 @@ export function TenMillionInner({
a.leading_tight,
{maxWidth: '60%'},
]}>
{sanitizeDisplayName(
profile.displayName ||
sanitizeHandle(profile.handle),
moderation.ui('displayName'),
)}
{displayName}
</Text>
<View
style={[a.flex_row, a.justify_between, a.gap_4xl]}>
@@ -508,7 +540,7 @@ export function TenMillionInner({
a.leading_snug,
lightTheme.atoms.text_contrast_medium,
]}>
{sanitizeHandle(profile.handle, '@')}
{handle}
</Text>
{profile.createdAt && (
@@ -524,14 +556,7 @@ export function TenMillionInner({
a.text_right,
lightTheme.atoms.text_contrast_low,
]}>
<Trans>
Joined{' '}
{i18n.date(profile.createdAt, {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</Trans>
<Trans>Joined on {joinedDate}</Trans>
</Text>
)}
</View>
+71 -9
View File
@@ -1,4 +1,5 @@
import React from 'react'
import {AppBskyActorDefs} from '@atproto/api'
import {useGate} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
@@ -8,9 +9,16 @@ import {
useRemoveNuxsMutation,
useUpsertNuxMutation,
} from '#/state/queries/nuxs'
import {useSession} from '#/state/session'
import {
usePreferencesQuery,
UsePreferencesQueryResponse,
} from '#/state/queries/preferences'
import {useProfileQuery} from '#/state/queries/profile'
import {SessionAccount, useSession} from '#/state/session'
import {useOnboardingState} from '#/state/shell'
import {NeueTypography} from '#/components/dialogs/nuxs/NeueTypography'
import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing'
// NUXs
import {TenMillion} from '#/components/dialogs/nuxs/TenMillion'
import {IS_DEV} from '#/env'
@@ -21,11 +29,27 @@ type Context = {
const queuedNuxs: {
id: Nux
enabled?: (props: {gate: ReturnType<typeof useGate>}) => boolean
enabled?: (props: {
gate: ReturnType<typeof useGate>
currentAccount: SessionAccount
currentProfile: AppBskyActorDefs.ProfileViewDetailed
preferences: UsePreferencesQueryResponse
}) => boolean
}[] = [
{
id: Nux.TenMillionDialog,
},
{
id: Nux.NeueTypography,
enabled(props) {
if (props.currentProfile.createdAt) {
if (new Date(props.currentProfile.createdAt) < new Date('2024-09-25')) {
return true
}
}
return false
},
},
]
const Context = React.createContext<Context>({
@@ -38,12 +62,31 @@ export function useNuxDialogContext() {
}
export function NuxDialogs() {
const {hasSession} = useSession()
const onboardingState = useOnboardingState()
return hasSession && !onboardingState.isActive ? <Inner /> : null
const {currentAccount} = useSession()
const {data: preferences} = usePreferencesQuery()
const {data: profile} = useProfileQuery({did: currentAccount?.did})
const onboardingActive = useOnboardingState().isActive
const isLoading =
!currentAccount || !preferences || !profile || onboardingActive
return !isLoading ? (
<Inner
currentAccount={currentAccount}
currentProfile={profile}
preferences={preferences}
/>
) : null
}
function Inner() {
function Inner({
currentAccount,
currentProfile,
preferences,
}: {
currentAccount: SessionAccount
currentProfile: AppBskyActorDefs.ProfileViewDetailed
preferences: UsePreferencesQueryResponse
}) {
const gate = useGate()
const {nuxs} = useNuxs()
const [snoozed, setSnoozed] = React.useState(() => {
@@ -80,10 +123,19 @@ function Inner() {
const nux = nuxs.find(nux => nux.id === id)
// check if completed first
if (nux && nux.completed) continue
if (nux && nux.completed) {
continue
}
// then check gate (track exposure)
if (enabled && !enabled({gate})) continue
if (
enabled &&
!enabled({gate, currentAccount, currentProfile, preferences})
) {
continue
}
logger.debug(`NUX dialogs: activating '${id}' NUX`)
// we have a winner
setActiveNux(id)
@@ -104,7 +156,16 @@ function Inner() {
break
}
}, [nuxs, snoozed, snoozeNuxDialog, upsertNux, gate])
}, [
nuxs,
snoozed,
snoozeNuxDialog,
upsertNux,
gate,
currentAccount,
currentProfile,
preferences,
])
const ctx = React.useMemo(() => {
return {
@@ -116,6 +177,7 @@ function Inner() {
return (
<Context.Provider value={ctx}>
{activeNux === Nux.TenMillionDialog && <TenMillion />}
{activeNux === Nux.NeueTypography && <NeueTypography />}
</Context.Provider>
)
}
+10 -10
View File
@@ -351,8 +351,8 @@ export function Checkbox() {
t.atoms.border_contrast_high,
{
borderWidth: 1,
height: 20,
width: 20,
height: 24,
width: 24,
},
baseStyles,
hovered ? baseHoverStyles : {},
@@ -383,9 +383,9 @@ export function Switch() {
t.atoms.border_contrast_high,
{
borderWidth: 1,
height: 20,
width: 32,
padding: 2,
height: 24,
width: 36,
padding: 3,
},
baseStyles,
hovered ? baseHoverStyles : {},
@@ -395,8 +395,8 @@ export function Switch() {
style={[
a.rounded_full,
{
height: 14,
width: 14,
height: 16,
width: 16,
},
selected
? {
@@ -436,8 +436,8 @@ export function Radio() {
t.atoms.border_contrast_high,
{
borderWidth: 1,
height: 20,
width: 20,
height: 24,
width: 24,
},
baseStyles,
hovered ? baseHoverStyles : {},
@@ -447,7 +447,7 @@ export function Radio() {
style={[
a.absolute,
a.rounded_full,
{height: 12, width: 12},
{height: 16, width: 16},
selected
? {
backgroundColor: t.palette.primary_500,
+13
View File
@@ -0,0 +1,13 @@
import {createSinglePathSVG} from './TEMPLATE'
export const AspectRatio11_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 1v14h14V5H5Z',
})
export const AspectRatio43_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M2 20.5c-.552 0-1-.41-1-.917V4.917C1 4.41 1.448 4 2 4h20c.552 0 1 .41 1 .917v14.666c0 .507-.448.917-1 .917H2Zm1-1.833h18V5.833H3v12.834Z',
})
export const AspectRatio34_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M4 2c0-.552.41-1 .917-1h14.666c.507 0 .917.448.917 1v20c0 .552-.41 1-.917 1H4.917C4.41 23 4 22.552 4 22V2Zm1.833 1v18h12.834V3H5.833Z',
})
+9
View File
@@ -0,0 +1,9 @@
import {createSinglePathSVG} from './TEMPLATE'
export const FlipVertical_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v5h-2V5H5v4H3V4Zm20 9H1v-2h22v2Zm-2.293 7.707A1 1 0 0 1 20 21h-1v-2h2v1a1 1 0 0 1-.293.707ZM17 19v2h-2v-2h2Zm-4 0v2h-2v-2h2Zm-4 0v2H7v-2h2Zm-4 0v2H4a1 1 0 0 1-1-1v-1h2Zm0-2H3v-2h2v2Zm14-2v2h2v-2h-2Z',
})
export const FlipHorizontal_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M4 21a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5v2H5v14h4v2H4Zm9-20v22h-2V1h2Zm7.707 2.293A1 1 0 0 1 21 4v1h-2V3h1a1 1 0 0 1 .707.293ZM19 7h2v2h-2V7Zm0 4h2v2h-2v-2Zm0 4h2v2h-2v-2Zm0 4h2v1a1 1 0 0 1-1 1h-1v-2Zm-2 0v2h-2v-2h2ZM15 5h2V3h-2v2Z',
})
+5
View File
@@ -0,0 +1,5 @@
import {createSinglePathSVG} from './TEMPLATE'
export const TextSize_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M9 5a1 1 0 0 1 1-1h12a1 1 0 1 1 0 2h-5v14a1 1 0 1 1-2 0V6h-5a1 1 0 0 1-1-1Zm-3.073 7v8a1 1 0 1 0 2 0v-8H12a1 1 0 1 0 0-2H6.971a1.015 1.015 0 0 0-.089 0H2a1 1 0 1 0 0 2h3.927Z',
})
+5
View File
@@ -0,0 +1,5 @@
import {createSinglePathSVG} from './TEMPLATE'
export const TitleCase_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M3.65 17.247c-.242.832-.632 1.178-1.325 1.178-.814 0-1.325-.476-1.325-1.23 0-.216.06-.51.173-.831L4.586 7.07c.364-1.014.979-1.482 1.966-1.482 1.022 0 1.629.45 2.001 1.473l3.43 9.303c.121.337.165.571.165.831 0 .72-.546 1.23-1.308 1.23-.736 0-1.126-.338-1.36-1.152l-.658-1.975H4.309l-.658 1.95ZM6.5 8.152l-1.62 5.12h3.335l-1.654-5.12H6.5Zm13.005 8.688c-.52.988-1.68 1.568-2.84 1.568-1.768 0-3.11-1.144-3.11-2.815 0-1.69 1.299-2.668 3.62-2.807l2.34-.138v-.615c0-.867-.607-1.369-1.56-1.369-.771 0-1.239.251-1.802.979-.277.312-.597.468-1.004.468-.615 0-1.057-.399-1.057-.97 0-.2.043-.382.13-.572.433-1.109 1.923-1.793 3.845-1.793 2.383 0 3.933 1.23 3.933 3.1v5.293c0 .84-.511 1.273-1.23 1.273-.684 0-1.16-.38-1.213-1.126v-.476h-.052Zm-3.43-1.386c0 .693.572 1.126 1.42 1.126 1.11 0 2.02-.719 2.02-1.723v-.676l-1.959.121c-.944.07-1.48.494-1.48 1.152Z',
})
+4 -4
View File
@@ -2,12 +2,12 @@ import React from 'react'
import {AppState, AppStateStatus} from 'react-native'
import AsyncStorage from '@react-native-async-storage/async-storage'
import {createClient, SegmentClient} from '@segment/analytics-react-native'
import * as Sentry from '@sentry/react-native'
import {sha256} from 'js-sha256'
import {Native} from 'sentry-expo'
import {useSession, SessionAccount} from '#/state/session'
import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
import {logger} from '#/logger'
import {SessionAccount, useSession} from '#/state/session'
import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
type AppInfo = {
build?: string | undefined
@@ -72,7 +72,7 @@ export function init(account: SessionAccount | undefined) {
if (account.did) {
const did_hashed = sha256(account.did)
client.identify(did_hashed, {did_hashed})
Native.setUser({id: did_hashed})
Sentry.setUser({id: did_hashed})
logger.debug('Ping w/hash')
} else {
logger.debug('Ping w/o hash')
+4 -4
View File
@@ -1,11 +1,11 @@
import React from 'react'
import {createClient} from '@segment/analytics-react'
import * as Sentry from '@sentry/react-native'
import {sha256} from 'js-sha256'
import {Browser} from 'sentry-expo'
import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
import {useSession, SessionAccount} from '#/state/session'
import {logger} from '#/logger'
import {SessionAccount, useSession} from '#/state/session'
import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
type SegmentClient = ReturnType<typeof createClient>
@@ -70,7 +70,7 @@ export function init(account: SessionAccount | undefined) {
if (account.did) {
const did_hashed = sha256(account.did)
client.identify(did_hashed, {did_hashed})
Browser.setUser({id: did_hashed})
Sentry.setUser({id: did_hashed})
logger.debug('Ping w/hash')
} else {
logger.debug('Ping w/o hash')
+1 -1
View File
@@ -10,7 +10,7 @@ import {
} from '#/components/icons/Heart2'
const animationConfig = {
duration: 400,
duration: 600,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
fill: 'forwards' as FillMode,
}
+1 -1
View File
@@ -1,7 +1,7 @@
import {
AppBskyFeedDefs,
AppBskyEmbedRecord,
AppBskyEmbedRecordWithMedia,
AppBskyFeedDefs,
} from '@atproto/api'
export function isEmbedByEmbedder(
+2 -2
View File
@@ -5,7 +5,7 @@
import {Platform} from 'react-native'
import {nativeApplicationVersion, nativeBuildVersion} from 'expo-application'
import {init} from 'sentry-expo'
import {init} from '@sentry/react-native'
import {BUILD_ENV, IS_DEV, IS_TESTFLIGHT} from 'lib/app-info'
@@ -30,10 +30,10 @@ const dist = `${Platform.OS}.${nativeBuildVersion}.${
}${IS_DEV ? 'dev' : ''}`
init({
enabled: !__DEV__,
autoSessionTracking: false,
dsn: 'https://05bc3789bf994b81bd7ce20c86ccd3ae@o4505071687041024.ingest.sentry.io/4505071690514432',
debug: false, // If `true`, Sentry will try to print out useful debugging information if something goes wrong with sending the event. Set it to `false` in production
enableInExpoDevelopment: false, // enable this to test in dev
environment: BUILD_ENV ?? 'development',
dist,
release,
+3 -3
View File
@@ -79,13 +79,13 @@ export const s = StyleSheet.create({
// font weights
fw600: {fontWeight: '600'},
bold: {fontWeight: 'bold'},
bold: {fontWeight: '700'},
fw500: {fontWeight: '500'},
semiBold: {fontWeight: '500'},
fw400: {fontWeight: '400'},
normal: {fontWeight: '400'},
fw300: {fontWeight: '300'},
light: {fontWeight: '300'},
fw300: {fontWeight: '400'},
light: {fontWeight: '400'},
fw200: {fontWeight: '200'},
// text decoration
+45 -44
View File
@@ -1,5 +1,6 @@
import {Platform} from 'react-native'
import {tokens} from '#/alf'
import {darkPalette, dimPalette, lightPalette} from '#/alf/themes'
import {colors} from './styles'
import type {Theme} from './ThemeContext'
@@ -88,163 +89,163 @@ export const defaultTheme: Theme = {
typography: {
'2xl-thin': {
fontSize: 18,
letterSpacing: 0.25,
fontWeight: '300',
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'2xl': {
fontSize: 18,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'2xl-medium': {
fontSize: 18,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '500',
},
'2xl-bold': {
fontSize: 18,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '700',
},
'2xl-heavy': {
fontSize: 18,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '800',
},
'xl-thin': {
fontSize: 17,
letterSpacing: 0.25,
fontWeight: '300',
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
xl: {
fontSize: 17,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'xl-medium': {
fontSize: 17,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '500',
},
'xl-bold': {
fontSize: 17,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '700',
},
'xl-heavy': {
fontSize: 17,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '800',
},
'lg-thin': {
fontSize: 16,
letterSpacing: 0.25,
fontWeight: '300',
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
lg: {
fontSize: 16,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'lg-medium': {
fontSize: 16,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '500',
},
'lg-bold': {
fontSize: 16,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '700',
},
'lg-heavy': {
fontSize: 16,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '800',
},
'md-thin': {
fontSize: 15,
letterSpacing: 0.25,
fontWeight: '300',
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
md: {
fontSize: 15,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'md-medium': {
fontSize: 15,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '500',
},
'md-bold': {
fontSize: 15,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '700',
},
'md-heavy': {
fontSize: 15,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '800',
},
'sm-thin': {
fontSize: 14,
letterSpacing: 0.25,
fontWeight: '300',
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
sm: {
fontSize: 14,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'sm-medium': {
fontSize: 14,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '500',
},
'sm-bold': {
fontSize: 14,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '700',
},
'sm-heavy': {
fontSize: 14,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '800',
},
'xs-thin': {
fontSize: 13,
letterSpacing: 0.25,
fontWeight: '300',
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
xs: {
fontSize: 13,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'xs-medium': {
fontSize: 13,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '500',
},
'xs-bold': {
fontSize: 13,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '700',
},
'xs-heavy': {
fontSize: 13,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '800',
},
'title-2xl': {
fontSize: 34,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '500',
},
'title-xl': {
fontSize: 28,
letterSpacing: 0.25,
letterSpacing: tokens.TRACKING,
fontWeight: '500',
},
'title-lg': {
@@ -254,32 +255,32 @@ export const defaultTheme: Theme = {
title: {
fontWeight: '500',
fontSize: 20,
letterSpacing: 0.15,
letterSpacing: tokens.TRACKING,
},
'title-sm': {
fontWeight: 'bold',
fontSize: 17,
letterSpacing: 0.15,
letterSpacing: tokens.TRACKING,
},
'post-text': {
fontSize: 16,
letterSpacing: 0.2,
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'post-text-lg': {
fontSize: 20,
letterSpacing: 0.2,
letterSpacing: tokens.TRACKING,
fontWeight: '400',
},
'button-lg': {
fontWeight: '500',
fontSize: 18,
letterSpacing: 0.5,
letterSpacing: tokens.TRACKING,
},
button: {
fontWeight: '500',
fontSize: 14,
letterSpacing: 0.5,
letterSpacing: tokens.TRACKING,
},
mono: {
fontSize: 14,
+1 -1
View File
@@ -75,7 +75,7 @@ msgstr "{0, plural, one {# segon} other {# segons}}"
#: src/components/KnownFollowers.tsx:179
#~ msgid "{0, plural, one {and # other} other {and # others}}"
#~ msgstr "{0, plural, one {i # altre} other {i # altres}"
#~ msgstr "{0, plural, one {i # altre} other {i # altres}}"
#: src/components/ProfileHoverCard/index.web.tsx:398
#: src/screens/Profile/Header/Metrics.tsx:23
+102 -58
View File
@@ -127,7 +127,7 @@ msgstr "{0} <0>em <1>texto e tags</1></0>"
msgid "{0} joined this week"
msgstr "{0} entrou esta semana"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:637
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/Scrubber.tsx:195
msgid "{0} of {1}"
msgstr "{0} de {1}"
@@ -343,12 +343,16 @@ msgstr "7 dias"
#~ msgid "A help tooltip"
#~ msgstr "Uma sugestão de ajuda"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:266
msgid "A virtual certificate with text \"Celebrating 10M users on Bluesky, #{0}, {displayName} {handle}, joined on {joinedDate}\""
msgstr "Um certificado virtual com o texto \"Comemorando 10 milhões de usuários no Bluesky, #{0}, {displayName} {handle}, ingressou em {joinedDate}\""
#: src/view/com/util/ViewHeader.tsx:92
#: src/view/screens/Search/Search.tsx:684
msgid "Access navigation links and settings"
msgstr "Acessar links de navegação e configurações"
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:56
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:103
msgid "Access profile and other navigation links"
msgstr "Acessar perfil e outros links de navegação"
@@ -640,7 +644,7 @@ msgstr "Ocorreu um erro"
#~ msgid "An error occured"
#~ msgstr "Tivemos um problema"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:413
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:416
msgid "An error occurred"
msgstr "Ocorreu um erro"
@@ -660,7 +664,7 @@ msgstr "Ocorreu um erro ao carregar o vídeo. Tente novamente mais tarde."
msgid "An error occurred while loading the video. Please try again."
msgstr "Ocorreu um erro ao carregar o vídeo. Tente novamente."
#: src/components/dialogs/nuxs/TenMillion/index.tsx:250
#: src/components/dialogs/nuxs/TenMillion/index.tsx:315
msgid "An error occurred while saving the image!"
msgstr "Ocorreu um erro ao salvar a imagem!"
@@ -990,6 +994,11 @@ msgstr "Bluesky é uma rede aberta que permite a escolha do seu provedor de hosp
msgid "Bluesky is better with friends!"
msgstr "Bluesky é melhor com amigos!"
#: src/components/dialogs/nuxs/TenMillion/Trigger.tsx:43
#: src/components/dialogs/nuxs/TenMillion/Trigger.tsx:59
msgid "Bluesky is celebrating 10 million users!"
msgstr ""
#: src/view/com/auth/onboarding/WelcomeDesktop.tsx:80
#: src/view/com/auth/onboarding/WelcomeMobile.tsx:82
#~ msgid "Bluesky is flexible."
@@ -1005,9 +1014,9 @@ msgstr "Bluesky é melhor com amigos!"
#~ msgid "Bluesky is public."
#~ msgstr "Bluesky é público."
#: src/components/dialogs/nuxs/TenMillion/index.tsx:206
#: src/components/dialogs/nuxs/TenMillion/index.tsx:256
msgid "Bluesky now has over 10 million users, and I was #{0}!"
msgstr "O Bluesky agora tem mais de 10 milhões de usuários, e eu tinha #{0}!"
msgstr "O Bluesky agora tem mais de 10 milhões de usuários, e eu fui o #{0}!"
#: src/components/StarterPack/ProfileStarterPacks.tsx:282
msgid "Bluesky will choose a set of recommended accounts from people in your network."
@@ -1030,7 +1039,7 @@ msgstr "Desfocar imagens e filtrar dos feeds"
msgid "Books"
msgstr "Livros"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:614
#: src/components/dialogs/nuxs/TenMillion/index.tsx:677
msgid "Brag a little!"
msgstr "Gabe-se um pouco!"
@@ -1100,8 +1109,8 @@ msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must
msgstr "Só pode conter letras, números, espaços, riscas e subtraços. Deve ter pelo menos 4 caracteres, mas não mais de 32 caracteres."
#: src/components/Menu/index.tsx:235
#: src/components/Prompt.tsx:122
#: src/components/Prompt.tsx:124
#: src/components/Prompt.tsx:126
#: src/components/TagMenu/index.tsx:282
#: src/screens/Deactivated.tsx:161
#: src/view/com/composer/Composer.tsx:594
@@ -1181,7 +1190,7 @@ msgstr "Legendas (.vtt)"
msgid "Captions & alt text"
msgstr "Legendas e texto alt"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:368
#: src/components/dialogs/nuxs/TenMillion/index.tsx:434
msgid "Celebrating {0} users"
msgstr "Comemorando {0} usuários"
@@ -1532,8 +1541,8 @@ msgstr "Configure o filtro de conteúdo por categoria: {name}"
msgid "Configured in <0>moderation settings</0>."
msgstr "Configure no <0>painel de moderação</0>."
#: src/components/Prompt.tsx:165
#: src/components/Prompt.tsx:168
#: src/components/Prompt.tsx:167
#: src/components/Prompt.tsx:170
#: src/view/com/modals/SelfLabel.tsx:155
#: src/view/com/modals/VerifyEmail.tsx:239
#: src/view/com/modals/VerifyEmail.tsx:241
@@ -2050,7 +2059,7 @@ msgstr "Desabilitar feedback tátil"
#~ msgid "Disable haptics"
#~ msgstr "Desabilitar feedback tátil"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:379
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:382
msgid "Disable subtitles"
msgstr "Desativar legendas"
@@ -2186,7 +2195,7 @@ msgstr "Baixe o Bluesky"
msgid "Download CAR file"
msgstr "Baixar arquivo CAR"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:622
#: src/components/dialogs/nuxs/TenMillion/index.tsx:686
msgid "Download image"
msgstr "Baixar imagem"
@@ -2433,7 +2442,7 @@ msgstr "Habilitar mídia para"
msgid "Enable priority notifications"
msgstr "Habilitar notificações prioritárias"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:380
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:383
msgid "Enable subtitles"
msgstr "Habilitar legendas"
@@ -2565,7 +2574,7 @@ msgstr "Excluir usuário que você segue"
msgid "Excludes users you follow"
msgstr "Excluir usuário que você segue"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:397
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:400
msgid "Exit fullscreen"
msgstr "Sair da tela cheia"
@@ -2912,13 +2921,13 @@ msgstr "Seguir Conta"
msgid "Follow all"
msgstr "Siga todos"
#: src/view/com/profile/FollowButton.tsx:79
msgctxt "action"
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:223
#: src/view/com/post-thread/PostThreadFollowBtn.tsx:142
msgid "Follow Back"
msgstr "Seguir De Volta"
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:223
#: src/view/com/post-thread/PostThreadFollowBtn.tsx:142
#: src/view/com/profile/FollowButton.tsx:79
msgctxt "action"
msgid "Follow Back"
msgstr "Seguir De Volta"
@@ -3075,7 +3084,7 @@ msgctxt "from-feed"
msgid "From <0/>"
msgstr "Por <0/>"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:398
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:401
msgid "Fullscreen"
msgstr "Tela cheia"
@@ -3419,7 +3428,7 @@ msgstr "Imagem"
msgid "Image alt text"
msgstr "Texto alternativo da imagem"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:247
#: src/components/dialogs/nuxs/TenMillion/index.tsx:312
#: src/components/StarterPack/ShareDialog.tsx:76
msgid "Image saved to your camera roll!"
msgstr "Imagem salva no rolo da câmera!"
@@ -3566,8 +3575,12 @@ msgid "Join the conversation"
msgstr "Participe da conversa"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:492
msgid "Joined {0}"
msgstr "Juntou-se {0}"
#~ msgid "Joined {0}"
#~ msgstr "Juntou-se {0}"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:559
msgid "Joined on {joinedDate}"
msgstr ""
#: src/screens/Onboarding/index.tsx:21
#: src/screens/Onboarding/state.ts:89
@@ -4074,8 +4087,8 @@ msgstr "Música"
msgid "Mute"
msgstr "Silenciar"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:166
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:389
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:157
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VolumeControl.tsx:94
msgctxt "video"
msgid "Mute"
msgstr "Silenciar"
@@ -4387,6 +4400,11 @@ msgstr "Nenhum GIF em destaque encontrado."
msgid "No feeds found. Try searching for something else."
msgstr "Nenhum feed encontrado. Tente pesquisar por outra coisa."
#: src/components/LikedByList.tsx:78
#: src/view/com/post-thread/PostLikedBy.tsx:85
msgid "No likes yet"
msgstr ""
#: src/components/ProfileCard.tsx:336
#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:116
msgid "No longer following {0}"
@@ -4423,6 +4441,14 @@ msgstr "Ninguém além do autor pode citar esta postagem."
msgid "No posts yet."
msgstr "Nenhuma postagem ainda."
#: src/view/com/post-thread/PostQuotes.tsx:106
msgid "No quotes yet"
msgstr ""
#: src/view/com/post-thread/PostRepostedBy.tsx:78
msgid "No reposts yet"
msgstr ""
#: src/view/com/composer/text-input/mobile/Autocomplete.tsx:101
#: src/view/com/composer/text-input/web/Autocomplete.tsx:195
msgid "No result"
@@ -4469,11 +4495,20 @@ msgstr "Ninguém"
#~ msgid "Nobody can reply"
#~ msgstr "Ninguém pode responder"
#: src/components/LikedByList.tsx:79
#: src/components/LikedByList.tsx:80
#: src/components/LikesDialog.tsx:99
#: src/view/com/post-thread/PostLikedBy.tsx:87
msgid "Nobody has liked this yet. Maybe you should be the first!"
msgstr "Ninguém curtiu isso ainda. Você pode ser o primeiro!"
#: src/view/com/post-thread/PostQuotes.tsx:108
msgid "Nobody has quoted this yet. Maybe you should be the first!"
msgstr ""
#: src/view/com/post-thread/PostRepostedBy.tsx:80
msgid "Nobody has reposted this yet. Maybe you should be the first!"
msgstr ""
#: src/screens/StarterPack/Wizard/StepProfiles.tsx:103
msgid "Nobody was found. Try searching for someone else."
msgstr "Ninguém foi encontrado. Tente procurar por outra pessoa."
@@ -4576,7 +4611,7 @@ msgstr "Opa!"
msgid "Oh no! Something went wrong."
msgstr "Opa! Algo deu errado."
#: src/components/dialogs/nuxs/TenMillion/index.tsx:175
#: src/components/dialogs/nuxs/TenMillion/index.tsx:224
msgid "Oh no! We weren't able to generate an image for you to share. Rest assured, we're glad you're here 🦋"
msgstr "Ah, não! Não conseguimos gerar uma imagem para você compartilhar. Fique tranquilo, estamos felizes que você esteja aqui 🦋"
@@ -4624,7 +4659,7 @@ msgstr "Apenas {0} pode responder."
msgid "Only contains letters, numbers, and hyphens"
msgstr "Contém apenas letras, números e hífens"
#: src/view/com/composer/videos/SubtitleFilePicker.tsx:39
#: src/view/com/composer/videos/SubtitleFilePicker.tsx:40
msgid "Only WebVTT (.vtt) files are supported"
msgstr "Somente arquivos WebVTT (.vtt) são suportados"
@@ -4680,7 +4715,7 @@ msgstr "Abrir opções de mensagem"
msgid "Open muted words and tags settings"
msgstr "Abrir opções de palavras/tags silenciadas"
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:54
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:101
msgid "Open navigation"
msgstr "Abrir navegação"
@@ -4924,12 +4959,12 @@ msgid "Password updated!"
msgstr "Senha atualizada!"
#: src/view/com/util/post-embeds/GifEmbed.tsx:46
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:150
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:366
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:141
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:369
msgid "Pause"
msgstr "Pausar"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:319
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:320
msgid "Pause video"
msgstr "Pausar vídeo"
@@ -4989,8 +5024,8 @@ msgid "Pinned to your feeds"
msgstr "Fixado em seus feeds"
#: src/view/com/util/post-embeds/GifEmbed.tsx:46
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:150
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:367
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:141
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:370
msgid "Play"
msgstr "Tocar"
@@ -5008,7 +5043,7 @@ msgid "Play or pause the GIF"
msgstr "Tocar ou pausar o GIF"
#: src/view/com/util/post-embeds/VideoEmbed.tsx:110
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:320
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:321
msgid "Play video"
msgstr "Reproduzir vídeo"
@@ -6076,7 +6111,7 @@ msgstr "Veja o guia"
#~ msgid "See what's next"
#~ msgstr "Veja o que vem por aí"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:631
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/Scrubber.tsx:189
msgid "Seek slider"
msgstr "Controle deslizante de busca"
@@ -6136,7 +6171,7 @@ msgstr "Seleciona opção {i} de {numItems}"
#~ msgid "Select some accounts below to follow"
#~ msgstr "Selecione algumas contas para seguir"
#: src/view/com/composer/videos/SubtitleFilePicker.tsx:65
#: src/view/com/composer/videos/SubtitleFilePicker.tsx:66
msgid "Select subtitle file (.vtt)"
msgstr "Selecione o arquivo de legenda (.vtt)"
@@ -6344,7 +6379,7 @@ msgstr "Atividade sexual ou nudez erótica."
msgid "Sexually Suggestive"
msgstr "Sexualmente Sugestivo"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:644
#: src/components/dialogs/nuxs/TenMillion/index.tsx:708
#: src/components/StarterPack/QrCodeDialog.tsx:177
#: src/screens/StarterPack/StarterPackScreen.tsx:411
#: src/screens/StarterPack/StarterPackScreen.tsx:582
@@ -6381,11 +6416,11 @@ msgstr "Compartilhar assim"
msgid "Share feed"
msgstr "Compartilhar feed"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:621
#: src/components/dialogs/nuxs/TenMillion/index.tsx:685
msgid "Share image externally"
msgstr "Compartilhar imagem externamente"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:639
#: src/components/dialogs/nuxs/TenMillion/index.tsx:703
msgid "Share image in post"
msgstr "Compartilhe a imagem na postagem"
@@ -6894,15 +6929,15 @@ msgstr "Alto"
msgid "Tap to dismiss"
msgstr "Toque para dispensar"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:145
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:136
msgid "Tap to enter full screen"
msgstr "Toque para entrar em tela cheia"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:151
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:142
msgid "Tap to play or pause"
msgstr "Toque para reproduzir ou pausar"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:164
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:159
msgid "Tap to toggle sound"
msgstr "Toque para alternar o som"
@@ -6936,7 +6971,7 @@ msgstr "Conte uma piada!"
msgid "Tell us a little more"
msgstr "Conte-nos um pouco mais"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:518
#: src/components/dialogs/nuxs/TenMillion/index.tsx:578
msgid "Ten Million"
msgstr "Dez milhões"
@@ -6977,7 +7012,7 @@ msgstr "Campo de entrada de texto"
msgid "Thank you. Your report has been sent."
msgstr "Obrigado. Sua denúncia foi enviada."
#: src/components/dialogs/nuxs/TenMillion/index.tsx:593
#: src/components/dialogs/nuxs/TenMillion/index.tsx:654
msgid "Thanks for being one of our first 10 million users."
msgstr "Obrigado por ser um dos nossos primeiros 10 milhões de usuários."
@@ -7002,7 +7037,7 @@ msgstr "Este identificador de usuário já está sendo usado."
msgid "That starter pack could not be found."
msgstr "Esse pacote inicial não pôde ser encontrado."
#: src/view/com/post-thread/PostQuotes.tsx:127
#: src/view/com/post-thread/PostQuotes.tsx:133
msgid "That's all, folks!"
msgstr "É isso, pessoal!"
@@ -7457,6 +7492,10 @@ msgstr "Preferências das Threads"
msgid "To disable the email 2FA method, please verify your access to the email address."
msgstr "Para desabilitar o 2FA via e-mail, por favor verifique seu acesso a este endereço de e-mail."
#: src/components/dialogs/nuxs/TenMillion/Trigger.tsx:69
msgid "To learn more, <0>check out our post.</0>"
msgstr ""
#: src/components/dms/ReportConversationPrompt.tsx:20
msgid "To report a conversation, please report one of its messages via the conversation screen. This lets our moderators understand the context of your issue."
msgstr "Para denunciar uma conversa, por favor, denuncie uma das mensagens individualmente. Isso vai permitir a análise da situação pelos nossos moderadores."
@@ -7469,7 +7508,8 @@ msgstr "Para enviar vídeos para o Bluesky, você deve primeiro verificar seu e-
msgid "To whom would you like to send this report?"
msgstr "Para quem você gostaria de enviar esta denúncia?"
#: src/components/dialogs/nuxs/TenMillion/index.tsx:597
#: src/components/dialogs/nuxs/TenMillion/index.tsx:658
#: src/components/dialogs/nuxs/TenMillion/Trigger.tsx:63
msgid "Together, we're rebuilding the social internet. We're glad you're here."
msgstr "Juntos, estamos reconstruindo a internet social. Estamos felizes que você esteja aqui."
@@ -7613,8 +7653,8 @@ msgstr "Descurtir este feed"
msgid "Unmute"
msgstr "Dessilenciar"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:165
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:388
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:156
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VolumeControl.tsx:93
msgctxt "video"
msgid "Unmute"
msgstr "Ativar o áudio"
@@ -7645,13 +7685,13 @@ msgstr "Desmutar conversa"
msgid "Unmute thread"
msgstr "Dessilenciar thread"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx:317
#: src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx:318
msgid "Unmute video"
msgstr "Ativar o áudio do vídeo"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:168
msgid "Unmuted"
msgstr "Áudio ativado"
#~ msgid "Unmuted"
#~ msgstr "Áudio ativado"
#: src/view/screens/ProfileFeed.tsx:292
#: src/view/screens/ProfileList.tsx:673
@@ -7927,8 +7967,8 @@ msgstr "Verificar Seu E-mail"
msgid "Version {appVersion} {bundleInfo}"
msgstr "Versão {appVersion} {bundleInfo}"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:93
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:144
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:84
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:135
msgid "Video"
msgstr "Vídeo"
@@ -7949,7 +7989,7 @@ msgstr "Vídeo não encontrado."
msgid "Video settings"
msgstr "Configurações de vídeo"
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:93
#: src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx:84
msgid "Video: {0}"
msgstr "Vídeo: {0}"
@@ -7999,6 +8039,10 @@ msgstr "Ver thread completa"
msgid "View information about these labels"
msgstr "Ver informações sobre estes rótulos"
#: src/components/dialogs/nuxs/TenMillion/Trigger.tsx:72
msgid "View our post"
msgstr ""
#: src/components/ProfileHoverCard/index.web.tsx:418
#: src/components/ProfileHoverCard/index.web.tsx:436
#: src/components/ProfileHoverCard/index.web.tsx:463
@@ -8023,8 +8067,8 @@ msgstr "Ver usuários que curtiram este feed"
msgid "View your blocked accounts"
msgstr "Veja suas contas bloqueadas"
#: src/view/com/home/HomeHeaderLayout.web.tsx:79
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:86
#: src/view/com/home/HomeHeaderLayout.web.tsx:132
#: src/view/com/home/HomeHeaderLayoutMobile.tsx:143
msgid "View your feeds and explore more"
msgstr "Veja seus feeds e explore mais"
@@ -8497,7 +8541,7 @@ msgstr "Você deve estar seguindo pelo menos sete outras pessoas para gerar um p
msgid "You must grant access to your photo library to save a QR code"
msgstr "Você deve conceder acesso à sua biblioteca de fotos para salvar o QR code."
#: src/components/dialogs/nuxs/TenMillion/index.tsx:237
#: src/components/dialogs/nuxs/TenMillion/index.tsx:302
#: src/components/StarterPack/ShareDialog.tsx:68
msgid "You must grant access to your photo library to save the image."
msgstr "Você deve conceder acesso à sua biblioteca de fotos para salvar a imagem."
+6 -8
View File
@@ -1,6 +1,6 @@
import {beforeAll, describe, expect, jest, test} from '@jest/globals'
import * as Sentry from '@sentry/react-native'
import {nanoid} from 'nanoid/non-secure'
import {jest, describe, expect, test, beforeAll} from '@jest/globals'
import {Native as Sentry} from 'sentry-expo'
import {Logger, LogLevel, sentryTransport} from '#/logger'
@@ -16,12 +16,10 @@ jest.mock('#/env', () => ({
LOG_DEBUG: '',
}))
jest.mock('sentry-expo', () => ({
Native: {
addBreadcrumb: jest.fn(),
captureException: jest.fn(),
captureMessage: jest.fn(),
},
jest.mock('@sentry/react-native', () => ({
addBreadcrumb: jest.fn(),
captureException: jest.fn(),
captureMessage: jest.fn(),
}))
beforeAll(() => {
+1 -1
View File
@@ -1 +1 @@
export {Native as Sentry} from 'sentry-expo'
export * as Sentry from '@sentry/react-native'
+1 -1
View File
@@ -1 +1 @@
export {Browser as Sentry} from 'sentry-expo'
export * as Sentry from '@sentry/react-native'
+155 -57
View File
@@ -14,17 +14,21 @@ import {s} from '#/lib/styles'
import {useSetThemePrefs, useThemePrefs} from '#/state/shell'
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {ScrollView} from '#/view/com/util/Views'
import {atoms as a, native, useTheme} from '#/alf'
import {atoms as a, native, useAlf, useTheme} from '#/alf'
import * as ToggleButton from '#/components/forms/ToggleButton'
import {Props as SVGIconProps} from '#/components/icons/common'
import {Moon_Stroke2_Corner0_Rounded as MoonIcon} from '#/components/icons/Moon'
import {Phone_Stroke2_Corner0_Rounded as PhoneIcon} from '#/components/icons/Phone'
import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize'
import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase'
import {Text} from '#/components/Typography'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppearanceSettings'>
export function AppearanceSettingsScreen({}: Props) {
const {_} = useLingui()
const t = useTheme()
const {_} = useLingui()
const {isTabletOrMobile} = useWebMediaQueries()
const {fonts} = useAlf()
const {colorMode, darkTheme} = useThemePrefs()
const {setColorMode, setDarkTheme} = useSetThemePrefs()
@@ -54,6 +58,22 @@ export function AppearanceSettingsScreen({}: Props) {
[setDarkTheme, darkTheme],
)
const onChangeFontFamily = useCallback(
(values: string[]) => {
const next = values[0] === 'system' ? 'system' : 'theme'
fonts.setFontFamily(next)
},
[fonts],
)
const onChangeFontScale = useCallback(
(values: string[]) => {
const next = values[0] || ('0' as any)
fonts.setFontScale(next)
},
[fonts],
)
return (
<LayoutAnimationConfig skipExiting skipEntering>
<View testID="preferencesThreadsScreen" style={s.hContentRegion}>
@@ -71,65 +91,143 @@ export function AppearanceSettingsScreen({}: Props) {
</View>
</SimpleViewHeader>
<View style={[a.p_xl, a.gap_lg]}>
<View style={[a.flex_row, a.align_center, a.gap_md]}>
<PhoneIcon style={t.atoms.text} />
<Text style={a.text_md}>
<Trans>Mode</Trans>
</Text>
</View>
<ToggleButton.Group
label={_(msg`Dark mode`)}
values={[colorMode]}
onChange={onChangeAppearance}>
<ToggleButton.Button label={_(msg`System`)} name="system">
<ToggleButton.ButtonText>
<Trans>System</Trans>
</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button label={_(msg`Light`)} name="light">
<ToggleButton.ButtonText>
<Trans>Light</Trans>
</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button label={_(msg`Dark`)} name="dark">
<ToggleButton.ButtonText>
<Trans>Dark</Trans>
</ToggleButton.ButtonText>
</ToggleButton.Button>
</ToggleButton.Group>
{colorMode !== 'light' && (
<Animated.View
entering={native(FadeInDown)}
exiting={native(FadeOutDown)}
style={[a.mt_md, a.gap_lg]}>
<View style={[a.flex_row, a.align_center, a.gap_md]}>
<MoonIcon style={t.atoms.text} />
<Text style={a.text_md}>
<Trans>Dark theme</Trans>
</Text>
</View>
<View style={[a.gap_3xl, a.pt_xl, a.px_xl]}>
<View style={[a.gap_lg]}>
<AppearanceToggleButtonGroup
title={_(msg`Color mode`)}
icon={PhoneIcon}
items={[
{
label: _(msg`System`),
name: 'system',
},
{
label: _(msg`Light`),
name: 'light',
},
{
label: _(msg`Dark`),
name: 'dark',
},
]}
values={[colorMode]}
onChange={onChangeAppearance}
/>
<ToggleButton.Group
label={_(msg`Dark theme`)}
values={[darkTheme ?? 'dim']}
onChange={onChangeDarkTheme}>
<ToggleButton.Button label={_(msg`Dim`)} name="dim">
<ToggleButton.ButtonText>
<Trans>Dim</Trans>
</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button label={_(msg`Dark`)} name="dark">
<ToggleButton.ButtonText>
<Trans>Dark</Trans>
</ToggleButton.ButtonText>
</ToggleButton.Button>
</ToggleButton.Group>
</Animated.View>
)}
{colorMode !== 'light' && (
<Animated.View
entering={native(FadeInDown)}
exiting={native(FadeOutDown)}>
<AppearanceToggleButtonGroup
title={_(msg`Dark theme`)}
icon={MoonIcon}
items={[
{
label: _(msg`Dim`),
name: 'dim',
},
{
label: _(msg`Dark`),
name: 'dark',
},
]}
values={[darkTheme ?? 'dim']}
onChange={onChangeDarkTheme}
/>
</Animated.View>
)}
<AppearanceToggleButtonGroup
title={_(msg`Font`)}
description={_(
msg`For the best experience, we recommend using the theme font.`,
)}
icon={Aa}
items={[
{
label: _(msg`System`),
name: 'system',
},
{
label: _(msg`Theme`),
name: 'theme',
},
]}
values={[fonts.family]}
onChange={onChangeFontFamily}
/>
<AppearanceToggleButtonGroup
title={_(msg`Font size`)}
icon={TextSize}
items={[
{
label: _(msg`Smaller`),
name: '-1',
},
{
label: _(msg`Default`),
name: '0',
},
{
label: _(msg`Larger`),
name: '1',
},
]}
values={[fonts.scale]}
onChange={onChangeFontScale}
/>
</View>
</View>
</ScrollView>
</View>
</LayoutAnimationConfig>
)
}
export function AppearanceToggleButtonGroup({
title,
description,
icon: Icon,
items,
values,
onChange,
}: {
title: string
description?: string
icon: React.ComponentType<SVGIconProps>
items: {
label: string
name: string
}[]
values: string[]
onChange: (values: string[]) => void
}) {
const t = useTheme()
return (
<View style={[a.gap_sm]}>
<View style={[a.gap_xs]}>
<View style={[a.flex_row, a.align_center, a.gap_md]}>
<Icon style={t.atoms.text} />
<Text style={[a.text_md, a.font_bold]}>{title}</Text>
</View>
{description && (
<Text
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
{description}
</Text>
)}
</View>
<ToggleButton.Group label={title} values={values} onChange={onChange}>
{items.map(item => (
<ToggleButton.Button
key={item.name}
label={item.label}
name={item.name}>
<ToggleButton.ButtonText>{item.label}</ToggleButton.ButtonText>
</ToggleButton.Button>
))}
</ToggleButton.Group>
</View>
)
}
+7 -7
View File
@@ -1,19 +1,20 @@
import {makeAutoObservable, runInAction} from 'mobx'
import {ImageModel} from './image'
import {Image as RNImage} from 'react-native-image-crop-picker'
import {openPicker} from 'lib/media/picker'
import {getImageDim} from 'lib/media/manip'
import {openPicker} from 'lib/media/picker'
import {ImageInitOptions, ImageModel} from './image'
interface InitialImageUri {
uri: string
width: number
height: number
altText?: string
}
export class GalleryModel {
images: ImageModel[] = []
constructor(uris?: {uri: string; width: number; height: number}[]) {
constructor(uris?: InitialImageUri[]) {
makeAutoObservable(this)
if (uris) {
@@ -33,7 +34,7 @@ export class GalleryModel {
return this.images.some(image => image.altText.trim() === '')
}
*add(image_: Omit<RNImage, 'size'>) {
*add(image_: ImageInitOptions) {
if (this.size >= 4) {
return
}
@@ -59,7 +60,6 @@ export class GalleryModel {
path: uri,
height,
width,
mime: 'image/jpeg',
}
runInAction(() => {
@@ -100,10 +100,10 @@ export class GalleryModel {
async addFromUris(uris: InitialImageUri[]) {
for (const uriObj of uris) {
this.add({
mime: 'image/jpeg',
height: uriObj.height,
width: uriObj.width,
path: uriObj.uri,
altText: uriObj.altText,
})
}
}
+18 -7
View File
@@ -1,14 +1,15 @@
import {Image as RNImage} from 'react-native-image-crop-picker'
import {makeAutoObservable, runInAction} from 'mobx'
import {POST_IMG_MAX} from 'lib/constants'
import * as ImageManipulator from 'expo-image-manipulator'
import {getDataUriSize} from 'lib/media/util'
import {openCropper} from 'lib/media/picker'
import {ActionCrop, FlipType, SaveFormat} from 'expo-image-manipulator'
import {makeAutoObservable, runInAction} from 'mobx'
import {Position} from 'react-avatar-editor'
import {Dimensions} from 'lib/media/types'
import {isIOS} from 'platform/detection'
import {logger} from '#/logger'
import {POST_IMG_MAX} from 'lib/constants'
import {openCropper} from 'lib/media/picker'
import {Dimensions} from 'lib/media/types'
import {getDataUriSize} from 'lib/media/util'
import {isIOS} from 'platform/detection'
export interface ImageManipulationAttributes {
aspectRatio?: '4:3' | '1:1' | '3:4' | 'None'
@@ -19,6 +20,13 @@ export interface ImageManipulationAttributes {
flipVertical?: boolean
}
export interface ImageInitOptions {
path: string
width: number
height: number
altText?: string
}
const MAX_IMAGE_SIZE_IN_BYTES = 976560
export class ImageModel implements Omit<RNImage, 'size'> {
@@ -41,12 +49,15 @@ export class ImageModel implements Omit<RNImage, 'size'> {
}
prevAttributes: ImageManipulationAttributes = {}
constructor(image: Omit<RNImage, 'size'>) {
constructor(image: ImageInitOptions) {
makeAutoObservable(this)
this.path = image.path
this.width = image.width
this.height = image.height
if (image.altText !== undefined) {
this.setAltText(image.altText)
}
}
setRatio(aspectRatio: ImageManipulationAttributes['aspectRatio']) {
+11 -4
View File
@@ -4,15 +4,22 @@ import {BaseNux} from '#/state/queries/nuxs/types'
export enum Nux {
TenMillionDialog = 'TenMillionDialog',
NeueTypography = 'NeueTypography',
}
export const nuxNames = new Set(Object.values(Nux))
export type AppNux = BaseNux<{
id: Nux.TenMillionDialog
data: undefined
}>
export type AppNux =
| BaseNux<{
id: Nux.TenMillionDialog
data: undefined
}>
| BaseNux<{
id: Nux.NeueTypography
data: undefined
}>
export const NuxSchemas: Record<Nux, zod.ZodObject<any> | undefined> = {
[Nux.TenMillionDialog]: undefined,
[Nux.NeueTypography]: undefined,
}
+1 -1
View File
@@ -36,7 +36,7 @@ export interface ComposerOpts {
mention?: string // handle of user to mention
openEmojiPicker?: (pos: DOMRect | undefined) => void
text?: string
imageUris?: {uri: string; width: number; height: number}[]
imageUris?: {uri: string; width: number; height: number; altText?: string}[]
}
type StateContext = ComposerOpts | undefined
@@ -48,7 +48,7 @@ export function useComposerKeyboardShortcut() {
function handler(event: KeyboardEvent) {
if (shouldIgnore(event)) return
if (
openDialogs.current.size > 0 ||
openDialogs?.current.size > 0 ||
isModalActive ||
activeLightbox ||
isDrawerOpen
+2
View File
@@ -2,6 +2,8 @@
* Device data that's specific to the device and does not vary based account
*/
export type Device = {
fontScale: '-2' | '-1' | '0' | '1' | '2'
fontFamily: 'system' | 'theme'
lastNuxDialog: string | undefined
geolocation?: {
countryCode: string | undefined
+34 -19
View File
@@ -19,6 +19,7 @@ import PasteInput, {
PasteInputRef,
} from '@mattermost/react-native-paste-input'
import {isAndroid} from '#/platform/detection'
import {POST_IMG_MAX} from 'lib/constants'
import {usePalette} from 'lib/hooks/usePalette'
import {downloadAndResize} from 'lib/media/manip'
@@ -26,12 +27,13 @@ import {isUriImage} from 'lib/media/util'
import {cleanError} from 'lib/strings/errors'
import {getMentionAt, insertMentionAt} from 'lib/strings/mention-manip'
import {useTheme} from 'lib/ThemeContext'
import {isIOS} from 'platform/detection'
import {
LinkFacetMatch,
suggestLinkCardUri,
} from 'view/com/composer/text-input/text-input-util'
import {Text} from 'view/com/util/text/Text'
import {atoms as a, useAlf} from '#/alf'
import {normalizeTextStyles} from '#/components/Typography'
import {Autocomplete} from './mobile/Autocomplete'
export interface TextInputRef {
@@ -67,6 +69,7 @@ export const TextInput = forwardRef(function TextInputImpl(
}: TextInputProps,
ref,
) {
const {theme: t, fonts} = useAlf()
const pal = usePalette('default')
const textInput = useRef<PasteInputRef>(null)
const textInputSelection = useRef<Selection>({start: 0, end: 0})
@@ -180,6 +183,33 @@ export const TextInput = forwardRef(function TextInputImpl(
[onChangeText, richtext, setAutocompletePrefix],
)
const inputTextStyle = React.useMemo(() => {
const style = normalizeTextStyles(
[a.text_xl, a.leading_snug, t.atoms.text],
{
fontScale: fonts.scaleMultiplier,
fontFamily: fonts.family,
flags: {},
},
)
/*
* `PasteInput` appears to prefer no `lineHeight`
*/
style.lineHeight = undefined
/*
* Android impl of `PasteInput` doesn't support the array syntax for `fontVariant`
*/
if (isAndroid) {
// @ts-ignore
style.fontVariant = style.fontVariant
? style.fontVariant.join(' ')
: undefined
}
return style
}, [t, fonts])
const textDecorated = useMemo(() => {
let i = 0
@@ -187,15 +217,12 @@ export const TextInput = forwardRef(function TextInputImpl(
return (
<Text
key={i++}
style={[
segment.facet ? pal.link : pal.text,
styles.textInputFormatting,
]}>
style={[inputTextStyle, segment.facet ? pal.link : pal.text]}>
{segment.text}
</Text>
)
})
}, [richtext, pal.link, pal.text])
}, [richtext, pal.link, pal.text, inputTextStyle])
return (
<View style={styles.container}>
@@ -213,12 +240,7 @@ export const TextInput = forwardRef(function TextInputImpl(
multiline
scrollEnabled={false}
numberOfLines={4}
style={[
pal.text,
styles.textInput,
styles.textInputFormatting,
{textAlignVertical: 'top'},
]}
style={[inputTextStyle, styles.textInput, {textAlignVertical: 'top'}]}
{...props}>
{textDecorated}
</PasteInput>
@@ -242,11 +264,4 @@ const styles = StyleSheet.create({
marginLeft: 8,
alignSelf: 'flex-start',
},
textInputFormatting: {
fontSize: 18,
letterSpacing: 0.2,
fontWeight: '400',
// This is broken on ios right now, so don't set it there.
lineHeight: isIOS ? undefined : 23.4, // 1.3*16
},
})
@@ -22,7 +22,9 @@ import {
LinkFacetMatch,
suggestLinkCardUri,
} from 'view/com/composer/text-input/text-input-util'
import {atoms as a, useAlf} from '#/alf'
import {Portal} from '#/components/Portal'
import {normalizeTextStyles} from '#/components/Typography'
import {Text} from '../../util/text/Text'
import {createSuggestion} from './web/Autocomplete'
import {Emoji} from './web/EmojiPicker.web'
@@ -58,6 +60,7 @@ export const TextInput = React.forwardRef(function TextInputImpl(
TextInputProps,
ref,
) {
const {theme: t, fonts} = useAlf()
const autocomplete = useActorAutocompleteFn()
const pal = usePalette('default')
const modeClass = useColorSchemeStyle('ProseMirror-light', 'ProseMirror-dark')
@@ -247,13 +250,32 @@ export const TextInput = React.forwardRef(function TextInputImpl(
},
}))
const inputStyle = React.useMemo(() => {
const style = normalizeTextStyles(
[a.text_lg, a.leading_snug, t.atoms.text],
{
fontScale: fonts.scaleMultiplier,
fontFamily: fonts.family,
flags: {},
},
)
/*
* TipTap component isn't a RN View and while it seems to convert
* `fontSize` to `px`, it doesn't convert `lineHeight`.
*
* `lineHeight` should always be defined here, this is defensive.
*/
style.lineHeight = style.lineHeight
? ((style.lineHeight + 'px') as unknown as number)
: undefined
return style
}, [t, fonts])
return (
<>
<View style={styles.container}>
<EditorContent
editor={editor}
style={{color: pal.text.color as string}}
/>
{/* @ts-ignore inputStyle is fine */}
<EditorContent editor={editor} style={inputStyle} />
</View>
{isDropping && (
+42 -64
View File
@@ -2,7 +2,6 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {Pressable, StyleSheet, View} from 'react-native'
import {useWindowDimensions} from 'react-native'
import {LinearGradient} from 'expo-linear-gradient'
import {MaterialIcons} from '@expo/vector-icons'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {Slider} from '@miblanchard/react-native-slider'
@@ -13,13 +12,24 @@ import {useModalControls} from '#/state/modals'
import {MAX_ALT_TEXT} from 'lib/constants'
import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {RectTallIcon, RectWideIcon, SquareIcon} from 'lib/icons'
import {enforceLen} from 'lib/strings/helpers'
import {gradients, s} from 'lib/styles'
import {useTheme} from 'lib/ThemeContext'
import {getKeys} from 'lib/type-assertions'
import {GalleryModel} from 'state/models/media/gallery'
import {ImageModel} from 'state/models/media/image'
import {atoms as a} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {
AspectRatio11_Stroke2_Corner0_Rounded as A11,
AspectRatio34_Stroke2_Corner0_Rounded as A34,
AspectRatio43_Stroke2_Corner0_Rounded as A43,
} from '#/components/icons/AspectRatio'
import {CircleBanSign_Stroke2_Corner0_Rounded as Ban} from '#/components/icons/CircleBanSign'
import {
FlipHorizontal_Stroke2_Corner0_Rounded as FlipHorizontal,
FlipVertical_Stroke2_Corner0_Rounded as FlipVertical,
} from '#/components/icons/FlipImage'
import {Text} from '../util/text/Text'
import {TextInput} from './util'
@@ -27,18 +37,16 @@ export const snapPoints = ['80%']
const RATIOS = {
'4:3': {
Icon: RectWideIcon,
icon: A43,
},
'1:1': {
Icon: SquareIcon,
icon: A11,
},
'3:4': {
Icon: RectTallIcon,
icon: A34,
},
None: {
label: 'None',
Icon: MaterialIcons,
name: 'do-not-disturb-alt',
icon: Ban,
},
} as const
@@ -112,12 +120,12 @@ export const Component = observer(function EditImageImpl({
// },
// },
{
name: 'flip' as const,
icon: FlipHorizontal,
label: _(msg`Flip horizontal`),
onPress: onFlipHorizontal,
},
{
name: 'flip' as const,
icon: FlipVertical,
label: _(msg`Flip vertically`),
onPress: onFlipVertical,
},
@@ -165,17 +173,6 @@ export const Component = observer(function EditImageImpl({
onCloseModal()
}, [altText, image, position, scale, onCloseModal])
const getLabelIconSize = useCallback((as: AspectRatio) => {
switch (as) {
case 'None':
return 22
case '1:1':
return 32
default:
return 26
}
}, [])
if (image.cropped === undefined) {
return null
}
@@ -231,7 +228,7 @@ export const Component = observer(function EditImageImpl({
maximumValue={3}
/>
</View>
<View>
<View style={[a.gap_sm]}>
{!isMobile ? (
<Text type="sm-bold" style={pal.text}>
<Trans>Ratios</Trans>
@@ -239,31 +236,25 @@ export const Component = observer(function EditImageImpl({
) : null}
<View style={imgControlStyles}>
{getKeys(RATIOS).map(ratio => {
const {Icon, ...props} = RATIOS[ratio]
const labelIconSize = getLabelIconSize(ratio)
const {icon} = RATIOS[ratio]
const isSelected = aspectRatio === ratio
return (
<Pressable
<Button
key={ratio}
label={ratio}
size="large"
shape="square"
variant="outline"
color={isSelected ? 'primary' : 'secondary'}
onPress={() => {
onSetRatio(ratio)
}}
accessibilityLabel={ratio}
accessibilityHint="">
<Icon
size={labelIconSize}
style={[styles.imgControl, isSelected ? s.blue3 : pal.text]}
color={(isSelected ? s.blue3 : pal.text).color}
{...props}
/>
<Text
type={isSelected ? 'xs-bold' : 'xs-medium'}
style={[isSelected ? s.blue3 : pal.text, s.textCenter]}>
{ratio}
</Text>
</Pressable>
}}>
<View style={[a.align_center, a.gap_2xs]}>
<ButtonIcon icon={icon} />
<ButtonText style={[a.text_xs]}>{ratio}</ButtonText>
</View>
</Button>
)
})}
</View>
@@ -273,24 +264,17 @@ export const Component = observer(function EditImageImpl({
</Text>
) : null}
<View style={imgControlStyles}>
{adjustments.map(({label, name, onPress}) => (
<Pressable
{adjustments.map(({label, icon, onPress}) => (
<Button
key={label}
onPress={onPress}
accessibilityLabel={label}
accessibilityHint=""
style={styles.flipBtn}>
<MaterialIcons
name={name}
size={label?.startsWith('Flip') ? 22 : 24}
style={[
pal.text,
label === _(msg`Flip vertically`)
? styles.flipVertical
: undefined,
]}
/>
</Pressable>
label={label}
size="large"
shape="square"
variant="outline"
color="secondary"
onPress={onPress}>
<ButtonIcon icon={icon} />
</Button>
))}
</View>
</View>
@@ -362,12 +346,6 @@ const styles = StyleSheet.create({
paddingVertical: 8,
paddingHorizontal: 24,
},
imgControl: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: 40,
},
imgEditor: {
maxWidth: '100%',
},
+8 -2
View File
@@ -19,7 +19,7 @@ import {colors} from 'lib/styles'
import {isAndroid, isNative, isWeb} from 'platform/detection'
import {precacheProfile} from 'state/queries/profile'
import {HighPriorityImage} from 'view/com/util/images/Image'
import {atoms as a, tokens, useTheme} from '#/alf'
import {tokens, useTheme} from '#/alf'
import {
Camera_Filled_Stroke2_Corner0_Rounded as CameraFilled,
Camera_Stroke2_Corner0_Rounded as Camera,
@@ -241,7 +241,13 @@ let UserAvatar = ({
onLoad={onLoad}
/>
)}
<MediaInsetBorder style={[a.rounded_full]} />
<MediaInsetBorder
style={[
{
borderRadius: aviStyle.borderRadius,
},
]}
/>
{alert}
</View>
) : (
@@ -59,7 +59,7 @@ export const ExternalLinkEmbed = ({
}
return (
<View style={[a.flex_col, a.rounded_sm]}>
<View style={[a.flex_col, a.w_full]}>
<LinkWrapper link={link} onOpen={onOpen} style={style}>
{imageUri && !embedPlayerParams ? (
<View>
+38 -9
View File
@@ -1,10 +1,11 @@
import React from 'react'
import {Text as RNText, TextProps} from 'react-native'
import {StyleSheet, Text as RNText, TextProps} from 'react-native'
import {UITextView} from 'react-native-uitextview'
import {lh, s} from 'lib/styles'
import {TypographyVariant, useTheme} from 'lib/ThemeContext'
import {isIOS, isWeb} from 'platform/detection'
import {applyFonts, useAlf} from '#/alf'
export type CustomTextProps = TextProps & {
type?: TypographyVariant
@@ -32,11 +33,28 @@ export function Text({
const theme = useTheme()
const typography = theme.typography[type]
const lineHeightStyle = lineHeight ? lh(theme, type, lineHeight) : undefined
const {fonts} = useAlf()
if (selectable && isIOS) {
const flattened = StyleSheet.flatten([
s.black,
typography,
lineHeightStyle,
style,
])
applyFonts(flattened, fonts.family)
// should always be defined on `typography`
// @ts-ignore
if (flattened.fontSize) {
// @ts-ignore
flattened.fontSize = flattened.fontSize * fonts.scaleMultiplier
}
return (
<UITextView
style={[s.black, typography, lineHeightStyle, style]}
style={flattened}
selectable={selectable}
uiTextView
{...props}>
@@ -45,15 +63,26 @@ export function Text({
)
}
const flattened = StyleSheet.flatten([
s.black,
typography,
isWeb && fontFamilyStyle,
lineHeightStyle,
style,
])
applyFonts(flattened, fonts.family)
// should always be defined on `typography`
// @ts-ignore
if (flattened.fontSize) {
// @ts-ignore
flattened.fontSize = flattened.fontSize * fonts.scaleMultiplier
}
return (
<RNText
style={[
s.black,
typography,
isWeb && fontFamilyStyle,
lineHeightStyle,
style,
]}
style={flattened}
// @ts-ignore web only -esb
dataSet={Object.assign({tooltip: title}, dataSet || {})}
selectable={selectable}
+99 -1
View File
@@ -17,7 +17,106 @@
<link rel="preconnect" href="https://bsky.social">
<link rel="preconnect" href="https://bsky.network">
<title>%WEB_TITLE%</title>
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Regular.1f5ed03b6dd9fd1f9982.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Italic.95778eb0c75dc956257e.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Medium.296aa2d65964269836b3.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-MediumItalic.0e57e17a6311368e2114.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-SemiBold.2277990330981b8409bb.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-SemiBoldItalic.f62fea3df3a521d6c8a7.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Bold.8d330503e1d034ad68de.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-BoldItalic.bb17e63f9baa0d861a20.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-ExtraBold.ff2581a193bf6b7e0b06.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-ExtraBoldItalic.0e50b40728d24d40fdf4.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-Black.66e9a87f1c921e844ed4.otf">
<link rel="preload" as="font" type="font/otf" href="/static/media/Inter-BlackItalic.27b9f0ad06fd13a7b9da.otf">
<style>
@font-face {
font-family: "Inter-Regular";
src: local("Inter-Regular"), url(/static/media/Inter-Regular.1f5ed03b6dd9fd1f9982.otf) format("font/otf");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-Italic";
src: local("Inter-Italic"), url(/static/media/Inter-Italic.95778eb0c75dc956257e.otf) format("font/otf");
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-Medium";
src: local("Inter-Medium"), url(/static/media/Inter-Medium.296aa2d65964269836b3.otf) format("font/otf");
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-MediumItalic";
src: local("Inter-MediumItalic"), url(/static/media/Inter-MediumItalic.0e57e17a6311368e2114.otf) format("font/otf");
font-weight: 500;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-SemiBold";
src: local("Inter-SemiBold"), url(/static/media/Inter-SemiBold.2277990330981b8409bb.otf) format("font/otf");
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-SemiBoldItalic";
src: local("Inter-SemiBoldItalic"), url(/static/media/Inter-SemiBoldItalic.f62fea3df3a521d6c8a7.otf) format("font/otf");
font-weight: 600;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-Bold";
src: local("Inter-Bold"), url(/static/media/Inter-Bold.8d330503e1d034ad68de.otf) format("font/otf");
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-BoldItalic";
src: local("Inter-BoldItalic"), url(/static/media/Inter-BoldItalic.bb17e63f9baa0d861a20.otf) format("font/otf");
font-weight: 700;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-ExtraBold";
src: local("Inter-ExtraBold"), url(/static/media/Inter-ExtraBold.ff2581a193bf6b7e0b06.otf) format("font/otf");
font-weight: 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-ExtraBoldItalic";
src: local("Inter-ExtraBoldItalic"), url(/static/media/Inter-ExtraBoldItalic.0e50b40728d24d40fdf4.otf) format("font/otf");
font-weight: 800;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "Inter-Black";
src: local("Inter-Black"), url(/static/media/Inter-Black.66e9a87f1c921e844ed4.otf) format("font/otf");
font-weight: 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter-BlackItalic";
src: local("Inter-BlackItalic"), url(/static/media/Inter-BlackItalic.27b9f0ad06fd13a7b9da.otf) format("font/otf");
font-weight: 900;
font-style: italic;
font-display: swap;
}
/**
* Extend the react-native-web reset:
* https://github.com/necolas/react-native-web/blob/master/packages/react-native-web/src/exports/StyleSheet/initialRules.js
@@ -153,7 +252,6 @@
/* ProseMirror */
.ProseMirror {
font: 18px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif;
min-height: 140px;
}
.ProseMirror-dark {
+158 -171
View File
@@ -3887,7 +3887,7 @@
dependencies:
cross-spawn "^6.0.5"
"@expo/spawn-async@^1.5.0", "@expo/spawn-async@^1.7.0", "@expo/spawn-async@^1.7.2":
"@expo/spawn-async@^1.5.0", "@expo/spawn-async@^1.7.2":
version "1.7.2"
resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.2.tgz#fcfe66c3e387245e72154b1a7eae8cada6a47f58"
integrity sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==
@@ -6006,188 +6006,181 @@
dset "^3.1.1"
tiny-hashes "^1.0.1"
"@sentry-internal/tracing@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.52.0.tgz#c4e0750ad0c3949c5bb4b59cbb708b0fef274080"
integrity sha512-o1YPcRGtC9tjeFCvWRJsbgK94zpExhzfxWaldAKvi3PuWEmPeewSdO/Q5pBIY1QonvSI+Q3gysLRcVlLYHhO5A==
"@sentry-internal/feedback@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.119.0.tgz#429b3ea0fd34e928d2e7de5dcbe9377272a3f221"
integrity sha512-om8TkAU5CQGO8nkmr7qsSBVkP+/vfeS4JgtW3sjoTK0fhj26+DljR6RlfCGWtYQdPSP6XV7atcPTjbSnsmG9FQ==
dependencies:
"@sentry/core" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
tslib "^1.9.3"
"@sentry/core" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
"@sentry-internal/tracing@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.52.1.tgz#c98823afd2f9814466fa26f24a1a54fe63b27c24"
integrity sha512-6N99rE+Ek0LgbqSzI/XpsKSLUyJjQ9nychViy+MP60p1x+hllukfTsDbNtUNrPlW0Bx+vqUrWKkAqmTFad94TQ==
"@sentry-internal/replay-canvas@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.119.0.tgz#85669d184ba79150e64d05de02f5e2b616e68371"
integrity sha512-NL02VQx6ekPxtVRcsdp1bp5Tb5w6vnfBKSIfMKuDRBy5A10Uc3GSoy/c3mPyHjOxB84452A+xZSx6bliEzAnuA==
dependencies:
"@sentry/core" "7.52.1"
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
tslib "^1.9.3"
"@sentry/core" "7.119.0"
"@sentry/replay" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
"@sentry/browser@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.52.0.tgz#55d266c89ed668389ff687e5cc885c27016ea85c"
integrity sha512-Sib0T24cQCqqqAhg+nZdfI7qNYGE03jiM3RbY7yG5UoycdnJzWEwrBVSzRTgg3Uya9TRTEGJ+d9vxPIU5TL7TA==
"@sentry-internal/tracing@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.119.0.tgz#201561af2a4ad1837333287c26050a5e688537ca"
integrity sha512-oKdFJnn+56f0DHUADlL8o9l8jTib3VDLbWQBVkjD9EprxfaCwt2m8L5ACRBdQ8hmpxCEo4I8/6traZ7qAdBUqA==
dependencies:
"@sentry-internal/tracing" "7.52.0"
"@sentry/core" "7.52.0"
"@sentry/replay" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
tslib "^1.9.3"
"@sentry/core" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
"@sentry/browser@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.52.1.tgz#f112ca4170bb5023f050bdcbcce5621b475a46eb"
integrity sha512-HrCOfieX68t+Wj42VIkraLYwx8kN5311SdBkHccevWs2Y2dZU7R9iLbI87+nb5kpOPQ7jVWW7d6QI/yZmliYgQ==
"@sentry/babel-plugin-component-annotate@2.20.1":
version "2.20.1"
resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.20.1.tgz#204c63ed006a048f48f633876e1b8bacf87a9722"
integrity sha512-4mhEwYTK00bIb5Y9UWIELVUfru587Vaeg0DQGswv4aIRHIiMKLyNqCEejaaybQ/fNChIZOKmvyqXk430YVd7Qg==
"@sentry/browser@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.119.0.tgz#65004015c107be5d2f49a852ebcffc5d19d90e0d"
integrity sha512-WwmW1Y4D764kVGeKmdsNvQESZiAn9t8LmCWO0ucBksrjL2zw9gBPtOpRcO6l064sCLeSxxzCN+kIxhRm1gDFEA==
dependencies:
"@sentry-internal/tracing" "7.52.1"
"@sentry/core" "7.52.1"
"@sentry/replay" "7.52.1"
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
tslib "^1.9.3"
"@sentry-internal/feedback" "7.119.0"
"@sentry-internal/replay-canvas" "7.119.0"
"@sentry-internal/tracing" "7.119.0"
"@sentry/core" "7.119.0"
"@sentry/integrations" "7.119.0"
"@sentry/replay" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
"@sentry/cli@2.17.5":
version "2.17.5"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.17.5.tgz#d41e24893a843bcd41e14274044a7ddea9332824"
integrity sha512-0tXjLDpaKB46851EMJ6NbP0o9/gdEaDSLAyjEtXxlVO6+RyhUj6x6jDwn0vis8n/7q0AvbIjAcJrot+TbZP+WQ==
"@sentry/cli-darwin@2.36.1":
version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.36.1.tgz#786adf6984dbe3c6fb7dac51b625c314117b807d"
integrity sha512-JOHQjVD8Kqxm1jUKioAP5ohLOITf+Dh6+DBz4gQjCNdotsvNW5m63TKROwq2oB811p+Jzv5304ujmN4cAqW1Ww==
"@sentry/cli-linux-arm64@2.36.1":
version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.36.1.tgz#ff449d7e7e715166257998c02cf635ca02acbadd"
integrity sha512-R//3ZEkbzvoStr3IA7nxBZNiBYyxOljOqAhgiTnejXHmnuwDzM3TBA2n5vKPE/kBFxboEBEw0UTzTIRb1T0bgw==
"@sentry/cli-linux-arm@2.36.1":
version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.36.1.tgz#1ae5d335a1b4cd217a34c2bd6c6f5e0670136eb3"
integrity sha512-gvEOKN0fWL2AVqUBKHNXPRZfJNvKTs8kQhS8cQqahZGgZHiPCI4BqW45cKMq+ZTt1UUbLmt6khx5Dz7wi+0i5A==
"@sentry/cli-linux-i686@2.36.1":
version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.36.1.tgz#112b9e26357e918cbbba918114ec8cdab07cdf60"
integrity sha512-R7sW5Vk/HacVy2YgQoQB+PwccvFYf2CZVPSFSFm2z7MEfNe77UYHWUq+sjJ4vxWG6HDWGVmaX0fjxyDkE01JRA==
"@sentry/cli-linux-x64@2.36.1":
version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.36.1.tgz#c3e5bdb0c9a4bb44c83927c62a3cd7e006709bf7"
integrity sha512-UMr3ik8ksA7zQfbzsfwCb+ztenLnaeAbX94Gp+bzANZwPfi/vVHf2bLyqsBs4OyVt9SPlN1bbM/RTGfMjZ3JOw==
"@sentry/cli-win32-i686@2.36.1":
version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.36.1.tgz#819573320e885e1dbf59b0a01d3bd370c84c1708"
integrity sha512-CflvhnvxPEs5GWQuuDtYSLqPrBaPbcSJFlBuUIb+8WNzRxvVfjgw1qzfZmkQqABqiy/YEsEekllOoMFZAvCcVA==
"@sentry/cli-win32-x64@2.36.1":
version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.36.1.tgz#80779b4bffb4e2e32944eae72c60e6f40151b4dc"
integrity sha512-wWqht2xghcK3TGnooHZSzA3WSjdtno/xFjZLvWmw38rblGwgKMxLZnlxV6uDyS+OJ6CbfDTlCRay/0TIqA0N8g==
"@sentry/cli@2.36.1":
version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.36.1.tgz#a9146b798cb6d2f782a7a48d74633ddcd88dc8d3"
integrity sha512-gzK5uQKDWKhyH5udoB5+oaUNrS//urWyaXgKvHKz4gFfl744HuKY9dpLPP2nMnf0zLGmGM6xJnMXLqILq0mtxw==
dependencies:
https-proxy-agent "^5.0.0"
node-fetch "^2.6.7"
progress "^2.0.3"
proxy-from-env "^1.1.0"
which "^2.0.2"
optionalDependencies:
"@sentry/cli-darwin" "2.36.1"
"@sentry/cli-linux-arm" "2.36.1"
"@sentry/cli-linux-arm64" "2.36.1"
"@sentry/cli-linux-i686" "2.36.1"
"@sentry/cli-linux-x64" "2.36.1"
"@sentry/cli-win32-i686" "2.36.1"
"@sentry/cli-win32-x64" "2.36.1"
"@sentry/core@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.52.0.tgz#6c820ca48fe2f06bfd6b290044c96de2375f2ad4"
integrity sha512-BWdG6vCMeUeMhF4ILpxXTmw70JJvT1MGJcnv09oSupWHTmqy6I19YP6YcEyFuBL4jXPN51eCl7luIdLGJrPbOg==
"@sentry/core@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.119.0.tgz#a6e41119bb03ec27689f9ad04e79d1fba5b7fc37"
integrity sha512-CS2kUv9rAJJEjiRat6wle3JATHypB0SyD7pt4cpX5y0dN5dZ1JrF57oLHRMnga9fxRivydHz7tMTuBhSSwhzjw==
dependencies:
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
tslib "^1.9.3"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
"@sentry/core@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.52.1.tgz#4de702937ba8944802bb06eb8dfdf089c39f6bab"
integrity sha512-36clugQu5z/9jrit1gzI7KfKbAUimjRab39JeR0mJ6pMuKLTTK7PhbpUAD4AQBs9qVeXN2c7h9SVZiSA0UDvkg==
"@sentry/hub@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.119.0.tgz#a94d657b9d3cfd4cc061c5c238f86faefb55d5d8"
integrity sha512-183h5B/rZosLxpB+ZYOvFdHk0rwZbKskxqKFtcyPbDAfpCUgCass41UTqyxF6aH1qLgCRxX8GcLRF7frIa/SOg==
dependencies:
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
tslib "^1.9.3"
"@sentry/core" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
"@sentry/hub@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.52.0.tgz#ffc087d58c745d57108862faa0f701b15503dcc2"
integrity sha512-w3d8Pmp3Fx2zbbjz6hAeIbsFEkLyrUs9YTGG2y8oCoTlAtGK+AjdG+Z0H/clAZONflD/je2EmFHCI0EuXE9tEw==
"@sentry/integrations@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.119.0.tgz#5b25c603026dbacfe1ae7bb8d768506a129149fb"
integrity sha512-OHShvtsRW0A+ZL/ZbMnMqDEtJddPasndjq+1aQXw40mN+zeP7At/V1yPZyFaURy86iX7Ucxw5BtmzuNy7hLyTA==
dependencies:
"@sentry/core" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
tslib "^1.9.3"
"@sentry/integrations@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.52.0.tgz#632aa5e54bdfdab910a24057c2072634a2670409"
integrity sha512-tqxYzgc71XdFD8MTCsVMCPef08lPY9jULE5Zi7TzjyV2AItDRJPkixG0qjwjOGwCtN/6KKz0lGPGYU8ZDxvsbg==
dependencies:
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
"@sentry/core" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
localforage "^1.8.1"
tslib "^1.9.3"
"@sentry/integrations@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.52.1.tgz#e8a5988477e8d295fa1d90ce5628c1a7794c2a09"
integrity sha512-4uejF01723wzEHjcP5AcNcV+Z/6U27b1LyaDu0jY3XDry98MMjhS/ASzecLpaEFxi3dh/jMTUrNp1u7WMj59Lg==
"@sentry/react-native@5.32.0":
version "5.32.0"
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-5.32.0.tgz#14c46a65f7359f5e74a9cef7edb9d7bf9a0a449d"
integrity sha512-Rh5EEYuWUyPaTaL8b/tl3okGiWb3LSvfYiS/WkvTYH+pFYr2RNtrZSCxhP5TpWSqkoy8VVXeYhSmlBvjfD/uDg==
dependencies:
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
localforage "^1.8.1"
tslib "^1.9.3"
"@sentry/babel-plugin-component-annotate" "2.20.1"
"@sentry/browser" "7.119.0"
"@sentry/cli" "2.36.1"
"@sentry/core" "7.119.0"
"@sentry/hub" "7.119.0"
"@sentry/integrations" "7.119.0"
"@sentry/react" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
"@sentry/react-native@5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-5.5.0.tgz#b1283f68465b1772ad6059ebba149673cef33f2d"
integrity sha512-xrES+OAIu3HFhoQSuJjd16Hh02/mByuNoKUjF7e4WDGIiTew3aqlqeLjU7x4npmg5Vbt+ND5jR12u/NmdfArwg==
"@sentry/react@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.119.0.tgz#79f2c9d94322a3afbfa8af9f5b872f7c2e9b0820"
integrity sha512-cf8Cei+qdSA26gx+IMAuc/k44PeBImNzIpXi3930SLhUe44ypT5OZ/44L6xTODHZzTIyMSJPduf59vT2+eW9yg==
dependencies:
"@sentry/browser" "7.52.0"
"@sentry/cli" "2.17.5"
"@sentry/core" "7.52.0"
"@sentry/hub" "7.52.0"
"@sentry/integrations" "7.52.0"
"@sentry/react" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
"@sentry/react@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.52.0.tgz#d12d270ec82dea0474e69deb9112181affe7c524"
integrity sha512-VQxquyFFlvB81k7UER7tTJxjzbczNI2jqsw6nN1TVDrAIDt8/hT2x7m/M0FlWc88roBKuaMmbvzfNGWaL9abyQ==
dependencies:
"@sentry/browser" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
"@sentry/browser" "7.119.0"
"@sentry/core" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
hoist-non-react-statics "^3.3.2"
tslib "^1.9.3"
"@sentry/react@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.52.1.tgz#5f30919f4680493558c5233165b2092d2b59f6d1"
integrity sha512-RRH+GJE5TNg5QS86bSjSZuR2snpBTOO5/SU9t4BOqZMknzhMVTClGMm84hffJa9pMPMJPQ2fWQAbhrlD8RcF6w==
"@sentry/replay@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.119.0.tgz#50881079d013c77f87a994331d8bcad1d49e0960"
integrity sha512-BnNsYL+X5I4WCH6wOpY6HQtp4MgVt0NVlhLUsEyrvMUiTs0bPkDBrulsgZQBUKJsbOr3l9nHrFoNVB/0i6WNLA==
dependencies:
"@sentry/browser" "7.52.1"
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
hoist-non-react-statics "^3.3.2"
tslib "^1.9.3"
"@sentry-internal/tracing" "7.119.0"
"@sentry/core" "7.119.0"
"@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0"
"@sentry/replay@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.52.0.tgz#4d78e88282d2c1044ea4b648a68d1b22173e810d"
integrity sha512-RRPALjDST2s7MHiMcUJ7Wo4WW7EWfUDYSG0LuhMT8DNc+ZsxQoFsLYX/yz8b3f0IUSr7xKBXP+aPeIy3jDAS2g==
"@sentry/types@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.119.0.tgz#8b3d7a1405c362e75cd900d46089df4e70919d2a"
integrity sha512-27qQbutDBPKGbuJHROxhIWc1i0HJaGLA90tjMu11wt0E4UNxXRX+UQl4Twu68v4EV3CPvQcEpQfgsViYcXmq+w==
"@sentry/utils@7.119.0":
version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.119.0.tgz#debe29020f6ef3786a5bd855cf1b97116b7be826"
integrity sha512-ZwyXexWn2ZIe2bBoYnXJVPc2esCSbKpdc6+0WJa8eutXfHq3FRKg4ohkfCBpfxljQGEfP1+kfin945lA21Ka+A==
dependencies:
"@sentry/core" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
"@sentry/replay@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.52.1.tgz#272a0bcb79bb9ffce99b5dcaf864f18d729ce0da"
integrity sha512-A+RaUmpU9/yBHnU3ATemc6wAvobGno0yf5R6fZYkAFoo2FCR2YG6AXxkTazymIf8v2DnLGaSDORYDPdhQClU9A==
dependencies:
"@sentry/core" "7.52.1"
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
"@sentry/types@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.52.0.tgz#b7d5372f17355e3991cbe818ad567f3fe277cc6b"
integrity sha512-XnEWpS6P6UdP1FqbmeqhI96Iowqd2jM5R7zJ97txTdAd5NmdHHH0pODTR9NiQViA1WlsXDut7ZLxgPzC9vIcMA==
"@sentry/types@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.52.1.tgz#bcff6d0462d9b9b7b9ec31c0068fe02d44f25da2"
integrity sha512-OMbGBPrJsw0iEXwZ2bJUYxewI1IEAU2e1aQGc0O6QW5+6hhCh+8HO8Xl4EymqwejjztuwStkl6G1qhK+Q0/Row==
"@sentry/utils@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.52.0.tgz#cacc36d905036ba7084c14965e964fc44239d7f0"
integrity sha512-X1NHYuqW0qpZfP731YcVe+cn36wJdAeBHPYPIkXCl4o4GePCJfH/CM/+9V9cZykNjyLrs2Xy/TavSAHNCj8j7w==
dependencies:
"@sentry/types" "7.52.0"
tslib "^1.9.3"
"@sentry/utils@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.52.1.tgz#4a3e49b918f78dba4524c924286210259020cac5"
integrity sha512-MPt1Xu/jluulknW8CmZ2naJ53jEdtdwCBSo6fXJvOTI0SDqwIPbXDVrsnqLAhVJuIN7xbkj96nuY/VBR6S5sWg==
dependencies:
"@sentry/types" "7.52.1"
tslib "^1.9.3"
"@sentry/types" "7.119.0"
"@sideway/address@^4.1.3":
version "4.1.4"
@@ -12226,6 +12219,13 @@ expo-file-system@^17.0.1, expo-file-system@~17.0.1:
resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-17.0.1.tgz#b9f8af8c1c06ec71d96fd7a0d2567fa9e1c88f15"
integrity sha512-dYpnZJqTGj6HCYJyXAgpFkQWsiCH3HY1ek2cFZVHFoEc5tLz9gmdEgTF6nFHurvmvfmXqxi7a5CXyVm0aFYJBw==
expo-font@~12.0.10:
version "12.0.10"
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-12.0.10.tgz#62deaf1f46159d7839f01305f44079268781b1db"
integrity sha512-Q1i2NuYri3jy32zdnBaHHCya1wH1yMAsI+3CCmj9zlQzlhsS9Bdwcj2W3c5eU5FvH2hsNQy4O+O1NnM6o/pDaQ==
dependencies:
fontfaceobserver "^2.1.0"
expo-font@~12.0.5:
version "12.0.5"
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-12.0.5.tgz#3451c2bd3f98859b127a6484d3474a292889b93f"
@@ -19032,10 +19032,10 @@ react-native-get-random-values@~1.11.0:
dependencies:
fast-base64-decode "^1.0.0"
react-native-image-crop-picker@0.40.3:
version "0.40.3"
resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.40.3.tgz#a6b135cd1218a33ad126c1a148ec5a1bd01737ff"
integrity sha512-45PKcTnsnLS+E36YwoXutllQdRSOuOsMN0IRcAcwsFXOuAQIOtugXlAuGGL28JHKb/ATaSSPvqCSrdG65Jv3GA==
react-native-image-crop-picker@0.41.2:
version "0.41.2"
resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.41.2.tgz#824fa8fee8391fbb3e0b5ae2973221a2dff0cafb"
integrity sha512-GcDu/adXU/1y/MrxsbOfqcGRGWC2pTttt5VGy/jyRJ6GXfoC29fTQf8SG5kGtc5schSR6K+mKYO4uW6eJPljlQ==
react-native-ios-context-menu@^1.15.3:
version "1.15.3"
@@ -20067,19 +20067,6 @@ send@0.18.0, send@^0.18.0:
range-parser "~1.2.1"
statuses "2.0.1"
sentry-expo@~7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/sentry-expo/-/sentry-expo-7.0.1.tgz#025f0e90ab7f7cba1e00c892fabc027de21bc5bc"
integrity sha512-8vmOy4R+qM1peQA9EP8rDGUMBhgMU1D5FyuWY9kfNGatmWuvEmlZpVgaXoXaNPIhPgf2TMrvQIlbqLHtTkoeSA==
dependencies:
"@expo/spawn-async" "^1.7.0"
"@sentry/integrations" "7.52.1"
"@sentry/react" "7.52.1"
"@sentry/react-native" "5.5.0"
"@sentry/types" "7.52.1"
mkdirp "^1.0.4"
rimraf "^3.0.2"
serialize-error@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a"
@@ -21361,7 +21348,7 @@ tsconfig-paths@^3.14.2:
minimist "^1.2.6"
strip-bom "^3.0.0"
tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==