mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
SELF-908: Add shared WebView screen (#1288)
* feat: add shared webview screen * get react web view working * fix default * fix footer * fix nav header * android layout looks good * fix initial screen * add webview types * fix types and clean error message * remove share logic * cr feedback and tests * fix tests * fix tests
This commit is contained in:
88
app/src/components/NavBar/WebViewNavBar.tsx
Normal file
88
app/src/components/NavBar/WebViewNavBar.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { ExternalLink, X } from '@tamagui/lucide-icons';
|
||||
|
||||
import { Button, XStack } from '@selfxyz/mobile-sdk-alpha/components';
|
||||
|
||||
import { black } from '@/utils/colors';
|
||||
import { dinot } from '@/utils/fonts';
|
||||
import { buttonTap } from '@/utils/haptic';
|
||||
|
||||
export interface WebViewNavBarProps {
|
||||
title?: string;
|
||||
onBackPress: () => void;
|
||||
onOpenExternalPress?: () => void;
|
||||
isOpenExternalDisabled?: boolean;
|
||||
}
|
||||
|
||||
export const WebViewNavBar: React.FC<WebViewNavBarProps> = ({
|
||||
title,
|
||||
onBackPress,
|
||||
onOpenExternalPress,
|
||||
isOpenExternalDisabled,
|
||||
}) => {
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
return (
|
||||
<XStack
|
||||
paddingHorizontal={20}
|
||||
paddingVertical={10}
|
||||
paddingTop={insets.top + 10}
|
||||
gap={14}
|
||||
alignItems="center"
|
||||
backgroundColor="white"
|
||||
>
|
||||
{/* Left: Close Button */}
|
||||
<Button
|
||||
unstyled
|
||||
hitSlop={{ top: 20, bottom: 20, left: 20, right: 10 }}
|
||||
icon={<X size={24} color={black} />}
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
onBackPress();
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Center: Title */}
|
||||
<XStack flex={1} alignItems="center" justifyContent="center">
|
||||
<Text style={styles.title} numberOfLines={1}>
|
||||
{title?.toUpperCase() || 'PAGE TITLE'}
|
||||
</Text>
|
||||
</XStack>
|
||||
|
||||
{/* Right: Open External Button */}
|
||||
<Button
|
||||
unstyled
|
||||
disabled={isOpenExternalDisabled}
|
||||
hitSlop={{ top: 20, bottom: 20, left: 10, right: 20 }}
|
||||
icon={
|
||||
<ExternalLink
|
||||
size={24}
|
||||
color={isOpenExternalDisabled ? black : black}
|
||||
opacity={isOpenExternalDisabled ? 0.3 : 1}
|
||||
/>
|
||||
}
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
onOpenExternalPress?.();
|
||||
}}
|
||||
/>
|
||||
</XStack>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
title: {
|
||||
fontFamily: dinot,
|
||||
fontSize: 15,
|
||||
color: black,
|
||||
letterSpacing: 0.6,
|
||||
textAlign: 'center',
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
});
|
||||
86
app/src/components/WebViewFooter.tsx
Normal file
86
app/src/components/WebViewFooter.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
|
||||
import React from 'react';
|
||||
import { ArrowLeft, ArrowRight, RotateCcw } from '@tamagui/lucide-icons';
|
||||
|
||||
import { Button, XStack, YStack } from '@selfxyz/mobile-sdk-alpha/components';
|
||||
|
||||
import { black, slate50, slate400 } from '@/utils/colors';
|
||||
import { buttonTap } from '@/utils/haptic';
|
||||
|
||||
export interface WebViewFooterProps {
|
||||
canGoBack: boolean;
|
||||
canGoForward: boolean;
|
||||
onGoBack: () => void;
|
||||
onGoForward: () => void;
|
||||
onReload: () => void;
|
||||
onOpenInBrowser: () => void;
|
||||
}
|
||||
|
||||
const iconSize = 22;
|
||||
const buttonSize = 36;
|
||||
|
||||
export const WebViewFooter: React.FC<WebViewFooterProps> = ({
|
||||
canGoBack,
|
||||
canGoForward,
|
||||
onGoBack,
|
||||
onGoForward,
|
||||
onReload,
|
||||
onOpenInBrowser: _onOpenInBrowser,
|
||||
}) => {
|
||||
const renderIconButton = (
|
||||
key: string,
|
||||
icon: React.ReactNode,
|
||||
onPress: () => void,
|
||||
disabled?: boolean,
|
||||
) => (
|
||||
<Button
|
||||
key={key}
|
||||
size="$4"
|
||||
unstyled
|
||||
disabled={disabled}
|
||||
onPress={() => {
|
||||
buttonTap();
|
||||
onPress();
|
||||
}}
|
||||
backgroundColor={slate50}
|
||||
borderRadius={buttonSize / 2}
|
||||
width={buttonSize}
|
||||
height={buttonSize}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
opacity={disabled ? 0.5 : 1}
|
||||
>
|
||||
{icon}
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<YStack gap={12} paddingVertical={12} width="100%">
|
||||
<XStack justifyContent="space-between" alignItems="center" width="100%">
|
||||
{renderIconButton(
|
||||
'back',
|
||||
<ArrowLeft size={iconSize} color={canGoBack ? black : slate400} />,
|
||||
onGoBack,
|
||||
!canGoBack,
|
||||
)}
|
||||
{renderIconButton(
|
||||
'reload',
|
||||
<RotateCcw size={iconSize} color={black} />,
|
||||
onReload,
|
||||
)}
|
||||
{renderIconButton(
|
||||
'forward',
|
||||
<ArrowRight
|
||||
size={iconSize}
|
||||
color={canGoForward ? black : slate400}
|
||||
/>,
|
||||
onGoForward,
|
||||
!canGoForward,
|
||||
)}
|
||||
</XStack>
|
||||
</YStack>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user