Skip to content

Commit 168c425

Browse files
committed
Social Image: render definition docs
1 parent 7184f89 commit 168c425

File tree

4 files changed

+318
-63
lines changed

4 files changed

+318
-63
lines changed

netlify/edge-functions/common/definition.ts

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
1-
type SyntaxSegment = { annotation?: { tag: string }; segment: string };
2-
type DocElement = { annotation?: { tag: string }; segment: string };
1+
type SyntaxSegment = {
2+
annotation?: { tag: string };
3+
segment: string;
4+
};
5+
6+
type DocSpecial = { tag: "Link"; contents: Array<SyntaxSegment> };
7+
8+
type DocElement =
9+
| { tag: "Word"; contents: string }
10+
| { tag: "NamedLink"; contents: [DocElement, DocElement] }
11+
| { tag: "Paragraph"; contents: Array<DocElement> }
12+
| { tag: "Special"; contents: DocSpecial }
13+
| { tag: "Span"; contents: Array<DocElement> }
14+
| { tag: "UntitledSection"; contents: Array<DocElement> }
15+
| { tag: "Section"; contents: [DocElement, Array<DocElement>] }
16+
| { tag: "BulletedList"; contents: Array<DocElement> }
17+
| { tag: "NumberedList"; contents: [Number, Array<DocElement>] }
18+
| { tag: "Code"; contents: Array<DocElement> }
19+
| { tag: "CodeBlock"; contents: [string, DocElement] }
20+
| { tag: "Group"; contents: DocElement }
21+
| { tag: "Join"; contents: Array<DocElement> }
22+
| { tag: string; contents: Array<DocElement> | DocElement };
323

