a tool for shared writing and social publishing
1import type { AppBskyFeedGetPostThread } from "@atproto/api";
2import type { DeepAsReadonlyJSONValue } from "./utils";
3
4const RootAttributes = {
5 "root/page": {
6 type: "ordered-reference",
7 cardinality: "many",
8 },
9} as const;
10const PageAttributes = {
11 "card/block": {
12 type: "ordered-reference",
13 cardinality: "many",
14 },
15 "page/type": {
16 type: "page-type-union",
17 cardinality: "one",
18 },
19 "canvas/block": {
20 type: "spatial-reference",
21 cardinality: "many",
22 },
23 "canvas/block/width": {
24 type: "number",
25 cardinality: "one",
26 },
27 "canvas/block/rotation": {
28 type: "number",
29 cardinality: "one",
30 },
31 "canvas/narrow-width": {
32 type: "boolean",
33 cardinality: "one",
34 },
35 "canvas/background-pattern": {
36 type: "canvas-pattern-union",
37 cardinality: "one",
38 },
39} as const;
40
41const BlockAttributes = {
42 "block/type": {
43 type: "block-type-union",
44 cardinality: "one",
45 },
46 "block/is-list": {
47 type: "boolean",
48 cardinality: "one",
49 },
50 "block/is-locked": {
51 type: "boolean",
52 cardinality: "one",
53 },
54 "block/check-list": {
55 type: "boolean",
56 cardinality: "one",
57 },
58 "block/text-alignment": {
59 type: "text-alignment-type-union",
60 cardinality: "one",
61 },
62 "block/date-time": {
63 type: "date-time",
64 cardinality: "one",
65 },
66 "block/text": {
67 type: "text",
68 cardinality: "one",
69 },
70 "block/heading-level": {
71 type: "number",
72 cardinality: "one",
73 },
74 "block/image": {
75 type: "image",
76 cardinality: "one",
77 },
78 "block/card": {
79 type: "reference",
80 cardinality: "one",
81 },
82 "block/bluesky-post": {
83 type: "bluesky-post",
84 cardinality: "one",
85 },
86 "block/math": {
87 type: "string",
88 cardinality: "one",
89 },
90 "block/code": {
91 type: "string",
92 cardinality: "one",
93 },
94 "block/code-language": {
95 type: "string",
96 cardinality: "one",
97 },
98} as const;
99
100const MailboxAttributes = {
101 "mailbox/draft": {
102 type: "reference",
103 cardinality: "one",
104 },
105 "mailbox/archive": {
106 type: "reference",
107 cardinality: "one",
108 },
109 "mailbox/subscriber-count": {
110 type: "number",
111 cardinality: "one",
112 },
113} as const;
114
115const LinkBlockAttributes = {
116 "link/preview": {
117 type: "image",
118 cardinality: "one",
119 },
120 "link/url": {
121 type: "string",
122 cardinality: "one",
123 },
124 "link/description": {
125 type: "string",
126 cardinality: "one",
127 },
128 "link/title": {
129 type: "string",
130 cardinality: "one",
131 },
132} as const;
133
134const EmbedBlockAttributes = {
135 "embed/url": {
136 type: "string",
137 cardinality: "one",
138 },
139 "embed/height": {
140 type: "number",
141 cardinality: "one",
142 },
143} as const;
144
145const BlueskyPostBlockAttributes = {
146 "bluesky-post/url": {
147 type: "string",
148 cardinality: "one",
149 },
150} as const;
151
152const ButtonBlockAttributes = {
153 "button/text": {
154 type: "string",
155 cardinality: "one",
156 },
157 "button/url": {
158 type: "string",
159 cardinality: "one",
160 },
161} as const;
162
163const ImageBlockAttributes = {
164 "image/full-bleed": {
165 type: "boolean",
166 cardinality: "one",
167 },
168 "image/alt": {
169 type: "string",
170 cardinality: "one",
171 },
172} as const;
173
174const PollBlockAttributes = {
175 "poll/options": {
176 type: "ordered-reference",
177 cardinality: "many",
178 },
179 "poll-option/name": {
180 type: "string",
181 cardinality: "one",
182 },
183} as const;
184
185export const ThemeAttributes = {
186 "theme/font": {
187 type: "string",
188 cardinality: "one",
189 },
190 "theme/page-leaflet-watermark": {
191 type: "boolean",
192 cardinality: "one",
193 },
194 "theme/page-width": {
195 type: "number",
196 cardinality: "one",
197 },
198 "theme/page-background": {
199 type: "color",
200 cardinality: "one",
201 },
202 "theme/background-image": {
203 type: "image",
204 cardinality: "one",
205 },
206 "theme/background-image-repeat": {
207 type: "number",
208 cardinality: "one",
209 },
210 "theme/card-background": {
211 type: "color",
212 cardinality: "one",
213 },
214 "theme/card-background-image": {
215 type: "image",
216 cardinality: "one",
217 },
218 "theme/card-background-image-repeat": {
219 type: "number",
220 cardinality: "one",
221 },
222 "theme/card-background-image-opacity": {
223 type: "number",
224 cardinality: "one",
225 },
226 "theme/card-border-hidden": {
227 type: "boolean",
228 cardinality: "one",
229 },
230 "theme/primary": {
231 type: "color",
232 cardinality: "one",
233 },
234 "theme/accent-background": {
235 type: "color",
236 cardinality: "one",
237 },
238 "theme/accent-text": {
239 type: "color",
240 cardinality: "one",
241 },
242 "theme/highlight-1": {
243 type: "color",
244 cardinality: "one",
245 },
246 "theme/highlight-2": {
247 type: "color",
248 cardinality: "one",
249 },
250 "theme/highlight-3": {
251 type: "color",
252 cardinality: "one",
253 },
254 "theme/code-theme": {
255 type: "string",
256 cardinality: "one",
257 },
258} as const;
259
260export const Attributes = {
261 ...RootAttributes,
262 ...PageAttributes,
263 ...BlockAttributes,
264 ...LinkBlockAttributes,
265 ...ThemeAttributes,
266 ...MailboxAttributes,
267 ...EmbedBlockAttributes,
268 ...BlueskyPostBlockAttributes,
269 ...ButtonBlockAttributes,
270 ...ImageBlockAttributes,
271 ...PollBlockAttributes,
272};
273export type Attributes = typeof Attributes;
274export type Attribute = keyof Attributes;
275export type Data<A extends keyof typeof Attributes> = {
276 text: { type: "text"; value: string };
277 string: { type: "string"; value: string };
278 "spatial-reference": {
279 type: "spatial-reference";
280 position: { x: number; y: number };
281 value: string;
282 };
283 "date-time": {
284 type: "date-time";
285 value: string;
286 originalTimezone: string;
287 dateOnly?: boolean;
288 };
289 "ordered-reference": {
290 type: "ordered-reference";
291 position: string;
292 value: string;
293 };
294 "bluesky-post": {
295 type: "bluesky-post";
296 value: DeepAsReadonlyJSONValue<
297 AppBskyFeedGetPostThread.OutputSchema["thread"]
298 >;
299 };
300 image: {
301 type: "image";
302 fallback: string;
303 src: string;
304 height: number;
305 width: number;
306 local?: string;
307 };
308 boolean: {
309 type: "boolean";
310 value: boolean;
311 };
312 number: {
313 type: "number";
314 value: number;
315 };
316 awareness: {
317 type: "awareness";
318 value: string;
319 };
320 reference: { type: "reference"; value: string };
321 "text-alignment-type-union": {
322 type: "text-alignment-type-union";
323 value: "right" | "left" | "center" | "justify";
324 };
325 "page-type-union": { type: "page-type-union"; value: "doc" | "canvas" };
326 "block-type-union": {
327 type: "block-type-union";
328 value:
329 | "datetime"
330 | "rsvp"
331 | "text"
332 | "image"
333 | "card"
334 | "heading"
335 | "link"
336 | "mailbox"
337 | "embed"
338 | "button"
339 | "poll"
340 | "bluesky-post"
341 | "math"
342 | "code"
343 | "blockquote"
344 | "horizontal-rule";
345 };
346 "canvas-pattern-union": {
347 type: "canvas-pattern-union";
348 value: "dot" | "grid" | "plain";
349 };
350 color: { type: "color"; value: string };
351}[(typeof Attributes)[A]["type"]];
352export type FilterAttributes<F extends Partial<Attributes[keyof Attributes]>> =
353 {
354 [A in keyof Attributes as Attributes[A] extends F
355 ? A
356 : never]: Attributes[A];
357 };