A little headless CMS that stores models and content in your PDS sites.wisp.place/wilb.me/pds-cms/
0

Configure Feed

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

Fix svelte warnings and add renderer bin to root

+28 -13
+1
.gitignore
··· 2 2 dist/ 3 3 *.log 4 4 .DS_Store 5 + site
+1 -1
README.md
··· 118 118 records, compile to a framework-agnostic render tree, and emit HTML. 119 119 120 120 ```sh 121 - pnpm --filter @pds-cms/renderer exec pds-cms-render alice.bsky.social -o site 121 + pnpm exec pds-cms-render alice.bsky.social -o site # from the workspace root 122 122 ``` 123 123 124 124 Or programmatically — the pipeline is split so each stage is reusable:
+3
package.json
··· 5 5 "build": "pnpm -r build", 6 6 "test": "pnpm -r test", 7 7 "typecheck": "pnpm -r typecheck" 8 + }, 9 + "devDependencies": { 10 + "@pds-cms/renderer": "workspace:*" 8 11 } 9 12 }
+2 -1
packages/content-editor/src/app.css
··· 37 37 margin-bottom: 1rem; 38 38 } 39 39 40 - .field label { 40 + .field label, 41 + .field .label { 41 42 display: block; 42 43 font-weight: 600; 43 44 margin-bottom: 0.25rem;
+9 -8
packages/content-editor/src/lib/components/FieldInput.svelte
··· 15 15 } = $props() 16 16 17 17 const label = $derived((field.label ?? field.name) + (field.required ? ' *' : '')) 18 + const uid = $props.id() 18 19 </script> 19 20 20 21 {#snippet fieldErrors(errors: [string, ...string[]] | null)} ··· 34 35 </div> 35 36 {:else if field.type === 'link'} 36 37 <div class="field" class:subfield={compact}> 37 - {#if !compact}<label>{label}</label>{/if} 38 + {#if !compact}<span class="label">{label}</span>{/if} 38 39 <div class="subfield"> 39 40 <Field of={form as never} path={[...path, 'uri'] as never}> 40 41 {#snippet children(f: never)} ··· 53 54 </div> 54 55 {:else if field.type === 'image'} 55 56 <div class="field" class:subfield={compact}> 56 - {#if !compact}<label>{label}</label>{/if} 57 + {#if !compact}<span class="label">{label}</span>{/if} 57 58 <div class="subfield"> 58 59 <Field of={form as never} path={[...path, 'file'] as never}> 59 60 {#snippet children(f: never)} ··· 75 76 </div> 76 77 {:else} 77 78 <div class="field" class:subfield={compact}> 78 - {#if !compact}<label>{label}</label>{/if} 79 + {#if !compact}<label for={uid}>{label}</label>{/if} 79 80 <Field of={form as never} path={path as never}> 80 81 {#snippet children(f: never)} 81 82 {#if field.type === 'longtext'} 82 - <textarea {...(f as any).props} value={(f as any).input ?? ''}></textarea> 83 + <textarea {...(f as any).props} id={uid} value={(f as any).input ?? ''}></textarea> 83 84 {:else if field.type === 'select'} 84 - <select {...(f as any).props} value={(f as any).input ?? ''}> 85 + <select {...(f as any).props} id={uid} value={(f as any).input ?? ''}> 85 86 {#if !field.required}<option value="">—</option>{/if} 86 87 {#each field.type === 'select' ? field.options : [] as option (option)} 87 88 <option value={option}>{option}</option> 88 89 {/each} 89 90 </select> 90 91 {:else if field.type === 'number'} 91 - <input {...(f as any).props} value={(f as any).input ?? ''} type="text" inputmode="numeric" /> 92 + <input {...(f as any).props} id={uid} value={(f as any).input ?? ''} type="text" inputmode="numeric" /> 92 93 {:else if field.type === 'date'} 93 - <input {...(f as any).props} value={(f as any).input ?? ''} type="date" /> 94 + <input {...(f as any).props} id={uid} value={(f as any).input ?? ''} type="date" /> 94 95 {:else} 95 - <input {...(f as any).props} value={(f as any).input ?? ''} type="text" /> 96 + <input {...(f as any).props} id={uid} value={(f as any).input ?? ''} type="text" /> 96 97 {/if} 97 98 {@render fieldErrors((f as any).errors)} 98 99 {/snippet}
+5 -1
packages/content-editor/src/lib/components/RecordForm.svelte
··· 18 18 oncancel: () => void 19 19 } = $props() 20 20 21 + // A form instance is intentionally bound to the model it was created 22 + // with — the parent must remount this component to switch models. 23 + // svelte-ignore state_referenced_locally 21 24 const schema = modelToValibot(model, { mode: 'form' }) 22 25 const form = createForm({ 23 26 schema: schema as never, 27 + // svelte-ignore state_referenced_locally 24 28 initialInput: modelToInitialInput(model) as never, 25 29 }) 26 30 ··· 44 48 {#each model.fields as field (field.name)} 45 49 {#if field.array} 46 50 <div class="field"> 47 - <label>{field.label ?? field.name}{field.required ? ' *' : ''}</label> 51 + <span class="label">{field.label ?? field.name}{field.required ? ' *' : ''}</span> 48 52 <FieldArray of={form} path={[field.name] as never}> 49 53 {#snippet children(arr: never)} 50 54 {#each (arr as any).items as itemId, index (itemId)}
+2 -1
packages/renderer/package.json
··· 20 20 "scripts": { 21 21 "build": "tsc -p tsconfig.json", 22 22 "typecheck": "tsc -p tsconfig.json --noEmit", 23 - "test": "vitest run" 23 + "test": "vitest run", 24 + "render": "node dist/cli.js" 24 25 }, 25 26 "dependencies": { 26 27 "@atproto/api": "^0.20.30",
+5 -1
pnpm-lock.yaml
··· 6 6 7 7 importers: 8 8 9 - .: {} 9 + .: 10 + devDependencies: 11 + '@pds-cms/renderer': 12 + specifier: workspace:* 13 + version: link:packages/renderer 10 14 11 15 packages/content-editor: 12 16 dependencies: