mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 23:45:48 +01:00
AppShelf adjustments
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Accordion, Grid, Paper, Stack, Text, useMantineColorScheme } from '@mantine/core';
|
import { Accordion, Grid, Stack, Title, useMantineColorScheme } from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
closestCenter,
|
closestCenter,
|
||||||
DndContext,
|
DndContext,
|
||||||
@@ -9,16 +9,16 @@ import {
|
|||||||
useSensor,
|
useSensor,
|
||||||
useSensors,
|
useSensors,
|
||||||
} from '@dnd-kit/core';
|
} from '@dnd-kit/core';
|
||||||
|
|
||||||
import { arrayMove, SortableContext } from '@dnd-kit/sortable';
|
import { arrayMove, SortableContext } from '@dnd-kit/sortable';
|
||||||
import { useLocalStorage } from '@mantine/hooks';
|
import { useLocalStorage } from '@mantine/hooks';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
|
import * as Modules from '../../modules';
|
||||||
import { useConfig } from '../../tools/state';
|
import { useConfig } from '../../tools/state';
|
||||||
|
|
||||||
import { SortableAppShelfItem, AppShelfItem } from './AppShelfItem';
|
import { AppShelfItem, SortableItem } from './AppShelfItem';
|
||||||
import { ModuleMenu, ModuleWrapper } from '../../modules/moduleWrapper';
|
import { ModuleWrapper } from '../../modules/moduleWrapper';
|
||||||
import { UsenetModule, TorrentsModule } from '../../modules';
|
import { UsenetModule, TorrentsModule } from '../../modules';
|
||||||
import TorrentsComponent from '../../modules/torrents/TorrentsModule';
|
|
||||||
import { UsenetComponent } from '../../modules/usenet/UsenetModule';
|
|
||||||
|
|
||||||
const AppShelf = (props: any) => {
|
const AppShelf = (props: any) => {
|
||||||
const { config, setConfig } = useConfig();
|
const { config, setConfig } = useConfig();
|
||||||
@@ -79,13 +79,14 @@ const AppShelf = (props: any) => {
|
|||||||
const getItems = (filter?: string) => {
|
const getItems = (filter?: string) => {
|
||||||
// If filter is not set, return all the services without a category or a null category
|
// If filter is not set, return all the services without a category or a null category
|
||||||
let filtered = config.services;
|
let filtered = config.services;
|
||||||
|
const modules = Object.values(Modules).map((module) => module);
|
||||||
|
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
filtered = config.services.filter((e) => !e.category || e.category === null);
|
filtered = config.services.filter((e) => !e.category || e.category === null);
|
||||||
}
|
}
|
||||||
if (filter) {
|
if (filter) {
|
||||||
filtered = config.services.filter((e) => e.category === filter);
|
filtered = config.services.filter((e) => e.category === filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndContext
|
<DndContext
|
||||||
sensors={sensors}
|
sensors={sensors}
|
||||||
@@ -94,17 +95,12 @@ const AppShelf = (props: any) => {
|
|||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
>
|
>
|
||||||
<SortableContext items={config.services}>
|
<SortableContext items={config.services}>
|
||||||
<Grid gutter="xl" align="center">
|
<Grid gutter="lg" align="center">
|
||||||
{filtered.map((service) => (
|
{filtered.map((service) => (
|
||||||
<Grid.Col
|
<Grid.Col key={service.id} span="content">
|
||||||
key={service.id}
|
<SortableItem service={service} key={service.id} id={service.id}>
|
||||||
span={6}
|
<AppShelfItem service={service} />
|
||||||
xl={config.settings.appCardWidth || 2}
|
</SortableItem>
|
||||||
xs={4}
|
|
||||||
sm={3}
|
|
||||||
md={3}
|
|
||||||
>
|
|
||||||
<SortableAppShelfItem service={service} key={service.id} id={service.id} />
|
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -123,18 +119,7 @@ const AppShelf = (props: any) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (categoryList.length > 0) {
|
|
||||||
const noCategory = config.services.filter(
|
|
||||||
(e) => e.category === undefined || e.category === null
|
|
||||||
);
|
|
||||||
|
|
||||||
const torrentEnabled = config.modules?.[TorrentsModule.id]?.enabled ?? false;
|
|
||||||
const usenetEnabled = config.modules?.[UsenetModule.id]?.enabled ?? false;
|
|
||||||
|
|
||||||
const downloadEnabled = usenetEnabled || torrentEnabled;
|
|
||||||
// Create an item with 0: true, 1: true, 2: true... For each category
|
|
||||||
return (
|
return (
|
||||||
// TODO: Style accordion so that the bar is transparent to the user settings
|
|
||||||
<Stack>
|
<Stack>
|
||||||
<Accordion
|
<Accordion
|
||||||
variant="separated"
|
variant="separated"
|
||||||
@@ -157,66 +142,13 @@ const AppShelf = (props: any) => {
|
|||||||
key={category}
|
key={category}
|
||||||
value={idx.toString()}
|
value={idx.toString()}
|
||||||
>
|
>
|
||||||
<Accordion.Control>{category}</Accordion.Control>
|
<Accordion.Control>
|
||||||
|
<Title order={5}>{category}</Title>
|
||||||
|
</Accordion.Control>
|
||||||
<Accordion.Panel>{getItems(category)}</Accordion.Panel>
|
<Accordion.Panel>{getItems(category)}</Accordion.Panel>
|
||||||
</Accordion.Item>
|
</Accordion.Item>
|
||||||
))}
|
))}
|
||||||
{/* Return the item for all services without category */}
|
|
||||||
{noCategory && noCategory.length > 0 ? (
|
|
||||||
<Accordion.Item
|
|
||||||
style={{
|
|
||||||
background: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '255, 255, 255,'} \
|
|
||||||
${(config.settings.appOpacity || 100) / 100}`,
|
|
||||||
borderColor: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '233, 236, 239,'} \
|
|
||||||
${(config.settings.appOpacity || 100) / 100}`,
|
|
||||||
}}
|
|
||||||
key="Other"
|
|
||||||
value="Other"
|
|
||||||
>
|
|
||||||
<Accordion.Control>{t('accordions.others.text')}</Accordion.Control>
|
|
||||||
<Accordion.Panel>{getItems()}</Accordion.Panel>
|
|
||||||
</Accordion.Item>
|
|
||||||
) : null}
|
|
||||||
{downloadEnabled ? (
|
|
||||||
<Accordion.Item
|
|
||||||
style={{
|
|
||||||
color: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '255, 255, 255,'} \
|
|
||||||
${(config.settings.appOpacity || 100) / 100}`,
|
|
||||||
background: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '255, 255, 255,'} \
|
|
||||||
${(config.settings.appOpacity || 100) / 100}`,
|
|
||||||
borderColor: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '233, 236, 239,'} \
|
|
||||||
${(config.settings.appOpacity || 100) / 100}`,
|
|
||||||
}}
|
|
||||||
key="Downloads"
|
|
||||||
value="Your downloads"
|
|
||||||
>
|
|
||||||
<Accordion.Control>{t('accordions.downloads.text')}</Accordion.Control>
|
|
||||||
<Accordion.Panel>
|
|
||||||
<Paper radius="lg" style={{ position: 'relative' }}>
|
|
||||||
{torrentEnabled && (
|
|
||||||
<>
|
|
||||||
<Text>{t('accordions.downloads.torrents')}</Text>
|
|
||||||
<ModuleMenu module={TorrentsModule} hovered />
|
|
||||||
<TorrentsComponent />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{usenetEnabled && (
|
|
||||||
<>
|
|
||||||
<Text mt="md">{t('accordions.downloads.usenet')}</Text>
|
|
||||||
<ModuleMenu module={UsenetModule} hovered />
|
|
||||||
<UsenetComponent />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Paper>
|
|
||||||
</Accordion.Panel>
|
|
||||||
</Accordion.Item>
|
|
||||||
) : null}
|
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Stack>
|
|
||||||
{getItems()}
|
{getItems()}
|
||||||
<ModuleWrapper mt="xl" module={TorrentsModule} />
|
<ModuleWrapper mt="xl" module={TorrentsModule} />
|
||||||
<ModuleWrapper mt="xl" module={UsenetModule} />
|
<ModuleWrapper mt="xl" module={UsenetModule} />
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const useStyles = createStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export function SortableAppShelfItem(props: any) {
|
export function SortableItem(props: any) {
|
||||||
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
|
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
|
||||||
id: props.id,
|
id: props.id,
|
||||||
});
|
});
|
||||||
@@ -43,7 +43,7 @@ export function SortableAppShelfItem(props: any) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={setNodeRef} style={style} {...attributes} {...listeners}>
|
<div ref={setNodeRef} style={style} {...attributes} {...listeners}>
|
||||||
<AppShelfItem service={props.service} />
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -75,6 +75,8 @@ export function AppShelfItem(props: any) {
|
|||||||
shadow="md"
|
shadow="md"
|
||||||
className={classes.item}
|
className={classes.item}
|
||||||
style={{
|
style={{
|
||||||
|
// Use the grab cursor when hovering over the card
|
||||||
|
cursor: hovering ? 'grab' : 'auto',
|
||||||
background: `rgba(${colorScheme === 'dark' ? '37, 38, 43,' : '255, 255, 255,'} \
|
background: `rgba(${colorScheme === 'dark' ? '37, 38, 43,' : '255, 255, 255,'} \
|
||||||
${(config.settings.appOpacity || 100) / 100}`,
|
${(config.settings.appOpacity || 100) / 100}`,
|
||||||
borderColor: `rgba(${colorScheme === 'dark' ? '37, 38, 43,' : '233, 236, 239,'} \
|
borderColor: `rgba(${colorScheme === 'dark' ? '37, 38, 43,' : '233, 236, 239,'} \
|
||||||
|
|||||||
Reference in New Issue
Block a user