a proof of concept realtime collaborative text editor using atproto as a sync server jake.tngl.io/y-pds/
2
fork

Configure Feed

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

members -> editors

+15 -15
+10 -10
app.js
··· 157 157 158 158 class ShareDialog extends Component { 159 159 dialogRef = createRef(); 160 - members = signal([]); 160 + editors = signal([]); 161 161 provider = null; 162 162 163 163 async open(provider) { 164 164 this.provider = provider; 165 - this.members.value = provider.getMembers(); 165 + this.editors.value = provider.getMembers(); 166 166 this.dialogRef.current.showModal(); 167 167 } 168 168 ··· 171 171 const identifier = e.currentTarget.did.value.trim(); 172 172 if (!identifier) return; 173 173 const newDid = await resolve(identifier); 174 - const members = this.provider.getMembers(); 175 - if (members.includes(newDid)) return; 176 - const updated = [...members, newDid]; 174 + const editors = this.provider.getMembers(); 175 + if (editors.includes(newDid)) return; 176 + const updated = [...editors, newDid]; 177 177 await this.provider.setMembers(updated); 178 - this.members.value = updated; 178 + this.editors.value = updated; 179 179 e.currentTarget.reset(); 180 180 } 181 181 182 182 async removeMember(memberDid) { 183 - const updated = this.members.value.filter(m => m !== memberDid); 183 + const updated = this.editors.value.filter(m => m !== memberDid); 184 184 await this.provider.setMembers(updated); 185 - this.members.value = updated; 185 + this.editors.value = updated; 186 186 } 187 187 188 188 render() { 189 189 return html` 190 190 <dialog ref=${this.dialogRef}> 191 191 <h2>Share</h2> 192 - <ul id="members"> 193 - ${this.members.value.map( 192 + <ul id="editors"> 193 + ${this.editors.value.map( 194 194 m => html` 195 195 <li key=${m}> 196 196 <span>${m}</span>
+5 -5
y-pds.js
··· 60 60 61 61 async load() { 62 62 const doc = await this.#ensureDocument(); 63 - this.#repos = new Set([this.#ownerDid, ...doc.members]); 63 + this.#repos = new Set([this.#ownerDid, ...doc.editors]); 64 64 65 65 const perRepo = await Promise.all([...this.#repos].map(repo => this.#fetchUpdates(repo))); 66 66 const updates = perRepo ··· 150 150 const record = { 151 151 $type: DOC_COLLECTION, 152 152 docId: this.#rkey, 153 - members: [], 153 + editors: [], 154 154 createdAt: new Date().toISOString(), 155 155 }; 156 156 await this.rpc.post("com.atproto.repo.putRecord", { ··· 173 173 return [...this.#repos].filter(r => r !== this.#ownerDid); 174 174 } 175 175 176 - async setMembers(members) { 176 + async setMembers(editors) { 177 177 const doc = await this.#fetchDocument(); 178 178 await this.rpc.post("com.atproto.repo.putRecord", { 179 179 input: { 180 180 repo: this.did, 181 181 collection: DOC_COLLECTION, 182 182 rkey: this.#rkey, 183 - record: { ...doc, members }, 183 + record: { ...doc, editors }, 184 184 }, 185 185 }); 186 186 } ··· 227 227 228 228 async #onMembersChange() { 229 229 const doc = await this.#fetchDocument(); 230 - const newRepos = new Set([this.#ownerDid, ...doc.members]); 230 + const newRepos = new Set([this.#ownerDid, ...doc.editors]); 231 231 232 232 const added = [...newRepos].filter(r => !this.#repos.has(r)); 233 233 if (added.length > 0) {