From 2beaa0d73046a1b02fcf2f6ad1989de421eacc00 Mon Sep 17 00:00:00 2001 From: celine Date: Thu, 8 Jan 2026 14:40:55 -0500 Subject: [PATCH 1/3] update color logic when selecting accent contrast color to use the most different color, rather than the most contrasted color --- .../ThemeManager/PublicationThemeProvider.tsx | 14 +++++++------- components/ThemeManager/ThemeProvider.tsx | 18 +++++++++--------- components/ThemeManager/themeUtils.ts | 7 ++++--- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/components/ThemeManager/PublicationThemeProvider.tsx b/components/ThemeManager/PublicationThemeProvider.tsx index 1549b5dd..c21302c1 100644 --- a/components/ThemeManager/PublicationThemeProvider.tsx +++ b/components/ThemeManager/PublicationThemeProvider.tsx @@ -2,7 +2,7 @@ import { useMemo, useState } from "react"; import { parseColor } from "react-aria-components"; import { useEntity } from "src/replicache"; -import { getColorContrast } from "./themeUtils"; +import { getColorDifference } from "./themeUtils"; import { useColorAttribute, colorToString } from "./useColorAttribute"; import { BaseThemeProvider, CardBorderHiddenContext } from "./ThemeProvider"; import { PubLeafletPublication, PubLeafletThemeColor } from "lexicons/api"; @@ -174,14 +174,14 @@ export const useLocalPubTheme = ( let newAccentContrast; let sortedAccents = [newTheme.accent1, newTheme.accent2].sort((a, b) => { return ( - getColorContrast( + getColorDifference( colorToString(b, "rgb"), colorToString( showPageBackground ? newTheme.bgPage : newTheme.bgLeaflet, "rgb", ), ) - - getColorContrast( + getColorDifference( colorToString(a, "rgb"), colorToString( showPageBackground ? newTheme.bgPage : newTheme.bgLeaflet, @@ -191,17 +191,17 @@ export const useLocalPubTheme = ( ); }); if ( - getColorContrast( + getColorDifference( colorToString(sortedAccents[0], "rgb"), colorToString(newTheme.primary, "rgb"), - ) < 30 && - getColorContrast( + ) < 0.15 && + getColorDifference( colorToString(sortedAccents[1], "rgb"), colorToString( showPageBackground ? newTheme.bgPage : newTheme.bgLeaflet, "rgb", ), - ) > 12 + ) > 0.08 ) { newAccentContrast = sortedAccents[1]; } else newAccentContrast = sortedAccents[0]; diff --git a/components/ThemeManager/ThemeProvider.tsx b/components/ThemeManager/ThemeProvider.tsx index 81f035a7..a6211c17 100644 --- a/components/ThemeManager/ThemeProvider.tsx +++ b/components/ThemeManager/ThemeProvider.tsx @@ -22,7 +22,7 @@ import { PublicationThemeProvider, } from "./PublicationThemeProvider"; import { PubLeafletPublication } from "lexicons/api"; -import { getColorContrast } from "./themeUtils"; +import { getColorDifference } from "./themeUtils"; // define a function to set an Aria Color to a CSS Variable in RGB function setCSSVariableToColor( @@ -140,11 +140,11 @@ export const BaseThemeProvider = ({ //sorting the accents by contrast on background let sortedAccents = [accent1, accent2].sort((a, b) => { return ( - getColorContrast( + getColorDifference( colorToString(b, "rgb"), colorToString(showPageBackground ? bgPage : bgLeaflet, "rgb"), ) - - getColorContrast( + getColorDifference( colorToString(a, "rgb"), colorToString(showPageBackground ? bgPage : bgLeaflet, "rgb"), ) @@ -156,14 +156,14 @@ export const BaseThemeProvider = ({ // then use the not contrasty option if ( - getColorContrast( + getColorDifference( colorToString(sortedAccents[0], "rgb"), colorToString(primary, "rgb"), - ) < 30 && - getColorContrast( + ) < 0.15 && + getColorDifference( colorToString(sortedAccents[1], "rgb"), colorToString(showPageBackground ? bgPage : bgLeaflet, "rgb"), - ) > 12 + ) > 0.08 ) { accentContrast = sortedAccents[1]; } else accentContrast = sortedAccents[0]; @@ -286,11 +286,11 @@ export function CardThemeProvider(props: { bgPage && accent1 && accent2 ? [accent1, accent2].sort((a, b) => { return ( - getColorContrast( + getColorDifference( colorToString(b, "rgb"), colorToString(bgPage, "rgb"), ) - - getColorContrast( + getColorDifference( colorToString(a, "rgb"), colorToString(bgPage, "rgb"), ) diff --git a/components/ThemeManager/themeUtils.ts b/components/ThemeManager/themeUtils.ts index 0f9fd175..a25c48b2 100644 --- a/components/ThemeManager/themeUtils.ts +++ b/components/ThemeManager/themeUtils.ts @@ -1,4 +1,4 @@ -import { parse, contrastLstar, ColorSpace, sRGB } from "colorjs.io/fn"; +import { parse, ColorSpace, sRGB, distance, OKLab } from "colorjs.io/fn"; // define the color defaults for everything export const ThemeDefaults = { @@ -17,11 +17,12 @@ export const ThemeDefaults = { }; // used to calculate the contrast between page and accent1, accent2, and determin which is higher contrast -export function getColorContrast(color1: string, color2: string) { +export function getColorDifference(color1: string, color2: string) { ColorSpace.register(sRGB); + ColorSpace.register(OKLab); let parsedColor1 = parse(`rgb(${color1})`); let parsedColor2 = parse(`rgb(${color2})`); - return contrastLstar(parsedColor1, parsedColor2); + return distance(parsedColor1, parsedColor2, "oklab"); } -- 2.51.2 From 53e75495b03ef46069a5394754b688c7dfe094a1 Mon Sep 17 00:00:00 2001 From: celine Date: Thu, 8 Jan 2026 14:35:03 -1000 Subject: [PATCH 2/3] Feature/small text (#253) * added small text attribute and button to leaflet * fixing separators that were borked * add textSize to lexicon * moves PostBlocks into a single folder * update post to get textsize from leaflet * added large text * running the lexgen * little tweak * keep text size when user enters to make new textblock * preserve text size when blocks are copy pasted into leaflet * fiz some jumping on action button * added heyboard shortcuts * use 0 instead of p in the regular text keyboard shorcut --- .prettierrc | 2 +- actions/publishToPublication.ts | 26 +- .../notifications/CommentNotication.tsx | 2 +- .../notifications/Notification.tsx | 2 +- .../notifications/ReplyNotification.tsx | 2 +- .../comments/CommentsContent.tsx | 2 +- app/[leaflet_id]/actions/HelpButton.tsx | 24 + app/[leaflet_id]/actions/PublishButton.tsx | 4 +- app/[leaflet_id]/publish/PublishPost.tsx | 6 +- .../[rkey]/{ => Blocks}/BaseTextBlock.tsx | 13 +- .../[rkey]/{ => Blocks}/PubCodeBlock.tsx | 0 .../{ => Blocks}/PublishBskyPostBlock.tsx | 16 +- .../{ => Blocks}/PublishedPageBlock.tsx | 24 +- .../{ => Blocks}/PublishedPollBlock.tsx | 6 +- .../[rkey]/{ => Blocks}/StaticMathBlock.tsx | 0 .../[rkey]/{ => Blocks}/TextBlock.tsx | 2 +- .../[rkey]/{ => Blocks}/TextBlockCore.tsx | 0 .../[rkey]/Interactions/Comments/index.tsx | 2 +- .../[publication]/[rkey]/PostContent.tsx | 26 +- .../[rkey]/StaticPostContent.tsx | 4 +- app/lish/[did]/[publication]/page.tsx | 9 +- components/ActionBar/ActionButton.tsx | 4 +- components/Blocks/Block.tsx | 2 +- .../Blocks/TextBlock/RenderYJSFragment.tsx | 2 +- components/Blocks/TextBlock/index.tsx | 22 +- components/Blocks/TextBlock/keymap.ts | 14 + components/Blocks/TextBlock/useHandlePaste.ts | 11 + components/SelectionManager/index.tsx | 149 +- components/Toolbar/BlockToolbar.tsx | 14 +- components/Toolbar/HighlightToolbar.tsx | 2 +- components/Toolbar/InlineLinkToolbar.tsx | 2 +- components/Toolbar/ListToolbar.tsx | 4 +- components/Toolbar/TextBlockTypeToolbar.tsx | 249 ++- components/Toolbar/TextToolbar.tsx | 6 +- components/utils/DotLoader.tsx | 4 +- lexicons/api/lexicons.ts | 1662 +++++++++-------- lexicons/api/types/pub/leaflet/blocks/text.ts | 1 + lexicons/api/types/pub/leaflet/publication.ts | 78 +- lexicons/pub/leaflet/blocks/text.json | 8 + lexicons/pub/leaflet/publication.json | 10 +- lexicons/src/blocks.ts | 1 + src/replicache/attributes.ts | 8 + src/utils/getBlocksAsHTML.tsx | 3 + 43 files changed, 1381 insertions(+), 1047 deletions(-) rename app/lish/[did]/[publication]/[rkey]/{ => Blocks}/BaseTextBlock.tsx (71%) rename app/lish/[did]/[publication]/[rkey]/{ => Blocks}/PubCodeBlock.tsx (100%) rename app/lish/[did]/[publication]/[rkey]/{ => Blocks}/PublishBskyPostBlock.tsx (94%) rename app/lish/[did]/[publication]/[rkey]/{ => Blocks}/PublishedPageBlock.tsx (94%) rename app/lish/[did]/[publication]/[rkey]/{ => Blocks}/PublishedPollBlock.tsx (98%) rename app/lish/[did]/[publication]/[rkey]/{ => Blocks}/StaticMathBlock.tsx (100%) rename app/lish/[did]/[publication]/[rkey]/{ => Blocks}/TextBlock.tsx (98%) rename app/lish/[did]/[publication]/[rkey]/{ => Blocks}/TextBlockCore.tsx (100%) diff --git a/.prettierrc b/.prettierrc index 9e26dfee..0967ef42 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1 +1 @@ -{} \ No newline at end of file +{} diff --git a/actions/publishToPublication.ts b/actions/publishToPublication.ts index 0aff3481..beb1b8fb 100644 --- a/actions/publishToPublication.ts +++ b/actions/publishToPublication.ts @@ -2,10 +2,7 @@ import * as Y from "yjs"; import * as base64 from "base64-js"; -import { - restoreOAuthSession, - OAuthSessionError, -} from "src/atproto-oauth"; +import { restoreOAuthSession, OAuthSessionError } from "src/atproto-oauth"; import { getIdentityData } from "actions/getIdentityData"; import { AtpBaseClient, @@ -50,7 +47,10 @@ import { ColorToRGBA, } from "components/ThemeManager/colorToLexicons"; import { parseColor } from "@react-stately/color"; -import { Notification, pingIdentityToUpdateNotification } from "src/notifications"; +import { + Notification, + pingIdentityToUpdateNotification, +} from "src/notifications"; import { v7 } from "uuid"; type PublishResult = @@ -253,7 +253,11 @@ export async function publishToPublication({ // Create notifications for mentions (only on first publish) if (!existingDocUri) { - await createMentionNotifications(result.uri, record, credentialSession.did!); + await createMentionNotifications( + result.uri, + record, + credentialSession.did!, + ); } return { success: true, rkey, record: JSON.parse(JSON.stringify(record)) }; @@ -463,10 +467,12 @@ async function processBlocksToPages( if (b.type == "text") { let [stringValue, facets] = getBlockContent(b.value); + let [textSize] = scan.eav(b.value, "block/text-size"); let block: $Typed = { $type: ids.PubLeafletBlocksText, plaintext: stringValue, facets, + ...(textSize && { textSize: textSize.data.value }), }; return block; } @@ -865,7 +871,10 @@ async function createMentionNotifications( .single(); if (publication && publication.identity_did !== authorDid) { - mentionedPublications.set(publication.identity_did, feature.atURI); + mentionedPublications.set( + publication.identity_did, + feature.atURI, + ); } } else if (uri.collection === "pub.leaflet.document") { // Get the document owner's DID @@ -876,7 +885,8 @@ async function createMentionNotifications( .single(); if (document) { - const docRecord = document.data as PubLeafletDocument.Record; + const docRecord = + document.data as PubLeafletDocument.Record; if (docRecord.author !== authorDid) { mentionedDocuments.set(docRecord.author, feature.atURI); } diff --git a/app/(home-pages)/notifications/CommentNotication.tsx b/app/(home-pages)/notifications/CommentNotication.tsx index b40c8b03..f2791955 100644 --- a/app/(home-pages)/notifications/CommentNotication.tsx +++ b/app/(home-pages)/notifications/CommentNotication.tsx @@ -1,4 +1,4 @@ -import { BaseTextBlock } from "app/lish/[did]/[publication]/[rkey]/BaseTextBlock"; +import { BaseTextBlock } from "app/lish/[did]/[publication]/[rkey]/Blocks/BaseTextBlock"; import { AppBskyActorProfile, PubLeafletComment, diff --git a/app/(home-pages)/notifications/Notification.tsx b/app/(home-pages)/notifications/Notification.tsx index ea85bfff..f70f7af2 100644 --- a/app/(home-pages)/notifications/Notification.tsx +++ b/app/(home-pages)/notifications/Notification.tsx @@ -1,6 +1,6 @@ "use client"; import { Avatar } from "components/Avatar"; -import { BaseTextBlock } from "app/lish/[did]/[publication]/[rkey]/BaseTextBlock"; +import { BaseTextBlock } from "app/lish/[did]/[publication]/[rkey]/Blocks/BaseTextBlock"; import { PubLeafletPublication, PubLeafletRichtextFacet } from "lexicons/api"; import { timeAgo } from "src/utils/timeAgo"; import { useReplicache, useEntity } from "src/replicache"; diff --git a/app/(home-pages)/notifications/ReplyNotification.tsx b/app/(home-pages)/notifications/ReplyNotification.tsx index 56fc2447..699b7174 100644 --- a/app/(home-pages)/notifications/ReplyNotification.tsx +++ b/app/(home-pages)/notifications/ReplyNotification.tsx @@ -1,5 +1,5 @@ import { Avatar } from "components/Avatar"; -import { BaseTextBlock } from "app/lish/[did]/[publication]/[rkey]/BaseTextBlock"; +import { BaseTextBlock } from "app/lish/[did]/[publication]/[rkey]/Blocks/BaseTextBlock"; import { ReplyTiny } from "components/Icons/ReplyTiny"; import { CommentInNotification, diff --git a/app/(home-pages)/p/[didOrHandle]/comments/CommentsContent.tsx b/app/(home-pages)/p/[didOrHandle]/comments/CommentsContent.tsx index 3b8a218e..b7a9a350 100644 --- a/app/(home-pages)/p/[didOrHandle]/comments/CommentsContent.tsx +++ b/app/(home-pages)/p/[didOrHandle]/comments/CommentsContent.tsx @@ -6,7 +6,7 @@ import { AppBskyActorProfile, AtUri } from "@atproto/api"; import { PubLeafletComment, PubLeafletDocument } from "lexicons/api"; import { ReplyTiny } from "components/Icons/ReplyTiny"; import { Avatar } from "components/Avatar"; -import { BaseTextBlock } from "app/lish/[did]/[publication]/[rkey]/BaseTextBlock"; +import { BaseTextBlock } from "app/lish/[did]/[publication]/[rkey]/Blocks/BaseTextBlock"; import { blobRefToSrc } from "src/utils/blobRefToSrc"; import { getProfileComments, diff --git a/app/[leaflet_id]/actions/HelpButton.tsx b/app/[leaflet_id]/actions/HelpButton.tsx index d20d2f04..12877a6a 100644 --- a/app/[leaflet_id]/actions/HelpButton.tsx +++ b/app/[leaflet_id]/actions/HelpButton.tsx @@ -58,6 +58,30 @@ export const HelpButton = (props: { noShortcuts?: boolean }) => { keys={[metaKey(), isMac() ? "Ctrl" : "Meta", "X"]} /> + + + + + + {/* shift + up/down arrows (or click + drag): select multiple blocks */} diff --git a/app/[leaflet_id]/actions/PublishButton.tsx b/app/[leaflet_id]/actions/PublishButton.tsx index 4c2e8a29..4b665775 100644 --- a/app/[leaflet_id]/actions/PublishButton.tsx +++ b/app/[leaflet_id]/actions/PublishButton.tsx @@ -136,7 +136,9 @@ const UpdateButton = () => { content: (
{pub.doc ? "Updated! " : "Published! "} - link + + See Post +
), type: "success", diff --git a/app/[leaflet_id]/publish/PublishPost.tsx b/app/[leaflet_id]/publish/PublishPost.tsx index 6b0bdf15..4b890427 100644 --- a/app/[leaflet_id]/publish/PublishPost.tsx +++ b/app/[leaflet_id]/publish/PublishPost.tsx @@ -199,7 +199,11 @@ const PublishPostForm = ( className="place-self-end h-[30px]" disabled={charCount > 300} > - {isLoading ? : "Publish this Post!"} + {isLoading ? ( + + ) : ( + "Publish this Post!" + )} {oauthError && ( diff --git a/app/lish/[did]/[publication]/[rkey]/BaseTextBlock.tsx b/app/lish/[did]/[publication]/[rkey]/Blocks/BaseTextBlock.tsx similarity index 71% rename from app/lish/[did]/[publication]/[rkey]/BaseTextBlock.tsx rename to app/lish/[did]/[publication]/[rkey]/Blocks/BaseTextBlock.tsx index bf8b0cb2..50feeb13 100644 --- a/app/lish/[did]/[publication]/[rkey]/BaseTextBlock.tsx +++ b/app/lish/[did]/[publication]/[rkey]/Blocks/BaseTextBlock.tsx @@ -1,17 +1,16 @@ import { ProfilePopover } from "components/ProfilePopover"; -import { TextBlockCore, TextBlockCoreProps, RichText } from "./TextBlockCore"; +import { + TextBlockCore, + TextBlockCoreProps, + RichText, +} from "../Blocks/TextBlockCore"; import { ReactNode } from "react"; // Re-export RichText for backwards compatibility export { RichText }; function DidMentionWithPopover(props: { did: string; children: ReactNode }) { - return ( - - ); + return ; } export function BaseTextBlock(props: Omit) { diff --git a/app/lish/[did]/[publication]/[rkey]/PubCodeBlock.tsx b/app/lish/[did]/[publication]/[rkey]/Blocks/PubCodeBlock.tsx similarity index 100% rename from app/lish/[did]/[publication]/[rkey]/PubCodeBlock.tsx rename to app/lish/[did]/[publication]/[rkey]/Blocks/PubCodeBlock.tsx diff --git a/app/lish/[did]/[publication]/[rkey]/PublishBskyPostBlock.tsx b/app/lish/[did]/[publication]/[rkey]/Blocks/PublishBskyPostBlock.tsx similarity index 94% rename from app/lish/[did]/[publication]/[rkey]/PublishBskyPostBlock.tsx rename to app/lish/[did]/[publication]/[rkey]/Blocks/PublishBskyPostBlock.tsx index 0f6ae045..44c41a60 100644 --- a/app/lish/[did]/[publication]/[rkey]/PublishBskyPostBlock.tsx +++ b/app/lish/[did]/[publication]/[rkey]/Blocks/PublishBskyPostBlock.tsx @@ -5,14 +5,14 @@ import { useHasPageLoaded } from "components/InitialPageLoadProvider"; import { BlueskyTiny } from "components/Icons/BlueskyTiny"; import { CommentTiny } from "components/Icons/CommentTiny"; import { QuoteTiny } from "components/Icons/QuoteTiny"; -import { ThreadLink, QuotesLink } from "./PostLinks"; +import { ThreadLink, QuotesLink } from "../PostLinks"; import { useLocalizedDate } from "src/hooks/useLocalizedDate"; import { BlueskyEmbed, PostNotAvailable, } from "components/Blocks/BlueskyPostBlock/BlueskyEmbed"; import { BlueskyRichText } from "components/Blocks/BlueskyPostBlock/BlueskyRichText"; -import { openPage } from "./PostPages"; +import { openPage } from "../PostPages"; export const PubBlueskyPostBlock = (props: { post: PostView; @@ -22,10 +22,10 @@ export const PubBlueskyPostBlock = (props: { let post = props.post; const handleOpenThread = () => { - openPage( - props.pageId ? { type: "doc", id: props.pageId } : undefined, - { type: "thread", uri: post.uri }, - ); + openPage(props.pageId ? { type: "doc", id: props.pageId } : undefined, { + type: "thread", + uri: post.uri, + }); }; switch (true) { @@ -51,7 +51,9 @@ export const PubBlueskyPostBlock = (props: { let postId = post.uri.split("/")[4]; let url = `https://bsky.app/profile/${post.author.handle}/post/${postId}`; - const parent = props.pageId ? { type: "doc" as const, id: props.pageId } : undefined; + const parent = props.pageId + ? { type: "doc" as const, id: props.pageId } + : undefined; return (
p.type === "doc" && p.id === props.pageId, - ); + let isOpen = openPages.some((p) => p.type === "doc" && p.id === props.pageId); return (
{ e.preventDefault(); e.stopPropagation(); openPage( - props.parentPageId ? { type: "doc", id: props.parentPageId } : undefined, + props.parentPageId + ? { type: "doc", id: props.parentPageId } + : undefined, { type: "doc", id: props.pageId }, { scrollIntoView: false }, ); @@ -239,7 +241,9 @@ const Interactions = (props: { pageId: string; parentPageId?: string }) => { e.preventDefault(); e.stopPropagation(); openPage( - props.parentPageId ? { type: "doc", id: props.parentPageId } : undefined, + props.parentPageId + ? { type: "doc", id: props.parentPageId } + : undefined, { type: "doc", id: props.pageId }, { scrollIntoView: false }, ); diff --git a/app/lish/[did]/[publication]/[rkey]/PublishedPollBlock.tsx b/app/lish/[did]/[publication]/[rkey]/Blocks/PublishedPollBlock.tsx similarity index 98% rename from app/lish/[did]/[publication]/[rkey]/PublishedPollBlock.tsx rename to app/lish/[did]/[publication]/[rkey]/Blocks/PublishedPollBlock.tsx index cab8f0f5..c552375b 100644 --- a/app/lish/[did]/[publication]/[rkey]/PublishedPollBlock.tsx +++ b/app/lish/[did]/[publication]/[rkey]/Blocks/PublishedPollBlock.tsx @@ -9,12 +9,12 @@ import { useState, useEffect } from "react"; import { ButtonPrimary, ButtonSecondary } from "components/Buttons"; import { useIdentityData } from "components/IdentityProvider"; import { AtpAgent } from "@atproto/api"; -import { voteOnPublishedPoll } from "./voteOnPublishedPoll"; -import { PollData } from "./fetchPollData"; +import { voteOnPublishedPoll } from "../voteOnPublishedPoll"; +import { PollData } from "../fetchPollData"; import { Popover } from "components/Popover"; import LoginForm from "app/login/LoginForm"; import { BlueskyTiny } from "components/Icons/BlueskyTiny"; -import { getVoterIdentities, VoterIdentity } from "./getVoterIdentities"; +import { getVoterIdentities, VoterIdentity } from "../getVoterIdentities"; import { Json } from "supabase/database.types"; import { InfoSmall } from "components/Icons/InfoSmall"; diff --git a/app/lish/[did]/[publication]/[rkey]/StaticMathBlock.tsx b/app/lish/[did]/[publication]/[rkey]/Blocks/StaticMathBlock.tsx similarity index 100% rename from app/lish/[did]/[publication]/[rkey]/StaticMathBlock.tsx rename to app/lish/[did]/[publication]/[rkey]/Blocks/StaticMathBlock.tsx diff --git a/app/lish/[did]/[publication]/[rkey]/TextBlock.tsx b/app/lish/[did]/[publication]/[rkey]/Blocks/TextBlock.tsx similarity index 98% rename from app/lish/[did]/[publication]/[rkey]/TextBlock.tsx rename to app/lish/[did]/[publication]/[rkey]/Blocks/TextBlock.tsx index 20c765a1..b102b94e 100644 --- a/app/lish/[did]/[publication]/[rkey]/TextBlock.tsx +++ b/app/lish/[did]/[publication]/[rkey]/Blocks/TextBlock.tsx @@ -2,7 +2,7 @@ import { UnicodeString } from "@atproto/api"; import { PubLeafletRichtextFacet } from "lexicons/api"; import { useMemo } from "react"; -import { useHighlight } from "./useHighlight"; +import { useHighlight } from "../useHighlight"; import { BaseTextBlock } from "./BaseTextBlock"; type Facet = PubLeafletRichtextFacet.Main; diff --git a/app/lish/[did]/[publication]/[rkey]/TextBlockCore.tsx b/app/lish/[did]/[publication]/[rkey]/Blocks/TextBlockCore.tsx similarity index 100% rename from app/lish/[did]/[publication]/[rkey]/TextBlockCore.tsx rename to app/lish/[did]/[publication]/[rkey]/Blocks/TextBlockCore.tsx diff --git a/app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx b/app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx index b848aa3f..4e27693e 100644 --- a/app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx +++ b/app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx @@ -5,7 +5,7 @@ import { useIdentityData } from "components/IdentityProvider"; import { CommentBox } from "./CommentBox"; import { Json } from "supabase/database.types"; import { PubLeafletComment } from "lexicons/api"; -import { BaseTextBlock } from "../../BaseTextBlock"; +import { BaseTextBlock } from "../../Blocks/BaseTextBlock"; import { useMemo, useState } from "react"; import { CommentTiny } from "components/Icons/CommentTiny"; import { Separator } from "components/Layout"; diff --git a/app/lish/[did]/[publication]/[rkey]/PostContent.tsx b/app/lish/[did]/[publication]/[rkey]/PostContent.tsx index 40a341c8..58096e70 100644 --- a/app/lish/[did]/[publication]/[rkey]/PostContent.tsx +++ b/app/lish/[did]/[publication]/[rkey]/PostContent.tsx @@ -20,18 +20,18 @@ import { } from "lexicons/api"; import { blobRefToSrc } from "src/utils/blobRefToSrc"; -import { TextBlock } from "./TextBlock"; +import { TextBlock } from "./Blocks/TextBlock"; import { Popover } from "components/Popover"; import { theme } from "tailwind.config"; import { ImageAltSmall } from "components/Icons/ImageAlt"; -import { StaticMathBlock } from "./StaticMathBlock"; -import { PubCodeBlock } from "./PubCodeBlock"; +import { StaticMathBlock } from "./Blocks/StaticMathBlock"; +import { PubCodeBlock } from "./Blocks/PubCodeBlock"; import { AppBskyFeedDefs } from "@atproto/api"; -import { PubBlueskyPostBlock } from "./PublishBskyPostBlock"; +import { PubBlueskyPostBlock } from "./Blocks/PublishBskyPostBlock"; import { openPage } from "./PostPages"; import { PageLinkBlock } from "components/Blocks/PageLinkBlock"; -import { PublishedPageLinkBlock } from "./PublishedPageBlock"; -import { PublishedPollBlock } from "./PublishedPollBlock"; +import { PublishedPageLinkBlock } from "./Blocks/PublishedPageBlock"; +import { PublishedPollBlock } from "./Blocks/PublishedPollBlock"; import { PollData } from "./fetchPollData"; import { ButtonPrimary } from "components/Buttons"; @@ -173,7 +173,13 @@ export let Block = ({ let uri = b.block.postRef.uri; let post = bskyPostData.find((p) => p.uri === uri); if (!post) return
no prefetched post rip
; - return ; + return ( + + ); } case PubLeafletBlocksIframe.isMain(b.block): { return ( @@ -339,7 +345,10 @@ export let Block = ({ } case PubLeafletBlocksText.isMain(b.block): return ( -

+

); + case PubLeafletBlocksHeader.isMain(b.block): { if (b.block.level === 1) return ( diff --git a/app/lish/[did]/[publication]/[rkey]/StaticPostContent.tsx b/app/lish/[did]/[publication]/[rkey]/StaticPostContent.tsx index 009ac855..1f25bbba 100644 --- a/app/lish/[did]/[publication]/[rkey]/StaticPostContent.tsx +++ b/app/lish/[did]/[publication]/[rkey]/StaticPostContent.tsx @@ -12,8 +12,8 @@ import { PubLeafletPagesLinearDocument, } from "lexicons/api"; import { blobRefToSrc } from "src/utils/blobRefToSrc"; -import { TextBlockCore, TextBlockCoreProps } from "./TextBlockCore"; -import { StaticMathBlock } from "./StaticMathBlock"; +import { TextBlockCore, TextBlockCoreProps } from "./Blocks/TextBlockCore"; +import { StaticMathBlock } from "./Blocks/StaticMathBlock"; import { codeToHtml, bundledLanguagesInfo, bundledThemesInfo } from "shiki"; function StaticBaseTextBlock(props: Omit) { diff --git a/app/lish/[did]/[publication]/page.tsx b/app/lish/[did]/[publication]/page.tsx index adbd5556..4b19b1d4 100644 --- a/app/lish/[did]/[publication]/page.tsx +++ b/app/lish/[did]/[publication]/page.tsx @@ -18,6 +18,7 @@ import { InteractionPreview } from "components/InteractionsPreview"; import { LocalizedDate } from "./LocalizedDate"; import { PublicationHomeLayout } from "./PublicationHomeLayout"; import { PublicationAuthor } from "./PublicationAuthor"; +import { Separator } from "components/Layout"; export default async function Publication(props: { params: Promise<{ publication: string; did: string }>; @@ -147,7 +148,7 @@ export default async function Publication(props: {

-
+

{doc_record.publishedAt && ( )}{" "}

- {comments > 0 || quotes > 0 ? "| " : ""} + {comments > 0 || quotes > 0 || tags.length > 0 ? ( + + ) : ( + "" + )}
{icon}
-
{label}
+
{label}
{subtext && (
{subtext} diff --git a/components/Blocks/Block.tsx b/components/Blocks/Block.tsx index f38b6482..0e899749 100644 --- a/components/Blocks/Block.tsx +++ b/components/Blocks/Block.tsx @@ -10,7 +10,7 @@ import { focusBlock } from "src/utils/focusBlock"; import { useHandleDrop } from "./useHandleDrop"; import { useEntitySetContext } from "components/EntitySetProvider"; -import { TextBlock } from "components/Blocks/TextBlock"; +import { TextBlock } from "./TextBlock/index"; import { ImageBlock } from "./ImageBlock"; import { PageLinkBlock } from "./PageLinkBlock"; import { ExternalLinkBlock } from "./ExternalLinkBlock"; diff --git a/components/Blocks/TextBlock/RenderYJSFragment.tsx b/components/Blocks/TextBlock/RenderYJSFragment.tsx index 89d48d03..35c97cad 100644 --- a/components/Blocks/TextBlock/RenderYJSFragment.tsx +++ b/components/Blocks/TextBlock/RenderYJSFragment.tsx @@ -8,7 +8,7 @@ import { AtMentionLink } from "components/AtMentionLink"; import { Delta } from "src/utils/yjsFragmentToString"; import { ProfilePopover } from "components/ProfilePopover"; -type BlockElements = "h1" | "h2" | "h3" | null | "blockquote" | "p"; +type BlockElements = "h1" | "h2" | "h3" | null | "blockquote" | "p" | "small"; export function RenderYJSFragment({ value, wrapper, diff --git a/components/Blocks/TextBlock/index.tsx b/components/Blocks/TextBlock/index.tsx index 27cb3cfc..f774469b 100644 --- a/components/Blocks/TextBlock/index.tsx +++ b/components/Blocks/TextBlock/index.tsx @@ -120,6 +120,7 @@ export function RenderedTextBlock(props: { }) { let initialFact = useEntity(props.entityID, "block/text"); let headingLevel = useEntity(props.entityID, "block/heading-level"); + let textSize = useEntity(props.entityID, "block/text-size"); let alignment = useEntity(props.entityID, "block/text-alignment")?.data.value || "left"; let alignmentClass = { @@ -128,6 +129,12 @@ export function RenderedTextBlock(props: { center: "text-center", justify: "text-justify", }[alignment]; + let textStyle = + textSize?.data.value === "small" + ? "text-sm" + : textSize?.data.value === "large" + ? "text-lg" + : ""; let { permissions } = useEntitySetContext(); let content =
; @@ -159,7 +166,7 @@ export function RenderedTextBlock(props: { className={` ${alignmentClass} ${props.type === "blockquote" ? (props.previousBlock?.type === "blockquote" ? `blockquote pt-3 ` : "blockquote") : ""} - ${props.type === "heading" ? HeadingStyle[headingLevel?.data.value || 1] : ""} + ${props.type === "heading" ? HeadingStyle[headingLevel?.data.value || 1] : textStyle} w-full whitespace-pre-wrap outline-hidden ${props.className} `} > {content} @@ -169,6 +176,7 @@ export function RenderedTextBlock(props: { export function BaseTextBlock(props: BlockProps & { className?: string }) { let headingLevel = useEntity(props.entityID, "block/heading-level"); + let textSize = useEntity(props.entityID, "block/text-size"); let alignment = useEntity(props.entityID, "block/text-alignment")?.data.value || "left"; @@ -184,6 +192,12 @@ export function BaseTextBlock(props: BlockProps & { className?: string }) { center: "text-center", justify: "text-justify", }[alignment]; + let textStyle = + textSize?.data.value === "small" + ? "text-sm text-secondary" + : textSize?.data.value === "large" + ? "text-lg text-primary" + : "text-base text-primary"; let editorState = useEditorStates( (s) => s.editorStates[props.entityID], @@ -258,7 +272,7 @@ export function BaseTextBlock(props: BlockProps & { className?: string }) { grow resize-none align-top whitespace-pre-wrap bg-transparent outline-hidden - ${props.type === "heading" ? HeadingStyle[headingLevel?.data.value || 1] : ""} + ${props.type === "heading" ? HeadingStyle[headingLevel?.data.value || 1] : textStyle} ${props.className}`} ref={mountRef} /> @@ -277,7 +291,7 @@ export function BaseTextBlock(props: BlockProps & { className?: string }) { // if this is the only block on the page and is empty or is a canvas, show placeholder
{props.type === "text" @@ -496,7 +510,7 @@ const useMentionState = (entityID: string) => { // Find the relative positioned parent container const editorEl = view.dom; - const container = editorEl.closest('.relative') as HTMLElement | null; + const container = editorEl.closest(".relative") as HTMLElement | null; if (container) { const containerRect = container.getBoundingClientRect(); diff --git a/components/Blocks/TextBlock/keymap.ts b/components/Blocks/TextBlock/keymap.ts index 861adf2f..1012c137 100644 --- a/components/Blocks/TextBlock/keymap.ts +++ b/components/Blocks/TextBlock/keymap.ts @@ -555,6 +555,20 @@ const enter = }, }); } + let [textSize] = + (await repRef.current?.query((tx) => + scanIndex(tx).eav(propsRef.current.entityID, "block/text-size"), + )) || []; + if (textSize) { + await repRef.current?.mutate.assertFact({ + entity: newEntityID, + attribute: "block/text-size", + data: { + type: "text-size-union", + value: textSize.data.value, + }, + }); + } }; asyncRun().then(() => { useUIState.getState().setSelectedBlock({ diff --git a/components/Blocks/TextBlock/useHandlePaste.ts b/components/Blocks/TextBlock/useHandlePaste.ts index 4ad4d5d3..1e50bc5d 100644 --- a/components/Blocks/TextBlock/useHandlePaste.ts +++ b/components/Blocks/TextBlock/useHandlePaste.ts @@ -299,6 +299,17 @@ const createBlockFromHTML = ( }, }); } + let textSize = child.getAttribute("data-text-size"); + if (textSize && ["default", "small", "large"].includes(textSize)) { + rep.mutate.assertFact({ + entity: entityID, + attribute: "block/text-size", + data: { + type: "text-size-union", + value: textSize as "default" | "small" | "large", + }, + }); + } if (child.tagName === "A") { let href = child.getAttribute("href"); let dataType = child.getAttribute("data-type"); diff --git a/components/SelectionManager/index.tsx b/components/SelectionManager/index.tsx index 5fd8253e..c822ac0a 100644 --- a/components/SelectionManager/index.tsx +++ b/components/SelectionManager/index.tsx @@ -87,6 +87,154 @@ export function SelectionManager() { } }, }, + { + metaKey: true, + altKey: true, + key: ["1", "¡"], + handler: async () => { + let [sortedBlocks] = await getSortedSelectionBound(); + for (let block of sortedBlocks) { + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/heading-level", + data: { type: "number", value: 1 }, + }); + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/type", + data: { type: "block-type-union", value: "heading" }, + }); + } + }, + }, + { + metaKey: true, + altKey: true, + key: ["2", "™"], + handler: async () => { + let [sortedBlocks] = await getSortedSelectionBound(); + for (let block of sortedBlocks) { + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/heading-level", + data: { type: "number", value: 2 }, + }); + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/type", + data: { type: "block-type-union", value: "heading" }, + }); + } + }, + }, + { + metaKey: true, + altKey: true, + key: ["3", "£"], + handler: async () => { + let [sortedBlocks] = await getSortedSelectionBound(); + for (let block of sortedBlocks) { + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/heading-level", + data: { type: "number", value: 3 }, + }); + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/type", + data: { type: "block-type-union", value: "heading" }, + }); + } + }, + }, + { + metaKey: true, + altKey: true, + key: ["0", "º"], + handler: async () => { + let [sortedBlocks] = await getSortedSelectionBound(); + for (let block of sortedBlocks) { + // Convert to text block + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/type", + data: { type: "block-type-union", value: "text" }, + }); + // Remove heading level if exists + let headingLevel = await rep?.query((tx) => + scanIndex(tx).eav(block.value, "block/heading-level"), + ); + if (headingLevel?.[0]) { + await rep?.mutate.retractFact({ factID: headingLevel[0].id }); + } + // Remove text-size to make it default + let textSizeFact = await rep?.query((tx) => + scanIndex(tx).eav(block.value, "block/text-size"), + ); + if (textSizeFact?.[0]) { + await rep?.mutate.retractFact({ factID: textSizeFact[0].id }); + } + } + }, + }, + { + metaKey: true, + altKey: true, + key: ["+", "≠"], + handler: async () => { + let [sortedBlocks] = await getSortedSelectionBound(); + for (let block of sortedBlocks) { + // Convert to text block + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/type", + data: { type: "block-type-union", value: "text" }, + }); + // Remove heading level if exists + let headingLevel = await rep?.query((tx) => + scanIndex(tx).eav(block.value, "block/heading-level"), + ); + if (headingLevel?.[0]) { + await rep?.mutate.retractFact({ factID: headingLevel[0].id }); + } + // Set text size to large + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/text-size", + data: { type: "text-size-union", value: "large" }, + }); + } + }, + }, + { + metaKey: true, + altKey: true, + key: ["-", "–"], + handler: async () => { + let [sortedBlocks] = await getSortedSelectionBound(); + for (let block of sortedBlocks) { + // Convert to text block + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/type", + data: { type: "block-type-union", value: "text" }, + }); + // Remove heading level if exists + let headingLevel = await rep?.query((tx) => + scanIndex(tx).eav(block.value, "block/heading-level"), + ); + if (headingLevel?.[0]) { + await rep?.mutate.retractFact({ factID: headingLevel[0].id }); + } + // Set text size to small + await rep?.mutate.assertFact({ + entity: block.value, + attribute: "block/text-size", + data: { type: "text-size-union", value: "small" }, + }); + } + }, + }, { metaKey: true, shift: true, @@ -685,7 +833,6 @@ function getContentEditableParent(e: Node | null): Node | null { return null; } - function toggleMarkInBlocks(blocks: string[], mark: MarkType, attrs?: any) { let everyBlockHasMark = blocks.reduce((acc, block) => { let editor = useEditorStates.getState().editorStates[block]; diff --git a/components/Toolbar/BlockToolbar.tsx b/components/Toolbar/BlockToolbar.tsx index cec79ce4..fb97e302 100644 --- a/components/Toolbar/BlockToolbar.tsx +++ b/components/Toolbar/BlockToolbar.tsx @@ -5,7 +5,11 @@ import { metaKey } from "src/utils/metaKey"; import { useUIState } from "src/useUIState"; import { LockBlockButton } from "./LockBlockButton"; import { TextAlignmentButton } from "./TextAlignmentToolbar"; -import { ImageFullBleedButton, ImageAltTextButton, ImageCoverButton } from "./ImageToolbar"; +import { + ImageFullBleedButton, + ImageAltTextButton, + ImageCoverButton, +} from "./ImageToolbar"; import { DeleteSmall } from "components/Icons/DeleteSmall"; import { getSortedSelection } from "components/SelectionManager/selectionState"; @@ -37,7 +41,7 @@ export const BlockToolbar = (props: { > - + {blockType === "image" && ( <> @@ -46,7 +50,7 @@ export const BlockToolbar = (props: { {focusedEntityType?.data.value !== "canvas" && ( - + )} )} @@ -54,7 +58,7 @@ export const BlockToolbar = (props: { <> {focusedEntityType?.data.value !== "canvas" && ( - + )} )} @@ -175,7 +179,7 @@ const MoveBlockButtons = () => { > - + ); }; diff --git a/components/Toolbar/HighlightToolbar.tsx b/components/Toolbar/HighlightToolbar.tsx index e232c1ea..d96a342a 100644 --- a/components/Toolbar/HighlightToolbar.tsx +++ b/components/Toolbar/HighlightToolbar.tsx @@ -126,7 +126,7 @@ export const HighlightToolbar = (props: { setLastUsedHightlight={props.setLastUsedHighlight} /> - +
diff --git a/components/Toolbar/InlineLinkToolbar.tsx b/components/Toolbar/InlineLinkToolbar.tsx index 408b332f..6dd51c07 100644 --- a/components/Toolbar/InlineLinkToolbar.tsx +++ b/components/Toolbar/InlineLinkToolbar.tsx @@ -132,7 +132,7 @@ export function InlineLinkToolbar(props: { onClose: () => void }) { return (
- + void }) => { > - +
Add a Checkbox
- start line with [ + [ ]
diff --git a/components/Toolbar/TextBlockTypeToolbar.tsx b/components/Toolbar/TextBlockTypeToolbar.tsx index 2a872264..8883f56a 100644 --- a/components/Toolbar/TextBlockTypeToolbar.tsx +++ b/components/Toolbar/TextBlockTypeToolbar.tsx @@ -4,7 +4,7 @@ import { Header3Small, } from "components/Icons/BlockTextSmall"; import { Props } from "components/Icons/Props"; -import { ShortcutKey } from "components/Layout"; +import { ShortcutKey, Separator } from "components/Layout"; import { ToolbarButton } from "components/Toolbar"; import { TextSelection } from "prosemirror-state"; import { useCallback } from "react"; @@ -22,6 +22,8 @@ export const TextBlockTypeToolbar = (props: { focusedBlock?.entityID || null, "block/heading-level", ); + + let textSize = useEntity(focusedBlock?.entityID || null, "block/text-size"); let { rep } = useReplicache(); let setLevel = useCallback( @@ -51,106 +53,163 @@ export const TextBlockTypeToolbar = (props: { ); return ( // This Toolbar should close once the user starts typing again -
-
- { - setLevel(1); - }} - active={ - blockType?.data.value === "heading" && - headingLevel?.data.value === 1 - } - tooltipContent={ -
-
Title
-
- start line with - # -
+ <> + { + setLevel(1); + }} + active={ + blockType?.data.value === "heading" && headingLevel?.data.value === 1 + } + tooltipContent={ +
+
Title
+
+ start line with + #
- } - > - - - { - setLevel(2); - }} - active={ - blockType?.data.value === "heading" && - headingLevel?.data.value === 2 - } - tooltipContent={ -
-
Heading
-
- start line with - ## -
+
+ } + > + +
+ { + setLevel(2); + }} + active={ + blockType?.data.value === "heading" && headingLevel?.data.value === 2 + } + tooltipContent={ +
+
Heading
+
+ start line with + ##
- } - > - - - { - setLevel(3); - }} - active={ - blockType?.data.value === "heading" && - headingLevel?.data.value === 3 - } - tooltipContent={ -
-
Subheading
-
- start line with - ### -
+
+ } + > + +
+ { + setLevel(3); + }} + active={ + blockType?.data.value === "heading" && headingLevel?.data.value === 3 + } + tooltipContent={ +
+
Subheading
+
+ start line with + ###
+
+ } + > + +
+ + { + if (headingLevel) + await rep?.mutate.retractFact({ factID: headingLevel.id }); + if (textSize) await rep?.mutate.retractFact({ factID: textSize.id }); + if (!focusedBlock || !blockType) return; + if (blockType.data.value !== "text") { + let existingEditor = + useEditorStates.getState().editorStates[focusedBlock.entityID]; + let selection = existingEditor?.editor.selection; + await rep?.mutate.assertFact({ + entity: focusedBlock?.entityID, + attribute: "block/type", + data: { type: "block-type-union", value: "text" }, + }); + + let newEditor = + useEditorStates.getState().editorStates[focusedBlock.entityID]; + if (!newEditor || !selection) return; + newEditor.view?.dispatch( + newEditor.editor.tr.setSelection( + TextSelection.create(newEditor.editor.doc, selection.anchor), + ), + ); + + newEditor.view?.focus(); } - > - - - { + }} + active={ + blockType?.data.value === "text" && + textSize?.data.value !== "small" && + textSize?.data.value !== "large" + } + tooltipContent={
Normal Text
} + > + Text +
+ { + if (!focusedBlock || !blockType) return; + if (blockType.data.value !== "text") { + // Convert to text block first if it's a heading if (headingLevel) await rep?.mutate.retractFact({ factID: headingLevel.id }); - if (!focusedBlock || !blockType) return; - if (blockType.data.value !== "text") { - let existingEditor = - useEditorStates.getState().editorStates[focusedBlock.entityID]; - let selection = existingEditor?.editor.selection; - await rep?.mutate.assertFact({ - entity: focusedBlock?.entityID, - attribute: "block/type", - data: { type: "block-type-union", value: "text" }, - }); - - let newEditor = - useEditorStates.getState().editorStates[focusedBlock.entityID]; - if (!newEditor || !selection) return; - newEditor.view?.dispatch( - newEditor.editor.tr.setSelection( - TextSelection.create(newEditor.editor.doc, selection.anchor), - ), - ); - - newEditor.view?.focus(); - } - }} - active={blockType?.data.value === "text"} - tooltipContent={
Paragraph
} - > - Paragraph -
-
-
+ await rep?.mutate.assertFact({ + entity: focusedBlock.entityID, + attribute: "block/type", + data: { type: "block-type-union", value: "text" }, + }); + } + // Set text size to large + await rep?.mutate.assertFact({ + entity: focusedBlock.entityID, + attribute: "block/text-size", + data: { type: "text-size-union", value: "large" }, + }); + }} + active={ + blockType?.data.value === "text" && textSize?.data.value === "large" + } + tooltipContent={
Large Text
} + > +
Large
+
+ { + if (!focusedBlock || !blockType) return; + if (blockType.data.value !== "text") { + // Convert to text block first if it's a heading + if (headingLevel) + await rep?.mutate.retractFact({ factID: headingLevel.id }); + await rep?.mutate.assertFact({ + entity: focusedBlock.entityID, + attribute: "block/type", + data: { type: "block-type-union", value: "text" }, + }); + } + // Set text size to small + await rep?.mutate.assertFact({ + entity: focusedBlock.entityID, + attribute: "block/text-size", + data: { type: "text-size-union", value: "small" }, + }); + }} + active={ + blockType?.data.value === "text" && textSize?.data.value === "small" + } + tooltipContent={
Small Text
} + > +
Small
+
+ ); }; diff --git a/components/Toolbar/TextToolbar.tsx b/components/Toolbar/TextToolbar.tsx index c75de328..fb663732 100644 --- a/components/Toolbar/TextToolbar.tsx +++ b/components/Toolbar/TextToolbar.tsx @@ -74,13 +74,13 @@ export const TextToolbar = (props: { lastUsedHighlight={props.lastUsedHighlight} setToolbarState={props.setToolbarState} /> - + - + - + diff --git a/components/utils/DotLoader.tsx b/components/utils/DotLoader.tsx index 233ff399..67571f22 100644 --- a/components/utils/DotLoader.tsx +++ b/components/utils/DotLoader.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react"; -export function DotLoader() { +export function DotLoader(props: { className?: string }) { let [dots, setDots] = useState(1); useEffect(() => { let id = setInterval(() => { @@ -11,7 +11,7 @@ export function DotLoader() { }; }, []); return ( -
+
{".".repeat(dots) + "\u00a0".repeat(3 - dots)}
); diff --git a/lexicons/api/lexicons.ts b/lexicons/api/lexicons.ts index 036492da..e4dd9245 100644 --- a/lexicons/api/lexicons.ts +++ b/lexicons/api/lexicons.ts @@ -6,63 +6,63 @@ import { Lexicons, ValidationError, type ValidationResult, -} from "@atproto/lexicon"; -import { type $Typed, is$typed, maybe$typed } from "./util"; +} from '@atproto/lexicon' +import { type $Typed, is$typed, maybe$typed } from './util' export const schemaDict = { AppBskyActorProfile: { lexicon: 1, - id: "app.bsky.actor.profile", + id: 'app.bsky.actor.profile', defs: { main: { - type: "record", - description: "A declaration of a Bluesky account profile.", - key: "literal:self", + type: 'record', + description: 'A declaration of a Bluesky account profile.', + key: 'literal:self', record: { - type: "object", + type: 'object', properties: { displayName: { - type: "string", + type: 'string', maxGraphemes: 64, maxLength: 640, }, description: { - type: "string", - description: "Free-form profile description text.", + type: 'string', + description: 'Free-form profile description text.', maxGraphemes: 256, maxLength: 2560, }, avatar: { - type: "blob", + type: 'blob', description: "Small image to be displayed next to posts from account. AKA, 'profile picture'", - accept: ["image/png", "image/jpeg"], + accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, banner: { - type: "blob", + type: 'blob', description: - "Larger horizontal image to display behind profile view.", - accept: ["image/png", "image/jpeg"], + 'Larger horizontal image to display behind profile view.', + accept: ['image/png', 'image/jpeg'], maxSize: 1000000, }, labels: { - type: "union", + type: 'union', description: - "Self-label values, specific to the Bluesky application, on the overall account.", - refs: ["lex:com.atproto.label.defs#selfLabels"], + 'Self-label values, specific to the Bluesky application, on the overall account.', + refs: ['lex:com.atproto.label.defs#selfLabels'], }, joinedViaStarterPack: { - type: "ref", - ref: "lex:com.atproto.repo.strongRef", + type: 'ref', + ref: 'lex:com.atproto.repo.strongRef', }, pinnedPost: { - type: "ref", - ref: "lex:com.atproto.repo.strongRef", + type: 'ref', + ref: 'lex:com.atproto.repo.strongRef', }, createdAt: { - type: "string", - format: "datetime", + type: 'string', + format: 'datetime', }, }, }, @@ -71,247 +71,247 @@ export const schemaDict = { }, ComAtprotoLabelDefs: { lexicon: 1, - id: "com.atproto.label.defs", + id: 'com.atproto.label.defs', defs: { label: { - type: "object", + type: 'object', description: - "Metadata tag on an atproto resource (eg, repo or record).", - required: ["src", "uri", "val", "cts"], + 'Metadata tag on an atproto resource (eg, repo or record).', + required: ['src', 'uri', 'val', 'cts'], properties: { ver: { - type: "integer", - description: "The AT Protocol version of the label object.", + type: 'integer', + description: 'The AT Protocol version of the label object.', }, src: { - type: "string", - format: "did", - description: "DID of the actor who created this label.", + type: 'string', + format: 'did', + description: 'DID of the actor who created this label.', }, uri: { - type: "string", - format: "uri", + type: 'string', + format: 'uri', description: - "AT URI of the record, repository (account), or other resource that this label applies to.", + 'AT URI of the record, repository (account), or other resource that this label applies to.', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', description: "Optionally, CID specifying the specific version of 'uri' resource this label applies to.", }, val: { - type: "string", + type: 'string', maxLength: 128, description: - "The short string name of the value or type of this label.", + 'The short string name of the value or type of this label.', }, neg: { - type: "boolean", + type: 'boolean', description: - "If true, this is a negation label, overwriting a previous label.", + 'If true, this is a negation label, overwriting a previous label.', }, cts: { - type: "string", - format: "datetime", - description: "Timestamp when this label was created.", + type: 'string', + format: 'datetime', + description: 'Timestamp when this label was created.', }, exp: { - type: "string", - format: "datetime", + type: 'string', + format: 'datetime', description: - "Timestamp at which this label expires (no longer applies).", + 'Timestamp at which this label expires (no longer applies).', }, sig: { - type: "bytes", - description: "Signature of dag-cbor encoded label.", + type: 'bytes', + description: 'Signature of dag-cbor encoded label.', }, }, }, selfLabels: { - type: "object", + type: 'object', description: - "Metadata tags on an atproto record, published by the author within the record.", - required: ["values"], + 'Metadata tags on an atproto record, published by the author within the record.', + required: ['values'], properties: { values: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:com.atproto.label.defs#selfLabel", + type: 'ref', + ref: 'lex:com.atproto.label.defs#selfLabel', }, maxLength: 10, }, }, }, selfLabel: { - type: "object", + type: 'object', description: - "Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel.", - required: ["val"], + 'Metadata tag on an atproto record, published by the author within the record. Note that schemas should use #selfLabels, not #selfLabel.', + required: ['val'], properties: { val: { - type: "string", + type: 'string', maxLength: 128, description: - "The short string name of the value or type of this label.", + 'The short string name of the value or type of this label.', }, }, }, labelValueDefinition: { - type: "object", + type: 'object', description: - "Declares a label value and its expected interpretations and behaviors.", - required: ["identifier", "severity", "blurs", "locales"], + 'Declares a label value and its expected interpretations and behaviors.', + required: ['identifier', 'severity', 'blurs', 'locales'], properties: { identifier: { - type: "string", + type: 'string', description: "The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+).", maxLength: 100, maxGraphemes: 100, }, severity: { - type: "string", + type: 'string', description: "How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing.", - knownValues: ["inform", "alert", "none"], + knownValues: ['inform', 'alert', 'none'], }, blurs: { - type: "string", + type: 'string', description: "What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing.", - knownValues: ["content", "media", "none"], + knownValues: ['content', 'media', 'none'], }, defaultSetting: { - type: "string", - description: "The default setting for this label.", - knownValues: ["ignore", "warn", "hide"], - default: "warn", + type: 'string', + description: 'The default setting for this label.', + knownValues: ['ignore', 'warn', 'hide'], + default: 'warn', }, adultOnly: { - type: "boolean", + type: 'boolean', description: - "Does the user need to have adult content enabled in order to configure this label?", + 'Does the user need to have adult content enabled in order to configure this label?', }, locales: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:com.atproto.label.defs#labelValueDefinitionStrings", + type: 'ref', + ref: 'lex:com.atproto.label.defs#labelValueDefinitionStrings', }, }, }, }, labelValueDefinitionStrings: { - type: "object", + type: 'object', description: - "Strings which describe the label in the UI, localized into a specific language.", - required: ["lang", "name", "description"], + 'Strings which describe the label in the UI, localized into a specific language.', + required: ['lang', 'name', 'description'], properties: { lang: { - type: "string", + type: 'string', description: - "The code of the language these strings are written in.", - format: "language", + 'The code of the language these strings are written in.', + format: 'language', }, name: { - type: "string", - description: "A short human-readable name for the label.", + type: 'string', + description: 'A short human-readable name for the label.', maxGraphemes: 64, maxLength: 640, }, description: { - type: "string", + type: 'string', description: - "A longer description of what the label means and why it might be applied.", + 'A longer description of what the label means and why it might be applied.', maxGraphemes: 10000, maxLength: 100000, }, }, }, labelValue: { - type: "string", + type: 'string', knownValues: [ - "!hide", - "!no-promote", - "!warn", - "!no-unauthenticated", - "dmca-violation", - "doxxing", - "porn", - "sexual", - "nudity", - "nsfl", - "gore", + '!hide', + '!no-promote', + '!warn', + '!no-unauthenticated', + 'dmca-violation', + 'doxxing', + 'porn', + 'sexual', + 'nudity', + 'nsfl', + 'gore', ], }, }, }, ComAtprotoRepoApplyWrites: { lexicon: 1, - id: "com.atproto.repo.applyWrites", + id: 'com.atproto.repo.applyWrites', defs: { main: { - type: "procedure", + type: 'procedure', description: - "Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.", + 'Apply a batch transaction of repository creates, updates, and deletes. Requires auth, implemented by PDS.', input: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["repo", "writes"], + type: 'object', + required: ['repo', 'writes'], properties: { repo: { - type: "string", - format: "at-identifier", + type: 'string', + format: 'at-identifier', description: - "The handle or DID of the repo (aka, current account).", + 'The handle or DID of the repo (aka, current account).', }, validate: { - type: "boolean", + type: 'boolean', description: "Can be set to 'false' to skip Lexicon schema validation of record data across all operations, 'true' to require it, or leave unset to validate only for known Lexicons.", }, writes: { - type: "array", + type: 'array', items: { - type: "union", + type: 'union', refs: [ - "lex:com.atproto.repo.applyWrites#create", - "lex:com.atproto.repo.applyWrites#update", - "lex:com.atproto.repo.applyWrites#delete", + 'lex:com.atproto.repo.applyWrites#create', + 'lex:com.atproto.repo.applyWrites#update', + 'lex:com.atproto.repo.applyWrites#delete', ], closed: true, }, }, swapCommit: { - type: "string", + type: 'string', description: - "If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.", - format: "cid", + 'If provided, the entire operation will fail if the current repo commit CID does not match this value. Used to prevent conflicting repo mutations.', + format: 'cid', }, }, }, }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", + type: 'object', required: [], properties: { commit: { - type: "ref", - ref: "lex:com.atproto.repo.defs#commitMeta", + type: 'ref', + ref: 'lex:com.atproto.repo.defs#commitMeta', }, results: { - type: "array", + type: 'array', items: { - type: "union", + type: 'union', refs: [ - "lex:com.atproto.repo.applyWrites#createResult", - "lex:com.atproto.repo.applyWrites#updateResult", - "lex:com.atproto.repo.applyWrites#deleteResult", + 'lex:com.atproto.repo.applyWrites#createResult', + 'lex:com.atproto.repo.applyWrites#updateResult', + 'lex:com.atproto.repo.applyWrites#deleteResult', ], closed: true, }, @@ -321,104 +321,104 @@ export const schemaDict = { }, errors: [ { - name: "InvalidSwap", + name: 'InvalidSwap', description: "Indicates that the 'swapCommit' parameter did not match current commit.", }, ], }, create: { - type: "object", - description: "Operation which creates a new record.", - required: ["collection", "value"], + type: 'object', + description: 'Operation which creates a new record.', + required: ['collection', 'value'], properties: { collection: { - type: "string", - format: "nsid", + type: 'string', + format: 'nsid', }, rkey: { - type: "string", + type: 'string', maxLength: 512, - format: "record-key", + format: 'record-key', description: - "NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility.", + 'NOTE: maxLength is redundant with record-key format. Keeping it temporarily to ensure backwards compatibility.', }, value: { - type: "unknown", + type: 'unknown', }, }, }, update: { - type: "object", - description: "Operation which updates an existing record.", - required: ["collection", "rkey", "value"], + type: 'object', + description: 'Operation which updates an existing record.', + required: ['collection', 'rkey', 'value'], properties: { collection: { - type: "string", - format: "nsid", + type: 'string', + format: 'nsid', }, rkey: { - type: "string", - format: "record-key", + type: 'string', + format: 'record-key', }, value: { - type: "unknown", + type: 'unknown', }, }, }, delete: { - type: "object", - description: "Operation which deletes an existing record.", - required: ["collection", "rkey"], + type: 'object', + description: 'Operation which deletes an existing record.', + required: ['collection', 'rkey'], properties: { collection: { - type: "string", - format: "nsid", + type: 'string', + format: 'nsid', }, rkey: { - type: "string", - format: "record-key", + type: 'string', + format: 'record-key', }, }, }, createResult: { - type: "object", - required: ["uri", "cid"], + type: 'object', + required: ['uri', 'cid'], properties: { uri: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, validationStatus: { - type: "string", - knownValues: ["valid", "unknown"], + type: 'string', + knownValues: ['valid', 'unknown'], }, }, }, updateResult: { - type: "object", - required: ["uri", "cid"], + type: 'object', + required: ['uri', 'cid'], properties: { uri: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, validationStatus: { - type: "string", - knownValues: ["valid", "unknown"], + type: 'string', + knownValues: ['valid', 'unknown'], }, }, }, deleteResult: { - type: "object", + type: 'object', required: [], properties: {}, }, @@ -426,81 +426,81 @@ export const schemaDict = { }, ComAtprotoRepoCreateRecord: { lexicon: 1, - id: "com.atproto.repo.createRecord", + id: 'com.atproto.repo.createRecord', defs: { main: { - type: "procedure", + type: 'procedure', description: - "Create a single new repository record. Requires auth, implemented by PDS.", + 'Create a single new repository record. Requires auth, implemented by PDS.', input: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["repo", "collection", "record"], + type: 'object', + required: ['repo', 'collection', 'record'], properties: { repo: { - type: "string", - format: "at-identifier", + type: 'string', + format: 'at-identifier', description: - "The handle or DID of the repo (aka, current account).", + 'The handle or DID of the repo (aka, current account).', }, collection: { - type: "string", - format: "nsid", - description: "The NSID of the record collection.", + type: 'string', + format: 'nsid', + description: 'The NSID of the record collection.', }, rkey: { - type: "string", - format: "record-key", - description: "The Record Key.", + type: 'string', + format: 'record-key', + description: 'The Record Key.', maxLength: 512, }, validate: { - type: "boolean", + type: 'boolean', description: "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons.", }, record: { - type: "unknown", - description: "The record itself. Must contain a $type field.", + type: 'unknown', + description: 'The record itself. Must contain a $type field.', }, swapCommit: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', description: - "Compare and swap with the previous commit by CID.", + 'Compare and swap with the previous commit by CID.', }, }, }, }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["uri", "cid"], + type: 'object', + required: ['uri', 'cid'], properties: { uri: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, commit: { - type: "ref", - ref: "lex:com.atproto.repo.defs#commitMeta", + type: 'ref', + ref: 'lex:com.atproto.repo.defs#commitMeta', }, validationStatus: { - type: "string", - knownValues: ["valid", "unknown"], + type: 'string', + knownValues: ['valid', 'unknown'], }, }, }, }, errors: [ { - name: "InvalidSwap", + name: 'InvalidSwap', description: "Indicates that 'swapCommit' didn't match current repo commit.", }, @@ -510,19 +510,19 @@ export const schemaDict = { }, ComAtprotoRepoDefs: { lexicon: 1, - id: "com.atproto.repo.defs", + id: 'com.atproto.repo.defs', defs: { commitMeta: { - type: "object", - required: ["cid", "rev"], + type: 'object', + required: ['cid', 'rev'], properties: { cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, rev: { - type: "string", - format: "tid", + type: 'string', + format: 'tid', }, }, }, @@ -530,64 +530,64 @@ export const schemaDict = { }, ComAtprotoRepoDeleteRecord: { lexicon: 1, - id: "com.atproto.repo.deleteRecord", + id: 'com.atproto.repo.deleteRecord', defs: { main: { - type: "procedure", + type: 'procedure', description: "Delete a repository record, or ensure it doesn't exist. Requires auth, implemented by PDS.", input: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["repo", "collection", "rkey"], + type: 'object', + required: ['repo', 'collection', 'rkey'], properties: { repo: { - type: "string", - format: "at-identifier", + type: 'string', + format: 'at-identifier', description: - "The handle or DID of the repo (aka, current account).", + 'The handle or DID of the repo (aka, current account).', }, collection: { - type: "string", - format: "nsid", - description: "The NSID of the record collection.", + type: 'string', + format: 'nsid', + description: 'The NSID of the record collection.', }, rkey: { - type: "string", - format: "record-key", - description: "The Record Key.", + type: 'string', + format: 'record-key', + description: 'The Record Key.', }, swapRecord: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', description: - "Compare and swap with the previous record by CID.", + 'Compare and swap with the previous record by CID.', }, swapCommit: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', description: - "Compare and swap with the previous commit by CID.", + 'Compare and swap with the previous commit by CID.', }, }, }, }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", + type: 'object', properties: { commit: { - type: "ref", - ref: "lex:com.atproto.repo.defs#commitMeta", + type: 'ref', + ref: 'lex:com.atproto.repo.defs#commitMeta', }, }, }, }, errors: [ { - name: "InvalidSwap", + name: 'InvalidSwap', }, ], }, @@ -595,60 +595,60 @@ export const schemaDict = { }, ComAtprotoRepoDescribeRepo: { lexicon: 1, - id: "com.atproto.repo.describeRepo", + id: 'com.atproto.repo.describeRepo', defs: { main: { - type: "query", + type: 'query', description: - "Get information about an account and repository, including the list of collections. Does not require auth.", + 'Get information about an account and repository, including the list of collections. Does not require auth.', parameters: { - type: "params", - required: ["repo"], + type: 'params', + required: ['repo'], properties: { repo: { - type: "string", - format: "at-identifier", - description: "The handle or DID of the repo.", + type: 'string', + format: 'at-identifier', + description: 'The handle or DID of the repo.', }, }, }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", + type: 'object', required: [ - "handle", - "did", - "didDoc", - "collections", - "handleIsCorrect", + 'handle', + 'did', + 'didDoc', + 'collections', + 'handleIsCorrect', ], properties: { handle: { - type: "string", - format: "handle", + type: 'string', + format: 'handle', }, did: { - type: "string", - format: "did", + type: 'string', + format: 'did', }, didDoc: { - type: "unknown", - description: "The complete DID document for this account.", + type: 'unknown', + description: 'The complete DID document for this account.', }, collections: { - type: "array", + type: 'array', description: - "List of all the collections (NSIDs) for which this repo contains at least one record.", + 'List of all the collections (NSIDs) for which this repo contains at least one record.', items: { - type: "string", - format: "nsid", + type: 'string', + format: 'nsid', }, }, handleIsCorrect: { - type: "boolean", + type: 'boolean', description: - "Indicates if handle is currently valid (resolves bi-directionally)", + 'Indicates if handle is currently valid (resolves bi-directionally)', }, }, }, @@ -658,62 +658,62 @@ export const schemaDict = { }, ComAtprotoRepoGetRecord: { lexicon: 1, - id: "com.atproto.repo.getRecord", + id: 'com.atproto.repo.getRecord', defs: { main: { - type: "query", + type: 'query', description: - "Get a single record from a repository. Does not require auth.", + 'Get a single record from a repository. Does not require auth.', parameters: { - type: "params", - required: ["repo", "collection", "rkey"], + type: 'params', + required: ['repo', 'collection', 'rkey'], properties: { repo: { - type: "string", - format: "at-identifier", - description: "The handle or DID of the repo.", + type: 'string', + format: 'at-identifier', + description: 'The handle or DID of the repo.', }, collection: { - type: "string", - format: "nsid", - description: "The NSID of the record collection.", + type: 'string', + format: 'nsid', + description: 'The NSID of the record collection.', }, rkey: { - type: "string", - description: "The Record Key.", - format: "record-key", + type: 'string', + description: 'The Record Key.', + format: 'record-key', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', description: - "The CID of the version of the record. If not specified, then return the most recent version.", + 'The CID of the version of the record. If not specified, then return the most recent version.', }, }, }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["uri", "value"], + type: 'object', + required: ['uri', 'value'], properties: { uri: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, value: { - type: "unknown", + type: 'unknown', }, }, }, }, errors: [ { - name: "RecordNotFound", + name: 'RecordNotFound', }, ], }, @@ -721,54 +721,54 @@ export const schemaDict = { }, ComAtprotoRepoImportRepo: { lexicon: 1, - id: "com.atproto.repo.importRepo", + id: 'com.atproto.repo.importRepo', defs: { main: { - type: "procedure", + type: 'procedure', description: - "Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.", + 'Import a repo in the form of a CAR file. Requires Content-Length HTTP header to be set.', input: { - encoding: "application/vnd.ipld.car", + encoding: 'application/vnd.ipld.car', }, }, }, }, ComAtprotoRepoListMissingBlobs: { lexicon: 1, - id: "com.atproto.repo.listMissingBlobs", + id: 'com.atproto.repo.listMissingBlobs', defs: { main: { - type: "query", + type: 'query', description: - "Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.", + 'Returns a list of missing blobs for the requesting account. Intended to be used in the account migration flow.', parameters: { - type: "params", + type: 'params', properties: { limit: { - type: "integer", + type: 'integer', minimum: 1, maximum: 1000, default: 500, }, cursor: { - type: "string", + type: 'string', }, }, }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["blobs"], + type: 'object', + required: ['blobs'], properties: { cursor: { - type: "string", + type: 'string', }, blobs: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:com.atproto.repo.listMissingBlobs#recordBlob", + type: 'ref', + ref: 'lex:com.atproto.repo.listMissingBlobs#recordBlob', }, }, }, @@ -776,16 +776,16 @@ export const schemaDict = { }, }, recordBlob: { - type: "object", - required: ["cid", "recordUri"], + type: 'object', + required: ['cid', 'recordUri'], properties: { cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, recordUri: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, }, }, @@ -793,66 +793,66 @@ export const schemaDict = { }, ComAtprotoRepoListRecords: { lexicon: 1, - id: "com.atproto.repo.listRecords", + id: 'com.atproto.repo.listRecords', defs: { main: { - type: "query", + type: 'query', description: - "List a range of records in a repository, matching a specific collection. Does not require auth.", + 'List a range of records in a repository, matching a specific collection. Does not require auth.', parameters: { - type: "params", - required: ["repo", "collection"], + type: 'params', + required: ['repo', 'collection'], properties: { repo: { - type: "string", - format: "at-identifier", - description: "The handle or DID of the repo.", + type: 'string', + format: 'at-identifier', + description: 'The handle or DID of the repo.', }, collection: { - type: "string", - format: "nsid", - description: "The NSID of the record type.", + type: 'string', + format: 'nsid', + description: 'The NSID of the record type.', }, limit: { - type: "integer", + type: 'integer', minimum: 1, maximum: 100, default: 50, - description: "The number of records to return.", + description: 'The number of records to return.', }, cursor: { - type: "string", + type: 'string', }, rkeyStart: { - type: "string", + type: 'string', description: - "DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)", + 'DEPRECATED: The lowest sort-ordered rkey to start from (exclusive)', }, rkeyEnd: { - type: "string", + type: 'string', description: - "DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)", + 'DEPRECATED: The highest sort-ordered rkey to stop at (exclusive)', }, reverse: { - type: "boolean", - description: "Flag to reverse the order of the returned records.", + type: 'boolean', + description: 'Flag to reverse the order of the returned records.', }, }, }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["records"], + type: 'object', + required: ['records'], properties: { cursor: { - type: "string", + type: 'string', }, records: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:com.atproto.repo.listRecords#record", + type: 'ref', + ref: 'lex:com.atproto.repo.listRecords#record', }, }, }, @@ -860,19 +860,19 @@ export const schemaDict = { }, }, record: { - type: "object", - required: ["uri", "cid", "value"], + type: 'object', + required: ['uri', 'cid', 'value'], properties: { uri: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, value: { - type: "unknown", + type: 'unknown', }, }, }, @@ -880,88 +880,88 @@ export const schemaDict = { }, ComAtprotoRepoPutRecord: { lexicon: 1, - id: "com.atproto.repo.putRecord", + id: 'com.atproto.repo.putRecord', defs: { main: { - type: "procedure", + type: 'procedure', description: - "Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.", + 'Write a repository record, creating or updating it as needed. Requires auth, implemented by PDS.', input: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["repo", "collection", "rkey", "record"], - nullable: ["swapRecord"], + type: 'object', + required: ['repo', 'collection', 'rkey', 'record'], + nullable: ['swapRecord'], properties: { repo: { - type: "string", - format: "at-identifier", + type: 'string', + format: 'at-identifier', description: - "The handle or DID of the repo (aka, current account).", + 'The handle or DID of the repo (aka, current account).', }, collection: { - type: "string", - format: "nsid", - description: "The NSID of the record collection.", + type: 'string', + format: 'nsid', + description: 'The NSID of the record collection.', }, rkey: { - type: "string", - format: "record-key", - description: "The Record Key.", + type: 'string', + format: 'record-key', + description: 'The Record Key.', maxLength: 512, }, validate: { - type: "boolean", + type: 'boolean', description: "Can be set to 'false' to skip Lexicon schema validation of record data, 'true' to require it, or leave unset to validate only for known Lexicons.", }, record: { - type: "unknown", - description: "The record to write.", + type: 'unknown', + description: 'The record to write.', }, swapRecord: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', description: - "Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation", + 'Compare and swap with the previous record by CID. WARNING: nullable and optional field; may cause problems with golang implementation', }, swapCommit: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', description: - "Compare and swap with the previous commit by CID.", + 'Compare and swap with the previous commit by CID.', }, }, }, }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["uri", "cid"], + type: 'object', + required: ['uri', 'cid'], properties: { uri: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, commit: { - type: "ref", - ref: "lex:com.atproto.repo.defs#commitMeta", + type: 'ref', + ref: 'lex:com.atproto.repo.defs#commitMeta', }, validationStatus: { - type: "string", - knownValues: ["valid", "unknown"], + type: 'string', + knownValues: ['valid', 'unknown'], }, }, }, }, errors: [ { - name: "InvalidSwap", + name: 'InvalidSwap', }, ], }, @@ -969,20 +969,20 @@ export const schemaDict = { }, ComAtprotoRepoStrongRef: { lexicon: 1, - id: "com.atproto.repo.strongRef", - description: "A URI with a content-hash fingerprint.", + id: 'com.atproto.repo.strongRef', + description: 'A URI with a content-hash fingerprint.', defs: { main: { - type: "object", - required: ["uri", "cid"], + type: 'object', + required: ['uri', 'cid'], properties: { uri: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, cid: { - type: "string", - format: "cid", + type: 'string', + format: 'cid', }, }, }, @@ -990,23 +990,23 @@ export const schemaDict = { }, ComAtprotoRepoUploadBlob: { lexicon: 1, - id: "com.atproto.repo.uploadBlob", + id: 'com.atproto.repo.uploadBlob', defs: { main: { - type: "procedure", + type: 'procedure', description: - "Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.", + 'Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.', input: { - encoding: "*/*", + encoding: '*/*', }, output: { - encoding: "application/json", + encoding: 'application/json', schema: { - type: "object", - required: ["blob"], + type: 'object', + required: ['blob'], properties: { blob: { - type: "blob", + type: 'blob', }, }, }, @@ -1016,20 +1016,20 @@ export const schemaDict = { }, PubLeafletBlocksBlockquote: { lexicon: 1, - id: "pub.leaflet.blocks.blockquote", + id: 'pub.leaflet.blocks.blockquote', defs: { main: { - type: "object", - required: ["plaintext"], + type: 'object', + required: ['plaintext'], properties: { plaintext: { - type: "string", + type: 'string', }, facets: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.richtext.facet", + type: 'ref', + ref: 'lex:pub.leaflet.richtext.facet', }, }, }, @@ -1038,15 +1038,15 @@ export const schemaDict = { }, PubLeafletBlocksBskyPost: { lexicon: 1, - id: "pub.leaflet.blocks.bskyPost", + id: 'pub.leaflet.blocks.bskyPost', defs: { main: { - type: "object", - required: ["postRef"], + type: 'object', + required: ['postRef'], properties: { postRef: { - type: "ref", - ref: "lex:com.atproto.repo.strongRef", + type: 'ref', + ref: 'lex:com.atproto.repo.strongRef', }, }, }, @@ -1054,18 +1054,18 @@ export const schemaDict = { }, PubLeafletBlocksButton: { lexicon: 1, - id: "pub.leaflet.blocks.button", + id: 'pub.leaflet.blocks.button', defs: { main: { - type: "object", - required: ["text", "url"], + type: 'object', + required: ['text', 'url'], properties: { text: { - type: "string", + type: 'string', }, url: { - type: "string", - format: "uri", + type: 'string', + format: 'uri', }, }, }, @@ -1073,20 +1073,20 @@ export const schemaDict = { }, PubLeafletBlocksCode: { lexicon: 1, - id: "pub.leaflet.blocks.code", + id: 'pub.leaflet.blocks.code', defs: { main: { - type: "object", - required: ["plaintext"], + type: 'object', + required: ['plaintext'], properties: { plaintext: { - type: "string", + type: 'string', }, language: { - type: "string", + type: 'string', }, syntaxHighlightingTheme: { - type: "string", + type: 'string', }, }, }, @@ -1094,25 +1094,25 @@ export const schemaDict = { }, PubLeafletBlocksHeader: { lexicon: 1, - id: "pub.leaflet.blocks.header", + id: 'pub.leaflet.blocks.header', defs: { main: { - type: "object", - required: ["plaintext"], + type: 'object', + required: ['plaintext'], properties: { level: { - type: "integer", + type: 'integer', minimum: 1, maximum: 6, }, plaintext: { - type: "string", + type: 'string', }, facets: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.richtext.facet", + type: 'ref', + ref: 'lex:pub.leaflet.richtext.facet', }, }, }, @@ -1121,10 +1121,10 @@ export const schemaDict = { }, PubLeafletBlocksHorizontalRule: { lexicon: 1, - id: "pub.leaflet.blocks.horizontalRule", + id: 'pub.leaflet.blocks.horizontalRule', defs: { main: { - type: "object", + type: 'object', required: [], properties: {}, }, @@ -1132,18 +1132,18 @@ export const schemaDict = { }, PubLeafletBlocksIframe: { lexicon: 1, - id: "pub.leaflet.blocks.iframe", + id: 'pub.leaflet.blocks.iframe', defs: { main: { - type: "object", - required: ["url"], + type: 'object', + required: ['url'], properties: { url: { - type: "string", - format: "uri", + type: 'string', + format: 'uri', }, height: { - type: "integer", + type: 'integer', minimum: 16, maximum: 1600, }, @@ -1153,37 +1153,37 @@ export const schemaDict = { }, PubLeafletBlocksImage: { lexicon: 1, - id: "pub.leaflet.blocks.image", + id: 'pub.leaflet.blocks.image', defs: { main: { - type: "object", - required: ["image", "aspectRatio"], + type: 'object', + required: ['image', 'aspectRatio'], properties: { image: { - type: "blob", - accept: ["image/*"], + type: 'blob', + accept: ['image/*'], maxSize: 1000000, }, alt: { - type: "string", + type: 'string', description: - "Alt text description of the image, for accessibility.", + 'Alt text description of the image, for accessibility.', }, aspectRatio: { - type: "ref", - ref: "lex:pub.leaflet.blocks.image#aspectRatio", + type: 'ref', + ref: 'lex:pub.leaflet.blocks.image#aspectRatio', }, }, }, aspectRatio: { - type: "object", - required: ["width", "height"], + type: 'object', + required: ['width', 'height'], properties: { width: { - type: "integer", + type: 'integer', }, height: { - type: "integer", + type: 'integer', }, }, }, @@ -1191,14 +1191,14 @@ export const schemaDict = { }, PubLeafletBlocksMath: { lexicon: 1, - id: "pub.leaflet.blocks.math", + id: 'pub.leaflet.blocks.math', defs: { main: { - type: "object", - required: ["tex"], + type: 'object', + required: ['tex'], properties: { tex: { - type: "string", + type: 'string', }, }, }, @@ -1206,14 +1206,14 @@ export const schemaDict = { }, PubLeafletBlocksPage: { lexicon: 1, - id: "pub.leaflet.blocks.page", + id: 'pub.leaflet.blocks.page', defs: { main: { - type: "object", - required: ["id"], + type: 'object', + required: ['id'], properties: { id: { - type: "string", + type: 'string', }, }, }, @@ -1221,15 +1221,15 @@ export const schemaDict = { }, PubLeafletBlocksPoll: { lexicon: 1, - id: "pub.leaflet.blocks.poll", + id: 'pub.leaflet.blocks.poll', defs: { main: { - type: "object", - required: ["pollRef"], + type: 'object', + required: ['pollRef'], properties: { pollRef: { - type: "ref", - ref: "lex:com.atproto.repo.strongRef", + type: 'ref', + ref: 'lex:com.atproto.repo.strongRef', }, }, }, @@ -1237,20 +1237,24 @@ export const schemaDict = { }, PubLeafletBlocksText: { lexicon: 1, - id: "pub.leaflet.blocks.text", + id: 'pub.leaflet.blocks.text', defs: { main: { - type: "object", - required: ["plaintext"], + type: 'object', + required: ['plaintext'], properties: { plaintext: { - type: "string", + type: 'string', + }, + textSize: { + type: 'string', + enum: ['default', 'small', 'large'], }, facets: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.richtext.facet", + type: 'ref', + ref: 'lex:pub.leaflet.richtext.facet', }, }, }, @@ -1259,38 +1263,38 @@ export const schemaDict = { }, PubLeafletBlocksUnorderedList: { lexicon: 1, - id: "pub.leaflet.blocks.unorderedList", + id: 'pub.leaflet.blocks.unorderedList', defs: { main: { - type: "object", - required: ["children"], + type: 'object', + required: ['children'], properties: { children: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.blocks.unorderedList#listItem", + type: 'ref', + ref: 'lex:pub.leaflet.blocks.unorderedList#listItem', }, }, }, }, listItem: { - type: "object", - required: ["content"], + type: 'object', + required: ['content'], properties: { content: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.blocks.text", - "lex:pub.leaflet.blocks.header", - "lex:pub.leaflet.blocks.image", + 'lex:pub.leaflet.blocks.text', + 'lex:pub.leaflet.blocks.header', + 'lex:pub.leaflet.blocks.image', ], }, children: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.blocks.unorderedList#listItem", + type: 'ref', + ref: 'lex:pub.leaflet.blocks.unorderedList#listItem', }, }, }, @@ -1299,26 +1303,26 @@ export const schemaDict = { }, PubLeafletBlocksWebsite: { lexicon: 1, - id: "pub.leaflet.blocks.website", + id: 'pub.leaflet.blocks.website', defs: { main: { - type: "object", - required: ["src"], + type: 'object', + required: ['src'], properties: { previewImage: { - type: "blob", - accept: ["image/*"], + type: 'blob', + accept: ['image/*'], maxSize: 1000000, }, title: { - type: "string", + type: 'string', }, description: { - type: "string", + type: 'string', }, src: { - type: "string", - format: "uri", + type: 'string', + format: 'uri', }, }, }, @@ -1326,71 +1330,71 @@ export const schemaDict = { }, PubLeafletComment: { lexicon: 1, - id: "pub.leaflet.comment", + id: 'pub.leaflet.comment', revision: 1, - description: "A lexicon for comments on documents", + description: 'A lexicon for comments on documents', defs: { main: { - type: "record", - key: "tid", - description: "Record containing a comment", + type: 'record', + key: 'tid', + description: 'Record containing a comment', record: { - type: "object", - required: ["subject", "plaintext", "createdAt"], + type: 'object', + required: ['subject', 'plaintext', 'createdAt'], properties: { subject: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, createdAt: { - type: "string", - format: "datetime", + type: 'string', + format: 'datetime', }, reply: { - type: "ref", - ref: "lex:pub.leaflet.comment#replyRef", + type: 'ref', + ref: 'lex:pub.leaflet.comment#replyRef', }, plaintext: { - type: "string", + type: 'string', }, facets: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.richtext.facet", + type: 'ref', + ref: 'lex:pub.leaflet.richtext.facet', }, }, onPage: { - type: "string", + type: 'string', }, attachment: { - type: "union", - refs: ["lex:pub.leaflet.comment#linearDocumentQuote"], + type: 'union', + refs: ['lex:pub.leaflet.comment#linearDocumentQuote'], }, }, }, }, linearDocumentQuote: { - type: "object", - required: ["document", "quote"], + type: 'object', + required: ['document', 'quote'], properties: { document: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, quote: { - type: "ref", - ref: "lex:pub.leaflet.pages.linearDocument#quote", + type: 'ref', + ref: 'lex:pub.leaflet.pages.linearDocument#quote', }, }, }, replyRef: { - type: "object", - required: ["parent"], + type: 'object', + required: ['parent'], properties: { parent: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, }, }, @@ -1398,67 +1402,67 @@ export const schemaDict = { }, PubLeafletDocument: { lexicon: 1, - id: "pub.leaflet.document", + id: 'pub.leaflet.document', revision: 1, - description: "A lexicon for long form rich media documents", + description: 'A lexicon for long form rich media documents', defs: { main: { - type: "record", - key: "tid", - description: "Record containing a document", + type: 'record', + key: 'tid', + description: 'Record containing a document', record: { - type: "object", - required: ["pages", "author", "title"], + type: 'object', + required: ['pages', 'author', 'title'], properties: { title: { - type: "string", + type: 'string', maxLength: 1280, maxGraphemes: 128, }, postRef: { - type: "ref", - ref: "lex:com.atproto.repo.strongRef", + type: 'ref', + ref: 'lex:com.atproto.repo.strongRef', }, description: { - type: "string", + type: 'string', maxLength: 3000, maxGraphemes: 300, }, publishedAt: { - type: "string", - format: "datetime", + type: 'string', + format: 'datetime', }, publication: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, author: { - type: "string", - format: "at-identifier", + type: 'string', + format: 'at-identifier', }, theme: { - type: "ref", - ref: "lex:pub.leaflet.publication#theme", + type: 'ref', + ref: 'lex:pub.leaflet.publication#theme', }, tags: { - type: "array", + type: 'array', items: { - type: "string", + type: 'string', maxLength: 50, }, }, coverImage: { - type: "blob", - accept: ["image/png", "image/jpeg", "image/webp"], + type: 'blob', + accept: ['image/png', 'image/jpeg', 'image/webp'], maxSize: 1000000, }, pages: { - type: "array", + type: 'array', items: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.pages.linearDocument", - "lex:pub.leaflet.pages.canvas", + 'lex:pub.leaflet.pages.linearDocument', + 'lex:pub.leaflet.pages.canvas', ], }, }, @@ -1469,19 +1473,19 @@ export const schemaDict = { }, PubLeafletGraphSubscription: { lexicon: 1, - id: "pub.leaflet.graph.subscription", + id: 'pub.leaflet.graph.subscription', defs: { main: { - type: "record", - key: "tid", - description: "Record declaring a subscription to a publication", + type: 'record', + key: 'tid', + description: 'Record declaring a subscription to a publication', record: { - type: "object", - required: ["publication"], + type: 'object', + required: ['publication'], properties: { publication: { - type: "string", - format: "at-uri", + type: 'string', + format: 'at-uri', }, }, }, @@ -1490,100 +1494,100 @@ export const schemaDict = { }, PubLeafletPagesCanvas: { lexicon: 1, - id: "pub.leaflet.pages.canvas", + id: 'pub.leaflet.pages.canvas', defs: { main: { - type: "object", - required: ["blocks"], + type: 'object', + required: ['blocks'], properties: { id: { - type: "string", + type: 'string', }, blocks: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.pages.canvas#block", + type: 'ref', + ref: 'lex:pub.leaflet.pages.canvas#block', }, }, }, }, block: { - type: "object", - required: ["block", "x", "y", "width"], + type: 'object', + required: ['block', 'x', 'y', 'width'], properties: { block: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.blocks.iframe", - "lex:pub.leaflet.blocks.text", - "lex:pub.leaflet.blocks.blockquote", - "lex:pub.leaflet.blocks.header", - "lex:pub.leaflet.blocks.image", - "lex:pub.leaflet.blocks.unorderedList", - "lex:pub.leaflet.blocks.website", - "lex:pub.leaflet.blocks.math", - "lex:pub.leaflet.blocks.code", - "lex:pub.leaflet.blocks.horizontalRule", - "lex:pub.leaflet.blocks.bskyPost", - "lex:pub.leaflet.blocks.page", - "lex:pub.leaflet.blocks.poll", - "lex:pub.leaflet.blocks.button", + 'lex:pub.leaflet.blocks.iframe', + 'lex:pub.leaflet.blocks.text', + 'lex:pub.leaflet.blocks.blockquote', + 'lex:pub.leaflet.blocks.header', + 'lex:pub.leaflet.blocks.image', + 'lex:pub.leaflet.blocks.unorderedList', + 'lex:pub.leaflet.blocks.website', + 'lex:pub.leaflet.blocks.math', + 'lex:pub.leaflet.blocks.code', + 'lex:pub.leaflet.blocks.horizontalRule', + 'lex:pub.leaflet.blocks.bskyPost', + 'lex:pub.leaflet.blocks.page', + 'lex:pub.leaflet.blocks.poll', + 'lex:pub.leaflet.blocks.button', ], }, x: { - type: "integer", + type: 'integer', }, y: { - type: "integer", + type: 'integer', }, width: { - type: "integer", + type: 'integer', }, height: { - type: "integer", + type: 'integer', }, rotation: { - type: "integer", - description: "The rotation of the block in degrees", + type: 'integer', + description: 'The rotation of the block in degrees', }, }, }, textAlignLeft: { - type: "token", + type: 'token', }, textAlignCenter: { - type: "token", + type: 'token', }, textAlignRight: { - type: "token", + type: 'token', }, quote: { - type: "object", - required: ["start", "end"], + type: 'object', + required: ['start', 'end'], properties: { start: { - type: "ref", - ref: "lex:pub.leaflet.pages.canvas#position", + type: 'ref', + ref: 'lex:pub.leaflet.pages.canvas#position', }, end: { - type: "ref", - ref: "lex:pub.leaflet.pages.canvas#position", + type: 'ref', + ref: 'lex:pub.leaflet.pages.canvas#position', }, }, }, position: { - type: "object", - required: ["block", "offset"], + type: 'object', + required: ['block', 'offset'], properties: { block: { - type: "array", + type: 'array', items: { - type: "integer", + type: 'integer', }, }, offset: { - type: "integer", + type: 'integer', }, }, }, @@ -1591,96 +1595,96 @@ export const schemaDict = { }, PubLeafletPagesLinearDocument: { lexicon: 1, - id: "pub.leaflet.pages.linearDocument", + id: 'pub.leaflet.pages.linearDocument', defs: { main: { - type: "object", - required: ["blocks"], + type: 'object', + required: ['blocks'], properties: { id: { - type: "string", + type: 'string', }, blocks: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.pages.linearDocument#block", + type: 'ref', + ref: 'lex:pub.leaflet.pages.linearDocument#block', }, }, }, }, block: { - type: "object", - required: ["block"], + type: 'object', + required: ['block'], properties: { block: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.blocks.iframe", - "lex:pub.leaflet.blocks.text", - "lex:pub.leaflet.blocks.blockquote", - "lex:pub.leaflet.blocks.header", - "lex:pub.leaflet.blocks.image", - "lex:pub.leaflet.blocks.unorderedList", - "lex:pub.leaflet.blocks.website", - "lex:pub.leaflet.blocks.math", - "lex:pub.leaflet.blocks.code", - "lex:pub.leaflet.blocks.horizontalRule", - "lex:pub.leaflet.blocks.bskyPost", - "lex:pub.leaflet.blocks.page", - "lex:pub.leaflet.blocks.poll", - "lex:pub.leaflet.blocks.button", + 'lex:pub.leaflet.blocks.iframe', + 'lex:pub.leaflet.blocks.text', + 'lex:pub.leaflet.blocks.blockquote', + 'lex:pub.leaflet.blocks.header', + 'lex:pub.leaflet.blocks.image', + 'lex:pub.leaflet.blocks.unorderedList', + 'lex:pub.leaflet.blocks.website', + 'lex:pub.leaflet.blocks.math', + 'lex:pub.leaflet.blocks.code', + 'lex:pub.leaflet.blocks.horizontalRule', + 'lex:pub.leaflet.blocks.bskyPost', + 'lex:pub.leaflet.blocks.page', + 'lex:pub.leaflet.blocks.poll', + 'lex:pub.leaflet.blocks.button', ], }, alignment: { - type: "string", + type: 'string', knownValues: [ - "lex:pub.leaflet.pages.linearDocument#textAlignLeft", - "lex:pub.leaflet.pages.linearDocument#textAlignCenter", - "lex:pub.leaflet.pages.linearDocument#textAlignRight", - "lex:pub.leaflet.pages.linearDocument#textAlignJustify", + 'lex:pub.leaflet.pages.linearDocument#textAlignLeft', + 'lex:pub.leaflet.pages.linearDocument#textAlignCenter', + 'lex:pub.leaflet.pages.linearDocument#textAlignRight', + 'lex:pub.leaflet.pages.linearDocument#textAlignJustify', ], }, }, }, textAlignLeft: { - type: "token", + type: 'token', }, textAlignCenter: { - type: "token", + type: 'token', }, textAlignRight: { - type: "token", + type: 'token', }, textAlignJustify: { - type: "token", + type: 'token', }, quote: { - type: "object", - required: ["start", "end"], + type: 'object', + required: ['start', 'end'], properties: { start: { - type: "ref", - ref: "lex:pub.leaflet.pages.linearDocument#position", + type: 'ref', + ref: 'lex:pub.leaflet.pages.linearDocument#position', }, end: { - type: "ref", - ref: "lex:pub.leaflet.pages.linearDocument#position", + type: 'ref', + ref: 'lex:pub.leaflet.pages.linearDocument#position', }, }, }, position: { - type: "object", - required: ["block", "offset"], + type: 'object', + required: ['block', 'offset'], properties: { block: { - type: "array", + type: 'array', items: { - type: "integer", + type: 'integer', }, }, offset: { - type: "integer", + type: 'integer', }, }, }, @@ -1688,40 +1692,40 @@ export const schemaDict = { }, PubLeafletPollDefinition: { lexicon: 1, - id: "pub.leaflet.poll.definition", + id: 'pub.leaflet.poll.definition', defs: { main: { - type: "record", - key: "tid", - description: "Record declaring a poll", + type: 'record', + key: 'tid', + description: 'Record declaring a poll', record: { - type: "object", - required: ["name", "options"], + type: 'object', + required: ['name', 'options'], properties: { name: { - type: "string", + type: 'string', maxLength: 500, maxGraphemes: 100, }, options: { - type: "array", + type: 'array', items: { - type: "ref", - ref: "lex:pub.leaflet.poll.definition#option", + type: 'ref', + ref: 'lex:pub.leaflet.poll.definition#option', }, }, endDate: { - type: "string", - format: "datetime", + type: 'string', + format: 'datetime', }, }, }, }, option: { - type: "object", + type: 'object', properties: { text: { - type: "string", + type: 'string', maxLength: 500, maxGraphemes: 50, }, @@ -1731,24 +1735,24 @@ export const schemaDict = { }, PubLeafletPollVote: { lexicon: 1, - id: "pub.leaflet.poll.vote", + id: 'pub.leaflet.poll.vote', defs: { main: { - type: "record", - key: "tid", - description: "Record declaring a vote on a poll", + type: 'record', + key: 'tid', + description: 'Record declaring a vote on a poll', record: { - type: "object", - required: ["poll", "option"], + type: 'object', + required: ['poll', 'option'], properties: { poll: { - type: "ref", - ref: "lex:com.atproto.repo.strongRef", + type: 'ref', + ref: 'lex:com.atproto.repo.strongRef', }, option: { - type: "array", + type: 'array', items: { - type: "string", + type: 'string', }, }, }, @@ -1758,105 +1762,105 @@ export const schemaDict = { }, PubLeafletPublication: { lexicon: 1, - id: "pub.leaflet.publication", + id: 'pub.leaflet.publication', defs: { main: { - type: "record", - key: "tid", - description: "Record declaring a publication", + type: 'record', + key: 'tid', + description: 'Record declaring a publication', record: { - type: "object", - required: ["name"], + type: 'object', + required: ['name'], properties: { name: { - type: "string", + type: 'string', maxLength: 2000, }, base_path: { - type: "string", + type: 'string', }, description: { - type: "string", + type: 'string', maxLength: 2000, }, icon: { - type: "blob", - accept: ["image/*"], + type: 'blob', + accept: ['image/*'], maxSize: 1000000, }, theme: { - type: "ref", - ref: "lex:pub.leaflet.publication#theme", + type: 'ref', + ref: 'lex:pub.leaflet.publication#theme', }, preferences: { - type: "ref", - ref: "lex:pub.leaflet.publication#preferences", + type: 'ref', + ref: 'lex:pub.leaflet.publication#preferences', }, }, }, }, preferences: { - type: "object", + type: 'object', properties: { showInDiscover: { - type: "boolean", + type: 'boolean', default: true, }, showComments: { - type: "boolean", + type: 'boolean', default: true, }, }, }, theme: { - type: "object", + type: 'object', properties: { backgroundColor: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.theme.color#rgba", - "lex:pub.leaflet.theme.color#rgb", + 'lex:pub.leaflet.theme.color#rgba', + 'lex:pub.leaflet.theme.color#rgb', ], }, backgroundImage: { - type: "ref", - ref: "lex:pub.leaflet.theme.backgroundImage", + type: 'ref', + ref: 'lex:pub.leaflet.theme.backgroundImage', }, pageWidth: { - type: "integer", - minimum: 320, - maximum: 1200, + type: 'integer', + minimum: 0, + maximum: 1600, }, primary: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.theme.color#rgba", - "lex:pub.leaflet.theme.color#rgb", + 'lex:pub.leaflet.theme.color#rgba', + 'lex:pub.leaflet.theme.color#rgb', ], }, pageBackground: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.theme.color#rgba", - "lex:pub.leaflet.theme.color#rgb", + 'lex:pub.leaflet.theme.color#rgba', + 'lex:pub.leaflet.theme.color#rgb', ], }, showPageBackground: { - type: "boolean", + type: 'boolean', default: false, }, accentBackground: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.theme.color#rgba", - "lex:pub.leaflet.theme.color#rgb", + 'lex:pub.leaflet.theme.color#rgba', + 'lex:pub.leaflet.theme.color#rgb', ], }, accentText: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.theme.color#rgba", - "lex:pub.leaflet.theme.color#rgb", + 'lex:pub.leaflet.theme.color#rgba', + 'lex:pub.leaflet.theme.color#rgb', ], }, }, @@ -1865,130 +1869,130 @@ export const schemaDict = { }, PubLeafletRichtextFacet: { lexicon: 1, - id: "pub.leaflet.richtext.facet", + id: 'pub.leaflet.richtext.facet', defs: { main: { - type: "object", - description: "Annotation of a sub-string within rich text.", - required: ["index", "features"], + type: 'object', + description: 'Annotation of a sub-string within rich text.', + required: ['index', 'features'], properties: { index: { - type: "ref", - ref: "lex:pub.leaflet.richtext.facet#byteSlice", + type: 'ref', + ref: 'lex:pub.leaflet.richtext.facet#byteSlice', }, features: { - type: "array", + type: 'array', items: { - type: "union", + type: 'union', refs: [ - "lex:pub.leaflet.richtext.facet#link", - "lex:pub.leaflet.richtext.facet#didMention", - "lex:pub.leaflet.richtext.facet#atMention", - "lex:pub.leaflet.richtext.facet#code", - "lex:pub.leaflet.richtext.facet#highlight", - "lex:pub.leaflet.richtext.facet#underline", - "lex:pub.leaflet.richtext.facet#strikethrough", - "lex:pub.leaflet.richtext.facet#id", - "lex:pub.leaflet.richtext.facet#bold", - "lex:pub.leaflet.richtext.facet#italic", + 'lex:pub.leaflet.richtext.facet#link', + 'lex:pub.leaflet.richtext.facet#didMention', + 'lex:pub.leaflet.richtext.facet#atMention', + 'lex:pub.leaflet.richtext.facet#code', + 'lex:pub.leaflet.richtext.facet#highlight', + 'lex:pub.leaflet.richtext.facet#underline', + 'lex:pub.leaflet.richtext.facet#strikethrough', + 'lex:pub.leaflet.richtext.facet#id', + 'lex:pub.leaflet.richtext.facet#bold', + 'lex:pub.leaflet.richtext.facet#italic', ], }, }, }, }, byteSlice: { - type: "object", + type: 'object', description: - "Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets.", - required: ["byteStart", "byteEnd"], + 'Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets.', + required: ['byteStart', 'byteEnd'], properties: { byteStart: { - type: "integer", + type: 'integer', minimum: 0, }, byteEnd: { - type: "integer", + type: 'integer', minimum: 0, }, }, }, link: { - type: "object", + type: 'object', description: - "Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.", - required: ["uri"], + 'Facet feature for a URL. The text URL may have been simplified or truncated, but the facet reference should be a complete URL.', + required: ['uri'], properties: { uri: { - type: "string", + type: 'string', }, }, }, didMention: { - type: "object", - description: "Facet feature for mentioning a did.", - required: ["did"], + type: 'object', + description: 'Facet feature for mentioning a did.', + required: ['did'], properties: { did: { - type: "string", - format: "did", + type: 'string', + format: 'did', }, }, }, atMention: { - type: "object", - description: "Facet feature for mentioning an AT URI.", - required: ["atURI"], + type: 'object', + description: 'Facet feature for mentioning an AT URI.', + required: ['atURI'], properties: { atURI: { - type: "string", - format: "uri", + type: 'string', + format: 'uri', }, }, }, code: { - type: "object", - description: "Facet feature for inline code.", + type: 'object', + description: 'Facet feature for inline code.', required: [], properties: {}, }, highlight: { - type: "object", - description: "Facet feature for highlighted text.", + type: 'object', + description: 'Facet feature for highlighted text.', required: [], properties: {}, }, underline: { - type: "object", - description: "Facet feature for underline markup", + type: 'object', + description: 'Facet feature for underline markup', required: [], properties: {}, }, strikethrough: { - type: "object", - description: "Facet feature for strikethrough markup", + type: 'object', + description: 'Facet feature for strikethrough markup', required: [], properties: {}, }, id: { - type: "object", + type: 'object', description: - "Facet feature for an identifier. Used for linking to a segment", + 'Facet feature for an identifier. Used for linking to a segment', required: [], properties: { id: { - type: "string", + type: 'string', }, }, }, bold: { - type: "object", - description: "Facet feature for bold text", + type: 'object', + description: 'Facet feature for bold text', required: [], properties: {}, }, italic: { - type: "object", - description: "Facet feature for italic text", + type: 'object', + description: 'Facet feature for italic text', required: [], properties: {}, }, @@ -1996,22 +2000,22 @@ export const schemaDict = { }, PubLeafletThemeBackgroundImage: { lexicon: 1, - id: "pub.leaflet.theme.backgroundImage", + id: 'pub.leaflet.theme.backgroundImage', defs: { main: { - type: "object", - required: ["image"], + type: 'object', + required: ['image'], properties: { image: { - type: "blob", - accept: ["image/*"], + type: 'blob', + accept: ['image/*'], maxSize: 1000000, }, width: { - type: "integer", + type: 'integer', }, repeat: { - type: "boolean", + type: 'boolean', }, }, }, @@ -2019,50 +2023,50 @@ export const schemaDict = { }, PubLeafletThemeColor: { lexicon: 1, - id: "pub.leaflet.theme.color", + id: 'pub.leaflet.theme.color', defs: { rgba: { - type: "object", - required: ["r", "g", "b", "a"], + type: 'object', + required: ['r', 'g', 'b', 'a'], properties: { r: { - type: "integer", + type: 'integer', maximum: 255, minimum: 0, }, g: { - type: "integer", + type: 'integer', maximum: 255, minimum: 0, }, b: { - type: "integer", + type: 'integer', maximum: 255, minimum: 0, }, a: { - type: "integer", + type: 'integer', maximum: 100, minimum: 0, }, }, }, rgb: { - type: "object", - required: ["r", "g", "b"], + type: 'object', + required: ['r', 'g', 'b'], properties: { r: { - type: "integer", + type: 'integer', maximum: 255, minimum: 0, }, g: { - type: "integer", + type: 'integer', maximum: 255, minimum: 0, }, b: { - type: "integer", + type: 'integer', maximum: 255, minimum: 0, }, @@ -2070,22 +2074,22 @@ export const schemaDict = { }, }, }, -} as const satisfies Record; -export const schemas = Object.values(schemaDict) satisfies LexiconDoc[]; -export const lexicons: Lexicons = new Lexicons(schemas); +} as const satisfies Record +export const schemas = Object.values(schemaDict) satisfies LexiconDoc[] +export const lexicons: Lexicons = new Lexicons(schemas) export function validate( v: unknown, id: string, hash: string, requiredType: true, -): ValidationResult; +): ValidationResult export function validate( v: unknown, id: string, hash: string, requiredType?: false, -): ValidationResult; +): ValidationResult export function validate( v: unknown, id: string, @@ -2097,49 +2101,49 @@ export function validate( : { success: false, error: new ValidationError( - `Must be an object with "${hash === "main" ? id : `${id}#${hash}`}" $type property`, + `Must be an object with "${hash === 'main' ? id : `${id}#${hash}`}" $type property`, ), - }; + } } export const ids = { - AppBskyActorProfile: "app.bsky.actor.profile", - ComAtprotoLabelDefs: "com.atproto.label.defs", - ComAtprotoRepoApplyWrites: "com.atproto.repo.applyWrites", - ComAtprotoRepoCreateRecord: "com.atproto.repo.createRecord", - ComAtprotoRepoDefs: "com.atproto.repo.defs", - ComAtprotoRepoDeleteRecord: "com.atproto.repo.deleteRecord", - ComAtprotoRepoDescribeRepo: "com.atproto.repo.describeRepo", - ComAtprotoRepoGetRecord: "com.atproto.repo.getRecord", - ComAtprotoRepoImportRepo: "com.atproto.repo.importRepo", - ComAtprotoRepoListMissingBlobs: "com.atproto.repo.listMissingBlobs", - ComAtprotoRepoListRecords: "com.atproto.repo.listRecords", - ComAtprotoRepoPutRecord: "com.atproto.repo.putRecord", - ComAtprotoRepoStrongRef: "com.atproto.repo.strongRef", - ComAtprotoRepoUploadBlob: "com.atproto.repo.uploadBlob", - PubLeafletBlocksBlockquote: "pub.leaflet.blocks.blockquote", - PubLeafletBlocksBskyPost: "pub.leaflet.blocks.bskyPost", - PubLeafletBlocksButton: "pub.leaflet.blocks.button", - PubLeafletBlocksCode: "pub.leaflet.blocks.code", - PubLeafletBlocksHeader: "pub.leaflet.blocks.header", - PubLeafletBlocksHorizontalRule: "pub.leaflet.blocks.horizontalRule", - PubLeafletBlocksIframe: "pub.leaflet.blocks.iframe", - PubLeafletBlocksImage: "pub.leaflet.blocks.image", - PubLeafletBlocksMath: "pub.leaflet.blocks.math", - PubLeafletBlocksPage: "pub.leaflet.blocks.page", - PubLeafletBlocksPoll: "pub.leaflet.blocks.poll", - PubLeafletBlocksText: "pub.leaflet.blocks.text", - PubLeafletBlocksUnorderedList: "pub.leaflet.blocks.unorderedList", - PubLeafletBlocksWebsite: "pub.leaflet.blocks.website", - PubLeafletComment: "pub.leaflet.comment", - PubLeafletDocument: "pub.leaflet.document", - PubLeafletGraphSubscription: "pub.leaflet.graph.subscription", - PubLeafletPagesCanvas: "pub.leaflet.pages.canvas", - PubLeafletPagesLinearDocument: "pub.leaflet.pages.linearDocument", - PubLeafletPollDefinition: "pub.leaflet.poll.definition", - PubLeafletPollVote: "pub.leaflet.poll.vote", - PubLeafletPublication: "pub.leaflet.publication", - PubLeafletRichtextFacet: "pub.leaflet.richtext.facet", - PubLeafletThemeBackgroundImage: "pub.leaflet.theme.backgroundImage", - PubLeafletThemeColor: "pub.leaflet.theme.color", -} as const; + AppBskyActorProfile: 'app.bsky.actor.profile', + ComAtprotoLabelDefs: 'com.atproto.label.defs', + ComAtprotoRepoApplyWrites: 'com.atproto.repo.applyWrites', + ComAtprotoRepoCreateRecord: 'com.atproto.repo.createRecord', + ComAtprotoRepoDefs: 'com.atproto.repo.defs', + ComAtprotoRepoDeleteRecord: 'com.atproto.repo.deleteRecord', + ComAtprotoRepoDescribeRepo: 'com.atproto.repo.describeRepo', + ComAtprotoRepoGetRecord: 'com.atproto.repo.getRecord', + ComAtprotoRepoImportRepo: 'com.atproto.repo.importRepo', + ComAtprotoRepoListMissingBlobs: 'com.atproto.repo.listMissingBlobs', + ComAtprotoRepoListRecords: 'com.atproto.repo.listRecords', + ComAtprotoRepoPutRecord: 'com.atproto.repo.putRecord', + ComAtprotoRepoStrongRef: 'com.atproto.repo.strongRef', + ComAtprotoRepoUploadBlob: 'com.atproto.repo.uploadBlob', + PubLeafletBlocksBlockquote: 'pub.leaflet.blocks.blockquote', + PubLeafletBlocksBskyPost: 'pub.leaflet.blocks.bskyPost', + PubLeafletBlocksButton: 'pub.leaflet.blocks.button', + PubLeafletBlocksCode: 'pub.leaflet.blocks.code', + PubLeafletBlocksHeader: 'pub.leaflet.blocks.header', + PubLeafletBlocksHorizontalRule: 'pub.leaflet.blocks.horizontalRule', + PubLeafletBlocksIframe: 'pub.leaflet.blocks.iframe', + PubLeafletBlocksImage: 'pub.leaflet.blocks.image', + PubLeafletBlocksMath: 'pub.leaflet.blocks.math', + PubLeafletBlocksPage: 'pub.leaflet.blocks.page', + PubLeafletBlocksPoll: 'pub.leaflet.blocks.poll', + PubLeafletBlocksText: 'pub.leaflet.blocks.text', + PubLeafletBlocksUnorderedList: 'pub.leaflet.blocks.unorderedList', + PubLeafletBlocksWebsite: 'pub.leaflet.blocks.website', + PubLeafletComment: 'pub.leaflet.comment', + PubLeafletDocument: 'pub.leaflet.document', + PubLeafletGraphSubscription: 'pub.leaflet.graph.subscription', + PubLeafletPagesCanvas: 'pub.leaflet.pages.canvas', + PubLeafletPagesLinearDocument: 'pub.leaflet.pages.linearDocument', + PubLeafletPollDefinition: 'pub.leaflet.poll.definition', + PubLeafletPollVote: 'pub.leaflet.poll.vote', + PubLeafletPublication: 'pub.leaflet.publication', + PubLeafletRichtextFacet: 'pub.leaflet.richtext.facet', + PubLeafletThemeBackgroundImage: 'pub.leaflet.theme.backgroundImage', + PubLeafletThemeColor: 'pub.leaflet.theme.color', +} as const diff --git a/lexicons/api/types/pub/leaflet/blocks/text.ts b/lexicons/api/types/pub/leaflet/blocks/text.ts index 8b8c873b..f7117790 100644 --- a/lexicons/api/types/pub/leaflet/blocks/text.ts +++ b/lexicons/api/types/pub/leaflet/blocks/text.ts @@ -18,6 +18,7 @@ const id = 'pub.leaflet.blocks.text' export interface Main { $type?: 'pub.leaflet.blocks.text' plaintext: string + textSize?: 'default' | 'small' | 'large' facets?: PubLeafletRichtextFacet.Main[] } diff --git a/lexicons/api/types/pub/leaflet/publication.ts b/lexicons/api/types/pub/leaflet/publication.ts index 3cdaeaab..1a7e9abd 100644 --- a/lexicons/api/types/pub/leaflet/publication.ts +++ b/lexicons/api/types/pub/leaflet/publication.ts @@ -1,91 +1,87 @@ /** * GENERATED CODE - DO NOT MODIFY */ -import { type ValidationResult, BlobRef } from "@atproto/lexicon"; -import { CID } from "multiformats/cid"; -import { validate as _validate } from "../../../lexicons"; -import { - type $Typed, - is$typed as _is$typed, - type OmitKey, -} from "../../../util"; -import type * as PubLeafletThemeColor from "./theme/color"; -import type * as PubLeafletThemeBackgroundImage from "./theme/backgroundImage"; +import { type ValidationResult, BlobRef } from '@atproto/lexicon' +import { CID } from 'multiformats/cid' +import { validate as _validate } from '../../../lexicons' +import { type $Typed, is$typed as _is$typed, type OmitKey } from '../../../util' +import type * as PubLeafletThemeColor from './theme/color' +import type * as PubLeafletThemeBackgroundImage from './theme/backgroundImage' const is$typed = _is$typed, - validate = _validate; -const id = "pub.leaflet.publication"; + validate = _validate +const id = 'pub.leaflet.publication' export interface Record { - $type: "pub.leaflet.publication"; - name: string; - base_path?: string; - description?: string; - icon?: BlobRef; - theme?: Theme; - preferences?: Preferences; - [k: string]: unknown; + $type: 'pub.leaflet.publication' + name: string + base_path?: string + description?: string + icon?: BlobRef + theme?: Theme + preferences?: Preferences + [k: string]: unknown } -const hashRecord = "main"; +const hashRecord = 'main' export function isRecord(v: V) { - return is$typed(v, id, hashRecord); + return is$typed(v, id, hashRecord) } export function validateRecord(v: V) { - return validate(v, id, hashRecord, true); + return validate(v, id, hashRecord, true) } export interface Preferences { - $type?: "pub.leaflet.publication#preferences"; - showInDiscover: boolean; - showComments: boolean; + $type?: 'pub.leaflet.publication#preferences' + showInDiscover: boolean + showComments: boolean } -const hashPreferences = "preferences"; +const hashPreferences = 'preferences' export function isPreferences(v: V) { - return is$typed(v, id, hashPreferences); + return is$typed(v, id, hashPreferences) } export function validatePreferences(v: V) { - return validate(v, id, hashPreferences); + return validate(v, id, hashPreferences) } export interface Theme { - $type?: "pub.leaflet.publication#theme"; + $type?: 'pub.leaflet.publication#theme' backgroundColor?: | $Typed | $Typed - | { $type: string }; - backgroundImage?: PubLeafletThemeBackgroundImage.Main; - pageWidth?: number; + | { $type: string } + backgroundImage?: PubLeafletThemeBackgroundImage.Main + pageWidth?: number primary?: | $Typed | $Typed - | { $type: string }; + | { $type: string } pageBackground?: | $Typed | $Typed - | { $type: string }; - showPageBackground: boolean; + | { $type: string } + showPageBackground: boolean accentBackground?: | $Typed | $Typed - | { $type: string }; + | { $type: string } accentText?: | $Typed | $Typed - | { $type: string }; + | { $type: string } } -const hashTheme = "theme"; +const hashTheme = 'theme' export function isTheme(v: V) { - return is$typed(v, id, hashTheme); + return is$typed(v, id, hashTheme) } export function validateTheme(v: V) { - return validate(v, id, hashTheme); + return validate(v, id, hashTheme) } diff --git a/lexicons/pub/leaflet/blocks/text.json b/lexicons/pub/leaflet/blocks/text.json index 5cde4582..c860b1c1 100644 --- a/lexicons/pub/leaflet/blocks/text.json +++ b/lexicons/pub/leaflet/blocks/text.json @@ -11,6 +11,14 @@ "plaintext": { "type": "string" }, + "textSize": { + "type": "string", + "enum": [ + "default", + "small", + "large" + ] + }, "facets": { "type": "array", "items": { diff --git a/lexicons/pub/leaflet/publication.json b/lexicons/pub/leaflet/publication.json index 00a8857b..707854bd 100644 --- a/lexicons/pub/leaflet/publication.json +++ b/lexicons/pub/leaflet/publication.json @@ -8,7 +8,9 @@ "description": "Record declaring a publication", "record": { "type": "object", - "required": ["name"], + "required": [ + "name" + ], "properties": { "name": { "type": "string", @@ -23,7 +25,9 @@ }, "icon": { "type": "blob", - "accept": ["image/*"], + "accept": [ + "image/*" + ], "maxSize": 1000000 }, "theme": { @@ -104,4 +108,4 @@ } } } -} +} \ No newline at end of file diff --git a/lexicons/src/blocks.ts b/lexicons/src/blocks.ts index 06fccbe3..dd3ff4ec 100644 --- a/lexicons/src/blocks.ts +++ b/lexicons/src/blocks.ts @@ -10,6 +10,7 @@ export const PubLeafletBlocksText: LexiconDoc = { required: ["plaintext"], properties: { plaintext: { type: "string" }, + textSize: { type: "string", enum: ["default", "small", "large"] }, facets: { type: "array", items: { type: "ref", ref: PubLeafletRichTextFacet.id }, diff --git a/src/replicache/attributes.ts b/src/replicache/attributes.ts index c2d71974..4f00e8e9 100644 --- a/src/replicache/attributes.ts +++ b/src/replicache/attributes.ts @@ -71,6 +71,10 @@ const BlockAttributes = { type: "number", cardinality: "one", }, + "block/text-size": { + type: "text-size-union", + cardinality: "one", + }, "block/image": { type: "image", cardinality: "one", @@ -322,6 +326,10 @@ export type Data = { 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"; diff --git a/src/utils/getBlocksAsHTML.tsx b/src/utils/getBlocksAsHTML.tsx index 235735ba..98bf380a 100644 --- a/src/utils/getBlocksAsHTML.tsx +++ b/src/utils/getBlocksAsHTML.tsx @@ -171,11 +171,14 @@ const BlockTypeToHTML: { }, text: async (b, tx, a) => { let [value] = await scanIndex(tx).eav(b.value, "block/text"); + let [textSize] = await scanIndex(tx).eav(b.value, "block/text-size"); + return ( -- 2.51.2 From 8875a53da71744975ae1b42ae7d1202e91949fa5 Mon Sep 17 00:00:00 2001 From: Jared Pereira Date: Mon, 12 Jan 2026 17:21:16 -0500 Subject: [PATCH 3/3] handle publishing page width for standlone docs --- actions/publishToPublication.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/actions/publishToPublication.ts b/actions/publishToPublication.ts index beb1b8fb..4f7e8b38 100644 --- a/actions/publishToPublication.ts +++ b/actions/publishToPublication.ts @@ -784,11 +784,13 @@ async function extractThemeFromFacts( root_entity, "theme/background-image-repeat", )?.[0]; + let pageWidth = scan.eav(root_entity, "theme/page-width")?.[0]; let theme: PubLeafletPublication.Theme = { showPageBackground: showPageBackground ?? true, }; + if (pageWidth) theme.pageWidth = pageWidth.data.value; if (pageBackground) theme.backgroundColor = ColorToRGBA(parseColor(`hsba(${pageBackground})`)); if (cardBackground) -- 2.51.2