Skip to content

Commit

Permalink
feat(rn-settings): impl about page
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Jan 20, 2025
1 parent ca47409 commit fd042e9
Show file tree
Hide file tree
Showing 13 changed files with 271 additions and 90 deletions.
3 changes: 2 additions & 1 deletion apps/mobile/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { DOMProps } from "expo/dom"
import type { FC } from "react"
import type WebView from "react-native-webview"

declare global {
export type WebComponent<P = object> = FC<P & { dom?: DOMProps }>
export type WebComponent<P = object> = FC<P & { dom?: DOMProps } & React.RefAttributes<WebView>>
}
export {}
2 changes: 1 addition & 1 deletion apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"expo-blur": "~14.0.1",
"expo-build-properties": "^0.13.1",
"expo-clipboard": "~7.0.0",
"expo-constants": "~17.0.3",
"expo-constants": "~17.0.4",
"expo-dev-client": "^5.0.9",
"expo-file-system": "~18.0.6",
"expo-font": "~13.0.1",
Expand Down
33 changes: 2 additions & 31 deletions apps/mobile/src/components/common/FollowWebView.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import { callWebviewExpose } from "@follow/shared"
import { parseSafeUrl, transformVideoUrl } from "@follow/utils"
import * as Linking from "expo-linking"
import type { RefObject } from "react"
import { useCallback, useEffect, useState } from "react"
import { Platform } from "react-native"
import type { WebViewNavigation, WebViewProps } from "react-native-webview"
import type { WebViewProps } from "react-native-webview"
import { WebView } from "react-native-webview"

import { useWebViewNavigation } from "@/src/hooks/useWebViewNavigation"
import { signOut } from "@/src/lib/auth"
import { useOpenLink } from "@/src/lib/hooks/use-open-link"

const presetUri = Platform.select({
ios: "rn-web/index.html",
android: "file:///android_asset/raw/index.html",
default: "https://app.follow.is",
})

const allowHosts = new Set(["app.follow.is"])

interface FollowWebViewProps extends WebViewProps {
customUrl?: string
}
Expand Down Expand Up @@ -80,32 +77,6 @@ export const FollowWebView = ({
)
}

const useWebViewNavigation = ({ webViewRef }: { webViewRef: RefObject<WebView> }) => {
const openLink = useOpenLink()

const onNavigationStateChange = useCallback(
(newNavState: WebViewNavigation) => {
const { url: urlStr } = newNavState
const url = parseSafeUrl(urlStr)
if (!url) return
if (url.protocol === "file:") return
if (allowHosts.has(url.host)) return

webViewRef.current?.stopLoading()

const formattedUrl = transformVideoUrl({ url: urlStr })
if (formattedUrl) {
openLink(formattedUrl)
return
}
openLink(urlStr)
},
[openLink, webViewRef],
)

return { onNavigationStateChange }
}