424
type DefinitionSyntax = {
525
contents: Array<SyntaxSegment>;
@@ -11,7 +31,7 @@ type APITerm = {
1131
defnTermTag: string;
1232
signature: Array<SyntaxSegment>;
1333
termDefinition: DefinitionSyntax;
14-
termDocs: Array<DocElement>;
34+
termDocs: Array<[string, string, DocElement]>;
1535
};
1636

1737
type APIType = {
@@ -33,5 +53,6 @@ export {
3353
APITerm,
3454
APIType,
3555
APIDefinitions,
56+
DocSpecial,
3657
DocElement,
3758
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import React from "https://esm.sh/[email protected]";
2+
import { DocSpecial, DocElement } from "../common/definition.ts";
3+
import * as Sizing from "../common/sizing.ts";
4+
import Colors from "../common/colors.ts";
5+
import { intersperse } from "../common/utils.ts";
6+
import { InlineSyntax } from "./syntax.tsx";
7+
8+
function Docs(props: { docRoot: DocElement }) {
9+
function renderSectionContent(e: DocElement) {
10+
switch (e.tag) {
11+
case "Span":
12+
return <p style={STYLES.docBlock}>{go(e)}</p>;
13+
case "Paragraph":
14+
return <p style={STYLES.docBlock}>{go(e)}</p>;
15+
default:
16+
return go(e);
17+
}
18+
}
19+
20+
function go(e: DocElement) {
21+
console.log(e.tag);
22+
switch (e.tag) {
23+
case "Special":
24+
const special = e.contents as DocSpecial;
25+
switch (special.tag) {
26+
case "Link":
27+
return (
28+
<span style={{ ...STYLES.docCode, ...STYLES.docCodeInline }}>
29+
<InlineSyntax syntax={special.contents} />
30+
</span>
31+
);
32+
}
33+
case "NamedLink":
34+
return <a style={STYLES.docLink}>{go(e.contents[0])}</a>;
35+
case "Word":
36+
return <span>{e.contents}</span>;
37+
case "Paragraph":
38+
return (
39+
<span style={STYLES.docInline}>
40+
{intersperse(
41+
(e.contents as Array<DocElement>).map(go),
42+
<span style={STYLES.docSpace}> </span>
43+
)}
44+
</span>
45+
);
46+
case "Span":
47+
return (
48+
<span style={STYLES.docInline}>
49+
{intersperse(
50+
(e.contents as Array<DocElement>).map(go),
51+
<span style={STYLES.docSpace}> </span>
52+
)}
53+
</span>
54+
);
55+
case "UntitledSection":
56+
return (
57+
<section style={STYLES.docBlock}>
58+
{(e.contents as Array<DocElement>).map(renderSectionContent)}
59+
</section>
60+
);
61+
case "Section":
62+
const [title, sectionContent] = e.contents as [
63+
DocElement,
64+
Array<DocElement>
65+
];
66+
67+
return (
68+
<section style={STYLES.docBlock}>
69+
<h1 style={STYLES.docBlock}>{go(title)}</h1>
70+
<div style={STYLES.docBlock}>
71+
{sectionContent.map(renderSectionContent)}
72+
</div>
73+
</section>
74+
);
75+
case "BulletedList":
76+
return (
77+
<ul style={STYLES.docList}>
78+
{(e.contents as Array<DocElement>).map((e) => (
79+
<li style={STYLES.docListItem}>
80+
<span style={STYLES.docListItemBullet}></span> {go(e)}
81+
</li>
82+
))}
83+
</ul>
84+
);
85+
case "NumberedList":
86+
const [start, els] = e.contents as [number, Array<DocElement>];
87+
return (
88+
<ol start={start} style={STYLES.docList}>
89+
{els.map((e, i) => (
90+
<li style={STYLES.docListItem}>
91+
<span style={STYLES.docListItemBullet}>{start + i}</span>{" "}
92+
{go(e)}
93+
</li>
94+
))}
95+
</ol>
96+
);
97+
case "Code":
98+
return (
99+
<code style={{ ...STYLES.docCode, ...STYLES.docCodeInline }}>
100+
{go(e.contents as DocElement)}
101+
</code>
102+
);
103+
case "Join":
104+
<span style={STYLES.docInline}>
105+
{(e.contents as Array<DocElement>).map(go)}
106+
</span>;
107+
case "Group":
108+
<span style={STYLES.docInline}>{go(e.contents as DocElement)}</span>;
109+
default:
110+
console.log("default", e.tag);
111+
if (Array.isArray(e.contents) && e.contents.length > 1) {
112+
return (
113+
<span>
114+
{intersperse(
115+
(e.contents as Array<DocElement>).map(go),
116+
<span style={{ width: "4ch" }}> </span>
117+
)}
118+
</span>
119+
);
120+
} else if (e.contents && typeof e.contents !== "string") {
121+
return go(e.contents as DocElement);
122+
} else {
123+
return <></>;
124+
}
125+
}
126+
}
127+
128+
const docs = go(props.docRoot);
129+
130+
return <section style={STYLES.docs}>{docs}</section>;
131+
}
132+
133+
const STYLES = {
134+
docs: {
135+
display: "flex",
136+
flexWrap: "wrap",
137+
flex: 1,
138+
width: "100%",
139+
marginTop: -300,
140+
background: "white",
141+
height: 300,
142+
fontSize: Sizing.toPx(2),
143+
gap: 0,
144+
paddingLeft: Sizing.toPx(3),
145+
paddingRight: Sizing.toPx(3),
146+
},
147+
docBlock: {
148+
display: "flex",
149+
flexWrap: "wrap",
150+
gap: 0,
151+
marginTop: 0,
152+
width: "100%",
153+
},
154+
docLink: {
155+
color: Colors.blue1,
156+
},
157+
docList: {
158+
display: "flex",
159+
flexWrap: "wrap",
160+
gap: Sizing.toPx(0.5),
161+
marginTop: 0,
162+
marginLeft: Sizing.toPx(1),
163+
width: "100%",
164+
},
165+
docListItem: {
166+
display: "flex",
167+
flexWrap: "wrap",
168+
gap: 0,
169+
marginTop: 0,
170+
width: "100%",
171+
listStyleType: "disc",
172+
},
173+
docListItemBullet: {
174+
marginRight: Sizing.toPx(1),
175+
},
176+
docInline: {},
177+
docSpace: {
178+
width: "8ch",
179+
},
180+
docCode: {
181+
fontFamily: "monospace",
182+
background: Colors.gray.lighten55,
183+
borderRadius: Sizing.toPx(0.25),
184+
paddingLeft: Sizing.toPx(0.5),
185+
paddingRight: Sizing.toPx(0.5),
186+
},
187+
docCodeInline: {},
188+
};
189+
190+
export default Docs;

netlify/edge-functions/social-image-helpers/project-definition-social-image.tsx

+17-60
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,18 @@
11
import React from "https://esm.sh/[email protected]";
2-
import { ShareAPI, SyntaxSegment } from "../common/share-api.ts";
2+
import { ShareAPI } from "../common/share-api.ts";
3+
import { DocSpecial, SyntaxSegment, DocElement } from "../common/definition.ts";
4+
import Docs from "./docs.tsx";
5+
import { Syntax } from "./syntax.tsx";
36
import { defaultSocialImage } from "./social-content.tsx";
47
import * as Sizing from "../common/sizing.ts";
58
import { Icon, IconType } from "./icon.tsx";
69
import Colors from "../common/colors.ts";
710
import SocialImageWithSheet from "./social-image-with-sheet.tsx";
11+
import SocialImageWithLargeSheet from "./social-image-with-large-sheet.tsx";
812
import Sheet from "./sheet.tsx";
913
import { titleize, hash } from "../common/utils.ts";
1014
import Tag from "./tag.tsx";
1115

12-
function Syntax(props: { syntax: Array<SyntaxSegment> }) {
13-
const segments = props.syntax.map((seg) => {
14-
const annotationStyle = STYLES[seg.annotation?.tag] || {};
15-
const style = {
16-
...STYLES.segment,
17-
...annotationStyle,
18-
};
19-
return <span style={style}>{seg.segment}</span>;
20-
});
21-
22-
return (
23-
<pre style={STYLES.syntax}>
24-
<code>{segments}</code>
25-
<span style={STYLES.syntaxFade}></span>
26-
</pre>
27-
);
28-
}
29-
3016
async function projectDefinitionSocialImage(
3117
handle: string,
3218
projectSlug: string,
@@ -66,6 +52,7 @@ async function projectDefinitionSocialImage(
6652
category: raw.defnTermeTag,
6753
signature: raw.signature,
6854
definition: raw.termDefinition,
55+
docs: raw.termDocs,
6956
};
7057
}
7158
} else {
@@ -77,6 +64,7 @@ async function projectDefinitionSocialImage(
7764
name: raw.bestTypeName,
7865
category: raw.defnTypeTag,
7966
definition: raw.typeDefinition,
67+
docs: raw.typeDocs,
8068
};
8169
}
8270
}
@@ -149,15 +137,23 @@ async function projectDefinitionSocialImage(
149137
topRowRight = [];
150138
}
151139

140+
const docs =
141+
definition.docs[0] && definition.docs[0][2] ? (
142+
<Docs docRoot={definition.docs[0][2]} />
143+
) : null;
144+
145+
const Wrapper = docs ? SocialImageWithLargeSheet : SocialImageWithSheet;
146+
152147
return (
153-
<SocialImageWithSheet>
148+
<Wrapper>
154149
<Sheet
155150
title={definition.name}
156151
topRowLeft={[projectRef, branchRef_]}
157152
topRowRight={topRowRight}
158153
bottomRowLeft={syntax}
159154
/>
160-
</SocialImageWithSheet>
155+
{docs}
156+
</Wrapper>
161157
);
162158
}
163159

