diff --git a/src/components/Dashboard/Wrappers/Wrapper/Wrapper.tsx b/src/components/Board/Sections/EmptySection.tsx
similarity index 53%
rename from src/components/Dashboard/Wrappers/Wrapper/Wrapper.tsx
rename to src/components/Board/Sections/EmptySection.tsx
index 5649525c1..d9b20ce4b 100644
--- a/src/components/Dashboard/Wrappers/Wrapper/Wrapper.tsx
+++ b/src/components/Board/Sections/EmptySection.tsx
@@ -1,21 +1,19 @@
-import { Button } from '@mantine/core';
-import { GridItemHTMLElement } from 'fily-publish-gridstack';
-import { EmptySection, useRequiredBoard } from '~/components/Board/context';
+import { EmptySection } from '~/components/Board/context';
import { GridstackProvider } from '~/components/Board/gridstack/context';
-import { useItemActions } from '~/components/Board/item-actions';
-import { useEditModeStore } from '../../Views/useEditModeStore';
-import { WrapperContent } from '../WrapperContent';
-import { useGridstack } from '../gridstack/use-gridstack';
+import { useEditModeStore } from '../../Dashboard/Views/useEditModeStore';
+import { WrapperContent } from '../../Dashboard/Wrappers/WrapperContent';
+import { useGridstack } from '../../Dashboard/Wrappers/gridstack/use-gridstack';
-interface DashboardWrapperProps {
+interface EmptySectionWrapperProps {
section: EmptySection;
}
-export const DashboardWrapper = ({ section }: DashboardWrapperProps) => {
+const defaultClasses = 'grid-stack grid-stack-empty min-row';
+
+export const EmptySectionWrapper = ({ section }: EmptySectionWrapperProps) => {
const { refs } = useGridstack({ section });
const isEditMode = useEditModeStore((x) => x.enabled);
- const defaultClasses = 'grid-stack grid-stack-empty min-row';
return (
@@ -29,6 +27,7 @@ export const DashboardWrapper = ({ section }: DashboardWrapperProps) => {
data-empty={section.id}
ref={refs.wrapper}
>
+ {section.items.length === 0 && }
diff --git a/src/components/Board/category-actions.ts b/src/components/Board/category-actions.ts
new file mode 100644
index 000000000..7e69ecf64
--- /dev/null
+++ b/src/components/Board/category-actions.ts
@@ -0,0 +1,204 @@
+import Consola from 'consola';
+import { useCallback } from 'react';
+import { v4 } from 'uuid';
+import { api } from '~/utils/api';
+
+import { type CategorySection, type EmptySection } from './context';
+
+type AddCategory = {
+ name: string;
+ position: number;
+};
+
+type RenameCategory = {
+ id: string;
+ name: string;
+};
+
+type MoveCategory = {
+ id: string;
+ direction: 'up' | 'down';
+};
+
+type RemoveCategory = {
+ id: string;
+};
+
+export const useCategoryActions = ({ boardName }: { boardName: string }) => {
+ const utils = api.useContext();
+
+ const addCategory = useCallback(
+ ({ name, position }: AddCategory) => {
+ if (position <= 0) {
+ Consola.error('Cannot add category before first section');
+ return;
+ }
+ utils.boards.byName.setData({ boardName }, (prev) => {
+ if (!prev) return prev;
+ return {
+ ...prev,
+ sections: [
+ // Ignore sidebar and hidden sections
+ ...prev.sections.filter(
+ (section) => section.type === 'sidebar' || section.type === 'hidden'
+ ),
+ // Place sections before the new category
+ ...prev.sections.filter(
+ (section) =>
+ (section.type === 'category' || section.type === 'empty') &&
+ section.position < position
+ ),
+ {
+ id: v4(),
+ name,
+ type: 'category',
+ position,
+ items: [],
+ },
+ {
+ id: v4(),
+ type: 'empty',
+ position: position + 1,
+ items: [],
+ },
+ // Place sections after the new category
+ ...prev.sections
+ .filter(
+ (section): section is CategorySection | EmptySection =>
+ (section.type === 'category' || section.type === 'empty') &&
+ section.position >= position
+ )
+ .map((section) => ({
+ ...section,
+ position: section.position + 2,
+ })),
+ ],
+ };
+ });
+ },
+ [boardName, utils]
+ );
+
+ const renameCategory = useCallback(
+ ({ id: categoryId, name }: RenameCategory) => {
+ utils.boards.byName.setData({ boardName }, (prev) => {
+ if (!prev) return prev;
+ return {
+ ...prev,
+ sections: prev.sections.map((section) => {
+ if (section.type !== 'category') return section;
+ if (section.id !== categoryId) return section;
+ return {
+ ...section,
+ name,
+ };
+ }),
+ };
+ });
+ },
+ [boardName, utils]
+ );
+
+ const moveCategory = useCallback(
+ ({ id: categoryId, direction }: MoveCategory) => {
+ utils.boards.byName.setData({ boardName }, (prev) => {
+ if (!prev) return prev;
+
+ const currentCategory = prev.sections.find(
+ (section): section is CategorySection =>
+ section.type === 'category' && section.id === categoryId
+ );
+ if (!currentCategory) return prev;
+ if (currentCategory?.position === 1 && direction === 'up') return prev;
+ if (currentCategory?.position === prev.sections.length - 2 && direction === 'down')
+ return prev;
+
+ return {
+ ...prev,
+ sections: prev.sections.map((section) => {
+ if (section.type !== 'category' && section.type !== 'empty') return section;
+ const offset = direction === 'up' ? -2 : 2;
+ // Move category and empty section
+ if (
+ section.position === currentCategory.position ||
+ section.position - 1 === currentCategory.position
+ ) {
+ return {
+ ...section,
+ position: section.position + offset,
+ };
+ }
+
+ // Move all sections behind
+ if (section.position >= currentCategory.position + offset) {
+ return {
+ ...section,
+ position: section.position + 2,
+ };
+ }
+
+ if (
+ direction === 'up' &&
+ (section.position === currentCategory.position + 2 ||
+ section.position === currentCategory.position + 3)
+ ) {
+ return {
+ ...section,
+ position: section.position - 2,
+ };
+ }
+
+ return section;
+ }),
+ };
+ });
+ },
+ [boardName, utils]
+ );
+
+ const removeCategory = useCallback(
+ ({ id: categoryId }: RemoveCategory) => {
+ utils.boards.byName.setData({ boardName }, (prev) => {
+ if (!prev) return prev;
+
+ const currentCategory = prev.sections.find(
+ (section): section is CategorySection =>
+ section.type === 'category' && section.id === categoryId
+ );
+ if (!currentCategory) return prev;
+
+ return {
+ ...prev,
+ sections: [
+ ...prev.sections.filter(
+ (section) => section.type === 'sidebar' || section.type === 'hidden'
+ ),
+ ...prev.sections.filter(
+ (section) =>
+ (section.type === 'category' || section.type === 'empty') &&
+ section.position < currentCategory.position
+ ),
+ ...prev.sections
+ .filter(
+ (section): section is CategorySection | EmptySection =>
+ (section.type === 'category' || section.type === 'empty') &&
+ section.position >= currentCategory.position + 2
+ )
+ .map((section) => ({
+ ...section,
+ position: section.position - 2,
+ })),
+ ],
+ };
+ });
+ },
+ [boardName, utils]
+ );
+
+ return {
+ addCategory,
+ renameCategory,
+ moveCategory,
+ removeCategory,
+ };
+};
diff --git a/src/components/Board/gridstack/context.tsx b/src/components/Board/gridstack/context.tsx
index e643de021..73664ea19 100644
--- a/src/components/Board/gridstack/context.tsx
+++ b/src/components/Board/gridstack/context.tsx
@@ -11,8 +11,6 @@ const GridstackContext = createContext({
export const useGridstackRef = () => {
const ctx = useContext(GridstackContext);
- if (!ctx || !ctx.ref)
- throw new Error('useGridstackContext must be used within a GridstackProvider');
return ctx.ref;
};
diff --git a/src/components/Board/gridstack/useResizeGridItem.ts b/src/components/Board/gridstack/useResizeGridItem.ts
index 3e5504337..5e86d5723 100644
--- a/src/components/Board/gridstack/useResizeGridItem.ts
+++ b/src/components/Board/gridstack/useResizeGridItem.ts
@@ -13,12 +13,10 @@ export const useResizeGridItem = () => {
const gridstackRef = useGridstackRef();
return ({ height, width, ...options }: ResizeGridItemProps) => {
- gridstackRef.current?.batchUpdate();
- gridstackRef.current?.update(itemRef.current!, {
+ gridstackRef?.current?.update(itemRef.current!, {
...options,
h: height,
w: width,
});
- gridstackRef.current?.batchUpdate(false);
};
};
diff --git a/src/components/Board/item-actions.tsx b/src/components/Board/item-actions.tsx
index 512df7602..026078f16 100644
--- a/src/components/Board/item-actions.tsx
+++ b/src/components/Board/item-actions.tsx
@@ -27,6 +27,7 @@ export const useItemActions = ({ boardName }: { boardName: string }) => {
const utils = api.useContext();
const moveAndResizeItem = useCallback(
({ itemId, ...positionProps }: MoveAndResizeItem) => {
+ console.log(itemId, positionProps);
utils.boards.byName.setData({ boardName }, (prev) => {
if (!prev) return prev;
return {
@@ -54,6 +55,7 @@ export const useItemActions = ({ boardName }: { boardName: string }) => {
const moveItemToSection = useCallback(
({ itemId, sectionId, ...positionProps }: MoveItemToSection) => {
+ console.log('moveItemToSection', itemId, sectionId, positionProps);
utils.boards.byName.setData({ boardName }, (prev) => {
if (!prev) return prev;
@@ -62,10 +64,16 @@ export const useItemActions = ({ boardName }: { boardName: string }) => {
);
// If item is in the same section (on initial loading) don't do anything
- if (!currentSection || currentSection.id === sectionId) return prev;
+ if (!currentSection || currentSection.id === sectionId) {
+ console.log('Current section is undefined or same as target section');
+ return prev;
+ }
let currentItem = currentSection?.items.find((item) => item.id === itemId);
- if (!currentItem) return prev;
+ if (!currentItem) {
+ console.log('Current item is undefined');
+ return prev;
+ }
return {
...prev,
diff --git a/src/components/Dashboard/Views/DashboardView.tsx b/src/components/Dashboard/Views/DashboardView.tsx
index 21091f2f5..304a72596 100644
--- a/src/components/Dashboard/Views/DashboardView.tsx
+++ b/src/components/Dashboard/Views/DashboardView.tsx
@@ -9,9 +9,9 @@ import {
import { useResize } from '~/hooks/use-resize';
import { useScreenLargerThan } from '~/hooks/useScreenLargerThan';
+import { EmptySectionWrapper } from '../../Board/Sections/EmptySection';
import { DashboardCategory } from '../Wrappers/Category/Category';
import { DashboardSidebar } from '../Wrappers/Sidebar/Sidebar';
-import { DashboardWrapper } from '../Wrappers/Wrapper/Wrapper';
import { useGridstackStore } from '../Wrappers/gridstack/store';
export const BoardView = () => {
@@ -43,7 +43,7 @@ export const BoardView = () => {
item.type === 'category' ? (
) : (
-
+
)
)}
@@ -55,17 +55,6 @@ export const BoardView = () => {
);
};
-//
-//
-/*
-{sidebarsVisible.left ? (
-
- ) : null}
-
-{sidebarsVisible.right ? (
-
- ) : null}
-*/
const usePrepareGridstack = () => {
const mainAreaRef = useRef(null);
diff --git a/src/components/Dashboard/Views/ViewToggleButton.tsx b/src/components/Dashboard/Views/ViewToggleButton.tsx
deleted file mode 100644
index 5502edcf9..000000000
--- a/src/components/Dashboard/Views/ViewToggleButton.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { ActionIcon, Button, Text, Tooltip } from '@mantine/core';
-import { IconEdit, IconEditOff } from '@tabler/icons-react';
-import { useTranslation } from 'next-i18next';
-
-import { useScreenLargerThan } from '~/hooks/useScreenLargerThan';
-import { useEditModeStore } from './useEditModeStore';
-
-export const ViewToggleButton = () => {
- const screenLargerThanMd = useScreenLargerThan('md');
- const { enabled: isEditMode, toggleEditMode } = useEditModeStore();
- const { t } = useTranslation('layout/header/actions/toggle-edit-mode');
-
- return (
- {t('description')}}>
- {screenLargerThanMd ? (
- : }
- onClick={() => toggleEditMode()}
- color={isEditMode ? 'red' : undefined}
- radius="md"
- >
- {isEditMode ? t('button.enabled') : t('button.disabled')}
-
- ) : (
- toggleEditMode()}
- variant="default"
- radius="md"
- size="xl"
- color="blue"
- >
- {isEditMode ? : }
-
- )}
-
- );
-};
diff --git a/src/components/Dashboard/Wrappers/Category/CategoryEditMenu.tsx b/src/components/Dashboard/Wrappers/Category/CategoryEditMenu.tsx
index 514f36e67..05ce1db76 100644
--- a/src/components/Dashboard/Wrappers/Category/CategoryEditMenu.tsx
+++ b/src/components/Dashboard/Wrappers/Category/CategoryEditMenu.tsx
@@ -8,11 +8,11 @@ import {
IconTransitionTop,
IconTrash,
} from '@tabler/icons-react';
-
+import { useTranslation } from 'next-i18next';
import { useConfigContext } from '~/config/provider';
import { CategoryType } from '~/types/category';
-import { useCategoryActions } from './useCategoryActions';
-import { useTranslation } from 'next-i18next';
+
+import { useCategoryActionHelper } from './useCategoryActions';
interface CategoryEditMenuProps {
category: CategoryType;
@@ -21,8 +21,8 @@ interface CategoryEditMenuProps {
export const CategoryEditMenu = ({ category }: CategoryEditMenuProps) => {
const { name: configName } = useConfigContext();
const { addCategoryAbove, addCategoryBelow, moveCategoryUp, moveCategoryDown, edit, remove } =
- useCategoryActions(configName, category);
- const { t } = useTranslation(['layout/common','common']);
+ useCategoryActionHelper(configName, category);
+ const { t } = useTranslation(['layout/common', 'common']);
return (
diff --git a/src/components/Dashboard/Wrappers/Category/useCategoryActions.tsx b/src/components/Dashboard/Wrappers/Category/useCategoryActions.tsx
index e954a2c9a..4d87817ae 100644
--- a/src/components/Dashboard/Wrappers/Category/useCategoryActions.tsx
+++ b/src/components/Dashboard/Wrappers/Category/useCategoryActions.tsx
@@ -1,15 +1,20 @@
import { v4 as uuidv4 } from 'uuid';
-
+import { useCategoryActions } from '~/components/Board/category-actions';
+import { useRequiredBoard } from '~/components/Board/context';
import { useConfigStore } from '~/config/store';
import { openContextModalGeneric } from '~/tools/mantineModalManagerExtensions';
import { AppType } from '~/types/app';
import { CategoryType } from '~/types/category';
import { WrapperType } from '~/types/wrapper';
import { IWidget } from '~/widgets/widgets';
+
import { CategoryEditModalInnerProps } from './CategoryEditModal';
-export const useCategoryActions = (configName: string | undefined, category: CategoryType) => {
- const updateConfig = useConfigStore((x) => x.updateConfig);
+export const useCategoryActionHelper = (configName: string | undefined, category: CategoryType) => {
+ const boardName = useRequiredBoard().name;
+ const { addCategory, moveCategory, removeCategory, renameCategory } = useCategoryActions({
+ boardName,
+ });
// creates a new category above the current
const addCategoryAbove = () => {
@@ -24,43 +29,10 @@ export const useCategoryActions = (configName: string | undefined, category: Cat
position: abovePosition + 1,
},
onSuccess: async (category) => {
- if (!configName) return;
-
- const newWrapper: WrapperType = {
- id: uuidv4(),
- position: abovePosition + 2,
- };
-
- // Adding category and wrapper and moving other items down
- updateConfig(
- configName,
- (previous) => {
- const aboveWrappers = previous.wrappers.filter((x) => x.position <= abovePosition);
- const aboveCategories = previous.categories.filter(
- (x) => x.position <= abovePosition
- );
-
- const belowWrappers = previous.wrappers.filter((x) => x.position > abovePosition);
- const belowCategories = previous.categories.filter((x) => x.position > abovePosition);
-
- return {
- ...previous,
- categories: [
- ...aboveCategories,
- category,
- // Move categories below down
- ...belowCategories.map((x) => ({ ...x, position: x.position + 1 })),
- ],
- wrappers: [
- ...aboveWrappers,
- newWrapper,
- // Move wrappers below down
- ...belowWrappers.map((x) => ({ ...x, position: x.position + 1 })),
- ],
- };
- },
- true
- );
+ addCategory({
+ name: category.name,
+ position: category.position,
+ });
},
},
});
@@ -79,194 +51,35 @@ export const useCategoryActions = (configName: string | undefined, category: Cat
position: belowPosition + 1,
},
onSuccess: async (category) => {
- if (!configName) return;
-
- const newWrapper: WrapperType = {
- id: uuidv4(),
- position: belowPosition,
- };
-
- // Adding category and wrapper and moving other items down
- updateConfig(
- configName,
- (previous) => {
- const aboveWrappers = previous.wrappers.filter((x) => x.position < belowPosition);
- const aboveCategories = previous.categories.filter((x) => x.position < belowPosition);
-
- const belowWrappers = previous.wrappers.filter((x) => x.position >= belowPosition);
- const belowCategories = previous.categories.filter(
- (x) => x.position >= belowPosition
- );
-
- return {
- ...previous,
- categories: [
- ...aboveCategories,
- category,
- // Move categories below down
- ...belowCategories.map((x) => ({ ...x, position: x.position + 2 })),
- ],
- wrappers: [
- ...aboveWrappers,
- newWrapper,
- // Move wrappers below down
- ...belowWrappers.map((x) => ({ ...x, position: x.position + 2 })),
- ],
- };
- },
- true
- );
+ addCategory({
+ name: category.name,
+ position: category.position,
+ });
},
},
});
};
const moveCategoryUp = () => {
- if (!configName) return;
-
- updateConfig(
- configName,
- (previous) => {
- const currentItem = previous.categories.find((x) => x.id === category.id);
- if (!currentItem) return previous;
-
- const upperItem = previous.categories.find((x) => x.position === currentItem.position - 1);
-
- if (!upperItem) return previous;
-
- currentItem.position -= 1;
- upperItem.position += 1;
-
- return {
- ...previous,
- categories: [
- ...previous.categories.filter((c) => ![currentItem.id, upperItem.id].includes(c.id)),
- { ...upperItem },
- { ...currentItem },
- ],
- };
- },
- true
- );
+ moveCategory({
+ id: category.id,
+ direction: 'up',
+ });
};
const moveCategoryDown = () => {
- if (!configName) return;
-
- updateConfig(
- configName,
- (previous) => {
- const currentItem = previous.categories.find((x) => x.id === category.id);
- if (!currentItem) return previous;
-
- const belowItem = previous.categories.find((x) => x.position === currentItem.position + 1);
-
- if (!belowItem) return previous;
-
- currentItem.position += 1;
- belowItem.position -= 1;
-
- return {
- ...previous,
- categories: [
- ...previous.categories.filter((c) => ![currentItem.id, belowItem.id].includes(c.id)),
- { ...currentItem },
- { ...belowItem },
- ],
- };
- },
- true
- );
+ moveCategory({
+ id: category.id,
+ direction: 'down',
+ });
};
// Removes the current category
const remove = () => {
- if (!configName) return;
- updateConfig(
- configName,
- (previous) => {
- const currentItem = previous.categories.find((x) => x.id === category.id);
- if (!currentItem) return previous;
- // Find the main wrapper
- const mainWrapper = previous.wrappers.find((x) => x.position === 0);
- const mainWrapperId = mainWrapper?.id ?? 'default';
-
- const isAppAffectedFilter = (app: AppType): boolean => {
- if (!app.area) {
- return false;
- }
-
- if (app.area.type !== 'category') {
- return false;
- }
-
- if (app.area.properties.id === mainWrapperId) {
- return false;
- }
-
- return app.area.properties.id === currentItem.id;
- };
-
- const isWidgetAffectedFilter = (widget: IWidget): boolean => {
- if (!widget.area) {
- return false;
- }
-
- if (widget.area.type !== 'category') {
- return false;
- }
-
- if (widget.area.properties.id === mainWrapperId) {
- return false;
- }
-
- return widget.area.properties.id === currentItem.id;
- };
-
- return {
- ...previous,
- apps: [
- ...previous.apps.filter((x) => !isAppAffectedFilter(x)),
- ...previous.apps
- .filter((x) => isAppAffectedFilter(x))
- .map(
- (app): AppType => ({
- ...app,
- area: {
- ...app.area,
- type: 'wrapper',
- properties: {
- ...app.area.properties,
- id: mainWrapperId,
- },
- },
- })
- ),
- ],
- widgets: [
- ...previous.widgets.filter((widget) => !isWidgetAffectedFilter(widget)),
- ...previous.widgets
- .filter((widget) => isWidgetAffectedFilter(widget))
- .map(
- (widget): IWidget => ({
- ...widget,
- area: {
- ...widget.area,
- type: 'wrapper',
- properties: {
- ...widget.area.properties,
- id: mainWrapperId,
- },
- },
- })
- ),
- ],
- categories: previous.categories.filter((x) => x.id !== category.id),
- wrappers: previous.wrappers.filter((x) => x.position !== currentItem.position),
- };
- },
- true
- );
+ // TODO: contained apps are currently just deleted
+ removeCategory({
+ id: category.id,
+ });
};
const edit = async () => {
@@ -276,14 +89,9 @@ export const useCategoryActions = (configName: string | undefined, category: Cat
innerProps: {
category,
onSuccess: async (category) => {
- if (!configName) return;
- await updateConfig(configName, (prev) => {
- const currentCategory = prev.categories.find((c) => c.id === category.id);
- if (!currentCategory) return prev;
- return {
- ...prev,
- categories: [...prev.categories.filter((c) => c.id !== category.id), { ...category }],
- };
+ renameCategory({
+ id: category.id,
+ name: category.name,
});
},
},
diff --git a/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts b/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts
index 3745812a1..8dba1646b 100644
--- a/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts
+++ b/src/components/Dashboard/Wrappers/gridstack/init-gridstack.ts
@@ -11,10 +11,6 @@ type InitializeGridstackProps = {
};
isEditMode: boolean;
sectionColumnCount: number;
- events: {
- onChange: (changedNode: GridStackNode) => void;
- onAdd: (addedNode: GridStackNode) => void;
- };
};
export const initializeGridstack = ({
@@ -22,7 +18,6 @@ export const initializeGridstack = ({
refs,
isEditMode,
sectionColumnCount,
- events,
}: InitializeGridstackProps) => {
if (!refs.wrapper.current) return;
// calculates the currently available count of columns
@@ -52,22 +47,6 @@ export const initializeGridstack = ({
// Must be used to update the column count after the initialization
grid.column(columnCount, 'none');
- // Add listener for moving items around in a wrapper
- grid.on('change', (_, el) => {
- const nodes = el as GridStackNode[];
- const firstNode = nodes.at(0);
- if (!firstNode) return;
- events.onChange(firstNode);
- });
-
- // Add listener for moving items in config from one wrapper to another
- grid.on('added', (_, el) => {
- const nodes = el as GridStackNode[];
- const firstNode = nodes.at(0);
- if (!firstNode) return;
- events.onAdd(firstNode);
- });
-
grid.batchUpdate();
grid.removeAll(false);
section.items.forEach((item) => {
diff --git a/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts b/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts
index 43bd7885c..ed1ced9be 100644
--- a/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts
+++ b/src/components/Dashboard/Wrappers/gridstack/use-gridstack.ts
@@ -1,19 +1,13 @@
+import { type GridItemHTMLElement, GridStack, type GridStackNode } from 'fily-publish-gridstack';
import {
- GridItemHTMLElement,
- GridStack,
- GridStackElement,
- GridStackNode,
-} from 'fily-publish-gridstack';
-import {
- MutableRefObject,
- RefObject,
+ type MutableRefObject,
+ type RefObject,
createRef,
- useCallback,
useEffect,
useMemo,
useRef,
} from 'react';
-import { Section, useRequiredBoard } from '~/components/Board/context';
+import { type Section, useRequiredBoard } from '~/components/Board/context';
import { useItemActions } from '~/components/Board/item-actions';
import { useEditModeStore } from '../../Views/useEditModeStore';
@@ -59,7 +53,7 @@ export const useGridstack = ({ section }: UseGridstackProps): UseGristackReturnT
// define items in itemRefs for easy access and reference to items
if (Object.keys(itemRefs.current).length !== items.length) {
items.forEach(({ id }: { id: keyof typeof itemRefs.current }) => {
- itemRefs.current[id] = itemRefs.current[id] || createRef();
+ itemRefs.current[id] = itemRefs.current[id] ?? createRef();
});
}
@@ -80,53 +74,60 @@ export const useGridstack = ({ section }: UseGridstackProps): UseGristackReturnT
gridRef.current?.setStatic(!isEditMode);
}, [isEditMode]);
- const onChange = useCallback(
- (changedNode: GridStackNode) => {
- if (!isEditMode) return;
+ const onChange = (changedNode: GridStackNode) => {
+ const itemType = changedNode.el?.getAttribute('data-type');
+ const itemId = changedNode.el?.getAttribute('data-id');
+ if (!itemType || !itemId) return;
- const itemType = changedNode.el?.getAttribute('data-type');
- const itemId = changedNode.el?.getAttribute('data-id');
- if (!itemType || !itemId) return;
+ // Updates the react-query state
+ moveAndResizeItem({
+ itemId,
+ x: changedNode.x!,
+ y: changedNode.y!,
+ width: changedNode.w!,
+ height: changedNode.h!,
+ });
+ };
+ const onAdd = (addedNode: GridStackNode) => {
+ const itemType = addedNode.el?.getAttribute('data-type');
+ const itemId = addedNode.el?.getAttribute('data-id');
+ if (!itemType || !itemId) return;
- // Updates the config and defines the new position of the item
- moveAndResizeItem({
- itemId,
- x: changedNode.x!,
- y: changedNode.y!,
- width: changedNode.w!,
- height: changedNode.h!,
- });
- },
- [isEditMode]
- );
+ // Updates the react-query state
+ moveItemToSection({
+ itemId,
+ sectionId: section.id,
+ x: addedNode.x!,
+ y: addedNode.y!,
+ width: addedNode.w!,
+ height: addedNode.h!,
+ });
+ };
- const onAdd = useCallback(
- (addedNode: GridStackNode) => {
- if (!isEditMode) return;
+ useEffect(() => {
+ if (!isEditMode) return;
+ // Add listener for moving items around in a wrapper
+ gridRef.current?.on('change', (_, nodes) => {
+ (nodes as GridStackNode[]).forEach(onChange);
+ });
- const itemType = addedNode.el?.getAttribute('data-type');
- const itemId = addedNode.el?.getAttribute('data-id');
- if (!itemType || !itemId) return;
+ // Add listener for moving items in config from one wrapper to another
+ gridRef.current?.on('added', (_, el) => {
+ const nodes = el as GridStackNode[];
+ const firstNode = nodes.at(0);
+ if (!firstNode) return;
+ onAdd(firstNode);
+ });
- moveItemToSection({
- itemId,
- sectionId: section.id,
- x: addedNode.x!,
- y: addedNode.y!,
- width: addedNode.w!,
- height: addedNode.h!,
- });
- },
- [isEditMode]
- );
+ return () => {
+ gridRef.current?.off('change');
+ gridRef.current?.off('added');
+ };
+ }, [isEditMode]);
// initialize the gridstack
useEffect(() => {
initializeGridstack({
- events: {
- onChange,
- onAdd,
- },
isEditMode,
section,
refs: {
@@ -136,13 +137,7 @@ export const useGridstack = ({ section }: UseGridstackProps): UseGristackReturnT
},
sectionColumnCount,
});
-
- // Remove event listeners on unmount
- return () => {
- gridRef.current?.off('change');
- gridRef.current?.off('added');
- };
- }, [items, wrapperRef.current, sectionColumnCount]);
+ }, [items.length, wrapperRef.current, sectionColumnCount]);
return {
refs: {
diff --git a/src/server/api/routers/board.ts b/src/server/api/routers/board.ts
index c4ad1aab7..1486c2dfa 100644
--- a/src/server/api/routers/board.ts
+++ b/src/server/api/routers/board.ts
@@ -245,8 +245,8 @@ export const boardRouter = createTRPCRouter({
iconUrl: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/github.png',
width: 2,
height: 1,
- x: 3,
- y: 1,
+ x: 2,
+ y: 0,
});
await addApp({
@@ -257,8 +257,8 @@ export const boardRouter = createTRPCRouter({
iconUrl: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/discord.png',
width: 2,
height: 1,
- x: 5,
- y: 1,
+ x: 4,
+ y: 0,
});
await addApp({
@@ -269,8 +269,8 @@ export const boardRouter = createTRPCRouter({
iconUrl: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/ko-fi.png',
width: 2,
height: 1,
- x: 7,
- y: 1,
+ x: 6,
+ y: 0,
});
await addApp({
@@ -281,8 +281,8 @@ export const boardRouter = createTRPCRouter({
iconUrl: '/imgs/logo/logo.png',
width: 2,
height: 2,
- x: 7,
- y: 2,
+ x: 6,
+ y: 1,
});
await addWidget({
@@ -291,8 +291,8 @@ export const boardRouter = createTRPCRouter({
type: 'weather',
width: 2,
height: 1,
- x: 1,
- y: 1,
+ x: 0,
+ y: 0,
});
await addWidget({
@@ -301,8 +301,8 @@ export const boardRouter = createTRPCRouter({
type: 'date',
width: 2,
height: 1,
- x: 9,
- y: 1,
+ x: 8,
+ y: 0,
});
await addWidget({
@@ -311,8 +311,8 @@ export const boardRouter = createTRPCRouter({
type: 'date',
width: 2,
height: 1,
- x: 9,
- y: 2,
+ x: 8,
+ y: 1,
});
await addWidget({
@@ -321,8 +321,8 @@ export const boardRouter = createTRPCRouter({
type: 'notebook',
width: 6,
height: 3,
- x: 1,
- y: 2,
+ x: 0,
+ y: 1,
});
}),
});