mirror of
https://github.com/tooot-app/app
synced 2025-03-31 11:50:16 +02:00
Expandable content done
This commit is contained in:
parent
9bfee02484
commit
8986680c6d
1
App.tsx
1
App.tsx
@ -33,7 +33,6 @@ const App: React.FC = () => {
|
||||
<PersistGate persistor={persistor}>
|
||||
{bootstrapped => {
|
||||
if (bootstrapped) {
|
||||
console.log('Bootstrapped!')
|
||||
require('src/i18n/i18n')
|
||||
return (
|
||||
<ThemeManager>
|
||||
|
@ -18,6 +18,7 @@
|
||||
"expo-auth-session": "~2.0.0",
|
||||
"expo-av": "~8.6.0",
|
||||
"expo-image-picker": "~9.1.1",
|
||||
"expo-linear-gradient": "~8.3.0",
|
||||
"expo-localization": "^9.0.0",
|
||||
"expo-secure-store": "~9.2.0",
|
||||
"expo-splash-screen": "~0.6.1",
|
||||
|
1
src/@types/untyped.d.ts
vendored
1
src/@types/untyped.d.ts
vendored
@ -1 +1,2 @@
|
||||
declare module 'react-native-toast-message'
|
||||
declare module 'react-native-htmlview'
|
||||
|
@ -31,7 +31,7 @@ const MenuContainer: React.FC<Props> = ({ ...props }) => {
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
borderTopWidth: 1,
|
||||
marginBottom: StyleConstants.Spacing.Global.PagePadding
|
||||
marginBottom: StyleConstants.Spacing.L
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useCallback } from 'react'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||
import HTMLView from 'react-native-htmlview'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
|
||||
@ -7,12 +7,14 @@ import Emojis from 'src/components/Timelines/Timeline/Shared/Emojis'
|
||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||
import { Feather } from '@expo/vector-icons'
|
||||
import { StyleConstants } from 'src/utils/styles/constants'
|
||||
import { LinearGradient } from 'expo-linear-gradient'
|
||||
|
||||
// Prevent going to the same hashtag multiple times
|
||||
const renderNode = ({
|
||||
theme,
|
||||
node,
|
||||
index,
|
||||
size,
|
||||
navigation,
|
||||
mentions,
|
||||
showFullLink
|
||||
@ -20,6 +22,7 @@ const renderNode = ({
|
||||
theme: any
|
||||
node: any
|
||||
index: number
|
||||
size: number
|
||||
navigation: any
|
||||
mentions?: Mastodon.Mention[]
|
||||
showFullLink: boolean
|
||||
@ -32,7 +35,7 @@ const renderNode = ({
|
||||
return (
|
||||
<Text
|
||||
key={index}
|
||||
style={{ color: theme.link }}
|
||||
style={{ color: theme.link, fontSize: size }}
|
||||
onPress={() => {
|
||||
const tag = href.split(new RegExp(/\/tag\/(.*)|\/tags\/(.*)/))
|
||||
navigation.push('Screen-Shared-Hashtag', {
|
||||
@ -48,7 +51,7 @@ const renderNode = ({
|
||||
return (
|
||||
<Text
|
||||
key={index}
|
||||
style={{ color: theme.link }}
|
||||
style={{ color: theme.link, fontSize: size }}
|
||||
onPress={() => {
|
||||
const username = href.split(new RegExp(/@(.*)/))
|
||||
const usernameIndex = mentions.findIndex(
|
||||
@ -69,7 +72,7 @@ const renderNode = ({
|
||||
return (
|
||||
<Text
|
||||
key={index}
|
||||
style={{ color: theme.link }}
|
||||
style={{ color: theme.link, fontSize: size }}
|
||||
onPress={() => {
|
||||
navigation.navigate('Screen-Shared-Webview', {
|
||||
uri: href,
|
||||
@ -77,11 +80,7 @@ const renderNode = ({
|
||||
})
|
||||
}}
|
||||
>
|
||||
<Feather
|
||||
name='external-link'
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color={theme.link}
|
||||
/>{' '}
|
||||
<Feather name='external-link' size={size} color={theme.link} />{' '}
|
||||
{showFullLink ? href : domain[1]}
|
||||
</Text>
|
||||
)
|
||||
@ -111,7 +110,15 @@ const ParseContent: React.FC<Props> = ({
|
||||
|
||||
const renderNodeCallback = useCallback(
|
||||
(node, index) =>
|
||||
renderNode({ theme, node, index, navigation, mentions, showFullLink }),
|
||||
renderNode({
|
||||
theme,
|
||||
node,
|
||||
index,
|
||||
size,
|
||||
navigation,
|
||||
mentions,
|
||||
showFullLink
|
||||
}),
|
||||
[]
|
||||
)
|
||||
const textComponent = useCallback(
|
||||
@ -124,10 +131,62 @@ const ParseContent: React.FC<Props> = ({
|
||||
[]
|
||||
)
|
||||
const rootComponent = useCallback(({ children }) => {
|
||||
const { theme } = useTheme()
|
||||
const [textLoaded, setTextLoaded] = useState(false)
|
||||
const [totalLines, setTotalLines] = useState<number | undefined>()
|
||||
const [lineHeight, setLineHeight] = useState<number | undefined>()
|
||||
const [shownLines, setShownLines] = useState(numberOfLines)
|
||||
|
||||
return (
|
||||
<Text numberOfLines={numberOfLines} style={styles.root}>
|
||||
{children}
|
||||
</Text>
|
||||
<>
|
||||
<Text
|
||||
numberOfLines={
|
||||
totalLines && totalLines > numberOfLines ? shownLines : totalLines
|
||||
}
|
||||
style={styles.root}
|
||||
onTextLayout={({ nativeEvent }) => {
|
||||
if (!textLoaded) {
|
||||
setTextLoaded(true)
|
||||
setTotalLines(nativeEvent.lines.length)
|
||||
setLineHeight(nativeEvent.lines[0].height)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
{totalLines && lineHeight && totalLines > shownLines && (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
setShownLines(totalLines)
|
||||
}}
|
||||
style={{
|
||||
marginTop: -lineHeight
|
||||
}}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[
|
||||
theme.backgroundGradientStart,
|
||||
theme.backgroundGradientEnd
|
||||
]}
|
||||
locations={[0, lineHeight / (StyleConstants.Font.Size.S * 5)]}
|
||||
style={{
|
||||
paddingTop: StyleConstants.Font.Size.S * 2,
|
||||
paddingBottom: StyleConstants.Font.Size.S
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
fontSize: StyleConstants.Font.Size.S,
|
||||
color: theme.primary
|
||||
}}
|
||||
>
|
||||
展开全文
|
||||
</Text>
|
||||
</LinearGradient>
|
||||
</Pressable>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}, [])
|
||||
|
||||
|
@ -12,13 +12,15 @@ export interface Props {
|
||||
emojis: Mastodon.Emoji[]
|
||||
mentions: Mastodon.Mention[]
|
||||
spoiler_text?: string
|
||||
numberOfLines?: number
|
||||
}
|
||||
|
||||
const Content: React.FC<Props> = ({
|
||||
content,
|
||||
emojis,
|
||||
mentions,
|
||||
spoiler_text
|
||||
spoiler_text,
|
||||
numberOfLines
|
||||
}) => {
|
||||
const { theme } = useTheme()
|
||||
const [spoilerCollapsed, setSpoilerCollapsed] = useState(true)
|
||||
@ -28,11 +30,13 @@ const Content: React.FC<Props> = ({
|
||||
{content &&
|
||||
(spoiler_text ? (
|
||||
<>
|
||||
<Text>
|
||||
<Text style={{ fontSize: StyleConstants.Font.Size.M }}>
|
||||
{spoiler_text}{' '}
|
||||
<Text
|
||||
onPress={() => setSpoilerCollapsed(!spoilerCollapsed)}
|
||||
style={{ color: theme.link }}
|
||||
style={{
|
||||
color: theme.link
|
||||
}}
|
||||
>
|
||||
{spoilerCollapsed ? '点击展开' : '点击收起'}
|
||||
</Text>
|
||||
@ -43,6 +47,7 @@ const Content: React.FC<Props> = ({
|
||||
size={StyleConstants.Font.Size.M}
|
||||
emojis={emojis}
|
||||
mentions={mentions}
|
||||
{...(numberOfLines && { numberOfLines: numberOfLines })}
|
||||
/>
|
||||
</Collapsible>
|
||||
</>
|
||||
@ -52,6 +57,7 @@ const Content: React.FC<Props> = ({
|
||||
size={StyleConstants.Font.Size.M}
|
||||
emojis={emojis}
|
||||
mentions={mentions}
|
||||
{...(numberOfLines && { numberOfLines: numberOfLines })}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
|
@ -5,6 +5,8 @@ export type ColorDefinitions =
|
||||
| 'secondary'
|
||||
| 'disabled'
|
||||
| 'background'
|
||||
| 'backgroundGradientStart'
|
||||
| 'backgroundGradientEnd'
|
||||
| 'link'
|
||||
| 'border'
|
||||
| 'separator'
|
||||
@ -34,6 +36,14 @@ const themeColors: {
|
||||
light: 'rgb(255, 255, 255)',
|
||||
dark: 'rgb(0, 0, 0)'
|
||||
},
|
||||
backgroundGradientStart: {
|
||||
light: 'rgba(255, 255, 255, 0.5)',
|
||||
dark: 'rgba(0, 0, 0, 0.5)'
|
||||
},
|
||||
backgroundGradientEnd: {
|
||||
light: 'rgba(255, 255, 255, 1)',
|
||||
dark: 'rgba(0, 0, 0, 1)'
|
||||
},
|
||||
link: {
|
||||
light: 'rgb(0, 122, 255)',
|
||||
dark: 'rgb(10, 132, 255)'
|
||||
|
@ -1481,11 +1481,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
|
||||
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
|
||||
|
||||
"@types/webpack-env@^1.16.0":
|
||||
version "1.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.0.tgz#8c0a9435dfa7b3b1be76562f3070efb3f92637b4"
|
||||
integrity sha512-Fx+NpfOO0CpeYX2g9bkvX8O5qh9wrU1sOF4g8sft4Mu7z+qfe387YlyY8w8daDyDsKY5vUxM0yxkAYnbkRbZEw==
|
||||
|
||||
"@types/yargs-parser@*":
|
||||
version "15.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
|
||||
|
Loading…
x
Reference in New Issue
Block a user