Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68d4956077 | ||
|
|
84588c956d | ||
|
|
73550ce998 | ||
|
|
41fe5928f1 | ||
|
|
6eb59d6f53 | ||
|
|
2c6b7a818e | ||
|
|
fd10788838 | ||
|
|
71d7332505 | ||
|
|
eae51a8447 | ||
|
|
e9308db5dc | ||
|
|
fb06b55845 | ||
|
|
108b488250 | ||
|
|
10cedbd906 | ||
|
|
f53527e2e7 | ||
|
|
121cff20d7 | ||
|
|
e14da6f747 |
No files matched your search
@@ -1,9 +1,11 @@
|
||||
import { cache } from "react";
|
||||
|
||||
import { api } from "@homarr/api/server";
|
||||
|
||||
import { createBoardContentPage } from "../_creator";
|
||||
|
||||
const getHomeBoardAsync = cache(() => api.board.getHomeBoard());
|
||||
|
||||
export default createBoardContentPage<{ locale: string }>({
|
||||
async getInitialBoardAsync() {
|
||||
return await api.board.getHomeBoard();
|
||||
},
|
||||
getInitialBoardAsync: getHomeBoardAsync,
|
||||
});
|
||||
@@ -1,9 +1,11 @@
|
||||
import { cache } from "react";
|
||||
|
||||
import { api } from "@homarr/api/server";
|
||||
|
||||
import { createBoardContentPage } from "../../_creator";
|
||||
|
||||
const getBoardByNameAsync = cache((name: string) => api.board.getBoardByName({ name }));
|
||||
|
||||
export default createBoardContentPage<{ locale: string; name: string }>({
|
||||
async getInitialBoardAsync({ name }) {
|
||||
return await api.board.getBoardByName({ name });
|
||||
},
|
||||
getInitialBoardAsync: async ({ name }) => getBoardByNameAsync(name),
|
||||
});
|
||||
@@ -1,33 +1,24 @@
|
||||
"use client";
|
||||
|
||||
import { Box, Stack } from "@mantine/core";
|
||||
import dynamic from "next/dynamic";
|
||||
import { Box } from "@mantine/core";
|
||||
|
||||
import { useCurrentLayout, useRequiredBoard } from "@homarr/boards/context";
|
||||
import { useRequiredBoard } from "@homarr/boards/context";
|
||||
import { useEditMode } from "@homarr/boards/edit-mode";
|
||||
|
||||
import { BoardCategorySection } from "~/components/board/sections/category-section";
|
||||
import { BoardEmptySection } from "~/components/board/sections/empty-section";
|
||||
import { StaticBoardGrid } from "~/components/board/sections/static-grid";
|
||||
import { BoardBackgroundVideo } from "~/components/layout/background";
|
||||
|
||||
const EditModeBoard = dynamic(() => import("./_edit-board"), { ssr: false });
|
||||
|
||||
export const ClientBoard = () => {
|
||||
const board = useRequiredBoard();
|
||||
const currentLayoutId = useCurrentLayout();
|
||||
|
||||
const fullWidthSortedSections = board.sections
|
||||
.filter((section) => section.kind === "empty" || section.kind === "category")
|
||||
.sort((sectionA, sectionB) => sectionA.yOffset - sectionB.yOffset);
|
||||
const [isEditMode] = useEditMode();
|
||||
|
||||
return (
|
||||
<Box h="100%" pos="relative">
|
||||
<BoardBackgroundVideo />
|
||||
<Stack h="100%">
|
||||
{fullWidthSortedSections.map((section) =>
|
||||
section.kind === "empty" ? (
|
||||
<BoardEmptySection key={`${currentLayoutId}-${section.id}`} section={section} />
|
||||
) : (
|
||||
<BoardCategorySection key={`${currentLayoutId}-${section.id}`} section={section} />
|
||||
),
|
||||
)}
|
||||
</Stack>
|
||||
{isEditMode ? <EditModeBoard /> : <StaticBoardGrid board={board} />}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -1,7 +1,3 @@
|
||||
"use client";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
export const DynamicClientBoard = dynamic(() => import("./_client").then((mod) => mod.ClientBoard), {
|
||||
ssr: false,
|
||||
});
|
||||
export { ClientBoard as DynamicClientBoard } from "./_client";
|
||||
@@ -0,0 +1,31 @@
|
||||
"use client";
|
||||
|
||||
import { Stack } from "@mantine/core";
|
||||
|
||||
import { useCurrentLayout, useRequiredBoard } from "@homarr/boards/context";
|
||||
|
||||
import { BoardCategorySection } from "~/components/board/sections/category-section";
|
||||
import { BoardEmptySection } from "~/components/board/sections/empty-section";
|
||||
|
||||
const EditModeBoard = () => {
|
||||
const board = useRequiredBoard();
|
||||
const currentLayoutId = useCurrentLayout();
|
||||
|
||||
const fullWidthSortedSections = board.sections
|
||||
.filter((section) => section.kind === "empty" || section.kind === "category")
|
||||
.toSorted((sectionA, sectionB) => sectionA.yOffset - sectionB.yOffset);
|
||||
|
||||
return (
|
||||
<Stack h="100%">
|
||||
{fullWidthSortedSections.map((section) =>
|
||||
section.kind === "empty" ? (
|
||||
<BoardEmptySection key={`${currentLayoutId}-${section.id}`} section={section} />
|
||||
) : (
|
||||
<BoardCategorySection key={`${currentLayoutId}-${section.id}`} section={section} />
|
||||
),
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditModeBoard;
|
||||
@@ -19,6 +19,10 @@ import { BoardItemMenu } from "./item-menu";
|
||||
|
||||
interface BoardItemContentProps {
|
||||
item: SectionItem;
|
||||
fallbackDimensions?: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
}
|
||||
|
||||
const getOverflowFromKind = (kind: SectionItem["kind"]) => {
|
||||
@@ -27,9 +31,11 @@ const getOverflowFromKind = (kind: SectionItem["kind"]) => {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const BoardItemContent = ({ item }: BoardItemContentProps) => {
|
||||
export const BoardItemContent = ({ item, fallbackDimensions }: BoardItemContentProps) => {
|
||||
const { ref, width, height } = useElementSize<HTMLDivElement>();
|
||||
const board = useRequiredBoard();
|
||||
const fallbackWidth = fallbackDimensions?.width ?? 0;
|
||||
const fallbackHeight = fallbackDimensions?.height ?? 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -52,7 +58,7 @@ export const BoardItemContent = ({ item }: BoardItemContentProps) => {
|
||||
}}
|
||||
p={0}
|
||||
>
|
||||
<InnerContent item={item} width={width} height={height} />
|
||||
<InnerContent item={item} width={width || fallbackWidth} height={height || fallbackHeight} />
|
||||
</Card>
|
||||
{item.advancedOptions.title?.trim() && (
|
||||
<Badge
|
||||
|
||||
@@ -12,7 +12,7 @@ import { widgetImports } from "@homarr/widgets";
|
||||
import { WidgetEditModal } from "@homarr/widgets/modals";
|
||||
|
||||
import type { SectionItem } from "~/app/[locale]/boards/_types";
|
||||
import { useSectionContext } from "../sections/section-context";
|
||||
import { useOptionalSectionContext } from "../sections/section-context";
|
||||
import { useItemActions } from "./item-actions";
|
||||
import { ItemMoveModal } from "./item-move-modal";
|
||||
|
||||
@@ -41,7 +41,8 @@ const BoardItemMenuInner = ({ offset, item, resetErrorBoundary }: BoardItemMenuP
|
||||
useItemActions();
|
||||
const { data: integrationData, isPending } = clientApi.integration.all.useQuery();
|
||||
const currentDefinition = useMemo(() => widgetImports[item.kind].definition, [item.kind]);
|
||||
const { gridstack } = useSectionContext().refs;
|
||||
const sectionContext = useOptionalSectionContext();
|
||||
const gridstack = sectionContext?.refs.gridstack;
|
||||
const settings = useSettings();
|
||||
|
||||
// Reset error boundary on next render if item has been edited
|
||||
@@ -127,7 +128,7 @@ const BoardItemMenuInner = ({ offset, item, resetErrorBoundary }: BoardItemMenuP
|
||||
<Menu.Item
|
||||
leftSection={<IconLayoutKanban size={16} />}
|
||||
onClick={() => {
|
||||
if (!gridstack.current) return;
|
||||
if (!gridstack?.current) return;
|
||||
openMoveModal({ item, columnCount: gridstack.current.getColumn(), gridStack: gridstack.current });
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,48 +1,21 @@
|
||||
import { Card, Collapse, Group, Stack, Title, UnstyledButton } from "@mantine/core";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { IconChevronDown, IconChevronUp } from "@tabler/icons-react";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useSession } from "@homarr/auth/client";
|
||||
import { useRequiredBoard } from "@homarr/boards/context";
|
||||
|
||||
import type { CategorySection } from "~/app/[locale]/boards/_types";
|
||||
import { CategoryMenu } from "./category/category-menu";
|
||||
import { GridStack } from "./gridstack/gridstack";
|
||||
import classes from "./item.module.css";
|
||||
|
||||
const localStorageKey = (sectionId: string) => `homarr-section-collapsed-${sectionId}`;
|
||||
import { useCategoryCollapse } from "./use-category-collapse";
|
||||
|
||||
interface Props {
|
||||
section: CategorySection;
|
||||
}
|
||||
|
||||
export const BoardCategorySection = ({ section }: Props) => {
|
||||
const { status } = useSession();
|
||||
const { mutate } = clientApi.section.changeCollapsed.useMutation();
|
||||
const board = useRequiredBoard();
|
||||
|
||||
const initialCollapsed =
|
||||
typeof window !== "undefined"
|
||||
? (localStorage.getItem(localStorageKey(section.id)) ?? String(section.collapsed)) === "true"
|
||||
: section.collapsed;
|
||||
|
||||
const [opened, { toggle }] = useDisclosure(initialCollapsed, {
|
||||
onOpen() {
|
||||
if (status === "authenticated") {
|
||||
mutate({ sectionId: section.id, collapsed: true });
|
||||
} else if (status === "unauthenticated") {
|
||||
localStorage.setItem(localStorageKey(section.id), "true");
|
||||
}
|
||||
},
|
||||
onClose() {
|
||||
if (status === "authenticated") {
|
||||
mutate({ sectionId: section.id, collapsed: false });
|
||||
} else if (status === "unauthenticated") {
|
||||
localStorage.setItem(localStorageKey(section.id), "false");
|
||||
}
|
||||
},
|
||||
});
|
||||
const [opened, { toggle }] = useCategoryCollapse(section);
|
||||
|
||||
return (
|
||||
<Card style={{ "--opacity": board.opacity / 100 }} radius={board.itemRadius} p={0} className={classes.itemCard}>
|
||||
|
||||
@@ -20,4 +20,8 @@ export const useSectionContext = () => {
|
||||
return context;
|
||||
};
|
||||
|
||||
export const useOptionalSectionContext = () => {
|
||||
return useContext(SectionContext);
|
||||
};
|
||||
|
||||
export const SectionProvider = SectionContext.Provider;
|
||||
@@ -0,0 +1,93 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { BoardMockBuilder } from "../items/actions/test/mocks/board-mock";
|
||||
import { DynamicSectionMockBuilder } from "../items/actions/test/mocks/dynamic-section-mock";
|
||||
import { ItemMockBuilder } from "../items/actions/test/mocks/item-mock";
|
||||
import { LayoutMockBuilder } from "../items/actions/test/mocks/layout-mock";
|
||||
import {
|
||||
getEstimatedGridWidth,
|
||||
getFallbackDimensions,
|
||||
getFullWidthSortedSections,
|
||||
getStaticGridElements,
|
||||
getStaticGridLayouts,
|
||||
getStaticGridRowCount,
|
||||
getStaticLayoutSelectionCss,
|
||||
} from "./static-grid-layout";
|
||||
|
||||
describe("static grid layout", () => {
|
||||
test("sorts layouts and creates breakpoint CSS in mobile-first order", () => {
|
||||
const mobile = new LayoutMockBuilder({ id: "mobile", breakpoint: 0, columnCount: 4 }).build();
|
||||
const tablet = new LayoutMockBuilder({ id: "tablet", breakpoint: 768, columnCount: 8 }).build();
|
||||
const desktop = new LayoutMockBuilder({ id: "desktop", breakpoint: 1024, columnCount: 12 }).build();
|
||||
|
||||
const sortedLayouts = getStaticGridLayouts([desktop, mobile, tablet]);
|
||||
const css = getStaticLayoutSelectionCss("board-1", sortedLayouts);
|
||||
|
||||
expect(sortedLayouts.map((layout) => layout.id)).toEqual(["mobile", "tablet", "desktop"]);
|
||||
expect(css).toContain('[data-static-layout="mobile"] { display: block; }');
|
||||
expect(css).toContain("@media (min-width: 768px)");
|
||||
expect(css).toContain('[data-static-layout="tablet"] { display: block; }');
|
||||
expect(css).toContain("@media (min-width: 1024px)");
|
||||
expect(css).toContain('[data-static-layout="desktop"] { display: block; }');
|
||||
});
|
||||
|
||||
test("selects and sorts layout-specific section elements", () => {
|
||||
const rootSectionId = "root";
|
||||
const mobileLayoutId = "mobile";
|
||||
const desktopLayoutId = "desktop";
|
||||
const mobile = new LayoutMockBuilder({ id: mobileLayoutId, breakpoint: 0, columnCount: 4 }).build();
|
||||
const desktop = new LayoutMockBuilder({ id: desktopLayoutId, breakpoint: 1024, columnCount: 12 }).build();
|
||||
const item = new ItemMockBuilder({ id: "item" })
|
||||
.addLayout({ layoutId: mobileLayoutId, sectionId: rootSectionId, xOffset: 2, yOffset: 1, width: 1, height: 1 })
|
||||
.addLayout({ layoutId: desktopLayoutId, sectionId: rootSectionId, xOffset: 0, yOffset: 1, width: 4, height: 2 })
|
||||
.build();
|
||||
const dynamicSection = new DynamicSectionMockBuilder({ id: "dynamic" })
|
||||
.addLayout({
|
||||
layoutId: mobileLayoutId,
|
||||
parentSectionId: rootSectionId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 2,
|
||||
height: 2,
|
||||
})
|
||||
.addLayout({
|
||||
layoutId: desktopLayoutId,
|
||||
parentSectionId: rootSectionId,
|
||||
xOffset: 4,
|
||||
yOffset: 1,
|
||||
width: 4,
|
||||
height: 2,
|
||||
})
|
||||
.build();
|
||||
const board = new BoardMockBuilder()
|
||||
.addEmptySection({ id: rootSectionId, yOffset: 2 })
|
||||
.addEmptySection({ id: "first", yOffset: 0 })
|
||||
.addSection(dynamicSection)
|
||||
.addItem(item)
|
||||
.build();
|
||||
board.layouts = [desktop, mobile];
|
||||
|
||||
const mobileElements = getStaticGridElements(board, rootSectionId, mobileLayoutId);
|
||||
const desktopElements = getStaticGridElements(board, rootSectionId, desktopLayoutId);
|
||||
const fullWidthSections = getFullWidthSortedSections(board);
|
||||
|
||||
expect(mobileElements.map((element) => element.id)).toEqual(["dynamic", "item"]);
|
||||
expect(desktopElements.map((element) => ({ id: element.id, width: element.width }))).toEqual([
|
||||
{ id: "item", width: 4 },
|
||||
{ id: "dynamic", width: 4 },
|
||||
]);
|
||||
expect(getStaticGridRowCount(mobileElements)).toBe(2);
|
||||
expect(fullWidthSections.map((section) => section.id)).toEqual(["first", rootSectionId]);
|
||||
});
|
||||
|
||||
test("estimates grid and item dimensions per layout range", () => {
|
||||
const mobile = new LayoutMockBuilder({ id: "mobile", breakpoint: 0, columnCount: 4 }).build();
|
||||
const tablet = new LayoutMockBuilder({ id: "tablet", breakpoint: 768, columnCount: 8 }).build();
|
||||
const desktop = new LayoutMockBuilder({ id: "desktop", breakpoint: 1024, columnCount: 12 }).build();
|
||||
|
||||
expect(getEstimatedGridWidth(mobile, tablet)).toBe(384);
|
||||
expect(getEstimatedGridWidth(tablet, desktop)).toBe(896);
|
||||
expect(getEstimatedGridWidth(desktop)).toBe(1280);
|
||||
expect(getFallbackDimensions({ width: 2, height: 3 }, 400, 4)).toEqual({ width: 180, height: 280 });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
import type { Board, DynamicSectionItem, EmptySection, SectionItem } from "~/app/[locale]/boards/_types";
|
||||
|
||||
type BoardLayout = Board["layouts"][number];
|
||||
type StaticGridElement = SectionItem | DynamicSectionItem;
|
||||
|
||||
const STATIC_GRID_ITEM_INSET = 20;
|
||||
const DEFAULT_SMALL_VIEWPORT_WIDTH = 360;
|
||||
const DEFAULT_LARGE_VIEWPORT_WIDTH = 1280;
|
||||
|
||||
export const getStaticGridLayouts = (layouts: Board["layouts"]) =>
|
||||
[...layouts].toSorted((layoutA, layoutB) => layoutA.breakpoint - layoutB.breakpoint);
|
||||
|
||||
const escapeCssString = (value: string) => value.replaceAll("\\", "\\\\").replaceAll('"', '\\"');
|
||||
|
||||
export const getStaticLayoutSelectionCss = (boardId: string, layouts: Board["layouts"]) => {
|
||||
const sortedLayouts = getStaticGridLayouts(layouts);
|
||||
const initialLayout = sortedLayouts.at(0);
|
||||
|
||||
if (!initialLayout) return "";
|
||||
|
||||
const scope = `[data-static-board="${escapeCssString(boardId)}"]`;
|
||||
const css = [
|
||||
`${scope} .static-board-layout { display: none; }`,
|
||||
`${scope} .static-board-layout[data-static-layout="${escapeCssString(initialLayout.id)}"] { display: block; }`,
|
||||
];
|
||||
|
||||
for (const layout of sortedLayouts.slice(1)) {
|
||||
css.push(
|
||||
`@media (min-width: ${layout.breakpoint}px) { ${scope} .static-board-layout { display: none; } ${scope} .static-board-layout[data-static-layout="${escapeCssString(layout.id)}"] { display: block; } }`,
|
||||
);
|
||||
}
|
||||
|
||||
return css.join("\n");
|
||||
};
|
||||
|
||||
export const getFullWidthSortedSections = (board: Board) =>
|
||||
board.sections
|
||||
.filter(
|
||||
(section): section is EmptySection | Extract<Board["sections"][number], { kind: "category" }> =>
|
||||
section.kind === "empty" || section.kind === "category",
|
||||
)
|
||||
.sort((sectionA, sectionB) => sectionA.yOffset - sectionB.yOffset);
|
||||
|
||||
export const getSectionItemsForLayout = (board: Board, sectionId: string, layoutId: string): SectionItem[] => {
|
||||
return board.items
|
||||
.map(({ layouts, ...item }) => {
|
||||
const layout = layouts.find((candidate) => candidate.layoutId === layoutId);
|
||||
if (!layout) return null;
|
||||
return { ...layout, ...item, type: "item" as const };
|
||||
})
|
||||
.filter((item): item is SectionItem => item !== null && item.sectionId === sectionId);
|
||||
};
|
||||
|
||||
export const getDynamicSectionsForLayout = (
|
||||
board: Board,
|
||||
sectionId: string,
|
||||
layoutId: string,
|
||||
): DynamicSectionItem[] => {
|
||||
return board.sections
|
||||
.filter((section) => section.kind === "dynamic")
|
||||
.map(({ layouts, ...section }) => {
|
||||
const layout = layouts.find((candidate) => candidate.layoutId === layoutId);
|
||||
if (!layout) return null;
|
||||
return { ...layout, ...section, type: "section" as const };
|
||||
})
|
||||
.filter((entry): entry is DynamicSectionItem => entry !== null && entry.parentSectionId === sectionId);
|
||||
};
|
||||
|
||||
export const getStaticGridElements = (board: Board, sectionId: string, layoutId: string): StaticGridElement[] => {
|
||||
return [
|
||||
...getSectionItemsForLayout(board, sectionId, layoutId),
|
||||
...getDynamicSectionsForLayout(board, sectionId, layoutId),
|
||||
].toSorted((itemA, itemB) => {
|
||||
if (itemA.yOffset === itemB.yOffset) return itemA.xOffset - itemB.xOffset;
|
||||
return itemA.yOffset - itemB.yOffset;
|
||||
});
|
||||
};
|
||||
|
||||
export const getStaticGridRowCount = (items: StaticGridElement[], fixedRowCount?: number) => {
|
||||
return fixedRowCount ?? Math.max(...items.map((item) => item.yOffset + item.height));
|
||||
};
|
||||
|
||||
export const getEstimatedGridWidth = (layout: BoardLayout, nextLayout?: BoardLayout) => {
|
||||
if (nextLayout) {
|
||||
const upperBound = Math.max(nextLayout.breakpoint - 1, DEFAULT_SMALL_VIEWPORT_WIDTH);
|
||||
return Math.max(DEFAULT_SMALL_VIEWPORT_WIDTH, Math.round((layout.breakpoint + upperBound) / 2));
|
||||
}
|
||||
|
||||
return Math.max(layout.breakpoint, DEFAULT_LARGE_VIEWPORT_WIDTH);
|
||||
};
|
||||
|
||||
export const getFallbackDimensions = (
|
||||
item: Pick<StaticGridElement, "width" | "height">,
|
||||
estimatedGridWidth: number,
|
||||
columnCount: number,
|
||||
) => {
|
||||
const cellSize = estimatedGridWidth / columnCount;
|
||||
|
||||
return {
|
||||
width: Math.max(0, item.width * cellSize - STATIC_GRID_ITEM_INSET),
|
||||
height: Math.max(0, item.height * cellSize - STATIC_GRID_ITEM_INSET),
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,289 @@
|
||||
"use client";
|
||||
|
||||
import { Badge, Card, Collapse, Group, Stack, Title, UnstyledButton } from "@mantine/core";
|
||||
import { IconChevronDown, IconChevronUp } from "@tabler/icons-react";
|
||||
|
||||
import { useRequiredBoard } from "@homarr/boards/context";
|
||||
|
||||
import type {
|
||||
Board,
|
||||
CategorySection,
|
||||
DynamicSectionItem,
|
||||
EmptySection,
|
||||
SectionItem,
|
||||
} from "~/app/[locale]/boards/_types";
|
||||
import { BoardItemContent } from "../items/item-content";
|
||||
import { CategoryMenu } from "./category/category-menu";
|
||||
import classes from "./item.module.css";
|
||||
import {
|
||||
getEstimatedGridWidth,
|
||||
getFallbackDimensions,
|
||||
getFullWidthSortedSections,
|
||||
getStaticGridElements,
|
||||
getStaticGridLayouts,
|
||||
getStaticGridRowCount,
|
||||
getStaticLayoutSelectionCss,
|
||||
} from "./static-grid-layout";
|
||||
import { useCategoryCollapse } from "./use-category-collapse";
|
||||
|
||||
interface StaticBoardGridProps {
|
||||
board: Board;
|
||||
}
|
||||
|
||||
export const StaticBoardGrid = ({ board }: StaticBoardGridProps) => {
|
||||
const boardId = `board-${board.id}`;
|
||||
const layouts = getStaticGridLayouts(board.layouts);
|
||||
const layoutSelectionCss = getStaticLayoutSelectionCss(boardId, layouts);
|
||||
const fullWidthSortedSections = getFullWidthSortedSections(board);
|
||||
|
||||
if (layouts.length === 0) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{layoutSelectionCss}</style>
|
||||
<div data-static-board={boardId}>
|
||||
{layouts.map((layout, index) => (
|
||||
<div key={layout.id} className="static-board-layout" data-static-layout={layout.id}>
|
||||
<Stack h="100%">
|
||||
{fullWidthSortedSections.map((section) =>
|
||||
section.kind === "empty" ? (
|
||||
<StaticEmptySection
|
||||
key={section.id}
|
||||
section={section}
|
||||
board={board}
|
||||
layoutId={layout.id}
|
||||
columnCount={layout.columnCount}
|
||||
estimatedGridWidth={getEstimatedGridWidth(layout, layouts.at(index + 1))}
|
||||
/>
|
||||
) : (
|
||||
<StaticCategorySection
|
||||
key={section.id}
|
||||
section={section}
|
||||
board={board}
|
||||
layoutId={layout.id}
|
||||
columnCount={layout.columnCount}
|
||||
estimatedGridWidth={getEstimatedGridWidth(layout, layouts.at(index + 1))}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</Stack>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface StaticSectionGridProps {
|
||||
sectionId: string;
|
||||
board: Board;
|
||||
layoutId: string;
|
||||
columnCount: number;
|
||||
estimatedGridWidth: number;
|
||||
isDynamic?: boolean;
|
||||
fixedRowCount?: number;
|
||||
}
|
||||
|
||||
const StaticSectionGrid = ({
|
||||
sectionId,
|
||||
board,
|
||||
layoutId,
|
||||
columnCount,
|
||||
estimatedGridWidth,
|
||||
isDynamic,
|
||||
fixedRowCount,
|
||||
}: StaticSectionGridProps) => {
|
||||
const allItems = getStaticGridElements(board, sectionId, layoutId);
|
||||
|
||||
if (allItems.length === 0) return null;
|
||||
|
||||
const rowCount = getStaticGridRowCount(allItems, fixedRowCount);
|
||||
|
||||
return (
|
||||
<div className="static-grid-container" style={{ height: isDynamic ? "100%" : undefined }}>
|
||||
<div
|
||||
className="static-grid"
|
||||
style={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${columnCount}, 1fr)`,
|
||||
gridTemplateRows: isDynamic
|
||||
? `repeat(${rowCount}, 1fr)`
|
||||
: `repeat(${rowCount}, calc(100cqi / ${columnCount}))`,
|
||||
height: isDynamic ? "100%" : undefined,
|
||||
}}
|
||||
>
|
||||
{allItems.map((item) => (
|
||||
<StaticGridItem
|
||||
key={item.id}
|
||||
item={item}
|
||||
board={board}
|
||||
layoutId={layoutId}
|
||||
estimatedGridWidth={estimatedGridWidth}
|
||||
columnCount={columnCount}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface StaticGridItemProps {
|
||||
item: SectionItem | DynamicSectionItem;
|
||||
board: Board;
|
||||
layoutId: string;
|
||||
estimatedGridWidth: number;
|
||||
columnCount: number;
|
||||
}
|
||||
|
||||
const StaticGridItem = ({ item, board, layoutId, estimatedGridWidth, columnCount }: StaticGridItemProps) => {
|
||||
const fallbackDimensions = getFallbackDimensions(item, estimatedGridWidth, columnCount);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
gridColumn: `${item.xOffset + 1} / span ${item.width}`,
|
||||
gridRow: `${item.yOffset + 1} / span ${item.height}`,
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<div className="static-grid-item-content">
|
||||
{item.type === "item" ? (
|
||||
<BoardItemContent item={item} fallbackDimensions={fallbackDimensions} />
|
||||
) : (
|
||||
<StaticDynamicSection
|
||||
section={item}
|
||||
board={board}
|
||||
layoutId={layoutId}
|
||||
estimatedGridWidth={fallbackDimensions.width}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface StaticEmptySectionProps {
|
||||
section: EmptySection;
|
||||
board: Board;
|
||||
layoutId: string;
|
||||
columnCount: number;
|
||||
estimatedGridWidth: number;
|
||||
}
|
||||
|
||||
const StaticEmptySection = ({ section, board, layoutId, columnCount, estimatedGridWidth }: StaticEmptySectionProps) => {
|
||||
const items = getStaticGridElements(board, section.id, layoutId);
|
||||
|
||||
if (items.length === 0) return null;
|
||||
|
||||
return (
|
||||
<StaticSectionGrid
|
||||
sectionId={section.id}
|
||||
board={board}
|
||||
layoutId={layoutId}
|
||||
columnCount={columnCount}
|
||||
estimatedGridWidth={estimatedGridWidth}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
interface StaticCategorySectionProps {
|
||||
section: CategorySection;
|
||||
board: Board;
|
||||
layoutId: string;
|
||||
columnCount: number;
|
||||
estimatedGridWidth: number;
|
||||
}
|
||||
|
||||
const StaticCategorySection = ({
|
||||
section,
|
||||
board,
|
||||
layoutId,
|
||||
columnCount,
|
||||
estimatedGridWidth,
|
||||
}: StaticCategorySectionProps) => {
|
||||
const boardData = useRequiredBoard();
|
||||
const [opened, { toggle }] = useCategoryCollapse(section);
|
||||
|
||||
return (
|
||||
<Card
|
||||
style={{ "--opacity": boardData.opacity / 100 }}
|
||||
radius={boardData.itemRadius}
|
||||
p={0}
|
||||
className={classes.itemCard}
|
||||
>
|
||||
<Stack>
|
||||
<Group wrap="nowrap" gap="sm">
|
||||
<UnstyledButton w="100%" p="sm" onClick={toggle}>
|
||||
<Group wrap="nowrap">
|
||||
{opened ? <IconChevronUp size={20} /> : <IconChevronDown size={20} />}
|
||||
<Title order={3}>{section.name}</Title>
|
||||
</Group>
|
||||
</UnstyledButton>
|
||||
<CategoryMenu category={section} />
|
||||
</Group>
|
||||
<Collapse expanded={opened} p="sm" pt={0}>
|
||||
<StaticSectionGrid
|
||||
sectionId={section.id}
|
||||
board={board}
|
||||
layoutId={layoutId}
|
||||
columnCount={columnCount}
|
||||
estimatedGridWidth={estimatedGridWidth}
|
||||
/>
|
||||
</Collapse>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
interface StaticDynamicSectionProps {
|
||||
section: DynamicSectionItem;
|
||||
board: Board;
|
||||
layoutId: string;
|
||||
estimatedGridWidth: number;
|
||||
}
|
||||
|
||||
const StaticDynamicSection = ({ section, board, layoutId, estimatedGridWidth }: StaticDynamicSectionProps) => {
|
||||
const boardData = useRequiredBoard();
|
||||
const options = section.options;
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={classes.itemCard}
|
||||
w="100%"
|
||||
h="100%"
|
||||
styles={{
|
||||
root: {
|
||||
overflow: "visible",
|
||||
"--opacity": boardData.opacity / 100,
|
||||
"--border-color": options.borderColor || undefined,
|
||||
},
|
||||
}}
|
||||
radius={boardData.itemRadius}
|
||||
p={0}
|
||||
>
|
||||
{options.title && (
|
||||
<Badge
|
||||
pos="absolute"
|
||||
top={-15}
|
||||
left={10}
|
||||
size="md"
|
||||
radius={boardData.itemRadius}
|
||||
color="var(--background-color)"
|
||||
c="var(--mantine-color-text)"
|
||||
bd="1px solid var(--border-color)"
|
||||
>
|
||||
{options.title}
|
||||
</Badge>
|
||||
)}
|
||||
<StaticSectionGrid
|
||||
sectionId={section.id}
|
||||
board={board}
|
||||
layoutId={layoutId}
|
||||
columnCount={section.width}
|
||||
estimatedGridWidth={estimatedGridWidth}
|
||||
isDynamic
|
||||
fixedRowCount={section.height}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useSession } from "@homarr/auth/client";
|
||||
|
||||
import type { CategorySection } from "~/app/[locale]/boards/_types";
|
||||
|
||||
export const getCategoryCollapseStorageKey = (sectionId: string) => `homarr-section-collapsed-${sectionId}`;
|
||||
|
||||
const categoryCollapseChangeEventName = "homarr-section-collapse-change";
|
||||
|
||||
interface CategoryExpandedChangeEventDetail {
|
||||
sectionId: string;
|
||||
expanded: boolean;
|
||||
}
|
||||
|
||||
const getInitialExpanded = (section: CategorySection) => {
|
||||
if (typeof window === "undefined") return section.collapsed;
|
||||
|
||||
return (localStorage.getItem(getCategoryCollapseStorageKey(section.id)) ?? String(section.collapsed)) === "true";
|
||||
};
|
||||
|
||||
export const useCategoryCollapse = (section: CategorySection) => {
|
||||
const { status } = useSession();
|
||||
const { mutate } = clientApi.section.changeCollapsed.useMutation();
|
||||
const [opened, setOpened] = useState(() => getInitialExpanded(section));
|
||||
|
||||
const persistExpanded = useCallback(
|
||||
(expanded: boolean) => {
|
||||
if (status === "authenticated") {
|
||||
mutate({ sectionId: section.id, collapsed: expanded });
|
||||
} else if (status === "unauthenticated") {
|
||||
localStorage.setItem(getCategoryCollapseStorageKey(section.id), String(expanded));
|
||||
}
|
||||
},
|
||||
[mutate, section.id, status],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleCollapseChange = (event: Event) => {
|
||||
const { sectionId, expanded } = (event as CustomEvent<CategoryExpandedChangeEventDetail>).detail;
|
||||
if (sectionId === section.id) {
|
||||
setOpened(expanded);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener(categoryCollapseChangeEventName, handleCollapseChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(categoryCollapseChangeEventName, handleCollapseChange);
|
||||
};
|
||||
}, [section.id]);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
setOpened((current) => {
|
||||
const expanded = !current;
|
||||
persistExpanded(expanded);
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent<CategoryExpandedChangeEventDetail>(categoryCollapseChangeEventName, {
|
||||
detail: {
|
||||
sectionId: section.id,
|
||||
expanded,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return expanded;
|
||||
});
|
||||
}, [persistExpanded, section.id]);
|
||||
|
||||
return [opened, { toggle }] as const;
|
||||
};
|
||||
@@ -112,3 +112,17 @@
|
||||
.grid-stack-empty-wrapper {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.static-grid-container {
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.static-grid-item-content {
|
||||
position: absolute;
|
||||
inset: 10px;
|
||||
|
||||
> .grid-stack-item-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
import { chromium } from "@playwright/test";
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
import SuperJSON from "superjson";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import * as sqliteSchema from "../packages/db/schema/sqlite";
|
||||
import { hashPasswordAsync } from "../packages/auth/security";
|
||||
import { createHomarrContainer } from "./shared/create-homarr-container";
|
||||
import { createSqliteDbFileAsync } from "./shared/e2e-db";
|
||||
import type { SqliteDatabase } from "./shared/e2e-db";
|
||||
|
||||
const boardName = "responsive-board";
|
||||
const credentials = {
|
||||
username: "responsive-admin",
|
||||
password: "Comp(exP4sswOrd",
|
||||
};
|
||||
const viewports = [
|
||||
{ width: 320, height: 568 },
|
||||
{ width: 375, height: 667 },
|
||||
{ width: 768, height: 1024 },
|
||||
{ width: 1024, height: 768 },
|
||||
{ width: 1366, height: 768 },
|
||||
{ width: 1920, height: 1080 },
|
||||
];
|
||||
|
||||
describe("Board responsive layout", () => {
|
||||
test("renders static board layouts across common viewports and loads edit mode", async () => {
|
||||
const { db, localMountPath } = await createSqliteDbFileAsync();
|
||||
const { categorySectionId } = await seedResponsiveBoardAsync(db);
|
||||
const homarrContainer = await createHomarrContainer({
|
||||
mounts: {
|
||||
"/appdata": localMountPath,
|
||||
},
|
||||
}).start();
|
||||
const browser = await chromium.launch();
|
||||
const baseUrl = `http://${homarrContainer.getHost()}:${homarrContainer.getMappedPort(7575)}`;
|
||||
|
||||
try {
|
||||
for (const viewport of viewports) {
|
||||
const context = await browser.newContext({ viewport });
|
||||
await context.addInitScript(() => {
|
||||
window.__homarrLayoutShiftScore = 0;
|
||||
new PerformanceObserver((entries) => {
|
||||
for (const entry of entries.getEntries()) {
|
||||
const layoutShift = entry as PerformanceEntry & { value: number; hadRecentInput: boolean };
|
||||
if (!layoutShift.hadRecentInput) {
|
||||
window.__homarrLayoutShiftScore += layoutShift.value;
|
||||
}
|
||||
}
|
||||
}).observe({ type: "layout-shift", buffered: true });
|
||||
});
|
||||
await context.addInitScript(
|
||||
({ sectionId }) => {
|
||||
localStorage.setItem(`homarr-section-collapsed-${sectionId}`, "true");
|
||||
},
|
||||
{ sectionId: categorySectionId },
|
||||
);
|
||||
const page = await context.newPage();
|
||||
|
||||
await page.goto(`${baseUrl}/boards/${boardName}`);
|
||||
await page.waitForSelector(".static-grid-item-content", { state: "visible" });
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const result = await page.evaluate(() => {
|
||||
const visibleLayout = Array.from(document.querySelectorAll<HTMLElement>(".static-board-layout")).find(
|
||||
(element) => getComputedStyle(element).display !== "none",
|
||||
);
|
||||
const grids = Array.from(visibleLayout?.querySelectorAll<HTMLElement>(".static-grid") ?? []);
|
||||
const hasOverlappingItems = grids.some((grid) => {
|
||||
const rects = Array.from(grid.children)
|
||||
.map((element) => element.getBoundingClientRect())
|
||||
.filter((rect) => rect.width > 0 && rect.height > 0);
|
||||
|
||||
return rects.some((rect, index) =>
|
||||
rects.slice(index + 1).some((otherRect) => {
|
||||
const horizontalOverlap = Math.min(rect.right, otherRect.right) - Math.max(rect.left, otherRect.left);
|
||||
const verticalOverlap = Math.min(rect.bottom, otherRect.bottom) - Math.max(rect.top, otherRect.top);
|
||||
return horizontalOverlap > 1 && verticalOverlap > 1;
|
||||
}),
|
||||
);
|
||||
});
|
||||
const visibleItems = Array.from(
|
||||
visibleLayout?.querySelectorAll<HTMLElement>(".static-grid-item-content") ?? [],
|
||||
).filter((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return rect.width > 0 && rect.height > 0;
|
||||
});
|
||||
|
||||
return {
|
||||
hasVisibleLayout: Boolean(visibleLayout),
|
||||
visibleItemCount: visibleItems.length,
|
||||
hasHorizontalOverflow: document.documentElement.scrollWidth > window.innerWidth + 1,
|
||||
hasOverlappingItems,
|
||||
layoutShiftScore: window.__homarrLayoutShiftScore,
|
||||
};
|
||||
});
|
||||
|
||||
expect(result.hasVisibleLayout).toBe(true);
|
||||
expect(result.visibleItemCount).toBe(4);
|
||||
expect(result.hasHorizontalOverflow).toBe(false);
|
||||
expect(result.hasOverlappingItems).toBe(false);
|
||||
expect(result.layoutShiftScore).toBeLessThanOrEqual(0.01);
|
||||
|
||||
await context.close();
|
||||
}
|
||||
|
||||
const context = await browser.newContext({ viewport: { width: 1366, height: 768 } });
|
||||
const page = await context.newPage();
|
||||
await page.goto(`${baseUrl}/auth/login`);
|
||||
await page.getByLabel("Username").fill(credentials.username);
|
||||
await page.getByLabel("Password").fill(credentials.password);
|
||||
await page.locator("css=button[type='submit']").click();
|
||||
await page.waitForURL(baseUrl);
|
||||
await page.goto(`${baseUrl}/boards/${boardName}`);
|
||||
await page.waitForSelector(".static-grid-item-content", { state: "visible" });
|
||||
|
||||
await page.keyboard.press("ControlOrMeta+E");
|
||||
|
||||
await page.waitForSelector(".grid-stack", { state: "visible" });
|
||||
await expect.poll(() => page.locator(".grid-stack-item").count()).toBeGreaterThan(0);
|
||||
await context.close();
|
||||
} finally {
|
||||
await browser.close();
|
||||
await homarrContainer.stop();
|
||||
}
|
||||
}, 120_000);
|
||||
});
|
||||
|
||||
const seedResponsiveBoardAsync = async (db: SqliteDatabase) => {
|
||||
const userId = createId();
|
||||
const boardId = createId();
|
||||
const mobileLayoutId = createId();
|
||||
const tabletLayoutId = createId();
|
||||
const desktopLayoutId = createId();
|
||||
const rootSectionId = createId();
|
||||
const categorySectionId = createId();
|
||||
const dynamicSectionId = createId();
|
||||
|
||||
await db.update(sqliteSchema.onboarding).set({ step: "finish" });
|
||||
await db.insert(sqliteSchema.users).values({
|
||||
id: userId,
|
||||
name: credentials.username,
|
||||
password: await hashPasswordAsync(credentials.password),
|
||||
});
|
||||
await db.insert(sqliteSchema.boards).values({
|
||||
id: boardId,
|
||||
name: boardName,
|
||||
isPublic: true,
|
||||
creatorId: userId,
|
||||
});
|
||||
await db.insert(sqliteSchema.layouts).values([
|
||||
{ id: mobileLayoutId, name: "Mobile", boardId, columnCount: 4, breakpoint: 0 },
|
||||
{ id: tabletLayoutId, name: "Tablet", boardId, columnCount: 8, breakpoint: 768 },
|
||||
{ id: desktopLayoutId, name: "Desktop", boardId, columnCount: 12, breakpoint: 1024 },
|
||||
]);
|
||||
await db.insert(sqliteSchema.sections).values([
|
||||
{ id: rootSectionId, boardId, kind: "empty", xOffset: 0, yOffset: 0 },
|
||||
{ id: categorySectionId, boardId, kind: "category", xOffset: 0, yOffset: 1, name: "Systems" },
|
||||
{
|
||||
id: dynamicSectionId,
|
||||
boardId,
|
||||
kind: "dynamic",
|
||||
options: SuperJSON.stringify({ title: "Nested", borderColor: "", customCssClasses: [] }),
|
||||
},
|
||||
]);
|
||||
await db.insert(sqliteSchema.sectionLayouts).values([
|
||||
{
|
||||
sectionId: dynamicSectionId,
|
||||
layoutId: mobileLayoutId,
|
||||
parentSectionId: categorySectionId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 4,
|
||||
height: 2,
|
||||
},
|
||||
{
|
||||
sectionId: dynamicSectionId,
|
||||
layoutId: tabletLayoutId,
|
||||
parentSectionId: categorySectionId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 4,
|
||||
height: 2,
|
||||
},
|
||||
{
|
||||
sectionId: dynamicSectionId,
|
||||
layoutId: desktopLayoutId,
|
||||
parentSectionId: categorySectionId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 6,
|
||||
height: 2,
|
||||
},
|
||||
]);
|
||||
|
||||
const rootItemId = await insertClockItemAsync(db, boardId);
|
||||
const categoryItemId = await insertClockItemAsync(db, boardId);
|
||||
const dynamicItemId = await insertClockItemAsync(db, boardId);
|
||||
await db.insert(sqliteSchema.itemLayouts).values([
|
||||
{
|
||||
itemId: rootItemId,
|
||||
sectionId: rootSectionId,
|
||||
layoutId: mobileLayoutId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 2,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
itemId: rootItemId,
|
||||
sectionId: rootSectionId,
|
||||
layoutId: tabletLayoutId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 3,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
itemId: rootItemId,
|
||||
sectionId: rootSectionId,
|
||||
layoutId: desktopLayoutId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 4,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
itemId: categoryItemId,
|
||||
sectionId: categorySectionId,
|
||||
layoutId: mobileLayoutId,
|
||||
xOffset: 0,
|
||||
yOffset: 2,
|
||||
width: 4,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
itemId: categoryItemId,
|
||||
sectionId: categorySectionId,
|
||||
layoutId: tabletLayoutId,
|
||||
xOffset: 4,
|
||||
yOffset: 0,
|
||||
width: 4,
|
||||
height: 2,
|
||||
},
|
||||
{
|
||||
itemId: categoryItemId,
|
||||
sectionId: categorySectionId,
|
||||
layoutId: desktopLayoutId,
|
||||
xOffset: 6,
|
||||
yOffset: 0,
|
||||
width: 6,
|
||||
height: 2,
|
||||
},
|
||||
{
|
||||
itemId: dynamicItemId,
|
||||
sectionId: dynamicSectionId,
|
||||
layoutId: mobileLayoutId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 2,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
itemId: dynamicItemId,
|
||||
sectionId: dynamicSectionId,
|
||||
layoutId: tabletLayoutId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 2,
|
||||
height: 1,
|
||||
},
|
||||
{
|
||||
itemId: dynamicItemId,
|
||||
sectionId: dynamicSectionId,
|
||||
layoutId: desktopLayoutId,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
width: 3,
|
||||
height: 1,
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
categorySectionId,
|
||||
};
|
||||
};
|
||||
|
||||
const insertClockItemAsync = async (db: SqliteDatabase, boardId: string) => {
|
||||
const itemId = createId();
|
||||
await db.insert(sqliteSchema.items).values({
|
||||
id: itemId,
|
||||
boardId,
|
||||
kind: "clock",
|
||||
options: SuperJSON.stringify({ is24HourFormat: true }),
|
||||
advancedOptions: SuperJSON.stringify({ title: null, customCssClasses: [], borderColor: "" }),
|
||||
});
|
||||
return itemId;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__homarrLayoutShiftScore: number;
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ const optionMapping: OptionMapping = {
|
||||
hideIcon: (oldOptions) => oldOptions.items.some((item) => item.hideIcon),
|
||||
hideHostname: (oldOptions) => oldOptions.items.some((item) => item.hideHostname),
|
||||
openNewTab: (oldOptions) => oldOptions.items.some((item) => item.openNewTab),
|
||||
withBorder: () => undefined,
|
||||
},
|
||||
calendar: {
|
||||
releaseType: (oldOptions) => [oldOptions.radarrReleaseType],
|
||||
|
||||
@@ -1406,6 +1406,9 @@
|
||||
"openNewTab": {
|
||||
"label": "Open in new tab"
|
||||
},
|
||||
"withBorder": {
|
||||
"label": "Show border"
|
||||
},
|
||||
"items": {
|
||||
"label": "Bookmarks",
|
||||
"add": "Add bookmark"
|
||||
|
||||
@@ -16,7 +16,7 @@ export default function BookmarksWidget({ options, itemId }: WidgetComponentProp
|
||||
const board = useRequiredBoard();
|
||||
const [data] = clientApi.app.byIds.useSuspenseQuery(options.items, {
|
||||
select(data) {
|
||||
return data.sort((appA, appB) => options.items.indexOf(appA.id) - options.items.indexOf(appB.id));
|
||||
return data.toSorted((appA, appB) => options.items.indexOf(appA.id) - options.items.indexOf(appB.id));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -56,6 +56,7 @@ export default function BookmarksWidget({ options, itemId }: WidgetComponentProp
|
||||
hideIcon={options.hideIcon}
|
||||
hideHostname={options.hideHostname}
|
||||
openNewTab={options.openNewTab}
|
||||
withBorder={options.withBorder}
|
||||
hasIconColor={board.iconColor !== null}
|
||||
/>
|
||||
)}
|
||||
@@ -67,6 +68,7 @@ export default function BookmarksWidget({ options, itemId }: WidgetComponentProp
|
||||
hideIcon={options.hideIcon}
|
||||
hideHostname={options.hideHostname}
|
||||
openNewTab={options.openNewTab}
|
||||
withBorder={options.withBorder}
|
||||
hasIconColor={board.iconColor !== null}
|
||||
/>
|
||||
)}
|
||||
@@ -81,6 +83,7 @@ interface FlexLayoutProps {
|
||||
hideIcon: boolean;
|
||||
hideHostname: boolean;
|
||||
openNewTab: boolean;
|
||||
withBorder: boolean;
|
||||
hasIconColor: boolean;
|
||||
}
|
||||
|
||||
@@ -91,6 +94,7 @@ const FlexLayout = ({
|
||||
hideIcon,
|
||||
hideHostname,
|
||||
openNewTab,
|
||||
withBorder,
|
||||
hasIconColor,
|
||||
}: FlexLayoutProps) => {
|
||||
const board = useRequiredBoard();
|
||||
@@ -106,7 +110,15 @@ const FlexLayout = ({
|
||||
key={app.id}
|
||||
w="100%"
|
||||
>
|
||||
<Card radius={board.itemRadius} className={classes.card} w="100%" display="flex" p={4} h="100%">
|
||||
<Card
|
||||
radius={board.itemRadius}
|
||||
className={classes.card}
|
||||
w="100%"
|
||||
display="flex"
|
||||
p={4}
|
||||
h="100%"
|
||||
withBorder={withBorder}
|
||||
>
|
||||
{direction === "row" ? (
|
||||
<VerticalItem
|
||||
app={app}
|
||||
@@ -138,6 +150,7 @@ interface GridLayoutProps {
|
||||
hideIcon: boolean;
|
||||
hideHostname: boolean;
|
||||
openNewTab: boolean;
|
||||
withBorder: boolean;
|
||||
itemDirection: "horizontal" | "vertical";
|
||||
hasIconColor: boolean;
|
||||
}
|
||||
@@ -148,6 +161,7 @@ const GridLayout = ({
|
||||
hideIcon,
|
||||
hideHostname,
|
||||
openNewTab,
|
||||
withBorder,
|
||||
itemDirection,
|
||||
hasIconColor,
|
||||
}: GridLayoutProps) => {
|
||||
@@ -168,6 +182,7 @@ const GridLayout = ({
|
||||
h="100%"
|
||||
className={combineClasses(classes.card, classes["card-grid"])}
|
||||
radius={board.itemRadius}
|
||||
withBorder={withBorder}
|
||||
p="xs"
|
||||
>
|
||||
{itemDirection === "horizontal" ? (
|
||||
|
||||
@@ -24,6 +24,7 @@ export const { definition, componentLoader } = createWidgetDefinition("bookmarks
|
||||
hideIcon: factory.switch({ defaultValue: false }),
|
||||
hideHostname: factory.switch({ defaultValue: false }),
|
||||
openNewTab: factory.switch({ defaultValue: true }),
|
||||
withBorder: factory.switch({ defaultValue: false }),
|
||||
items: factory.sortableItemList<RouterOutputs["app"]["all"][number], string>({
|
||||
ItemComponent: ({ item, handle: Handle, removeItem, rootAttributes }) => {
|
||||
return (
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
.statItem {
|
||||
padding: 12px;
|
||||
border-radius: var(--mantine-radius-md);
|
||||
background-color: var(--mantine-color-gray-0);
|
||||
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--mantine-color-gray-1);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.statItem {
|
||||
background-color: var(--mantine-color-dark-6);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--mantine-color-dark-5);
|
||||
}
|
||||
background-color: light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-5));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ComponentType } from "react";
|
||||
import type { Loader } from "next/dynamic";
|
||||
import dynamic from "next/dynamic";
|
||||
import { Center, Loader as UiLoader } from "@mantine/core";
|
||||
import { Skeleton } from "@mantine/core";
|
||||
|
||||
import { objectEntries } from "@homarr/common";
|
||||
import type { IntegrationKind, WidgetKind } from "@homarr/definitions";
|
||||
@@ -107,11 +107,7 @@ export const loadWidgetDynamic = <TKind extends WidgetKind>(kind: TKind) => {
|
||||
const newlyLoadedComponent = dynamic<WidgetComponentProps<TKind>>(
|
||||
widgetImports[kind].componentLoader as Loader<WidgetComponentProps<TKind>>,
|
||||
{
|
||||
loading: () => (
|
||||
<Center w="100%" h="100%">
|
||||
<UiLoader />
|
||||
</Center>
|
||||
),
|
||||
loading: () => <Skeleton w="100%" h="100%" radius="md" animate />,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import prefetchForApps from "./app/prefetch";
|
||||
import prefetchForBookmarks from "./bookmarks/prefetch";
|
||||
import type { Prefetch, WidgetOptionsRecordOf } from "./definition";
|
||||
import type { inferOptionsFromCreator } from "./options";
|
||||
import prefetchRssFeedsAsync from "./rssFeed/prefetch";
|
||||
import prefetchWeatherAsync from "./weather/prefetch";
|
||||
|
||||
const cachedGetServerSettingsAsync = cache(getServerSettingsAsync);
|
||||
|
||||
@@ -19,6 +21,8 @@ const prefetchCallbacks: Partial<{
|
||||
}> = {
|
||||
bookmarks: prefetchForBookmarks,
|
||||
app: prefetchForApps,
|
||||
weather: prefetchWeatherAsync,
|
||||
rssFeed: prefetchRssFeedsAsync,
|
||||
};
|
||||
|
||||
export const prefetchForKindAsync = async <TKind extends WidgetKind>(
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { api, trpc } from "@homarr/api/server";
|
||||
import { createLogger } from "@homarr/core/infrastructure/logs";
|
||||
|
||||
import type { Prefetch } from "../definition";
|
||||
|
||||
const logger = createLogger({ module: "rssFeedWidgetPrefetch" });
|
||||
|
||||
const prefetchRssFeedsAsync: Prefetch<"rssFeed"> = async (queryClient, items) => {
|
||||
for (const item of items) {
|
||||
const input = {
|
||||
urls: item.options.feedUrls,
|
||||
maximumAmountPosts: item.options.maximumAmountPosts,
|
||||
};
|
||||
|
||||
const data = await api.widget.rssFeed.getFeeds(input);
|
||||
queryClient.setQueryData(trpc.widget.rssFeed.getFeeds.queryKey(input), data);
|
||||
}
|
||||
|
||||
logger.info("Successfully prefetched RSS feeds", { count: items.length });
|
||||
};
|
||||
|
||||
export default prefetchRssFeedsAsync;
|
||||
@@ -0,0 +1,29 @@
|
||||
import { api, trpc } from "@homarr/api/server";
|
||||
import { createLogger } from "@homarr/core/infrastructure/logs";
|
||||
|
||||
import type { Prefetch } from "../definition";
|
||||
|
||||
const logger = createLogger({ module: "weatherWidgetPrefetch" });
|
||||
|
||||
const prefetchWeatherAsync: Prefetch<"weather"> = async (queryClient, items) => {
|
||||
const locations = items.map((item) => ({
|
||||
latitude: item.options.location.latitude,
|
||||
longitude: item.options.location.longitude,
|
||||
}));
|
||||
|
||||
const uniqueLocations = locations.filter(
|
||||
(loc, idx, arr) =>
|
||||
arr.findIndex((other) => other.latitude === loc.latitude && other.longitude === loc.longitude) === idx,
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
uniqueLocations.map(async (input) => {
|
||||
const data = await api.widget.weather.atLocation(input);
|
||||
queryClient.setQueryData(trpc.widget.weather.atLocation.queryKey(input), data);
|
||||
}),
|
||||
);
|
||||
|
||||
logger.info("Successfully prefetched weather data", { count: uniqueLocations.length });
|
||||
};
|
||||
|
||||
export default prefetchWeatherAsync;
|
||||
Generated
+317
-325
@@ -142,53 +142,53 @@ catalogs:
|
||||
specifier: ^12.0.1
|
||||
version: 12.0.1
|
||||
'@tiptap/extension-color':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-highlight':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-image':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-link':
|
||||
specifier: ^3.23.6
|
||||
version: 3.23.6
|
||||
specifier: ^3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-placeholder':
|
||||
specifier: ^3.23.6
|
||||
version: 3.23.6
|
||||
specifier: ^3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-table':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-table-cell':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-table-header':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-table-row':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-task-item':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-task-list':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-text-align':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-text-style':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/extension-underline':
|
||||
specifier: 3.23.6
|
||||
version: 3.23.6
|
||||
specifier: 3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/react':
|
||||
specifier: ^3.23.6
|
||||
version: 3.23.6
|
||||
specifier: ^3.24.0
|
||||
version: 3.24.0
|
||||
'@tiptap/starter-kit':
|
||||
specifier: ^3.23.6
|
||||
version: 3.23.6
|
||||
specifier: ^3.24.0
|
||||
version: 3.24.0
|
||||
'@trpc/client':
|
||||
specifier: ^11.17.0
|
||||
version: 11.17.0
|
||||
@@ -756,7 +756,7 @@ importers:
|
||||
version: 9.2.2(@mantine/core@9.2.2(@mantine/hooks@9.2.2(react@19.2.6))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@9.2.2(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
'@mantine/tiptap':
|
||||
specifier: 'catalog:'
|
||||
version: 9.2.2(@mantine/core@9.2.2(@mantine/hooks@9.2.2(react@19.2.6))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@9.2.2(react@19.2.6))(@tiptap/extension-link@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))(@tiptap/react@3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
version: 9.2.2(@mantine/core@9.2.2(@mantine/hooks@9.2.2(react@19.2.6))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@9.2.2(react@19.2.6))(@tiptap/extension-link@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))(@tiptap/react@3.24.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
'@tabler/icons-react':
|
||||
specifier: 'catalog:'
|
||||
version: 3.44.0(react@19.2.6)
|
||||
@@ -2396,52 +2396,52 @@ importers:
|
||||
version: 3.44.0(react@19.2.6)
|
||||
'@tiptap/extension-color':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/extension-text-style@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)))
|
||||
version: 3.24.0(@tiptap/extension-text-style@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0)))
|
||||
'@tiptap/extension-highlight':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-image':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-link':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
version: 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/extension-placeholder':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/extensions@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-table':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
version: 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/extension-table-cell':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/extension-table@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/extension-table@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-table-header':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/extension-table@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/extension-table@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-table-row':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/extension-table@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/extension-table@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-task-item':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-task-list':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-text-align':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-text-style':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-underline':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
version: 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/react':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
version: 3.24.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
'@tiptap/starter-kit':
|
||||
specifier: 'catalog:'
|
||||
version: 3.23.6
|
||||
version: 3.24.0
|
||||
clsx:
|
||||
specifier: 'catalog:'
|
||||
version: 2.1.1
|
||||
@@ -3268,15 +3268,9 @@ packages:
|
||||
'@fastify/proxy-addr@5.1.0':
|
||||
resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==}
|
||||
|
||||
'@floating-ui/core@1.7.3':
|
||||
resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==}
|
||||
|
||||
'@floating-ui/core@1.7.5':
|
||||
resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==}
|
||||
|
||||
'@floating-ui/dom@1.7.4':
|
||||
resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==}
|
||||
|
||||
'@floating-ui/dom@1.7.6':
|
||||
resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==}
|
||||
|
||||
@@ -4932,215 +4926,215 @@ packages:
|
||||
'@testcontainers/redis@12.0.1':
|
||||
resolution: {integrity: sha512-x5iDR6Y2Mc+2rTJYSQlRTtBMCPt77pKxDogpqRwXgJVmWoDrWFpiFcA/dw6IEoNuyxYUg03tbS8/VzCJI5JX6A==}
|
||||
|
||||
'@tiptap/core@3.23.6':
|
||||
resolution: {integrity: sha512-MRB3pHz4Oxqmcawh0cQ5iOGdY5xtNYp/1CoK7hdTLzw5K0C6/gTC2VvanB1R4INaB6EpBkxG/GiWkVirDRnuXw==}
|
||||
'@tiptap/core@3.24.0':
|
||||
resolution: {integrity: sha512-GTAsXAI32p4hEZgPzvUv2RPrObxamy9AFhmhG10fXSvN/cDUs8naEYVIqDV3Sh99jMwQEbTFKW1E1mcspsY6ow==}
|
||||
peerDependencies:
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-blockquote@3.23.6':
|
||||
resolution: {integrity: sha512-2RmnqNqTltZ2k1F7IfjoDNs935Uq4rRDR7d98mqkg3OlDktcQIyBpv0t9dTay6H5bkQeZUuS8ogK2S1E8Edjug==}
|
||||
'@tiptap/extension-blockquote@3.24.0':
|
||||
resolution: {integrity: sha512-DgwEEJ1GbDQcT054ynxoaZGmB9apGeUklPrinq9o6xdLHpdg+bO9HCQzggdB8n21VLLglb8jfAEWsVNwh3eASQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-bold@3.23.6':
|
||||
resolution: {integrity: sha512-1LMhjnytdbbhWHSoOwnLxZAOQZWPkKyXVCNmaIk0Mhi4tLPUXptG4qKS5sVYTCveE5H6IBPFrbgBFi5dMI6krA==}
|
||||
'@tiptap/extension-bold@3.24.0':
|
||||
resolution: {integrity: sha512-CujogYaynasklFKHADUseuvj8X2FnWktTCCo3Hl+nlyRvBTmm5TK2aqiamg3v2P4dBh3O6a70mo8BfRJPuiR1g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-bubble-menu@3.23.6':
|
||||
resolution: {integrity: sha512-Mwkyp9LkDHFbqmWRIkp63FinRxFu3ajC4qSb9t4mnHsb4kAdbNLLsGtbFg+le0SWk4CxGwAOwM7SzeJ+6UGqCA==}
|
||||
'@tiptap/extension-bubble-menu@3.24.0':
|
||||
resolution: {integrity: sha512-jRXD+JPu9ayvq78g8hsCxx4q/qUFtrdfIYirRSf5YUseuuUbtfrq83AsGabcygpUTefjJkMQoXNITkh6294Ggw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-bullet-list@3.23.6':
|
||||
resolution: {integrity: sha512-RMRgfXZykr/13X8UBOwvpgysVOo9KchwqMoEbvqQSj4YFfU56iIn59C8sbxiQ1sKfeltUf0wH4fPc0I4iwKqAA==}
|
||||
'@tiptap/extension-bullet-list@3.24.0':
|
||||
resolution: {integrity: sha512-IOpAm5c4XVVVvkOef+V9XYMVpea+3MgBpCQgn83UQRlwO9eIMwmcyxOznu7gQPQVShTEpkt4T6uK+ZN9o8meIA==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-list': 3.23.6
|
||||
'@tiptap/extension-list': 3.24.0
|
||||
|
||||
'@tiptap/extension-code-block@3.23.6':
|
||||
resolution: {integrity: sha512-4kccgcn5yHThxrzsIhJny3EwfEZYIk+BjUCL4uIuzOyWvExtGhZ6JMHVCZeMhI8D1/bX1LNkkAKN5DXPzH4lXQ==}
|
||||
'@tiptap/extension-code-block@3.24.0':
|
||||
resolution: {integrity: sha512-NZglw4oHoH6oJ5+HvxxQCYk+wODJmsxzUpRQdsOmje08sekQH+Zt9i4UKimBhg4urpd5r+dKXTslab9a5eQ86w==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-code@3.23.6':
|
||||
resolution: {integrity: sha512-KG8KXFYyLrtYvT7AZ1WGV61ofx8pDe5g9pH658MERxqQGii+Pyfc6xkz04l7XeBts/7+571UQp/0O7i/z560TA==}
|
||||
'@tiptap/extension-code@3.24.0':
|
||||
resolution: {integrity: sha512-MAQtrPRQ+HRmcGotWbksdIGeH1gqayFAdvi4lNGeFT7taHXP1o1XD7CQp7iYIKmg8IU4/MQ+RdetSfuC1A9edQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-color@3.23.6':
|
||||
resolution: {integrity: sha512-2WxYc+X+OGFXbq/Ak0VXODEzfK1l5wz33oTWSuhdSw44HAQM7+SSyiDnMCXDQdqi063ANqMmQmlw5WngjQ6wCA==}
|
||||
'@tiptap/extension-color@3.24.0':
|
||||
resolution: {integrity: sha512-gVv9zfQ9diq/sk+SVJzqadShsOtDK1XPojBZR1zXg1QxedzdwLKuRDxvnlfIc3kFIyaDP4mNrek+anednTbWBA==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-text-style': 3.23.6
|
||||
'@tiptap/extension-text-style': 3.24.0
|
||||
|
||||
'@tiptap/extension-document@3.23.6':
|
||||
resolution: {integrity: sha512-XDAIgG9KcKumFM9KJWUEUhXPbFIhhl47bfy5GknareWTRKke85rcoj/oxKKO9ihLZr8JfpbXjqnS4SCm5yhYPw==}
|
||||
'@tiptap/extension-document@3.24.0':
|
||||
resolution: {integrity: sha512-yxgM3+yXy2XZzEwH43y2Kp8D1BkblxEWLXqo0YCoAKtxyKCcEaT8kdlf70kS7D0+VSzYU4D0iN7VdQIYHcL2mA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-dropcursor@3.23.6':
|
||||
resolution: {integrity: sha512-+XWEoRKf3lXxi7Le1aOM2xU1XHwxICGpXjT3m4QaYqUgIpsq8gQEuso6kVg8DnTD7biKQs6+oIQ0o2b/gTW9WA==}
|
||||
'@tiptap/extension-dropcursor@3.24.0':
|
||||
resolution: {integrity: sha512-Dbv1c5LnvG3PT+yEbCNroyOeeUkHq9wcir2pbC7wri7g7d2sCi0+HvKH0MAxLwY3j5NJJSiSyG2ypMaXOAs4sg==}
|
||||
peerDependencies:
|
||||
'@tiptap/extensions': 3.23.6
|
||||
'@tiptap/extensions': 3.24.0
|
||||
|
||||
'@tiptap/extension-floating-menu@3.23.6':
|
||||
resolution: {integrity: sha512-2kjuDcEq69lEcECl75xqY5MyzUSh2zcC5aLrpwP1WwhJz5bxsIFHiaps5AP6h9R4A+ZBj5b2haay2Y1wDUU3VA==}
|
||||
'@tiptap/extension-floating-menu@3.24.0':
|
||||
resolution: {integrity: sha512-7QEbf3mUzFAkejjQGX9f0L507oMtnOBRwHt2skUTR+9yXgudsN8zaDBSSRHLeMWGk9b7L293ZMA6zCRrZaHrfA==}
|
||||
peerDependencies:
|
||||
'@floating-ui/dom': ^1.0.0
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-gapcursor@3.23.6':
|
||||
resolution: {integrity: sha512-wbKmxXsszxWacEkrHucRpSQbiKjz4fmOebD6OVyL9AcrmlbxNk8vcM3iyh/8cVeRy09XY+morM165t/u7/z4IQ==}
|
||||
'@tiptap/extension-gapcursor@3.24.0':
|
||||
resolution: {integrity: sha512-CzCP5/jni5RFwW9jCfBO6auh83GbaioMTpSk6tyR3sd+CbwlBcUdsJFGJkbaRdiSS9dgIyi+6hRbhjpYdHcp+w==}
|
||||
peerDependencies:
|
||||
'@tiptap/extensions': 3.23.6
|
||||
'@tiptap/extensions': 3.24.0
|
||||
|
||||
'@tiptap/extension-hard-break@3.23.6':
|
||||
resolution: {integrity: sha512-KeUm+tkUfIVSX9QM9XOIhaay0Fn36sLKUo5NVYjN3uJaxFvaZXZmTlxdO85OTdgF2P5sqh9LomrIgliaFRGk4w==}
|
||||
'@tiptap/extension-hard-break@3.24.0':
|
||||
resolution: {integrity: sha512-T/ZEBiHQPMyTqDvXG0tiqBToNeuSemIPmNtdoGSgBN/degVl7VJZqQIrLIvOUHfjf3QkRs7TE/mcqTJsIboO/g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-heading@3.23.6':
|
||||
resolution: {integrity: sha512-A/0jPhxnUh9THSZymlu0OGPZe1wdFdwHAXnRCmqvYUCwJjrG7LCC/ahzmcj1tcNzI9hgHyuYPSfev8RXYrNu/w==}
|
||||
'@tiptap/extension-heading@3.24.0':
|
||||
resolution: {integrity: sha512-GCSgapIzQPqEGNcVGE0/Pcjg5wITMLYJlrS3GGVw7BPmECJwgexcoOsEwkxtzJnXT/HpFXbvOFW43sM0KeHSjg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-highlight@3.23.6':
|
||||
resolution: {integrity: sha512-GWv6R4iZzVrNeB33qtJDBt/BfVjuc5S/sUF/VDFAtK8h86bg4cEm1tGLEsui4T3+vij/t+P+eoGhkzF6NGogdg==}
|
||||
'@tiptap/extension-highlight@3.24.0':
|
||||
resolution: {integrity: sha512-+Vx6YKSP+lzCBiTbgQOpR2rIOzL8Ns6UnOBtW4O6tYc7TMTexycaG66RWxXMpAD6QkamwLwX3H5TTYviWtU9RQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-horizontal-rule@3.23.6':
|
||||
resolution: {integrity: sha512-hEUlz4H+I64r+TH6LCuNCRgO7JTHncXGmx9+WbU69EOfY8O0ZurcgeJc8HeiAKL+r9YuC1e5YHfFxgCaaC0jlg==}
|
||||
'@tiptap/extension-horizontal-rule@3.24.0':
|
||||
resolution: {integrity: sha512-DFzWJTrb23x+qssLLs85vEyho8ItUGp3RY9XUsVTIAGZn5IsoUw8wMsvIBlH1ux4Ch7gLchtcD6kpTdMdrL9kw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-image@3.23.6':
|
||||
resolution: {integrity: sha512-vvNGxArvD2dW+XvV0KdYovRVUzCy8QVNulc2r5pV7umnG1E6cCmMkiHiif8J2ePJu2KtysAvJQe0iF+UqueGMw==}
|
||||
'@tiptap/extension-image@3.24.0':
|
||||
resolution: {integrity: sha512-mH+bvsX2cPKuZzV7YMQi4FV2YbDP+Kmq36bY+Bwi/x4mYUc8u0cjQxcu8RzLO7GtsgUJPxGMwfkQxmDqXFLZvw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-italic@3.23.6':
|
||||
resolution: {integrity: sha512-wol5KdwCPAvpiYhH9PLlvO8ZnJHwZtIboVevrfOGgBcKlXRA3dedR4OAMXHnUtkkzu9KtliLg1+TYzEx4JZG9Q==}
|
||||
'@tiptap/extension-italic@3.24.0':
|
||||
resolution: {integrity: sha512-mf3cbNlbMPUNj3IyUkIke+o3ZpOUrtVeY5Yqs5IM/VhkUUh/PdIzqw74VuqEAJ0Z4oZ6nNDHeYLrl3Be1j99lQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-link@3.23.6':
|
||||
resolution: {integrity: sha512-KNZz7z7P2/qbQsx5bPAbSPjrKDg1VHsedGlLHJCr8U2VRD5VgmDLkMpkouP1CsDg15qgyUKv/nDib5KgPpLNWA==}
|
||||
'@tiptap/extension-link@3.24.0':
|
||||
resolution: {integrity: sha512-MwMoNGG2mL5XGFV1tEGunBRglwsIbW+ZOB2QnKiv+Mcbi2JCWMrorndJZBqpVPR5nM+Bef2KnpchEJmYlQLvKQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-list-item@3.23.6':
|
||||
resolution: {integrity: sha512-3zzyhdkUWcHVpXuvy6KiIwjh29rbH6gEDEqPQqHLrl1XGnO9pnShC7pSHctlCDjmcx3O4n9cd4QMtVBlUerbiA==}
|
||||
'@tiptap/extension-list-item@3.24.0':
|
||||
resolution: {integrity: sha512-zl/U3viJiV9OzkKM37AHIUN1af1TSLrcbHUUoNLkfJ33Nq+NlpaXpCVK0rKRqiLFJf7zk/a5KWG5CrOy9TxjKA==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-list': 3.23.6
|
||||
'@tiptap/extension-list': 3.24.0
|
||||
|
||||
'@tiptap/extension-list-keymap@3.23.6':
|
||||
resolution: {integrity: sha512-x8bPcLViGzg/RAmQM/XtmfqIwQ/Pv9Q8mkd+OgfUiTqjeJqKwVQmiqbLFNa7zw81+H61M+HDU+qGAaQ3vRIMjw==}
|
||||
'@tiptap/extension-list-keymap@3.24.0':
|
||||
resolution: {integrity: sha512-69fKcrngYGEKWNn4R5oLwl0YuV3FY4kufEValVcjnihUmqJTE1vx+fwctYoTsOGnIuNGpUIQ7f9YDD/0w34qBw==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-list': 3.23.6
|
||||
'@tiptap/extension-list': 3.24.0
|
||||
|
||||
'@tiptap/extension-list@3.23.6':
|
||||
resolution: {integrity: sha512-z6vj9+Qht2sjdQkyyHcUpsC/yCIZqTrQiyHDhs/HGKrfvoANyAZGpqdNeKf1wSyjIso+27tQuIH5NDfk8ygyNw==}
|
||||
'@tiptap/extension-list@3.24.0':
|
||||
resolution: {integrity: sha512-GcxDVMMmDGj7OFTBrV7JpVgr5wxlr2vmjwH7U8QxZX7OJI5vrsMYl/U6KRTvUpG8wP+Zmo5jRlLM+BbL+a/W3g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-ordered-list@3.23.6':
|
||||
resolution: {integrity: sha512-1m/wWB/ZtXcmG2vNdiUkCqsOgqv5vBjCv/mVaHhF9OvV+zQS8YDjoWE7zEuT/GgELdT77Xq8lHrn4nCDudB3/A==}
|
||||
'@tiptap/extension-ordered-list@3.24.0':
|
||||
resolution: {integrity: sha512-buRa6bmBDw0TztH+rAcusIye14DiLDS+yGheo6GiNCTD7kKJnksXagBdxvip3jhW5sx7gyAKvoBmvGSg1BbsGA==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-list': 3.23.6
|
||||
'@tiptap/extension-list': 3.24.0
|
||||
|
||||
'@tiptap/extension-paragraph@3.23.6':
|
||||
resolution: {integrity: sha512-+7m58LUSncodjrIyXks4RZ3tLNYrvgT77wRR4l3HnM5OABY3GDsDTqi7c1t1yI29NVOSk/DUacqy6UwYAj1DGg==}
|
||||
'@tiptap/extension-paragraph@3.24.0':
|
||||
resolution: {integrity: sha512-wD06aB6hO7LgcrlhGiw7I64k2tus9kNoICX5R+UecBSB1DVJdzKvXoXL2kPNv4DqYvljHdkIeK/OpuOTQd6MJA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-placeholder@3.23.6':
|
||||
resolution: {integrity: sha512-8I6b2aevF74aLgymKMxbDxSLxWA2y+2dh0zZDeI8sRZ2m6WHHes+Kyuuwkq1HIPcR+ZLpbec74cmf6lcL/yvqQ==}
|
||||
'@tiptap/extension-placeholder@3.24.0':
|
||||
resolution: {integrity: sha512-3jfYYCIuwMADhvZ92vB6c80YiTmgTSFR23JqyLps8qkQtV59Va5CBYpwJtSs1+VrbCVnNxhZBHhVXusZO3uRkA==}
|
||||
peerDependencies:
|
||||
'@tiptap/extensions': 3.23.6
|
||||
'@tiptap/extensions': 3.24.0
|
||||
|
||||
'@tiptap/extension-strike@3.23.6':
|
||||
resolution: {integrity: sha512-oF7FEZ37f15aCe5kPgzGDYf/m+hr7VdQ/Ko/Hds/UM9pX7AG1fdtmRrl6wqkRqDM/incZaC/AQR2/Dpo2VCNGQ==}
|
||||
'@tiptap/extension-strike@3.24.0':
|
||||
resolution: {integrity: sha512-sfN1iQs6Fdlorrfe8wipDkTPwu/Egx3s2fkY7TAWusTGFHwlovuRUGFKqCL9dI4N3u6uqUMpEuWmQNgv+aQGjQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-table-cell@3.23.6':
|
||||
resolution: {integrity: sha512-hS9TmmvRlT9/ikT+0ukACS+hmJuii4zQaH47cg3oJkz/Fv7O7tL7GZniKtK6l2OUZGPhY+4SV2RkDB6bD7DXfw==}
|
||||
'@tiptap/extension-table-cell@3.24.0':
|
||||
resolution: {integrity: sha512-jg62iVc1L8tOycSuwZ5i82EGKGuvelCIkpFX7wvHMl9EiPX9fv70enmb4ua9DyLgRtYg/MNrGOdUATRpxWsFRA==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-table': 3.23.6
|
||||
'@tiptap/extension-table': 3.24.0
|
||||
|
||||
'@tiptap/extension-table-header@3.23.6':
|
||||
resolution: {integrity: sha512-D6o0a1cJXUU0xWakainBFGPnGHinQkPcdu1YqGd/PoFANY38lnuZt/NW2O/OLfLXu5LXDRfpqF1+dsKww27dUA==}
|
||||
'@tiptap/extension-table-header@3.24.0':
|
||||
resolution: {integrity: sha512-z1TGVoBD5lVX48hpKcrQY5vETB8aCR61Enk5wGl45zNO/sMEMNxYfDKTkMydyOFUWfGqvOPnjDHJqJuT36/19w==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-table': 3.23.6
|
||||
'@tiptap/extension-table': 3.24.0
|
||||
|
||||
'@tiptap/extension-table-row@3.23.6':
|
||||
resolution: {integrity: sha512-OauWVzkyRQg0rKOqM/a3PuKPc1S7YXMb1LRN7Nh8Ytvglvd7GFRTbl1lVqdZRaz4Jzopag4PQnriIZfMPUpxWw==}
|
||||
'@tiptap/extension-table-row@3.24.0':
|
||||
resolution: {integrity: sha512-kASEYMWZF9ZqO6DRGz0LiD11c3LPfzOlFiJQVDrOyLP7xkJpHzIAKH0K+8u4aohOziDLn8nz+8I+3xjRS46oGg==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-table': 3.23.6
|
||||
'@tiptap/extension-table': 3.24.0
|
||||
|
||||
'@tiptap/extension-table@3.23.6':
|
||||
resolution: {integrity: sha512-XbhZXjhsS6AP7ThoZxjAnNs+NiR81YRori25l6E+ORqB7quiPkIXOAi5h4AIpkn/CYIqze6ere11lWsYpDjtaQ==}
|
||||
'@tiptap/extension-table@3.24.0':
|
||||
resolution: {integrity: sha512-lr5elob3uJnB+ltgqPDEeVQmIPRx6JoS0I6z93tOgKsI2mIsaw5ErghteeiCTpExdyax7aWR0fn5pZzLVDQL8A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-task-item@3.23.6':
|
||||
resolution: {integrity: sha512-PIHW+3KZCtEmtC7z34rfkusbC42HYr7uw1h5xNvrazQwJGWhKo1UmI0Yea5vyJNKPrTLPCMEm/mgMrj8nNAZfA==}
|
||||
'@tiptap/extension-task-item@3.24.0':
|
||||
resolution: {integrity: sha512-2VtX6VOp4SJk5E/VHeSC2Acfbge6h69TUBhF7hFebbiCDyB73xCaPKcuClIyzOlWJgpWz2ZPXwVB+Y3meXw+yw==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-list': 3.23.6
|
||||
'@tiptap/extension-list': 3.24.0
|
||||
|
||||
'@tiptap/extension-task-list@3.23.6':
|
||||
resolution: {integrity: sha512-XNuYbVV7F0TBpxHqqEFvrxwGbmTq01qJrZA6qwbQopOsw5wOsCy4XQsCkeZ8BGkakORCEWGSMjPyVOtIKq2jGA==}
|
||||
'@tiptap/extension-task-list@3.24.0':
|
||||
resolution: {integrity: sha512-EIbB/WQ7L92WfaY5AF9upH93nIgBHjGt5zwPYoX+ZTpBncebr1AEDF7rc+LHNuSa1g1ToOKbFB88ep02IIXOjA==}
|
||||
peerDependencies:
|
||||
'@tiptap/extension-list': 3.23.6
|
||||
'@tiptap/extension-list': 3.24.0
|
||||
|
||||
'@tiptap/extension-text-align@3.23.6':
|
||||
resolution: {integrity: sha512-pE+gDmvnrSMWHADDnDSzaO7YUi9kOywQkyrqZ9bEPLddZred7ICoJ4NtD2DqLjDSur+HijaJuByResWb78c6FA==}
|
||||
'@tiptap/extension-text-align@3.24.0':
|
||||
resolution: {integrity: sha512-WKFtYXGthtkUc+Cwy2fItSr+9FKwLZjkJVAY1GhkRdcq35qTuVhkb4Q4wR2Rhkb6QRqtlxF1NDuTf2vxiQmfBQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-text-style@3.23.6':
|
||||
resolution: {integrity: sha512-Auasgj469wkQ5ip+Zi2gaRzvqxx9qKG58+1mkT8yPE3QAGnOIg/AaKyQ7pTV77UyL3FHvLnU+KsWCad+qcobww==}
|
||||
'@tiptap/extension-text-style@3.24.0':
|
||||
resolution: {integrity: sha512-1Hy+5tFEAsnoLhZ/eqmza4USvFHwMA8haeAdCGlwTeshBrt+nUKTrEsRHidF60cGsRwlTcuqxSkjT94dULgp5Q==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-text@3.23.6':
|
||||
resolution: {integrity: sha512-ipoC2TkIAIOTiF5ByiGgvQB1DqDyfP90wrUB3mohBcgvp7lQnwHszCDGv8dNnmcUek8uXV/uoLu2VXeVQlxjPA==}
|
||||
'@tiptap/extension-text@3.24.0':
|
||||
resolution: {integrity: sha512-Im7keLPEihxm3+LyF+drYCoaOY5hlq35lvHAp/el6M8pJ/scts88HrYpdR1Yc4BtpZBIhfHSyWgPaupI4qwdeg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extension-underline@3.23.6':
|
||||
resolution: {integrity: sha512-P55wGIZGYTVH92Fq0cgI4/O9AhLCaJC3hhxg15RSERP5/YegM9eJHDK/GQ1EE/DvYA+xpYGOV6agKwAUqfA/Iw==}
|
||||
'@tiptap/extension-underline@3.24.0':
|
||||
resolution: {integrity: sha512-D4W4X3UMq9dLVIOfPB9+UodQ4eAJ8yDcm8qFWAwq0a15YWH6bnwulCuIdV+U5dEG+yaRxN8haB9GrrID9jmrSA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
|
||||
'@tiptap/extensions@3.23.6':
|
||||
resolution: {integrity: sha512-X09/Db1teB+ifXzDGVVFmOeQRx7wTAayE9/280spxpsHkHZvJ5bHRvWIzUzviMIjbBz+NPDIKYPK7gMfh9iaig==}
|
||||
'@tiptap/extensions@3.24.0':
|
||||
resolution: {integrity: sha512-z6gRYzy2ucJp07OQ0F2W07NxyhMTxPYH1ia2eGiQkWax1i56oExpjMsDHP8THWlg8Tb7NnbfKpkfh881EsmofA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/pm@3.23.6':
|
||||
resolution: {integrity: sha512-in5CaMaWlJcH2A1q6GJKFtrodE8WLS3M9tIi/f89jPmIVHJShpodC0KZDNyJkrVBQomYk0DEh86Utm6ASXzQww==}
|
||||
'@tiptap/pm@3.24.0':
|
||||
resolution: {integrity: sha512-QQP/78ryOZDN99gNBV7dgh69/8AYaOYQYFklq/iR+ZRFaaL3+qqHFvPVJapGkzPdymBgNJ34xjFM8n5pJ4QmMg==}
|
||||
|
||||
'@tiptap/react@3.23.6':
|
||||
resolution: {integrity: sha512-Tw9KZkYqFMk3vaJAEQKqEYIO/iq3cSJe7OUEGBul4k4GaMQeLItLf5EYhUd0GIPXci1WVVPNntKJsHfX25M37w==}
|
||||
'@tiptap/react@3.24.0':
|
||||
resolution: {integrity: sha512-KxnrlQbzOgA02EMsfuGGHtNhfkJQGqVlQttmQctI9DOl/F3gcaRqg+wNTBY1Fof8yDaZ8Z1LL1F0C05W0o3vUw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': 3.23.6
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0
|
||||
'@tiptap/pm': 3.24.0
|
||||
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
'@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
'@tiptap/starter-kit@3.23.6':
|
||||
resolution: {integrity: sha512-gykwtGWrnWCmtql1hid3opac/KV8zQvOAnu3bTqIqcHrn1FusbUwKmNzavSbfGvcktHM3hFjb35W48JyVLyu/A==}
|
||||
'@tiptap/starter-kit@3.24.0':
|
||||
resolution: {integrity: sha512-Ef4PCP96vcY2GonXN9J0M8iC6zvxPTmQlL/QZiCwuYqqnH/hNpYIjNSQdTndiDpxRKofa32Sr2HWktgEnL32Bg==}
|
||||
|
||||
'@tree-sitter-grammars/tree-sitter-yaml@0.7.1':
|
||||
resolution: {integrity: sha512-AynBwkIoQCTgjDR33bDUp9Mqq+YTco0is3n5hRApMqG9of/6A4eQsfC1/uSEeHSUyMQSYawcAWamsexnVpIP4Q==}
|
||||
@@ -8313,6 +8307,9 @@ packages:
|
||||
prosemirror-history@1.4.1:
|
||||
resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==}
|
||||
|
||||
prosemirror-inputrules@1.5.1:
|
||||
resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==}
|
||||
|
||||
prosemirror-keymap@1.2.2:
|
||||
resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==}
|
||||
|
||||
@@ -10463,21 +10460,10 @@ snapshots:
|
||||
'@fastify/forwarded': 3.0.1
|
||||
ipaddr.js: 2.3.0
|
||||
|
||||
'@floating-ui/core@1.7.3':
|
||||
dependencies:
|
||||
'@floating-ui/utils': 0.2.11
|
||||
optional: true
|
||||
|
||||
'@floating-ui/core@1.7.5':
|
||||
dependencies:
|
||||
'@floating-ui/utils': 0.2.11
|
||||
|
||||
'@floating-ui/dom@1.7.4':
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.7.3
|
||||
'@floating-ui/utils': 0.2.11
|
||||
optional: true
|
||||
|
||||
'@floating-ui/dom@1.7.6':
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.7.5
|
||||
@@ -11010,12 +10996,12 @@ snapshots:
|
||||
dependencies:
|
||||
react: 19.2.6
|
||||
|
||||
'@mantine/tiptap@9.2.2(@mantine/core@9.2.2(@mantine/hooks@9.2.2(react@19.2.6))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@9.2.2(react@19.2.6))(@tiptap/extension-link@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))(@tiptap/react@3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
|
||||
'@mantine/tiptap@9.2.2(@mantine/core@9.2.2(@mantine/hooks@9.2.2(react@19.2.6))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@9.2.2(react@19.2.6))(@tiptap/extension-link@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))(@tiptap/react@3.24.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
|
||||
dependencies:
|
||||
'@mantine/core': 9.2.2(@mantine/hooks@9.2.2(react@19.2.6))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
'@mantine/hooks': 9.2.2(react@19.2.6)
|
||||
'@tiptap/extension-link': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/react': 3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
'@tiptap/extension-link': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/react': 3.24.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
|
||||
react: 19.2.6
|
||||
react-dom: 19.2.6(react@19.2.6)
|
||||
|
||||
@@ -12232,174 +12218,175 @@ snapshots:
|
||||
- bare-buffer
|
||||
- supports-color
|
||||
|
||||
'@tiptap/core@3.23.6(@tiptap/pm@3.23.6)':
|
||||
'@tiptap/core@3.24.0(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-blockquote@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-blockquote@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-bold@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-bold@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-bubble-menu@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.7.4
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
optional: true
|
||||
|
||||
'@tiptap/extension-bullet-list@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
|
||||
'@tiptap/extension-code-block@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
|
||||
'@tiptap/extension-code@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
|
||||
'@tiptap/extension-color@3.23.6(@tiptap/extension-text-style@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)))':
|
||||
dependencies:
|
||||
'@tiptap/extension-text-style': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
|
||||
'@tiptap/extension-document@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
|
||||
'@tiptap/extension-dropcursor@3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
dependencies:
|
||||
'@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
|
||||
'@tiptap/extension-floating-menu@3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||
'@tiptap/extension-bubble-menu@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.7.6
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
optional: true
|
||||
|
||||
'@tiptap/extension-gapcursor@3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-bullet-list@3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-list': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-hard-break@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-code-block@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-heading@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-code@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-highlight@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-color@3.24.0(@tiptap/extension-text-style@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0)))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-text-style': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
|
||||
'@tiptap/extension-horizontal-rule@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||
'@tiptap/extension-document@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-image@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-dropcursor@3.24.0(@tiptap/extensions@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extensions': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-italic@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-floating-menu@3.24.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@floating-ui/dom': 1.7.6
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
optional: true
|
||||
|
||||
'@tiptap/extension-link@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||
'@tiptap/extension-gapcursor@3.24.0(@tiptap/extensions@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/extensions': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-hard-break@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-heading@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-highlight@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-horizontal-rule@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-image@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-italic@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-link@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
linkifyjs: 4.3.3
|
||||
|
||||
'@tiptap/extension-list-item@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-list-item@3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-list': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-list-keymap@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-list-keymap@3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-list': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||
'@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-ordered-list@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-ordered-list@3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-list': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-paragraph@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-paragraph@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-placeholder@3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-placeholder@3.24.0(@tiptap/extensions@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extensions': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-strike@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-strike@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-table-cell@3.23.6(@tiptap/extension-table@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-table-cell@3.24.0(@tiptap/extension-table@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extension-table': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-table': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-table-header@3.23.6(@tiptap/extension-table@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-table-header@3.24.0(@tiptap/extension-table@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extension-table': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-table': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-table-row@3.23.6(@tiptap/extension-table@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-table-row@3.24.0(@tiptap/extension-table@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extension-table': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-table': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-table@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||
'@tiptap/extension-table@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/extension-task-item@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-task-item@3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-list': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-task-list@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-task-list@3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-list': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-text-align@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-text-align@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-text-style@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-text-style@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-text@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-text@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extension-underline@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||
'@tiptap/extension-underline@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
|
||||
'@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||
'@tiptap/extensions@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tiptap/pm@3.23.6':
|
||||
'@tiptap/pm@3.24.0':
|
||||
dependencies:
|
||||
prosemirror-changeset: 2.3.0
|
||||
prosemirror-commands: 1.6.2
|
||||
prosemirror-dropcursor: 1.8.1
|
||||
prosemirror-gapcursor: 1.3.2
|
||||
prosemirror-history: 1.4.1
|
||||
prosemirror-inputrules: 1.5.1
|
||||
prosemirror-keymap: 1.2.2
|
||||
prosemirror-model: 1.24.1
|
||||
prosemirror-schema-list: 1.5.1
|
||||
@@ -12408,10 +12395,10 @@ snapshots:
|
||||
prosemirror-transform: 1.10.2
|
||||
prosemirror-view: 1.41.4
|
||||
|
||||
'@tiptap/react@3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
|
||||
'@tiptap/react@3.24.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
'@types/react': 19.2.15
|
||||
'@types/react-dom': 19.2.3(@types/react@19.2.15)
|
||||
'@types/use-sync-external-store': 0.0.6
|
||||
@@ -12420,37 +12407,37 @@ snapshots:
|
||||
react-dom: 19.2.6(react@19.2.6)
|
||||
use-sync-external-store: 1.6.0(react@19.2.6)
|
||||
optionalDependencies:
|
||||
'@tiptap/extension-bubble-menu': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-floating-menu': 3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-bubble-menu': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/extension-floating-menu': 3.24.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
transitivePeerDependencies:
|
||||
- '@floating-ui/dom'
|
||||
|
||||
'@tiptap/starter-kit@3.23.6':
|
||||
'@tiptap/starter-kit@3.24.0':
|
||||
dependencies:
|
||||
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-blockquote': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-bold': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-bullet-list': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-code': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-code-block': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-document': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-dropcursor': 3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-gapcursor': 3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-hard-break': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-heading': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-horizontal-rule': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-italic': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-link': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/extension-list-item': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-list-keymap': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-ordered-list': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-paragraph': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-strike': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-text': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extension-underline': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||
'@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||
'@tiptap/pm': 3.23.6
|
||||
'@tiptap/core': 3.24.0(@tiptap/pm@3.24.0)
|
||||
'@tiptap/extension-blockquote': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-bold': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-bullet-list': 3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-code': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-code-block': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/extension-document': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-dropcursor': 3.24.0(@tiptap/extensions@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-gapcursor': 3.24.0(@tiptap/extensions@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-hard-break': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-heading': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-horizontal-rule': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/extension-italic': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-link': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/extension-list': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/extension-list-item': 3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-list-keymap': 3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-ordered-list': 3.24.0(@tiptap/extension-list@3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-paragraph': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-strike': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-text': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extension-underline': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))
|
||||
'@tiptap/extensions': 3.24.0(@tiptap/core@3.24.0(@tiptap/pm@3.24.0))(@tiptap/pm@3.24.0)
|
||||
'@tiptap/pm': 3.24.0
|
||||
|
||||
'@tree-sitter-grammars/tree-sitter-yaml@0.7.1(tree-sitter@0.22.4)':
|
||||
dependencies:
|
||||
@@ -15748,6 +15735,11 @@ snapshots:
|
||||
prosemirror-view: 1.41.4
|
||||
rope-sequence: 1.3.4
|
||||
|
||||
prosemirror-inputrules@1.5.1:
|
||||
dependencies:
|
||||
prosemirror-state: 1.4.3
|
||||
prosemirror-transform: 1.10.2
|
||||
|
||||
prosemirror-keymap@1.2.2:
|
||||
dependencies:
|
||||
prosemirror-state: 1.4.3
|
||||
|
||||
+16
-16
@@ -49,22 +49,22 @@ catalog:
|
||||
"@testcontainers/mysql": ^12.0.1
|
||||
"@testcontainers/postgresql": ^12.0.1
|
||||
"@testcontainers/redis": ^12.0.1
|
||||
"@tiptap/extension-color": 3.23.6
|
||||
"@tiptap/extension-highlight": 3.23.6
|
||||
"@tiptap/extension-image": 3.23.6
|
||||
"@tiptap/extension-link": ^3.23.6
|
||||
"@tiptap/extension-placeholder": ^3.23.6
|
||||
"@tiptap/extension-table": 3.23.6
|
||||
"@tiptap/extension-table-cell": 3.23.6
|
||||
"@tiptap/extension-table-header": 3.23.6
|
||||
"@tiptap/extension-table-row": 3.23.6
|
||||
"@tiptap/extension-task-item": 3.23.6
|
||||
"@tiptap/extension-task-list": 3.23.6
|
||||
"@tiptap/extension-text-align": 3.23.6
|
||||
"@tiptap/extension-text-style": 3.23.6
|
||||
"@tiptap/extension-underline": 3.23.6
|
||||
"@tiptap/react": ^3.23.6
|
||||
"@tiptap/starter-kit": ^3.23.6
|
||||
"@tiptap/extension-color": 3.24.0
|
||||
"@tiptap/extension-highlight": 3.24.0
|
||||
"@tiptap/extension-image": 3.24.0
|
||||
"@tiptap/extension-link": ^3.24.0
|
||||
"@tiptap/extension-placeholder": ^3.24.0
|
||||
"@tiptap/extension-table": 3.24.0
|
||||
"@tiptap/extension-table-cell": 3.24.0
|
||||
"@tiptap/extension-table-header": 3.24.0
|
||||
"@tiptap/extension-table-row": 3.24.0
|
||||
"@tiptap/extension-task-item": 3.24.0
|
||||
"@tiptap/extension-task-list": 3.24.0
|
||||
"@tiptap/extension-text-align": 3.24.0
|
||||
"@tiptap/extension-text-style": 3.24.0
|
||||
"@tiptap/extension-underline": 3.24.0
|
||||
"@tiptap/react": ^3.24.0
|
||||
"@tiptap/starter-kit": ^3.24.0
|
||||
"@trpc/client": ^11.17.0
|
||||
"@trpc/next": ^11.17.0
|
||||
"@trpc/react-query": ^11.17.0
|
||||
|
||||
Reference in new issue
Block a user