mirror of
https://github.com/ajnart/homarr.git
synced 2025-10-31 18:46:23 +01:00
Rework appshell and include calendar to the main page
This commit is contained in:
@@ -103,30 +103,34 @@ export default function AddItemShelfItem(props: any) {
|
||||
</Group>
|
||||
</form>
|
||||
</Modal>
|
||||
<Grid.Col span={4} lg={2} sm={3}>
|
||||
<AspectRatio ratio={4 / 3}>
|
||||
<Box
|
||||
sx={{
|
||||
<AspectRatio
|
||||
style={{
|
||||
minHeight: 120,
|
||||
minWidth: 120,
|
||||
}}
|
||||
ratio={4 / 3}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
|
||||
textAlign: 'center',
|
||||
padding: theme.spacing.xl,
|
||||
borderRadius: theme.radius.md,
|
||||
'&:hover': {
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
|
||||
textAlign: 'center',
|
||||
padding: theme.spacing.xl,
|
||||
borderRadius: theme.radius.md,
|
||||
'&:hover': {
|
||||
backgroundColor:
|
||||
theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Group direction="column" position="center">
|
||||
<motion.div whileHover={{ scale: 1.2 }}>
|
||||
<Apps style={{ cursor: 'pointer' }} onClick={() => setOpened(true)} size={60} />
|
||||
</motion.div>
|
||||
<Text>Add Service</Text>
|
||||
</Group>
|
||||
</Box>
|
||||
</AspectRatio>
|
||||
</Grid.Col>
|
||||
theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Group direction="column" position="center">
|
||||
<motion.div whileHover={{ scale: 1.2 }}>
|
||||
<Apps style={{ cursor: 'pointer' }} onClick={() => setOpened(true)} size={60} />
|
||||
</motion.div>
|
||||
<Text>Add Service</Text>
|
||||
</Group>
|
||||
</Box>
|
||||
</AspectRatio>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ import {
|
||||
AspectRatio,
|
||||
createStyles,
|
||||
Center,
|
||||
Container,
|
||||
SimpleGrid,
|
||||
Space,
|
||||
} from '@mantine/core';
|
||||
import { showNotification } from '@mantine/notifications';
|
||||
import { AlertCircle, Cross, X } from 'tabler-icons-react';
|
||||
@@ -24,7 +27,9 @@ const useStyles = createStyles((theme) => ({
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
|
||||
textAlign: 'center',
|
||||
padding: theme.spacing.xl,
|
||||
borderRadius: theme.radius.md,
|
||||
borderRadius: theme.radius.sm,
|
||||
width: 200,
|
||||
height: 180,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[2],
|
||||
@@ -53,39 +58,42 @@ const AppShelf = (props: any) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid m="xl" gutter="xl">
|
||||
{config.services
|
||||
? config.services.map((service, i) => (
|
||||
<Grid.Col lg={2} sm={3} key={i}>
|
||||
<motion.div
|
||||
onHoverStart={(e) => {
|
||||
setHovering(service.name);
|
||||
}}
|
||||
onHoverEnd={(e) => {
|
||||
setHovering('none');
|
||||
}}
|
||||
>
|
||||
<AspectRatio ratio={4 / 3}>
|
||||
<Box className={classes.main}>
|
||||
<motion.div animate={{ opacity: hovering == service.name ? 1 : 0 }}>
|
||||
<AppShelfMenu removeitem={removeService} name={service.name} />
|
||||
</motion.div>
|
||||
<Group direction="column" position="center">
|
||||
<Anchor href={service.url} target="_blank">
|
||||
<motion.div whileHover={{ scale: 1.2 }}>
|
||||
<Image style={{ maxWidth: 60 }} src={service.icon} alt={service.name} />
|
||||
</motion.div>
|
||||
</Anchor>
|
||||
<Text>{service.name}</Text>
|
||||
</Group>
|
||||
</Box>
|
||||
</AspectRatio>
|
||||
<SimpleGrid m="xl" cols={4} spacing="xl">
|
||||
{config.services.map((service, i) => (
|
||||
<motion.div
|
||||
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>
|
||||
</Grid.Col>
|
||||
))
|
||||
: null}
|
||||
<AddItemShelfItem additem={addService} />
|
||||
</Grid>
|
||||
</Group>
|
||||
<Group direction="column" position="center">
|
||||
<Anchor href={service.url} target="_blank">
|
||||
<motion.div whileHover={{ scale: 1.2 }}>
|
||||
<Image
|
||||
style={{
|
||||
maxWidth: 100,
|
||||
}}
|
||||
fit="cover"
|
||||
src={service.icon}
|
||||
alt={service.name}
|
||||
/>
|
||||
</motion.div>
|
||||
</Anchor>
|
||||
</Group>
|
||||
</Box>
|
||||
</motion.div>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Check, Edit, Trash } from 'tabler-icons-react';
|
||||
export default function AppShelfMenu(props: any) {
|
||||
const { name, removeitem: removeItem } = props;
|
||||
return (
|
||||
<Menu sx={{ position: 'absolute', top: 3, right: 3 }}>
|
||||
<Menu position='right'>
|
||||
<Menu.Label>Settings</Menu.Label>
|
||||
<Menu.Item
|
||||
color="primary"
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
useMantineTheme,
|
||||
Center,
|
||||
Popover,
|
||||
Box,
|
||||
} from '@mantine/core';
|
||||
import { useForm } from '@mantine/hooks';
|
||||
import { showNotification } from '@mantine/notifications';
|
||||
@@ -39,65 +40,70 @@ export default function SearchBar(props: any) {
|
||||
}
|
||||
|
||||
return (
|
||||
<form
|
||||
onChange={() => {
|
||||
// If querry contains !yt or !t add "Searching on YouTube" or "Searching torrent"
|
||||
const querry = form.values.querry.trim();
|
||||
const isYoutube = querry.startsWith('!yt');
|
||||
const isTorrent = querry.startsWith('!t');
|
||||
if (isYoutube) {
|
||||
setIcon(<BrandYoutube />);
|
||||
} else if (isTorrent) {
|
||||
setIcon(<Download />);
|
||||
} else {
|
||||
setIcon(<Search />);
|
||||
}
|
||||
<Box
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
onSubmit={form.onSubmit((values) => {
|
||||
// Find if querry is prefixed by !yt or !t
|
||||
const querry = values.querry.trim();
|
||||
const isYoutube = querry.startsWith('!yt');
|
||||
const isTorrent = querry.startsWith('!t');
|
||||
if (isYoutube) {
|
||||
window.open(`https://www.youtube.com/results?search_query=${querry.substring(3)}`);
|
||||
} else if (isTorrent) {
|
||||
window.open(`https://thepiratebay.org/search.php?q=${querry.substring(3)}`);
|
||||
} else {
|
||||
window.open(`${querryUrl}${values.querry}`);
|
||||
}
|
||||
})}
|
||||
>
|
||||
<Popover
|
||||
opened={opened}
|
||||
style={{
|
||||
width: '100%',
|
||||
<form
|
||||
onChange={() => {
|
||||
// If querry contains !yt or !t add "Searching on YouTube" or "Searching torrent"
|
||||
const querry = form.values.querry.trim();
|
||||
const isYoutube = querry.startsWith('!yt');
|
||||
const isTorrent = querry.startsWith('!t');
|
||||
if (isYoutube) {
|
||||
setIcon(<BrandYoutube size={22} />);
|
||||
} else if (isTorrent) {
|
||||
setIcon(<Download size={22} />);
|
||||
} else {
|
||||
setIcon(<Search size={22} />);
|
||||
}
|
||||
}}
|
||||
position="bottom"
|
||||
placement="start"
|
||||
withArrow
|
||||
trapFocus={false}
|
||||
transition="pop-top-left"
|
||||
onFocusCapture={() => setOpened(true)}
|
||||
onBlurCapture={() => setOpened(false)}
|
||||
target={
|
||||
<TextInput
|
||||
variant="filled"
|
||||
color="blue"
|
||||
icon={<Search size={18} />}
|
||||
radius="md"
|
||||
rightSection={icon}
|
||||
size="md"
|
||||
placeholder="Search the web"
|
||||
{...props}
|
||||
{...form.getInputProps('querry')}
|
||||
/>
|
||||
}
|
||||
onSubmit={form.onSubmit((values) => {
|
||||
// Find if querry is prefixed by !yt or !t
|
||||
const querry = values.querry.trim();
|
||||
const isYoutube = querry.startsWith('!yt');
|
||||
const isTorrent = querry.startsWith('!t');
|
||||
if (isYoutube) {
|
||||
window.open(`https://www.youtube.com/results?search_query=${querry.substring(3)}`);
|
||||
} else if (isTorrent) {
|
||||
window.open(`https://thepiratebay.org/search.php?q=${querry.substring(3)}`);
|
||||
} else {
|
||||
window.open(`${querryUrl}${values.querry}`);
|
||||
}
|
||||
})}
|
||||
>
|
||||
<Text>
|
||||
tip: You can prefix your querry with <b>!yt</b> or <b>!t</b> to research on youtube or for
|
||||
a torrent
|
||||
</Text>
|
||||
</Popover>
|
||||
</form>
|
||||
<Popover
|
||||
opened={opened}
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
position="bottom"
|
||||
placement="start"
|
||||
withArrow
|
||||
trapFocus={false}
|
||||
transition="pop-top-left"
|
||||
onFocusCapture={() => setOpened(true)}
|
||||
onBlurCapture={() => setOpened(false)}
|
||||
target={
|
||||
<TextInput
|
||||
variant="filled"
|
||||
color="blue"
|
||||
icon={icon}
|
||||
radius="md"
|
||||
size="md"
|
||||
placeholder="Search the web"
|
||||
{...props}
|
||||
{...form.getInputProps('querry')}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Text>
|
||||
tip: You can prefix your querry with <b>!yt</b> or <b>!t</b> to research on youtube or
|
||||
for a torrent
|
||||
</Text>
|
||||
</Popover>
|
||||
</form>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Group, Indicator, Popover, Box, Container, Text, Avatar } from '@mantine/core';
|
||||
import { Group, Indicator, Popover, Box, Container, Text, Avatar, ActionIcon } from '@mantine/core';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Calendar } from '@mantine/dates';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -27,7 +27,6 @@ export default function CalendarComponent(props: any) {
|
||||
const [opened, setOpened] = useState(false);
|
||||
// const [medias, setMedias] = useState();
|
||||
const dates = medias.map((media) => media.inCinemas);
|
||||
const [value, setValue] = useState(null);
|
||||
const parsedDates = dates.map((date) => dayjs(date));
|
||||
console.log(parsedDates);
|
||||
|
||||
@@ -64,10 +63,7 @@ export default function CalendarComponent(props: any) {
|
||||
|
||||
return (
|
||||
<Calendar
|
||||
value={value}
|
||||
onChange={(day: any) => {
|
||||
setValue(day);
|
||||
}}
|
||||
onChange={(day: any) => {}}
|
||||
renderDay={(renderdate) => <DayComponent renderdate={renderdate} parsedDates={parsedDates} />}
|
||||
/>
|
||||
);
|
||||
@@ -82,13 +78,13 @@ function DayComponent(props: any) {
|
||||
|
||||
if (match > -1) {
|
||||
return (
|
||||
<Avatar
|
||||
<ActionIcon
|
||||
onClick={() => {
|
||||
setOpened(true);
|
||||
console.log();
|
||||
}}
|
||||
radius="xl"
|
||||
color="teal"
|
||||
variant="light"
|
||||
>
|
||||
<Popover
|
||||
position="right"
|
||||
@@ -98,7 +94,7 @@ function DayComponent(props: any) {
|
||||
target={day}
|
||||
children={<MediaDisplay media={medias[match]} />}
|
||||
/>
|
||||
</Avatar>
|
||||
</ActionIcon>
|
||||
);
|
||||
}
|
||||
return <div>{day}</div>;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Notification } from '@mantine/core';
|
||||
import { Group, Notification } from '@mantine/core';
|
||||
import AppShelf from '../components/AppShelf/AppShelf';
|
||||
import CalendarComponent from '../components/calendar/CalendarComponent';
|
||||
import LoadConfigComponent from '../components/Config/LoadConfig';
|
||||
import SearchBar from '../components/SearchBar/SearchBar';
|
||||
|
||||
@@ -7,7 +8,10 @@ export default function HomePage() {
|
||||
return (
|
||||
<>
|
||||
<SearchBar />
|
||||
<AppShelf />
|
||||
<Group align={"start"} position="apart" noWrap>
|
||||
<AppShelf />
|
||||
<CalendarComponent />
|
||||
</Group>
|
||||
<LoadConfigComponent />
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user