// We only need to handle deep link at the first time the app is opened
let lastInitialUrl: string | null = null
const useDeepLink = ({
Expand Down
17 changes: 17 additions & 0 deletions apps/mobile/src/components/ui/grouped/GroupedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,20 @@ export const GroupedInsetListNavigationLink: FC<{
</Pressable>
)
}

export const GroupedInsetListNavigationLinkIcon: FC<
{
backgroundColor: string
} & PropsWithChildren
> = ({ backgroundColor, children }) => {
return (
<View
className="mr-4 items-center justify-center rounded-[5px] p-1"
style={{
backgroundColor,
}}
>
{children}
</View>
)
}
41 changes: 41 additions & 0 deletions apps/mobile/src/components/ui/typography/Markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { FC } from "react"
import { useRef } from "react"
import { Linking } from "react-native"
import type { WebView } from "react-native-webview"

import MarkdownWeb from "./MarkdownWeb"

export const Markdown: FC<{
value: string
style?: React.CSSProperties
className?: string

webViewProps?: import("expo/dom").DOMProps
}> = ({ value, style, className, webViewProps }) => {
const ref = useRef<WebView>(null)

return (
<MarkdownWeb
value={value}
ref={ref}
style={style}
className={className}
dom={{
...webViewProps,

onMessage: (event) => {
const { type, url } = JSON.parse(event.nativeEvent.data)
if (type === "openLinkInModal") {
Linking.openURL(url)
}
},
injectedJavaScriptBeforeContentLoaded: `window.openLinkInModal = (url) => {
window.ReactNativeWebView.postMessage(JSON.stringify({
type: "openLinkInModal",
url,
}))
}`,
}}
/>
)
}
48 changes: 39 additions & 9 deletions apps/mobile/src/components/ui/typography/MarkdownWeb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,58 @@ import { useDarkMode } from "usehooks-ts"

import { useCSSInjection } from "@/src/theme/web"

const MarkdownWeb: WebComponent<{ value: string; style?: React.CSSProperties }> = ({
value,
style,
}) => {
declare const window: {
openLinkInModal: (url: string) => void
}
/**
* @internal
*/
const MarkdownWeb: WebComponent<{
value: string
style?: React.CSSProperties
className?: string
}> = ({ value, style, className }) => {
useCSSInjection()

const { isDarkMode } = useDarkMode()
return (
<div
className={cn("text-text prose min-w-0", isDarkMode ? "prose-invert" : "prose")}
className={cn("text-text prose min-w-0", isDarkMode ? "prose-invert" : "prose", className)}
style={style}
>
<style
dangerouslySetInnerHTML={{
__html: `
body, html {
overflow: hidden;
}
:root {
overscroll-behavior: none;
}
body, html {
overflow: hidden;
}
`,
}}
/>
{useMemo(() => parseMarkdown(value).content, [value])}
{useMemo(
() =>
parseMarkdown(value, {
components: {
a: ({ children, ...props }) => (
<a
onClick={(e) => {
if (!props.href) return

e.preventDefault()
window.openLinkInModal(props.href)
}}
{...props}
>
{children}
</a>
),
},
}).content,
[value],
)}
</div>
)
}
Expand Down
34 changes: 34 additions & 0 deletions apps/mobile/src/hooks/useWebViewNavigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { parseSafeUrl, transformVideoUrl } from "@follow/utils"
import type { RefObject } from "react"
import { useCallback } from "react"
import type WebView from "react-native-webview"
import type { WebViewNavigation } from "react-native-webview"

import { useOpenLink } from "../lib/hooks/use-open-link"

const allowHosts = new Set(["app.follow.is"])
export function useWebViewNavigation({ webViewRef }: { webViewRef: RefObject<WebView> }) {
const openLink = useOpenLink()

const onNavigationStateChange = useCallback(
(newNavState: WebViewNavigation) => {
const { url: urlStr } = newNavState
const url = parseSafeUrl(urlStr)
if (!url) return
if (url.protocol === "file:") return
if (allowHosts.has(url.host)) return

webViewRef.current?.stopLoading()

const formattedUrl = transformVideoUrl({ url: urlStr })
if (formattedUrl) {
openLink(formattedUrl)
return
}
openLink(urlStr)
},
[openLink, webViewRef],
)

return { onNavigationStateChange }
}
19 changes: 0 additions & 19 deletions apps/mobile/src/modules/settings/SettingNavigationLink.tsx

This file was deleted.

18 changes: 9 additions & 9 deletions apps/mobile/src/modules/settings/SettingsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useSafeAreaInsets } from "react-native-safe-area-context"
import {
GroupedInsetListCard,
GroupedInsetListNavigationLink,
GroupedInsetListNavigationLinkIcon,
} from "@/src/components/ui/grouped/GroupedList"
import { SetBottomTabBarVisibleContext } from "@/src/contexts/BottomTabBarVisibleContext"
import { BellRingingCuteFiIcon } from "@/src/icons/bell_ringing_cute_fi"
Expand All @@ -24,7 +25,6 @@ import { TrophyCuteFiIcon } from "@/src/icons/trophy_cute_fi"
import { User3CuteFiIcon } from "@/src/icons/user_3_cute_fi"

import { useSettingsNavigation } from "./hooks"
import { SettingNavigationLinkIcon } from "./SettingNavigationLink"

interface GroupNavigationLink {
label: string
Expand Down Expand Up @@ -162,9 +162,9 @@ export const SettingsList: FC<{ scrollRef: RefObject<ScrollView> }> = ({ scrollR
key={link.label}
label={link.label}
icon={
<SettingNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
<GroupedInsetListNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
<link.icon height={18} width={18} color="#fff" />
</SettingNavigationLinkIcon>
</GroupedInsetListNavigationLinkIcon>
}
onPress={() => link.onPress(navigation, scrollRef)}
/>
Expand All @@ -178,9 +178,9 @@ export const SettingsList: FC<{ scrollRef: RefObject<ScrollView> }> = ({ scrollR
key={link.label}
label={link.label}
icon={
<SettingNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
<GroupedInsetListNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
<link.icon height={18} width={18} color="#fff" />
</SettingNavigationLinkIcon>
</GroupedInsetListNavigationLinkIcon>
}
onPress={() => link.onPress(navigation, scrollRef)}
/>
Expand All @@ -194,9 +194,9 @@ export const SettingsList: FC<{ scrollRef: RefObject<ScrollView> }> = ({ scrollR
key={link.label}
label={link.label}
icon={
<SettingNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
<GroupedInsetListNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
<link.icon height={18} width={18} color="#fff" />
</SettingNavigationLinkIcon>
</GroupedInsetListNavigationLinkIcon>
}
onPress={() => link.onPress(navigation, scrollRef)}
/>
Expand All @@ -210,9 +210,9 @@ export const SettingsList: FC<{ scrollRef: RefObject<ScrollView> }> = ({ scrollR
key={link.label}
label={link.label}
icon={
<SettingNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
<GroupedInsetListNavigationLinkIcon backgroundColor={link.iconBackgroundColor}>
<link.icon height={18} width={18} color="#fff" />
</SettingNavigationLinkIcon>
</GroupedInsetListNavigationLinkIcon>
}
onPress={() => link.onPress(navigation, scrollRef)}
/>
Expand Down
Loading

0 comments on commit fd042e9

Please sign in to comment.