about summary refs log tree commit diff
path: root/src/components/RichText.tsx
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-01-25 22:22:40 -0600
committerGitHub <noreply@github.com>2024-01-25 20:22:40 -0800
commit3371038f7d8b740f2415d3a54dc99b69e0598042 (patch)
tree9ef008e132f268ce6a8a23765ab34fda71a4bedc /src/components/RichText.tsx
parent5443503593a67cc7ff6e081ef9b1fe66ea0cbe0d (diff)
downloadvoidsky-3371038f7d8b740f2415d3a54dc99b69e0598042.tar.zst
New Onboarding (#2596)
* Add round and square buttons

* Allow some style for buttons, add icons

* Change text selection color

* Center button text, whoops

* Outer layout, some primitive updates

* WIP

* onboarding feed prefs (#2590)

* add `style` to toggle label to modify text style

* Revert "add `style` to toggle label to modify text style"

This reverts commit 8f4b517b8585ca64a4bf44f6cb40ac070ece8932.

* following feed prefs

* remove unnecessary memo

* reusable divider component

* org imports

* add finished screen

* Theme SelectedAccountCard

* Require at least 3 interests

* Placeholder save logic

* WIP algo feeds

* Improve lineHeight handling, add RichText, improve Link by adding InlineLink

* Inherit lineHeight in heading comps

* Algo feeds mostly good

* Topical feeds ish

* Layout cleanup

* Improve button styles

* moderation prefs for onboarding (#2594)

* WIP algo feeds

* modify controlalbelgroup typing for easy .map()

* adjust padding on button

* add moderation screen

* add moderation screen

* add moderation screen

---------

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

* Fix toggle button styles

* A11y props on outer portal

* Put it all on red

* New data shape

* Handle mock data

* Bulk write (not yet)

* Remove interests validation

* Clean up interests

* i18n layout and first step

* Clean up suggested follows screen

* Clean up following step

* Clean up algo feeds step

* Clean up topical feeds

* Add skeleton for feed card

* WIP moderation step

* cleanup moderation styles (#2605)

* cleanup moderation styles

* fix(?) toggle button group styles

* adjust toggle to fit any screen

* Some more cleanup

* Icons

* ToggleButton tweaks

* Reset

* Hook up data

* Better suggestions

* Bulk write

* Some logging

* Use new api

* Concat topical feeds

* Metrics

* Disable links in RichText, feedcards

* Tweak primary feed cards

* Update metrics

* Fix layout shift

* Fix ToggleButton again, whoops

* Error state

* Bump api package, ensure interests are saved

* Better fix for autofill

* i18n, button positions

* Remove unused export

* Add default prefs object

* Fix overflow in user cards

* Add 2 lines of bios to suggested accounts cards

* Nits

* Don't resolve facets by default

* Update storybook

* Disable flag for now

* Remove age dialog from moderations step

* Improvements and tweaks to new onboarding

---------

Co-authored-by: Hailey <153161762+haileyok@users.noreply.github.com>
Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Diffstat (limited to 'src/components/RichText.tsx')
-rw-r--r--src/components/RichText.tsx131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/components/RichText.tsx b/src/components/RichText.tsx
new file mode 100644
index 000000000..068ee99e0
--- /dev/null
+++ b/src/components/RichText.tsx
@@ -0,0 +1,131 @@
+import React from 'react'
+import {RichText as RichTextAPI, AppBskyRichtextFacet} from '@atproto/api'
+
+import {atoms as a, TextStyleProp} from '#/alf'
+import {InlineLink} from '#/components/Link'
+import {Text} from '#/components/Typography'
+import {toShortUrl} from 'lib/strings/url-helpers'
+import {getAgent} from '#/state/session'
+
+const WORD_WRAP = {wordWrap: 1}
+
+export function RichText({
+  testID,
+  value,
+  style,
+  numberOfLines,
+  disableLinks,
+  resolveFacets = false,
+}: TextStyleProp & {
+  value: RichTextAPI | string
+  testID?: string
+  numberOfLines?: number
+  disableLinks?: boolean
+  resolveFacets?: boolean
+}) {
+  const detected = React.useRef(false)
+  const [richText, setRichText] = React.useState<RichTextAPI>(() =>
+    value instanceof RichTextAPI ? value : new RichTextAPI({text: value}),
+  )
+  const styles = [a.leading_normal, style]
+
+  React.useEffect(() => {
+    if (!resolveFacets) return
+
+    async function detectFacets() {
+      const rt = new RichTextAPI({text: richText.text})
+      await rt.detectFacets(getAgent())
+      setRichText(rt)
+    }
+
+    if (!detected.current) {
+      detected.current = true
+      detectFacets()
+    }
+  }, [richText, setRichText, resolveFacets])
+
+  const {text, facets} = richText
+
+  if (!facets?.length) {
+    if (text.length <= 5 && /^\p{Extended_Pictographic}+$/u.test(text)) {
+      return (
+        <Text
+          testID={testID}
+          style={[
+            {
+              fontSize: 26,
+              lineHeight: 30,
+            },
+          ]}
+          // @ts-ignore web only -prf
+          dataSet={WORD_WRAP}>
+          {text}
+        </Text>
+      )
+    }
+    return (
+      <Text
+        testID={testID}
+        style={styles}
+        numberOfLines={numberOfLines}
+        // @ts-ignore web only -prf
+        dataSet={WORD_WRAP}>
+        {text}
+      </Text>
+    )
+  }
+
+  const els = []
+  let key = 0
+  // N.B. must access segments via `richText.segments`, not via destructuring
+  for (const segment of richText.segments()) {
+    const link = segment.link
+    const mention = segment.mention
+    if (
+      mention &&
+      AppBskyRichtextFacet.validateMention(mention).success &&
+      !disableLinks
+    ) {
+      els.push(
+        <InlineLink
+          key={key}
+          to={`/profile/${mention.did}`}
+          style={[...styles, {pointerEvents: 'auto'}]}
+          // @ts-ignore TODO
+          dataSet={WORD_WRAP}>
+          {segment.text}
+        </InlineLink>,
+      )
+    } else if (link && AppBskyRichtextFacet.validateLink(link).success) {
+      if (disableLinks) {
+        els.push(toShortUrl(segment.text))
+      } else {
+        els.push(
+          <InlineLink
+            key={key}
+            to={link.uri}
+            style={[...styles, {pointerEvents: 'auto'}]}
+            // @ts-ignore TODO
+            dataSet={WORD_WRAP}
+            warnOnMismatchingLabel>
+            {toShortUrl(segment.text)}
+          </InlineLink>,
+        )
+      }
+    } else {
+      els.push(segment.text)
+    }
+    key++
+  }
+
+  return (
+    <Text
+      testID={testID}
+      style={styles}
+      numberOfLines={numberOfLines}
+      // @ts-ignore web only -prf
+      dataSet={WORD_WRAP}>
+      {els}
+    </Text>
+  )
+}