From f42d44112d268588f0d25f81715d01190b7047ea Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 20 Sep 2024 09:11:29 +0100 Subject: [PATCH 01/13] Add eslint rule to fix imports without the `#/` path alias (#5175) --- .eslintrc.js | 1 + eslint/index.js | 1 + eslint/use-exact-imports.js | 8 +++---- eslint/use-prefixed-imports.js | 39 ++++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 eslint/use-prefixed-imports.js diff --git a/.eslintrc.js b/.eslintrc.js index 2d5f2822ac..f6407fa6fa 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -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', { diff --git a/eslint/index.js b/eslint/index.js index cf5d41225d..6f75f1bc34 100644 --- a/eslint/index.js +++ b/eslint/index.js @@ -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'), }, } diff --git a/eslint/use-exact-imports.js b/eslint/use-exact-imports.js index 06723043fe..26e688563e 100644 --- a/eslint/use-exact-imports.js +++ b/eslint/use-exact-imports.js @@ -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: diff --git a/eslint/use-prefixed-imports.js b/eslint/use-prefixed-imports.js new file mode 100644 index 0000000000..141d536484 --- /dev/null +++ b/eslint/use-prefixed-imports.js @@ -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}'`) + }, + }) + } + }, + } + }, +} From cd88cbeab83169410fff3245505b53122dfe28aa Mon Sep 17 00:00:00 2001 From: futur Date: Fri, 20 Sep 2024 11:09:55 -0400 Subject: [PATCH 02/13] Add border to menu on web (#5439) --- src/components/Menu/index.web.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/Menu/index.web.tsx b/src/components/Menu/index.web.tsx index 6d2f5e9416..47c3c63adb 100644 --- a/src/components/Menu/index.web.tsx +++ b/src/components/Menu/index.web.tsx @@ -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} From fa6f6f9e473a0dd731ea95210fbd66e0b8c0c283 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 20 Sep 2024 10:50:33 -0500 Subject: [PATCH 03/13] Language fixes (#5384) * Add some comments * Decouple language settings * Normalize on read/write * Refactor * Support device locale on app startup * Cleanup, port to web * Clean up comments * Comment * Try not to mutate * Protect util handling, update test * Dedupe array values --- package.json | 1 + src/components/AppLanguageDropdown.tsx | 2 - src/components/AppLanguageDropdown.web.tsx | 2 - src/locale/deviceLocales.ts | 53 +++++++++++++++++++ src/locale/helpers.ts | 24 ++++++++- src/platform/detection.ts | 10 ---- src/state/persisted/index.ts | 10 ++-- src/state/persisted/index.web.ts | 13 +++-- src/state/persisted/schema.ts | 52 ++++++++++++++---- src/state/persisted/util.ts | 51 ++++++++++++++++++ src/state/session/__tests__/session-test.ts | 4 ++ .../ContentLanguagesSettings.tsx | 21 ++++---- .../lang-settings/PostLanguagesSettings.tsx | 23 ++++---- yarn.lock | 27 ++++++++++ 14 files changed, 240 insertions(+), 53 deletions(-) create mode 100644 src/locale/deviceLocales.ts create mode 100644 src/state/persisted/util.ts diff --git a/package.json b/package.json index 09985de02f..b2356eb75e 100644 --- a/package.json +++ b/package.json @@ -110,6 +110,7 @@ "await-lock": "^2.2.2", "babel-plugin-transform-remove-console": "^6.9.4", "base64-js": "^1.5.1", + "bcp-47": "^2.1.0", "bcp-47-match": "^2.0.3", "date-fns": "^2.30.0", "deprecated-react-native-prop-types": "^5.0.0", diff --git a/src/components/AppLanguageDropdown.tsx b/src/components/AppLanguageDropdown.tsx index 02cd0ce2d4..6170ab2e20 100644 --- a/src/components/AppLanguageDropdown.tsx +++ b/src/components/AppLanguageDropdown.tsx @@ -24,8 +24,6 @@ export function AppLanguageDropdown() { if (sanitizedLang !== value) { setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value)) } - setLangPrefs.setPrimaryLanguage(value) - setLangPrefs.setContentLanguage(value) // reset feeds to refetch content resetPostsFeedQueries(queryClient) diff --git a/src/components/AppLanguageDropdown.web.tsx b/src/components/AppLanguageDropdown.web.tsx index a106d99663..00a7b53011 100644 --- a/src/components/AppLanguageDropdown.web.tsx +++ b/src/components/AppLanguageDropdown.web.tsx @@ -27,8 +27,6 @@ export function AppLanguageDropdown() { if (sanitizedLang !== value) { setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value)) } - setLangPrefs.setPrimaryLanguage(value) - setLangPrefs.setContentLanguage(value) // reset feeds to refetch content resetPostsFeedQueries(queryClient) diff --git a/src/locale/deviceLocales.ts b/src/locale/deviceLocales.ts new file mode 100644 index 0000000000..9e19e372b8 --- /dev/null +++ b/src/locale/deviceLocales.ts @@ -0,0 +1,53 @@ +import {getLocales as defaultGetLocales, Locale} from 'expo-localization' + +import {dedupArray} from '#/lib/functions' + +type LocalWithLanguageCode = Locale & { + languageCode: string +} + +/** + * Normalized locales + * + * Handles legacy migration for Java devices. + * + * {@link https://github.com/bluesky-social/social-app/pull/4461} + * {@link https://xml.coverpages.org/iso639a.html} + */ +export function getLocales() { + const locales = defaultGetLocales?.() ?? [] + const output: LocalWithLanguageCode[] = [] + + for (const locale of locales) { + if (typeof locale.languageCode === 'string') { + if (locale.languageCode === 'in') { + // indonesian + locale.languageCode = 'id' + } + if (locale.languageCode === 'iw') { + // hebrew + locale.languageCode = 'he' + } + if (locale.languageCode === 'ji') { + // yiddish + locale.languageCode = 'yi' + } + + // @ts-ignore checked above + output.push(locale) + } + } + + return output +} + +export const deviceLocales = getLocales() + +/** + * BCP-47 language tag without region e.g. array of 2-char lang codes + * + * {@link https://docs.expo.dev/versions/latest/sdk/localization/#locale} + */ +export const deviceLanguageCodes = dedupArray( + deviceLocales.map(l => l.languageCode), +) diff --git a/src/locale/helpers.ts b/src/locale/helpers.ts index 3bae45214d..a7517eae9b 100644 --- a/src/locale/helpers.ts +++ b/src/locale/helpers.ts @@ -160,8 +160,13 @@ export function sanitizeAppLanguageSetting(appLanguage: string): AppLanguage { return AppLanguage.en } +/** + * Handles legacy migration for Java devices. + * + * {@link https://github.com/bluesky-social/social-app/pull/4461} + * {@link https://xml.coverpages.org/iso639a.html} + */ export function fixLegacyLanguageCode(code: string | null): string | null { - // handle some legacy code conversions, see https://xml.coverpages.org/iso639a.html if (code === 'in') { // indonesian return 'id' @@ -176,3 +181,20 @@ export function fixLegacyLanguageCode(code: string | null): string | null { } return code } + +/** + * Find the first language supported by our translation infra. Values should be + * in order of preference, and match the values of {@link AppLanguage}. + * + * If no match, returns `en`. + */ +export function findSupportedAppLanguage(languageTags: (string | undefined)[]) { + const supported = new Set(Object.values(AppLanguage)) + for (const tag of languageTags) { + if (!tag) continue + if (supported.has(tag as AppLanguage)) { + return tag + } + } + return AppLanguage.en +} diff --git a/src/platform/detection.ts b/src/platform/detection.ts index c62ae71aae..dc30c2fd33 100644 --- a/src/platform/detection.ts +++ b/src/platform/detection.ts @@ -1,8 +1,4 @@ import {Platform} from 'react-native' -import {getLocales} from 'expo-localization' - -import {fixLegacyLanguageCode} from '#/locale/helpers' -import {dedupArray} from 'lib/functions' export const isIOS = Platform.OS === 'ios' export const isAndroid = Platform.OS === 'android' @@ -15,9 +11,3 @@ export const isMobileWeb = // @ts-ignore we know window exists -prf global.window.matchMedia(isMobileWebMediaQuery)?.matches export const isIPhoneWeb = isWeb && /iPhone/.test(navigator.userAgent) - -export const deviceLocales = dedupArray( - getLocales?.() - .map?.(locale => fixLegacyLanguageCode(locale.languageCode)) - .filter(code => typeof code === 'string'), -) as string[] diff --git a/src/state/persisted/index.ts b/src/state/persisted/index.ts index 6f4beae2ca..51d757ad8b 100644 --- a/src/state/persisted/index.ts +++ b/src/state/persisted/index.ts @@ -8,6 +8,7 @@ import { tryStringify, } from '#/state/persisted/schema' import {PersistedApi} from './types' +import {normalizeData} from './util' export type {PersistedAccount, Schema} from '#/state/persisted/schema' export {defaults} from '#/state/persisted/schema' @@ -33,10 +34,10 @@ export async function write( key: K, value: Schema[K], ): Promise { - _state = { + _state = normalizeData({ ..._state, [key]: value, - } + }) await writeToStorage(_state) } write satisfies PersistedApi['write'] @@ -81,6 +82,9 @@ async function readFromStorage(): Promise { }) } if (rawData) { - return tryParse(rawData) + const parsed = tryParse(rawData) + if (parsed) { + return normalizeData(parsed) + } } } diff --git a/src/state/persisted/index.web.ts b/src/state/persisted/index.web.ts index 7521776bc0..4cfc87cdb1 100644 --- a/src/state/persisted/index.web.ts +++ b/src/state/persisted/index.web.ts @@ -9,6 +9,7 @@ import { tryStringify, } from '#/state/persisted/schema' import {PersistedApi} from './types' +import {normalizeData} from './util' export type {PersistedAccount, Schema} from '#/state/persisted/schema' export {defaults} from '#/state/persisted/schema' @@ -56,10 +57,10 @@ export async function write( } catch (e) { // Ignore and go through the normal path. } - _state = { + _state = normalizeData({ ..._state, [key]: value, - } + }) writeToStorage(_state) broadcast.postMessage({event: {type: UPDATE_EVENT, key}}) broadcast.postMessage({event: UPDATE_EVENT}) // Backcompat while upgrading @@ -140,9 +141,11 @@ function readFromStorage(): Schema | undefined { return lastResult } else { const result = tryParse(rawData) - lastRawData = rawData - lastResult = result - return result + if (result) { + lastRawData = rawData + lastResult = normalizeData(result) + return lastResult + } } } } diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 331a111a2e..8040179496 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -1,7 +1,8 @@ import {z} from 'zod' +import {deviceLanguageCodes, deviceLocales} from '#/locale/deviceLocales' +import {findSupportedAppLanguage} from '#/locale/helpers' import {logger} from '#/logger' -import {deviceLocales} from '#/platform/detection' import {PlatformInfo} from '../../../modules/expo-bluesky-swiss-army' const externalEmbedOptions = ['show', 'hide'] as const @@ -55,10 +56,39 @@ const schema = z.object({ lastEmailConfirm: z.string().optional(), }), languagePrefs: z.object({ - primaryLanguage: z.string(), // should move to server - contentLanguages: z.array(z.string()), // should move to server - postLanguage: z.string(), // should move to server + /** + * The target language for translating posts. + * + * BCP-47 2-letter language code without region. + */ + primaryLanguage: z.string(), + /** + * The languages the user can read, passed to feeds. + * + * BCP-47 2-letter language codes without region. + */ + contentLanguages: z.array(z.string()), + /** + * The language(s) the user is currently posting in, configured within the + * composer. Multiple languages are psearate by commas. + * + * BCP-47 2-letter language code without region. + */ + postLanguage: z.string(), + /** + * The user's post language history, used to pre-populate the post language + * selector in the composer. Within each value, multiple languages are + * separated by values. + * + * BCP-47 2-letter language codes without region. + */ postLanguageHistory: z.array(z.string()), + /** + * The language for UI translations in the app. + * + * BCP-47 2-letter language code with or without region, + * to match with {@link AppLanguage}. + */ appLanguage: z.string(), }), requireAltTextEnabled: z.boolean(), // should move to server @@ -108,13 +138,17 @@ export const defaults: Schema = { lastEmailConfirm: undefined, }, languagePrefs: { - primaryLanguage: deviceLocales[0] || 'en', - contentLanguages: deviceLocales || [], - postLanguage: deviceLocales[0] || 'en', - postLanguageHistory: (deviceLocales || []) + primaryLanguage: deviceLanguageCodes[0] || 'en', + contentLanguages: deviceLanguageCodes || [], + postLanguage: deviceLanguageCodes[0] || 'en', + postLanguageHistory: (deviceLanguageCodes || []) .concat(['en', 'ja', 'pt', 'de']) .slice(0, 6), - appLanguage: deviceLocales[0] || 'en', + // try full language tag first, then fallback to language code + appLanguage: findSupportedAppLanguage([ + deviceLocales.at(0)?.languageTag, + deviceLanguageCodes[0], + ]), }, requireAltTextEnabled: false, largeAltBadgeEnabled: false, diff --git a/src/state/persisted/util.ts b/src/state/persisted/util.ts new file mode 100644 index 0000000000..64a8bf9459 --- /dev/null +++ b/src/state/persisted/util.ts @@ -0,0 +1,51 @@ +import {parse} from 'bcp-47' + +import {dedupArray} from '#/lib/functions' +import {logger} from '#/logger' +import {Schema} from '#/state/persisted/schema' + +export function normalizeData(data: Schema) { + const next = {...data} + + /** + * Normalize language prefs to ensure that these values only contain 2-letter + * country codes without region. + */ + try { + const langPrefs = {...next.languagePrefs} + langPrefs.primaryLanguage = normalizeLanguageTagToTwoLetterCode( + langPrefs.primaryLanguage, + ) + langPrefs.contentLanguages = dedupArray( + langPrefs.contentLanguages.map(lang => + normalizeLanguageTagToTwoLetterCode(lang), + ), + ) + langPrefs.postLanguage = langPrefs.postLanguage + .split(',') + .map(lang => normalizeLanguageTagToTwoLetterCode(lang)) + .filter(Boolean) + .join(',') + langPrefs.postLanguageHistory = dedupArray( + langPrefs.postLanguageHistory.map(postLanguage => { + return postLanguage + .split(',') + .map(lang => normalizeLanguageTagToTwoLetterCode(lang)) + .filter(Boolean) + .join(',') + }), + ) + next.languagePrefs = langPrefs + } catch (e: any) { + logger.error(`persisted state: failed to normalize language prefs`, { + safeMessage: e.message, + }) + } + + return next +} + +export function normalizeLanguageTagToTwoLetterCode(lang: string) { + const result = parse(lang).language + return result ?? lang +} diff --git a/src/state/session/__tests__/session-test.ts b/src/state/session/__tests__/session-test.ts index 3e22c262cb..44c5cf9343 100644 --- a/src/state/session/__tests__/session-test.ts +++ b/src/state/session/__tests__/session-test.ts @@ -10,6 +10,10 @@ jest.mock('jwt-decode', () => ({ }, })) +jest.mock('expo-localization', () => ({ + getLocales: () => [], +})) + describe('session', () => { it('can log in and out', () => { let state = getInitialState([]) diff --git a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx index b8c125b65c..017b59db9e 100644 --- a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx @@ -1,19 +1,20 @@ import React from 'react' import {StyleSheet, View} from 'react-native' -import {ScrollView} from '../util' -import {Text} from '../../util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {deviceLocales} from 'platform/detection' -import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' -import {LanguageToggle} from './LanguageToggle' -import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' import {Trans} from '@lingui/macro' + +import {deviceLanguageCodes} from '#/locale/deviceLocales' import {useModalControls} from '#/state/modals' import { useLanguagePrefs, useLanguagePrefsApi, } from '#/state/preferences/languages' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' +import {Text} from '../../util/text/Text' +import {ScrollView} from '../util' +import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' +import {LanguageToggle} from './LanguageToggle' export const snapPoints = ['100%'] @@ -37,10 +38,10 @@ export function Component({}: {}) { langs.sort((a, b) => { const hasA = langPrefs.contentLanguages.includes(a.code2) || - deviceLocales.includes(a.code2) + deviceLanguageCodes.includes(a.code2) const hasB = langPrefs.contentLanguages.includes(b.code2) || - deviceLocales.includes(b.code2) + deviceLanguageCodes.includes(b.code2) if (hasA === hasB) return a.name.localeCompare(b.name) if (hasA) return -1 return 1 diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx index 05cfb81156..a20458702e 100644 --- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx @@ -1,20 +1,21 @@ import React from 'react' import {StyleSheet, View} from 'react-native' -import {ScrollView} from '../util' -import {Text} from '../../util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {deviceLocales} from 'platform/detection' -import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' -import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' -import {ToggleButton} from 'view/com/util/forms/ToggleButton' import {Trans} from '@lingui/macro' + +import {deviceLanguageCodes} from '#/locale/deviceLocales' import {useModalControls} from '#/state/modals' import { + hasPostLanguage, useLanguagePrefs, useLanguagePrefsApi, - hasPostLanguage, } from '#/state/preferences/languages' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {ToggleButton} from 'view/com/util/forms/ToggleButton' +import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' +import {Text} from '../../util/text/Text' +import {ScrollView} from '../util' +import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' export const snapPoints = ['100%'] @@ -38,10 +39,10 @@ export function Component() { langs.sort((a, b) => { const hasA = hasPostLanguage(langPrefs.postLanguage, a.code2) || - deviceLocales.includes(a.code2) + deviceLanguageCodes.includes(a.code2) const hasB = hasPostLanguage(langPrefs.postLanguage, b.code2) || - deviceLocales.includes(b.code2) + deviceLanguageCodes.includes(b.code2) if (hasA === hasB) return a.name.localeCompare(b.name) if (hasA) return -1 return 1 diff --git a/yarn.lock b/yarn.lock index 98479ba44c..380e7e4f16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9572,6 +9572,15 @@ bcp-47-match@^2.0.3: resolved "https://registry.yarnpkg.com/bcp-47-match/-/bcp-47-match-2.0.3.tgz#603226f6e5d3914a581408be33b28a53144b09d0" integrity sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ== +bcp-47@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/bcp-47/-/bcp-47-2.1.0.tgz#7e80734c3338fe8320894981dccf4968c3092df6" + integrity sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w== + dependencies: + is-alphabetical "^2.0.0" + is-alphanumerical "^2.0.0" + is-decimal "^2.0.0" + better-opn@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/better-opn/-/better-opn-3.0.2.tgz#f96f35deaaf8f34144a4102651babcf00d1d8817" @@ -13893,6 +13902,19 @@ ipaddr.js@^2.1.0: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== +is-alphabetical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" + integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== + +is-alphanumerical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" + integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== + dependencies: + is-alphabetical "^2.0.0" + is-decimal "^2.0.0" + is-arguments@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -13987,6 +14009,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" +is-decimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" + integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== + is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" From 27cceb96f33c86a06507a9ad3e631171474100b4 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 20 Sep 2024 11:28:25 -0500 Subject: [PATCH 04/13] Add explicit non-handling of detached quotes in embed (#5156) --- bskyembed/src/components/embed.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bskyembed/src/components/embed.tsx b/bskyembed/src/components/embed.tsx index 1ed107b592..82c3fd60a0 100644 --- a/bskyembed/src/components/embed.tsx +++ b/bskyembed/src/components/embed.tsx @@ -158,6 +158,12 @@ export function Embed({ return The quoted post is blocked. } + // Case 3.8: Detached quote post + if (AppBskyEmbedRecord.isViewDetached(record)) { + // Just don't show anything + return null + } + // Unknown embed type return null } From 0eed1cfec1b0caac35930529dfd9ac92bf38606f Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 20 Sep 2024 11:38:51 -0500 Subject: [PATCH 05/13] [Neue] Buttons (#5406) * Re-align button sizing (cherry picked from commit bcec243bb59dfe468313d98ba61f464d9750feec) * Use large, small, tiny (cherry picked from commit 1dc333c2993ab7f2e0ac750c0670dcec9a7069d0) * Tweaks --- src/components/Button.tsx | 148 ++++++++++++---- src/components/Prompt.tsx | 4 +- .../Wizard/WizardEditListDialog.tsx | 2 +- .../StarterPack/Wizard/WizardListCard.tsx | 2 +- src/components/dialogs/BirthDateSettings.tsx | 2 +- src/components/dialogs/Embed.tsx | 2 +- src/components/dialogs/EmbedConsent.tsx | 6 +- src/components/dialogs/GifSelect.ios.tsx | 2 +- src/components/dialogs/GifSelect.tsx | 2 +- src/components/dialogs/MutedWords.tsx | 2 +- .../dialogs/PostInteractionSettingsDialog.tsx | 2 +- src/components/dms/MessagesNUX.tsx | 2 +- src/components/forms/DateField/index.tsx | 2 +- .../intents/VerifyEmailIntentDialog.tsx | 4 +- .../moderation/LabelsOnMeDialog.tsx | 4 +- src/screens/Deactivated.tsx | 6 +- .../E2E/SharedPreferencesTesterScreen.tsx | 12 +- src/screens/Home/NoFeedsPinned.tsx | 4 +- src/screens/List/ListHiddenScreen.tsx | 8 +- src/screens/Login/ChooseAccountForm.tsx | 2 +- src/screens/Login/ForgotPasswordForm.tsx | 6 +- src/screens/Login/LoginForm.tsx | 6 +- src/screens/Login/PasswordUpdatedForm.tsx | 2 +- src/screens/Login/SetNewPasswordForm.tsx | 4 +- .../Messages/Conversation/ChatDisabled.tsx | 4 +- src/screens/Messages/List/index.tsx | 2 +- .../components/DeactivateAccountDialog.tsx | 2 +- src/screens/Signup/BackNextButtons.tsx | 6 +- .../StarterPack/StarterPackLandingScreen.tsx | 2 +- src/screens/StarterPack/StarterPackScreen.tsx | 4 +- src/screens/StarterPack/Wizard/index.tsx | 2 +- src/view/com/composer/GifAltText.tsx | 2 +- .../com/composer/threadgate/ThreadgateBtn.tsx | 2 +- .../com/composer/videos/SubtitleDialog.tsx | 4 +- .../composer/videos/SubtitleFilePicker.tsx | 2 +- src/view/com/notifications/FeedItem.tsx | 2 +- src/view/com/util/post-ctrls/RepostButton.tsx | 2 +- .../web-controls/ControlButton.tsx | 2 +- src/view/screens/Storybook/Buttons.tsx | 161 +++++++++++------- src/view/screens/Storybook/index.tsx | 2 + 40 files changed, 273 insertions(+), 164 deletions(-) diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 704aa9d987..8728b88c2c 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -14,7 +14,7 @@ import { } from 'react-native' import {LinearGradient} from 'expo-linear-gradient' -import {android, atoms as a, flatten, select, tokens, useTheme} from '#/alf' +import {atoms as a, flatten, select, tokens, useTheme, web} from '#/alf' import {Props as SVGIconProps} from '#/components/icons/common' import {Text} from '#/components/Typography' @@ -30,7 +30,7 @@ export type ButtonColor = | 'gradient_sunset' | 'gradient_nordic' | 'gradient_bonfire' -export type ButtonSize = 'tiny' | 'xsmall' | 'small' | 'medium' | 'large' +export type ButtonSize = 'tiny' | 'small' | 'large' export type ButtonShape = 'round' | 'square' | 'default' export type VariantProps = { /** @@ -343,39 +343,46 @@ export const Button = React.forwardRef( if (shape === 'default') { if (size === 'large') { - baseStyles.push( - {paddingVertical: 15}, - a.px_2xl, - a.rounded_sm, - a.gap_md, - ) - } else if (size === 'medium') { - baseStyles.push( - {paddingVertical: 12}, - a.px_2xl, - a.rounded_sm, - a.gap_md, - ) + baseStyles.push({ + paddingVertical: 13, + paddingHorizontal: 20, + borderRadius: 8, + gap: 8, + }) } else if (size === 'small') { - baseStyles.push({paddingVertical: 9}, a.px_lg, a.rounded_sm, a.gap_sm) - } else if (size === 'xsmall') { - baseStyles.push({paddingVertical: 6}, a.px_sm, a.rounded_sm, a.gap_sm) + baseStyles.push({ + paddingVertical: 8, + paddingHorizontal: 12, + borderRadius: 6, + gap: 6, + }) } else if (size === 'tiny') { - baseStyles.push({paddingVertical: 4}, a.px_sm, a.rounded_xs, a.gap_xs) + baseStyles.push({ + paddingVertical: 4, + paddingHorizontal: 8, + borderRadius: 4, + gap: 4, + }) } } else if (shape === 'round' || shape === 'square') { if (size === 'large') { if (shape === 'round') { - baseStyles.push({height: 54, width: 54}) + baseStyles.push({height: 46, width: 46}) } else { - baseStyles.push({height: 50, width: 50}) + baseStyles.push({height: 44, width: 44}) } } else if (size === 'small') { - baseStyles.push({height: 34, width: 34}) - } else if (size === 'xsmall') { - baseStyles.push({height: 28, width: 28}) + if (shape === 'round') { + baseStyles.push({height: 36, width: 36}) + } else { + baseStyles.push({height: 34, width: 34}) + } } else if (size === 'tiny') { - baseStyles.push({height: 20, width: 20}) + if (shape === 'round') { + baseStyles.push({height: 22, width: 22}) + } else { + baseStyles.push({height: 21, width: 21}) + } } if (shape === 'round') { @@ -619,11 +626,11 @@ export function useSharedButtonTextStyles() { } if (size === 'large') { - baseStyles.push(a.text_md, android({paddingBottom: 1})) + baseStyles.push(a.text_md, a.leading_tight, web({paddingTop: 1})) + } else if (size === 'small') { + baseStyles.push(a.text_sm, a.leading_tight, web({paddingTop: 1})) } else if (size === 'tiny') { - baseStyles.push(a.text_xs, android({paddingBottom: 1})) - } else { - baseStyles.push(a.text_sm, android({paddingBottom: 1})) + baseStyles.push(a.text_xs, a.leading_tight) } return StyleSheet.flatten(baseStyles) @@ -643,31 +650,98 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) { export function ButtonIcon({ icon: Comp, position, - size: iconSize, + size, }: { icon: React.ComponentType position?: 'left' | 'right' size?: SVGIconProps['size'] }) { - const {size, disabled} = useButtonContext() + const {size: buttonSize, disabled} = useButtonContext() const textStyles = useSharedButtonTextStyles() + const {iconSize, iconContainerSize} = React.useMemo(() => { + /** + * Pre-set icon sizes for different button sizes + */ + const iconSizeShorthand = + size ?? + (({ + large: 'sm', + small: 'xs', + tiny: 'xs', + }[buttonSize || 'small'] || 'sm') as Exclude< + SVGIconProps['size'], + undefined + >) + + /* + * Copied here from icons/common.tsx so we can tweak if we need to, but + * also so that we can calculate transforms. + */ + const iconSize = { + xs: 12, + sm: 16, + md: 20, + lg: 24, + xl: 28, + '2xl': 32, + }[iconSizeShorthand] + + /* + * Goal here is to match rendered text size so that different size icons + * don't increase button size + */ + const iconContainerSize = { + large: 18, + small: 16, + tiny: 13, + }[buttonSize || 'small'] + + return { + iconSize, + iconContainerSize, + } + }, [buttonSize, size]) return ( - + + + ) } diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx index 7836bbef95..8765cdee31 100644 --- a/src/components/Prompt.tsx +++ b/src/components/Prompt.tsx @@ -120,7 +120,7 @@ export function Cancel({ diff --git a/src/screens/Login/ForgotPasswordForm.tsx b/src/screens/Login/ForgotPasswordForm.tsx index 8588888b87..7acaae5101 100644 --- a/src/screens/Login/ForgotPasswordForm.tsx +++ b/src/screens/Login/ForgotPasswordForm.tsx @@ -129,7 +129,7 @@ export const ForgotPasswordForm = ({ label={_(msg`Back`)} variant="solid" color="secondary" - size="medium" + size="large" onPress={onPressBack}> Back @@ -143,7 +143,7 @@ export const ForgotPasswordForm = ({ label={_(msg`Next`)} variant="solid" color={'primary'} - size="medium" + size="large" onPress={onPressNext}> Next @@ -170,7 +170,7 @@ export const ForgotPasswordForm = ({ onPress={onEmailSent} label={_(msg`Go to next`)} accessibilityHint={_(msg`Navigates to the next screen`)} - size="medium" + size="large" variant="ghost" color="secondary"> diff --git a/src/screens/Login/LoginForm.tsx b/src/screens/Login/LoginForm.tsx index 9a01c04990..c2038b2879 100644 --- a/src/screens/Login/LoginForm.tsx +++ b/src/screens/Login/LoginForm.tsx @@ -285,7 +285,7 @@ export const LoginForm = ({ label={_(msg`Back`)} variant="solid" color="secondary" - size="medium" + size="large" onPress={onPressBack}> Back @@ -299,7 +299,7 @@ export const LoginForm = ({ accessibilityHint={_(msg`Retries login`)} variant="solid" color="secondary" - size="medium" + size="large" onPress={onPressRetryConnect}> Retry @@ -319,7 +319,7 @@ export const LoginForm = ({ accessibilityHint={_(msg`Navigates to the next screen`)} variant="solid" color="primary" - size="medium" + size="large" onPress={onPressNext}> Next diff --git a/src/screens/Login/PasswordUpdatedForm.tsx b/src/screens/Login/PasswordUpdatedForm.tsx index 5407f3f1e3..03e7d86696 100644 --- a/src/screens/Login/PasswordUpdatedForm.tsx +++ b/src/screens/Login/PasswordUpdatedForm.tsx @@ -39,7 +39,7 @@ export const PasswordUpdatedForm = ({ accessibilityHint={_(msg`Closes password update alert`)} variant="solid" color="primary" - size="medium"> + size="large"> Okay diff --git a/src/screens/Login/SetNewPasswordForm.tsx b/src/screens/Login/SetNewPasswordForm.tsx index 88f7ec5416..a6658621cc 100644 --- a/src/screens/Login/SetNewPasswordForm.tsx +++ b/src/screens/Login/SetNewPasswordForm.tsx @@ -160,7 +160,7 @@ export const SetNewPasswordForm = ({ label={_(msg`Back`)} variant="solid" color="secondary" - size="medium" + size="large" onPress={onPressBack}> Back @@ -174,7 +174,7 @@ export const SetNewPasswordForm = ({ label={_(msg`Next`)} variant="solid" color="primary" - size="medium" + size="large" onPress={onPressNext}> Next diff --git a/src/screens/Messages/Conversation/ChatDisabled.tsx b/src/screens/Messages/Conversation/ChatDisabled.tsx index 23acc41cde..c768d2504b 100644 --- a/src/screens/Messages/Conversation/ChatDisabled.tsx +++ b/src/screens/Messages/Conversation/ChatDisabled.tsx @@ -128,7 +128,7 @@ function DialogInner() { testID="backBtn" variant="solid" color="secondary" - size="medium" + size="large" onPress={onBack} label={_(msg`Back`)}> {_(msg`Back`)} @@ -137,7 +137,7 @@ function DialogInner() { testID="submitBtn" variant="solid" color="primary" - size="medium" + size="large" onPress={onSubmit} label={_(msg`Submit`)}> {_(msg`Submit`)} diff --git a/src/screens/Messages/List/index.tsx b/src/screens/Messages/List/index.tsx index e782395808..efd717f0b4 100644 --- a/src/screens/Messages/List/index.tsx +++ b/src/screens/Messages/List/index.tsx @@ -198,7 +198,7 @@ export function MessagesScreen({navigation, route}: Props) { - - - ), - )} - - */} - + - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/screens/Signup/StepInfo/index.tsx b/src/screens/Signup/StepInfo/index.tsx index e0a7912fd7..2cdb4b7224 100644 --- a/src/screens/Signup/StepInfo/index.tsx +++ b/src/screens/Signup/StepInfo/index.tsx @@ -3,9 +3,11 @@ import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import * as EmailValidator from 'email-validator' +import type tldts from 'tldts' import {logEvent} from '#/lib/statsig/statsig' import {logger} from '#/logger' +import {isEmailMaybeInvalid} from 'lib/strings/email' import {ScreenTransition} from '#/screens/Login/ScreenTransition' import {is13, is18, useSignupContext} from '#/screens/Signup/state' import {Policies} from '#/screens/Signup/StepInfo/Policies' @@ -46,13 +48,41 @@ export function StepInfo({ const inviteCodeValueRef = useRef(state.inviteCode) const emailValueRef = useRef(state.email) + const prevEmailValueRef = useRef(state.email) const passwordValueRef = useRef(state.password) - const onNextPress = React.useCallback(async () => { + const [hasWarnedEmail, setHasWarnedEmail] = React.useState(false) + + const tldtsRef = React.useRef() + React.useEffect(() => { + // @ts-expect-error - valid path + import('tldts/dist/index.cjs.min.js').then(tldts => { + tldtsRef.current = tldts + }) + }, []) + + const onNextPress = () => { const inviteCode = inviteCodeValueRef.current const email = emailValueRef.current + const emailChanged = prevEmailValueRef.current !== email const password = passwordValueRef.current + if (emailChanged && tldtsRef.current) { + if (isEmailMaybeInvalid(email, tldtsRef.current)) { + prevEmailValueRef.current = email + setHasWarnedEmail(true) + return dispatch({ + type: 'setError', + value: _( + msg`It looks like you may have entered your email address incorrectly. Are you sure it's right?`, + ), + }) + } + } else if (hasWarnedEmail) { + setHasWarnedEmail(false) + } + prevEmailValueRef.current = email + if (!is13(state.dateOfBirth)) { return } @@ -89,13 +119,7 @@ export function StepInfo({ logEvent('signup:nextPressed', { activeStep: state.activeStep, }) - }, [ - _, - dispatch, - state.activeStep, - state.dateOfBirth, - state.serviceDescription?.inviteCodeRequired, - ]) + } return ( @@ -148,6 +172,9 @@ export function StepInfo({ testID="emailInput" onChangeText={value => { emailValueRef.current = value.trim() + if (hasWarnedEmail) { + setHasWarnedEmail(false) + } }} label={_(msg`Enter your email address`)} defaultValue={state.email} @@ -208,6 +235,7 @@ export function StepInfo({ onBackPress={onPressBack} onNextPress={onNextPress} onRetryPress={refetchServer} + overrideNextText={hasWarnedEmail ? _(msg`It's correct`) : undefined} /> ) diff --git a/yarn.lock b/yarn.lock index 380e7e4f16..d199d5869f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21243,6 +21243,18 @@ tlds@^1.234.0: resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.242.0.tgz#da136a9c95b0efa1a4cd57dca8ef240c08ada4b7" integrity sha512-aP3dXawgmbfU94mA32CJGHmJUE1E58HCB1KmlKRhBNtqBL27mSQcAEmcaMaQ1Za9kIVvOdbxJD3U5ycDy7nJ3w== +tldts-core@^6.1.46: + version "6.1.46" + resolved "https://registry.yarnpkg.com/tldts-core/-/tldts-core-6.1.46.tgz#062d64981ee83f934f875c178a97e42bcd13bef7" + integrity sha512-zA3ai/j4aFcmbqTvTONkSBuWs0Q4X4tJxa0gV9sp6kDbq5dAhQDSg0WUkReEm0fBAKAGNj+wPKCCsR8MYOYmwA== + +tldts@^6.1.46: + version "6.1.46" + resolved "https://registry.yarnpkg.com/tldts/-/tldts-6.1.46.tgz#0c3c4157efe732caeddd06eee6da891b26bd8a75" + integrity sha512-fw81lXV2CijkNrZAZvee7wegs+EOlTyIuVl/z4q6OUzZHQ1jGL2xQzKXq9geYf/1tzo9LZQLrkcko2m8HLh+rg== + dependencies: + tldts-core "^6.1.46" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" From 4161e233200cc1d111faef47f05881e44ab4e731 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 20 Sep 2024 17:25:28 -0500 Subject: [PATCH 12/13] Fix spacing (#5444) --- src/view/com/notifications/FeedItem.tsx | 31 +++++++++++++------------ 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index 53152b50d4..bcf5db03de 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -22,21 +22,21 @@ import {useLingui} from '@lingui/react' import {useNavigation} from '@react-navigation/native' import {useQueryClient} from '@tanstack/react-query' +import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue' +import {usePalette} from '#/lib/hooks/usePalette' +import {makeProfileLink} from '#/lib/routes/links' +import {NavigationProp} from '#/lib/routes/types' +import {forceLTR} from '#/lib/strings/bidi' +import {sanitizeDisplayName} from '#/lib/strings/display-names' +import {sanitizeHandle} from '#/lib/strings/handles' +import {niceDate} from '#/lib/strings/time' +import {colors, s} from '#/lib/styles' import {logger} from '#/logger' +import {isWeb} from '#/platform/detection' +import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const' import {FeedNotification} from '#/state/queries/notifications/feed' -import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' -import {usePalette} from 'lib/hooks/usePalette' -import {makeProfileLink} from 'lib/routes/links' -import {NavigationProp} from 'lib/routes/types' -import {forceLTR} from 'lib/strings/bidi' -import {sanitizeDisplayName} from 'lib/strings/display-names' -import {sanitizeHandle} from 'lib/strings/handles' -import {niceDate} from 'lib/strings/time' -import {colors, s} from 'lib/styles' -import {isWeb} from 'platform/detection' -import {DM_SERVICE_HEADERS} from 'state/queries/messages/const' -import {precacheProfile} from 'state/queries/profile' -import {useAgent} from 'state/session' +import {precacheProfile} from '#/state/queries/profile' +import {useAgent} from '#/state/session' import {atoms as a, useTheme} from '#/alf' import {Button, ButtonText} from '#/components/Button' import { @@ -315,8 +315,9 @@ let FeedItem = ({ /> {authors.length > 1 ? ( <> - - and + + {' '} + and{' '} {plural(authors.length - 1, { From 7e2456b906563464c8e43867e62f07df9109bc2b Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 20 Sep 2024 17:29:58 -0500 Subject: [PATCH 13/13] [Neue] Font weights (#5442) * Align all font weights * Only load necessary fonts * Also comment out from hook --- bskyweb/templates/base.html | 12 ++++++ src/alf/atoms.ts | 9 ++-- src/alf/fonts.ts | 12 +++--- src/alf/tokens.ts | 13 ++++-- src/components/LabelingServiceCard/index.tsx | 2 +- src/components/MediaPreview.tsx | 2 +- src/components/Pills.tsx | 2 +- src/components/ProgressGuide/List.tsx | 2 +- src/components/ProgressGuide/Task.tsx | 4 +- src/components/ProgressGuide/Toast.tsx | 2 +- .../ReportDialog/SelectLabelerView.tsx | 3 +- .../dialogs/PostInteractionSettingsDialog.tsx | 4 +- .../dialogs/nuxs/NeueTypography.tsx | 2 +- .../dialogs/nuxs/TenMillion/index.tsx | 21 ++++------ src/components/moderation/ContentHider.tsx | 4 +- src/components/moderation/LabelPreference.tsx | 3 +- src/components/moderation/ScreenHider.tsx | 14 ++----- src/lib/styles.ts | 9 ++-- src/lib/themes.ts | 38 ++++++++--------- src/screens/Moderation/index.tsx | 2 +- src/screens/Profile/Header/DisplayName.tsx | 6 +-- src/screens/Signup/index.tsx | 6 +-- .../StarterPack/StarterPackLandingScreen.tsx | 35 ++++++---------- src/view/com/auth/SplashScreen.tsx | 5 +-- src/view/com/auth/SplashScreen.web.tsx | 10 ++--- src/view/com/composer/photos/Gallery.tsx | 14 +++---- src/view/com/modals/CreateOrEditList.tsx | 20 ++++----- src/view/com/modals/EditImage.tsx | 20 ++++----- src/view/com/modals/EditProfile.tsx | 22 +++++----- src/view/com/modals/InAppBrowserConsent.tsx | 15 ++++--- src/view/com/modals/UserAddRemoveLists.tsx | 12 +++--- .../ContentLanguagesSettings.tsx | 6 +-- .../lang-settings/PostLanguagesSettings.tsx | 8 ++-- src/view/com/notifications/FeedItem.tsx | 2 +- src/view/com/profile/ProfileSubpageHeader.tsx | 16 +++---- src/view/com/util/Html.tsx | 13 +++--- src/view/com/util/ViewHeader.tsx | 12 +++--- src/view/com/util/forms/Button.tsx | 29 ++++++------- src/view/com/util/forms/DropdownButton.tsx | 12 +++--- .../com/util/forms/NativeDropdown.web.tsx | 8 ++-- src/view/com/util/forms/RadioButton.tsx | 22 +++++----- src/view/com/util/forms/ToggleButton.tsx | 27 ++++++------ src/view/com/util/post-embeds/GifEmbed.tsx | 6 +-- src/view/com/util/post-embeds/index.tsx | 6 +-- src/view/screens/AccessibilitySettings.tsx | 2 +- src/view/screens/LanguageSettings.tsx | 30 ++++++------- src/view/screens/Lists.tsx | 18 ++++---- src/view/screens/ModerationModlists.tsx | 29 ++++++------- .../screens/PreferencesExternalEmbeds.tsx | 18 ++++---- src/view/screens/PreferencesFollowingFeed.tsx | 2 +- src/view/screens/PreferencesThreads.tsx | 2 +- src/view/screens/Search/Search.tsx | 18 ++++---- src/view/screens/Settings/index.tsx | 42 +++++++++---------- src/view/shell/Drawer.tsx | 26 ++++++------ src/view/shell/bottom-bar/BottomBarStyles.tsx | 4 +- src/view/shell/desktop/Feeds.tsx | 10 ++--- src/view/shell/desktop/LeftNav.tsx | 24 +++++------ web/index.html | 12 ++++++ 58 files changed, 362 insertions(+), 367 deletions(-) diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html index b0c3c2195e..609c17c7ce 100644 --- a/bskyweb/templates/base.html +++ b/bskyweb/templates/base.html @@ -15,16 +15,22 @@ + + +