import { Header1Small, Header2Small, Header3Small, } from "components/Icons/BlockTextSmall"; import { Props } from "components/Icons/Props"; import { ShortcutKey, Separator } from "components/Layout"; import { ToolbarButton } from "components/Toolbar"; import { TextSelection } from "prosemirror-state"; import { useCallback } from "react"; import { useEntity, useReplicache } from "src/replicache"; import { useEditorStates } from "src/state/useEditorState"; import { useUIState } from "src/useUIState"; export const TextBlockTypeToolbar = (props: { onClose: () => void; className?: string; }) => { let focusedBlock = useUIState((s) => s.focusedEntity); let blockType = useEntity(focusedBlock?.entityID || null, "block/type"); let headingLevel = useEntity( focusedBlock?.entityID || null, "block/heading-level", ); let textSize = useEntity(focusedBlock?.entityID || null, "block/text-size"); let { rep } = useReplicache(); let setLevel = useCallback( async (level: number) => { if (!focusedBlock) return; let entityID = focusedBlock.entityID; if ( blockType?.data.value !== "text" && blockType?.data.value !== "heading" ) { return; } await rep?.mutate.assertFact({ entity: entityID, attribute: "block/heading-level", data: { type: "number", value: level }, }); if (blockType.data.value === "text") { await rep?.mutate.assertFact({ entity: entityID, attribute: "block/type", data: { type: "block-type-union", value: "heading" }, }); } }, [rep, focusedBlock, blockType], ); return ( // This Toolbar should close once the user starts typing again <> { setLevel(1); }} active={ blockType?.data.value === "heading" && headingLevel?.data.value === 1 } tooltipContent={
Title
start line with #
} >
{ setLevel(2); }} active={ blockType?.data.value === "heading" && headingLevel?.data.value === 2 } tooltipContent={
Heading
start line with ##
} >
{ setLevel(3); }} active={ blockType?.data.value === "heading" && headingLevel?.data.value === 3 } tooltipContent={
Subheading
start line with ###
} >
{ if (headingLevel) await rep?.mutate.retractFact({ factID: headingLevel.id }); if (textSize) await rep?.mutate.retractFact({ factID: textSize.id }); if (!focusedBlock || !blockType) return; if (blockType.data.value !== "text") { let existingEditor = useEditorStates.getState().editorStates[focusedBlock.entityID]; let selection = existingEditor?.editor.selection; await rep?.mutate.assertFact({ entity: focusedBlock?.entityID, attribute: "block/type", data: { type: "block-type-union", value: "text" }, }); let newEditor = useEditorStates.getState().editorStates[focusedBlock.entityID]; if (!newEditor || !selection) return; newEditor.view?.dispatch( newEditor.editor.tr.setSelection( TextSelection.create(newEditor.editor.doc, selection.anchor), ), ); newEditor.view?.focus(); } }} active={ blockType?.data.value === "text" && textSize?.data.value !== "small" && textSize?.data.value !== "large" } tooltipContent={
Normal Text
} > Text
{ if (!focusedBlock || !blockType) return; if (blockType.data.value !== "text") { // Convert to text block first if it's a heading if (headingLevel) await rep?.mutate.retractFact({ factID: headingLevel.id }); await rep?.mutate.assertFact({ entity: focusedBlock.entityID, attribute: "block/type", data: { type: "block-type-union", value: "text" }, }); } // Set text size to large await rep?.mutate.assertFact({ entity: focusedBlock.entityID, attribute: "block/text-size", data: { type: "text-size-union", value: "large" }, }); }} active={ blockType?.data.value === "text" && textSize?.data.value === "large" } tooltipContent={
Large Text
} >
Large
{ if (!focusedBlock || !blockType) return; if (blockType.data.value !== "text") { // Convert to text block first if it's a heading if (headingLevel) await rep?.mutate.retractFact({ factID: headingLevel.id }); await rep?.mutate.assertFact({ entity: focusedBlock.entityID, attribute: "block/type", data: { type: "block-type-union", value: "text" }, }); } // Set text size to small await rep?.mutate.assertFact({ entity: focusedBlock.entityID, attribute: "block/text-size", data: { type: "text-size-union", value: "small" }, }); }} active={ blockType?.data.value === "text" && textSize?.data.value === "small" } tooltipContent={
Small Text
} >
Small
); }; export function TextBlockTypeButton(props: { setToolbarState: (s: "heading") => void; className?: string; }) { return ( Text Size} className={`${props.className}`} onClick={() => { props.setToolbarState("heading"); }} > ); } const TextSizeSmall = (props: Props) => { return ( ); };