a tool for shared writing and social publishing

added heyboard shortcuts

+172 -1
+24
app/[leaflet_id]/actions/HelpButton.tsx
··· 58 58 keys={[metaKey(), isMac() ? "Ctrl" : "Meta", "X"]} 59 59 /> 60 60 <KeyboardShortcut name="Inline Link" keys={[metaKey(), "K"]} /> 61 + <KeyboardShortcut 62 + name="Make Title" 63 + keys={[metaKey(), isMac() ? "Opt" : "Alt", "1"]} 64 + /> 65 + <KeyboardShortcut 66 + name="Make Heading" 67 + keys={[metaKey(), isMac() ? "Opt" : "Alt", "2"]} 68 + /> 69 + <KeyboardShortcut 70 + name="Make Subheading" 71 + keys={[metaKey(), isMac() ? "Opt" : "Alt", "3"]} 72 + /> 73 + <KeyboardShortcut 74 + name="Regular Text" 75 + keys={[metaKey(), isMac() ? "Opt" : "Alt", "P"]} 76 + /> 77 + <KeyboardShortcut 78 + name="Large Text" 79 + keys={[metaKey(), isMac() ? "Opt" : "Alt", "+"]} 80 + /> 81 + <KeyboardShortcut 82 + name="Small Text" 83 + keys={[metaKey(), isMac() ? "Opt" : "Alt", "-"]} 84 + /> 61 85 62 86 <Label>Block Shortcuts</Label> 63 87 {/* shift + up/down arrows (or click + drag): select multiple blocks */}
+148 -1
components/SelectionManager/index.tsx
··· 89 89 }, 90 90 { 91 91 metaKey: true, 92 + altKey: true, 93 + key: ["1", "¡"], 94 + handler: async () => { 95 + let [sortedBlocks] = await getSortedSelectionBound(); 96 + for (let block of sortedBlocks) { 97 + await rep?.mutate.assertFact({ 98 + entity: block.value, 99 + attribute: "block/heading-level", 100 + data: { type: "number", value: 1 }, 101 + }); 102 + await rep?.mutate.assertFact({ 103 + entity: block.value, 104 + attribute: "block/type", 105 + data: { type: "block-type-union", value: "heading" }, 106 + }); 107 + } 108 + }, 109 + }, 110 + { 111 + metaKey: true, 112 + altKey: true, 113 + key: ["2", "™"], 114 + handler: async () => { 115 + let [sortedBlocks] = await getSortedSelectionBound(); 116 + for (let block of sortedBlocks) { 117 + await rep?.mutate.assertFact({ 118 + entity: block.value, 119 + attribute: "block/heading-level", 120 + data: { type: "number", value: 2 }, 121 + }); 122 + await rep?.mutate.assertFact({ 123 + entity: block.value, 124 + attribute: "block/type", 125 + data: { type: "block-type-union", value: "heading" }, 126 + }); 127 + } 128 + }, 129 + }, 130 + { 131 + metaKey: true, 132 + altKey: true, 133 + key: ["3", "£"], 134 + handler: async () => { 135 + let [sortedBlocks] = await getSortedSelectionBound(); 136 + for (let block of sortedBlocks) { 137 + await rep?.mutate.assertFact({ 138 + entity: block.value, 139 + attribute: "block/heading-level", 140 + data: { type: "number", value: 3 }, 141 + }); 142 + await rep?.mutate.assertFact({ 143 + entity: block.value, 144 + attribute: "block/type", 145 + data: { type: "block-type-union", value: "heading" }, 146 + }); 147 + } 148 + }, 149 + }, 150 + { 151 + metaKey: true, 152 + altKey: true, 153 + key: ["p", "π"], 154 + handler: async () => { 155 + let [sortedBlocks] = await getSortedSelectionBound(); 156 + for (let block of sortedBlocks) { 157 + // Convert to text block 158 + await rep?.mutate.assertFact({ 159 + entity: block.value, 160 + attribute: "block/type", 161 + data: { type: "block-type-union", value: "text" }, 162 + }); 163 + // Remove heading level if exists 164 + let headingLevel = await rep?.query((tx) => 165 + scanIndex(tx).eav(block.value, "block/heading-level"), 166 + ); 167 + if (headingLevel?.[0]) { 168 + await rep?.mutate.retractFact({ factID: headingLevel[0].id }); 169 + } 170 + // Remove text-size to make it default 171 + let textSizeFact = await rep?.query((tx) => 172 + scanIndex(tx).eav(block.value, "block/text-size"), 173 + ); 174 + if (textSizeFact?.[0]) { 175 + await rep?.mutate.retractFact({ factID: textSizeFact[0].id }); 176 + } 177 + } 178 + }, 179 + }, 180 + { 181 + metaKey: true, 182 + altKey: true, 183 + key: ["+", "≠"], 184 + handler: async () => { 185 + let [sortedBlocks] = await getSortedSelectionBound(); 186 + for (let block of sortedBlocks) { 187 + // Convert to text block 188 + await rep?.mutate.assertFact({ 189 + entity: block.value, 190 + attribute: "block/type", 191 + data: { type: "block-type-union", value: "text" }, 192 + }); 193 + // Remove heading level if exists 194 + let headingLevel = await rep?.query((tx) => 195 + scanIndex(tx).eav(block.value, "block/heading-level"), 196 + ); 197 + if (headingLevel?.[0]) { 198 + await rep?.mutate.retractFact({ factID: headingLevel[0].id }); 199 + } 200 + // Set text size to large 201 + await rep?.mutate.assertFact({ 202 + entity: block.value, 203 + attribute: "block/text-size", 204 + data: { type: "text-size-union", value: "large" }, 205 + }); 206 + } 207 + }, 208 + }, 209 + { 210 + metaKey: true, 211 + altKey: true, 212 + key: ["-", "–"], 213 + handler: async () => { 214 + let [sortedBlocks] = await getSortedSelectionBound(); 215 + for (let block of sortedBlocks) { 216 + // Convert to text block 217 + await rep?.mutate.assertFact({ 218 + entity: block.value, 219 + attribute: "block/type", 220 + data: { type: "block-type-union", value: "text" }, 221 + }); 222 + // Remove heading level if exists 223 + let headingLevel = await rep?.query((tx) => 224 + scanIndex(tx).eav(block.value, "block/heading-level"), 225 + ); 226 + if (headingLevel?.[0]) { 227 + await rep?.mutate.retractFact({ factID: headingLevel[0].id }); 228 + } 229 + // Set text size to small 230 + await rep?.mutate.assertFact({ 231 + entity: block.value, 232 + attribute: "block/text-size", 233 + data: { type: "text-size-union", value: "small" }, 234 + }); 235 + } 236 + }, 237 + }, 238 + { 239 + metaKey: true, 92 240 shift: true, 93 241 key: ["ArrowDown", "J"], 94 242 handler: async () => { ··· 684 832 } 685 833 return null; 686 834 } 687 - 688 835 689 836 function toggleMarkInBlocks(blocks: string[], mark: MarkType, attrs?: any) { 690 837 let everyBlockHasMark = blocks.reduce((acc, block) => {