@@ -137,7 +141,7 @@ export function RenderedTextBlock(props: {
{(props.pageType === "doc" && props.first) ||
props.pageType === "canvas" ? (
{headingLevel?.data.value === 1
? "Title"
diff --git a/components/Blocks/index.tsx b/components/Blocks/index.tsx
index 68501c6f..9257b2ee 100644
--- a/components/Blocks/index.tsx
+++ b/components/Blocks/index.tsx
@@ -1,6 +1,6 @@
"use client";
-import { Fact, useReplicache } from "src/replicache";
+import { Fact, useEntity, useReplicache } from "src/replicache";
import { useUIState } from "src/useUIState";
import { useBlocks } from "src/hooks/queries/useBlocks";
@@ -169,9 +169,11 @@ function NewBlockButton(props: { lastBlock: Block | null; entityID: string }) {
: null,
);
+ let isLocked = useEntity(props.lastBlock?.value || null, "block/is-locked");
if (!entity_set.permissions.write) return null;
if (
- (props.lastBlock?.type === "text" || props.lastBlock?.type === "heading") &&
+ ((props.lastBlock?.type === "text" && !isLocked?.data.value) ||
+ props.lastBlock?.type === "heading") &&
(!editorState?.editor || editorState.editor.doc.content.size <= 2)
)
return null;
diff --git a/components/Blocks/useBlockKeyboardHandlers.ts b/components/Blocks/useBlockKeyboardHandlers.ts
index 030c5aa3..1408c8f4 100644
--- a/components/Blocks/useBlockKeyboardHandlers.ts
+++ b/components/Blocks/useBlockKeyboardHandlers.ts
@@ -23,11 +23,12 @@ export function useBlockKeyboardHandlers(
) {
let { rep } = useReplicache();
let entity_set = useEntitySetContext();
+ let isLocked = !!useEntity(props.entityID, "block/is-locked")?.data.value;
let isSelected = useUIState((s) => {
let selectedBlocks = s.selectedBlocks;
return (
- (!isTextBlock[props.type] || selectedBlocks.length > 1) &&
+ (!isTextBlock[props.type] || selectedBlocks.length > 1 || isLocked) &&
!!s.selectedBlocks.find((b) => b.value === props.entityID)
);
});
@@ -42,15 +43,24 @@ export function useBlockKeyboardHandlers(
let command = { Tab, ArrowUp, ArrowDown, Backspace, Enter, Escape }[
e.key
];
- command?.({ e, props, rep, entity_set, areYouSure, setAreYouSure });
+ command?.({
+ e,
+ props,
+ rep,
+ entity_set,
+ areYouSure,
+ setAreYouSure,
+ isLocked,
+ });
};
window.addEventListener("keydown", listener);
return () => window.removeEventListener("keydown", listener);
- }, [entity_set, isSelected, props, rep, areYouSure, setAreYouSure]);
+ }, [entity_set, isSelected, props, rep, areYouSure, setAreYouSure, isLocked]);
}
type Args = {
e: KeyboardEvent;
+ isLocked: boolean;
props: BlockProps;
rep: Replicache
;
entity_set: { set: string };
@@ -93,8 +103,16 @@ function ArrowUp({ e, props }: Args) {
if (!prevBlock) return;
}
-async function Backspace({ e, props, rep, areYouSure, setAreYouSure }: Args) {
+async function Backspace({
+ e,
+ props,
+ rep,
+ areYouSure,
+ setAreYouSure,
+ isLocked,
+}: Args) {
// if this is a textBlock, let the textBlock/keymap handle the backspace
+ if (isLocked) return;
if (isTextBlock[props.type]) return;
let el = e.target as HTMLElement;
if (
diff --git a/components/Canvas.tsx b/components/Canvas.tsx
index 081ec1c8..dd36e18d 100644
--- a/components/Canvas.tsx
+++ b/components/Canvas.tsx
@@ -543,13 +543,15 @@ const Gripper = (props: { onMouseDown: (e: React.MouseEvent) => void }) => {
className="w-[9px] shrink-0 py-1 mr-1 bg-bg-card cursor-grab touch-none"
>
+ {/* the gripper is two svg's stacked on top of each other.
+ One for the actual gripper, the other is an outline to endure the gripper stays visible on image backgrounds */}
diff --git a/components/Icons.tsx b/components/Icons.tsx
index 477487f5..e3ae3997 100644
--- a/components/Icons.tsx
+++ b/components/Icons.tsx
@@ -686,6 +686,46 @@ export const CloseTiny = (props: Props) => {
);
};
+export const LockTiny = (props: Props) => {
+ return (
+
+ );
+};
+
+export const UnlockTiny = (props: Props) => {
+ return (
+
+ );
+};
+
export const LogoTiny = (
props: Props & { fillColor: string; strokeColor: string },
) => {
@@ -1195,6 +1235,46 @@ export const ListCheckboxSmall = (props: Props) => {
);
};
+export const LockSmall = (props: Props) => {
+ return (
+
+ );
+};
+
+export const UnlockSmall = (props: Props) => {
+ return (
+
+ );
+};
+
export const MoveBlockDown = (props: Props) => {
return (