diff options
Diffstat (limited to 'src/view/com')
-rw-r--r-- | src/view/com/composer/text-input/web/LinkDecorator.ts | 5 | ||||
-rw-r--r-- | src/view/com/composer/text-input/web/TagDecorator.ts | 22 | ||||
-rw-r--r-- | src/view/com/home/HomeHeader.tsx | 2 | ||||
-rw-r--r-- | src/view/com/home/HomeHeaderLayout.web.tsx | 76 | ||||
-rw-r--r-- | src/view/com/home/HomeHeaderLayoutMobile.tsx | 1 | ||||
-rw-r--r-- | src/view/com/util/Link.tsx | 10 | ||||
-rw-r--r-- | src/view/com/util/ViewHeader.tsx | 97 | ||||
-rw-r--r-- | src/view/com/util/moderation/ContentHider.tsx | 2 | ||||
-rw-r--r-- | src/view/com/util/moderation/PostHider.tsx | 2 | ||||
-rw-r--r-- | src/view/com/util/text/RichText.tsx | 1 |
10 files changed, 127 insertions, 91 deletions
diff --git a/src/view/com/composer/text-input/web/LinkDecorator.ts b/src/view/com/composer/text-input/web/LinkDecorator.ts index 19945de08..e36ac80e4 100644 --- a/src/view/com/composer/text-input/web/LinkDecorator.ts +++ b/src/view/com/composer/text-input/web/LinkDecorator.ts @@ -18,6 +18,8 @@ import {Mark} from '@tiptap/core' import {Plugin, PluginKey} from '@tiptap/pm/state' import {Node as ProsemirrorNode} from '@tiptap/pm/model' import {Decoration, DecorationSet} from '@tiptap/pm/view' +import {URL_REGEX} from '@atproto/api' + import {isValidDomain} from 'lib/strings/url-helpers' export const LinkDecorator = Mark.create({ @@ -78,8 +80,7 @@ function linkDecorator() { function iterateUris(str: string, cb: (from: number, to: number) => void) { let match - const re = - /(^|\s|\()((https?:\/\/[\S]+)|((?<domain>[a-z][a-z0-9]*(\.[a-z0-9]+)+)[\S]*))/gim + const re = URL_REGEX while ((match = re.exec(str))) { let uri = match[2] if (!uri.startsWith('http')) { diff --git a/src/view/com/composer/text-input/web/TagDecorator.ts b/src/view/com/composer/text-input/web/TagDecorator.ts index d820ec3f0..2bf3184a8 100644 --- a/src/view/com/composer/text-input/web/TagDecorator.ts +++ b/src/view/com/composer/text-input/web/TagDecorator.ts @@ -18,28 +18,36 @@ import {Mark} from '@tiptap/core' import {Plugin, PluginKey} from '@tiptap/pm/state' import {Node as ProsemirrorNode} from '@tiptap/pm/model' import {Decoration, DecorationSet} from '@tiptap/pm/view' +import {TAG_REGEX, TRAILING_PUNCTUATION_REGEX} from '@atproto/api' function getDecorations(doc: ProsemirrorNode) { const decorations: Decoration[] = [] doc.descendants((node, pos) => { if (node.isText && node.text) { - const regex = /(?:^|\s)(#[^\d\s]\S*)(?=\s)?/g + const regex = TAG_REGEX const textContent = node.textContent let match while ((match = regex.exec(textContent))) { - const [matchedString, tag] = match + const [matchedString, _, tag] = match - if (tag.length > 66) continue + if (!tag || tag.replace(TRAILING_PUNCTUATION_REGEX, '').length > 64) + continue - const [trailingPunc = ''] = tag.match(/\p{P}+$/u) || [] + const [trailingPunc = ''] = tag.match(TRAILING_PUNCTUATION_REGEX) || [] + const matchedFrom = match.index + matchedString.indexOf(tag) + const matchedTo = matchedFrom + (tag.length - trailingPunc.length) - const from = match.index + matchedString.indexOf(tag) - const to = from + (tag.length - trailingPunc.length) + /* + * The match is exclusive of `#` so we need to adjust the start of the + * highlight by -1 to include the `#` + */ + const start = pos + matchedFrom - 1 + const end = pos + matchedTo decorations.push( - Decoration.inline(pos + from, pos + to, { + Decoration.inline(start, end, { class: 'autolink', }), ) diff --git a/src/view/com/home/HomeHeader.tsx b/src/view/com/home/HomeHeader.tsx index bbd16465a..aa3ecb7fc 100644 --- a/src/view/com/home/HomeHeader.tsx +++ b/src/view/com/home/HomeHeader.tsx @@ -52,7 +52,7 @@ export function HomeHeader( ) return ( - <HomeHeaderLayout> + <HomeHeaderLayout tabBarAnchor={props.tabBarAnchor}> <TabBar key={items.join(',')} onPressSelected={props.onPressSelected} diff --git a/src/view/com/home/HomeHeaderLayout.web.tsx b/src/view/com/home/HomeHeaderLayout.web.tsx index fbb55e6bc..6145081af 100644 --- a/src/view/com/home/HomeHeaderLayout.web.tsx +++ b/src/view/com/home/HomeHeaderLayout.web.tsx @@ -1,13 +1,10 @@ import React from 'react' import {StyleSheet, View} from 'react-native' -import Animated from 'react-native-reanimated' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {HomeHeaderLayoutMobile} from './HomeHeaderLayoutMobile' -import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' -import {useShellLayout} from '#/state/shell/shell-layout' import {Logo} from '#/view/icons/Logo' -import {Link, TextLink} from '../util/Link' +import {Link} from '../util/Link' import { FontAwesomeIcon, FontAwesomeIconStyle, @@ -16,41 +13,42 @@ import {useLingui} from '@lingui/react' import {msg} from '@lingui/macro' import {CogIcon} from '#/lib/icons' -export function HomeHeaderLayout({children}: {children: React.ReactNode}) { +export function HomeHeaderLayout(props: { + children: React.ReactNode + tabBarAnchor: JSX.Element | null | undefined +}) { const {isMobile} = useWebMediaQueries() if (isMobile) { - return <HomeHeaderLayoutMobile>{children}</HomeHeaderLayoutMobile> + return <HomeHeaderLayoutMobile {...props} /> } else { - return <HomeHeaderLayoutTablet>{children}</HomeHeaderLayoutTablet> + return <HomeHeaderLayoutDesktopAndTablet {...props} /> } } -function HomeHeaderLayoutTablet({children}: {children: React.ReactNode}) { +function HomeHeaderLayoutDesktopAndTablet({ + children, + tabBarAnchor, +}: { + children: React.ReactNode + tabBarAnchor: JSX.Element | null | undefined +}) { const pal = usePalette('default') - const {headerMinimalShellTransform} = useMinimalShellMode() - const {headerHeight} = useShellLayout() const {_} = useLingui() return ( - // @ts-ignore the type signature for transform wrong here, translateX and translateY need to be in separate objects -prf - <Animated.View - style={[pal.view, pal.border, styles.tabBar, headerMinimalShellTransform]} - onLayout={e => { - headerHeight.value = e.nativeEvent.layout.height - }}> - <View style={[pal.view, styles.topBar]}> - <TextLink - type="title-lg" + <> + <View style={[pal.view, pal.border, styles.bar, styles.topBar]}> + <Link href="/settings/following-feed" + hitSlop={10} + accessibilityRole="button" accessibilityLabel={_(msg`Following Feed Preferences`)} - accessibilityHint="" - text={ - <FontAwesomeIcon - icon="sliders" - style={pal.textLight as FontAwesomeIconStyle} - /> - } - /> + accessibilityHint=""> + <FontAwesomeIcon + icon="sliders" + style={pal.textLight as FontAwesomeIconStyle} + /> + </Link> <Logo width={28} /> <Link href="/settings/saved-feeds" @@ -61,32 +59,38 @@ function HomeHeaderLayoutTablet({children}: {children: React.ReactNode}) { <CogIcon size={22} strokeWidth={2} style={pal.textLight} /> </Link> </View> - {children} - </Animated.View> + {tabBarAnchor} + <View style={[pal.view, pal.border, styles.bar, styles.tabBar]}> + {children} + </View> + </> ) } const styles = StyleSheet.create({ + bar: { + // @ts-ignore Web only + left: 'calc(50% - 300px)', + width: 600, + borderLeftWidth: 1, + borderRightWidth: 1, + }, topBar: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 18, - paddingVertical: 8, - marginTop: 8, - width: '100%', + paddingTop: 16, + paddingBottom: 8, }, tabBar: { // @ts-ignore Web only position: 'sticky', - zIndex: 1, - // @ts-ignore Web only -prf - left: 'calc(50% - 300px)', - width: 600, top: 0, flexDirection: 'column', alignItems: 'center', borderLeftWidth: 1, borderRightWidth: 1, + zIndex: 1, }, }) diff --git a/src/view/com/home/HomeHeaderLayoutMobile.tsx b/src/view/com/home/HomeHeaderLayoutMobile.tsx index f51efb7b4..d7b7231c6 100644 --- a/src/view/com/home/HomeHeaderLayoutMobile.tsx +++ b/src/view/com/home/HomeHeaderLayoutMobile.tsx @@ -23,6 +23,7 @@ export function HomeHeaderLayoutMobile({ children, }: { children: React.ReactNode + tabBarAnchor: JSX.Element | null | undefined }) { const pal = usePalette('default') const {_} = useLingui() diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx index d52d3c0e6..e50fb7f09 100644 --- a/src/view/com/util/Link.tsx +++ b/src/view/com/util/Link.tsx @@ -159,7 +159,7 @@ export const TextLink = memo(function TextLink({ dataSet, title, onPress, - warnOnMismatchingLabel, + disableMismatchWarning, navigationAction, ...orgProps }: { @@ -172,7 +172,7 @@ export const TextLink = memo(function TextLink({ lineHeight?: number dataSet?: any title?: string - warnOnMismatchingLabel?: boolean + disableMismatchWarning?: boolean navigationAction?: 'push' | 'replace' | 'navigate' } & TextProps) { const {...props} = useLinkProps({to: sanitizeUrl(href)}) @@ -180,14 +180,14 @@ export const TextLink = memo(function TextLink({ const {openModal, closeModal} = useModalControls() const openLink = useOpenLink() - if (warnOnMismatchingLabel && typeof text !== 'string') { + if (!disableMismatchWarning && typeof text !== 'string') { console.error('Unable to detect mismatching label') } props.onPress = React.useCallback( (e?: Event) => { const requiresWarning = - warnOnMismatchingLabel && + !disableMismatchWarning && linkRequiresWarning(href, typeof text === 'string' ? text : '') if (requiresWarning) { e?.preventDefault?.() @@ -227,7 +227,7 @@ export const TextLink = memo(function TextLink({ navigation, href, text, - warnOnMismatchingLabel, + disableMismatchWarning, navigationAction, openLink, ], diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx index 1ccfcf56c..872e10eef 100644 --- a/src/view/com/util/ViewHeader.tsx +++ b/src/view/com/util/ViewHeader.tsx @@ -13,11 +13,13 @@ import Animated from 'react-native-reanimated' import {useSetDrawerOpen} from '#/state/shell' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {useTheme} from '#/alf' const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} export function ViewHeader({ title, + subtitle, canGoBack, showBackButton = true, hideOnScroll, @@ -26,6 +28,7 @@ export function ViewHeader({ renderButton, }: { title: string + subtitle?: string canGoBack?: boolean showBackButton?: boolean hideOnScroll?: boolean @@ -39,6 +42,7 @@ export function ViewHeader({ const navigation = useNavigation<NavigationProp>() const {track} = useAnalytics() const {isDesktop, isTablet} = useWebMediaQueries() + const t = useTheme() const onPressBack = React.useCallback(() => { if (navigation.canGoBack()) { @@ -71,42 +75,60 @@ export function ViewHeader({ return ( <Container hideOnScroll={hideOnScroll || false} showBorder={showBorder}> - {showBackButton ? ( - <TouchableOpacity - testID="viewHeaderDrawerBtn" - onPress={canGoBack ? onPressBack : onPressMenu} - hitSlop={BACK_HITSLOP} - style={canGoBack ? styles.backBtn : styles.backBtnWide} - accessibilityRole="button" - accessibilityLabel={canGoBack ? _(msg`Back`) : _(msg`Menu`)} - accessibilityHint={ - canGoBack ? '' : _(msg`Access navigation links and settings`) - }> - {canGoBack ? ( - <FontAwesomeIcon - size={18} - icon="angle-left" - style={[styles.backIcon, pal.text]} - /> - ) : !isTablet ? ( - <FontAwesomeIcon - size={18} - icon="bars" - style={[styles.backIcon, pal.textLight]} - /> + <View style={{flex: 1}}> + <View style={{flexDirection: 'row', alignItems: 'center'}}> + {showBackButton ? ( + <TouchableOpacity + testID="viewHeaderDrawerBtn" + onPress={canGoBack ? onPressBack : onPressMenu} + hitSlop={BACK_HITSLOP} + style={canGoBack ? styles.backBtn : styles.backBtnWide} + accessibilityRole="button" + accessibilityLabel={canGoBack ? _(msg`Back`) : _(msg`Menu`)} + accessibilityHint={ + canGoBack ? '' : _(msg`Access navigation links and settings`) + }> + {canGoBack ? ( + <FontAwesomeIcon + size={18} + icon="angle-left" + style={[styles.backIcon, pal.text]} + /> + ) : !isTablet ? ( + <FontAwesomeIcon + size={18} + icon="bars" + style={[styles.backIcon, pal.textLight]} + /> + ) : null} + </TouchableOpacity> ) : null} - </TouchableOpacity> - ) : null} - <View style={styles.titleContainer} pointerEvents="none"> - <Text type="title" style={[pal.text, styles.title]}> - {title} - </Text> + <View style={styles.titleContainer} pointerEvents="none"> + <Text type="title" style={[pal.text, styles.title]}> + {title} + </Text> + </View> + {renderButton ? ( + renderButton() + ) : showBackButton ? ( + <View style={canGoBack ? styles.backBtn : styles.backBtnWide} /> + ) : null} + </View> + {subtitle ? ( + <View + style={[styles.titleContainer, {marginTop: -3}]} + pointerEvents="none"> + <Text + style={[ + pal.text, + styles.subtitle, + t.atoms.text_contrast_medium, + ]}> + {subtitle} + </Text> + </View> + ) : undefined} </View> - {renderButton ? ( - renderButton() - ) : showBackButton ? ( - <View style={canGoBack ? styles.backBtn : styles.backBtnWide} /> - ) : null} </Container> ) } @@ -185,7 +207,6 @@ function Container({ const styles = StyleSheet.create({ header: { flexDirection: 'row', - alignItems: 'center', paddingHorizontal: 12, paddingVertical: 6, width: '100%', @@ -207,12 +228,14 @@ const styles = StyleSheet.create({ titleContainer: { marginLeft: 'auto', marginRight: 'auto', - paddingRight: 10, + alignItems: 'center', }, title: { fontWeight: 'bold', }, - + subtitle: { + fontSize: 13, + }, backBtn: { width: 30, height: 30, diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx index b3a563116..cd2545290 100644 --- a/src/view/com/util/moderation/ContentHider.tsx +++ b/src/view/com/util/moderation/ContentHider.tsx @@ -46,7 +46,7 @@ export function ContentHider({ ) } - const isMute = moderation.cause?.type === 'muted' + const isMute = ['muted', 'muted-word'].includes(moderation.cause?.type || '') const desc = describeModerationCause(moderation.cause, 'content') return ( <View testID={testID} style={[styles.outer, style]}> diff --git a/src/view/com/util/moderation/PostHider.tsx b/src/view/com/util/moderation/PostHider.tsx index b1fa71d4a..ede62e988 100644 --- a/src/view/com/util/moderation/PostHider.tsx +++ b/src/view/com/util/moderation/PostHider.tsx @@ -47,7 +47,7 @@ export function PostHider({ ) } - const isMute = moderation.cause?.type === 'muted' + const isMute = ['muted', 'muted-word'].includes(moderation.cause?.type || '') const desc = describeModerationCause(moderation.cause, 'content') return !override ? ( <Pressable diff --git a/src/view/com/util/text/RichText.tsx b/src/view/com/util/text/RichText.tsx index 0ec3f3181..f4ade30e5 100644 --- a/src/view/com/util/text/RichText.tsx +++ b/src/view/com/util/text/RichText.tsx @@ -114,7 +114,6 @@ export function RichText({ href={link.uri} style={[style, lineHeightStyle, pal.link, {pointerEvents: 'auto'}]} dataSet={WORD_WRAP} - warnOnMismatchingLabel selectable={selectable} />, ) |