show reactions on posts
This commit is contained in:
parent
e824e43a94
commit
c1531dc41c
3 changed files with 137 additions and 17 deletions
|
@ -73,6 +73,21 @@ textarea, input {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reaction-group {
|
||||||
|
display: inline-flex;
|
||||||
|
background-color: rgba(255,255,255,0.15);
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reaction-group img {
|
||||||
|
margin-left: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reaction-emoji {
|
||||||
|
margin-right: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -145,10 +160,18 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
.pfp {
|
.pfp {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pfp-small {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pfp-normal {
|
||||||
|
margin: 0 15px 0 15px;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
margin: 0 15px 0 15px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment {
|
.comment {
|
||||||
|
@ -159,7 +182,7 @@ html {
|
||||||
/*align-items: center;*/
|
/*align-items: center;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment p {
|
.comment .comment-body {
|
||||||
background-color: rgba(255.0,255.0,255.0,0.1);
|
background-color: rgba(255.0,255.0,255.0,0.1);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
@ -167,6 +190,10 @@ html {
|
||||||
width: 55%;
|
width: 55%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-body p {
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.comment .info {
|
.comment .info {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
width: 18%;
|
width: 18%;
|
||||||
|
|
111
webv2/damus.js
111
webv2/damus.js
|
@ -40,6 +40,7 @@ function init_home_model() {
|
||||||
notifications: 0,
|
notifications: 0,
|
||||||
rendered: {},
|
rendered: {},
|
||||||
all_events: {},
|
all_events: {},
|
||||||
|
reactions_to: {},
|
||||||
events: [],
|
events: [],
|
||||||
profiles: {},
|
profiles: {},
|
||||||
last_event_of_kind: {},
|
last_event_of_kind: {},
|
||||||
|
@ -121,12 +122,30 @@ async function damus_web_init()
|
||||||
return pool
|
return pool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function process_reaction_event(model, ev)
|
||||||
|
{
|
||||||
|
let last = {}
|
||||||
|
|
||||||
|
for (const tag of ev.tags) {
|
||||||
|
if (tag.length >= 2 && (tag[0] === "e" || tag[0] === "p"))
|
||||||
|
last[tag[0]] = tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last.e && last.p) {
|
||||||
|
model.reactions_to[last.e] = model.reactions_to[last.e] || new Set()
|
||||||
|
model.reactions_to[last.e].add(ev.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function process_event(model, ev)
|
function process_event(model, ev)
|
||||||
{
|
{
|
||||||
ev.refs = determine_event_refs(ev.tags)
|
ev.refs = determine_event_refs(ev.tags)
|
||||||
const notified = was_pubkey_notified(model.pubkey, ev)
|
const notified = was_pubkey_notified(model.pubkey, ev)
|
||||||
ev.notified = notified
|
ev.notified = notified
|
||||||
|
|
||||||
|
if (ev.kind === 7)
|
||||||
|
process_reaction_event(model, ev)
|
||||||
|
|
||||||
const last_notified = get_local_state('last_notified_date')
|
const last_notified = get_local_state('last_notified_date')
|
||||||
if (notified && (last_notified == null || ((ev.created_at*1000) > last_notified))) {
|
if (notified && (last_notified == null || ((ev.created_at*1000) > last_notified))) {
|
||||||
set_local_state('last_notified_date', new Date().getTime())
|
set_local_state('last_notified_date', new Date().getTime())
|
||||||
|
@ -151,6 +170,11 @@ function was_pubkey_notified(pubkey, ev)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function should_add_to_home(ev)
|
||||||
|
{
|
||||||
|
return ev.kind === 1 || ev.kind === 42
|
||||||
|
}
|
||||||
|
|
||||||
let rerender_home_timer
|
let rerender_home_timer
|
||||||
function handle_home_event(ids, model, relay, sub_id, ev) {
|
function handle_home_event(ids, model, relay, sub_id, ev) {
|
||||||
model.all_events[ev.id] = ev
|
model.all_events[ev.id] = ev
|
||||||
|
@ -158,6 +182,8 @@ function handle_home_event(ids, model, relay, sub_id, ev) {
|
||||||
switch (sub_id) {
|
switch (sub_id) {
|
||||||
case ids.home:
|
case ids.home:
|
||||||
process_event(model, ev)
|
process_event(model, ev)
|
||||||
|
|
||||||
|
if (should_add_to_home(ev))
|
||||||
insert_event_sorted(model.events, ev)
|
insert_event_sorted(model.events, ev)
|
||||||
|
|
||||||
if (model.realtime) {
|
if (model.realtime) {
|
||||||
|
@ -490,16 +516,17 @@ function can_reply(ev) {
|
||||||
return ev.kind === 1 || ev.kind === 42
|
return ev.kind === 1 || ev.kind === 42
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_PROFILE = {
|
||||||
|
name: "anon",
|
||||||
|
display_name: "Anonymous",
|
||||||
|
}
|
||||||
|
|
||||||
function render_event(model, ev, opts={}) {
|
function render_event(model, ev, opts={}) {
|
||||||
if (!opts.is_composing && model.rendered[ev.id])
|
if (!opts.is_composing && model.rendered[ev.id])
|
||||||
return ""
|
return ""
|
||||||
model.rendered[ev.id] = true
|
model.rendered[ev.id] = true
|
||||||
const profile = model.profiles[ev.pubkey] || {
|
const profile = model.profiles[ev.pubkey] || DEFAULT_PROFILE
|
||||||
name: "anon",
|
|
||||||
display_name: "Anonymous",
|
|
||||||
}
|
|
||||||
const delta = time_delta(new Date().getTime(), ev.created_at*1000)
|
const delta = time_delta(new Date().getTime(), ev.created_at*1000)
|
||||||
const pk = ev.pubkey
|
|
||||||
const bar = !can_reply(ev) || opts.nobar? "" : render_action_bar(ev)
|
const bar = !can_reply(ev) || opts.nobar? "" : render_action_bar(ev)
|
||||||
|
|
||||||
let replying_to = ""
|
let replying_to = ""
|
||||||
|
@ -528,15 +555,79 @@ function render_event(model, ev, opts={}) {
|
||||||
</div>
|
</div>
|
||||||
<div class="pfpbox">
|
<div class="pfpbox">
|
||||||
${reply_line_top}
|
${reply_line_top}
|
||||||
<img class="pfp" onerror="this.onerror=null;this.src='${robohash(pk)}';" src="${get_picture(pk, profile)}">
|
${render_pfp(ev.pubkey, profile)}
|
||||||
${reply_line_bot}
|
${reply_line_bot}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="comment-body">
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
${format_content(ev)}
|
${format_content(ev)}
|
||||||
|
|
||||||
${bar}
|
|
||||||
</p>
|
</p>
|
||||||
|
${render_reactions(model, ev)}
|
||||||
|
${bar}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_pfp(pk, profile, size="normal") {
|
||||||
|
return `<img class="pfp pfp-${size}" onerror="this.onerror=null;this.src='${robohash(pk)}';" src="${get_picture(pk, profile)}">`
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_reaction_emoji(ev) {
|
||||||
|
if (ev.content === "+" || ev.content === "")
|
||||||
|
return "❤️"
|
||||||
|
return ev.content
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_reaction_group(model, emoji, reactions) {
|
||||||
|
const pfps = Object.keys(reactions).map((pk) => render_reaction(model, reactions[pk]))
|
||||||
|
return `
|
||||||
|
<span class="reaction-group">
|
||||||
|
<span class="reaction-emoji">
|
||||||
|
${emoji}
|
||||||
|
</span>
|
||||||
|
${pfps.join("\n")}
|
||||||
|
</span>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_reaction(model, reaction) {
|
||||||
|
const profile = model.profiles[reaction.pubkey] || DEFAULT_PROFILE
|
||||||
|
let emoji = reaction.content[0]
|
||||||
|
if (reaction.content === "+" || reaction.content === "")
|
||||||
|
emoji = "❤️"
|
||||||
|
|
||||||
|
return render_pfp(reaction.pubkey, profile, "small")
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_reactions(model, ev) {
|
||||||
|
const reactions_set = model.reactions_to[ev.id]
|
||||||
|
if (!reactions_set)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
let reactions = []
|
||||||
|
for (const id of reactions_set.keys()) {
|
||||||
|
const reaction = model.all_events[id]
|
||||||
|
if (!reaction)
|
||||||
|
continue
|
||||||
|
reactions.push(reaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = ""
|
||||||
|
const groups = reactions.reduce((grp, r) => {
|
||||||
|
const e = get_reaction_emoji(r)
|
||||||
|
grp[e] = grp[e] || {}
|
||||||
|
grp[e][r.pubkey] = r
|
||||||
|
return grp
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
for (const emoji of Object.keys(groups)) {
|
||||||
|
str += render_reaction_group(model, emoji, groups[emoji])
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="reactions">
|
||||||
|
${str}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
@ -677,7 +768,9 @@ function reply_to(evid) {
|
||||||
|
|
||||||
function render_action_bar(ev) {
|
function render_action_bar(ev) {
|
||||||
return `
|
return `
|
||||||
|
<div class="action-bar">
|
||||||
<a href="javascript:reply_to('${ev.id}')">reply</a>
|
<a href="javascript:reply_to('${ev.id}')">reply</a>
|
||||||
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<title>Damus</title>
|
<title>Damus</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="damus.css?v=8">
|
<link rel="stylesheet" href="damus.css?v=9">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<section class="header">
|
<section class="header">
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
<script src="noble-secp256k1.js?v=1"></script>
|
<script src="noble-secp256k1.js?v=1"></script>
|
||||||
<script src="bech32.js?v=1"></script>
|
<script src="bech32.js?v=1"></script>
|
||||||
<script src="nostr.js?v=5"></script>
|
<script src="nostr.js?v=5"></script>
|
||||||
<script src="damus.js?v=30"></script>
|
<script src="damus.js?v=31"></script>
|
||||||
<script>
|
<script>
|
||||||
// I have to delay loading to wait for nos2x
|
// I have to delay loading to wait for nos2x
|
||||||
const relay = setTimeout(damus_web_init, 100)
|
const relay = setTimeout(damus_web_init, 100)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue