mirror of
https://github.com/edufeed-org/polloer.git
synced 2025-12-07 23:34:31 +00:00
add basic reactions
This commit is contained in:
parent
7a0d33fa9d
commit
bc23755758
6 changed files with 185 additions and 62 deletions
81
package-lock.json
generated
81
package-lock.json
generated
|
|
@ -11,7 +11,9 @@
|
|||
"@nostr-dev-kit/ndk": "^2.14.5",
|
||||
"@nostr-dev-kit/ndk-svelte": "^2.4.10",
|
||||
"daisyui": "^5.0.28",
|
||||
"qrcode": "^1.5.4"
|
||||
"emoji-picker-element": "^1.26.3",
|
||||
"qrcode": "^1.5.4",
|
||||
"svelte-emoji-selector": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.5",
|
||||
|
|
@ -603,6 +605,39 @@
|
|||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "0.2.36",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz",
|
||||
"integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz",
|
||||
"integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz",
|
||||
"integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
|
|
@ -1814,6 +1849,11 @@
|
|||
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
|
||||
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
|
||||
},
|
||||
"node_modules/emoji-picker-element": {
|
||||
"version": "1.26.3",
|
||||
"resolved": "https://registry.npmjs.org/emoji-picker-element/-/emoji-picker-element-1.26.3.tgz",
|
||||
"integrity": "sha512-fOMG44d/3OqTe1pPqlu5H4ZtWg7gK4Le6Bt24JTKtDyce5+EO3Mo8WA95cKHbPSsSsg7ehM12M1x3Y6U6fgvTQ=="
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
|
|
@ -2088,6 +2128,11 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fa-svelte": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fa-svelte/-/fa-svelte-3.1.0.tgz",
|
||||
"integrity": "sha512-RqBOWwt7sc+ta9GFjbu5GOwKFRzn3rMPPSqvSGpIwsfVnpMjiI5ttv84lwNsCMEYI6/lu/iH21HUcE3TLz8RGQ=="
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
|
|
@ -2930,6 +2975,16 @@
|
|||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
||||
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
|
||||
"deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||
|
|
@ -3446,6 +3501,25 @@
|
|||
"typescript": ">=5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-click-outside": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte-click-outside/-/svelte-click-outside-1.0.0.tgz",
|
||||
"integrity": "sha512-TVDn5Vd8L0WI0Y9BFh/2I7judkIqYCbFKkGwGl/f8D0inwBFNyU0weKhrbJY4VQtYnWriq0NPl+mIYGisgALbw=="
|
||||
},
|
||||
"node_modules/svelte-emoji-selector": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-emoji-selector/-/svelte-emoji-selector-1.0.1.tgz",
|
||||
"integrity": "sha512-gGjDydt+79YQIdUyz/r1sHSkjLko2rb9qHNiBveC5RSl6rJ0mob4T5DrADRArjQ/HA8kNfEJFyqbnLoA+dyLqA==",
|
||||
"deprecated": "This package is no longer supported",
|
||||
"dependencies": {
|
||||
"@fortawesome/free-regular-svg-icons": "^5.10.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.10.1",
|
||||
"fa-svelte": "^3.0.0",
|
||||
"popper.js": "^1.15.0",
|
||||
"svelte-click-outside": "^1.0.0",
|
||||
"svelte-tabs": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-eslint-parser": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.1.3.tgz",
|
||||
|
|
@ -3474,6 +3548,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-tabs": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte-tabs/-/svelte-tabs-1.1.0.tgz",
|
||||
"integrity": "sha512-bCynxgET2uvqpB6xf/dVyqHjzmumRURQyh2QqXlrki8NxzO7h2WghF8qgpb5qeB5NTX1bMU+9Q5Hf5ey2WLaMg=="
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.4.tgz",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
"@nostr-dev-kit/ndk": "^2.14.5",
|
||||
"@nostr-dev-kit/ndk-svelte": "^2.4.10",
|
||||
"daisyui": "^5.0.28",
|
||||
"qrcode": "^1.5.4"
|
||||
"emoji-picker-element": "^1.26.3",
|
||||
"qrcode": "^1.5.4",
|
||||
"svelte-emoji-selector": "^1.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,43 @@
|
|||
<script>
|
||||
export let event;
|
||||
let { event } = $props();
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import { ndk, ndkReady, user } from '$lib/stores';
|
||||
import { writable } from 'svelte/store';
|
||||
import { login } from '$lib';
|
||||
|
||||
let reactions = writable([]);
|
||||
|
||||
async function sendReaction() {
|
||||
const reactionEvent = new NDKEvent($ndk, {
|
||||
kind: 7,
|
||||
content: '👍',
|
||||
tags: [['e', event.id]]
|
||||
});
|
||||
await reactionEvent.publish();
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (!$user) {
|
||||
console.log('no user, logging in');
|
||||
login();
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if ($ndkReady) {
|
||||
const sub = $ndk.subscribe({ kinds: [7], '#e': [event.id] });
|
||||
sub.on('event', (e) => {
|
||||
$reactions = [...$reactions, e];
|
||||
console.log(`${e.content}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<p>{event.content}</p>
|
||||
<div class="w-full border p-2">
|
||||
<p>{event.content}</p>
|
||||
<button onclick={() => sendReaction()}>👍</button>
|
||||
<p>Reaction Count: {$reactions.length}</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1 +1,35 @@
|
|||
// place files you want to import through the `$lib` alias in this folder.
|
||||
import { NDKNip07Signer, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
||||
import { ndk as ndkStore, user as userStore } from "$lib/stores";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
export async function login() {
|
||||
let ndk = get(ndkStore)
|
||||
let user = get(userStore)
|
||||
if (window.nostr) {
|
||||
const signer = new NDKNip07Signer();
|
||||
ndk.signer = signer;
|
||||
const signedUser = await signer.user();
|
||||
userStore.set(signedUser)
|
||||
} else {
|
||||
const storedPrivateKey = window.localStorage.getItem('nostrPrivateKey');
|
||||
if (storedPrivateKey) {
|
||||
const privateKey = JSON.parse(storedPrivateKey);
|
||||
console.log("stored private key", privateKey)
|
||||
const signer = new NDKPrivateKeySigner(privateKey);
|
||||
ndk.signer = signer;
|
||||
const signedUser = await signer.user();
|
||||
userStore.set(signedUser)
|
||||
|
||||
} else {
|
||||
console.log('No private key found, generating a new one...');
|
||||
const privateKey = NDKPrivateKeySigner.generate();
|
||||
const signer = new NDKPrivateKeySigner(privateKey.privateKey);
|
||||
console.log('Generated Private Key:', privateKey);
|
||||
ndk.signer = signer;
|
||||
const signedUser = await signer.user();
|
||||
userStore.set(signedUser)
|
||||
|
||||
window.localStorage.setItem('nostrPrivateKey', JSON.stringify(privateKey.privateKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import { NDKEvent, NDKNip07Signer, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
||||
import { writable } from 'svelte/store';
|
||||
import QRCode from 'qrcode';
|
||||
import { login } from '$lib';
|
||||
|
||||
let question = '';
|
||||
let questionId = writable(''); ;
|
||||
|
|
@ -49,31 +50,7 @@
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
async function login() {
|
||||
if (window.nostr) {
|
||||
const signer = new NDKNip07Signer();
|
||||
$ndk.signer = signer;
|
||||
$user = await signer.user();
|
||||
} else {
|
||||
const storedPrivateKey = window.localStorage.getItem('nostrPrivateKey');
|
||||
if (storedPrivateKey) {
|
||||
const privateKey = JSON.parse(storedPrivateKey);
|
||||
console.log("stored private key", privateKey)
|
||||
const signer = new NDKPrivateKeySigner(privateKey);
|
||||
$ndk.signer = signer;
|
||||
$user = await signer.user();
|
||||
} else {
|
||||
console.log('No private key found, generating a new one...');
|
||||
const privateKey = NDKPrivateKeySigner.generate();
|
||||
const signer = new NDKPrivateKeySigner(privateKey.privateKey);
|
||||
console.log('Generated Private Key:', privateKey);
|
||||
$ndk.signer = signer;
|
||||
$user = await signer.user();
|
||||
window.localStorage.setItem('nostrPrivateKey', JSON.stringify(privateKey.privateKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$effect(() => {
|
||||
if ($ndkReady) {
|
||||
if ($ndk.activeUser) {
|
||||
|
|
|
|||
|
|
@ -11,18 +11,18 @@
|
|||
const commentEvent = new NDKEvent($ndk, {
|
||||
kind: 2222,
|
||||
content: comment,
|
||||
tags: [["E", data.id]]
|
||||
tags: [['E', data.id]]
|
||||
});
|
||||
commentEvent.publish();
|
||||
}
|
||||
|
||||
let comment = ""
|
||||
let comment = '';
|
||||
let comments = writable([]);
|
||||
let question = writable("")
|
||||
let question = writable('');
|
||||
|
||||
$effect(() => {
|
||||
if ($ndkReady) {
|
||||
const sub = $ndk.subscribe({ kinds: [2222], "#E": [data.id] });
|
||||
const sub = $ndk.subscribe({ kinds: [2222], '#E': [data.id] });
|
||||
sub.on('event', (event) => {
|
||||
$comments = [...$comments, event];
|
||||
console.log(`${event.content}`);
|
||||
|
|
@ -31,33 +31,28 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<div class="w-full flex flex-col justify-center mx-auto items-center">
|
||||
|
||||
<h1 class="">Identifier: {data.id}</h1>
|
||||
<div>{@html data.id}</div>
|
||||
|
||||
{#await $ndk.fetchEvent(data.id) then question}
|
||||
{#if question}
|
||||
<div class="mb-4 w-full rounded border p-2">
|
||||
<h2>Question: {question.content}</h2>
|
||||
<p>Tags: {question.tags}</p>
|
||||
<p>Created At: {new Date(question.created_at * 1000).toLocaleString()}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-xl">Ideensammlung</h1>
|
||||
<textarea bind:value={comment} placeholder="Mein Kommentar"></textarea>
|
||||
<button class="btn btn-error" onclick={() => submitComment()}>Absenden</button>
|
||||
</div>
|
||||
{:else}
|
||||
<p>Loading...</p>
|
||||
{/if}
|
||||
{:catch error}
|
||||
<p>Error fetching question: {error.message}</p>
|
||||
{/await}
|
||||
|
||||
{#each $comments as event}
|
||||
<Comment {event} />
|
||||
{/each}
|
||||
<div class="mx-auto flex flex-col items-center justify-center w-3/4">
|
||||
{#await $ndk.fetchEvent(data.id) then question}
|
||||
{#if question}
|
||||
<div class="mb-4 w-full rounded border p-2">
|
||||
<h2>Question: {question.content}</h2>
|
||||
</div>
|
||||
|
||||
<div class="w-full flex flex-col items-center justify-center gap-2 mb-2">
|
||||
<h1 class="text-xl">Ideensammlung</h1>
|
||||
<textarea class="w-full border" bind:value={comment} placeholder="Mein Kommentar"></textarea>
|
||||
<button class="btn btn-success" onclick={() => submitComment()}>Absenden</button>
|
||||
</div>
|
||||
{:else}
|
||||
<p>Loading...</p>
|
||||
{/if}
|
||||
{:catch error}
|
||||
<p>Error fetching question: {error.message}</p>
|
||||
{/await}
|
||||
|
||||
<div class="mx-auto flex w-full flex-col items-center justify-center gap-2">
|
||||
{#each $comments as event}
|
||||
<Comment {event} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue