import type { AppBskyFeedGetPostThread } from "@atproto/api"; import type { DeepAsReadonlyJSONValue } from "./utils"; const RootAttributes = { "root/page": { type: "ordered-reference", cardinality: "many", }, // Links a standalone cover image (uploaded from the publish page, not an // in-document image block) to the root so it's reachable by get_facts and // its blob gets uploaded on publish. "root/cover-image": { type: "reference", cardinality: "one", }, } as const; const PageAttributes = { "card/block": { type: "ordered-reference", cardinality: "many", }, "page/type": { type: "page-type-union", cardinality: "one", }, // Publication nav state: root/page entries carry a route and tab title; // entries with page/external-url instead are external link tabs. "page/route": { type: "string", cardinality: "one", }, "page/title": { type: "string", cardinality: "one", }, "page/external-url": { type: "string", cardinality: "one", }, "canvas/block": { type: "spatial-reference", cardinality: "many", }, "canvas/block/width": { type: "number", cardinality: "one", }, "canvas/block/rotation": { type: "number", cardinality: "one", }, "canvas/narrow-width": { type: "boolean", cardinality: "one", }, "canvas/background-pattern": { type: "canvas-pattern-union", cardinality: "one", }, } as const; const BlockAttributes = { "block/type": { type: "block-type-union", cardinality: "one", }, "block/is-list": { type: "boolean", cardinality: "one", }, "block/is-locked": { type: "boolean", cardinality: "one", }, "block/check-list": { type: "boolean", cardinality: "one", }, "block/text-alignment": { type: "text-alignment-type-union", cardinality: "one", }, "block/date-time": { type: "date-time", cardinality: "one", }, "block/text": { type: "text", cardinality: "one", }, "block/heading-level": { type: "number", cardinality: "one", }, "block/text-size": { type: "text-size-union", cardinality: "one", }, "block/image": { type: "image", cardinality: "one", }, "block/card": { type: "reference", cardinality: "one", }, "block/bluesky-post": { type: "bluesky-post", cardinality: "one", }, "block/standard-site-post": { type: "string", cardinality: "one", }, "standard-site-post/size": { type: "standard-site-post-size-union", cardinality: "one", }, "standard-site-post/show-publication-theme": { type: "boolean", cardinality: "one", }, "block/standard-site-publication": { type: "string", cardinality: "one", }, "standard-site-publication/show-publication-theme": { type: "boolean", cardinality: "one", }, "block/math": { type: "string", cardinality: "one", }, "block/code": { type: "string", cardinality: "one", }, "block/code-language": { type: "string", cardinality: "one", }, "block/list-style": { type: "list-style-union", cardinality: "one", }, "block/list-number": { type: "number", cardinality: "one", }, "block/footnote": { type: "ordered-reference", cardinality: "many", }, "block/comment": { type: "ordered-reference", cardinality: "many", }, } as const; // Comments are authored by authenticated users; their facts carry an // author_did so the server can gate writes to the comment's author. // Comment content is stored as a YJS doc in a "block/text" fact on the // comment entity, like footnotes. const CommentAttributes = { "comment/reply": { type: "ordered-reference", cardinality: "many", }, "comment/author": { type: "string", cardinality: "one", }, "comment/created-at": { type: "string", cardinality: "one", }, // Snapshot of the anchor range in the block's text at creation time. The // live anchor is the comment mark in the block's YJS doc, which moves with // edits; these are kept as a fallback record of where the comment started. "comment/anchor-start": { type: "number", cardinality: "one", }, "comment/anchor-end": { type: "number", cardinality: "one", }, } as const; const MailboxAttributes = { "mailbox/draft": { type: "reference", cardinality: "one", }, "mailbox/archive": { type: "reference", cardinality: "one", }, "mailbox/subscriber-count": { type: "number", cardinality: "one", }, } as const; const LinkBlockAttributes = { "link/preview": { type: "image", cardinality: "one", }, "link/url": { type: "string", cardinality: "one", }, "link/description": { type: "string", cardinality: "one", }, "link/title": { type: "string", cardinality: "one", }, } as const; const EmbedBlockAttributes = { "embed/url": { type: "string", cardinality: "one", }, "embed/height": { type: "number", cardinality: "one", }, "embed/aspect-ratio": { type: "string", cardinality: "one", }, } as const; const BlueskyPostBlockAttributes = { "bluesky-post/url": { type: "string", cardinality: "one", }, "bluesky-post/host": { type: "string", cardinality: "one", }, } as const; const ButtonBlockAttributes = { "button/text": { type: "string", cardinality: "one", }, "button/url": { type: "string", cardinality: "one", }, } as const; const ImageBlockAttributes = { "image/full-bleed": { type: "boolean", cardinality: "one", }, "image/alt": { type: "string", cardinality: "one", }, // Original filename, shown in the gallery's Edit Images list. "image/name": { type: "string", cardinality: "one", }, } as const; const GalleryBlockAttributes = { // Child image entities, each carrying their own block/image, image/alt and // image/name facts — mirrors poll/options. "gallery/image": { type: "ordered-reference", cardinality: "many", }, "gallery/format": { type: "gallery-format-union", cardinality: "one", }, "gallery/gap": { type: "number", cardinality: "one", }, // Max width per image in grid view (px); drives how many columns fit. "gallery/max-width": { type: "number", cardinality: "one", }, } as const; const PollBlockAttributes = { "poll/options": { type: "ordered-reference", cardinality: "many", }, "poll-option/name": { type: "string", cardinality: "one", }, } as const; const PostsListBlockAttributes = { "posts-list/view": { type: "posts-list-view-union", cardinality: "one", }, "posts-list/highlight-first-post": { type: "boolean", cardinality: "one", }, "posts-list/filter-tag": { type: "string", cardinality: "many", }, "posts-list/limit": { type: "number", cardinality: "one", }, } as const; const ThemeAttributes = { "theme/heading-font": { type: "string", cardinality: "one", }, "theme/body-font": { type: "string", cardinality: "one", }, "theme/page-leaflet-watermark": { type: "boolean", cardinality: "one", }, "theme/page-width": { type: "number", cardinality: "one", }, "theme/page-background": { type: "color", cardinality: "one", }, "theme/background-image": { type: "image", cardinality: "one", }, "theme/background-image-repeat": { type: "number", cardinality: "one", }, "theme/wordmark-image": { type: "image", cardinality: "one", }, "theme/wordmark-width": { type: "number", cardinality: "one", }, "theme/card-background": { type: "color", cardinality: "one", }, "theme/card-background-image": { type: "image", cardinality: "one", }, "theme/card-background-image-repeat": { type: "number", cardinality: "one", }, "theme/card-background-image-opacity": { type: "number", cardinality: "one", }, "theme/card-border-hidden": { type: "boolean", cardinality: "one", }, "theme/primary": { type: "color", cardinality: "one", }, "theme/accent-background": { type: "color", cardinality: "one", }, "theme/accent-text": { type: "color", cardinality: "one", }, "theme/highlight-1": { type: "color", cardinality: "one", }, "theme/highlight-2": { type: "color", cardinality: "one", }, "theme/highlight-3": { type: "color", cardinality: "one", }, "theme/code-theme": { type: "string", cardinality: "one", }, } as const; export const Attributes = { ...RootAttributes, ...PageAttributes, ...BlockAttributes, ...CommentAttributes, ...LinkBlockAttributes, ...ThemeAttributes, ...MailboxAttributes, ...EmbedBlockAttributes, ...BlueskyPostBlockAttributes, ...ButtonBlockAttributes, ...ImageBlockAttributes, ...GalleryBlockAttributes, ...PollBlockAttributes, ...PostsListBlockAttributes, }; export type Attributes = typeof Attributes; export type Attribute = keyof Attributes; export type Data = { text: { type: "text"; value: string }; string: { type: "string"; value: string }; "spatial-reference": { type: "spatial-reference"; position: { x: number; y: number }; value: string; }; "date-time": { type: "date-time"; value: string; originalTimezone: string; dateOnly?: boolean; }; "ordered-reference": { type: "ordered-reference"; position: string; value: string; }; "bluesky-post": { type: "bluesky-post"; value: DeepAsReadonlyJSONValue< AppBskyFeedGetPostThread.OutputSchema["thread"] >; }; image: { type: "image"; fallback: string; src: string; height: number; width: number; local?: string; }; boolean: { type: "boolean"; value: boolean; }; number: { type: "number"; value: number; }; awareness: { type: "awareness"; value: string; }; reference: { type: "reference"; value: string }; "text-alignment-type-union": { type: "text-alignment-type-union"; value: "right" | "left" | "center" | "justify"; }; "text-size-union": { type: "text-size-union"; value: "default" | "small" | "large"; }; "page-type-union": { type: "page-type-union"; value: "doc" | "canvas" }; "block-type-union": { type: "block-type-union"; value: | "datetime" | "rsvp" | "text" | "image" | "card" | "heading" | "link" | "mailbox" | "embed" | "button" | "poll" | "bluesky-post" | "standard-site-post" | "standard-site-publication" | "math" | "code" | "blockquote" | "horizontal-rule" | "members-only-delimiter" | "posts-list" | "signup" | "image-gallery"; }; "canvas-pattern-union": { type: "canvas-pattern-union"; value: "dot" | "grid" | "plain"; }; "list-style-union": { type: "list-style-union"; value: "ordered" | "unordered"; }; "gallery-format-union": { type: "gallery-format-union"; value: "grid" | "carousel" | "strip"; }; "posts-list-view-union": { type: "posts-list-view-union"; value: "small" | "medium"; }; "standard-site-post-size-union": { type: "standard-site-post-size-union"; value: "large" | "medium" | "small"; }; color: { type: "color"; value: string }; }[(typeof Attributes)[A]["type"]]; export type FilterAttributes> = { [A in keyof Attributes as Attributes[A] extends F ? A : never]: Attributes[A]; };