[Merge]
This commit is contained in:
@@ -132,7 +132,14 @@ const ButtonBase: React.FC<ButtonProps> = ({
|
||||
/>
|
||||
)}
|
||||
{iconImage && <Image source={{ uri: iconImage }} style={styles.icon} />}
|
||||
{title && <Text style={[styles.text, type === 'filled' ? {color: '#fff'} : {}]} selectable={false}>{title}</Text>}
|
||||
{title && (
|
||||
<Text
|
||||
style={[styles.text, type === 'filled' ? { color: '#fff' } : {}]}
|
||||
selectable={false}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</InteractiveBase>
|
||||
|
||||
@@ -127,12 +127,22 @@ const ButtonBase: React.FC<ButtonProps> = ({
|
||||
{icon && (
|
||||
<MyIcon
|
||||
size={'18'}
|
||||
color={type === 'outlined' ? '#6075F9' : colorScheme === 'light' ? colors.black[500] : '#FFFFFF'}
|
||||
color={
|
||||
type === 'outlined'
|
||||
? '#6075F9'
|
||||
: colorScheme === 'light'
|
||||
? colors.black[500]
|
||||
: '#FFFFFF'
|
||||
}
|
||||
variant={iconVariant}
|
||||
/>
|
||||
)}
|
||||
{iconImage && <Image source={{ uri: iconImage }} style={styles.icon} />}
|
||||
{title && <Text style={styles.text} selectable={false}>{title}</Text>}
|
||||
{title && (
|
||||
<Text style={styles.text} selectable={false}>
|
||||
{title}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</InteractiveBase>
|
||||
|
||||
@@ -5,22 +5,22 @@ import { StyleProp, ViewStyle } from 'react-native';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
type GlassmorphismCCProps = {
|
||||
children?: ReactNode,
|
||||
children?: ReactNode;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
};
|
||||
|
||||
const GlassmorphismCC = ({ children, style }: GlassmorphismCCProps) => {
|
||||
const colorScheme = useColorScheme();
|
||||
console.log(colorScheme);
|
||||
const colorScheme = useColorScheme();
|
||||
console.log(colorScheme);
|
||||
|
||||
return (
|
||||
<BlurView
|
||||
style={[{borderRadius: 12}, style]}
|
||||
intensity={60}
|
||||
tint={colorScheme === 'light' ? 'light' : 'dark'}
|
||||
>
|
||||
{children}
|
||||
</BlurView>
|
||||
return (
|
||||
<BlurView
|
||||
style={[{ borderRadius: 12 }, style]}
|
||||
intensity={60}
|
||||
tint={colorScheme === 'light' ? 'light' : 'dark'}
|
||||
>
|
||||
{children}
|
||||
</BlurView>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,51 +3,50 @@ import { TouchableOpacity, Animated, StyleSheet, Platform } from 'react-native';
|
||||
import { Column, Text, useTheme } from 'native-base';
|
||||
|
||||
interface LinkBaseProps {
|
||||
text: string;
|
||||
onPress: () => void;
|
||||
text: string;
|
||||
onPress: () => void;
|
||||
}
|
||||
|
||||
const LinkBase: React.FC<LinkBaseProps> = ({ text, onPress }) => {
|
||||
const underlineHeight = useRef(new Animated.Value(4)).current;
|
||||
const opacity = useRef(new Animated.Value(1)).current;
|
||||
const color = useRef(new Animated.Value(1)).current;
|
||||
const underlineHeight = useRef(new Animated.Value(4)).current;
|
||||
const opacity = useRef(new Animated.Value(1)).current;
|
||||
const theme = useTheme();
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
if (Platform.OS === 'web') {
|
||||
Animated.timing(underlineHeight, {
|
||||
toValue: 20,
|
||||
duration: 250,
|
||||
useNativeDriver: false
|
||||
}).start();
|
||||
}
|
||||
};
|
||||
const handleMouseEnter = () => {
|
||||
if (Platform.OS === 'web') {
|
||||
Animated.timing(underlineHeight, {
|
||||
toValue: 20,
|
||||
duration: 250,
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
if (Platform.OS === 'web') {
|
||||
Animated.timing(underlineHeight, {
|
||||
toValue: 4,
|
||||
duration: 250,
|
||||
useNativeDriver: false
|
||||
}).start();
|
||||
}
|
||||
};
|
||||
const handleMouseLeave = () => {
|
||||
if (Platform.OS === 'web') {
|
||||
Animated.timing(underlineHeight, {
|
||||
toValue: 4,
|
||||
duration: 250,
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
}
|
||||
};
|
||||
|
||||
const handlePressIn = () => {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 0.8,
|
||||
duration: 250,
|
||||
useNativeDriver: false
|
||||
}).start();
|
||||
};
|
||||
const handlePressIn = () => {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 0.8,
|
||||
duration: 250,
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
};
|
||||
|
||||
const handlePressOut = () => {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 1,
|
||||
duration: 250,
|
||||
useNativeDriver: false
|
||||
}).start();
|
||||
};
|
||||
const handlePressOut = () => {
|
||||
Animated.timing(opacity, {
|
||||
toValue: 1,
|
||||
duration: 250,
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
@@ -74,15 +73,15 @@ const LinkBase: React.FC<LinkBaseProps> = ({ text, onPress }) => {
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: 'relative',
|
||||
},
|
||||
underline: {
|
||||
width: '100%',
|
||||
position: 'absolute',
|
||||
zIndex: -1,
|
||||
bottom: 0,
|
||||
},
|
||||
container: {
|
||||
position: 'relative',
|
||||
},
|
||||
underline: {
|
||||
width: '100%',
|
||||
position: 'absolute',
|
||||
zIndex: -1,
|
||||
bottom: 0,
|
||||
},
|
||||
});
|
||||
|
||||
export default LinkBase;
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { Text, Row, Heading, Column, Center } from 'native-base';
|
||||
import ButtonBase, { ButtonType } from './ButtonBase';
|
||||
import { CloseSquare, LoginCurve, LogoutCurve } from 'iconsax-react-native';
|
||||
import { LogoutCurve } from 'iconsax-react-native';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { translate } from '../../i18n/i18n';
|
||||
import { unsetAccessToken } from '../../state/UserSlice';
|
||||
import { BlurView } from 'expo-blur';
|
||||
import { useState } from 'react';
|
||||
import Modal from "react-native-modal";
|
||||
import React from 'react';
|
||||
import SignUpForm from '../../components/forms/signupform';
|
||||
import API, { APIError } from '../../API';
|
||||
import PopupCC from './PopupCC';
|
||||
import { StyleProp, ViewStyle } from 'react-native';
|
||||
|
||||
const handleSubmit = async (username: string, password: string, email: string) => {
|
||||
try {
|
||||
@@ -26,11 +24,16 @@ const handleSubmit = async (username: string, password: string, email: string) =
|
||||
type LogoutButtonCCProps = {
|
||||
collapse?: boolean;
|
||||
isGuest?: boolean;
|
||||
style: any;
|
||||
buttonType: ButtonType
|
||||
style: StyleProp<ViewStyle>;
|
||||
buttonType: ButtonType;
|
||||
};
|
||||
|
||||
const LogoutButtonCC = ({collapse = false, isGuest = false, buttonType = 'menu', style}: LogoutButtonCCProps) => {
|
||||
const LogoutButtonCC = ({
|
||||
collapse = false,
|
||||
isGuest = false,
|
||||
buttonType = 'menu',
|
||||
style,
|
||||
}: LogoutButtonCCProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
|
||||
@@ -1,63 +1,58 @@
|
||||
import { Text, Row, Heading, Column } from 'native-base';
|
||||
import ButtonBase from './ButtonBase';
|
||||
import { CloseSquare } from 'iconsax-react-native';
|
||||
import { BlurView } from 'expo-blur';
|
||||
import { ReactNode } from 'react';
|
||||
import Modal from "react-native-modal";
|
||||
import Modal from 'react-native-modal';
|
||||
import React from 'react';
|
||||
import GlassmorphismCC from './Glassmorphism';
|
||||
|
||||
type PopupCCProps = {
|
||||
title: string,
|
||||
description?: string,
|
||||
children?: ReactNode,
|
||||
isVisible: boolean,
|
||||
setIsVisible?: (isVisible: boolean) => void,
|
||||
title: string;
|
||||
description?: string;
|
||||
children?: ReactNode;
|
||||
isVisible: boolean;
|
||||
setIsVisible?: (isVisible: boolean) => void;
|
||||
};
|
||||
|
||||
const PopupCC = ({ title, description, children, isVisible, setIsVisible }: PopupCCProps) => {
|
||||
return (
|
||||
<Modal
|
||||
backdropOpacity={0.75}
|
||||
isVisible={isVisible}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignContent: 'center',
|
||||
alignSelf: 'center',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<GlassmorphismCC>
|
||||
<Column
|
||||
style={{
|
||||
maxWidth: '800px',
|
||||
maxHeight: 'fit-content',
|
||||
padding: '20px',
|
||||
}}
|
||||
space={4}
|
||||
>
|
||||
<Heading size="md" mb={2} alignItems={'flex-end'}>
|
||||
<Row style={{flex: 1, width: '100%', alignItems: 'flex-end'}}>
|
||||
<Text style={{flex: 1,width: '100%'}}>
|
||||
{title}
|
||||
</Text>
|
||||
{setIsVisible !== undefined &&
|
||||
<ButtonBase
|
||||
type='menu'
|
||||
style={{width: 'fit-content'}}
|
||||
icon={CloseSquare}
|
||||
onPress={async () => setIsVisible(false)}
|
||||
/>
|
||||
}
|
||||
</Row>
|
||||
</Heading>
|
||||
{description !== undefined &&
|
||||
<Text>{description}</Text>
|
||||
}
|
||||
{children !== undefined && children}
|
||||
</Column>
|
||||
</GlassmorphismCC>
|
||||
</Modal>
|
||||
<Modal
|
||||
backdropOpacity={0.75}
|
||||
isVisible={isVisible}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignContent: 'center',
|
||||
alignSelf: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<GlassmorphismCC>
|
||||
<Column
|
||||
style={{
|
||||
maxWidth: '800px',
|
||||
maxHeight: 'fit-content',
|
||||
padding: '20px',
|
||||
}}
|
||||
space={4}
|
||||
>
|
||||
<Heading size="md" mb={2} alignItems={'flex-end'}>
|
||||
<Row style={{ flex: 1, width: '100%', alignItems: 'flex-end' }}>
|
||||
<Text style={{ flex: 1, width: '100%' }}>{title}</Text>
|
||||
{setIsVisible !== undefined && (
|
||||
<ButtonBase
|
||||
type="menu"
|
||||
style={{ width: 'fit-content' }}
|
||||
icon={CloseSquare}
|
||||
onPress={async () => setIsVisible(false)}
|
||||
/>
|
||||
)}
|
||||
</Row>
|
||||
</Heading>
|
||||
{description !== undefined && <Text>{description}</Text>}
|
||||
{children !== undefined && children}
|
||||
</Column>
|
||||
</GlassmorphismCC>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -86,11 +86,11 @@ const ScaffoldCC = (props: ScaffoldCCProps) => {
|
||||
height: 32,
|
||||
}}
|
||||
/>
|
||||
{layout.width > 650 &&
|
||||
{layout.width > 650 && (
|
||||
<Text fontSize={'xl'} selectable={false}>
|
||||
Chromacase
|
||||
</Text>
|
||||
}
|
||||
)}
|
||||
</Row>
|
||||
<Spacer height="xl" />
|
||||
<View style={{ width: '100%' }}>
|
||||
@@ -168,7 +168,7 @@ const ScaffoldCC = (props: ScaffoldCCProps) => {
|
||||
type="menu"
|
||||
isDisabled={props.routeName === 'Settings'}
|
||||
iconVariant={props.routeName === 'Settings' ? 'Bold' : 'Outline'}
|
||||
onPress={async () => navigation.navigate('Settings')}
|
||||
onPress={async () => navigation.navigate('Settings', {})}
|
||||
/>
|
||||
<Spacer />
|
||||
{!user.isGuest && (
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { Flex, Stack, View, Text, Wrap, Image, Row, Column, ScrollView, useToast } from 'native-base';
|
||||
import {
|
||||
Flex,
|
||||
Stack,
|
||||
View,
|
||||
Text,
|
||||
Wrap,
|
||||
Image,
|
||||
Row,
|
||||
Column,
|
||||
ScrollView,
|
||||
useToast,
|
||||
} from 'native-base';
|
||||
import { FunctionComponent } from 'react';
|
||||
import { Linking, useWindowDimensions } from 'react-native';
|
||||
import ButtonBase from './ButtonBase';
|
||||
@@ -37,9 +48,11 @@ const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({
|
||||
const dispatch = useDispatch();
|
||||
const toast = useToast();
|
||||
const colorScheme = useColorScheme();
|
||||
const logo = colorScheme == 'light'
|
||||
? require('../../assets/icon_light.png')
|
||||
: require('../../assets/icon_dark.png');
|
||||
const logo =
|
||||
colorScheme == 'light'
|
||||
? require('../../assets/icon_light.png')
|
||||
: require('../../assets/icon_dark.png');
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const [banner] = useAssets(require('../../assets/banner.jpg'));
|
||||
|
||||
return (
|
||||
@@ -49,7 +62,7 @@ const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({
|
||||
style={{ flex: 1, backgroundColor: '#cdd4fd' }}
|
||||
>
|
||||
<Column style={{ flex: 1 }}>
|
||||
<Wrap space={4} direction='row' style={{padding: 16, paddingBottom: 0}}>
|
||||
<Wrap space={4} direction="row" style={{ padding: 16, paddingBottom: 0 }}>
|
||||
<Row space={2} flex={1}>
|
||||
<Image
|
||||
source={{ uri: logo }}
|
||||
@@ -59,14 +72,14 @@ const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({
|
||||
height: 32,
|
||||
}}
|
||||
/>
|
||||
{layout.width > 650 &&
|
||||
{layout.width > 650 && (
|
||||
<Text fontSize={'xl'} selectable={false}>
|
||||
Chromacase
|
||||
</Text>
|
||||
}
|
||||
)}
|
||||
</Row>
|
||||
<ButtonBase
|
||||
title='guest mode'
|
||||
title="guest mode"
|
||||
onPress={async () => {
|
||||
try {
|
||||
handleGuestLogin((accessToken: string) => {
|
||||
@@ -79,10 +92,17 @@ const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({
|
||||
}
|
||||
toast.show({ description: error as string });
|
||||
}
|
||||
}}
|
||||
}}
|
||||
/>
|
||||
</Wrap>
|
||||
<ScrollView contentContainerStyle={{ padding: 16, flexGrow: 1, justifyContent: 'center', alignSelf: 'center' }}>
|
||||
<ScrollView
|
||||
contentContainerStyle={{
|
||||
padding: 16,
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
alignSelf: 'center',
|
||||
}}
|
||||
>
|
||||
<View style={{ width: '100%', maxWidth: 420 }}>
|
||||
<Stack
|
||||
space={8}
|
||||
@@ -125,16 +145,13 @@ const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({
|
||||
{submitButton}
|
||||
<Wrap style={{ flexDirection: 'row', justifyContent: 'center' }}>
|
||||
<Text>{link.label}</Text>
|
||||
<LinkBase
|
||||
text={link.text}
|
||||
onPress={link.onPress}
|
||||
/>
|
||||
<LinkBase text={link.text} onPress={link.onPress} />
|
||||
</Wrap>
|
||||
</Stack>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</Column>
|
||||
{layout.width > 650 &&
|
||||
{layout.width > 650 && (
|
||||
<View style={{ width: '50%', height: '100%', padding: 16 }}>
|
||||
<Image
|
||||
source={{ uri: banner?.at(0)?.uri }}
|
||||
@@ -142,8 +159,8 @@ const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({
|
||||
style={{ width: '100%', height: '100%', borderRadius: 8 }}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
{colorScheme === 'dark' &&
|
||||
)}
|
||||
{colorScheme === 'dark' && (
|
||||
<LinearGradient
|
||||
colors={['#101014', '#6075F9']}
|
||||
style={{
|
||||
@@ -153,7 +170,7 @@ const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({
|
||||
zIndex: -2,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,31 +3,23 @@ import useColorScheme from '../../hooks/colorScheme';
|
||||
import { useQuery } from '../../Queries';
|
||||
import API from '../../API';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import {
|
||||
Cup,
|
||||
Discover,
|
||||
Icon,
|
||||
Music,
|
||||
SearchNormal1,
|
||||
Setting2,
|
||||
User,
|
||||
} from 'iconsax-react-native';
|
||||
import { Cup, Discover, Icon, Music, SearchNormal1, Setting2, User } from 'iconsax-react-native';
|
||||
import { LoadingView } from '../Loading';
|
||||
import ScaffoldDesktopCC from './ScaffoldDesktopCC';
|
||||
import ScaffoldMobileCC from './ScaffoldMobileCC';
|
||||
|
||||
const menu: {
|
||||
type: "main" | "sub";
|
||||
type: 'main' | 'sub';
|
||||
title: string;
|
||||
icon: Icon;
|
||||
link: string;
|
||||
}[] = [
|
||||
{ type: "main", title: 'menuDiscovery', icon: Discover, link: 'HomeNew' },
|
||||
{ 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: 'Score' },
|
||||
{ type: "sub", title: 'menuSettings', icon: Setting2, link: 'Settings' },
|
||||
{ type: 'main', title: 'menuDiscovery', icon: Discover, link: 'HomeNew' },
|
||||
{ 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: 'Score' },
|
||||
{ type: 'sub', title: 'menuSettings', icon: Setting2, link: 'Settings' },
|
||||
];
|
||||
|
||||
type ScaffoldCCProps = {
|
||||
@@ -36,7 +28,7 @@ type ScaffoldCCProps = {
|
||||
withPadding?: boolean;
|
||||
};
|
||||
|
||||
const ScaffoldCC = ({children, routeName, withPadding = true}: ScaffoldCCProps) => {
|
||||
const ScaffoldCC = ({ children, routeName, withPadding = true }: ScaffoldCCProps) => {
|
||||
const userQuery = useQuery(API.getUserInfo);
|
||||
const screenSize = useBreakpointValue({ base: 'small', md: 'big' });
|
||||
|
||||
@@ -44,13 +36,14 @@ const ScaffoldCC = ({children, routeName, withPadding = true}: ScaffoldCCProps)
|
||||
return <LoadingView />;
|
||||
}
|
||||
const colorScheme = useColorScheme();
|
||||
const logo = colorScheme == 'light'
|
||||
? require('../../assets/icon_light.png')
|
||||
: require('../../assets/icon_dark.png');
|
||||
const logo =
|
||||
colorScheme == 'light'
|
||||
? require('../../assets/icon_light.png')
|
||||
: require('../../assets/icon_dark.png');
|
||||
|
||||
return (
|
||||
<Flex style={{ flex: 1, backgroundColor: '#cdd4fd' }}>
|
||||
{screenSize === 'small' ?
|
||||
{screenSize === 'small' ? (
|
||||
<ScaffoldMobileCC
|
||||
user={userQuery.data}
|
||||
logo={logo}
|
||||
@@ -60,7 +53,8 @@ const ScaffoldCC = ({children, routeName, withPadding = true}: ScaffoldCCProps)
|
||||
>
|
||||
{children}
|
||||
</ScaffoldMobileCC>
|
||||
: <ScaffoldDesktopCC
|
||||
) : (
|
||||
<ScaffoldDesktopCC
|
||||
user={userQuery.data}
|
||||
logo={logo}
|
||||
routeName={routeName}
|
||||
@@ -69,8 +63,8 @@ const ScaffoldCC = ({children, routeName, withPadding = true}: ScaffoldCCProps)
|
||||
>
|
||||
{children}
|
||||
</ScaffoldDesktopCC>
|
||||
}
|
||||
{colorScheme === 'dark' &&
|
||||
)}
|
||||
{colorScheme === 'dark' && (
|
||||
<LinearGradient
|
||||
colors={['#101014', '#6075F9']}
|
||||
style={{
|
||||
@@ -80,7 +74,7 @@ const ScaffoldCC = ({children, routeName, withPadding = true}: ScaffoldCCProps)
|
||||
zIndex: -2,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { View, Image, useWindowDimensions } from 'react-native';
|
||||
import { Divider, Text, ScrollView, Flex, Row, useMediaQuery, useTheme } from 'native-base';
|
||||
/* eslint-disable no-mixed-spaces-and-tabs */
|
||||
import { View, Image } from 'react-native';
|
||||
import { Divider, Text, ScrollView, Row, useMediaQuery, useTheme } from 'native-base';
|
||||
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 { Icon } from 'iconsax-react-native';
|
||||
import { LoadingView } from '../Loading';
|
||||
@@ -13,24 +13,22 @@ import Spacer from './Spacer';
|
||||
import User from '../../models/User';
|
||||
import LogoutButtonCC from './LogoutButtonCC';
|
||||
import GlassmorphismCC from './Glassmorphism';
|
||||
import { ColorSchemeProvider } from '../../Theme';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
type ScaffoldDesktopCCProps = {
|
||||
widthPadding: boolean,
|
||||
widthPadding: boolean;
|
||||
children?: React.ReactNode;
|
||||
user: User;
|
||||
logo: string;
|
||||
routeName: string;
|
||||
menu: {
|
||||
type: "main" | "sub";
|
||||
type: 'main' | 'sub';
|
||||
title: string;
|
||||
icon: Icon;
|
||||
link: string;
|
||||
}[]
|
||||
}[];
|
||||
};
|
||||
|
||||
const SongHistory = (props: {quantity: number}) => {
|
||||
const SongHistory = (props: { quantity: number }) => {
|
||||
const playHistoryQuery = useQuery(API.getUserPlayHistory);
|
||||
const songHistory = useQueries(
|
||||
playHistoryQuery.data?.map(({ songID }) => API.getSong(songID)) ?? []
|
||||
@@ -42,9 +40,10 @@ const SongHistory = (props: {quantity: number}) => {
|
||||
|
||||
return (
|
||||
<View>
|
||||
{songHistory.length === 0 ?
|
||||
{songHistory.length === 0 ? (
|
||||
<Text style={{ paddingHorizontal: 16 }}>{translate('menuNoSongsPlayedYet')}</Text>
|
||||
: songHistory
|
||||
) : (
|
||||
songHistory
|
||||
.map((h) => h.data)
|
||||
.filter((data): data is Song => data !== undefined)
|
||||
.filter(
|
||||
@@ -62,12 +61,11 @@ const SongHistory = (props: {quantity: number}) => {
|
||||
>
|
||||
<Text numberOfLines={1}>{histoItem.name}</Text>
|
||||
</View>
|
||||
)
|
||||
)
|
||||
}
|
||||
))
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const ScaffoldDesktopCC = (props: ScaffoldDesktopCCProps) => {
|
||||
const navigation = useNavigation();
|
||||
@@ -102,39 +100,53 @@ const ScaffoldDesktopCC = (props: ScaffoldDesktopCCProps) => {
|
||||
height: 32,
|
||||
}}
|
||||
/>
|
||||
{!isSmallScreen &&
|
||||
{!isSmallScreen && (
|
||||
<Text fontSize={'xl'} selectable={false}>
|
||||
Chromacase
|
||||
</Text>
|
||||
}
|
||||
)}
|
||||
</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>
|
||||
))}
|
||||
{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>
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
{!isSmallScreen &&
|
||||
{!isSmallScreen && (
|
||||
<View>
|
||||
<Divider my="2" _light={{bg: colors.black[500]}} _dark={{bg:'#FFF'}}/>
|
||||
<Spacer height='xs'/>
|
||||
<Divider my="2" _light={{ bg: colors.black[500] }} _dark={{ bg: '#FFF' }} />
|
||||
<Spacer height="xs" />
|
||||
<Text
|
||||
bold
|
||||
style={{
|
||||
@@ -145,38 +157,52 @@ const ScaffoldDesktopCC = (props: ScaffoldDesktopCCProps) => {
|
||||
>
|
||||
{translate('menuRecentlyPlayed')}
|
||||
</Text>
|
||||
<SongHistory quantity={3}/>
|
||||
<SongHistory quantity={3} />
|
||||
</View>
|
||||
}
|
||||
<Spacer height='xs'/>
|
||||
)}
|
||||
<Spacer height="xs" />
|
||||
<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)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
<Spacer height='xs'/>
|
||||
<LogoutButtonCC collapse={isSmallScreen} isGuest={props.user.isGuest} style={!isSmallScreen ? { width: '100%' } : {}} buttonType={'menu'}/>
|
||||
<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)}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<Spacer height="xs" />
|
||||
<LogoutButtonCC
|
||||
collapse={isSmallScreen}
|
||||
isGuest={props.user.isGuest}
|
||||
style={!isSmallScreen ? { width: '100%' } : {}}
|
||||
buttonType={'menu'}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<ScrollView
|
||||
style={{ flex: 1, maxHeight: '100vh' }}
|
||||
contentContainerStyle={{ flex: 1 }}
|
||||
>
|
||||
<ScrollView style={{ flex: 1, maxHeight: '100vh' }} contentContainerStyle={{ flex: 1 }}>
|
||||
<GlassmorphismCC
|
||||
style={{
|
||||
backgroundColor: colors.coolGray[500],
|
||||
@@ -191,10 +217,9 @@ const ScaffoldDesktopCC = (props: ScaffoldDesktopCCProps) => {
|
||||
>
|
||||
{props.children}
|
||||
</GlassmorphismCC>
|
||||
<Spacer height='xs'/>
|
||||
<Spacer height="xs" />
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-mixed-spaces-and-tabs */
|
||||
import { View } from 'react-native';
|
||||
import { ScrollView, Flex, useMediaQuery, useTheme } from 'native-base';
|
||||
import { ScrollView, Flex, useMediaQuery, useTheme } from 'native-base';
|
||||
import ButtonBase from './ButtonBase';
|
||||
import { Icon } from 'iconsax-react-native';
|
||||
import { useNavigation } from '../../Navigation';
|
||||
@@ -12,13 +13,13 @@ type ScaffoldMobileCCProps = {
|
||||
user: User;
|
||||
logo: string;
|
||||
routeName: string;
|
||||
widthPadding: number;
|
||||
widthPadding: boolean;
|
||||
menu: {
|
||||
type: "main" | "sub";
|
||||
type: 'main' | 'sub';
|
||||
title: string;
|
||||
icon: Icon;
|
||||
link: string;
|
||||
}[]
|
||||
}[];
|
||||
};
|
||||
|
||||
const ScaffoldMobileCC = (props: ScaffoldMobileCCProps) => {
|
||||
@@ -45,7 +46,7 @@ const ScaffoldMobileCC = (props: ScaffoldMobileCCProps) => {
|
||||
</View>
|
||||
<Spacer/>
|
||||
</ScrollView>
|
||||
<View style={{padding: 8, paddingTop: 0}}>
|
||||
<View style={{ padding: 8, paddingTop: 0 }}>
|
||||
<Flex
|
||||
style={{
|
||||
width: '100%',
|
||||
@@ -62,14 +63,22 @@ const ScaffoldMobileCC = (props: ScaffoldMobileCCProps) => {
|
||||
key={'key-menu-link-' + value.title}
|
||||
type="menu"
|
||||
icon={value.icon}
|
||||
title={props.routeName === value.link && !isSmallScreen ? translate(value.title as 'menuDiscovery' | 'menuProfile' | 'menuMusic' | 'menuSearch' | 'menuLeaderBoard' | 'menuSettings') : undefined}
|
||||
title={
|
||||
props.routeName === value.link && !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)
|
||||
}
|
||||
iconVariant={props.routeName === value.link ? 'Bold' : 'Outline'}
|
||||
onPress={async () => navigation.navigate(value.link as never)}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
|
||||
@@ -27,14 +27,14 @@ const SeparatorBase: FunctionComponent<SeparatorBaseProps> = ({ children }) => {
|
||||
const colorScheme = useColorScheme();
|
||||
const { colors } = useTheme();
|
||||
const color = colorScheme === 'light' ? colors.black[500] : '#FFFFFF';
|
||||
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={[styles.line, {backgroundColor: color}]} />
|
||||
<View style={[styles.line, { backgroundColor: color }]} />
|
||||
<Text style={styles.text}>{children}</Text>
|
||||
<View style={[styles.line, {backgroundColor: color}]} />
|
||||
<View style={[styles.line, { backgroundColor: color }]} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SeparatorBase;
|
||||
|
||||
@@ -3,7 +3,6 @@ import React, { useState } from 'react';
|
||||
import { View, TouchableOpacity, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||
import InteractiveBase from './InteractiveBase';
|
||||
import { Input, useTheme } from 'native-base';
|
||||
import { ColorSchemeProvider } from '../../Theme';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
export interface TextFieldBaseProps {
|
||||
@@ -104,7 +103,11 @@ const TextFieldBase: React.FC<TextFieldBaseProps> = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<InteractiveBase style={[style, { borderRadius: 12 }]} styleAnimate={styleAnimate} focusable={false}>
|
||||
<InteractiveBase
|
||||
style={[style, { borderRadius: 12 }]}
|
||||
styleAnimate={styleAnimate}
|
||||
focusable={false}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.iconContainerLeft}>
|
||||
{icon && (
|
||||
@@ -121,7 +124,9 @@ const TextFieldBase: React.FC<TextFieldBaseProps> = ({
|
||||
style={[styles.input, icon ? {} : { paddingLeft: 12 }]}
|
||||
autoComplete={autoComplete}
|
||||
placeholder={placeholder + (isRequired ? '*' : '')}
|
||||
placeholderTextColor={colorScheme === 'light' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.7)'}
|
||||
placeholderTextColor={
|
||||
colorScheme === 'light' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.7)'
|
||||
}
|
||||
secureTextEntry={isSecret ? !isPasswordVisible : false}
|
||||
onFocus={() => setFocused(true)}
|
||||
onBlur={() => setFocused(false)}
|
||||
|
||||
Reference in New Issue
Block a user