[add] Scaffold redesign
This commit is contained in:
@@ -23,7 +23,6 @@ import { AccessTokenResponseHandler } from './models/AccessTokenResponse';
|
||||
import * as yup from 'yup';
|
||||
import { base64ToBlob } from './utils/base64ToBlob';
|
||||
import { ImagePickerAsset } from 'expo-image-picker';
|
||||
import Constant from 'expo-constants';
|
||||
|
||||
type AuthenticationInput = { username: string; password: string };
|
||||
type RegistrationInput = AuthenticationInput & { email: string };
|
||||
@@ -69,7 +68,7 @@ export default class API {
|
||||
public static readonly baseUrl =
|
||||
process.env.NODE_ENV != 'development' && Platform.OS === 'web'
|
||||
? '/api'
|
||||
: "https://nightly.chroma.octohub.app/api";
|
||||
: 'https://nightly.chroma.octohub.app/api';
|
||||
public static async fetch(
|
||||
params: FetchParams,
|
||||
handle: Pick<Required<HandleParams>, 'raw'>
|
||||
|
||||
@@ -32,9 +32,10 @@ import GoogleView from './views/GoogleView';
|
||||
import VerifiedView from './views/VerifiedView';
|
||||
import SigninView from './views/SigninView';
|
||||
import SignupView from './views/SignupView';
|
||||
import TabNavigation from './components/V2/TabNavigation';
|
||||
import PasswordResetView from './views/PasswordResetView';
|
||||
import ForgotPasswordView from './views/ForgotPasswordView';
|
||||
import ScaffoldCC from './components/UI/Scaffold';
|
||||
import DiscoveryView from './views/V2/DiscoveryView';
|
||||
|
||||
// Util function to hide route props in URL
|
||||
const removeMe = () => '';
|
||||
@@ -43,18 +44,18 @@ const protectedRoutes = () =>
|
||||
({
|
||||
Home: {
|
||||
component: HomeView,
|
||||
options: { title: translate('welcome'), headerLeft: null },
|
||||
options: { headerShown: false },
|
||||
link: '/',
|
||||
},
|
||||
HomeNew: {
|
||||
component: TabNavigation,
|
||||
component: DiscoveryView,
|
||||
options: { headerShown: false },
|
||||
link: '/V2',
|
||||
},
|
||||
Play: { component: PlayView, options: { title: translate('play') }, link: '/play/:songId' },
|
||||
Settings: {
|
||||
component: SetttingsNavigator,
|
||||
options: { title: 'Settings' },
|
||||
options: { headerShown: false },
|
||||
link: '/settings/:screen?',
|
||||
stringify: {
|
||||
screen: removeMe,
|
||||
@@ -82,7 +83,7 @@ const protectedRoutes = () =>
|
||||
},
|
||||
Search: {
|
||||
component: SearchView,
|
||||
options: { title: translate('search') },
|
||||
options: { headerShown: false },
|
||||
link: '/search/:query?',
|
||||
},
|
||||
Error: {
|
||||
@@ -90,7 +91,7 @@ const protectedRoutes = () =>
|
||||
options: { title: translate('error'), headerLeft: null },
|
||||
link: undefined,
|
||||
},
|
||||
User: { component: ProfileView, options: { title: translate('user') }, link: '/user' },
|
||||
User: { component: ProfileView, options: { headerShown: false }, link: '/user' },
|
||||
Verified: {
|
||||
component: VerifiedView,
|
||||
options: { title: 'Verify email', headerShown: false },
|
||||
@@ -164,9 +165,13 @@ const RouteToScreen =
|
||||
(props: NativeStackScreenProps<T & ParamListBase>) =>
|
||||
(
|
||||
<>
|
||||
{component({ ...props.route.params, route: props.route } as Parameters<
|
||||
Route<T>['component']
|
||||
>[0])}
|
||||
<ScaffoldCC routeName={props.route.name}>
|
||||
<>
|
||||
{component({ ...props.route.params, route: props.route } as Parameters<
|
||||
Route<T>['component']
|
||||
>[0])}
|
||||
</>
|
||||
</ScaffoldCC>
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ interface ButtonProps {
|
||||
onPress?: () => Promise<void>;
|
||||
isDisabled?: boolean;
|
||||
icon?: Icon;
|
||||
iconVariant?: 'Bold' | 'Outline';
|
||||
iconImage?: string;
|
||||
type?: 'filled' | 'outlined' | 'menu';
|
||||
}
|
||||
@@ -22,6 +23,7 @@ const ButtonBase: React.FC<ButtonProps> = ({
|
||||
icon,
|
||||
iconImage,
|
||||
type = 'filled',
|
||||
iconVariant = 'Outline',
|
||||
}) => {
|
||||
const { colors } = useTheme();
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -60,10 +62,10 @@ const ButtonBase: React.FC<ButtonProps> = ({
|
||||
const styleMenu = StyleSheet.create({
|
||||
Default: {
|
||||
scale: 1,
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 4.65,
|
||||
elevation: 8,
|
||||
backgroundColor: 'rgba(16,16,20,0.5)',
|
||||
shadowOpacity: 0,
|
||||
shadowRadius: 0,
|
||||
elevation: 0,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
onHover: {
|
||||
scale: 1.01,
|
||||
@@ -112,9 +114,18 @@ const ButtonBase: React.FC<ButtonProps> = ({
|
||||
color={type === 'outlined' ? '#6075F9' : '#FFFFFF'}
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.content}>
|
||||
<View
|
||||
style={[
|
||||
styles.content,
|
||||
type === 'menu' ? { justifyContent: 'flex-start' } : {},
|
||||
]}
|
||||
>
|
||||
{icon && (
|
||||
<MyIcon size={'18'} color={type === 'outlined' ? '#6075F9' : '#FFFFFF'} />
|
||||
<MyIcon
|
||||
size={'18'}
|
||||
color={type === 'outlined' ? '#6075F9' : '#FFFFFF'}
|
||||
variant={iconVariant}
|
||||
/>
|
||||
)}
|
||||
{iconImage && <Image source={{ uri: iconImage }} style={styles.icon} />}
|
||||
{title && <Text style={styles.text}>{title}</Text>}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
|
||||
import InteractiveBase from './InteractiveBase';
|
||||
import { Checkbox, useTheme, Text } from 'native-base';
|
||||
import { useTheme, Text } from 'native-base';
|
||||
import { AddSquare, TickSquare } from 'iconsax-react-native';
|
||||
|
||||
interface CheckboxProps {
|
||||
@@ -12,13 +12,7 @@ interface CheckboxProps {
|
||||
style?: StyleProp<ViewStyle>;
|
||||
}
|
||||
|
||||
const CheckboxBase: React.FC<CheckboxProps> = ({
|
||||
title,
|
||||
color,
|
||||
style,
|
||||
check,
|
||||
setCheck,
|
||||
}) => {
|
||||
const CheckboxBase: React.FC<CheckboxProps> = ({ title, color, style, check, setCheck }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<InteractiveBase
|
||||
@@ -29,13 +23,22 @@ const CheckboxBase: React.FC<CheckboxProps> = ({
|
||||
}}
|
||||
>
|
||||
<View style={styles.content}>
|
||||
{
|
||||
check ?
|
||||
<TickSquare size="24" color={color ? color : theme.colors.primary[400]} variant="Bold"/>
|
||||
: <AddSquare size="24" color={color ? color : theme.colors.primary[400]} variant="Outline"/>
|
||||
|
||||
}
|
||||
<Text style={styles.text} selectable={false}>{title}</Text>
|
||||
{check ? (
|
||||
<TickSquare
|
||||
size="24"
|
||||
color={color ? color : theme.colors.primary[400]}
|
||||
variant="Bold"
|
||||
/>
|
||||
) : (
|
||||
<AddSquare
|
||||
size="24"
|
||||
color={color ? color : theme.colors.primary[400]}
|
||||
variant="Outline"
|
||||
/>
|
||||
)}
|
||||
<Text style={styles.text} selectable={false}>
|
||||
{title}
|
||||
</Text>
|
||||
</View>
|
||||
</InteractiveBase>
|
||||
);
|
||||
@@ -84,8 +87,8 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: 5,
|
||||
},
|
||||
text: {
|
||||
paddingLeft: 10
|
||||
}
|
||||
paddingLeft: 10,
|
||||
},
|
||||
});
|
||||
|
||||
export default CheckboxBase;
|
||||
|
||||
266
front/components/UI/Scaffold.tsx
Normal file
266
front/components/UI/Scaffold.tsx
Normal file
@@ -0,0 +1,266 @@
|
||||
import { View, Image } from 'react-native';
|
||||
import { Divider, Text, ScrollView, Flex, Row, Popover, Heading, Button } from 'native-base';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
import { useQuery, useQueries } from '../../Queries';
|
||||
import API from '../../API';
|
||||
import Song from '../../models/Song';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import ButtonBase from './ButtonBase';
|
||||
import {
|
||||
Cup,
|
||||
Discover,
|
||||
Icon,
|
||||
LogoutCurve,
|
||||
Music,
|
||||
SearchNormal1,
|
||||
Setting2,
|
||||
User,
|
||||
} from 'iconsax-react-native';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { LoadingView } from '../Loading';
|
||||
import { translate } from '../../i18n/i18n';
|
||||
import { unsetAccessToken } from '../../state/UserSlice';
|
||||
import { useNavigation } from '../../Navigation';
|
||||
import Spacer from './Spacer';
|
||||
|
||||
const menu: {
|
||||
title: string;
|
||||
icon: Icon;
|
||||
link: string;
|
||||
}[] = [
|
||||
{ title: 'Discovery', icon: Discover, link: 'HomeNew' },
|
||||
{ title: 'Profile', icon: User, link: 'User' },
|
||||
{ title: 'Music', icon: Music, link: 'Home' },
|
||||
{ title: 'Search', icon: SearchNormal1, link: 'Search' },
|
||||
{ title: 'LeaderBoard', icon: Cup, link: 'Score' },
|
||||
];
|
||||
|
||||
type ScaffoldCCProps = {
|
||||
children?: React.ReactNode;
|
||||
routeName: string;
|
||||
};
|
||||
|
||||
const ScaffoldCC = (props: ScaffoldCCProps) => {
|
||||
const navigation = useNavigation();
|
||||
const userQuery = useQuery(API.getUserInfo);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
if (!userQuery.data || userQuery.isLoading) {
|
||||
return <LoadingView />;
|
||||
}
|
||||
const user = userQuery.data;
|
||||
const colorScheme = useColorScheme();
|
||||
const icon =
|
||||
colorScheme == 'light'
|
||||
? require('../../assets/icon_light.png')
|
||||
: require('../../assets/icon_dark.png');
|
||||
const playHistoryQuery = useQuery(API.getUserPlayHistory);
|
||||
const songHistory = useQueries(
|
||||
playHistoryQuery.data?.map(({ songID }) => API.getSong(songID)) ?? []
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex style={{ flex: 1 }}>
|
||||
<View style={{ height: '100%', flexDirection: 'row', overflow: 'hidden' }}>
|
||||
<View
|
||||
style={{
|
||||
display: 'flex',
|
||||
width: '300px',
|
||||
height: '100vh',
|
||||
maxHeight: '100vh',
|
||||
padding: '32px',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-start',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<View style={{ width: '100%' }}>
|
||||
<Row>
|
||||
<Image
|
||||
source={{ uri: icon }}
|
||||
style={{
|
||||
aspectRatio: 1,
|
||||
width: '40px',
|
||||
height: 'auto',
|
||||
marginRight: '10px',
|
||||
}}
|
||||
/>
|
||||
<Spacer width="xs" />
|
||||
<Text fontSize={'2xl'} selectable={false}>
|
||||
Chromacase
|
||||
</Text>
|
||||
</Row>
|
||||
<Spacer height="xl" />
|
||||
<View style={{ width: '100%' }}>
|
||||
{menu.map((value) => (
|
||||
<View key={'key-menu-link-' + value.title}>
|
||||
<ButtonBase
|
||||
style={{ width: '100%' }}
|
||||
type="menu"
|
||||
icon={value.icon}
|
||||
title={value.title}
|
||||
isDisabled={props.routeName === value.link}
|
||||
iconVariant={
|
||||
props.routeName === value.link ? 'Bold' : 'Outline'
|
||||
}
|
||||
onPress={async () =>
|
||||
navigation.navigate(value.link as never)
|
||||
}
|
||||
/>
|
||||
<Spacer />
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
<View style={{ width: '100%' }}>
|
||||
<Divider />
|
||||
<Spacer />
|
||||
<Text
|
||||
bold
|
||||
style={{
|
||||
paddingHorizontal: '16px',
|
||||
paddingVertical: '10px',
|
||||
fontSize: 20,
|
||||
}}
|
||||
>
|
||||
Recently played
|
||||
</Text>
|
||||
{songHistory.length === 0 && (
|
||||
<Text
|
||||
style={{
|
||||
paddingHorizontal: '16px',
|
||||
paddingVertical: '10px',
|
||||
}}
|
||||
>
|
||||
No songs played yet
|
||||
</Text>
|
||||
)}
|
||||
{songHistory
|
||||
.map((h) => h.data)
|
||||
.filter((data): data is Song => data !== undefined)
|
||||
.filter(
|
||||
(song, i, array) =>
|
||||
array.map((s) => s.id).findIndex((id) => id == song.id) == i
|
||||
)
|
||||
.slice(0, 4)
|
||||
.map((histoItem, index) => (
|
||||
<View
|
||||
key={'tab-navigation-other-' + index}
|
||||
style={{
|
||||
paddingHorizontal: '16px',
|
||||
paddingVertical: '10px',
|
||||
}}
|
||||
>
|
||||
<Text numberOfLines={1}>{histoItem.name}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
<Spacer />
|
||||
<View style={{ width: '100%' }}>
|
||||
<Divider />
|
||||
<Spacer />
|
||||
<ButtonBase
|
||||
style={{ width: '100%' }}
|
||||
title="Settings"
|
||||
icon={Setting2}
|
||||
type="menu"
|
||||
isDisabled={props.routeName === 'Settings'}
|
||||
iconVariant={props.routeName === 'Settings' ? 'Bold' : 'Outline'}
|
||||
onPress={async () => navigation.navigate('Settings')}
|
||||
/>
|
||||
<Spacer />
|
||||
{!user.isGuest && (
|
||||
<ButtonBase
|
||||
style={{ width: '100%' }}
|
||||
icon={LogoutCurve}
|
||||
title={translate('signOutBtn')}
|
||||
type="menu"
|
||||
onPress={async () => {
|
||||
dispatch(unsetAccessToken());
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{user.isGuest && (
|
||||
<Popover
|
||||
trigger={(triggerProps) => (
|
||||
<ButtonBase {...triggerProps}>
|
||||
{translate('signOutBtn')}
|
||||
</ButtonBase>
|
||||
)}
|
||||
>
|
||||
<Popover.Content>
|
||||
<Popover.Arrow />
|
||||
<Popover.Body>
|
||||
<Heading size="md" mb={2}>
|
||||
{translate('Attention')}
|
||||
</Heading>
|
||||
<Text>
|
||||
{translate(
|
||||
'YouAreCurrentlyConnectedWithAGuestAccountWarning'
|
||||
)}
|
||||
</Text>
|
||||
<Button.Group variant="ghost" space={2}>
|
||||
<Button
|
||||
onPress={() => dispatch(unsetAccessToken())}
|
||||
colorScheme="red"
|
||||
>
|
||||
{translate('signOutBtn')}
|
||||
</Button>
|
||||
<Button
|
||||
onPress={() => {
|
||||
navigation.navigate('Login');
|
||||
}}
|
||||
colorScheme="green"
|
||||
>
|
||||
{translate('signUpBtn')}
|
||||
</Button>
|
||||
</Button.Group>
|
||||
</Popover.Body>
|
||||
</Popover.Content>
|
||||
</Popover>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<ScrollView
|
||||
style={{ flex: 1, maxHeight: '100vh' }}
|
||||
contentContainerStyle={{ flex: 1 }}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: 'rgba(16,16,20,0.5)',
|
||||
flex: 1,
|
||||
margin: 8,
|
||||
padding: 20,
|
||||
borderRadius: 12,
|
||||
minHeight: 'fit-content',
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
<LinearGradient
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
colors={['#101014', '#6075F9']}
|
||||
style={{
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
minHeight: 'fit-content',
|
||||
minWidth: 'fit-content',
|
||||
flex: 1,
|
||||
position: 'absolute',
|
||||
zIndex: -2,
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScaffoldCC;
|
||||
31
front/components/UI/Spacer.tsx
Normal file
31
front/components/UI/Spacer.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { View } from 'native-base';
|
||||
|
||||
type SpacerProps = {
|
||||
width?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
||||
height?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
||||
};
|
||||
|
||||
const Spacer = ({ width = 'md', height = 'md' }: SpacerProps) => {
|
||||
const str2size = (str: string) => {
|
||||
switch (str) {
|
||||
case 'xs':
|
||||
return 8;
|
||||
case 'sm':
|
||||
return 16;
|
||||
case 'md':
|
||||
return 20;
|
||||
case 'lg':
|
||||
return 32;
|
||||
case 'xl':
|
||||
return 40;
|
||||
case '2xl':
|
||||
return 80;
|
||||
default:
|
||||
return 20;
|
||||
}
|
||||
};
|
||||
|
||||
return <View style={{ height: str2size(height), width: str2size(width) }}></View>;
|
||||
};
|
||||
|
||||
export default Spacer;
|
||||
@@ -5,7 +5,7 @@ import TabNavigationPhone from './TabNavigationPhone';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import React, { useState } from 'react';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
import HomeView from '../../views/V2/HomeView';
|
||||
import HomeView from '../../views/V2/DiscoveryView';
|
||||
|
||||
export type NaviTab = {
|
||||
id: string;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { useQueries, useQuery } from '../Queries';
|
||||
import API from '../API';
|
||||
import { LoadingView } from '../components/Loading';
|
||||
import { Box, ScrollView, Flex, Stack, Heading, VStack, HStack } from 'native-base';
|
||||
import { Box, Flex, Stack, Heading, VStack, HStack } from 'native-base';
|
||||
import { useNavigation } from '../Navigation';
|
||||
import SongCardGrid from '../components/SongCardGrid';
|
||||
import CompetenciesTable from '../components/CompetenciesTable';
|
||||
@@ -39,7 +39,7 @@ const HomeView = () => {
|
||||
return <LoadingView />;
|
||||
}
|
||||
return (
|
||||
<ScrollView p={10}>
|
||||
<Flex>
|
||||
<Flex>
|
||||
<Stack
|
||||
space={4}
|
||||
@@ -59,7 +59,7 @@ const HomeView = () => {
|
||||
</Box>
|
||||
</Stack>
|
||||
</Flex>
|
||||
<Stack direction={{ base: 'column', lg: 'row' }} height="100%" space={5} paddingTop={5}>
|
||||
<Stack direction={{ base: 'column', lg: 'row' }} space={5} paddingTop={5}>
|
||||
<VStack flex={{ lg: 2 }} space={5}>
|
||||
<SongCardGrid
|
||||
heading={<Translate translationKey="goNextStep" />}
|
||||
@@ -182,7 +182,7 @@ const HomeView = () => {
|
||||
</Box>
|
||||
</VStack>
|
||||
</Stack>
|
||||
</ScrollView>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import UserAvatar from '../components/UserAvatar';
|
||||
import { LoadingView } from '../components/Loading';
|
||||
import { useQuery } from '../Queries';
|
||||
import API from '../API';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import ButtonBase from '../components/UI/ButtonBase';
|
||||
import { translate } from '../i18n/i18n';
|
||||
import ScoreGraph from '../components/ScoreGraph';
|
||||
@@ -737,7 +736,7 @@ const ProfileView = () => {
|
||||
const level = xpToLevel(userQuery.data.data.xp);
|
||||
|
||||
return (
|
||||
<Flex style={{ minHeight: layout.height, height: '100%', padding: 20 }}>
|
||||
<Flex>
|
||||
<Wrap
|
||||
style={{
|
||||
flexDirection: layout.width > 650 ? 'row' : 'column',
|
||||
@@ -799,23 +798,6 @@ const ProfileView = () => {
|
||||
best: 200,
|
||||
}}
|
||||
/>
|
||||
<LinearGradient
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
colors={['#101014', '#6075F9']}
|
||||
style={{
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '180%', // TODO Need to fixe the background
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'absolute',
|
||||
zIndex: -2,
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -99,7 +99,7 @@ const SigninView = () => {
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
isSecret
|
||||
isSecret
|
||||
/>,
|
||||
<LinkBase key={'signin-link'} onPress={() => navigation.navigate('ForgotPassword')}>
|
||||
{translate('forgottenPassword')}
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
FolderCross,
|
||||
} from 'iconsax-react-native';
|
||||
import { Scene } from 'react-native-tab-view/lib/typescript/src/types';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import PremiumSettings from './SettingsPremiumView';
|
||||
|
||||
export const PianoSettingsView = () => {
|
||||
@@ -100,7 +99,7 @@ const SetttingsNavigator = () => {
|
||||
);
|
||||
}}
|
||||
renderLabel={({ route, color }) =>
|
||||
layout.width > 750 ? (
|
||||
layout.width > 1100 ? (
|
||||
<Text style={{ color, paddingLeft: 10, overflow: 'hidden' }}>
|
||||
{route.title}
|
||||
</Text>
|
||||
@@ -111,32 +110,15 @@ const SetttingsNavigator = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={{ width: '100%' }}>
|
||||
<TabView
|
||||
style={{ minHeight: layout.height, height: '100%', paddingBottom: 32 }}
|
||||
style={{ height: 'fit-content' }}
|
||||
renderTabBar={renderTabBar}
|
||||
navigationState={{ index, routes }}
|
||||
renderScene={renderScene}
|
||||
onIndexChange={setIndex}
|
||||
initialLayout={{ width: layout.width }}
|
||||
/>
|
||||
<LinearGradient
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
colors={['#101014', '#6075F9']}
|
||||
style={{
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'absolute',
|
||||
zIndex: -2,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user