@@ -184,45 +180,6 @@ const STYLES = {
184180
flexDirection: "column",
185181
gap: Sizing.toPx(0.5),
186182
},
187-
syntax: {
188-
position: "relative",
189-
margin: 0,
190-
padding: 0,
191-
fontSize: Sizing.toPx(2),
192-
lineHeight: 1.2,
193-
width: "100%",
194-
},
195-
syntaxFade: {
196-
position: "absolute",
197-
top: -10,
198-
right: `-${Sizing.toPx(2.5)}px`,
199-
bottom: -10,
200-
width: 400,
201-
height: Sizing.toPx(4),
202-
background: `linear-gradient(to right, rgba(255, 255, 255, 0), ${Colors.gray.lighten100}, ${Colors.gray.lighten100})`,
203-
},
204-
segment: {
205-
color: Colors.gray.base,
206-
fontFamily: "FiraCode",
207-
},
208-
DataTypeKeyword: {
209-
color: Colors.gray.lighten30,
210-
},
211-
TypeAscriptionColon: {
212-
color: Colors.gray.lighten30,
213-
},
214-
DataTypeModifier: {
215-
color: Colors.gray.lighten30,
216-
},
217-
TypeOperator: {
218-
color: Colors.gray.lighten30,
219-
},
220-
AbilityBraces: {
221-
color: Colors.gray.lighten30,
222-
},
223-
DelimiterChar: {
224-
color: Colors.gray.lighten30,
225-
},
226183
};
227184

228185
export default projectDefinitionSocialImage;

0 commit comments

Comments
 (0)