@@ -135,36 +99,7 @@ const MoveBlockButtons = () => {
hiddenOnCanvas
onClick={async () => {
if (!rep) return;
- let [sortedBlocks, siblings] = await getSortedSelection(rep);
- if (sortedBlocks.length > 1) return;
- let block = sortedBlocks[0];
- let nextBlock = siblings
- .slice(siblings.findIndex((s) => s.value === block.value) + 1)
- .find(
- (f) =>
- f.listData &&
- block.listData &&
- !f.listData.path.find((f) => f.entity === block.value),
- );
- if (
- nextBlock?.listData &&
- block.listData &&
- nextBlock.listData.depth === block.listData.depth - 1
- ) {
- if (useUIState.getState().foldedBlocks.includes(nextBlock.value))
- useUIState.getState().toggleFold(nextBlock.value);
- rep?.mutate.moveBlock({
- block: block.value,
- oldParent: block.listData?.parent,
- newParent: nextBlock.value,
- position: { type: "first" },
- });
- } else {
- rep?.mutate.moveBlockDown({
- entityID: block.value,
- parent: block.listData?.parent || block.parent,
- });
- }
+ await moveBlockDown(rep, entity_set.set);
}}
tooltipContent={
diff --git a/src/replicache/mutations.ts b/src/replicache/mutations.ts
index 20d915f7..4b57d64b 100644
--- a/src/replicache/mutations.ts
+++ b/src/replicache/mutations.ts
@@ -4,6 +4,7 @@ import type { Attribute, Attributes, FilterAttributes } from "./attributes";
import { SupabaseClient } from "@supabase/supabase-js";
import { Database } from "supabase/database.types";
import { generateKeyBetween } from "fractional-indexing";
+import { v7 } from "uuid";
export type MutationContext = {
permission_token_id: string;
@@ -427,17 +428,42 @@ const moveBlockUp: Mutation<{ entityID: string; parent: string }> = async (
},
});
};
-const moveBlockDown: Mutation<{ entityID: string; parent: string }> = async (
- args,
- ctx,
-) => {
+const moveBlockDown: Mutation<{
+ entityID: string;
+ parent: string;
+ permission_set?: string;
+}> = async (args, ctx) => {
let children = (await ctx.scanIndex.eav(args.parent, "card/block")).toSorted(
(a, b) => (a.data.position > b.data.position ? 1 : -1),
);
let index = children.findIndex((f) => f.data.value === args.entityID);
if (index === -1) return;
let next = children[index + 1];
- if (!next) return;
+ if (!next) {
+ // If this is the last block, create a new empty block above it using the addBlock helper
+ if (!args.permission_set) return; // Can't create block without permission_set
+
+ let newEntityID = v7();
+ let previousBlock = children[index - 1];
+ let position = generateKeyBetween(
+ previousBlock?.data.position || null,
+ children[index].data.position,
+ );
+
+ // Call the addBlock mutation helper directly
+ await addBlock(
+ {
+ parent: args.parent,
+ permission_set: args.permission_set,
+ factID: v7(),
+ type: "text",
+ newEntityID: newEntityID,
+ position: position,
+ },
+ ctx,
+ );
+ return;
+ }
await ctx.retractFact(children[index].id);
await ctx.assertFact({
id: children[index].id,
@@ -670,8 +696,7 @@ const updatePublicationDraft: Mutation<{
}
});
await ctx.runOnClient(async ({ tx }) => {
- if (args.title !== undefined)
- await tx.set("publication_title", args.title);
+ if (args.title !== undefined) await tx.set("publication_title", args.title);
if (args.description !== undefined)
await tx.set("publication_description", args.description);
if (args.tags !== undefined) await tx.set("publication_tags", args.tags);
diff --git a/src/utils/moveBlock.ts b/src/utils/moveBlock.ts
new file mode 100644
index 00000000..06b1de3e
--- /dev/null
+++ b/src/utils/moveBlock.ts
@@ -0,0 +1,81 @@
+import { Replicache } from "replicache";
+import { ReplicacheMutators } from "src/replicache";
+import { getSortedSelection } from "components/SelectionManager/selectionState";
+import { useUIState } from "src/useUIState";
+
+export const moveBlockUp = async (rep: Replicache) => {
+ let [sortedBlocks, siblings] = await getSortedSelection(rep);
+ if (sortedBlocks.length > 1) return;
+ let block = sortedBlocks[0];
+ let previousBlock =
+ siblings?.[siblings.findIndex((s) => s.value === block.value) - 1];
+ if (previousBlock.value === block.listData?.parent) {
+ previousBlock =
+ siblings?.[siblings.findIndex((s) => s.value === block.value) - 2];
+ }
+
+ if (
+ previousBlock?.listData &&
+ block.listData &&
+ block.listData.depth > 1 &&
+ !previousBlock.listData.path.find(
+ (f) => f.entity === block.listData?.parent,
+ )
+ ) {
+ let depth = block.listData.depth;
+ let newParent = previousBlock.listData.path.find(
+ (f) => f.depth === depth - 1,
+ );
+ if (!newParent) return;
+ if (useUIState.getState().foldedBlocks.includes(newParent.entity))
+ useUIState.getState().toggleFold(newParent.entity);
+ rep?.mutate.moveBlock({
+ block: block.value,
+ oldParent: block.listData?.parent,
+ newParent: newParent.entity,
+ position: { type: "end" },
+ });
+ } else {
+ rep?.mutate.moveBlockUp({
+ entityID: block.value,
+ parent: block.listData?.parent || block.parent,
+ });
+ }
+};
+
+export const moveBlockDown = async (
+ rep: Replicache,
+ permission_set: string,
+) => {
+ let [sortedBlocks, siblings] = await getSortedSelection(rep);
+ if (sortedBlocks.length > 1) return;
+ let block = sortedBlocks[0];
+ let nextBlock = siblings
+ .slice(siblings.findIndex((s) => s.value === block.value) + 1)
+ .find(
+ (f) =>
+ f.listData &&
+ block.listData &&
+ !f.listData.path.find((f) => f.entity === block.value),
+ );
+ if (
+ nextBlock?.listData &&
+ block.listData &&
+ nextBlock.listData.depth === block.listData.depth - 1
+ ) {
+ if (useUIState.getState().foldedBlocks.includes(nextBlock.value))
+ useUIState.getState().toggleFold(nextBlock.value);
+ rep?.mutate.moveBlock({
+ block: block.value,
+ oldParent: block.listData?.parent,
+ newParent: nextBlock.value,
+ position: { type: "first" },
+ });
+ } else {
+ rep?.mutate.moveBlockDown({
+ entityID: block.value,
+ parent: block.listData?.parent || block.parent,
+ permission_set: permission_set,
+ });
+ }
+};