a tool for shared writing and social publishing

add code inline markup

+105 -3
+2
actions/publishToPublication.ts
··· 389 389 $type: "pub.leaflet.richtext.facet#strikethrough", 390 390 }); 391 391 392 + if (d.attributes?.code) 393 + facet.features.push({ $type: "pub.leaflet.richtext.facet#code" }); 392 394 if (d.attributes?.highlight) 393 395 facet.features.push({ $type: "pub.leaflet.richtext.facet#highlight" }); 394 396 if (d.attributes?.underline)
+13 -1
app/globals.css
··· 30 30 31 31 --safe-padding-bottom: max(calc(env(safe-area-inset-bottom) - 8px), 16px); 32 32 } 33 - 34 33 @media (max-width: 640px) { 35 34 :root { 36 35 --list-marker-width: 20px; ··· 155 154 rgb(var(--primary)), 156 155 rgb(var(--bg-page)) 55% 157 156 ); 157 + } 158 + 159 + .inline-code { 160 + display: inline; 161 + font-size: 1em; 162 + @apply bg-border-light; 163 + @apply font-mono; 164 + @apply px-[1px]; 165 + @apply py-[1px]; 166 + @apply -mx-[1px]; 167 + @apply -my-[1px]; 168 + @apply rounded-[4px]; 169 + @apply box-decoration-clone; 158 170 } 159 171 160 172 pre.shiki code {
+9 -1
app/lish/[did]/[publication]/[rkey]/TextBlock.tsx
··· 45 45 let id = segment.facet?.find(PubLeafletRichtextFacet.isId); 46 46 let link = segment.facet?.find(PubLeafletRichtextFacet.isLink); 47 47 let isBold = segment.facet?.find(PubLeafletRichtextFacet.isBold); 48 + let isCode = segment.facet?.find(PubLeafletRichtextFacet.isCode); 48 49 let isStrikethrough = segment.facet?.find( 49 50 PubLeafletRichtextFacet.isStrikethrough, 50 51 ); ··· 54 55 PubLeafletRichtextFacet.isHighlight, 55 56 ); 56 57 let className = ` 58 + ${isCode ? "inline-code" : ""} 57 59 ${id ? "scroll-mt-12 scroll-mb-10" : ""} 58 60 ${isBold ? "font-bold" : ""} 59 61 ${isItalic ? "italic" : ""} ··· 61 63 ${isStrikethrough ? "line-through decoration-tertiary" : ""} 62 64 ${isHighlighted ? "highlight bg-highlight-1" : ""}`; 63 65 64 - if (link) { 66 + if (isCode) { 67 + children.push( 68 + <code key={counter} className={className} id={id?.id}> 69 + {segment.text} 70 + </code>, 71 + ); 72 + } else if (link) { 65 73 children.push( 66 74 <a 67 75 key={counter}
+4 -1
components/Blocks/TextBlock/RenderYJSFragment.tsx
··· 83 83 insert: string; 84 84 attributes?: { 85 85 strong?: {}; 86 + code?: {}; 86 87 em?: {}; 87 88 underline?: {}; 88 89 strikethrough?: {}; ··· 98 99 } as { style: CSSProperties; className: string } & { 99 100 [s: `data-${string}`]: any; 100 101 }; 102 + 103 + if (d.attributes?.code) props.className += " inline-code"; 101 104 if (d.attributes?.strong) props.style.fontWeight = "700"; 102 105 if (d.attributes?.em) props.style.fontStyle = "italic"; 103 106 if (d.attributes?.underline) props.style.textDecoration = "underline"; ··· 106 109 (props.style.textDecorationColor = theme.colors.tertiary); 107 110 } 108 111 if (d.attributes?.highlight) { 109 - props.className = "highlight"; 112 + props.className += " highlight"; 110 113 props["data-color"] = d.attributes.highlight.color; 111 114 props.style.backgroundColor = 112 115 d.attributes?.highlight.color === "1"
+18
components/Blocks/TextBlock/inputRules.ts
··· 70 70 return null; 71 71 }), 72 72 73 + //Code 74 + new InputRule(/\`([^`]+)\`$/, (state, match, start, end) => { 75 + const [fullMatch, content] = match; 76 + const { tr } = state; 77 + if (content) { 78 + const startIndex = start + fullMatch.indexOf("`"); 79 + tr.replaceWith(startIndex, end, state.schema.text(content)) 80 + .addMark( 81 + startIndex, 82 + startIndex + content.length, 83 + schema.marks.code.create(), 84 + ) 85 + .removeStoredMark(schema.marks.code); 86 + return tr; 87 + } 88 + return null; 89 + }), 90 + 73 91 //Italic 74 92 new InputRule(/(?:^|[^*])\*([^*]+)\*$/, (state, match, start, end) => { 75 93 const [fullMatch, content] = match;
+11
components/Blocks/TextBlock/schema.ts
··· 6 6 marks: { 7 7 strong: marks.strong, 8 8 em: marks.em, 9 + code: { 10 + parseDOM: [ 11 + { 12 + tag: "code", 13 + }, 14 + ], 15 + 16 + toDOM() { 17 + return ["code", { class: "inline-code" }, 0]; 18 + }, 19 + } as MarkSpec, 9 20 underline: { 10 21 parseDOM: [ 11 22 { tag: "u" },
+19
lexicons/api/lexicons.ts
··· 444 444 type: 'union', 445 445 refs: [ 446 446 'lex:pub.leaflet.richtext.facet#link', 447 + 'lex:pub.leaflet.richtext.facet#code', 447 448 'lex:pub.leaflet.richtext.facet#highlight', 448 449 'lex:pub.leaflet.richtext.facet#underline', 449 450 'lex:pub.leaflet.richtext.facet#strikethrough', 451 + 'lex:pub.leaflet.richtext.facet#id', 450 452 'lex:pub.leaflet.richtext.facet#bold', 451 453 'lex:pub.leaflet.richtext.facet#italic', 452 454 ], ··· 482 484 }, 483 485 }, 484 486 }, 487 + code: { 488 + type: 'object', 489 + description: 'Facet feature for inline code.', 490 + required: [], 491 + properties: {}, 492 + }, 485 493 highlight: { 486 494 type: 'object', 487 495 description: 'Facet feature for highlighted text.', ··· 499 507 description: 'Facet feature for strikethrough markup', 500 508 required: [], 501 509 properties: {}, 510 + }, 511 + id: { 512 + type: 'object', 513 + description: 514 + 'Facet feature for an identifier. Used for linking to a segment', 515 + required: [], 516 + properties: { 517 + id: { 518 + type: 'string', 519 + }, 520 + }, 502 521 }, 503 522 bold: { 504 523 type: 'object',
+16
lexicons/api/types/pub/leaflet/richtext/facet.ts
··· 16 16 index: ByteSlice 17 17 features: ( 18 18 | $Typed<Link> 19 + | $Typed<Code> 19 20 | $Typed<Highlight> 20 21 | $Typed<Underline> 21 22 | $Typed<Strikethrough> ··· 67 68 68 69 export function validateLink<V>(v: V) { 69 70 return validate<Link & V>(v, id, hashLink) 71 + } 72 + 73 + /** Facet feature for inline code. */ 74 + export interface Code { 75 + $type?: 'pub.leaflet.richtext.facet#code' 76 + } 77 + 78 + const hashCode = 'code' 79 + 80 + export function isCode<V>(v: V) { 81 + return is$typed(v, id, hashCode) 82 + } 83 + 84 + export function validateCode<V>(v: V) { 85 + return validate<Code & V>(v, id, hashCode) 70 86 } 71 87 72 88 /** Facet feature for highlighted text. */
+7
lexicons/pub/leaflet/richtext/facet.json
··· 20 20 "type": "union", 21 21 "refs": [ 22 22 "#link", 23 + "#code", 23 24 "#highlight", 24 25 "#underline", 25 26 "#strikethrough", ··· 61 62 "format": "uri" 62 63 } 63 64 } 65 + }, 66 + "code": { 67 + "type": "object", 68 + "description": "Facet feature for inline code.", 69 + "required": [], 70 + "properties": {} 64 71 }, 65 72 "highlight": { 66 73 "type": "object",
+6
lexicons/src/facet.ts
··· 9 9 uri: { type: "string", format: "uri" }, 10 10 }, 11 11 }, 12 + code: { 13 + type: "object", 14 + description: "Facet feature for inline code.", 15 + required: [], 16 + properties: {}, 17 + }, 12 18 highlight: { 13 19 type: "object", 14 20 description: "Facet feature for highlighted text.",