From 4e8d86db317864257f6416cd867d7bb07baca6d0 Mon Sep 17 00:00:00 2001
From: Mary <148872143+mary-ext@users.noreply.github.com>
Date: Mon, 23 Sep 2024 21:38:04 +0700
Subject: [PATCH 1/5] Let Expo/Webpack handle CSS assets (#3942)
* chore: handle built css assets
* chore: let prettier handle css code
* refactor: let webpack build css assets
* chore: prettier on bskyembed
* chore: touch empty.txt on css directory
* chore: do the same to the workflow
---
.github/workflows/golang-test-lint.yml | 4 +-
.prettierignore | 4 +-
Dockerfile.embedr | 1 +
bskyembed/src/index.css | 2 +-
bskyweb/.gitignore | 4 +
bskyweb/static/css/.gitkeep | 0
bskyweb/templates/base.html | 381 -----------------------
package.json | 2 +-
scripts/post-web-build.js | 25 +-
src/App.web.tsx | 1 +
src/style.css | 403 +++++++++++++++++++++++++
web/index.html | 382 -----------------------
12 files changed, 440 insertions(+), 769 deletions(-)
create mode 100644 bskyweb/static/css/.gitkeep
create mode 100644 src/style.css
diff --git a/.github/workflows/golang-test-lint.yml b/.github/workflows/golang-test-lint.yml
index 36e28841d5..c8124dbade 100644
--- a/.github/workflows/golang-test-lint.yml
+++ b/.github/workflows/golang-test-lint.yml
@@ -21,7 +21,7 @@ jobs:
with:
go-version: '1.22'
- name: Dummy Static Files
- run: touch bskyweb/static/js/blah.js && touch bskyweb/static/media/blah.txt
+ run: touch bskyweb/static/js/blah.js && touch bskyweb/static/css/blah.txt && touch bskyweb/static/media/blah.txt
- name: Check
run: cd bskyweb/ && make check
- name: Build (binary)
@@ -38,6 +38,6 @@ jobs:
with:
go-version: '1.22'
- name: Dummy Static Files
- run: touch bskyweb/static/js/blah.js && touch bskyweb/static/media/blah.txt
+ run: touch bskyweb/static/js/blah.js && touch bskyweb/static/css/blah.txt && touch bskyweb/static/media/blah.txt
- name: Lint
run: cd bskyweb/ && make lint
diff --git a/.prettierignore b/.prettierignore
index 641a1b8bfc..8ccbae2148 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,4 +1,4 @@
-# Ignore everything except JS-ey code.
+# Ignore everything except JS-ey or CSS code.
# Based on https://stackoverflow.com/a/70715829/458193
*
!**/*.js
@@ -7,6 +7,8 @@
!**/*.tsx
!*/
+!**/*.css
+
# More specific ignores go below.
.expo
android
diff --git a/Dockerfile.embedr b/Dockerfile.embedr
index 9ff04aa5c7..663cbcfc51 100644
--- a/Dockerfile.embedr
+++ b/Dockerfile.embedr
@@ -40,6 +40,7 @@ RUN find ./bskyweb/embedr-static && find ./bskyweb/embedr-templates && find ./bs
# hack around issue with empty directory and go:embed
RUN touch bskyweb/static/js/empty.txt
+RUN touch bskyweb/static/css/empty.txt
RUN touch bskyweb/static/media/empty.txt
#
diff --git a/bskyembed/src/index.css b/bskyembed/src/index.css
index 23457ec28d..22b2b8be5c 100644
--- a/bskyembed/src/index.css
+++ b/bskyembed/src/index.css
@@ -4,4 +4,4 @@
.break-word {
word-break: break-word;
-}
\ No newline at end of file
+}
diff --git a/bskyweb/.gitignore b/bskyweb/.gitignore
index 05b3ad7ab5..a63a381f94 100644
--- a/bskyweb/.gitignore
+++ b/bskyweb/.gitignore
@@ -10,6 +10,10 @@ static/js/*.js
static/js/*.map
static/js/*.js.LICENSE.txt
static/js/empty.txt
+static/css/*.css
+static/css/*.map
+static/css/*.css.LICENSE.txt
+static/css/empty.txt
static/media/*.png
static/media/empty.txt
templates/scripts.html
diff --git a/bskyweb/static/css/.gitkeep b/bskyweb/static/css/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html
index 609c17c7ce..eaa31aa4a3 100644
--- a/bskyweb/templates/base.html
+++ b/bskyweb/templates/base.html
@@ -32,387 +32,6 @@
-->
-
{% include "scripts.html" %}
diff --git a/package.json b/package.json
index 05b5f086db..e3aff1fe0c 100644
--- a/package.json
+++ b/package.json
@@ -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/* ./bskyweb/static/media/",
+ "build-web": "expo export:web && node ./scripts/post-web-build.js",
"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",
diff --git a/scripts/post-web-build.js b/scripts/post-web-build.js
index baaa7cb8b7..7bbee38554 100644
--- a/scripts/post-web-build.js
+++ b/scripts/post-web-build.js
@@ -20,7 +20,30 @@ console.log(`Writing ${templateFile}`)
const outputFile = entrypoints
.map(name => {
const file = path.basename(name)
- return ``
+ const ext = path.extname(file)
+
+ if (ext === '.js') {
+ return ``
+ }
+ if (ext === '.css') {
+ return ``
+ }
+
+ return ''
})
.join('\n')
fs.writeFileSync(templateFile, outputFile)
+
+function copyFiles(sourceDir, targetDir) {
+ const files = fs.readdirSync(path.join(projectRoot, sourceDir))
+ files.forEach(file => {
+ const sourcePath = path.join(projectRoot, sourceDir, file)
+ const targetPath = path.join(projectRoot, targetDir, file)
+ fs.copyFileSync(sourcePath, targetPath)
+ console.log(`Copied ${sourcePath} to ${targetPath}`)
+ })
+}
+
+copyFiles('web-build/static/js', 'bskyweb/static/js')
+copyFiles('web-build/static/css', 'bskyweb/static/css')
+copyFiles('web-build/static/media', 'bskyweb/static/media')
diff --git a/src/App.web.tsx b/src/App.web.tsx
index c81ed10d33..7d98737a3b 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -1,5 +1,6 @@
import 'lib/sentry' // must be near top
import 'view/icons'
+import './style.css'
import React, {useEffect, useState} from 'react'
import {KeyboardProvider} from 'react-native-keyboard-controller'
diff --git a/src/style.css b/src/style.css
new file mode 100644
index 0000000000..29e9770e32
--- /dev/null
+++ b/src/style.css
@@ -0,0 +1,403 @@
+@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
+ */
+html,
+body,
+#root {
+ width: 100%;
+ /* To smooth any scrolling behavior */
+ -webkit-overflow-scrolling: touch;
+ margin: 0px;
+ padding: 0px;
+ /* Allows content to fill the viewport and go beyond the bottom */
+ min-height: 100%;
+}
+#root {
+ flex-shrink: 0;
+ flex-basis: auto;
+ flex-grow: 1;
+ display: flex;
+ flex: 1;
+}
+
+html {
+ /* Prevent text size change on orientation change https://gist.github.com/tfausak/2222823#file-ios-8-web-app-html-L138 */
+ -webkit-text-size-adjust: 100%;
+ height: calc(100% + env(safe-area-inset-top));
+ scrollbar-gutter: stable both-edges;
+}
+html,
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
+ 'Liberation Sans', Helvetica, Arial, sans-serif;
+}
+
+#preload {
+ width: 100px;
+ position: fixed;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+}
+
+/* Buttons and inputs have a font set by UA, so we'll have to reset that */
+button,
+input,
+textarea {
+ font: inherit;
+ line-height: inherit;
+}
+
+/* Color theming */
+/* Default will always be white */
+:root {
+ --text: black;
+ --background: white;
+ --backgroundLight: hsl(211, 20%, 95%);
+}
+/* This gives us a black background when system is dark and we have not loaded the theme/color scheme values in JS */
+@media (prefers-color-scheme: dark) {
+ :root {
+ --text: white;
+ --background: black;
+ --backgroundLight: hsl(211, 20%, 20%);
+ color-scheme: dark;
+ }
+}
+
+/* Overwrite those preferences with the selected theme */
+html.theme--light {
+ --text: black;
+ --background: white;
+ --backgroundLight: hsl(211, 20%, 95%);
+}
+html.theme--dark {
+ --text: white;
+ --background: black;
+ --backgroundLight: hsl(211, 20%, 20%);
+ color-scheme: dark;
+}
+html.theme--dim {
+ --text: white;
+ --background: hsl(211, 20%, 4%);
+ --backgroundLight: hsl(211, 20%, 10%);
+ color-scheme: dark;
+}
+
+/* Remove autofill styles on Webkit */
+input:autofill,
+input:-webkit-autofill,
+input:-webkit-autofill:hover,
+input:-webkit-autofill:focus,
+input:-webkit-autofill:active {
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: var(--text);
+ transition: background-color 5000s ease-in-out 0s;
+ box-shadow: inset 0 0 20px 20px var(--background);
+ background: var(--background);
+ color: var(--text);
+}
+/* Force left-align date/time inputs on iOS mobile */
+input::-webkit-date-and-time-value {
+ text-align: left;
+}
+
+body {
+ display: flex;
+ /* Allows you to scroll below the viewport; default value is visible */
+ overflow-y: auto;
+ overscroll-behavior-y: none;
+ text-rendering: optimizeLegibility;
+ background-color: var(--background);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -ms-overflow-style: scrollbar;
+ font-synthesis-weight: none;
+}
+
+/* Remove default link styling */
+a {
+ color: inherit;
+}
+a[role='link']:hover {
+ text-decoration: underline;
+}
+a[role='link'][data-no-underline='1']:hover {
+ text-decoration: none;
+}
+
+/* Styling hacks */
+*[data-word-wrap] {
+ word-break: break-word;
+}
+*[data-stable-gutters] {
+ scrollbar-gutter: stable both-edges;
+}
+
+/* ProseMirror */
+.ProseMirror {
+ font: 18px -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
+ 'Liberation Sans', Helvetica, Arial, sans-serif;
+ min-height: 140px;
+}
+.ProseMirror-dark {
+ color: white;
+}
+.ProseMirror p {
+ margin: 0;
+}
+.ProseMirror p.is-editor-empty:first-child::before {
+ color: #8d8e96;
+ content: attr(data-placeholder);
+ float: left;
+ height: 0;
+ pointer-events: none;
+}
+.ProseMirror .mention {
+ color: #0085ff;
+}
+.ProseMirror a,
+.ProseMirror .autolink {
+ color: #0085ff;
+}
+/* OLLIE: TODO -- this is not accessible */
+/* Remove focus state on inputs */
+.ProseMirror-focused {
+ outline: 0;
+}
+textarea:focus,
+input:focus {
+ outline: 0;
+}
+.tippy-content .items {
+ width: fit-content;
+}
+
+/* Tooltips */
+[data-tooltip] {
+ position: relative;
+ z-index: 10;
+}
+[data-tooltip]::after {
+ content: attr(data-tooltip);
+ display: none;
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ transform: translateY(100%) translateY(8px) translateX(-50%);
+ padding: 4px 10px;
+ border-radius: 10px;
+ background: var(--backgroundLight);
+ color: var(--text);
+ text-align: center;
+ white-space: nowrap;
+ font-size: 12px;
+ z-index: 10;
+}
+[data-tooltip]::before {
+ content: '';
+ display: none;
+ position: absolute;
+ border-bottom: 6px solid var(--backgroundLight);
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ bottom: 0;
+ left: 50%;
+ transform: translateY(100%) translateY(2px) translateX(-50%);
+ z-index: 10;
+}
+[data-tooltip]:hover::after,
+[data-tooltip]:hover::before {
+ display: block;
+}
+
+/* NativeDropdown component */
+.radix-dropdown-item:focus,
+.nativeDropdown-item:focus {
+ outline: none;
+}
+
+/* Spinner component */
+@keyframes rotate {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+.rotate-500ms {
+ position: absolute;
+ inset: 0;
+ animation: rotate 500ms linear infinite;
+}
+
+@keyframes avatarHoverFadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes avatarHoverFadeOut {
+ from {
+ opacity: 1;
+ }
+ to {
+ opacity: 0;
+ }
+}
+
+.force-no-clicks > *,
+.force-no-clicks * {
+ pointer-events: none !important;
+}
+
+input[type='range'][orient='vertical'] {
+ writing-mode: vertical-lr;
+ direction: rtl;
+ appearance: slider-vertical;
+ width: 16px;
+ vertical-align: bottom;
+ -webkit-appearance: none;
+ appearance: none;
+ background: transparent;
+ cursor: pointer;
+}
+
+input[type='range'][orient='vertical']::-webkit-slider-runnable-track {
+ background: white;
+ height: 100%;
+ width: 4px;
+ border-radius: 4px;
+}
+
+input[type='range'][orient='vertical']::-moz-range-track {
+ background: white;
+ height: 100%;
+ width: 4px;
+ border-radius: 4px;
+}
+
+input[type='range']::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ border-radius: 50%;
+ background-color: white;
+ height: 16px;
+ width: 16px;
+ margin-left: -6px;
+}
+
+input[type='range'][orient='vertical']::-moz-range-thumb {
+ border: none;
+ border-radius: 50%;
+ background-color: white;
+ height: 16px;
+ width: 16px;
+ margin-left: -6px;
+}
diff --git a/web/index.html b/web/index.html
index 3a132d25b8..512178327f 100644
--- a/web/index.html
+++ b/web/index.html
@@ -36,388 +36,6 @@
-->
-
-
From 87d601e68d38b1337639b0d89cbd074147fa6236 Mon Sep 17 00:00:00 2001
From: "whey.party" <132627503+rimar1337@users.noreply.github.com>
Date: Mon, 23 Sep 2024 22:24:36 +0700
Subject: [PATCH 2/5] changed white (gray_0) text to offwhite (gray_25) (#5453)
---
src/alf/themes.ts | 2 +-
src/lib/themes.ts | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/alf/themes.ts b/src/alf/themes.ts
index f5d2247f9f..9f7ec5c673 100644
--- a/src/alf/themes.ts
+++ b/src/alf/themes.ts
@@ -183,7 +183,7 @@ export function createThemes({
} as const
const darkPalette: Palette = {
- white: color.gray_0,
+ white: color.gray_25,
black: color.trueBlack,
contrast_25: color.gray_975,
diff --git a/src/lib/themes.ts b/src/lib/themes.ts
index 5030799932..eb11872fa3 100644
--- a/src/lib/themes.ts
+++ b/src/lib/themes.ts
@@ -325,11 +325,11 @@ export const darkTheme: Theme = {
textInverted: colors.green2,
},
inverted: {
- background: lightPalette.white,
+ background: darkPalette.white,
backgroundLight: lightPalette.contrast_50,
text: lightPalette.black,
textLight: lightPalette.contrast_700,
- textInverted: lightPalette.white,
+ textInverted: darkPalette.white,
link: lightPalette.primary_500,
border: lightPalette.contrast_100,
borderDark: lightPalette.contrast_200,
From 5e333d4dfcc434f76fd54def2f965f54e112257b Mon Sep 17 00:00:00 2001
From: Eric Bailey
Date: Mon, 23 Sep 2024 10:35:07 -0500
Subject: [PATCH 3/5] Resolve source files for fonts, remove hack (#5454)
* Resolve source files for fonts, remove hack
* Prettier
* Prettier, add to hook
---------
Co-authored-by: Dan Abramov
---
package.json | 4 +++-
src/alf/fonts.ts | 35 -----------------------------------
src/style.css | 28 ++++++++++++----------------
3 files changed, 15 insertions(+), 52 deletions(-)
diff --git a/package.json b/package.json
index e3aff1fe0c..bb9706c39a 100644
--- a/package.json
+++ b/package.json
@@ -338,7 +338,9 @@
},
"lint-staged": {
"*{.js,.jsx,.ts,.tsx}": [
- "eslint --cache --fix",
+ "eslint --cache --fix"
+ ],
+ "*{.js,.jsx,.ts,.tsx,.css}": [
"prettier --cache --write --ignore-unknown"
]
}
diff --git a/src/alf/fonts.ts b/src/alf/fonts.ts
index 08cfd9f42d..b11ce939f8 100644
--- a/src/alf/fonts.ts
+++ b/src/alf/fonts.ts
@@ -1,5 +1,3 @@
-import {useFonts as defaultUseFonts} from 'expo-font'
-
import {isWeb} from '#/platform/detection'
import {Device, device} from '#/storage'
@@ -34,39 +32,6 @@ 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.
*/
diff --git a/src/style.css b/src/style.css
index 29e9770e32..ebb0471584 100644
--- a/src/style.css
+++ b/src/style.css
@@ -1,7 +1,7 @@
@font-face {
font-family: 'Inter-Regular';
src: local('Inter-Regular'),
- url(/static/media/Inter-Regular.1f5ed03b6dd9fd1f9982.otf) format('font/otf');
+ url(/assets/fonts/inter/Inter-Regular.otf) format('font/otf');
font-weight: 400;
font-style: normal;
font-display: swap;
@@ -9,7 +9,7 @@
@font-face {
font-family: 'Inter-Italic';
src: local('Inter-Italic'),
- url(/static/media/Inter-Italic.95778eb0c75dc956257e.otf) format('font/otf');
+ url(/assets/fonts/inter/Inter-Italic.otf) format('font/otf');
font-weight: 400;
font-style: italic;
font-display: swap;
@@ -17,14 +17,14 @@
/*
@font-face {
font-family: "Inter-Medium";
- src: local("Inter-Medium"), url(/static/media/Inter-Medium.296aa2d65964269836b3.otf) format("font/otf");
+ src: local("Inter-Medium"), url(/assets/fonts/inter/Inter-Medium.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");
+ src: local("Inter-MediumItalic"), url(/assets/fonts/inter/Inter-MediumItalic.otf) format("font/otf");
font-weight: 500;
font-style: italic;
font-display: swap;
@@ -33,8 +33,7 @@
@font-face {
font-family: 'Inter-SemiBold';
src: local('Inter-SemiBold'),
- url(/static/media/Inter-SemiBold.2277990330981b8409bb.otf)
- format('font/otf');
+ url(/assets/fonts/inter/Inter-SemiBold.otf) format('font/otf');
font-weight: 600;
font-style: normal;
font-display: swap;
@@ -42,8 +41,7 @@
@font-face {
font-family: 'Inter-SemiBoldItalic';
src: local('Inter-SemiBoldItalic'),
- url(/static/media/Inter-SemiBoldItalic.f62fea3df3a521d6c8a7.otf)
- format('font/otf');
+ url(/assets/fonts/inter/Inter-SemiBoldItalic.otf) format('font/otf');
font-weight: 600;
font-style: italic;
font-display: swap;
@@ -51,14 +49,14 @@
/*
@font-face {
font-family: "Inter-Bold";
- src: local("Inter-Bold"), url(/static/media/Inter-Bold.8d330503e1d034ad68de.otf) format("font/otf");
+ src: local("Inter-Bold"), url(/assets/fonts/inter/Inter-Bold.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");
+ src: local("Inter-BoldItalic"), url(/assets/fonts/inter/Inter-BoldItalic.otf) format("font/otf");
font-weight: 700;
font-style: italic;
font-display: swap;
@@ -67,8 +65,7 @@
@font-face {
font-family: 'Inter-ExtraBold';
src: local('Inter-ExtraBold'),
- url(/static/media/Inter-ExtraBold.ff2581a193bf6b7e0b06.otf)
- format('font/otf');
+ url(/assets/fonts/inter/Inter-ExtraBold.otf) format('font/otf');
font-weight: 800;
font-style: normal;
font-display: swap;
@@ -76,8 +73,7 @@
@font-face {
font-family: 'Inter-ExtraBoldItalic';
src: local('Inter-ExtraBoldItalic'),
- url(/static/media/Inter-ExtraBoldItalic.0e50b40728d24d40fdf4.otf)
- format('font/otf');
+ url(/assets/fonts/inter/Inter-ExtraBoldItalic.otf) format('font/otf');
font-weight: 800;
font-style: italic;
font-display: swap;
@@ -85,14 +81,14 @@
/*
@font-face {
font-family: "Inter-Black";
- src: local("Inter-Black"), url(/static/media/Inter-Black.66e9a87f1c921e844ed4.otf) format("font/otf");
+ src: local("Inter-Black"), url(/assets/fonts/inter/Inter-Black.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");
+ src: local("Inter-BlackItalic"), url(/assets/fonts/inter/Inter-BlackItalic.otf) format("font/otf");
font-weight: 900;
font-style: italic;
font-display: swap;
From 443f3a64069f081764c2f49578108a9570e8e834 Mon Sep 17 00:00:00 2001
From: Samuel Newman
Date: Mon, 23 Sep 2024 16:35:16 +0100
Subject: [PATCH 4/5] Use pressable for video controls (#5452)
* use pressable for video controls
* add `as any` to preexisiting bad type
* stop mutating prop
---
src/view/com/pager/TabBar.tsx | 6 +--
src/view/com/util/PressableWithHover.tsx | 46 +++++++++----------
.../web-controls/ControlButton.tsx | 22 +++++----
.../web-controls/VideoControls.tsx | 11 +++--
4 files changed, 43 insertions(+), 42 deletions(-)
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx
index 59bb77e367..d36d794b72 100644
--- a/src/view/com/pager/TabBar.tsx
+++ b/src/view/com/pager/TabBar.tsx
@@ -1,9 +1,9 @@
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {LayoutChangeEvent, ScrollView, StyleSheet, View} from 'react-native'
+import {usePalette} from '#/lib/hooks/usePalette'
+import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {isNative} from '#/platform/detection'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {PressableWithHover} from '../util/PressableWithHover'
import {Text} from '../util/text/Text'
import {DraggableScrollView} from './DraggableScrollView'
@@ -131,7 +131,7 @@ export function TabBar({
(itemRefs.current[i] = node)}
+ ref={node => (itemRefs.current[i] = node as any)}
onLayout={e => onItemLayout(e, i)}
style={styles.item}
hoverStyle={pal.viewLight}
diff --git a/src/view/com/util/PressableWithHover.tsx b/src/view/com/util/PressableWithHover.tsx
index 77276f1843..48659e2295 100644
--- a/src/view/com/util/PressableWithHover.tsx
+++ b/src/view/com/util/PressableWithHover.tsx
@@ -1,39 +1,35 @@
-import React, {
- useState,
- useCallback,
- PropsWithChildren,
- forwardRef,
- Ref,
-} from 'react'
+import React, {forwardRef, PropsWithChildren} from 'react'
import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native'
-import {addStyle} from 'lib/styles'
+import {View} from 'react-native'
+
+import {addStyle} from '#/lib/styles'
+import {useInteractionState} from '#/components/hooks/useInteractionState'
interface PressableWithHover extends PressableProps {
hoverStyle: StyleProp
}
-export const PressableWithHover = forwardRef(function PressableWithHoverImpl(
- {
- children,
- style,
- hoverStyle,
- ...props
- }: PropsWithChildren,
- ref: Ref,
+export const PressableWithHover = forwardRef<
+ View,
+ PropsWithChildren
+>(function PressableWithHoverImpl(
+ {children, style, hoverStyle, ...props},
+ ref,
) {
- const [isHovering, setIsHovering] = useState(false)
-
- const onHoverIn = useCallback(() => setIsHovering(true), [setIsHovering])
- const onHoverOut = useCallback(() => setIsHovering(false), [setIsHovering])
- style =
- typeof style !== 'function' && isHovering
- ? addStyle(style, hoverStyle)
- : style
+ const {
+ state: hovered,
+ onIn: onHoverIn,
+ onOut: onHoverOut,
+ } = useInteractionState()
return (
diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/ControlButton.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/ControlButton.tsx
index 6b509d09a3..8ffe482a8f 100644
--- a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/ControlButton.tsx
+++ b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/ControlButton.tsx
@@ -1,8 +1,8 @@
import React from 'react'
import {SvgProps} from 'react-native-svg'
-import {atoms as a, useTheme} from '#/alf'
-import {Button} from '#/components/Button'
+import {atoms as a, useTheme, web} from '#/alf'
+import {PressableWithHover} from '../../../PressableWithHover'
export function ControlButton({
active,
@@ -21,19 +21,21 @@ export function ControlButton({
}) {
const t = useTheme()
return (
-
+
)
}
diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx
index 5bd7e0d179..2d1427347d 100644
--- a/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx
+++ b/src/view/com/util/post-embeds/VideoEmbedInner/web-controls/VideoControls.tsx
@@ -358,9 +358,8 @@ export function Controls({
style={[
a.flex_1,
a.px_xs,
- a.pt_2xs,
- a.pb_md,
- a.gap_md,
+ a.pb_sm,
+ a.gap_sm,
a.flex_row,
a.align_center,
]}>
@@ -373,7 +372,11 @@ export function Controls({
onPress={onPressPlayPause}
/>
-
+
{formatTime(currentTime)} / {formatTime(duration)}
{hasSubtitleTrack && (
From 5eb294488f08534abac3335acfa366cffea9259e Mon Sep 17 00:00:00 2001
From: Eric Bailey
Date: Mon, 23 Sep 2024 10:40:37 -0500
Subject: [PATCH 5/5] [Neue] Handle emoji within custom font (#5449)
* Support emoji in text with custom font
* Add emoji support to elements that need it
* Remove unused file causing lint failure
* Fix a few more emoji locations
* Couple more
* No throw
---
package.json | 1 +
src/components/FeedCard.tsx | 13 ++-
src/components/KnownFollowers.tsx | 14 +--
src/components/LabelingServiceCard/index.tsx | 11 +-
src/components/ListCard.tsx | 24 ++--
src/components/Pills.tsx | 1 +
src/components/ProfileCard.tsx | 12 +-
src/components/ReportDialog/SubmitView.tsx | 1 +
src/components/RichText.tsx | 9 +-
.../StarterPack/StarterPackCard.tsx | 27 ++---
.../StarterPack/Wizard/WizardListCard.tsx | 11 +-
src/components/Typography.tsx | 108 +++++++++++++++++-
src/components/dms/MessagesListHeader.tsx | 17 +--
.../moderation/LabelsOnMeDialog.tsx | 6 +-
.../moderation/ModerationDetailsDialog.tsx | 8 +-
src/screens/Messages/List/ChatListItem.tsx | 10 +-
src/screens/Profile/Header/DisplayName.tsx | 1 +
src/screens/Profile/Header/Handle.tsx | 11 +-
.../com/composer/text-input/TextInput.tsx | 19 +--
.../composer/text-input/web/Autocomplete.tsx | 15 +--
src/view/com/feeds/FeedSourceCard.tsx | 12 +-
src/view/com/modals/UserAddRemoveLists.tsx | 32 +++---
src/view/com/notifications/FeedItem.tsx | 23 ++--
src/view/com/pager/TabBar.tsx | 1 +
src/view/com/post-thread/PostThreadItem.tsx | 31 ++---
src/view/com/posts/FeedItem.tsx | 26 +++--
src/view/com/profile/ProfileCard.tsx | 19 +--
src/view/com/util/PostMeta.tsx | 44 ++++---
src/view/com/util/UserInfoText.tsx | 33 +++---
.../util/post-embeds/ExternalLinkEmbed.tsx | 27 ++---
src/view/com/util/text/Text.tsx | 50 +++++---
src/view/com/util/text/ThemedText.tsx | 80 -------------
src/view/screens/Search/Search.tsx | 1 +
src/view/shell/desktop/Search.tsx | 11 +-
yarn.lock | 5 +
35 files changed, 424 insertions(+), 290 deletions(-)
delete mode 100644 src/view/com/util/text/ThemedText.tsx
diff --git a/package.json b/package.json
index bb9706c39a..245c095f19 100644
--- a/package.json
+++ b/package.json
@@ -116,6 +116,7 @@
"deprecated-react-native-prop-types": "^5.0.0",
"email-validator": "^2.0.4",
"emoji-mart": "^5.5.2",
+ "emoji-regex": "^10.4.0",
"eventemitter3": "^5.0.1",
"expo": "^51.0.8",
"expo-application": "^5.9.1",
diff --git a/src/components/FeedCard.tsx b/src/components/FeedCard.tsx
index e6d664cfda..b28f66f839 100644
--- a/src/components/FeedCard.tsx
+++ b/src/components/FeedCard.tsx
@@ -11,17 +11,17 @@ import {msg, plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useQueryClient} from '@tanstack/react-query'
+import {sanitizeHandle} from '#/lib/strings/handles'
import {logger} from '#/logger'
+import {precacheFeedFromGeneratorView} from '#/state/queries/feed'
import {
useAddSavedFeedsMutation,
usePreferencesQuery,
useRemoveFeedMutation,
} from '#/state/queries/preferences'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {precacheFeedFromGeneratorView} from 'state/queries/feed'
-import {useSession} from 'state/session'
+import {useSession} from '#/state/session'
+import * as Toast from '#/view/com/util/Toast'
import {UserAvatar} from '#/view/com/util/UserAvatar'
-import * as Toast from 'view/com/util/Toast'
import {useTheme} from '#/alf'
import {atoms as a} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button'
@@ -121,7 +121,10 @@ export function TitleAndByline({
return (
-
+
{title}
{creator && (
diff --git a/src/components/KnownFollowers.tsx b/src/components/KnownFollowers.tsx
index 4017a7b0be..35a346c3a5 100644
--- a/src/components/KnownFollowers.tsx
+++ b/src/components/KnownFollowers.tsx
@@ -5,7 +5,7 @@ import {msg, Plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {makeProfileLink} from '#/lib/routes/links'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useTheme} from '#/alf'
import {Link, LinkProps} from '#/components/Link'
@@ -185,11 +185,11 @@ function KnownFollowersInner({
serverCount > 2 ? (
Followed by{' '}
-
+
{slice[0].profile.displayName}
,{' '}
-
+
{slice[1].profile.displayName}
, and{' '}
@@ -203,11 +203,11 @@ function KnownFollowersInner({
// only 2
Followed by{' '}
-
+
{slice[0].profile.displayName}
{' '}
and{' '}
-
+
{slice[1].profile.displayName}
@@ -216,7 +216,7 @@ function KnownFollowersInner({
// 1-n followers, including blocks
Followed by{' '}
-
+
{slice[0].profile.displayName}
{' '}
and{' '}
@@ -230,7 +230,7 @@ function KnownFollowersInner({
// only 1
Followed by{' '}
-
+
{slice[0].profile.displayName}
diff --git a/src/components/LabelingServiceCard/index.tsx b/src/components/LabelingServiceCard/index.tsx
index 851645a48c..03b8ece6b1 100644
--- a/src/components/LabelingServiceCard/index.tsx
+++ b/src/components/LabelingServiceCard/index.tsx
@@ -44,17 +44,22 @@ export function Avatar({avatar}: {avatar?: string}) {
}
export function Title({value}: {value: string}) {
- return {value}
+ return (
+
+ {value}
+
+ )
}
export function Description({value, handle}: {value?: string; handle: string}) {
+ const {_} = useLingui()
return value ? (
) : (
-
- By {sanitizeHandle(handle, '@')}
+
+ {_(msg`By ${sanitizeHandle(handle, '@')}`)}
)
}
diff --git a/src/components/ListCard.tsx b/src/components/ListCard.tsx
index 829f36d471..ed5838fb04 100644
--- a/src/components/ListCard.tsx
+++ b/src/components/ListCard.tsx
@@ -7,13 +7,14 @@ import {
moderateUserList,
ModerationUI,
} from '@atproto/api'
-import {Trans} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
import {useQueryClient} from '@tanstack/react-query'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {useModerationOpts} from 'state/preferences/moderation-opts'
-import {precacheList} from 'state/queries/feed'
-import {useSession} from 'state/session'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {useModerationOpts} from '#/state/preferences/moderation-opts'
+import {precacheList} from '#/state/queries/feed'
+import {useSession} from '#/state/session'
import {atoms as a, useTheme} from '#/alf'
import {
Avatar,
@@ -111,6 +112,7 @@ export function TitleAndByline({
modUi?: ModerationUI
}) {
const t = useTheme()
+ const {_} = useLingui()
const {currentAccount} = useSession()
return (
@@ -130,6 +132,7 @@ export function TitleAndByline({
{title}
@@ -139,15 +142,12 @@ export function TitleAndByline({
{creator && (
- {purpose === MODLIST ? (
-
- Moderation list by {sanitizeHandle(creator.handle, '@')}
-
- ) : (
- List by {sanitizeHandle(creator.handle, '@')}
- )}
+ {purpose === MODLIST
+ ? _(msg`Moderation list by ${sanitizeHandle(creator.handle, '@')}`)
+ : _(msg`List by ${sanitizeHandle(creator.handle, '@')}`)}
)}
diff --git a/src/components/Pills.tsx b/src/components/Pills.tsx
index 6c8084743f..974d83593f 100644
--- a/src/components/Pills.tsx
+++ b/src/components/Pills.tsx
@@ -130,6 +130,7 @@ export function Label({
)}
{name}
{handle}
diff --git a/src/components/ReportDialog/SubmitView.tsx b/src/components/ReportDialog/SubmitView.tsx
index 2def0fa4b4..e323d15042 100644
--- a/src/components/ReportDialog/SubmitView.tsx
+++ b/src/components/ReportDialog/SubmitView.tsx
@@ -256,6 +256,7 @@ function LabelerToggle({title}: {title: string}) {
a.z_10,
]}>
,
)
} else {
- els.push(segment.text)
+ els.push(
+
+ {segment.text}
+ ,
+ )
}
key++
}
@@ -213,6 +219,7 @@ function RichTextTag({
{!noIcon ? : null}
-
+
{record.name}
-
-
- Starter pack by{' '}
- {creator?.did === currentAccount?.did
- ? _(msg`you`)
- : `@${sanitizeHandle(creator.handle)}`}
-
+
+ {creator?.did === currentAccount?.did
+ ? _(msg`Starter pack by you`)
+ : _(msg`Starter pack by ${sanitizeHandle(creator.handle, '@')}`)}
{!noDescription && record.description ? (
-
+
{record.description}
) : null}
diff --git a/src/components/StarterPack/Wizard/WizardListCard.tsx b/src/components/StarterPack/Wizard/WizardListCard.tsx
index ad02cdc306..44f01a1545 100644
--- a/src/components/StarterPack/Wizard/WizardListCard.tsx
+++ b/src/components/StarterPack/Wizard/WizardListCard.tsx
@@ -12,11 +12,11 @@ import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
-import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from 'lib/constants'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {useSession} from 'state/session'
-import {UserAvatar} from 'view/com/util/UserAvatar'
+import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {useSession} from '#/state/session'
+import {UserAvatar} from '#/view/com/util/UserAvatar'
import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
@@ -78,6 +78,7 @@ function WizardListCard({
/>
& {
/**
* Lets the user select text, to use the native copy and paste functionality.
*/
selectable?: boolean
+ /**
+ * Provides `data-*` attributes to the underlying `UITextView` component on
+ * web only.
+ */
+ dataSet?: Record
+ /**
+ * Appears as a small tooltip on web hover.
+ */
+ title?: string
+} & (
+ | {
+ emoji: true
+ children: StringChild
+ }
+ | {
+ emoji?: false
+ children: RNTextProps['children']
+ }
+ )
+
+const EMOJI = createEmojiRegex()
+
+export function childHasEmoji(children: React.ReactNode) {
+ return (Array.isArray(children) ? children : [children]).some(
+ child => typeof child === 'string' && createEmojiRegex().test(child),
+ )
+}
+
+export function childIsString(
+ children: React.ReactNode,
+): children is StringChild {
+ return (
+ typeof children === 'string' ||
+ (Array.isArray(children) &&
+ children.every(child => typeof child === 'string' || child === null))
+ )
+}
+
+export function renderChildrenWithEmoji(children: StringChild) {
+ const normalized = Array.isArray(children) ? children : [children]
+
+ return (
+
+ {normalized.map(child => {
+ if (typeof child !== 'string') return child
+
+ const emojis = child.match(EMOJI)
+
+ if (emojis === null) {
+ return child
+ }
+
+ return child.split(EMOJI).map((stringPart, index) => (
+
+ {stringPart}
+ {emojis[index] ? (
+
+ {emojis[index]}
+
+ ) : null}
+
+ ))
+ })}
+
+ )
}
/**
@@ -64,7 +134,15 @@ export function normalizeTextStyles(
/**
* Our main text component. Use this most of the time.
*/
-export function Text({style, selectable, ...rest}: TextProps) {
+export function Text({
+ children,
+ emoji,
+ style,
+ selectable,
+ title,
+ dataSet,
+ ...rest
+}: TextProps) {
const {fonts, flags} = useAlf()
const t = useTheme()
const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)], {
@@ -73,7 +151,29 @@ export function Text({style, selectable, ...rest}: TextProps) {
flags,
})
- return
+ if (IS_DEV) {
+ if (!emoji && childHasEmoji(children)) {
+ logger.warn(
+ `Text: emoji detected but emoji not enabled: "${children}"\n\nPlease add '`,
+ )
+ }
+
+ if (emoji && !childIsString(children)) {
+ logger.error('Text: when , children can only be strings.')
+ }
+ }
+
+ return (
+
+ {isIOS && emoji ? renderChildrenWithEmoji(children) : children}
+
+ )
}
export function createHeadingElement({level}: {level: number}) {
diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx
index 1a6bbbe601..ab9ec16e4d 100644
--- a/src/components/dms/MessagesListHeader.tsx
+++ b/src/components/dms/MessagesListHeader.tsx
@@ -10,14 +10,14 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native'
-import {BACK_HITSLOP} from 'lib/constants'
-import {makeProfileLink} from 'lib/routes/links'
-import {NavigationProp} from 'lib/routes/types'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {isWeb} from 'platform/detection'
-import {useProfileShadow} from 'state/cache/profile-shadow'
-import {isConvoActive, useConvo} from 'state/messages/convo'
-import {PreviewableUserAvatar} from 'view/com/util/UserAvatar'
+import {BACK_HITSLOP} from '#/lib/constants'
+import {makeProfileLink} from '#/lib/routes/links'
+import {NavigationProp} from '#/lib/routes/types'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {isWeb} from '#/platform/detection'
+import {useProfileShadow} from '#/state/cache/profile-shadow'
+import {isConvoActive, useConvo} from '#/state/messages/convo'
+import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
import {ConvoMenu} from '#/components/dms/ConvoMenu'
import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2'
@@ -170,6 +170,7 @@ function HeaderReady({
- {strings.name}
-
+
+ {strings.name}
+
+
{strings.description}
diff --git a/src/components/moderation/ModerationDetailsDialog.tsx b/src/components/moderation/ModerationDetailsDialog.tsx
index d95717cf43..2259178538 100644
--- a/src/components/moderation/ModerationDetailsDialog.tsx
+++ b/src/components/moderation/ModerationDetailsDialog.tsx
@@ -118,7 +118,11 @@ function ModerationDetailsDialogInner({
: _(msg`The author of this thread has hidden this reply.`)
} else if (modcause.type === 'label') {
name = desc.name
- description = desc.description
+ description = (
+
+ {desc.description}
+
+ )
} else {
// should never happen
name = ''
@@ -127,7 +131,7 @@ function ModerationDetailsDialogInner({
return (
-
+
{name}
diff --git a/src/screens/Messages/List/ChatListItem.tsx b/src/screens/Messages/List/ChatListItem.tsx
index c45cc28d7a..e9668b4e11 100644
--- a/src/screens/Messages/List/ChatListItem.tsx
+++ b/src/screens/Messages/List/ChatListItem.tsx
@@ -10,6 +10,10 @@ import {
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
+import {useHaptics} from '#/lib/haptics'
+import {decrementBadgeCount} from '#/lib/notifications/notifications'
+import {logEvent} from '#/lib/statsig/statsig'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {
postUriToRelativePath,
toBskyAppUrl,
@@ -19,10 +23,6 @@ import {isNative} from '#/platform/detection'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useSession} from '#/state/session'
-import {useHaptics} from 'lib/haptics'
-import {decrementBadgeCount} from 'lib/notifications/notifications'
-import {logEvent} from 'lib/statsig/statsig'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
import {TimeElapsed} from '#/view/com/util/TimeElapsed'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
@@ -248,6 +248,7 @@ function ChatListItemReady({
numberOfLines={1}
style={[{maxWidth: '85%'}, web([a.leading_normal])]}>
{sanitizeDisplayName(
diff --git a/src/screens/Profile/Header/Handle.tsx b/src/screens/Profile/Header/Handle.tsx
index 0344f1a234..ba869b6626 100644
--- a/src/screens/Profile/Header/Handle.tsx
+++ b/src/screens/Profile/Header/Handle.tsx
@@ -1,11 +1,12 @@
import React from 'react'
import {View} from 'react-native'
import {AppBskyActorDefs} from '@atproto/api'
-import {Trans} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {isInvalidHandle} from '#/lib/strings/handles'
+import {isIOS} from '#/platform/detection'
import {Shadow} from '#/state/cache/types'
-import {isInvalidHandle} from 'lib/strings/handles'
-import {isIOS} from 'platform/detection'
import {atoms as a, useTheme, web} from '#/alf'
import {NewskieDialog} from '#/components/NewskieDialog'
import {Text} from '#/components/Typography'
@@ -18,6 +19,7 @@ export function ProfileHeaderHandle({
disableTaps?: boolean
}) {
const t = useTheme()
+ const {_} = useLingui()
const invalidHandle = isInvalidHandle(profile.handle)
const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy
return (
@@ -33,6 +35,7 @@ export function ProfileHeaderHandle({
) : undefined}
- {invalidHandle ? ⚠Invalid Handle : `@${profile.handle}`}
+ {invalidHandle ? _(msg`⚠Invalid Handle`) : `@${profile.handle}`}
)
diff --git a/src/view/com/composer/text-input/TextInput.tsx b/src/view/com/composer/text-input/TextInput.tsx
index 778439259e..95c57ad899 100644
--- a/src/view/com/composer/text-input/TextInput.tsx
+++ b/src/view/com/composer/text-input/TextInput.tsx
@@ -19,19 +19,19 @@ import PasteInput, {
PasteInputRef,
} from '@mattermost/react-native-paste-input'
+import {POST_IMG_MAX} from '#/lib/constants'
+import {usePalette} from '#/lib/hooks/usePalette'
+import {downloadAndResize} from '#/lib/media/manip'
+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 {isAndroid} from '#/platform/detection'
-import {POST_IMG_MAX} from 'lib/constants'
-import {usePalette} from 'lib/hooks/usePalette'
-import {downloadAndResize} from 'lib/media/manip'
-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 {
LinkFacetMatch,
suggestLinkCardUri,
-} from 'view/com/composer/text-input/text-input-util'
-import {Text} from 'view/com/util/text/Text'
+} 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'
@@ -216,6 +216,7 @@ export const TextInput = forwardRef(function TextInputImpl(
return Array.from(richtext.segments()).map(segment => {
return (
{segment.text}
diff --git a/src/view/com/composer/text-input/web/Autocomplete.tsx b/src/view/com/composer/text-input/web/Autocomplete.tsx
index 29b8f0bc65..a43e67c044 100644
--- a/src/view/com/composer/text-input/web/Autocomplete.tsx
+++ b/src/view/com/composer/text-input/web/Autocomplete.tsx
@@ -5,19 +5,20 @@ import React, {
useState,
} from 'react'
import {Pressable, StyleSheet, View} from 'react-native'
+import {Trans} from '@lingui/macro'
import {ReactRenderer} from '@tiptap/react'
-import tippy, {Instance as TippyInstance} from 'tippy.js'
import {
+ SuggestionKeyDownProps,
SuggestionOptions,
SuggestionProps,
- SuggestionKeyDownProps,
} from '@tiptap/suggestion'
+import tippy, {Instance as TippyInstance} from 'tippy.js'
+
+import {usePalette} from '#/lib/hooks/usePalette'
import {ActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
-import {usePalette} from 'lib/hooks/usePalette'
-import {Text} from 'view/com/util/text/Text'
-import {UserAvatar} from 'view/com/util/UserAvatar'
+import {Text} from '#/view/com/util/text/Text'
+import {UserAvatar} from '#/view/com/util/UserAvatar'
import {useGrapheme} from '../hooks/useGrapheme'
-import {Trans} from '@lingui/macro'
interface MentionListRef {
onKeyDown: (props: SuggestionKeyDownProps) => boolean
@@ -180,7 +181,7 @@ const MentionList = forwardRef(
size={26}
type={item.associated?.labeler ? 'labeler' : 'user'}
/>
-
+
{displayName}
diff --git a/src/view/com/feeds/FeedSourceCard.tsx b/src/view/com/feeds/FeedSourceCard.tsx
index 68437c37a0..3276cf8821 100644
--- a/src/view/com/feeds/FeedSourceCard.tsx
+++ b/src/view/com/feeds/FeedSourceCard.tsx
@@ -12,6 +12,10 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg, Plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
+import {useNavigationDeduped} from '#/lib/hooks/useNavigationDeduped'
+import {usePalette} from '#/lib/hooks/usePalette'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {s} from '#/lib/styles'
import {logger} from '#/logger'
import {shouldClickOpenNewTab} from '#/platform/urls'
import {FeedSourceInfo, useFeedSourceInfoQuery} from '#/state/queries/feed'
@@ -21,12 +25,8 @@ import {
UsePreferencesQueryResponse,
useRemoveFeedMutation,
} from '#/state/queries/preferences'
-import {useNavigationDeduped} from 'lib/hooks/useNavigationDeduped'
-import {usePalette} from 'lib/hooks/usePalette'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {s} from 'lib/styles'
import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
-import * as Toast from 'view/com/util/Toast'
+import * as Toast from '#/view/com/util/Toast'
import {useTheme} from '#/alf'
import {atoms as a} from '#/alf'
import * as Prompt from '#/components/Prompt'
@@ -242,7 +242,7 @@ export function FeedSourceCardLoaded({
-
+
{feed.displayName}
diff --git a/src/view/com/modals/UserAddRemoveLists.tsx b/src/view/com/modals/UserAddRemoveLists.tsx
index 29caf46609..b0b76644f0 100644
--- a/src/view/com/modals/UserAddRemoveLists.tsx
+++ b/src/view/com/modals/UserAddRemoveLists.tsx
@@ -65,21 +65,27 @@ export function Component({
return [pal.border, {flex: 1, borderTopWidth: StyleSheet.hairlineWidth}]
}, [pal.border, screenHeight])
+ const headerStyles = [
+ {
+ textAlign: 'center',
+ fontWeight: '600',
+ fontSize: 20,
+ marginBottom: 12,
+ paddingHorizontal: 12,
+ } as const,
+ pal.text,
+ ]
+
return (
-
- Update {displayName} in Lists
+
+
+ Update{' '}
+
+ {displayName}
+ {' '}
+ in Lists
+
+ {forceLTR(firstAuthorName)}
+
+ }
disableMismatchWarning
/>
{authors.length > 1 ? (
@@ -570,12 +574,13 @@ function ExpandedAuthorsList({
numberOfLines={1}
style={pal.text}
lineHeight={1.2}>
- {sanitizeDisplayName(
- author.profile.displayName || author.profile.handle,
- )}
-
+
+ {sanitizeDisplayName(
+ author.profile.displayName || author.profile.handle,
+ )}
+ {' '}
- {sanitizeHandle(author.profile.handle)}
+ {sanitizeHandle(author.profile.handle, '@')}
@@ -592,7 +597,11 @@ function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) {
return (
<>
- {text?.length > 0 && {text}}
+ {text?.length > 0 && (
+
+ {text}
+
+ )}
onPressItem(i)}>
-
+
{sanitizeHandle(post.author.handle, '@')}
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index 7537a46448..b1509b2719 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -316,11 +316,19 @@ let FeedItemInner = ({
style={pal.textLight}
lineHeight={1.2}
numberOfLines={1}
- text={sanitizeDisplayName(
- reason.by.displayName ||
- sanitizeHandle(reason.by.handle),
- moderation.ui('displayName'),
- )}
+ text={
+
+ {sanitizeDisplayName(
+ reason.by.displayName ||
+ sanitizeHandle(reason.by.handle),
+ moderation.ui('displayName'),
+ )}
+
+ }
href={makeProfileLink(reason.by)}
onBeforePress={onOpenReposter}
/>
@@ -527,9 +535,11 @@ function ReplyToLabel({
numberOfLines={1}
href={makeProfileLink(profile)}
text={
- profile.displayName
- ? sanitizeDisplayName(profile.displayName)
- : sanitizeHandle(profile.handle)
+
+ {profile.displayName
+ ? sanitizeDisplayName(profile.displayName)
+ : sanitizeHandle(profile.handle)}
+
}
/>
diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx
index fd32e37a42..eab8611dd4 100644
--- a/src/view/com/profile/ProfileCard.tsx
+++ b/src/view/com/profile/ProfileCard.tsx
@@ -7,17 +7,17 @@ import {
} from '@atproto/api'
import {useQueryClient} from '@tanstack/react-query'
+import {usePalette} from '#/lib/hooks/usePalette'
+import {getModerationCauseKey, isJustAMute} from '#/lib/moderation'
+import {makeProfileLink} from '#/lib/routes/links'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {s} from '#/lib/styles'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {Shadow} from '#/state/cache/types'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
+import {precacheProfile} from '#/state/queries/profile'
import {useSession} from '#/state/session'
-import {usePalette} from 'lib/hooks/usePalette'
-import {getModerationCauseKey, isJustAMute} from 'lib/moderation'
-import {makeProfileLink} from 'lib/routes/links'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {s} from 'lib/styles'
-import {precacheProfile} from 'state/queries/profile'
import {atoms as a} from '#/alf'
import {
KnownFollowers,
@@ -103,6 +103,7 @@ export function ProfileCard({
-
+
{sanitizeHandle(profile.handle, '@')}
{profile.description ? (
-
+
{profile.description as string}
) : null}
diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx
index 3bd350bf32..f2d717e962 100644
--- a/src/view/com/util/PostMeta.tsx
+++ b/src/view/com/util/PostMeta.tsx
@@ -4,16 +4,16 @@ import {AppBskyActorDefs, ModerationDecision, ModerationUI} from '@atproto/api'
import {useLingui} from '@lingui/react'
import {useQueryClient} from '@tanstack/react-query'
+import {usePalette} from '#/lib/hooks/usePalette'
+import {makeProfileLink} from '#/lib/routes/links'
+import {forceLTR} from '#/lib/strings/bidi'
+import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {niceDate} from '#/lib/strings/time'
+import {TypographyVariant} from '#/lib/ThemeContext'
+import {isAndroid} from '#/platform/detection'
import {precacheProfile} from '#/state/queries/profile'
-import {usePalette} from 'lib/hooks/usePalette'
-import {makeProfileLink} from 'lib/routes/links'
-import {forceLTR} from 'lib/strings/bidi'
-import {NON_BREAKING_SPACE} from 'lib/strings/constants'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {niceDate} from 'lib/strings/time'
-import {TypographyVariant} from 'lib/ThemeContext'
-import {isAndroid} from 'platform/detection'
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
import {TextLinkOnWebOnly} from './Link'
import {Text} from './text/Text'
@@ -73,12 +73,20 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
style={[pal.text]}
lineHeight={1.2}
disableMismatchWarning
- text={forceLTR(
- sanitizeDisplayName(
- displayName,
- opts.moderation?.ui('displayName'),
- ),
- )}
+ text={
+
+ {forceLTR(
+ sanitizeDisplayName(
+ displayName,
+ opts.moderation?.ui('displayName'),
+ ),
+ )}
+
+ }
href={profileLink}
onBeforePress={onBeforePressAuthor}
/>
@@ -86,7 +94,11 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
type="md"
disableMismatchWarning
style={[pal.textLight, {flexShrink: 4}]}
- text={NON_BREAKING_SPACE + sanitizeHandle(handle, '@')}
+ text={
+
+ {NON_BREAKING_SPACE + sanitizeHandle(handle, '@')}
+
+ }
href={profileLink}
onBeforePress={onBeforePressAuthor}
anchorNoUnderline
diff --git a/src/view/com/util/UserInfoText.tsx b/src/view/com/util/UserInfoText.tsx
index 9cb9997f60..8a444d5901 100644
--- a/src/view/com/util/UserInfoText.tsx
+++ b/src/view/com/util/UserInfoText.tsx
@@ -1,15 +1,16 @@
import React from 'react'
-import {AppBskyActorGetProfile as GetProfile} from '@atproto/api'
import {StyleProp, StyleSheet, TextStyle} from 'react-native'
-import {TextLinkOnWebOnly} from './Link'
-import {Text} from './text/Text'
-import {LoadingPlaceholder} from './LoadingPlaceholder'
-import {TypographyVariant} from 'lib/ThemeContext'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {makeProfileLink} from 'lib/routes/links'
-import {useProfileQuery} from '#/state/queries/profile'
+import {AppBskyActorGetProfile as GetProfile} from '@atproto/api'
+
+import {makeProfileLink} from '#/lib/routes/links'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {TypographyVariant} from '#/lib/ThemeContext'
import {STALE} from '#/state/queries'
+import {useProfileQuery} from '#/state/queries/profile'
+import {TextLinkOnWebOnly} from './Link'
+import {LoadingPlaceholder} from './LoadingPlaceholder'
+import {Text} from './text/Text'
export function UserInfoText({
type = 'md',
@@ -50,11 +51,15 @@ export function UserInfoText({
lineHeight={1.2}
numberOfLines={1}
href={makeProfileLink(profile)}
- text={`${prefix || ''}${sanitizeDisplayName(
- typeof profile[attr] === 'string' && profile[attr]
- ? (profile[attr] as string)
- : sanitizeHandle(profile.handle),
- )}`}
+ text={
+
+ {`${prefix || ''}${sanitizeDisplayName(
+ typeof profile[attr] === 'string' && profile[attr]
+ ? (profile[attr] as string)
+ : sanitizeHandle(profile.handle),
+ )}`}
+
+ }
/>
)
} else {
diff --git a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
index 54e1eb4d55..98332c33b0 100644
--- a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
+++ b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
@@ -5,21 +5,21 @@ import {AppBskyEmbedExternal} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
-import {usePalette} from 'lib/hooks/usePalette'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {shareUrl} from 'lib/sharing'
-import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
+import {usePalette} from '#/lib/hooks/usePalette'
+import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
+import {shareUrl} from '#/lib/sharing'
+import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player'
import {
getStarterPackOgCard,
parseStarterPackUri,
-} from 'lib/strings/starter-pack'
-import {toNiceDomain} from 'lib/strings/url-helpers'
-import {isNative} from 'platform/detection'
-import {useExternalEmbedsPrefs} from 'state/preferences'
-import {Link} from 'view/com/util/Link'
-import {ExternalGifEmbed} from 'view/com/util/post-embeds/ExternalGifEmbed'
-import {ExternalPlayer} from 'view/com/util/post-embeds/ExternalPlayerEmbed'
-import {GifEmbed} from 'view/com/util/post-embeds/GifEmbed'
+} from '#/lib/strings/starter-pack'
+import {toNiceDomain} from '#/lib/strings/url-helpers'
+import {isNative} from '#/platform/detection'
+import {useExternalEmbedsPrefs} from '#/state/preferences'
+import {Link} from '#/view/com/util/Link'
+import {ExternalGifEmbed} from '#/view/com/util/post-embeds/ExternalGifEmbed'
+import {ExternalPlayer} from '#/view/com/util/post-embeds/ExternalPlayerEmbed'
+import {GifEmbed} from '#/view/com/util/post-embeds/GifEmbed'
import {atoms as a, useTheme} from '#/alf'
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
import {Text} from '../text/Text'
@@ -115,12 +115,13 @@ export const ExternalLinkEmbed = ({
{!embedPlayerParams?.isGif && !embedPlayerParams?.dimensions && (
-
+
{link.title || link.uri}
)}
{link.description ? (
diff --git a/src/view/com/util/text/Text.tsx b/src/view/com/util/text/Text.tsx
index 52a45b0e2e..3d885480cc 100644
--- a/src/view/com/util/text/Text.tsx
+++ b/src/view/com/util/text/Text.tsx
@@ -2,27 +2,40 @@ import React from 'react'
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 {lh, s} from '#/lib/styles'
+import {TypographyVariant, useTheme} from '#/lib/ThemeContext'
+import {logger} from '#/logger'
+import {isIOS} from '#/platform/detection'
import {applyFonts, useAlf} from '#/alf'
+import {
+ childHasEmoji,
+ childIsString,
+ renderChildrenWithEmoji,
+ StringChild,
+} from '#/components/Typography'
+import {IS_DEV} from '#/env'
-export type CustomTextProps = TextProps & {
+export type CustomTextProps = Omit & {
type?: TypographyVariant
lineHeight?: number
title?: string
dataSet?: Record
selectable?: boolean
-}
-
-const fontFamilyStyle = {
- fontFamily:
- '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif',
-}
+} & (
+ | {
+ emoji: true
+ children: StringChild
+ }
+ | {
+ emoji?: false
+ children: TextProps['children']
+ }
+ )
export function Text({
type = 'md',
children,
+ emoji,
lineHeight,
style,
title,
@@ -35,6 +48,18 @@ export function Text({
const lineHeightStyle = lineHeight ? lh(theme, type, lineHeight) : undefined
const {fonts} = useAlf()
+ if (IS_DEV) {
+ if (!emoji && childHasEmoji(children)) {
+ logger.warn(
+ `Text: emoji detected but emoji not enabled: "${children}"\n\nPlease add '`,
+ )
+ }
+
+ if (emoji && !childIsString(children)) {
+ logger.error('Text: when , children can only be strings.')
+ }
+ }
+
if (selectable && isIOS) {
const flattened = StyleSheet.flatten([
s.black,
@@ -58,7 +83,7 @@ export function Text({
selectable={selectable}
uiTextView
{...props}>
- {children}
+ {isIOS && emoji ? renderChildrenWithEmoji(children) : children}
)
}
@@ -66,7 +91,6 @@ export function Text({
const flattened = StyleSheet.flatten([
s.black,
typography,
- isWeb && fontFamilyStyle,
lineHeightStyle,
style,
])
@@ -87,7 +111,7 @@ export function Text({
dataSet={Object.assign({tooltip: title}, dataSet || {})}
selectable={selectable}
{...props}>
- {children}
+ {isIOS && emoji ? renderChildrenWithEmoji(children) : children}
)
}
diff --git a/src/view/com/util/text/ThemedText.tsx b/src/view/com/util/text/ThemedText.tsx
deleted file mode 100644
index 2844d273c2..0000000000
--- a/src/view/com/util/text/ThemedText.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React from 'react'
-import {CustomTextProps, Text} from './Text'
-import {usePalette} from 'lib/hooks/usePalette'
-import {addStyle} from 'lib/styles'
-
-export type ThemedTextProps = CustomTextProps & {
- fg?: 'default' | 'light' | 'error' | 'inverted' | 'inverted-light'
- bg?: 'default' | 'light' | 'error' | 'inverted' | 'inverted-light'
- border?: 'default' | 'dark' | 'error' | 'inverted' | 'inverted-dark'
- lineHeight?: number
-}
-
-export function ThemedText({
- fg,
- bg,
- border,
- style,
- children,
- ...props
-}: React.PropsWithChildren) {
- const pal = usePalette('default')
- const palInverted = usePalette('inverted')
- const palError = usePalette('error')
- switch (fg) {
- case 'default':
- style = addStyle(style, pal.text)
- break
- case 'light':
- style = addStyle(style, pal.textLight)
- break
- case 'error':
- style = addStyle(style, {color: palError.colors.background})
- break
- case 'inverted':
- style = addStyle(style, palInverted.text)
- break
- case 'inverted-light':
- style = addStyle(style, palInverted.textLight)
- break
- }
- switch (bg) {
- case 'default':
- style = addStyle(style, pal.view)
- break
- case 'light':
- style = addStyle(style, pal.viewLight)
- break
- case 'error':
- style = addStyle(style, palError.view)
- break
- case 'inverted':
- style = addStyle(style, palInverted.view)
- break
- case 'inverted-light':
- style = addStyle(style, palInverted.viewLight)
- break
- }
- switch (border) {
- case 'default':
- style = addStyle(style, pal.border)
- break
- case 'dark':
- style = addStyle(style, pal.borderDark)
- break
- case 'error':
- style = addStyle(style, palError.border)
- break
- case 'inverted':
- style = addStyle(style, palInverted.border)
- break
- case 'inverted-dark':
- style = addStyle(style, palInverted.borderDark)
- break
- }
- return (
-
- {children}
-
- )
-}
diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx
index e1e412648b..07d762c0fe 100644
--- a/src/view/screens/Search/Search.tsx
+++ b/src/view/screens/Search/Search.tsx
@@ -959,6 +959,7 @@ function SearchHistory({
accessibilityIgnoresInvertColors
/>
{profile.displayName || profile.handle}
diff --git a/src/view/shell/desktop/Search.tsx b/src/view/shell/desktop/Search.tsx
index 1ba2d3f3db..b43dbcce32 100644
--- a/src/view/shell/desktop/Search.tsx
+++ b/src/view/shell/desktop/Search.tsx
@@ -16,19 +16,19 @@ import {useLingui} from '@lingui/react'
import {StackActions, useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query'
+import {usePalette} from '#/lib/hooks/usePalette'
import {makeProfileLink} from '#/lib/routes/links'
+import {NavigationProp} from '#/lib/routes/types'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {s} from '#/lib/styles'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
-import {usePalette} from 'lib/hooks/usePalette'
-import {NavigationProp} from 'lib/routes/types'
-import {precacheProfile} from 'state/queries/profile'
+import {precacheProfile} from '#/state/queries/profile'
+import {SearchInput} from '#/view/com/util/forms/SearchInput'
import {Link} from '#/view/com/util/Link'
+import {Text} from '#/view/com/util/text/Text'
import {UserAvatar} from '#/view/com/util/UserAvatar'
-import {SearchInput} from 'view/com/util/forms/SearchInput'
-import {Text} from 'view/com/util/text/Text'
import {atoms as a} from '#/alf'
let SearchLinkCard = ({
@@ -126,6 +126,7 @@ let SearchProfileCard = ({
/>