Improve UI

This commit is contained in:
Aj - Thomas
2022-05-04 07:12:22 +02:00
parent 4a7480f94e
commit 4245a273fe
6 changed files with 141 additions and 85 deletions

View File

@@ -12,6 +12,7 @@ import {
Box, Box,
Text, Text,
Grid, Grid,
Card,
} from '@mantine/core'; } from '@mantine/core';
import { useForm } from '@mantine/hooks'; import { useForm } from '@mantine/hooks';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
@@ -30,9 +31,8 @@ export default function AddItemShelfItem(props: any) {
name: '', name: '',
icon: '', icon: '',
url: '', url: '',
apiKey: undefined as unknown as string,
}, },
validationRules: {},
}); });
return ( return (
<> <>
@@ -85,7 +85,7 @@ export default function AddItemShelfItem(props: any) {
placeholder="http://localhost:8989" placeholder="http://localhost:8989"
value={form.values.url} value={form.values.url}
onChange={(event) => form.setFieldValue('url', event.currentTarget.value)} onChange={(event) => form.setFieldValue('url', event.currentTarget.value)}
error={form.errors.icon && 'Icon url is invalid'} error={form.errors.url && 'Service url is invalid'}
/> />
<Select <Select
label="Select the type of service (used for API calls)" label="Select the type of service (used for API calls)"
@@ -97,6 +97,16 @@ export default function AddItemShelfItem(props: any) {
onChange={(value) => form.setFieldValue('type', value ?? 'Other')} onChange={(value) => form.setFieldValue('type', value ?? 'Other')}
data={ServiceTypeList} data={ServiceTypeList}
/> />
{(form.values.type === 'Sonarr' || form.values.type === 'Radarr') && (
<TextInput
required
label="API key"
placeholder="Your API key"
value={form.values.apiKey}
onChange={(event) => form.setFieldValue('apiKey', event.currentTarget.value)}
error={form.errors.apiKey && 'Invalid API key'}
/>
)}
</Group> </Group>
<Group grow position="center" mt="xl"> <Group grow position="center" mt="xl">
@@ -111,18 +121,15 @@ export default function AddItemShelfItem(props: any) {
}} }}
ratio={4 / 3} ratio={4 / 3}
> >
<Box <Card
sx={{ style={{
backgroundColor:
theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
textAlign: 'center',
padding: theme.spacing.xl,
borderRadius: theme.radius.md,
'&:hover': {
backgroundColor: backgroundColor:
theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1], theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
}, width: 200,
height: 180,
}} }}
radius="md"
> >
<Group direction="column" position="center"> <Group direction="column" position="center">
<motion.div whileHover={{ scale: 1.2 }}> <motion.div whileHover={{ scale: 1.2 }}>
@@ -130,7 +137,7 @@ export default function AddItemShelfItem(props: any) {
</motion.div> </motion.div>
<Text>Add Service</Text> <Text>Add Service</Text>
</Group> </Group>
</Box> </Card>
</AspectRatio> </AspectRatio>
</> </>
); );

View File

@@ -1,7 +1,18 @@
import AppShelf from './AppShelf'; import AppShelf, { AppShelfItem } from './AppShelf';
export default { export default {
title: 'Item Shelf', title: 'Item Shelf',
component: AppShelf,
args: {
service: {
name: 'qBittorrent',
url: 'http://',
icon: 'https://cdn.jsdelivr.net/gh/IceWhaleTech/CasaOS-AppStore@main/Apps/qBittorrent/icon.png',
type: 'qBittorrent',
apiKey: '',
},
},
}; };
export const Default = (args: any) => <AppShelf {...args} />; export const Default = (args: any) => <AppShelf {...args} />;
export const One = (args: any) => <AppShelfItem {...args} />;

View File

