mirror of
https://github.com/ajnart/homarr.git
synced 2026-01-15 12:02:15 +01:00
🚚 Move all dashboard files in board directory
This commit is contained in:
11
src/components/Board/Board.tsx
Normal file
11
src/components/Board/Board.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { BoardView } from './BoardView';
|
||||
import { MobileRibbons } from './Sections/Sidebar/MobileRibbon/MobileRibbon';
|
||||
|
||||
export const Board = () => {
|
||||
return (
|
||||
<>
|
||||
<BoardView />
|
||||
<MobileRibbons />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -10,10 +10,10 @@ import {
|
||||
import { useResize } from '~/hooks/use-resize';
|
||||
import { useScreenLargerThan } from '~/hooks/useScreenLargerThan';
|
||||
|
||||
import { BoardCategorySection } from '../../Board/Sections/CategorySection';
|
||||
import { BoardEmptySection } from '../../Board/Sections/EmptySection';
|
||||
import { DashboardSidebar } from '../Wrappers/Sidebar/Sidebar';
|
||||
import { useGridstackStore } from '../Wrappers/gridstack/store';
|
||||
import { BoardCategorySection } from './Sections/Category/CategorySection';
|
||||
import { BoardEmptySection } from './Sections/EmptySection';
|
||||
import { DashboardSidebar } from './Sections/Sidebar/SidebarSection';
|
||||
import { useGridstackStore } from './gridstack/store';
|
||||
|
||||
export const BoardView = () => {
|
||||
const boardName = useRequiredBoard().name;
|
||||
@@ -43,6 +43,7 @@ export const BoardView = () => {
|
||||
visible={!isReady}
|
||||
transitionDuration={500}
|
||||
loaderProps={{ size: 'lg', variant: 'bars' }}
|
||||
h="calc(100dvh - var(--mantine-header-height))"
|
||||
/>
|
||||
<Group
|
||||
align="top"
|
||||
@@ -51,7 +52,7 @@ export const BoardView = () => {
|
||||
style={{ visibility: isReady ? 'visible' : 'hidden' }}
|
||||
>
|
||||
{sidebarsVisible.left && leftSidebarSection ? (
|
||||
<DashboardSidebar section={leftSidebarSection} isGridstackReady={isReady} />
|
||||
<DashboardSidebar section={leftSidebarSection} />
|
||||
) : null}
|
||||
|
||||
<Stack ref={mainAreaRef} mx={-10} style={{ flexGrow: 1 }}>
|
||||
@@ -70,7 +71,7 @@ export const BoardView = () => {
|
||||
</Stack>
|
||||
|
||||
{sidebarsVisible.right && rightSidebarSection ? (
|
||||
<DashboardSidebar section={rightSidebarSection} isGridstackReady={isReady} />
|
||||
<DashboardSidebar section={rightSidebarSection} />
|
||||
) : null}
|
||||
</Group>
|
||||
</Box>
|
||||
@@ -4,14 +4,14 @@ import { motion } from 'framer-motion';
|
||||
import Link from 'next/link';
|
||||
import { AppItem } from '~/components/Board/context';
|
||||
|
||||
import { useEditModeStore } from '../../Views/useEditModeStore';
|
||||
import { HomarrCardWrapper } from '../HomarrCardWrapper';
|
||||
import { BaseTileProps } from '../type';
|
||||
import { useEditModeStore } from '../../useEditModeStore';
|
||||
import { ItemWrapper } from '../ItemWrapper';
|
||||
import { AppMenu } from './AppMenu';
|
||||
import { AppPing } from './AppPing';
|
||||
|
||||
interface AppTileProps extends BaseTileProps {
|
||||
interface AppTileProps {
|
||||
app: AppItem;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const namePositions = {
|
||||
@@ -21,7 +21,7 @@ const namePositions = {
|
||||
bottom: 'column-reverse',
|
||||
};
|
||||
|
||||
export const AppTile = ({ className, app }: AppTileProps) => {
|
||||
export const BoardAppItem = ({ className, app }: AppTileProps) => {
|
||||
const isEditMode = useEditModeStore((x) => x.enabled);
|
||||
const { cx, classes } = useStyles();
|
||||
const { colorScheme } = useMantineTheme();
|
||||
@@ -81,7 +81,7 @@ export const AppTile = ({ className, app }: AppTileProps) => {
|
||||
const url = app.externalUrl ? app.externalUrl : app.internalUrl;
|
||||
|
||||
return (
|
||||
<HomarrCardWrapper className={className} p={10}>
|
||||
<ItemWrapper className={className} p={10}>
|
||||
<AppMenu app={app} />
|
||||
{!url || isEditMode ? (
|
||||
<UnstyledButton
|
||||
@@ -102,11 +102,11 @@ export const AppTile = ({ className, app }: AppTileProps) => {
|
||||
</UnstyledButton>
|
||||
)}
|
||||
<AppPing app={app} />
|
||||
</HomarrCardWrapper>
|
||||
</ItemWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const useStyles = createStyles((theme, _params, getRef) => ({
|
||||
const useStyles = createStyles(() => ({
|
||||
base: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@@ -133,11 +133,3 @@ const useStyles = createStyles((theme, _params, getRef) => ({
|
||||
gap: 4,
|
||||
},
|
||||
}));
|
||||
|
||||
export const appTileDefinition = {
|
||||
component: AppTile,
|
||||
minWidth: 1,
|
||||
minHeight: 1,
|
||||
maxWidth: 12,
|
||||
maxHeight: 12,
|
||||
};
|
||||
@@ -1,9 +1,9 @@
|
||||
import { openRemoveItemModal, useItemActions } from '~/components/Board/Items/item-actions';
|
||||
import { type AppItem, useRequiredBoard } from '~/components/Board/context';
|
||||
import { useResizeGridItem } from '~/components/Board/gridstack/useResizeGridItem';
|
||||
import { openRemoveItemModal, useItemActions } from '~/components/Board/item-actions';
|
||||
import { openContextModalGeneric } from '~/tools/mantineModalManagerExtensions';
|
||||
|
||||
import { GenericTileMenu } from '../GenericTileMenu';
|
||||
import { CommonItemMenu } from '../CommonItemMenu';
|
||||
|
||||
interface TileMenuProps {
|
||||
app: AppItem;
|
||||
@@ -58,7 +58,7 @@ export const AppMenu = ({ app }: TileMenuProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<GenericTileMenu
|
||||
<CommonItemMenu
|
||||
handleClickEdit={handleClickEdit}
|
||||
handleClickChangePosition={handleClickChangePosition}
|
||||
handleClickDelete={handleClickDelete}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { type SelectItem } from '@mantine/core';
|
||||
import { type ContextModalProps, closeModal } from '@mantine/modals';
|
||||
import { useItemActions } from '~/components/Board/Items/item-actions';
|
||||
import { type AppItem } from '~/components/Board/context';
|
||||
import { type useResizeGridItem } from '~/components/Board/gridstack/useResizeGridItem';
|
||||
import { useItemActions } from '~/components/Board/item-actions';
|
||||
|
||||
import { useGridstackStore, useWrapperColumnCount } from '../../Wrappers/gridstack/store';
|
||||
import { ChangePositionModal } from './ChangePositionModal';
|
||||
import { useGridstackStore, useWrapperColumnCount } from '../../gridstack/store';
|
||||
import { CommonChangePositionModal } from '../CommonChangePositionModal';
|
||||
|
||||
type ChangeAppPositionModalInnerProps = {
|
||||
app: AppItem;
|
||||
@@ -40,7 +40,7 @@ export const ChangeAppPositionModal = ({
|
||||
const heightData = useHeightData();
|
||||
|
||||
return (
|
||||
<ChangePositionModal
|
||||
<CommonChangePositionModal
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={handleCancel}
|
||||
widthData={widthData}
|
||||
@@ -2,9 +2,9 @@ import { Stack, Tabs, Text, TextInput } from '@mantine/core';
|
||||
import { UseFormReturnType } from '@mantine/form';
|
||||
import { IconClick, IconCursorText, IconLink } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import { AppType } from '~/types/app';
|
||||
import { EditAppModalTab } from '../type';
|
||||
|
||||
import { EditAppModalTab } from '../EditAppModal';
|
||||
|
||||
interface GeneralTabProps {
|
||||
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
|
||||
@@ -51,7 +51,7 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
|
||||
<Text color="red" mt="sm" size="sm">
|
||||
{t('behaviour.customProtocolWarning')}
|
||||
</Text>
|
||||
)}
|
||||
)}
|
||||
</Stack>
|
||||
</Tabs.Panel>
|
||||
);
|
||||
@@ -2,10 +2,10 @@ import { Alert, Divider, Tabs, Text } from '@mantine/core';
|
||||
import { UseFormReturnType } from '@mantine/form';
|
||||
import { IconAlertTriangle } from '@tabler/icons-react';
|
||||
import { Trans, useTranslation } from 'next-i18next';
|
||||
|
||||
import { AppType } from '~/types/app';
|
||||
import { IntegrationSelector } from './Components/InputElements/IntegrationSelector';
|
||||
import { IntegrationOptionsRenderer } from './Components/IntegrationOptionsRenderer/IntegrationOptionsRenderer';
|
||||
|
||||
import { IntegrationSelector } from './InputElements/IntegrationSelector';
|
||||
import { IntegrationOptionsRenderer } from './IntegrationOptionsRenderer/IntegrationOptionsRenderer';
|
||||
|
||||
interface IntegrationTabProps {
|
||||
form: UseFormReturnType<AppType, (values: AppType) => AppType>;
|
||||
@@ -12,18 +12,17 @@ import {
|
||||
} from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useConfigContext } from '~/config/provider';
|
||||
import { useConfigStore } from '~/config/store';
|
||||
import { AppType } from '~/types/app';
|
||||
|
||||
import { DebouncedImage } from '../../../IconSelector/DebouncedImage';
|
||||
import { useEditModeStore } from '../../Views/useEditModeStore';
|
||||
import { AppearanceTab } from './Tabs/AppereanceTab/AppereanceTab';
|
||||
import { BehaviourTab } from './Tabs/BehaviourTab/BehaviourTab';
|
||||
import { GeneralTab } from './Tabs/GeneralTab/GeneralTab';
|
||||
import { IntegrationTab } from './Tabs/IntegrationTab/IntegrationTab';
|
||||
import { NetworkTab } from './Tabs/NetworkTab/NetworkTab';
|
||||
import { EditAppModalTab } from './Tabs/type';
|
||||
import { useEditModeStore } from '../../useEditModeStore';
|
||||
import { AppearanceTab } from './Edit/AppereanceTab';
|
||||
import { BehaviourTab } from './Edit/BehaviourTab';
|
||||
import { GeneralTab } from './Edit/GeneralTab';
|
||||
import { IntegrationTab } from './Edit/IntegrationTab/IntegrationTab';
|
||||
import { NetworkTab } from './Edit/NetworkTab';
|
||||
|
||||
const appUrlRegex =
|
||||
'(https?://(?:www.|(?!www))\\[?[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\]?.[^\\s]{2,}|www.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9].[^\\s]{2,}|https?://(?:www.|(?!www))\\[?[a-zA-Z0-9]+\\]?.[^\\s]{2,}|www.[a-zA-Z0-9]+.[^\\s]{2,})';
|
||||
@@ -240,3 +239,5 @@ const SaveButton = ({ formIsValid }: { formIsValid: boolean }) => {
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
export type EditAppModalTab = 'general' | 'behaviour' | 'network' | 'appereance' | 'integration';
|
||||
@@ -2,7 +2,7 @@ import { Button, Flex, Grid, NumberInput, Select, SelectItem } from '@mantine/co
|
||||
import { useForm } from '@mantine/form';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
interface ChangePositionModalProps {
|
||||
interface CommonChangePositionModalProps {
|
||||
initialX?: number;
|
||||
initialY?: number;
|
||||
initialWidth?: number;
|
||||
@@ -13,7 +13,7 @@ interface ChangePositionModalProps {
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
export const ChangePositionModal = ({
|
||||
export const CommonChangePositionModal = ({
|
||||
initialX,
|
||||
initialY,
|
||||
initialWidth,
|
||||
@@ -22,7 +22,7 @@ export const ChangePositionModal = ({
|
||||
heightData,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
}: ChangePositionModalProps) => {
|
||||
}: CommonChangePositionModalProps) => {
|
||||
const form = useForm<FormType>({
|
||||
initialValues: {
|
||||
x: initialX ?? null,
|
||||
@@ -2,24 +2,21 @@ import { ActionIcon, Menu } from '@mantine/core';
|
||||
import { IconLayoutKanban, IconPencil, IconSettings, IconTrash } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import { useColorTheme } from '~/tools/color';
|
||||
import { useEditModeStore } from '../Views/useEditModeStore';
|
||||
import { useEditModeStore } from '../useEditModeStore';
|
||||
|
||||
interface GenericTileMenuProps {
|
||||
interface CommonItemMenuProps {
|
||||
handleClickEdit: () => void;
|
||||
handleClickChangePosition: () => void;
|
||||
handleClickDelete: () => void;
|
||||
displayEdit: boolean;
|
||||
}
|
||||
|
||||
export const GenericTileMenu = (
|
||||
{
|
||||
handleClickEdit,
|
||||
handleClickChangePosition,
|
||||
handleClickDelete,
|
||||
displayEdit,
|
||||
}: GenericTileMenuProps
|
||||
) => {
|
||||
export const CommonItemMenu = ({
|
||||
handleClickEdit,
|
||||
handleClickChangePosition,
|
||||
handleClickDelete,
|
||||
displayEdit,
|
||||
}: CommonItemMenuProps) => {
|
||||
const { t } = useTranslation('common');
|
||||
const isEditMode = useEditModeStore((x) => x.enabled);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable react/no-unknown-property */
|
||||
import { GridItemHTMLElement } from 'fily-publish-gridstack';
|
||||
import { ReactNode, RefObject } from 'react';
|
||||
import { GridItemProvider } from '~/components/Board/item/context';
|
||||
import { GridItemProvider } from '~/components/Board/Items/context';
|
||||
|
||||
interface GridstackTileWrapperProps {
|
||||
interface GridstackItemWrapperProps {
|
||||
id: string;
|
||||
type: 'app' | 'widget';
|
||||
x?: number;
|
||||
@@ -18,7 +18,7 @@ interface GridstackTileWrapperProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const GridstackTileWrapper = ({
|
||||
export const GridstackItemWrapper = ({
|
||||
id,
|
||||
type,
|
||||
x,
|
||||
@@ -31,7 +31,7 @@ export const GridstackTileWrapper = ({
|
||||
maxHeight,
|
||||
children,
|
||||
itemRef,
|
||||
}: GridstackTileWrapperProps) => {
|
||||
}: GridstackItemWrapperProps) => {
|
||||
const locationProperties = useLocationProperties(x, y);
|
||||
const normalizedWidth = width ?? minWidth;
|
||||
const normalizedHeight = height ?? minHeight;
|
||||
@@ -2,19 +2,17 @@ import { Card, CardProps } from '@mantine/core';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { useCardStyles } from '../../layout/Common/useCardStyles';
|
||||
import { useEditModeStore } from '../Views/useEditModeStore';
|
||||
import { useEditModeStore } from '../useEditModeStore';
|
||||
|
||||
interface HomarrCardWrapperProps extends CardProps {
|
||||
interface ItemWrapperProps extends CardProps {
|
||||
children: ReactNode;
|
||||
isCategory?: boolean;
|
||||
}
|
||||
|
||||
export const HomarrCardWrapper = ({ ...props }: HomarrCardWrapperProps) => {
|
||||
const { isCategory = false, ...restProps } = props;
|
||||
export const ItemWrapper = ({ ...restProps }: ItemWrapperProps) => {
|
||||
const {
|
||||
cx,
|
||||
classes: { card: cardClass },
|
||||
} = useCardStyles(isCategory);
|
||||
} = useCardStyles(false);
|
||||
const isEditMode = useEditModeStore((x) => x.enabled);
|
||||
return (
|
||||
<Card
|
||||
@@ -1,12 +1,12 @@
|
||||
import { type SelectItem } from '@mantine/core';
|
||||
import { type ContextModalProps, closeModal } from '@mantine/modals';
|
||||
import { useItemActions } from '~/components/Board/Items/item-actions';
|
||||
import { type WidgetItem } from '~/components/Board/context';
|
||||
import { type useResizeGridItem } from '~/components/Board/gridstack/useResizeGridItem';
|
||||
import { useItemActions } from '~/components/Board/item-actions';
|
||||
|
||||
import widgets from '../../../../widgets';
|
||||
import { useGridstackStore, useWrapperColumnCount } from '../../Wrappers/gridstack/store';
|
||||
import { ChangePositionModal } from './ChangePositionModal';
|
||||
import { useGridstackStore, useWrapperColumnCount } from '../../gridstack/store';
|
||||
import { CommonChangePositionModal } from '../CommonChangePositionModal';
|
||||
|
||||
export type WidgetChangePositionModalInnerProps = {
|
||||
widget: WidgetItem;
|
||||
@@ -43,7 +43,7 @@ export const ChangeWidgetPositionModal = ({
|
||||
const heightData = useHeightData(innerProps.widget.sort);
|
||||
|
||||
return (
|
||||
<ChangePositionModal
|
||||
<CommonChangePositionModal
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={handleCancel}
|
||||
heightData={heightData}
|
||||
@@ -1,23 +1,22 @@
|
||||
import { Title } from '@mantine/core';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { openRemoveItemModal, useItemActions } from '~/components/Board/Items/item-actions';
|
||||
import { type WidgetItem, useRequiredBoard } from '~/components/Board/context';
|
||||
import { useResizeGridItem } from '~/components/Board/gridstack/useResizeGridItem';
|
||||
import { openRemoveItemModal, useItemActions } from '~/components/Board/item-actions';
|
||||
import { openContextModalGeneric } from '~/tools/mantineModalManagerExtensions';
|
||||
|
||||
import WidgetsDefinitions from '../../../../widgets';
|
||||
import { type WidgetChangePositionModalInnerProps } from '../../Modals/ChangePosition/ChangeWidgetPositionModal';
|
||||
import { useWrapperColumnCount } from '../../Wrappers/gridstack/store';
|
||||
import { GenericTileMenu } from '../GenericTileMenu';
|
||||
import { useWrapperColumnCount } from '../../gridstack/store';
|
||||
import { CommonItemMenu } from '../CommonItemMenu';
|
||||
import { type WidgetChangePositionModalInnerProps } from './ChangeWidgetPositionModal';
|
||||
import { type WidgetEditModalInnerProps } from './WidgetsEditModal';
|
||||
|
||||
interface WidgetsMenuProps {
|
||||
type: string;
|
||||
widget: WidgetItem | undefined;
|
||||
widget: WidgetItem;
|
||||
}
|
||||
|
||||
export const WidgetsMenu = ({ type, widget }: WidgetsMenuProps) => {
|
||||
const { t } = useTranslation(`modules/${type}`);
|
||||
export const WidgetsMenu = ({ widget }: WidgetsMenuProps) => {
|
||||
const { t } = useTranslation(`modules/${widget.sort}`);
|
||||
const board = useRequiredBoard();
|
||||
const wrapperColumnCount = useWrapperColumnCount();
|
||||
const resizeGridItem = useResizeGridItem();
|
||||
@@ -58,7 +57,7 @@ export const WidgetsMenu = ({ type, widget }: WidgetsMenuProps) => {
|
||||
title: <Title order={4}>{t('descriptor.settings.title')}</Title>,
|
||||
innerProps: {
|
||||
widgetId: widget.id,
|
||||
widgetType: type,
|
||||
widgetType: widget.sort,
|
||||
options: widget.options,
|
||||
boardName: board.name,
|
||||
widgetOptions: widgetDefinitionObject.options,
|
||||
@@ -68,7 +67,7 @@ export const WidgetsMenu = ({ type, widget }: WidgetsMenuProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<GenericTileMenu
|
||||
<CommonItemMenu
|
||||
handleClickEdit={handleEditClick}
|
||||
handleClickChangePosition={handleChangeSizeClick}
|
||||
handleClickDelete={handleDeleteClick}
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
|
||||
import { useEditModeStore } from '~/components/Board/useEditModeStore';
|
||||
|
||||
import { AppItem, CategorySection } from '../../context';
|
||||
import { useCategoryMenuActions } from './Actions/category-menu-actions';
|
||||
|
||||
@@ -4,11 +4,11 @@ import { useTranslation } from 'next-i18next';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { AppItem, CategorySection } from '~/components/Board/context';
|
||||
|
||||
import { useEditModeStore } from '../../Dashboard/Views/useEditModeStore';
|
||||
import { WrapperContent } from '../../Dashboard/Wrappers/WrapperContent';
|
||||
import { useGridstack } from '../../Dashboard/Wrappers/gridstack/use-gridstack';
|
||||
import { useCardStyles } from '../../layout/Common/useCardStyles';
|
||||
import { CategoryMenu } from './Category/CategoryMenu';
|
||||
import { useCardStyles } from '../../../layout/Common/useCardStyles';
|
||||
import { useGridstack } from '../../gridstack/use-gridstack';
|
||||
import { useEditModeStore } from '../../useEditModeStore';
|
||||
import { SectionContent } from '../SectionContent';
|
||||
import { CategoryMenu } from './CategoryMenu';
|
||||
|
||||
interface DashboardCategoryProps {
|
||||
section: CategorySection;
|
||||
@@ -49,7 +49,7 @@ export const BoardCategorySection = ({ section, isOpened, toggle }: DashboardCat
|
||||
data-category={section.id}
|
||||
ref={refs.wrapper}
|
||||
>
|
||||
<WrapperContent items={section.items} refs={refs} />
|
||||
<SectionContent items={section.items} refs={refs} />
|
||||
</div>
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
@@ -1,9 +1,9 @@
|
||||
import { EmptySection } from '~/components/Board/context';
|
||||
import { GridstackProvider } from '~/components/Board/gridstack/context';
|
||||
|
||||
import { useEditModeStore } from '../../Dashboard/Views/useEditModeStore';
|
||||
import { WrapperContent } from '../../Dashboard/Wrappers/WrapperContent';
|
||||
import { useGridstack } from '../../Dashboard/Wrappers/gridstack/use-gridstack';
|
||||
import { useGridstack } from '../gridstack/use-gridstack';
|
||||
import { useEditModeStore } from '../useEditModeStore';
|
||||
import { SectionContent } from './SectionContent';
|
||||
|
||||
interface EmptySectionWrapperProps {
|
||||
section: EmptySection;
|
||||
@@ -28,7 +28,7 @@ export const BoardEmptySection = ({ section }: EmptySectionWrapperProps) => {
|
||||
ref={refs.wrapper}
|
||||
>
|
||||
{section.items.length === 0 && <span></span>}
|
||||
<WrapperContent items={section.items} refs={refs} />
|
||||
<SectionContent items={section.items} refs={refs} />
|
||||
</div>
|
||||
</GridstackProvider>
|
||||
);
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { GridItemHTMLElement, GridStack } from 'fily-publish-gridstack';
|
||||
import { GridItemHTMLElement } from 'fily-publish-gridstack';
|
||||
import { MutableRefObject, RefObject, useMemo } from 'react';
|
||||
import { AppItem, Item, WidgetItem } from '~/components/Board/context';
|
||||
import { AppType } from '~/types/app';
|
||||
import { WidgetWrapper } from '~/widgets/WidgetWrapper';
|
||||
import { IWidget, IWidgetDefinition } from '~/widgets/widgets';
|
||||
|
||||
import Widgets from '../../../widgets';
|
||||
import { appTileDefinition } from '../Tiles/Apps/AppTile';
|
||||
import { GridstackTileWrapper } from '../Tiles/TileWrapper';
|
||||
import { useGridstackStore } from './gridstack/store';
|
||||
import { BoardAppItem } from '../Items/App/AppItem';
|
||||
import { GridstackItemWrapper } from '../Items/GridstackItemWrapper';
|
||||
|
||||
interface WrapperContentProps {
|
||||
interface SectionContentProps {
|
||||
items: Item[];
|
||||
refs: {
|
||||
wrapper: RefObject<HTMLDivElement>;
|
||||
@@ -18,36 +15,36 @@ interface WrapperContentProps {
|
||||
};
|
||||
}
|
||||
|
||||
export function WrapperContent({ items, refs }: WrapperContentProps) {
|
||||
export function SectionContent({ items, refs }: SectionContentProps) {
|
||||
const apps = useMemo(() => items.filter((x): x is AppItem => x.type === 'app'), [items]);
|
||||
const widgets = useMemo(() => items.filter((x): x is WidgetItem => x.type === 'widget'), [items]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{apps?.map((app) => {
|
||||
const { component: TileComponent, ...tile } = appTileDefinition;
|
||||
return (
|
||||
<GridstackTileWrapper
|
||||
id={app.id}
|
||||
type="app"
|
||||
key={app.id}
|
||||
itemRef={refs.items.current[app.id]}
|
||||
{...tile}
|
||||
x={app.x}
|
||||
y={app.y}
|
||||
width={app.width}
|
||||
height={app.height}
|
||||
>
|
||||
<TileComponent className="grid-stack-item-content" app={app} />
|
||||
</GridstackTileWrapper>
|
||||
);
|
||||
})}
|
||||
{apps?.map((app) => (
|
||||
<GridstackItemWrapper
|
||||
id={app.id}
|
||||
type="app"
|
||||
key={app.id}
|
||||
itemRef={refs.items.current[app.id]}
|
||||
maxHeight={12}
|
||||
maxWidth={12}
|
||||
minHeight={1}
|
||||
minWidth={1}
|
||||
x={app.x}
|
||||
y={app.y}
|
||||
width={app.width}
|
||||
height={app.height}
|
||||
>
|
||||
<BoardAppItem className="grid-stack-item-content" app={app} />
|
||||
</GridstackItemWrapper>
|
||||
))}
|
||||
{widgets.map((widget) => {
|
||||
const definition = Widgets[widget.sort];
|
||||
if (!definition) return null;
|
||||
|
||||
return (
|
||||
<GridstackTileWrapper
|
||||
<GridstackItemWrapper
|
||||
type="widget"
|
||||
key={widget.id}
|
||||
itemRef={refs.items.current[widget.id]}
|
||||
@@ -61,10 +58,9 @@ export function WrapperContent({ items, refs }: WrapperContentProps) {
|
||||
<WidgetWrapper
|
||||
className="grid-stack-item-content"
|
||||
widget={widget}
|
||||
widgetType={widget.sort}
|
||||
WidgetComponent={definition.component as any}
|
||||
/>
|
||||
</GridstackTileWrapper>
|
||||
</GridstackItemWrapper>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
@@ -2,7 +2,7 @@ import { Drawer, Title } from '@mantine/core';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { SidebarSection } from '~/components/Board/context';
|
||||
|
||||
import { DashboardSidebar } from '../../Wrappers/Sidebar/Sidebar';
|
||||
import { DashboardSidebar } from '../SidebarSection';
|
||||
|
||||
interface MobileRibbonSidebarDrawerProps {
|
||||
onClose: () => void;
|
||||
@@ -32,7 +32,7 @@ export const MobileRibbonSidebarDrawer = ({
|
||||
transitionProps={{ transition: `slide-${section.position === 'right' ? 'left' : 'right'}` }}
|
||||
{...props}
|
||||
>
|
||||
<DashboardSidebar section={section} isGridstackReady />
|
||||
<DashboardSidebar section={section} />
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
46
src/components/Board/Sections/Sidebar/SidebarSection.tsx
Normal file
46
src/components/Board/Sections/Sidebar/SidebarSection.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Card } from '@mantine/core';
|
||||
import { RefObject } from 'react';
|
||||
import { SidebarSection } from '~/components/Board/context';
|
||||
|
||||
import { useCardStyles } from '../../../layout/Common/useCardStyles';
|
||||
import { useGridstack } from '../../gridstack/use-gridstack';
|
||||
import { SectionContent } from '../SectionContent';
|
||||
|
||||
interface DashboardSidebarProps extends DashboardSidebarInnerProps {
|
||||
section: SidebarSection;
|
||||
}
|
||||
// TODO: Move mobile ribons in this directory too!
|
||||
export const DashboardSidebar = ({ section }: DashboardSidebarProps) => {
|
||||
const {
|
||||
classes: { card: cardClass },
|
||||
} = useCardStyles(true);
|
||||
const { refs } = useGridstack({ section });
|
||||
|
||||
const minRow = useMinRowForFullHeight(refs.wrapper);
|
||||
|
||||
return (
|
||||
<Card p={0} m={0} radius="lg" className={cardClass} withBorder>
|
||||
<div
|
||||
ref={refs.wrapper}
|
||||
className="grid-stack grid-stack-sidebar"
|
||||
style={{
|
||||
transitionDuration: '0s',
|
||||
minWidth: 256,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
data-sidebar={section.id}
|
||||
gs-min-row={minRow}
|
||||
>
|
||||
<SectionContent items={section.items} refs={refs} />
|
||||
</div>{' '}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
interface DashboardSidebarInnerProps {
|
||||
section: SidebarSection;
|
||||
}
|
||||
|
||||
const useMinRowForFullHeight = (wrapperRef: RefObject<HTMLDivElement>) =>
|
||||
wrapperRef.current ? Math.floor(wrapperRef.current!.offsetHeight / 128) : 2;
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ContextModalProps } from '@mantine/modals';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { AvailableElementTypes } from './Components/Overview/AvailableElementsOverview';
|
||||
import { AvailableStaticTypes } from './Components/StaticElementsTab/AvailableStaticElementsTab';
|
||||
import { AvailableIntegrationElements } from './Components/WidgetsTab/AvailableWidgetsTab';
|
||||
import { AvailableElementTypes } from './Overview/AvailableElementsOverview';
|
||||
import { AvailableStaticTypes } from './StaticElementsTab/AvailableStaticElementsTab';
|
||||
import { AvailableIntegrationElements } from './WidgetsTab/AvailableWidgetsTab';
|
||||
|
||||
export const SelectElementModal = ({ context, id }: ContextModalProps) => {
|
||||
const [activeTab, setActiveTab] = useState<undefined | 'integrations' | 'static_elements'>();
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Grid, Text } from '@mantine/core';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import widgets from '../../../../../../widgets';
|
||||
import widgets from '../../../../widgets';
|
||||
import { SelectorBackArrow } from '../Shared/SelectorBackArrow';
|
||||
import { WidgetElementType } from './WidgetElementType';
|
||||
|
||||
@@ -3,11 +3,11 @@ import { showNotification } from '@mantine/notifications';
|
||||
import { Icon, IconChecks } from '@tabler/icons-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { useConfigContext } from '~/config/provider';
|
||||
import { useConfigStore } from '~/config/store';
|
||||
import { IWidget, IWidgetDefinition } from '~/widgets/widgets';
|
||||
import { useEditModeStore } from '../../../../Views/useEditModeStore';
|
||||
|
||||
import { useEditModeStore } from '../../useEditModeStore';
|
||||
import { GenericAvailableElementType } from '../Shared/GenericElementType';
|
||||
|
||||
interface WidgetElementTypeProps {
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { useItemActions } from '~/components/Board/Items/item-actions';
|
||||
import { type Section, useRequiredBoard } from '~/components/Board/context';
|
||||
import { useItemActions } from '~/components/Board/item-actions';
|
||||
|
||||
import { useEditModeStore } from '../../Views/useEditModeStore';
|
||||
import { useEditModeStore } from '../useEditModeStore';
|
||||
import { initializeGridstack } from './init-gridstack';
|
||||
import { useGridstackStore, useWrapperColumnCount } from './store';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useGridItemRef } from '../item/context';
|
||||
import { useGridItemRef } from '../Items/context';
|
||||
import { useGridstackRef } from './context';
|
||||
|
||||
type ResizeGridItemProps = {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { MobileRibbons } from './Mobile/Ribbon/MobileRibbon';
|
||||
import { BoardView } from './Views/DashboardView';
|
||||
|
||||
export const Board = () => {
|
||||
return (
|
||||
<>
|
||||
{/* The following elemens are splitted because gridstack doesn't reinitialize them when using same item. */}
|
||||
<BoardView />
|
||||
<MobileRibbons />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
export type EditAppModalTab = 'general' | 'behaviour' | 'network' | 'appereance' | 'integration';
|
||||
@@ -1,5 +0,0 @@
|
||||
interface ServiceIconProps {
|
||||
size: '100%' | number;
|
||||
}
|
||||
|
||||
export const AppIcon = ({ size }: ServiceIconProps) => null;
|
||||
@@ -1,6 +0,0 @@
|
||||
import { HomarrCardWrapper } from './HomarrCardWrapper';
|
||||
import { BaseTileProps } from './type';
|
||||
|
||||
export const EmptyTile = ({ className }: BaseTileProps) => (
|
||||
<HomarrCardWrapper className={className}>Empty</HomarrCardWrapper>
|
||||
);
|
||||
@@ -1,3 +0,0 @@
|
||||
export interface BaseTileProps {
|
||||
className?: string;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { Card } from '@mantine/core';
|
||||
import { RefObject } from 'react';
|
||||
import { SidebarSection } from '~/components/Board/context';
|
||||
|
||||
import { useCardStyles } from '../../../layout/Common/useCardStyles';
|
||||
import { WrapperContent } from '../WrapperContent';
|
||||
import { useGridstack } from '../gridstack/use-gridstack';
|
||||
|
||||
interface DashboardSidebarProps extends DashboardSidebarInnerProps {
|
||||
section: SidebarSection;
|
||||
isGridstackReady: boolean;
|
||||
}
|
||||
|
||||
export const DashboardSidebar = ({ section, isGridstackReady }: DashboardSidebarProps) => {
|
||||
const {
|
||||
cx,
|
||||
classes: { card: cardClass },
|
||||
} = useCardStyles(true);
|
||||
|
||||
return (
|
||||
<Card p={0} m={0} radius="lg" className={cardClass} withBorder>
|
||||
{isGridstackReady && <SidebarInner section={section} />}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
interface DashboardSidebarInnerProps {
|
||||
section: SidebarSection;
|
||||
}
|
||||
|
||||
// Is Required because of the gridstack main area width.
|
||||
const SidebarInner = ({ section }: DashboardSidebarInnerProps) => {
|
||||
const { refs } = useGridstack({ section });
|
||||
|
||||
const minRow = useMinRowForFullHeight(refs.wrapper);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={refs.wrapper}
|
||||
className="grid-stack grid-stack-sidebar"
|
||||
style={{
|
||||
transitionDuration: '0s',
|
||||
minWidth: 256,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
data-sidebar={section.id}
|
||||
// eslint-disable-next-line react/no-unknown-property
|
||||
gs-min-row={minRow}
|
||||
>
|
||||
<WrapperContent items={section.items} refs={refs} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const useMinRowForFullHeight = (wrapperRef: RefObject<HTMLDivElement>) =>
|
||||
wrapperRef.current ? Math.floor(wrapperRef.current!.offsetHeight / 128) : 2;
|
||||
@@ -15,8 +15,8 @@ import { Trans, useTranslation } from 'next-i18next';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useRequiredBoard } from '~/components/Board/context';
|
||||
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
|
||||
import { useNamedWrapperColumnCount } from '~/components/Dashboard/Wrappers/gridstack/store';
|
||||
import { useNamedWrapperColumnCount } from '~/components/Board/gridstack/store';
|
||||
import { useEditModeStore } from '~/components/Board/useEditModeStore';
|
||||
import { BoardHeadOverride } from '~/components/layout/Meta/BoardHeadOverride';
|
||||
import { HeaderActionButton } from '~/components/layout/header/ActionButton';
|
||||
import { api } from '~/utils/api';
|
||||
|
||||
@@ -20,7 +20,7 @@ import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useMemo } from 'react';
|
||||
import { z } from 'zod';
|
||||
import { availableIntegrations } from '~/components/Dashboard/Modals/EditAppModal/Tabs/IntegrationTab/Components/InputElements/IntegrationSelector';
|
||||
import { availableIntegrations } from '~/components/Board/Items/App/Edit/IntegrationTab/InputElements/IntegrationSelector';
|
||||
import { useConfigContext } from '~/config/provider';
|
||||
import { RequestModal } from '~/modules/overseerr/RequestModal';
|
||||
import { RouterOutputs, api } from '~/utils/api';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ChangeAppPositionModal } from '~/components/Board/Items/App/ChangeAppPositionModal';
|
||||
import { EditAppModal } from '~/components/Board/Items/App/EditAppModal';
|
||||
import { ChangeWidgetPositionModal } from '~/components/Board/Items/Widget/ChangeWidgetPositionModal';
|
||||
import { WidgetsEditModal } from '~/components/Board/Items/Widget/WidgetsEditModal';
|
||||
import { CategoryEditModal } from '~/components/Board/Sections/Category/CategoryEditModal';
|
||||
import { ChangeAppPositionModal } from '~/components/Dashboard/Modals/ChangePosition/ChangeAppPositionModal';
|
||||
import { ChangeWidgetPositionModal } from '~/components/Dashboard/Modals/ChangePosition/ChangeWidgetPositionModal';
|
||||
import { EditAppModal } from '~/components/Dashboard/Modals/EditAppModal/EditAppModal';
|
||||
import { SelectElementModal } from '~/components/Dashboard/Modals/SelectElement/SelectElementModal';
|
||||
import { WidgetsEditModal } from '~/components/Dashboard/Tiles/Widgets/WidgetsEditModal';
|
||||
import { SelectElementModal } from '~/components/Board/SelectElement/SelectElementModal';
|
||||
|
||||
import { CreateBoardModal } from './components/Manage/Board/create-board.modal';
|
||||
import { DeleteBoardModal } from './components/Manage/Board/delete-board.modal';
|
||||
|
||||
@@ -2,8 +2,8 @@ import { TRPCError } from '@trpc/server';
|
||||
import { GetServerSideProps, InferGetServerSidePropsType } from 'next';
|
||||
import { SSRConfig } from 'next-i18next';
|
||||
import { z } from 'zod';
|
||||
import { Board } from '~/components/Board/Board';
|
||||
import { BoardProvider } from '~/components/Board/context';
|
||||
import { Board } from '~/components/Dashboard/Dashboard';
|
||||
import { BoardLayout } from '~/components/layout/Templates/BoardLayout';
|
||||
import { env } from '~/env';
|
||||
import { createTrpcServersideHelpers } from '~/server/api/helper';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import { GetServerSideProps, InferGetServerSidePropsType } from 'next';
|
||||
import { SSRConfig } from 'next-i18next';
|
||||
import { Board } from '~/components/Board/Board';
|
||||
import { BoardProvider } from '~/components/Board/context';
|
||||
import { Board } from '~/components/Dashboard/Dashboard';
|
||||
import { BoardLayout } from '~/components/layout/Templates/BoardLayout';
|
||||
import { env } from '~/env';
|
||||
import { createTrpcServersideHelpers } from '~/server/api/helper';
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import { ComponentType } from 'react';
|
||||
import { ItemWrapper } from '~/components/Board/Items/ItemWrapper';
|
||||
import { WidgetsMenu } from '~/components/Board/Items/Widget/WidgetsMenu';
|
||||
import { WidgetItem } from '~/components/Board/context';
|
||||
import { HomarrCardWrapper } from '~/components/Dashboard/Tiles/HomarrCardWrapper';
|
||||
import { WidgetsMenu } from '~/components/Dashboard/Tiles/Widgets/WidgetsMenu';
|
||||
|
||||
import Widgets from '.';
|
||||
import ErrorBoundary from './boundary';
|
||||
import { IWidget } from './widgets';
|
||||
|
||||
interface WidgetWrapperProps {
|
||||
widgetType: string;
|
||||
widget: WidgetItem;
|
||||
className: string;
|
||||
WidgetComponent: ComponentType<{ widget: WidgetItem }>;
|
||||
}
|
||||
|
||||
// If a property has no value, set it to the default value
|
||||
const useWidget = <T extends WidgetItem>(widget: T): T => {
|
||||
const useWidgetWithDefaultOptionValues = <T extends WidgetItem>(widget: T): T => {
|
||||
const definition = Widgets[widget.sort];
|
||||
|
||||
const newProps = { ...widget.options };
|
||||
@@ -32,20 +30,15 @@ const useWidget = <T extends WidgetItem>(widget: T): T => {
|
||||
};
|
||||
};
|
||||
|
||||
export const WidgetWrapper = ({
|
||||
widgetType,
|
||||
widget,
|
||||
className,
|
||||
WidgetComponent,
|
||||
}: WidgetWrapperProps) => {
|
||||
const widgetWithDefaultProps = useWidget(widget);
|
||||
export const WidgetWrapper = ({ widget, className, WidgetComponent }: WidgetWrapperProps) => {
|
||||
const widgetWithDefaultProps = useWidgetWithDefaultOptionValues(widget);
|
||||
|
||||
return (
|
||||
<ErrorBoundary integration={widgetType} widget={widgetWithDefaultProps}>
|
||||
<HomarrCardWrapper className={className}>
|
||||
<WidgetsMenu type={widgetType} widget={widgetWithDefaultProps} />
|
||||
<ErrorBoundary widget={widgetWithDefaultProps}>
|
||||
<ItemWrapper className={className}>
|
||||
<WidgetsMenu widget={widgetWithDefaultProps} />
|
||||
<WidgetComponent widget={widgetWithDefaultProps} />
|
||||
</HomarrCardWrapper>
|
||||
</ItemWrapper>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ import { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
import { z } from 'zod';
|
||||
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
|
||||
import { useEditModeStore } from '~/components/Board/useEditModeStore';
|
||||
import { IconSelector } from '~/components/IconSelector/IconSelector';
|
||||
|
||||
import { defineWidget } from '../helper';
|
||||
|
||||
@@ -4,10 +4,8 @@ import { IconBrandGithub, IconBug, IconInfoCircle, IconRefresh } from '@tabler/i
|
||||
import Consola from 'consola';
|
||||
import { withTranslation } from 'next-i18next';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { WidgetsMenu } from '~/components/Board/Items/Widget/WidgetsMenu';
|
||||
import { WidgetItem } from '~/components/Board/context';
|
||||
import { WidgetsMenu } from '~/components/Dashboard/Tiles/Widgets/WidgetsMenu';
|
||||
|
||||
import { IWidget } from './widgets';
|
||||
|
||||
type ErrorBoundaryState = {
|
||||
hasError: boolean;
|
||||
@@ -17,7 +15,6 @@ type ErrorBoundaryState = {
|
||||
type ErrorBoundaryProps = {
|
||||
t: (key: string) => string;
|
||||
children: ReactNode;
|
||||
integration: string;
|
||||
widget: WidgetItem;
|
||||
};
|
||||
|
||||
@@ -56,7 +53,7 @@ class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundarySta
|
||||
withBorder
|
||||
h="calc(100% - 20px)"
|
||||
>
|
||||
<WidgetsMenu type={this.props.integration} widget={this.props.widget} />
|
||||
<WidgetsMenu widget={this.props.widget} />
|
||||
<ScrollArea h="100%" type="auto" offsetScrollbars>
|
||||
<Center>
|
||||
<Stack align="center" spacing="xs">
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Calendar } from '@mantine/dates';
|
||||
import { IconCalendarTime } from '@tabler/icons-react';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { useState } from 'react';
|
||||
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
|
||||
import { useEditModeStore } from '~/components/Board/useEditModeStore';
|
||||
import { useConfigContext } from '~/config/provider';
|
||||
import { getLanguageByCode } from '~/tools/language';
|
||||
import { RouterOutputs, api } from '~/utils/api';
|
||||
|
||||
@@ -6,7 +6,7 @@ import { BubbleMenu, useEditor } from '@tiptap/react';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
import { useState } from 'react';
|
||||
import { useRequiredBoard } from '~/components/Board/context';
|
||||
import { useEditModeStore } from '~/components/Dashboard/Views/useEditModeStore';
|
||||
import { useEditModeStore } from '~/components/Board/useEditModeStore';
|
||||
import { useColorTheme } from '~/tools/color';
|
||||
import { api } from '~/utils/api';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user