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/text-size": {
75 type: "text-size-union",
76 cardinality: "one",
77 },
78 "block/image": {
79 type: "image",
80 cardinality: "one",
81 },
82 "block/card": {
83 type: "reference",
84 cardinality: "one",
85 },
86 "block/bluesky-post": {
87 type: "bluesky-post",
88 cardinality: "one",
89 },
90 "block/math": {
91 type: "string",
92 cardinality: "one",
93 },
94 "block/code": {
95 type: "string",
96 cardinality: "one",
97 },
98 "block/code-language": {
99 type: "string",
100 cardinality: "one",
101 },
102} as const;
103
104const MailboxAttributes = {
105 "mailbox/draft": {
106 type: "reference",
107 cardinality: "one",
108 },
109 "mailbox/archive": {
110 type: "reference",
111 cardinality: "one",
112 },
113 "mailbox/subscriber-count": {
114 type: "number",
115 cardinality: "one",
116 },
117} as const;
118
119const LinkBlockAttributes = {
120 "link/preview": {
121 type: "image",
122 cardinality: "one",
123 },
124 "link/url": {
125 type: "string",
126 cardinality: "one",
127 },
128 "link/description": {
129 type: "string",
130 cardinality: "one",
131 },
132 "link/title": {
133 type: "string",
134 cardinality: "one",
135 },
136} as const;
137
138const EmbedBlockAttributes = {
139 "embed/url": {
140 type: "string",
141 cardinality: "one",
142 },
143 "embed/height": {
144 type: "number",
145 cardinality: "one",
146 },
147} as const;
148
149const BlueskyPostBlockAttributes = {
150 "bluesky-post/url": {
151 type: "string",
152 cardinality: "one",
153 },
154} as const;
155
156const ButtonBlockAttributes = {
157 "button/text": {
158 type: "string",
159 cardinality: "one",
160 },
161 "button/url": {
162 type: "string",
163 cardinality: "one",
164 },
165} as const;
166
167const ImageBlockAttributes = {
168 "image/full-bleed": {
169 type: "boolean",
170 cardinality: "one",
171 },
172 "image/alt": {
173 type: "string",
174 cardinality: "one",
175 },
176} as const;
177
178const PollBlockAttributes = {
179 "poll/options": {
180 type: "ordered-reference",
181 cardinality: "many",
182 },
183 "poll-option/name": {
184 type: "string",
185 cardinality: "one",
186 },
187} as const;
188
189export const ThemeAttributes = {
190 "theme/font": {
191 type: "string",
192 cardinality: "one",
193 },
194 "theme/page-leaflet-watermark": {
195 type: "boolean",
196 cardinality: "one",
197 },
198 "theme/page-width": {
199 type: "number",
200 cardinality: "one",
201 },
202 "theme/page-background": {
203 type: "color",
204 cardinality: "one",
205 },
206 "theme/background-image": {
207 type: "image",
208 cardinality: "one",
209 },
210 "theme/background-image-repeat": {
211 type: "number",
212 cardinality: "one",
213 },
214 "theme/card-background": {
215 type: "color",
216 cardinality: "one",
217 },
218 "theme/card-background-image": {
219 type: "image",
220 cardinality: "one",
221 },
222 "theme/card-background-image-repeat": {
223 type: "number",
224 cardinality: "one",
225 },
226 "theme/card-background-image-opacity": {
227 type: "number",
228 cardinality: "one",
229 },
230 "theme/card-border-hidden": {
231 type: "boolean",
232 cardinality: "one",
233 },
234 "theme/primary": {
235 type: "color",
236 cardinality: "one",
237 },
238 "theme/accent-background": {
239 type: "color",
240 cardinality: "one",
241 },
242 "theme/accent-text": {
243 type: "color",
244 cardinality: "one",
245 },
246 "theme/highlight-1": {
247 type: "color",
248 cardinality: "one",
249 },
250 "theme/highlight-2": {
251 type: "color",
252 cardinality: "one",
253 },
254 "theme/highlight-3": {
255 type: "color",
256 cardinality: "one",
257 },
258 "theme/code-theme": {
259 type: "string",
260 cardinality: "one",
261 },
262} as const;
263
264export const Attributes = {
265 ...RootAttributes,
266 ...PageAttributes,
267 ...BlockAttributes,
268 ...LinkBlockAttributes,
269 ...ThemeAttributes,
270 ...MailboxAttributes,
271 ...EmbedBlockAttributes,
272 ...BlueskyPostBlockAttributes,
273 ...ButtonBlockAttributes,
274 ...ImageBlockAttributes,
275 ...PollBlockAttributes,
276};
277export type Attributes = typeof Attributes;
278export type Attribute = keyof Attributes;
279export type Data<A extends keyof typeof Attributes> = {
280 text: { type: "text"; value: string };
281 string: { type: "string"; value: string };
282 "spatial-reference": {
283 type: "spatial-reference";
284 position: { x: number; y: number };
285 value: string;
286 };
287 "date-time": {
288 type: "date-time";
289 value: string;
290 originalTimezone: string;
291 dateOnly?: boolean;
292 };
293 "ordered-reference": {
294 type: "ordered-reference";
295 position: string;
296 value: string;
297 };
298 "bluesky-post": {
299 type: "bluesky-post";
300 value: DeepAsReadonlyJSONValue<
301 AppBskyFeedGetPostThread.OutputSchema["thread"]
302 >;
303 };
304 image: {
305 type: "image";
306 fallback: string;
307 src: string;
308 height: number;
309 width: number;
310 local?: string;
311 };
312 boolean: {
313 type: "boolean";
314 value: boolean;
315 };
316 number: {
317 type: "number";
318 value: number;
319 };
320 awareness: {
321 type: "awareness";
322 value: string;
323 };
324 reference: { type: "reference"; value: string };
325 "text-alignment-type-union": {
326 type: "text-alignment-type-union";
327 value: "right" | "left" | "center" | "justify";
328 };
329 "text-size-union": {
330 type: "text-size-union";
331 value: "default" | "small" | "large";
332 };
333 "page-type-union": { type: "page-type-union"; value: "doc" | "canvas" };
334 "block-type-union": {
335 type: "block-type-union";
336 value:
337 | "datetime"
338 | "rsvp"
339 | "text"
340 | "image"
341 | "card"
342 | "heading"
343 | "link"
344 | "mailbox"
345 | "embed"
346 | "button"
347 | "poll"
348 | "bluesky-post"
349 | "math"
350 | "code"
351 | "blockquote"
352 | "horizontal-rule";
353 };
354 "canvas-pattern-union": {
355 type: "canvas-pattern-union";
356 value: "dot" | "grid" | "plain";
357 };
358 color: { type: "color"; value: string };
359}[(typeof Attributes)[A]["type"]];
360export type FilterAttributes<F extends Partial<Attributes[keyof Attributes]>> =
361 {
362 [A in keyof Attributes as Attributes[A] extends F
363 ? A
364 : never]: Attributes[A];
365 };