diff --git a/package.json b/package.json
index 720b3e6..f1e281d 100644
--- a/package.json
+++ b/package.json
@@ -44,9 +44,12 @@
"@fuxui/social": "^0.0.9",
"@tailwindcss/typography": "^0.5.16",
"@tiptap/core": "^2.12.0",
+ "@tiptap/extension-document": "^2.12.0",
"@tiptap/extension-image": "^2.12.0",
"@tiptap/extension-link": "^2.12.0",
+ "@tiptap/extension-paragraph": "^2.12.0",
"@tiptap/extension-placeholder": "^2.12.0",
+ "@tiptap/extension-text": "^2.12.0",
"@tiptap/starter-kit": "^2.12.0",
"marked": "^15.0.11",
"turndown": "^7.2.0"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 539a3fc..f07db8a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -26,15 +26,24 @@ importers:
'@tiptap/core':
specifier: ^2.12.0
version: 2.12.0(@tiptap/pm@2.12.0)
+ '@tiptap/extension-document':
+ specifier: ^2.12.0
+ version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
'@tiptap/extension-image':
specifier: ^2.12.0
version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
'@tiptap/extension-link':
specifier: ^2.12.0
version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
+ '@tiptap/extension-paragraph':
+ specifier: ^2.12.0
+ version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
'@tiptap/extension-placeholder':
specifier: ^2.12.0
version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))(@tiptap/pm@2.12.0)
+ '@tiptap/extension-text':
+ specifier: ^2.12.0
+ version: 2.12.0(@tiptap/core@2.12.0(@tiptap/pm@2.12.0))
'@tiptap/starter-kit':
specifier: ^2.12.0
version: 2.12.0
diff --git a/src/lib/oauth/atproto.ts b/src/lib/oauth/atproto.ts
index cb3e499..717563d 100644
--- a/src/lib/oauth/atproto.ts
+++ b/src/lib/oauth/atproto.ts
@@ -90,6 +90,16 @@ export async function putRecord({
}) {
if (!client.profile || !client.rpc) throw new Error('No profile or rpc');
+ console.log('updating record', {
+ data: {
+ collection,
+ repo: client.profile.did,
+ rkey,
+ record: {
+ ...record
+ }
+ }
+ });
const response = await client.rpc.call('com.atproto.repo.putRecord', {
data: {
collection,
@@ -103,3 +113,25 @@ export async function putRecord({
return response;
}
+
+export async function deleteRecord({
+ did,
+ collection,
+ rkey
+}: {
+ did: string;
+ collection: string;
+ rkey: string;
+}) {
+ if (!client.profile || !client.rpc) throw new Error('No profile or rpc');
+
+ const response = await client.rpc.call('com.atproto.repo.deleteRecord', {
+ data: {
+ collection,
+ repo: did,
+ rkey
+ }
+ });
+
+ return response;
+}
diff --git a/src/lib/website/EditingList.svelte b/src/lib/website/EditingList.svelte
new file mode 100644
index 0000000..84d4989
--- /dev/null
+++ b/src/lib/website/EditingList.svelte
@@ -0,0 +1,55 @@
+
+
+{#if allRecords.length === 0 && empty}
+ {@render empty()}
+{:else}
+ {#each allRecords as itemData (itemData.uri)}
+
+ {#snippet child(data)}
+ {@render item(data, async () => {
+ const { rkey } = parseUri(itemData.uri as string);
+ await deleteRecord({ did, collection, rkey });
+
+ allRecords = allRecords.filter((record) => record.uri !== itemData.uri);
+ })}
+ {/snippet}
+
+ {/each}
+{/if}
+
+{@render addItem?.(() => {
+ console.log('clicked');
+ const rkey = TID.nextStr();
+
+ allRecords.push({
+ uri: 'at://' + did + '/' + collection + '/' + rkey,
+ value: {}
+ });
+})}
diff --git a/src/lib/website/Link.svelte b/src/lib/website/Link.svelte
new file mode 100644
index 0000000..78a885b
--- /dev/null
+++ b/src/lib/website/Link.svelte
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+ {#if hasContext('isEditing')}
+
Delete
+ {:else}
+
+ {/if}
+
diff --git a/src/lib/website/List.svelte b/src/lib/website/List.svelte
index 8a1de1b..98da7f2 100644
--- a/src/lib/website/List.svelte
+++ b/src/lib/website/List.svelte
@@ -2,31 +2,36 @@
import { getContext, hasContext, type Snippet } from 'svelte';
import type { Collection } from './data';
import { listRecords } from '$lib/oauth/atproto';
+ import EditingList from './EditingList.svelte';
let {
collection,
- data,
- item
+ item,
+ addItem,
+ empty
}: {
collection: Collection;
- data: Record;
- item: Snippet<[any]>;
+ item: Snippet<[any, any]>;
+ addItem: Snippet<[any]>;
+ empty?: Snippet;
} = $props();
+ let data = getContext('data') as Record;
const did = getContext('did') as string;
{#if hasContext('isEditing')}
{#await listRecords({ did, collection }) then records}
- {#each records as itemData}
- {@render item(itemData)}
- {/each}
+
{:catch error}
{error}
{/await}
{:else}
-{#each data[collection] as itemData}
- {@render item(itemData)}
-{/each}
+ {#each data[collection] as itemData}
+ {@render item(itemData.value, () => {})}
+ {/each}
-{/if}
\ No newline at end of file
+ {#if (!data[collection] || (data[collection] as any[]).length === 0) && empty}
+ {@render empty()}
+ {/if}
+{/if}
diff --git a/src/lib/website/PlainText.svelte b/src/lib/website/PlainText.svelte
new file mode 100644
index 0000000..71e6e64
--- /dev/null
+++ b/src/lib/website/PlainText.svelte
@@ -0,0 +1,23 @@
+
+
+{#if getContext('isEditing')}
+ {#await import('./PlainTextEditor.svelte') then { default: PlainTextEditor }}
+
+ {/await}
+{:else}
+ {data[key] || defaultContent || placeholder}
+{/if}
diff --git a/src/lib/website/PlainTextEditor.svelte b/src/lib/website/PlainTextEditor.svelte
new file mode 100644
index 0000000..a0067de
--- /dev/null
+++ b/src/lib/website/PlainTextEditor.svelte
@@ -0,0 +1,108 @@
+
+
+
+
+
diff --git a/src/lib/website/PlainTextItem.svelte b/src/lib/website/PlainTextItem.svelte
new file mode 100644
index 0000000..a9ada9d
--- /dev/null
+++ b/src/lib/website/PlainTextItem.svelte
@@ -0,0 +1,48 @@
+
+
+{#if getContext('isEditing')}
+ {#await getRecord({ did, collection, rkey }) then record}
+
+ {#snippet child(recordData)}
+ {#await import('./PlainTextEditor.svelte') then { default: PlainTextEditor }}
+
+ {/await}
+ {/snippet}
+
+ {:catch error}
+
+ {#snippet child(recordData)}
+ {#await import('./PlainTextEditor.svelte') then { default: PlainTextEditor }}
+
+ {/await}
+ {/snippet}
+
+ {/await}
+{:else}
+ {data?.[collection]?.[rkey]?.value?.[key] || defaultContent || placeholder}
+{/if}
diff --git a/src/lib/website/SingleRecord.svelte b/src/lib/website/SingleRecord.svelte
index 593de9f..4324f76 100644
--- a/src/lib/website/SingleRecord.svelte
+++ b/src/lib/website/SingleRecord.svelte
@@ -1,66 +1,46 @@
-{#if hasContext('isEditing')}
- {@render editing(data.value, willUpdate)}
-{:else}
- {@render view(data.value)}
-{/if}
+{@render child(data.value)}
diff --git a/src/lib/website/Test.svelte b/src/lib/website/Test.svelte
index c58ec0d..68183c4 100644
--- a/src/lib/website/Test.svelte
+++ b/src/lib/website/Test.svelte
@@ -1,11 +1,37 @@
-
-
- {data.value.label}:
- {data.value.description}
-
+ let label = $state(data.label);
+ let description = $state(data.description);
+
+ let updatedLabel = $state(false);
+ let updatedDescription = $state(false);
+ const update = async () => {
+ const updated: Record = {};
+ if(updatedLabel) {
+ updated.label = label;
+ }
+ if(updatedDescription) {
+ updated.description = description;
+ }
+ return updated;
+ };
+
+ const updateFunctions = getContext('updateRecord') as UpdateRecordFunction[];
+
+ if(updateFunctions) {
+ updateFunctions.push(update);
+ }
+
+
+
updatedLabel = true} />
+ updatedDescription = true} />
+
\ No newline at end of file
diff --git a/src/lib/website/Website.svelte b/src/lib/website/Website.svelte
index 5ce22bb..4c9351a 100644
--- a/src/lib/website/Website.svelte
+++ b/src/lib/website/Website.svelte
@@ -4,10 +4,14 @@
import MarkdownText from './MarkdownText.svelte';
import SingleRecord from './SingleRecord.svelte';
import Test from './Test.svelte';
+ import PlainText from './PlainText.svelte';
+ import { setContext } from 'svelte';
+ import Link from './Link.svelte';
+ import PlainTextItem from './PlainTextItem.svelte';
let { data } = $props();
- console.log(data);
+ setContext('data', data);
@@ -24,25 +28,33 @@
defaultContent="Hello there"
/> -->
-
-
- {#snippet item(item)}
-
- {#snippet editing(data)}
-
-
-
-
- {/snippet}
-
- {#snippet view(data)}
-
-
{data.label}
-
{data.description}
-
- {/snippet}
-
+
+
+
+
+ {#snippet item(data, deleteItem)}
+
+ {/snippet}
+
+ {#snippet addItem(add)}
+ Add
{/snippet}
+
diff --git a/src/lib/website/context.ts b/src/lib/website/context.ts
index 2d3d90d..d3f374b 100644
--- a/src/lib/website/context.ts
+++ b/src/lib/website/context.ts
@@ -1 +1,3 @@
export type UpdateFunction = () => boolean | Promise
;
+
+export type UpdateRecordFunction = () => Record | Promise>;
\ No newline at end of file
diff --git a/src/lib/website/data.ts b/src/lib/website/data.ts
index 04ae62e..1af6082 100644
--- a/src/lib/website/data.ts
+++ b/src/lib/website/data.ts
@@ -1,6 +1,6 @@
// collections and records we want to grab
export const data = {
- 'dev.flo-bit.about': ['self'],
+ 'dev.flo-bit.about': ['self', 'test'],
'dev.flo-bit.test': ['self'],
'link.flo-bit.dev': 'all'
} as const;
@@ -15,3 +15,9 @@ export type CollectionRecord =
(typeof data)[C] extends readonly (infer U)[]
? U // yes → U is the element type (e.g. "self")
: any; // no → value must have been "all"
+
+export function parseUri(uri: string) {
+ // at://did:plc:257wekqxg4hyapkq6k47igmp/link.flo-bit.dev/3lnblfznvhr2a
+ const [did, collection, rkey] = uri.split('/').slice(2);
+ return { did, collection, rkey };
+}
\ No newline at end of file
diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts
index a635517..4ad9b42 100644
--- a/src/routes/+page.server.ts
+++ b/src/routes/+page.server.ts
@@ -14,7 +14,6 @@ export async function load() {
const downloadedData = {} as DownloadedData;
- // 3️⃣ Narrow Object.keys back to your Collection union
for (const collection of Object.keys(data) as Collection[]) {
const cfg = data[collection];
diff --git a/src/routes/edit/+page.svelte b/src/routes/edit/+page.svelte
index e9f0343..a206474 100644
--- a/src/routes/edit/+page.svelte
+++ b/src/routes/edit/+page.svelte
@@ -23,9 +23,7 @@
class="absolute right-2 bottom-2"
onclick={() => {
for (const updateFunction of updateFunctions) {
- if (updateFunction()) {
- console.log('updated');
- }
+ updateFunction();
}
}}
>