@@ -4,7 +4,6 @@ import {
Grid, Grid,
Group, Group,
Text, Text,
Image,
Anchor, Anchor,
Box, Box,
AspectRatio, AspectRatio,
@@ -13,6 +12,10 @@ import {
Container, Container,
SimpleGrid, SimpleGrid,
Space, Space,
Card,
useMantineTheme,
Image,
Badge,
} from '@mantine/core'; } from '@mantine/core';
import { showNotification } from '@mantine/notifications'; import { showNotification } from '@mantine/notifications';
import { AlertCircle, Cross, X } from 'tabler-icons-react'; import { AlertCircle, Cross, X } from 'tabler-icons-react';
@@ -20,27 +23,19 @@ import AppShelfMenu from './AppShelfMenu';
import AddItemShelfItem from './AddAppShelfItem'; import AddItemShelfItem from './AddAppShelfItem';
import { useConfig } from '../../tools/state'; import { useConfig } from '../../tools/state';
import { pingQbittorrent } from '../../tools/api'; import { pingQbittorrent } from '../../tools/api';
import { Config } from '../../tools/types'; import { Config, serviceItem } from '../../tools/types';
import { SettingsMenuButton } from '../Settings/SettingsMenu';
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
main: { main: {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1], backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
textAlign: 'center',
padding: theme.spacing.xl,
borderRadius: theme.radius.sm,
width: 200, width: 200,
height: 180, height: 180,
'&:hover': {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[2],
},
}, },
})); }));
const AppShelf = (props: any) => { const AppShelf = (props: any) => {
const { config, addService, removeService, setConfig } = useConfig(); const { config, addService, removeService, setConfig } = useConfig();
const { classes } = useStyles();
const [hovering, setHovering] = useState('none');
/* A hook that is used to load the config from local storage. */ /* A hook that is used to load the config from local storage. */
useEffect(() => { useEffect(() => {
@@ -60,42 +55,73 @@ const AppShelf = (props: any) => {
return ( return (
<SimpleGrid m="xl" cols={4} spacing="xl"> <SimpleGrid m="xl" cols={4} spacing="xl">
{config.services.map((service, i) => ( {config.services.map((service, i) => (
<motion.div <AppShelfItem service={service} />
onHoverStart={(e) => {
setHovering(service.name);
}}
onHoverEnd={(e) => {
setHovering('none');
}}
>
<Box className={classes.main}>
<Group position="center">
<Space />
<Text>{service.name}</Text>
<motion.div animate={{ opacity: hovering == service.name ? 1 : 0 }}>
<AppShelfMenu removeitem={removeService} name={service.name} />
</motion.div>
</Group>
<Group direction="column" position="center">
<Anchor href={service.url} target="_blank">
<motion.div whileHover={{ scale: 1.2 }}>
<Image
style={{
maxWidth: 80,
}}
fit="cover"
src={service.icon}
alt={service.name}
/>
</motion.div>
</Anchor>
</Group>
</Box>
</motion.div>
))} ))}
<AddItemShelfItem/> <AddItemShelfItem />
</SimpleGrid> </SimpleGrid>
); );
}; };
export function AppShelfItem(props: any) {
const { service }: { service: serviceItem } = props;
const theme = useMantineTheme();
const { removeService } = useConfig();
const { classes } = useStyles();
const [hovering, setHovering] = useState(false);
return (
<motion.div
onHoverStart={(e) => {
setHovering(true);
}}
onHoverEnd={(e) => {
setHovering(false);
}}
>
<Card
className={classes.main}
style={{
boxShadow: hovering ? '0px 0px 3px rgba(0, 0, 0, 0.5)' : '0px 0px 1px rgba(0, 0, 0, 0.5)',
}}
radius={'md'}
>
<motion.div
animate={{
opacity: hovering ? 1 : 0,
}}
>
<AppShelfMenu name={service.name} removeitem={removeService} />
</motion.div>
<Card.Section>
<Center>
<Text mt={'sm'} weight={500}>
{service.name}
</Text>
</Center>
</Card.Section>
<Card.Section>
<AspectRatio ratio={5 / 3} m="xl">
<motion.i
whileHover={{
cursor: 'pointer',
scale: 1.1,
}}
>
<Image
onClick={() => {
window.open(service.url);
}}
style={{
maxWidth: '50%',
marginBottom: 10,
}}
src={service.icon}
/>
</motion.i>
</AspectRatio>
</Card.Section>
</Card>
</motion.div>
);
}
export default AppShelf; export default AppShelf;

View File

@@ -5,7 +5,11 @@ import { Check, Edit, Trash } from 'tabler-icons-react';
export default function AppShelfMenu(props: any) { export default function AppShelfMenu(props: any) {
const { name, removeitem: removeItem } = props; const { name, removeitem: removeItem } = props;
return ( return (
<Menu position='right'> <Menu style={{
position: 'absolute',
top: 10,
right: 10,
}}>
<Menu.Label>Settings</Menu.Label> <Menu.Label>Settings</Menu.Label>
<Menu.Item <Menu.Item
color="primary" color="primary"

View File

@@ -7,6 +7,9 @@ import {
Burger, Burger,
Paper, Paper,
Transition, Transition,
Aside,
Drawer,
Center,
} from '@mantine/core'; } from '@mantine/core';
import { useBooleanToggle } from '@mantine/hooks'; import { useBooleanToggle } from '@mantine/hooks';
import { NextLink } from '@mantine/next'; import { NextLink } from '@mantine/next';
@@ -14,6 +17,7 @@ import { Logo } from './Logo';
import { ColorSchemeToggle } from '../ColorSchemeToggle/ColorSchemeToggle'; import { ColorSchemeToggle } from '../ColorSchemeToggle/ColorSchemeToggle';
import SaveConfigComponent from '../Config/SaveConfig'; import SaveConfigComponent from '../Config/SaveConfig';
import { SettingsMenuButton } from '../Settings/SettingsMenu'; import { SettingsMenuButton } from '../Settings/SettingsMenu';
import CalendarComponent from '../calendar/CalendarComponent';
const HEADER_HEIGHT = 60; const HEADER_HEIGHT = 60;
@@ -34,7 +38,7 @@ const useStyles = createStyles((theme) => ({
borderTopWidth: 0, borderTopWidth: 0,
overflow: 'hidden', overflow: 'hidden',
[theme.fn.largerThan('sm')]: { [theme.fn.largerThan('md')]: {
display: 'none', display: 'none',
}, },
}, },
@@ -47,13 +51,13 @@ const useStyles = createStyles((theme) => ({
}, },
links: { links: {
[theme.fn.smallerThan('sm')]: { [theme.fn.smallerThan('md')]: {
display: 'none', display: 'none',
}, },
}, },
burger: { burger: {
[theme.fn.largerThan('sm')]: { [theme.fn.largerThan('md')]: {
display: 'none', display: 'none',
}, },
}, },
@@ -127,6 +131,7 @@ export function Header({ links }: HeaderResponsiveProps) {
<Group spacing={5} className={classes.links}> <Group spacing={5} className={classes.links}>
{items} {items}
</Group> </Group>
<Group>
<SettingsMenuButton /> <SettingsMenuButton />
<Burger <Burger
@@ -135,14 +140,19 @@ export function Header({ links }: HeaderResponsiveProps) {
className={classes.burger} className={classes.burger}
size="sm" size="sm"
/> />
</Group>
<Transition transition="pop-top-right" duration={200} mounted={opened}> <Drawer
{(styles) => ( opened={opened}
<Paper className={classes.dropdown} withBorder style={{ zIndex: 99 }}> overlayOpacity={0.55}
{items} overlayBlur={3}
</Paper> onClose={() => toggleOpened()}
)} position="right"
</Transition> >
<Center>
<CalendarComponent />
</Center>
</Drawer>
</Container> </Container>
</Head> </Head>
); );

View File

@@ -15,15 +15,13 @@ export default function Layout({ children, style }: any) {
const { classes, cx } = useStyles(); const { classes, cx } = useStyles();
return ( return (
<AppShell <AppShell
aside={ aside={
<Aside <Aside
height={'auto'} height={'auto'}
hiddenBreakpoint="md"
hidden
width={{ width={{
xs: 'auto', base: 'auto',
md: 'auto',
lg: 'auto',
xl: 'auto',
}} }}
> >
<CalendarComponent /> <CalendarComponent />