a tool for shared writing and social publishing

add horizontal rules

+113 -3
+10 -1
actions/publishToPublication.ts
··· 16 16 PubLeafletBlocksWebsite, 17 17 PubLeafletBlocksCode, 18 18 PubLeafletBlocksMath, 19 + PubLeafletBlocksHorizontalRule, 19 20 } from "lexicons/api"; 20 21 import { Block } from "components/Blocks/Block"; 21 22 import { TID } from "@atproto/common"; ··· 232 233 b.type !== "image" && 233 234 b.type !== "link" && 234 235 b.type !== "code" && 235 - b.type !== "math" 236 + b.type !== "math" && 237 + b.type !== "horizontal-rule" 236 238 ) 237 239 return; 240 + 241 + if (b.type === "horizontal-rule") { 242 + let block: $Typed<PubLeafletBlocksHorizontalRule.Main> = { 243 + $type: ids.PubLeafletBlocksHorizontalRule, 244 + }; 245 + return block; 246 + } 238 247 239 248 if (b.type === "heading") { 240 249 let [headingLevel] = scan.eav(b.value, "block/heading-level");
+4
app/lish/[did]/[publication]/[rkey]/PostContent.tsx
··· 8 8 PubLeafletBlocksWebsite, 9 9 PubLeafletDocument, 10 10 PubLeafletPagesLinearDocument, 11 + PubLeafletBlocksHorizontalRule, 11 12 } from "lexicons/api"; 12 13 import { blobRefToSrc } from "src/utils/blobRefToSrc"; 13 14 import { TextBlock } from "./TextBlock"; ··· 92 93 `; 93 94 94 95 switch (true) { 96 + case PubLeafletBlocksHorizontalRule.isMain(b.block): { 97 + return <hr className="my-2 w-full border-border-light" />; 98 + } 95 99 case PubLeafletBlocksUnorderedList.isMain(b.block): { 96 100 return ( 97 101 <ul className="-ml-[1px] sm:ml-[9px] pb-2">
+4
app/lish/[did]/[publication]/[rkey]/StaticPostContent.tsx
··· 1 1 import { 2 2 PubLeafletBlocksCode, 3 3 PubLeafletBlocksHeader, 4 + PubLeafletBlocksHorizontalRule, 4 5 PubLeafletBlocksImage, 5 6 PubLeafletBlocksMath, 6 7 PubLeafletBlocksText, ··· 42 43 let b = block; 43 44 44 45 switch (true) { 46 + case PubLeafletBlocksHorizontalRule.isMain(b.block): { 47 + return <hr className="my-2 w-full border-border-light" />; 48 + } 45 49 case PubLeafletBlocksMath.isMain(b.block): { 46 50 return <StaticMathBlock block={b.block} />; 47 51 }
+2
components/Blocks/Block.tsx
··· 28 28 import { LockTiny } from "components/Icons/LockTiny"; 29 29 import { MathBlock } from "./MathBlock"; 30 30 import { CodeBlock } from "./CodeBlock"; 31 + import { HorizontalRule } from "./HorizontalRule"; 31 32 32 33 export type Block = { 33 34 factID: string; ··· 184 185 button: ButtonBlock, 185 186 poll: PollBlock, 186 187 "bluesky-post": BlueskyPostBlock, 188 + "horizontal-rule": HorizontalRule, 187 189 }; 188 190 189 191 export const BlockMultiselectIndicator = (props: BlockProps) => {
+3
components/Blocks/HorizontalRule.tsx
··· 1 + export const HorizontalRule = () => { 2 + return <hr className="my-2 w-full border-border-light" />; 3 + };
+11
components/Blocks/TextBlock/index.tsx
··· 342 342 <pre 343 343 data-entityid={props.entityID} 344 344 onBlur={async () => { 345 + if ( 346 + ["***", "---", "___"].includes( 347 + editorState?.doc.textContent.trim() || "", 348 + ) 349 + ) { 350 + await rep.rep?.mutate.assertFact({ 351 + entity: props.entityID, 352 + attribute: "block/type", 353 + data: { type: "block-type-union", value: "horizontal-rule" }, 354 + }); 355 + } 345 356 if (actionTimeout.current) { 346 357 rep.undoManager.endGroup(); 347 358 window.clearTimeout(actionTimeout.current);
+5
components/Blocks/TextBlock/useHandlePaste.ts
··· 243 243 type = "link"; 244 244 break; 245 245 } 246 + case "HR": { 247 + type = "horizontal-rule"; 248 + break; 249 + } 246 250 default: 247 251 type = null; 248 252 } ··· 563 567 "IMG", 564 568 "A", 565 569 "SPAN", 570 + "HR", 566 571 ].includes(elementNode.tagName) || 567 572 elementNode.getAttribute("data-entityid") || 568 573 elementNode.getAttribute("data-tex")
+2
lexicons/api/index.ts
··· 9 9 import * as PubLeafletPublication from './types/pub/leaflet/publication' 10 10 import * as PubLeafletBlocksCode from './types/pub/leaflet/blocks/code' 11 11 import * as PubLeafletBlocksHeader from './types/pub/leaflet/blocks/header' 12 + import * as PubLeafletBlocksHorizontalRule from './types/pub/leaflet/blocks/horizontalRule' 12 13 import * as PubLeafletBlocksImage from './types/pub/leaflet/blocks/image' 13 14 import * as PubLeafletBlocksMath from './types/pub/leaflet/blocks/math' 14 15 import * as PubLeafletBlocksText from './types/pub/leaflet/blocks/text' ··· 38 39 export * as PubLeafletPublication from './types/pub/leaflet/publication' 39 40 export * as PubLeafletBlocksCode from './types/pub/leaflet/blocks/code' 40 41 export * as PubLeafletBlocksHeader from './types/pub/leaflet/blocks/header' 42 + export * as PubLeafletBlocksHorizontalRule from './types/pub/leaflet/blocks/horizontalRule' 41 43 export * as PubLeafletBlocksImage from './types/pub/leaflet/blocks/image' 42 44 export * as PubLeafletBlocksMath from './types/pub/leaflet/blocks/math' 43 45 export * as PubLeafletBlocksText from './types/pub/leaflet/blocks/text'
+13
lexicons/api/lexicons.ts
··· 209 209 }, 210 210 }, 211 211 }, 212 + PubLeafletBlocksHorizontalRule: { 213 + lexicon: 1, 214 + id: 'pub.leaflet.blocks.horizontalRule', 215 + defs: { 216 + main: { 217 + type: 'object', 218 + required: [], 219 + properties: {}, 220 + }, 221 + }, 222 + }, 212 223 PubLeafletBlocksImage: { 213 224 lexicon: 1, 214 225 id: 'pub.leaflet.blocks.image', ··· 402 413 'lex:pub.leaflet.blocks.website', 403 414 'lex:pub.leaflet.blocks.math', 404 415 'lex:pub.leaflet.blocks.code', 416 + 'lex:pub.leaflet.blocks.horizontalRule', 405 417 ], 406 418 }, 407 419 alignment: { ··· 1651 1663 PubLeafletPublication: 'pub.leaflet.publication', 1652 1664 PubLeafletBlocksCode: 'pub.leaflet.blocks.code', 1653 1665 PubLeafletBlocksHeader: 'pub.leaflet.blocks.header', 1666 + PubLeafletBlocksHorizontalRule: 'pub.leaflet.blocks.horizontalRule', 1654 1667 PubLeafletBlocksImage: 'pub.leaflet.blocks.image', 1655 1668 PubLeafletBlocksMath: 'pub.leaflet.blocks.math', 1656 1669 PubLeafletBlocksText: 'pub.leaflet.blocks.text',
+25
lexicons/api/types/pub/leaflet/blocks/horizontalRule.ts
··· 1 + /** 2 + * GENERATED CODE - DO NOT MODIFY 3 + */ 4 + import { ValidationResult, BlobRef } from '@atproto/lexicon' 5 + import { CID } from 'multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons' 7 + import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' 8 + 9 + const is$typed = _is$typed, 10 + validate = _validate 11 + const id = 'pub.leaflet.blocks.horizontalRule' 12 + 13 + export interface Main { 14 + $type?: 'pub.leaflet.blocks.horizontalRule' 15 + } 16 + 17 + const hashMain = 'main' 18 + 19 + export function isMain<V>(v: V) { 20 + return is$typed(v, id, hashMain) 21 + } 22 + 23 + export function validateMain<V>(v: V) { 24 + return validate<Main & V>(v, id, hashMain) 25 + }
+2
lexicons/api/types/pub/leaflet/pages/linearDocument.ts
··· 12 12 import type * as PubLeafletBlocksWebsite from '../blocks/website' 13 13 import type * as PubLeafletBlocksMath from '../blocks/math' 14 14 import type * as PubLeafletBlocksCode from '../blocks/code' 15 + import type * as PubLeafletBlocksHorizontalRule from '../blocks/horizontalRule' 15 16 16 17 const is$typed = _is$typed, 17 18 validate = _validate ··· 42 43 | $Typed<PubLeafletBlocksWebsite.Main> 43 44 | $Typed<PubLeafletBlocksMath.Main> 44 45 | $Typed<PubLeafletBlocksCode.Main> 46 + | $Typed<PubLeafletBlocksHorizontalRule.Main> 45 47 | { $type: string } 46 48 alignment?: 47 49 | 'lex:pub.leaflet.pages.linearDocument#textAlignLeft'
+11
lexicons/pub/leaflet/blocks/horizontalRule.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "pub.leaflet.blocks.horizontalRule", 4 + "defs": { 5 + "main": { 6 + "type": "object", 7 + "required": [], 8 + "properties": {} 9 + } 10 + } 11 + }
+2 -1
lexicons/pub/leaflet/pages/linearDocument.json
··· 29 29 "pub.leaflet.blocks.unorderedList", 30 30 "pub.leaflet.blocks.website", 31 31 "pub.leaflet.blocks.math", 32 - "pub.leaflet.blocks.code" 32 + "pub.leaflet.blocks.code", 33 + "pub.leaflet.blocks.horizontalRule" 33 34 ] 34 35 }, 35 36 "alignment": {
+14
lexicons/src/blocks.ts
··· 18 18 }, 19 19 }, 20 20 }; 21 + 22 + export const PubLeafletBlocksHorizontalRule: LexiconDoc = { 23 + lexicon: 1, 24 + id: "pub.leaflet.blocks.horizontalRule", 25 + defs: { 26 + main: { 27 + type: "object", 28 + required: [], 29 + properties: {}, 30 + }, 31 + }, 32 + }; 33 + 21 34 export const PubLeafletBlocksCode: LexiconDoc = { 22 35 lexicon: 1, 23 36 id: "pub.leaflet.blocks.code", ··· 168 181 PubLeafletBlocksWebsite, 169 182 PubLeafletBlocksMath, 170 183 PubLeafletBlocksCode, 184 + PubLeafletBlocksHorizontalRule, 171 185 ]; 172 186 export const BlockUnion: LexRefUnion = { 173 187 type: "union",
+2 -1
src/replicache/attributes.ts
··· 331 331 | "poll" 332 332 | "bluesky-post" 333 333 | "math" 334 - | "code"; 334 + | "code" 335 + | "horizontal-rule"; 335 336 }; 336 337 "canvas-pattern-union": { 337 338 type: "canvas-pattern-union";
+3
src/utils/getBlocksAsHTML.tsx
··· 76 76 ) { 77 77 let wrapper: undefined | "h1" | "h2" | "h3"; 78 78 let [alignment] = await scanIndex(tx).eav(b.value, "block/text-alignment"); 79 + if (b.type === "horizontal-rule") { 80 + return "<hr />"; 81 + } 79 82 if (b.type === "code") { 80 83 let [code] = await scanIndex(tx).eav(b.value, "block/code"); 81 84 let [lang] = await scanIndex(tx).eav(b.value, "block/code-language");