👁️
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

use union for primer

+124 -10
+2 -1
.claude/settings.local.json
··· 64 64 "Bash(npm run screenshot:wireframe:*)", 65 65 "Bash(curl:*)", 66 66 "Bash(npm run build:lexicons:*)", 67 - "Bash(npm run lexicons:lint:*)" 67 + "Bash(npm run lexicons:lint:*)", 68 + "Bash(npm run lexicons:all:*)" 68 69 ], 69 70 "deny": [], 70 71 "ask": []
+33 -2
lexicons/com/deckbelcher/deck/list.json
··· 21 21 "description": "Format of the deck (e.g., \"commander\", \"cube\", \"pauper\")." 22 22 }, 23 23 "primer": { 24 - "type": "ref", 25 - "ref": "com.deckbelcher.richtext#document", 24 + "type": "union", 25 + "refs": [ 26 + "com.deckbelcher.richtext#document", 27 + "#primerUri", 28 + "#primerRef" 29 + ], 26 30 "description": "Deck primer with strategy, combos, and card choices." 27 31 }, 28 32 "cards": { ··· 51 55 ] 52 56 }, 53 57 "description": "A Magic: The Gathering decklist." 58 + }, 59 + "primerUri": { 60 + "type": "object", 61 + "properties": { 62 + "uri": { 63 + "type": "string", 64 + "maxLength": 10000, 65 + "maxGraphemes": 1000 66 + } 67 + }, 68 + "description": "External primer content. Typically a URL, but any valid URI scheme.", 69 + "required": [ 70 + "uri" 71 + ] 72 + }, 73 + "primerRef": { 74 + "type": "object", 75 + "properties": { 76 + "ref": { 77 + "type": "ref", 78 + "ref": "com.atproto.repo.strongRef" 79 + } 80 + }, 81 + "description": "Primer in a separate ATProto record. For use with any longform writing lexicon.", 82 + "required": [ 83 + "ref" 84 + ] 54 85 }, 55 86 "card": { 56 87 "type": "object",
+1 -1
scripts/generate-oauth-scopes.ts
··· 36 36 metadata.scope = scope; 37 37 writeFileSync( 38 38 CLIENT_METADATA_PATH, 39 - JSON.stringify(metadata, null, "\t") + "\n", 39 + `${JSON.stringify(metadata, null, "\t")}\n`, 40 40 ); 41 41 42 42 console.log("Updated", CLIENT_METADATA_PATH);
+19
src/lib/deck-types.ts
··· 33 33 cards: DeckCard[]; 34 34 }; 35 35 36 + /** Primer can be embedded document, external URI, or reference to another record */ 37 + export type Primer = Deck["primer"]; 38 + 39 + import type { Document } from "./lexicons/types/com/deckbelcher/richtext"; 40 + 41 + const EMBEDDED_PRIMER_TYPE = "com.deckbelcher.richtext#document" as const; 42 + 43 + /** Extract embedded document from primer union, if present */ 44 + export function getEmbeddedPrimer(primer: Primer): Document | undefined { 45 + if (!primer) return undefined; 46 + if (primer.$type === EMBEDDED_PRIMER_TYPE) return primer; 47 + return undefined; 48 + } 49 + 50 + /** Wrap a document as an embedded primer for saving */ 51 + export function toEmbeddedPrimer(doc: Document): Primer { 52 + return { ...doc, $type: EMBEDDED_PRIMER_TYPE }; 53 + } 54 + 36 55 /** 37 56 * View configuration for deck display 38 57 */
+37 -1
src/lib/lexicons/types/com/deckbelcher/deck/list.ts
··· 1 1 import type {} from "@atcute/lexicons"; 2 2 import * as v from "@atcute/lexicons/validations"; 3 3 import type {} from "@atcute/lexicons/ambient"; 4 + import * as ComAtprotoRepoStrongRef from "../../atproto/repo/strongRef.js"; 4 5 import * as ComDeckbelcherDefs from "../defs.js"; 5 6 import * as ComDeckbelcherRichtext from "../richtext.js"; 6 7 ··· 81 82 * Deck primer with strategy, combos, and card choices. 82 83 */ 83 84 get primer() { 84 - return /*#__PURE__*/ v.optional(ComDeckbelcherRichtext.documentSchema); 85 + return /*#__PURE__*/ v.optional( 86 + /*#__PURE__*/ v.variant([ 87 + primerRefSchema, 88 + primerUriSchema, 89 + ComDeckbelcherRichtext.documentSchema, 90 + ]), 91 + ); 85 92 }, 86 93 /** 87 94 * Timestamp when the decklist was last updated. ··· 89 96 updatedAt: /*#__PURE__*/ v.optional(/*#__PURE__*/ v.datetimeString()), 90 97 }), 91 98 ); 99 + const _primerRefSchema = /*#__PURE__*/ v.object({ 100 + $type: /*#__PURE__*/ v.optional( 101 + /*#__PURE__*/ v.literal("com.deckbelcher.deck.list#primerRef"), 102 + ), 103 + get ref() { 104 + return ComAtprotoRepoStrongRef.mainSchema; 105 + }, 106 + }); 107 + const _primerUriSchema = /*#__PURE__*/ v.object({ 108 + $type: /*#__PURE__*/ v.optional( 109 + /*#__PURE__*/ v.literal("com.deckbelcher.deck.list#primerUri"), 110 + ), 111 + /** 112 + * @maxLength 10000 113 + * @maxGraphemes 1000 114 + */ 115 + uri: /*#__PURE__*/ v.constrain(/*#__PURE__*/ v.string(), [ 116 + /*#__PURE__*/ v.stringLength(0, 10000), 117 + /*#__PURE__*/ v.stringGraphemes(0, 1000), 118 + ]), 119 + }); 92 120 const _sectionSchema = /*#__PURE__*/ v.constrain( 93 121 /*#__PURE__*/ v.string< 94 122 "commander" | "mainboard" | "maybeboard" | "sideboard" | (string & {}) ··· 101 129 102 130 type card$schematype = typeof _cardSchema; 103 131 type main$schematype = typeof _mainSchema; 132 + type primerRef$schematype = typeof _primerRefSchema; 133 + type primerUri$schematype = typeof _primerUriSchema; 104 134 type section$schematype = typeof _sectionSchema; 105 135 106 136 export interface cardSchema extends card$schematype {} 107 137 export interface mainSchema extends main$schematype {} 138 + export interface primerRefSchema extends primerRef$schematype {} 139 + export interface primerUriSchema extends primerUri$schematype {} 108 140 export interface sectionSchema extends section$schematype {} 109 141 110 142 export const cardSchema = _cardSchema as cardSchema; 111 143 export const mainSchema = _mainSchema as mainSchema; 144 + export const primerRefSchema = _primerRefSchema as primerRefSchema; 145 + export const primerUriSchema = _primerUriSchema as primerUriSchema; 112 146 export const sectionSchema = _sectionSchema as sectionSchema; 113 147 114 148 export interface Card extends v.InferInput<typeof cardSchema> {} 115 149 export interface Main extends v.InferInput<typeof mainSchema> {} 150 + export interface PrimerRef extends v.InferInput<typeof primerRefSchema> {} 151 + export interface PrimerUri extends v.InferInput<typeof primerUriSchema> {} 116 152 export type Section = v.InferInput<typeof sectionSchema>; 117 153 118 154 declare module "@atcute/lexicons/ambient" {
+7 -4
src/routes/profile/$did/deck/$rkey/index.tsx
··· 36 36 addCardToDeck, 37 37 type DeckCard, 38 38 getCardsInSection, 39 + getEmbeddedPrimer, 39 40 moveCardToSection, 40 41 removeCardFromDeck, 42 + toEmbeddedPrimer, 41 43 updateCardQuantity, 42 44 updateCardTags, 43 45 } from "@/lib/deck-types"; ··· 102 104 const ogTitle = format ? `${deck.name} (${format})` : deck.name; 103 105 104 106 const cardCount = deck.cards.reduce((sum, c) => sum + c.quantity, 0); 105 - const primerText = deck.primer 106 - ? documentToPlainText(deck.primer) 107 + const embeddedPrimer = getEmbeddedPrimer(deck.primer); 108 + const primerText = embeddedPrimer 109 + ? documentToPlainText(embeddedPrimer) 107 110 : undefined; 108 111 const description = primerText 109 112 ? `${primerText.slice(0, 150)}${primerText.length > 150 ? "..." : ""}` ··· 198 201 const handlePrimerSave = useCallback( 199 202 (doc: Document) => { 200 203 if (!isOwner) return; 201 - mutation.mutate({ ...deck, primer: doc }); 204 + mutation.mutate({ ...deck, primer: toEmbeddedPrimer(doc) }); 202 205 }, 203 206 [isOwner, mutation, deck], 204 207 ); ··· 478 481 updateDeck={updateDeck} 479 482 highlightedCards={highlightedCards} 480 483 handleCardsChanged={handleCardsChanged} 481 - primer={deck.primer} 484 + primer={getEmbeddedPrimer(deck.primer)} 482 485 onPrimerSave={handlePrimerSave} 483 486 isSaving={mutation.isPending} 484 487 />
+25 -1
typelex/deck-list.tsp
··· 19 19 format?: string; 20 20 21 21 /** Deck primer with strategy, combos, and card choices. */ 22 - primer?: com.deckbelcher.richtext.Document; 22 + primer?: Primer; 23 23 24 24 /** Array of cards in the decklist. */ 25 25 @required ··· 31 31 32 32 /** Timestamp when the decklist was last updated. */ 33 33 updatedAt?: datetime; 34 + } 35 + 36 + /** Primer content - inline, external URI, or linked record. */ 37 + @inline 38 + union Primer { 39 + embedded: com.deckbelcher.richtext.Document, 40 + uri: PrimerUri, 41 + ref: PrimerRef, 42 + unknown, 43 + } 44 + 45 + /** External primer content. Typically a URL, but any valid URI scheme. */ 46 + model PrimerUri { 47 + @required 48 + @format("uri") 49 + @maxLength(10000) 50 + @maxGraphemes(1000) 51 + uri: string; 52 + } 53 + 54 + /** Primer in a separate ATProto record. For use with any longform writing lexicon. */ 55 + model PrimerRef { 56 + @required 57 + ref: com.atproto.repo.strongRef.Main; 34 58 } 35 59 36 60 /** A tag annotation for a card. */