tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
28
pulls
pipelines
add code inline markup
awarm.space
7 months ago
6d9e91a0
593370df
+105
-3
10 changed files
expand all
collapse all
unified
split
actions
publishToPublication.ts
app
globals.css
lish
[did]
[publication]
[rkey]
TextBlock.tsx
components
Blocks
TextBlock
RenderYJSFragment.tsx
inputRules.ts
schema.ts
lexicons
api
lexicons.ts
types
pub
leaflet
richtext
facet.ts
pub
leaflet
richtext
facet.json
src
facet.ts
+2
actions/publishToPublication.ts
···
389
389
$type: "pub.leaflet.richtext.facet#strikethrough",
390
390
});
391
391
392
392
+
if (d.attributes?.code)
393
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
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
157
+
}
158
158
+
159
159
+
.inline-code {
160
160
+
display: inline;
161
161
+
font-size: 1em;
162
162
+
@apply bg-border-light;
163
163
+
@apply font-mono;
164
164
+
@apply px-[1px];
165
165
+
@apply py-[1px];
166
166
+
@apply -mx-[1px];
167
167
+
@apply -my-[1px];
168
168
+
@apply rounded-[4px];
169
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
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
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
64
-
if (link) {
66
66
+
if (isCode) {
67
67
+
children.push(
68
68
+
<code key={counter} className={className} id={id?.id}>
69
69
+
{segment.text}
70
70
+
</code>,
71
71
+
);
72
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
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
102
+
103
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
109
-
props.className = "highlight";
112
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
73
+
//Code
74
74
+
new InputRule(/\`([^`]+)\`$/, (state, match, start, end) => {
75
75
+
const [fullMatch, content] = match;
76
76
+
const { tr } = state;
77
77
+
if (content) {
78
78
+
const startIndex = start + fullMatch.indexOf("`");
79
79
+
tr.replaceWith(startIndex, end, state.schema.text(content))
80
80
+
.addMark(
81
81
+
startIndex,
82
82
+
startIndex + content.length,
83
83
+
schema.marks.code.create(),
84
84
+
)
85
85
+
.removeStoredMark(schema.marks.code);
86
86
+
return tr;
87
87
+
}
88
88
+
return null;
89
89
+
}),
90
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
9
+
code: {
10
10
+
parseDOM: [
11
11
+
{
12
12
+
tag: "code",
13
13
+
},
14
14
+
],
15
15
+
16
16
+
toDOM() {
17
17
+
return ["code", { class: "inline-code" }, 0];
18
18
+
},
19
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
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
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
487
+
code: {
488
488
+
type: 'object',
489
489
+
description: 'Facet feature for inline code.',
490
490
+
required: [],
491
491
+
properties: {},
492
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
510
+
},
511
511
+
id: {
512
512
+
type: 'object',
513
513
+
description:
514
514
+
'Facet feature for an identifier. Used for linking to a segment',
515
515
+
required: [],
516
516
+
properties: {
517
517
+
id: {
518
518
+
type: 'string',
519
519
+
},
520
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
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
71
+
}
72
72
+
73
73
+
/** Facet feature for inline code. */
74
74
+
export interface Code {
75
75
+
$type?: 'pub.leaflet.richtext.facet#code'
76
76
+
}
77
77
+
78
78
+
const hashCode = 'code'
79
79
+
80
80
+
export function isCode<V>(v: V) {
81
81
+
return is$typed(v, id, hashCode)
82
82
+
}
83
83
+
84
84
+
export function validateCode<V>(v: V) {
85
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
23
+
"#code",
23
24
"#highlight",
24
25
"#underline",
25
26
"#strikethrough",
···
61
62
"format": "uri"
62
63
}
63
64
}
65
65
+
},
66
66
+
"code": {
67
67
+
"type": "object",
68
68
+
"description": "Facet feature for inline code.",
69
69
+
"required": [],
70
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
12
+
code: {
13
13
+
type: "object",
14
14
+
description: "Facet feature for inline code.",
15
15
+
required: [],
16
16
+
properties: {},
17
17
+
},
12
18
highlight: {
13
19
type: "object",
14
20
description: "Facet feature for highlighted text.",