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
handle header sizes and base size for fonts
awarm.space
1 week ago
980fcd7d
3e831c1f
+51
-97
5 changed files
expand all
collapse all
unified
split
app
lish
[did]
[publication]
[rkey]
PostContent.tsx
StaticPostContent.tsx
components
Blocks
TextBlock
index.tsx
src
fonts.ts
utils
blockTextSize.ts
+6
-4
app/lish/[did]/[publication]/[rkey]/PostContent.tsx
···
34
34
import { PublishedPollBlock } from "./Blocks/PublishedPollBlock";
35
35
import { PollData } from "./fetchPollData";
36
36
import { ButtonPrimary } from "components/Buttons";
37
37
+
import { blockTextSize } from "src/utils/blockTextSize";
37
38
38
39
export function PostContent({
39
40
blocks,
···
346
347
case PubLeafletBlocksText.isMain(b.block):
347
348
return (
348
349
<p
350
350
+
style={{ fontSize: blockTextSize.p }}
349
351
className={`textBlock ${className} ${b.block.textSize === "small" ? "text-sm text-secondary" : b.block.textSize === "large" ? "text-lg" : ""}`}
350
352
{...blockProps}
351
353
>
···
362
364
case PubLeafletBlocksHeader.isMain(b.block): {
363
365
if (b.block.level === 1)
364
366
return (
365
365
-
<h2 className={`h1Block ${className}`} {...blockProps}>
367
367
+
<h2 style={{ fontSize: blockTextSize.h1 }} className={`h1Block ${className}`} {...blockProps}>
366
368
<TextBlock
367
369
{...b.block}
368
370
index={index}
···
373
375
);
374
376
if (b.block.level === 2)
375
377
return (
376
376
-
<h3 className={`h2Block ${className}`} {...blockProps}>
378
378
+
<h3 style={{ fontSize: blockTextSize.h2 }} className={`h2Block ${className}`} {...blockProps}>
377
379
<TextBlock
378
380
{...b.block}
379
381
index={index}
···
384
386
);
385
387
if (b.block.level === 3)
386
388
return (
387
387
-
<h4 className={`h3Block ${className}`} {...blockProps}>
389
389
+
<h4 style={{ fontSize: blockTextSize.h3 }} className={`h3Block ${className}`} {...blockProps}>
388
390
<TextBlock
389
391
{...b.block}
390
392
index={index}
···
396
398
// if (b.block.level === 4) return <h4>{b.block.plaintext}</h4>;
397
399
// if (b.block.level === 5) return <h5>{b.block.plaintext}</h5>;
398
400
return (
399
399
-
<h6 className={`h6Block ${className}`} {...blockProps}>
401
401
+
<h6 style={{ fontSize: blockTextSize.h4 }} className={`h6Block ${className}`} {...blockProps}>
400
402
<TextBlock
401
403
{...b.block}
402
404
index={index}
+6
-5
app/lish/[did]/[publication]/[rkey]/StaticPostContent.tsx
···
12
12
PubLeafletPagesLinearDocument,
13
13
} from "lexicons/api";
14
14
import { blobRefToSrc } from "src/utils/blobRefToSrc";
15
15
+
import { blockTextSize } from "src/utils/blockTextSize";
15
16
import { TextBlockCore, TextBlockCoreProps } from "./Blocks/TextBlockCore";
16
17
import { StaticMathBlock } from "./Blocks/StaticMathBlock";
17
18
import { codeToHtml, bundledLanguagesInfo, bundledThemesInfo } from "shiki";
···
119
120
}
120
121
case PubLeafletBlocksText.isMain(b.block):
121
122
return (
122
122
-
<p>
123
123
+
<p style={{ fontSize: blockTextSize.p }}>
123
124
<StaticBaseTextBlock
124
125
facets={b.block.facets}
125
126
plaintext={b.block.plaintext}
···
130
131
case PubLeafletBlocksHeader.isMain(b.block): {
131
132
if (b.block.level === 1)
132
133
return (
133
133
-
<h1>
134
134
+
<h1 style={{ fontSize: blockTextSize.h1 }}>
134
135
<StaticBaseTextBlock {...b.block} index={[]} />
135
136
</h1>
136
137
);
137
138
if (b.block.level === 2)
138
139
return (
139
139
-
<h2>
140
140
+
<h2 style={{ fontSize: blockTextSize.h2 }}>
140
141
<StaticBaseTextBlock {...b.block} index={[]} />
141
142
</h2>
142
143
);
143
144
if (b.block.level === 3)
144
145
return (
145
145
-
<h3>
146
146
+
<h3 style={{ fontSize: blockTextSize.h3 }}>
146
147
<StaticBaseTextBlock {...b.block} index={[]} />
147
148
</h3>
148
149
);
149
150
// if (b.block.level === 4) return <h4>{b.block.plaintext}</h4>;
150
151
// if (b.block.level === 5) return <h5>{b.block.plaintext}</h5>;
151
152
return (
152
152
-
<h6>
153
153
+
<h6 style={{ fontSize: blockTextSize.h4 }}>
153
154
<StaticBaseTextBlock {...b.block} index={[]} />
154
155
</h6>
155
156
);
+20
-5
components/Blocks/TextBlock/index.tsx
···
25
25
import { DotLoader } from "components/utils/DotLoader";
26
26
import { useMountProsemirror } from "./mountProsemirror";
27
27
import { schema } from "./schema";
28
28
+
import { blockTextSize } from "src/utils/blockTextSize";
28
29
29
30
import { Mention, MentionAutocomplete } from "components/Mention";
30
31
import { addMentionToEditor } from "app/[leaflet_id]/publish/BskyPostEditorProsemirror";
31
32
32
33
const HeadingStyle = {
33
33
-
1: "text-xl font-bold [font-family:var(--theme-heading-font)]",
34
34
-
2: "text-lg font-bold [font-family:var(--theme-heading-font)]",
35
35
-
3: "text-base font-bold text-secondary [font-family:var(--theme-heading-font)]",
34
34
+
1: "font-bold [font-family:var(--theme-heading-font)]",
35
35
+
2: "font-bold [font-family:var(--theme-heading-font)]",
36
36
+
3: "font-bold text-secondary [font-family:var(--theme-heading-font)]",
37
37
+
} as { [level: number]: string };
38
38
+
39
39
+
const headingFontSize = {
40
40
+
1: blockTextSize.h1,
41
41
+
2: blockTextSize.h2,
42
42
+
3: blockTextSize.h3,
36
43
} as { [level: number]: string };
37
44
38
45
export function TextBlock(
···
162
169
}
163
170
return (
164
171
<div
165
165
-
style={{ wordBreak: "break-word" }} // better than tailwind break-all!
172
172
+
style={{
173
173
+
wordBreak: "break-word",
174
174
+
...(props.type === "heading" ? { fontSize: headingFontSize[headingLevel?.data.value || 1] } : {}),
175
175
+
}}
166
176
className={`
167
177
${alignmentClass}
168
178
${props.type === "blockquote" ? (props.previousBlock?.type === "blockquote" ? `blockquote pt-3 ` : "blockquote") : ""}
···
266
276
// unless we break *only* on urls, this is better than tailwind 'break-all'
267
277
// b/c break-all can cause breaks in the middle of words, but break-word still
268
278
// forces break if a single text string (e.g. a url) spans more than a full line
269
269
-
style={{ wordBreak: "break-word", fontFamily: props.type === "heading" ? "var(--theme-heading-font)" : "var(--theme-font)" }}
279
279
+
style={{
280
280
+
wordBreak: "break-word",
281
281
+
fontFamily: props.type === "heading" ? "var(--theme-heading-font)" : "var(--theme-font)",
282
282
+
...(props.type === "heading" ? { fontSize: headingFontSize[headingLevel?.data.value || 1] } : {}),
283
283
+
}}
270
284
className={`
271
285
${alignmentClass}
272
286
grow resize-none align-top whitespace-pre-wrap bg-transparent
···
290
304
props.nextBlock === null ? (
291
305
// if this is the only block on the page and is empty or is a canvas, show placeholder
292
306
<div
307
307
+
style={props.type === "heading" ? { fontSize: headingFontSize[headingLevel?.data.value || 1] } : undefined}
293
308
className={`${props.className} ${alignmentClass} w-full pointer-events-none absolute top-0 left-0 italic text-tertiary flex flex-col
294
309
${props.type === "heading" ? HeadingStyle[headingLevel?.data.value || 1] : textStyle}
295
310
`}
+12
-83
src/fonts.ts
···
6
6
displayName: string;
7
7
fontFamily: string;
8
8
fallback: string[];
9
9
+
baseSize?: number; // base font size in px for document content
9
10
} & (
10
11
| {
11
12
// Self-hosted fonts with local files
···
33
34
id: "quattro",
34
35
displayName: "iA Writer Quattro",
35
36
fontFamily: "iA Writer Quattro V",
37
37
+
baseSize: 16,
36
38
type: "local",
37
39
files: [
38
40
{
···
52
54
id: "lora",
53
55
displayName: "Lora",
54
56
fontFamily: "Lora",
57
57
+
baseSize: 17,
55
58
type: "local",
56
59
files: [
57
60
{
···
67
70
],
68
71
fallback: ["Georgia", "serif"],
69
72
},
70
70
-
"source-sans": {
71
71
-
id: "source-sans",
72
72
-
displayName: "Source Sans",
73
73
-
fontFamily: "Source Sans 3",
74
74
-
type: "local",
75
75
-
files: [
76
76
-
{
77
77
-
path: "/fonts/SourceSans3-Variable.woff2",
78
78
-
style: "normal",
79
79
-
weight: "200 900",
80
80
-
},
81
81
-
{
82
82
-
path: "/fonts/SourceSans3-Italic-Variable.woff2",
83
83
-
style: "italic",
84
84
-
weight: "200 900",
85
85
-
},
86
86
-
],
87
87
-
fallback: ["system-ui", "sans-serif"],
88
88
-
},
89
73
"atkinson-hyperlegible": {
90
74
id: "atkinson-hyperlegible",
91
75
displayName: "Atkinson Hyperlegible",
92
76
fontFamily: "Atkinson Hyperlegible Next",
77
77
+
baseSize: 18,
93
78
type: "google",
94
79
googleFontsFamily:
95
80
"Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800",
96
81
fallback: ["system-ui", "sans-serif"],
97
82
},
98
98
-
"space-mono": {
99
99
-
id: "space-mono",
100
100
-
displayName: "Space Mono",
101
101
-
fontFamily: "Space Mono",
102
102
-
type: "google",
103
103
-
googleFontsFamily: "Space+Mono:ital,wght@0,400;0,700;1,400;1,700",
104
104
-
fallback: ["monospace"],
105
105
-
},
106
106
-
107
83
// Additional Google Fonts - Mono
108
84
"sometype-mono": {
109
85
id: "sometype-mono",
110
86
displayName: "Sometype Mono",
111
87
fontFamily: "Sometype Mono",
88
88
+
baseSize: 17,
112
89
type: "google",
113
90
googleFontsFamily: "Sometype+Mono:ital,wght@0,400;0,700;1,400;1,700",
114
91
fallback: ["monospace"],
115
92
},
116
93
117
94
// Additional Google Fonts - Sans
118
118
-
"pt-sans": {
119
119
-
id: "pt-sans",
120
120
-
displayName: "PT Sans",
121
121
-
fontFamily: "PT Sans",
122
122
-
type: "google",
123
123
-
googleFontsFamily: "PT+Sans:ital,wght@0,400;0,700;1,400;1,700",
124
124
-
fallback: ["system-ui", "sans-serif"],
125
125
-
},
126
95
montserrat: {
127
96
id: "montserrat",
128
97
displayName: "Montserrat",
129
98
fontFamily: "Montserrat",
99
99
+
baseSize: 17,
130
100
type: "google",
131
101
googleFontsFamily: "Montserrat:ital,wght@0,400;0,700;1,400;1,700",
132
102
fallback: ["system-ui", "sans-serif"],
133
103
},
134
134
-
"alegreya-sans": {
135
135
-
id: "alegreya-sans",
136
136
-
displayName: "Alegreya Sans",
137
137
-
fontFamily: "Alegreya Sans",
104
104
+
"source-sans": {
105
105
+
id: "source-sans",
106
106
+
displayName: "Source Sans 3",
107
107
+
fontFamily: "Source Sans 3",
108
108
+
baseSize: 18,
138
109
type: "google",
139
139
-
googleFontsFamily: "Alegreya+Sans:ital,wght@0,400;0,700;1,400;1,700",
110
110
+
googleFontsFamily: "Source+Sans+3:ital,wght@0,400;0,700;1,400;1,700",
140
111
fallback: ["system-ui", "sans-serif"],
141
141
-
},
142
142
-
143
143
-
// Additional Google Fonts - Serif
144
144
-
"pt-serif": {
145
145
-
id: "pt-serif",
146
146
-
displayName: "PT Serif",
147
147
-
fontFamily: "PT Serif",
148
148
-
type: "google",
149
149
-
googleFontsFamily: "PT+Serif:ital,wght@0,400;0,700;1,400;1,700",
150
150
-
fallback: ["Georgia", "serif"],
151
151
-
},
152
152
-
"crimson-text": {
153
153
-
id: "crimson-text",
154
154
-
displayName: "Crimson Text",
155
155
-
fontFamily: "Crimson Text",
156
156
-
type: "google",
157
157
-
googleFontsFamily: "Crimson+Text:ital,wght@0,400;0,700;1,400;1,700",
158
158
-
fallback: ["Georgia", "serif"],
159
159
-
},
160
160
-
cardo: {
161
161
-
id: "cardo",
162
162
-
displayName: "Cardo",
163
163
-
fontFamily: "Cardo",
164
164
-
type: "google",
165
165
-
googleFontsFamily: "Cardo:ital,wght@0,400;0,700;1,400",
166
166
-
fallback: ["Georgia", "serif"],
167
167
-
},
168
168
-
"ibm-plex-serif": {
169
169
-
id: "ibm-plex-serif",
170
170
-
displayName: "IBM Plex Serif",
171
171
-
fontFamily: "IBM Plex Serif",
172
172
-
type: "google",
173
173
-
googleFontsFamily: "IBM+Plex+Serif:ital,wght@0,400;0,700;1,400;1,700",
174
174
-
fallback: ["Georgia", "serif"],
175
175
-
},
176
176
-
"source-serif": {
177
177
-
id: "source-serif",
178
178
-
displayName: "Source Serif 4",
179
179
-
fontFamily: "Source Serif 4",
180
180
-
type: "google",
181
181
-
googleFontsFamily: "Source+Serif+4:ital,wght@0,400;0,700;1,400;1,700",
182
182
-
fallback: ["Georgia", "serif"],
183
112
},
184
113
};
185
114
+7
src/utils/blockTextSize.ts
···
1
1
+
export const blockTextSize = {
2
2
+
p: "1em",
3
3
+
h1: "2em",
4
4
+
h2: "1.5em",
5
5
+
h3: "1.25em",
6
6
+
h4: "1.125em",
7
7
+
} as const;