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-background": {
195 type: "color",
196 cardinality: "one",
197 },
198 "theme/background-image": {
199 type: "image",
200 cardinality: "one",
201 },
202 "theme/background-image-repeat": {
203 type: "number",
204 cardinality: "one",
205 },
206 "theme/card-background": {
207 type: "color",
208 cardinality: "one",
209 },
210 "theme/card-background-image": {
211 type: "image",
212 cardinality: "one",
213 },
214 "theme/card-background-image-repeat": {
215 type: "number",
216 cardinality: "one",
217 },
218 "theme/card-background-image-opacity": {
219 type: "number",
220 cardinality: "one",
221 },
222 "theme/card-border-hidden": {
223 type: "boolean",
224 cardinality: "one",
225 },
226 "theme/primary": {
227 type: "color",
228 cardinality: "one",
229 },
230 "theme/accent-background": {
231 type: "color",
232 cardinality: "one",
233 },
234 "theme/accent-text": {
235 type: "color",
236 cardinality: "one",
237 },
238 "theme/highlight-1": {
239 type: "color",
240 cardinality: "one",
241 },
242 "theme/highlight-2": {
243 type: "color",
244 cardinality: "one",
245 },
246 "theme/highlight-3": {
247 type: "color",
248 cardinality: "one",
249 },
250 "theme/code-theme": {
251 type: "string",
252 cardinality: "one",
253 },
254} as const;
255
256export const Attributes = {
257 ...RootAttributes,
258 ...PageAttributes,
259 ...BlockAttributes,
260 ...LinkBlockAttributes,
261 ...ThemeAttributes,
262 ...MailboxAttributes,
263 ...EmbedBlockAttributes,
264 ...BlueskyPostBlockAttributes,
265 ...ButtonBlockAttributes,
266 ...ImageBlockAttributes,
267 ...PollBlockAttributes,
268};
269export type Attributes = typeof Attributes;
270export type Attribute = keyof Attributes;
271export type Data<A extends keyof typeof Attributes> = {
272 text: { type: "text"; value: string };
273 string: { type: "string"; value: string };
274 "spatial-reference": {
275 type: "spatial-reference";
276 position: { x: number; y: number };
277 value: string;
278 };
279 "date-time": {
280 type: "date-time";
281 value: string;
282 originalTimezone: string;
283 dateOnly?: boolean;
284 };
285 "ordered-reference": {
286 type: "ordered-reference";
287 position: string;
288 value: string;
289 };
290 "bluesky-post": {
291 type: "bluesky-post";
292 value: DeepAsReadonlyJSONValue<
293 AppBskyFeedGetPostThread.OutputSchema["thread"]
294 >;
295 };
296 image: {
297 type: "image";
298 fallback: string;
299 src: string;
300 height: number;
301 width: number;
302 local?: string;
303 };
304 boolean: {
305 type: "boolean";
306 value: boolean;
307 };
308 number: {
309 type: "number";
310 value: number;
311 };
312 awareness: {
313 type: "awareness";
314 value: string;
315 };
316 reference: { type: "reference"; value: string };
317 "text-alignment-type-union": {
318 type: "text-alignment-type-union";
319 value: "right" | "left" | "center" | "justify";
320 };
321 "page-type-union": { type: "page-type-union"; value: "doc" | "canvas" };
322 "block-type-union": {
323 type: "block-type-union";
324 value:
325 | "datetime"
326 | "rsvp"
327 | "text"
328 | "image"
329 | "card"
330 | "heading"
331 | "link"
332 | "mailbox"
333 | "embed"
334 | "button"
335 | "poll"
336 | "bluesky-post"
337 | "math"
338 | "code"
339 | "blockquote"
340 | "horizontal-rule";
341 };
342 "canvas-pattern-union": {
343 type: "canvas-pattern-union";
344 value: "dot" | "grid" | "plain";
345 };
346 color: { type: "color"; value: string };
347}[(typeof Attributes)[A]["type"]];
348export type FilterAttributes<F extends Partial<Attributes[keyof Attributes]>> =
349 {
350 [A in keyof Attributes as Attributes[A] extends F
351 ? A
352 : never]: Attributes[A];
353 };