Add the desktop scaffold

This commit is contained in:
2024-01-06 14:38:47 +01:00
committed by Clément Le Bihan
parent fa60fc65a9
commit a3659618ea
5 changed files with 146 additions and 183 deletions
-69
View File
@@ -1,69 +0,0 @@
import { Flex, useBreakpointValue } from 'native-base';
import useColorScheme from '../../hooks/colorScheme';
import { useQuery } from '../../Queries';
import API from '../../API';
import { LinearGradient } from 'expo-linear-gradient';
import { Cup, Discover, Music, SearchNormal1, Setting2, User } from 'iconsax-react-native';
import { LoadingView } from '../Loading';
import ScaffoldDesktopCC from './ScaffoldDesktopCC';
import ScaffoldMobileCC from './ScaffoldMobileCC';
import { useAssets } from 'expo-asset';
const menu = [
{ type: 'main', title: 'menuDiscovery', icon: Discover, link: 'Home' },
{ type: 'main', title: 'menuProfile', icon: User, link: 'User' },
{ type: 'main', title: 'menuMusic', icon: Music, link: 'Music' },
{ type: 'main', title: 'menuSearch', icon: SearchNormal1, link: 'Search' },
{ type: 'main', title: 'menuLeaderBoard', icon: Cup, link: 'Leaderboard' },
{ type: 'sub', title: 'menuSettings', icon: Setting2, link: 'Settings' },
] as const;
type ScaffoldCCProps = {
children?: React.ReactNode;
routeName: string;
withPadding?: boolean;
enableScroll?: boolean;
};
const ScaffoldCC = ({
children,
routeName,
}: ScaffoldCCProps) => {
const userQuery = useQuery(API.getUserInfo);
const screenSize = useBreakpointValue({ base: 'small', md: 'big' });
if (!userQuery.data || userQuery.isLoading) {
return <LoadingView />;
}
const colorScheme = useColorScheme();
const [logo] = useAssets(
colorScheme == 'light'
? require('../../assets/icon_light.png')
: require('../../assets/icon_dark.png')
);
return (
<Flex style={{ flex: 1, backgroundColor: '#cdd4fd' }}>
{screenSize === 'small' ? (
<ScaffoldMobileCC
routeName={routeName}
menu={menu}
>
{children}
</ScaffoldMobileCC>
) : (
<ScaffoldDesktopCC
user={userQuery.data}
logo={logo?.at(0)?.uri ?? ''}
routeName={routeName}
menu={menu}
widthPadding={true}
>
{children}
</ScaffoldDesktopCC>
)}
</Flex>
);
};
export default ScaffoldCC;
+101 -90
View File
@@ -1,6 +1,7 @@
/* eslint-disable no-mixed-spaces-and-tabs */
import { View, Image, Pressable } from 'react-native';
import { View, Image, Pressable, useColorScheme } from 'react-native';
import { Divider, Text, ScrollView, Row, useMediaQuery, useTheme } from 'native-base';
import { useAssets } from 'expo-asset';
import { useQuery } from '../../Queries';
import API from '../../API';
import ButtonBase from './ButtonBase';
@@ -12,20 +13,9 @@ import Spacer from './Spacer';
import User from '../../models/User';
import LogoutButtonCC from './LogoutButtonCC';
import GlassmorphismCC from './Glassmorphism';
type ScaffoldDesktopCCProps = {
widthPadding: boolean;
children?: React.ReactNode;
user: User;
logo: string;
routeName: string;
menu: readonly {
type: 'main' | 'sub';
title: TranslationKey;
icon: Icon;
link: string;
}[];
};
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import { ReactElement } from 'react';
import { NavigationState, ParamListBase } from '@react-navigation/native';
// TODO a tester avec un historique de plus de 3 musics différente mdr !!
const SongHistory = (props: { quantity: number }) => {
@@ -81,15 +71,68 @@ const SongHistory = (props: { quantity: number }) => {
);
};
const ScaffoldDesktopCC = (props: ScaffoldDesktopCCProps) => {
const navigation = useNavigation();
const userQuery = useQuery(API.getUserInfo);
const NavigationButton = ({
isSmallScreen,
label,
icon,
isFocused,
navigation,
route,
}: {
isSmallScreen: boolean;
label: string;
icon?: Icon;
isFocused: boolean;
navigation: BottomTabBarProps['navigation'];
route: NavigationState['routes'][0];
}) => {
return (
<View key={'key-menu-link-' + label}>
<ButtonBase
style={!isSmallScreen ? { width: '100%' } : {}}
type="menu"
icon={icon}
title={!isSmallScreen ? translate(label as any) : undefined}
isDisabled={isFocused}
iconVariant={isFocused ? 'Bold' : 'Outline'}
onPress={() => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name, route.params);
}
}}
onLongPress={() => {
navigation.emit({
type: 'tabLongPress',
target: route.key,
});
}}
/>
<Spacer height="xs" />
</View>
);
};
const ScaffoldDesktopCC = ({
state,
descriptors,
navigation,
children,
}: Omit<BottomTabBarProps, 'insets'> & { children: ReactElement }) => {
const user = useQuery(API.getUserInfo);
const [isSmallScreen] = useMediaQuery({ maxWidth: 1100 });
const { colors } = useTheme();
if (!userQuery.data || userQuery.isLoading) {
return <LoadingView />;
}
const colorScheme = useColorScheme();
const [logo] = useAssets(
colorScheme == 'light'
? require('../../assets/icon_light.png')
: require('../../assets/icon_dark.png')
);
return (
<View style={{ height: '100%', flexDirection: 'row', overflow: 'hidden' }}>
@@ -111,7 +154,7 @@ const ScaffoldDesktopCC = (props: ScaffoldDesktopCCProps) => {
style={{ justifyContent: isSmallScreen ? 'center' : 'flex-start' }}
>
<Image
source={{ uri: props.logo }}
source={{ uri: logo?.at(0)?.uri ?? '' }}
style={{
aspectRatio: 1,
width: 32,
@@ -126,39 +169,21 @@ const ScaffoldDesktopCC = (props: ScaffoldDesktopCCProps) => {
</Row>
<Spacer height="lg" />
<View>
{props.menu.map(
(value) =>
value.type === 'main' && (
<View key={'key-menu-link-' + value.title}>
<ButtonBase
style={!isSmallScreen ? { width: '100%' } : {}}
type="menu"
icon={value.icon}
title={
!isSmallScreen
? translate(
value.title as
| 'menuDiscovery'
| 'menuProfile'
| 'menuMusic'
| 'menuSearch'
| 'menuLeaderBoard'
| 'menuSettings'
)
: undefined
}
isDisabled={props.routeName === value.link}
iconVariant={
props.routeName === value.link ? 'Bold' : 'Outline'
}
onPress={async () =>
navigation.navigate(value.link as never)
}
/>
<Spacer height="xs" />
</View>
)
)}
{state.routes.map((route, index) => {
const { options } = descriptors[route.key]!;
if ((options as any).subMenu) return null;
return (
<NavigationButton
isSmallScreen={!!isSmallScreen}
label={options.title !== undefined ? options.title : route.name}
icon={options.tabBarIcon as Icon}
isFocused={state.index === index}
navigation={navigation}
route={route}
/>
);
})}
</View>
</View>
{!isSmallScreen && (
@@ -182,59 +207,45 @@ const ScaffoldDesktopCC = (props: ScaffoldDesktopCCProps) => {
<View style={!isSmallScreen ? { width: '100%' } : {}}>
<Divider my="2" _light={{ bg: colors.black[500] }} _dark={{ bg: '#FFF' }} />
<Spacer height="xs" />
{props.menu.map(
(value) =>
value.type === 'sub' && (
<ButtonBase
key={'key-menu-link-' + value.title}
style={!isSmallScreen ? { width: '100%' } : {}}
type="menu"
icon={value.icon}
title={
!isSmallScreen
? translate(
value.title as
| 'menuDiscovery'
| 'menuProfile'
| 'menuMusic'
| 'menuSearch'
| 'menuLeaderBoard'
| 'menuSettings'
)
: undefined
}
isDisabled={props.routeName === value.link}
iconVariant={
props.routeName === value.link ? 'Bold' : 'Outline'
}
onPress={async () => navigation.navigate(value.link as never)}
/>
)
)}
{state.routes.map((route, index) => {
const { options } = descriptors[route.key]!;
if (!(options as any).subMenu) return null;
return (
<NavigationButton
isSmallScreen={!!isSmallScreen}
label={options.title !== undefined ? options.title : route.name}
icon={options.tabBarIcon as Icon}
isFocused={state.index === index}
navigation={navigation}
route={route}
/>
);
})}
<Spacer height="xs" />
<LogoutButtonCC
collapse={isSmallScreen}
isGuest={props.user.isGuest}
isGuest={user.data?.isGuest}
style={!isSmallScreen ? { width: '100%' } : {}}
buttonType={'menu'}
/>
</View>
</View>
<ScrollView style={{ flex: 1, maxHeight: '100%' }} contentContainerStyle={{ flex: 1 }}>
<GlassmorphismCC
<View
style={{
backgroundColor: colors.coolGray[500],
flex: 1,
margin: 8,
marginBottom: 0,
marginLeft: 0,
padding: props.widthPadding ? 20 : 0,
padding: 20,
borderRadius: 12,
minHeight: 'auto',
}}
>
{props.children}
</GlassmorphismCC>
{children}
</View>
<Spacer height="xs" />
</ScrollView>
</View>
+3 -2
View File
@@ -1,7 +1,7 @@
import { View } from 'react-native';
import { Flex, useMediaQuery, useTheme } from 'native-base';
import ButtonBase from './ButtonBase';
import { Discover } from 'iconsax-react-native';
import { Discover, Icon } from 'iconsax-react-native';
import { translate } from '../../i18n/i18n';
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import { ComponentProps } from 'react';
@@ -25,13 +25,14 @@ const ScaffoldMobileCC = ({ state, descriptors, navigation }: BottomTabBarProps)
{state.routes.map((route, index) => {
const { options } = descriptors[route.key]!;
const label = options.title !== undefined ? options.title : route.name;
const icon = options.tabBarIcon as Icon;
const isFocused = state.index === index;
return (
<ButtonBase
key={'key-menu-link-' + label}
type="menu"
icon={Discover}
icon={icon}
title={
isFocused && !isSmallScreen ? translate(label as any) : undefined
}