| Comment: | notifications work now |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
9cc5d48cd80df268d79a987727880507 |
| User & Date: | lexi on 2021-01-06 22:18:59 |
| Other Links: | manifest | tags |
|
2021-01-06
| ||
| 22:31 | unfuck last commit check-in: 8d8ab01573 user: lexi tags: trunk | |
| 22:18 | notifications work now check-in: 9cc5d48cd8 user: lexi tags: trunk | |
|
2021-01-05
| ||
| 22:48 | adjusted bell check-in: 0faa879398 user: lexi tags: trunk | |
Modified backend/pgsql.t from [7305c1c258] to [80ca2205e4].
693 693 return buf 694 694 end 695 695 end; 696 696 } 697 697 698 698 local sqlvars = {} 699 699 for i, n in ipairs(lib.store.noticetype.members) do 700 - sqlvars['notice:' .. n] = lib.store.noticetype[n] 700 + sqlvars['notice:' .. n] = lib.store.noticetype[n]:asvalue() 701 701 end 702 702 703 703 for i, n in ipairs(lib.store.relation.members) do 704 704 sqlvars['rel:' .. n] = lib.store.relation.idvmap[n] 705 705 end 706 706 707 707 local con = symbol(&lib.pq.PGconn) ................................................................................ 847 847 else p.ptr.chgcount = r:int(uint32,row,11) 848 848 end 849 849 p.ptr.accent = r:int(int16,row,12) 850 850 p.ptr.rtdby = r:int(uint64,row,13) 851 851 p.ptr.rtact = r:int(uint64,row,14) 852 852 p.ptr.likes = r:int(uint32,row,15) 853 853 p.ptr.rts = r:int(uint32,row,16) 854 + p.ptr.isreply = r:bool(row,17) 854 855 p.ptr.localpost = r:bool(row,0) 855 856 856 857 return p 857 858 end 858 859 local terra row_to_actor(r: &pqr, row: intptr): lib.mem.ptr(lib.store.actor) 859 860 var a: lib.mem.ptr(lib.store.actor) 860 861 var av: rawstring, avlen: intptr ................................................................................ 1416 1417 return r 1417 1418 end]; 1418 1419 1419 1420 actor_purge_uid = [terra( 1420 1421 src: &lib.store.source, 1421 1422 uid: uint64 1422 1423 ) queries.actor_purge_uid.exec(src,uid) end]; 1424 + 1425 + actor_notice_enum = [terra( 1426 + src: &lib.store.source, 1427 + uid: uint64 1428 + ): lib.mem.ptr(lib.store.notice) 1429 + var r = queries.actor_notice_enum.exec(src,uid); 1430 + if r.sz == 0 then return [lib.mem.ptr(lib.store.notice)].null() end 1431 + defer r:free() 1432 + 1433 + var notes = lib.mem.heapa(lib.store.notice, r.sz) 1434 + for i=0, r.sz do 1435 + var n = notes.ptr + i 1436 + n.kind = r:int(uint16,i,0) 1437 + n.when = r:int(int64,i,1) 1438 + n.who = r:int(int64,i,2) 1439 + n.what = r:int(uint64,i,3) 1440 + if n.kind == lib.store.noticetype.reply then 1441 + n.reply = r:int(uint64,i,4) 1442 + elseif n.kind == lib.store.noticetype.react then 1443 + var react = r:_string(i,5) 1444 + lib.str.ncpy(n.reaction, react.ptr, lib.math.smallest(react.ct,[(`n.reaction).tree.type.N])) 1445 + end 1446 + end 1447 + 1448 + return notes 1449 + end]; 1423 1450 1424 1451 auth_enum_uid = [terra( 1425 1452 src: &lib.store.source, 1426 1453 uid: uint64 1427 1454 ): lib.mem.ptr(lib.mem.ptr(lib.store.auth)) 1428 1455 var r = queries.auth_enum_uid.exec(src,uid) 1429 1456 if r.sz == 0 then return [lib.mem.ptr(lib.mem.ptr(lib.store.auth))].null() end
Modified backend/schema/pgsql-views.sql from [54b7851d27] to [d567971842].
70 70 body text, 71 71 posted bigint, 72 72 discovered bigint, 73 73 edited bigint, 74 74 parent bigint, 75 75 convoheaduri text, 76 76 chgcount integer, 77 +-- ephemeral 77 78 accent smallint, 78 79 rtdby bigint, -- note that these must be 0 if the record 79 80 rtid bigint, -- in question does not represent an RT! 80 81 n_likes integer, 81 - n_rts integer 82 + n_rts integer, 83 + isreply bool -- true if parent in (table posts); saves us a bunch of queries 82 84 ); 83 85 84 86 create or replace function 85 87 pg_temp.parsavpg_translate_post(parsav_posts,bigint,bigint) 86 88 returns pg_temp.parsavpg_intern_post as $$ 87 89 select a.origin is null, 88 90 ($1).id, ($1).author, 89 91 ($1).subject,($1).acl, ($1).body, 90 92 ($1).posted, ($1).discovered, ($1).edited, 91 93 ($1).parent, ($1).convoheaduri,($1).chgcount, 92 94 coalesce(c.value, -1)::smallint, 93 95 $2 as rtdby, $3 as rtid, 94 - re.likes, re.rts 96 + re.likes, re.rts, 97 + ($1).parent in (select id from parsav_posts) 95 98 from parsav_actors as a 96 99 left join parsav_actor_conf_ints as c 97 100 on c.key = 'ui-accent' and 98 101 c.uid = a.id 99 102 left join pg_temp.parsavpg_post_react_counts as re 100 103 on re.post = ($1).id 101 104 where a.id = ($1).author
Modified config.lua from [5768880cb8] to [eb323f3b45].
56 56 {'default-avatar.webp', 'image/webp'}; -- needs inkscape-exclusive svg features 57 57 {'bell.svg', 'image/svg+xml'}; 58 58 {'heart.webp', 'image/webp'}; 59 59 {'retweet.webp', 'image/webp'}; 60 60 {'padlock.svg', 'image/svg+xml'}; 61 61 {'warn.svg', 'image/svg+xml'}; 62 62 {'query.webp', 'image/webp'}; 63 + {'reply.webp', 'image/webp'}; 64 + -- keep in mind before you add anything to this list: these are not 65 + -- just files parsav can access, they are files that are *kept in 66 + -- memory* for fast access the entire time parsav is running, and 67 + -- which need to be loaded into memory before the program can even 68 + -- start. it's imperative to keep these as small and few in number 69 + -- as is realistically possible. 63 70 }; 64 71 default_ui_accent = tonumber(default('parsav_ui_default_accent',323)); 65 72 } 66 73 if os.getenv('parsav_let_me_be_an_idiot') == "i know what i'm doing" then 67 74 conf.braingeniousmode = true -- SOUND GENERAL QUARTERS 68 75 end 69 76 if u.ping '.fslckout' or u.ping '_FOSSIL_' then
Modified makefile from [5c5158676d] to [0e9ec3efb8].
1 1 dl = git 2 2 dbg-flags = $(if $(dbg),-g) 3 3 4 -images = static/default-avatar.webp static/query.webp static/heart.webp static/retweet.webp 4 +images = static/default-avatar.webp static/query.webp static/heart.webp static/retweet.webp static/reply.webp 5 5 #$(addsuffix .webp, $(basename $(wildcard static/*.svg))) 6 6 styles = $(addsuffix .css, $(basename $(wildcard static/*.scss))) 7 7 8 8 parsav parsavd: parsav.t config.lua pkgdata.lua $(images) $(styles) 9 9 terra $(dbg-flags) $< 10 10 parsav.o parsavd.o: parsav.t config.lua pkgdata.lua $(images) $(styles) 11 11 env parsav_link=no terra $(dbg-flags) $<
Modified parsav.t from [5b9672ebb4] to [8bdefbaeb6].
238 238 local ty = uint8 239 239 if #tbl >= 2^32 then ty = uint64 -- hey, can't be too safe 240 240 elseif #tbl >= 2^16 then ty = uint32 241 241 elseif #tbl >= 2^8 then ty = uint16 end 242 242 local o = { t = ty, members = tbl } 243 243 local strings = {} 244 244 for i, name in ipairs(tbl) do 245 - o[name] = i - 1 245 + o[name] = `[ty]([i - 1]) 246 246 strings[i] = `[lib.mem.ref(int8)]{ptr=[name], ct=[#name]} 247 247 end 248 248 o._str = terra(val: ty) 249 249 var l = array([strings]) 250 250 return l[val] 251 251 end 252 252 return o ................................................................................ 433 433 'render:login'; 434 434 'render:profile'; 435 435 'render:compose'; 436 436 'render:tweet'; 437 437 'render:tweet-page'; 438 438 'render:user-page'; 439 439 'render:timeline'; 440 + 'render:notices'; 440 441 441 442 'render:docpage'; 442 443 443 444 'render:conf:profile'; 444 445 'render:conf:sec'; 445 446 'render:conf:users'; 446 447 'render:conf';
Added render/notices.t version [99b348e685].
1 +-- vim: ft=terra 2 +local pstr = lib.mem.ptr(int8) 3 +local P = lib.str.plit 4 +local terra cs(s: rawstring) 5 + return pstr { ptr = s, ct = lib.str.sz(s) } 6 +end 7 + 8 +local terra 9 +render_notices( 10 + co: &lib.srv.convo 11 +): {} 12 + var notes = co.srv:actor_notice_enum(co.who.id) 13 + 14 + if notes.ct == 0 then 15 + co:complain(200,'no news is good news',"you don't have any notices to review") 16 + return 17 + end 18 + defer notes:free() 19 + 20 + var pg: lib.str.acc pg:init(512) defer pg:free() 21 + var pflink: lib.str.acc pflink:init(64) 22 + var body: lib.str.acc body:init(256) 23 + var latest: lib.store.timepoint = 0 24 + for i=0,notes.ct do 25 + if notes(i).when > latest then latest = notes(i).when end 26 + var who = co.srv:actor_fetch_uid(notes(i).who) defer who:free() 27 + if not who then lib.bail('schema integrity violation: nonexistent actor referenced in notification, this is almost certainly an SQL error or bug in the backend implementation') end 28 + pflink:cue(lib.str.sz(who(0).xid) + 4) 29 + if who(0).origin == 0 then pflink:lpush('/') 30 + else pflink:lpush('/@') end 31 + pflink:push(who(0).xid,0) 32 + var n = data.view.notice { 33 + avatar = cs(who(0).avatar); 34 + nym = lib.render.nym(who.ptr,0,nil,true); 35 + pflink = pstr{ptr = pflink.buf; ct = pflink.sz}; 36 + } 37 + var notweet = true 38 + var what = co.srv:post_fetch(notes(i).what) defer what:free() 39 + switch notes(i).kind do 40 + case lib.store.noticetype.rt then 41 + n.kind = P'rt' 42 + n.act = P'retweeted your post' 43 + end 44 + case lib.store.noticetype.like then 45 + n.kind = P'like' 46 + n.act = P'likes your post' 47 + end 48 + case lib.store.noticetype.reply then 49 + n.kind = P'reply' 50 + n.act = P'replied to your post' 51 + notweet = false 52 + end 53 + else goto skip end 54 + do var idbuf: int8[lib.math.shorthand.maxlen] 55 + var idlen = lib.math.shorthand.gen(notes(i).what, idbuf) 56 + var b = lib.smackdown.html(pstr {ptr=what(0).body,ct=0},true) defer b:free() 57 + body:lpush(' <a class="quote" href="/post/'):push(&idbuf[0],idlen):lpush('">'):ppush(b):lpush('</a>') 58 + end 59 + if not notweet then 60 + var reply = co.srv:post_fetch(notes(i).reply) 61 + lib.render.tweet(co,reply.ptr,&body) 62 + reply:free() 63 + end 64 + n.ref = pstr {ptr = body.buf, ct = body.sz} 65 + 66 + n:append(&pg) 67 + ::skip:: n.nym:free() 68 + pflink:reset() 69 + body:reset() 70 + end 71 + pflink:free() 72 + pg:lpush('<form method="post"><button name="act" value="clear">clear all notices</button></form>') 73 + co:livepage([lib.srv.convo.page] { 74 + title = P'notices', class = P'notices'; 75 + body = pstr {ptr = pg.buf, ct = pg.sz}; 76 + cache = false; 77 + }, latest) 78 +end 79 + 80 +return render_notices
Modified render/profile.t from [edefc21455] to [3525ca58bc].
34 34 var stats = co.srv:actor_stats(actor.id) 35 35 var sn_posts = cs(lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ])) 36 36 var sn_follows = cs(lib.math.decstr_friendly(stats.follows, sn_posts.ptr - 1)) 37 37 var sn_followers = cs(lib.math.decstr_friendly(stats.followers, sn_follows.ptr - 1)) 38 38 var sn_mutuals = cs(lib.math.decstr_friendly(stats.mutuals, sn_followers.ptr - 1)) 39 39 var bio = lib.str.plit '<em style="opacity:0.6">tall, dark, and mysterious</em>' 40 40 if actor.bio ~= nil then 41 - bio = lib.smackdown.html(cs(actor.bio)) 41 + bio = lib.smackdown.html(cs(actor.bio),false) 42 42 end 43 43 var fullname = lib.render.nym(actor,0,nil,false) defer fullname:free() 44 44 var comments: lib.str.acc comments:init(64) 45 45 46 46 if co.srv.cfg.master == actor.id then 47 47 var foundertxt = lib.str.plit 'founder' 48 48 if co.srv.cfg.ui_cue_founder:ref() then
Modified render/tweet.t from [8bee6c6ab8] to [0700e85db2].
37 37 ::foundauth:: 38 38 var avistr: lib.str.acc if author.origin == 0 then 39 39 avistr:compose('/avi/',author.handle) 40 40 end 41 41 var timestr: int8[26] lib.osclock.ctime_r(&p.posted, ×tr[0]) 42 42 for i=0,26 do if timestr[i] == @'\n' then timestr[i] = 0 break end end -- 🙄 43 43 44 - var bhtml = lib.smackdown.html([lib.mem.ptr(int8)] {ptr=p.body,ct=0}) 44 + var bhtml = lib.smackdown.html([lib.mem.ptr(int8)] {ptr=p.body,ct=0},false) 45 45 defer bhtml:free() 46 46 47 47 var idbuf: int8[lib.math.shorthand.maxlen] 48 48 var idlen = lib.math.shorthand.gen(p.id, idbuf) 49 49 var permalink: lib.str.acc permalink:compose('/post/',{idbuf,idlen}) 50 50 var fullname = lib.render.nym(author,0,nil, false) defer fullname:free() 51 51 var tpl = data.view.tweet { ................................................................................ 54 54 nym = fullname; 55 55 when = cs(×tr[0]); 56 56 avatar = cs(author.avatar); 57 57 acctlink = cs(author.xid); 58 58 permalink = permalink:finalize(); 59 59 attr = pstr{'',0}; 60 60 stats = pstr{'',0}; 61 + extra = pstr{'',0}; 61 62 } 63 + if p.isreply then 64 + var parent = co.srv:post_fetch(p.parent) defer parent:free() 65 + if not parent then 66 + lib.bail('schema integrity violation - could not match post to parent') 67 + end 68 + var pauth = co.srv:actor_fetch_uid(parent(0).author) defer pauth:free() 69 + var pidbuf: int8[lib.math.shorthand.maxlen] 70 + var pidlen = lib.math.shorthand.gen(p.parent, pidbuf) 71 + var pa: lib.str.acc pa:init(128) 72 + pa:lpush('<small>in reply to <a class="username" href="'):push(&pidbuf[0],pidlen):lpush('">') 73 + lib.render.nym(pauth.ptr,0,&pa,true) 74 + pa:lpush('</a></small>') 75 + tpl.extra = pa:finalize() 76 + end 62 77 if p.rts + p.likes > 0 then 63 78 var s: lib.str.acc s:init(128) 64 79 s:lpush('<div class="stats">') 65 80 if p.rts > 0 then s:lpush('<div class="rt">' ):dpush(p.rts ):lpush('</div>') end 66 81 if p.likes > 0 then s:lpush('<div class="like">'):dpush(p.likes):lpush('</div>') end 67 82 s:lpush('</div>') 68 83 tpl.stats = s:finalize() ................................................................................ 85 100 86 101 defer tpl.permalink:free() 87 102 if acc ~= nil then 88 103 if retweeter ~= nil then push_promo_header(co, acc, retweeter, p.rtact) end 89 104 tpl:append(acc) 90 105 if retweeter ~= nil then acc:lpush('</div>') end 91 106 if p.rts + p.likes > 0 then tpl.stats:free() end 107 + if tpl.extra.ct > 0 then tpl.extra:free() end 92 108 return [lib.mem.ptr(int8)]{ptr=nil,ct=0} 93 109 end 94 110 95 111 if retweeter ~= nil then 96 112 var rta: lib.str.acc rta:init(512) 97 113 push_promo_header(co, &rta, retweeter, p.rtact) 98 114 tpl:append(&rta) rta:lpush('</div>') 115 + if tpl.extra.ct > 0 then tpl.extra:free() end 99 116 return rta:finalize() 100 117 else 101 118 var txt = tpl:tostr() 119 + if tpl.extra.ct > 0 then tpl.extra:free() end 102 120 if p.rts + p.likes > 0 then tpl.stats:free() end 103 121 return txt 104 122 end 105 123 end 106 124 return render_tweet
Modified route.t from [cc5cf170ae] to [e8c2143a0c].
164 164 return 165 165 end 166 166 if subj == nil then subj = '' end 167 167 168 168 var p = lib.store.post { 169 169 author = co.who.id, acl = acl; 170 170 body = text, subject = subj; 171 + parent = 0; 171 172 } 172 173 var newid = p:publish(co.srv) 173 174 174 175 var idbuf: int8[lib.math.shorthand.maxlen] 175 176 var idlen = lib.math.shorthand.gen(newid, idbuf) 176 177 var redirto: lib.str.acc redirto:compose('/post/',{idbuf,idlen}) defer redirto:free() 177 178 co:reroute(redirto.buf) ................................................................................ 380 381 end 381 382 end 382 383 lib.render.conf(co,path,msg) 383 384 do return end 384 385 385 386 ::nopriv:: co:complain(403,'insufficient privileges','you do not have the necessary powers to perform this action') 386 387 end 388 + 389 +terra http.user_notices(co: &lib.srv.convo, meth: method.t) 390 + if meth == method.post then 391 + var act = co:ppostv('act') 392 + if act:cmp(lib.str.plit'clear') then 393 + co.srv:actor_conf_int_set(co.who.id, 'notice-clear-time', lib.osclock.time(nil)) 394 + co:reroute('/') 395 + return 396 + else goto badop end 397 + end 398 + 399 + lib.render.notices(co) 400 + do return end 401 + 402 + ::badop :: do co:complain(405, 'invalid operation', 'the operation you have attempted on this post is not meaningful') return end 403 +end 387 404 388 405 do local branches = quote end 389 406 local filename, flen = symbol(&int8), symbol(intptr) 390 407 local page = symbol(lib.http.page) 391 408 local send = label() 392 409 local storage = data.stmap 393 410 for i,e in ipairs(config.embeds) do local id,mime = e[1],e[2] ................................................................................ 442 459 elseif uri.ptr[1] == @'@' then 443 460 http.actor_profile_xid(co, uri, meth) 444 461 elseif uri.ptr[1] == @'s' and uri.ptr[2] == @'/' and uri.ct > 3 then 445 462 if not meth_get(meth) then goto wrongmeth end 446 463 if not http.static_content(co, uri.ptr + 3, uri.ct - 3) then goto notfound end 447 464 elseif lib.str.ncmp('/avi/', uri.ptr, 5) == 0 then 448 465 http.local_avatar(co, [lib.mem.ptr(int8)] {ptr = uri.ptr + 5, ct = uri.ct - 5}) 449 - elseif lib.str.ncmp('/compose', uri.ptr, lib.math.biggest(uri.ct,8)) == 0 then 466 + elseif uri:cmp(lib.str.plit '/notices') then 467 + if co.aid == 0 then co:reroute('/login') return end 468 + http.user_notices(co,meth) 469 + elseif uri:cmp(lib.str.plit '/compose') then 450 470 if co.aid == 0 then co:reroute('/login') return end 451 471 http.post_compose(co,meth) 452 - elseif lib.str.ncmp('/login', uri.ptr, lib.math.biggest(uri.ct,6)) == 0 then 472 + elseif uri:cmp(lib.str.plit '/login') then 453 473 if co.aid == 0 454 474 then http.login_form(co, meth) 455 475 else co:reroute('/') 456 476 end 457 - elseif lib.str.ncmp('/logout', uri.ptr, lib.math.biggest(uri.ct,7)) == 0 then 477 + elseif uri:cmp(lib.str.plit '/logout') then 458 478 if co.aid == 0 459 479 then goto notfound 460 480 else co:reroute_cookie('/','auth=; Path=/') 461 481 end 462 482 else -- hierarchical routes 463 483 var path = lib.http.hier(uri) defer path:free() 464 484 if path.ct > 1 and path(0):cmp(lib.str.lit('user')) then
Modified smackdown.t from [c51eb8a6b2] to [926ec15b69].
52 52 local terra scanline_wordend(l: rawstring, max: intptr, n: rawstring, nc: intptr) 53 53 var sl = scanline(l,max,n,nc) 54 54 if sl == nil then return nil else sl = sl + nc end 55 55 if sl >= l+max or isws(@sl) then return sl-nc end 56 56 return nil 57 57 end 58 58 59 -terra m.html(input: pstr) 59 +terra m.html(input: pstr, firstline: bool) 60 60 if input.ct == 0 then input.ct = lib.str.sz(input.ptr) end 61 61 62 62 var md = lib.html.sanitize(input,false) 63 63 64 64 var styled: lib.str.acc styled:init(md.ct) 65 65 66 66 do var i = 0 while i < md.ct do
Added static/reply.svg version [0a0b88e351].
1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 +<!-- Created with Inkscape (http://www.inkscape.org/) --> 3 + 4 +<svg 5 + xmlns:dc="http://purl.org/dc/elements/1.1/" 6 + xmlns:cc="http://creativecommons.org/ns#" 7 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 8 + xmlns:svg="http://www.w3.org/2000/svg" 9 + xmlns="http://www.w3.org/2000/svg" 10 + xmlns:xlink="http://www.w3.org/1999/xlink" 11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 12 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 13 + width="20" 14 + height="20" 15 + viewBox="0 0 5.2916664 5.2916665" 16 + version="1.1" 17 + id="svg8" 18 + inkscape:version="0.92.4 (5da689c313, 2019-01-14)" 19 + sodipodi:docname="reply.svg"> 20 + <defs 21 + id="defs2"> 22 + <linearGradient 23 + inkscape:collect="always" 24 + id="linearGradient954"> 25 + <stop 26 + style="stop-color:#ffffff;stop-opacity:1;" 27 + offset="0" 28 + id="stop950" /> 29 + <stop 30 + style="stop-color:#ffffff;stop-opacity:0;" 31 + offset="1" 32 + id="stop952" /> 33 + </linearGradient> 34 + <linearGradient 35 + inkscape:collect="always" 36 + id="linearGradient938"> 37 + <stop 38 + style="stop-color:#d9fff6;stop-opacity:1;" 39 + offset="0" 40 + id="stop934" /> 41 + <stop 42 + style="stop-color:#d9fff6;stop-opacity:0;" 43 + offset="1" 44 + id="stop936" /> 45 + </linearGradient> 46 + <linearGradient 47 + inkscape:collect="always" 48 + id="linearGradient1403"> 49 + <stop 50 + style="stop-color:#ccaaff;stop-opacity:1;" 51 + offset="0" 52 + id="stop1399" /> 53 + <stop 54 + style="stop-color:#ccaaff;stop-opacity:0;" 55 + offset="1" 56 + id="stop1401" /> 57 + </linearGradient> 58 + <linearGradient 59 + id="linearGradient1395" 60 + inkscape:collect="always"> 61 + <stop 62 + id="stop1391" 63 + offset="0" 64 + style="stop-color:#ff1616;stop-opacity:1" /> 65 + <stop 66 + id="stop1393" 67 + offset="1" 68 + style="stop-color:#ff1d1d;stop-opacity:0" /> 69 + </linearGradient> 70 + <linearGradient 71 + inkscape:collect="always" 72 + id="linearGradient1383"> 73 + <stop 74 + style="stop-color:#980000;stop-opacity:1;" 75 + offset="0" 76 + id="stop1379" /> 77 + <stop 78 + style="stop-color:#980000;stop-opacity:0;" 79 + offset="1" 80 + id="stop1381" /> 81 + </linearGradient> 82 + <linearGradient 83 + inkscape:collect="always" 84 + id="linearGradient832"> 85 + <stop 86 + style="stop-color:#ffcfcf;stop-opacity:1;" 87 + offset="0" 88 + id="stop828" /> 89 + <stop 90 + style="stop-color:#ffcfcf;stop-opacity:0;" 91 + offset="1" 92 + id="stop830" /> 93 + </linearGradient> 94 + <radialGradient 95 + inkscape:collect="always" 96 + xlink:href="#linearGradient832" 97 + id="radialGradient834" 98 + cx="3.2286437" 99 + cy="286.62921" 100 + fx="3.2286437" 101 + fy="286.62921" 102 + r="1.0866126" 103 + gradientTransform="matrix(1.8608797,0.8147617,-0.38242057,0.87343168,106.71446,33.692223)" 104 + gradientUnits="userSpaceOnUse" /> 105 + <radialGradient 106 + inkscape:collect="always" 107 + xlink:href="#linearGradient1383" 108 + id="radialGradient1385" 109 + cx="4.1787109" 110 + cy="286.89261" 111 + fx="4.1787109" 112 + fy="286.89261" 113 + r="1.2260786" 114 + gradientTransform="matrix(1.7016464,0,0,1.6348586,-2.9319775,-182.10895)" 115 + gradientUnits="userSpaceOnUse" /> 116 + <radialGradient 117 + inkscape:collect="always" 118 + xlink:href="#linearGradient1395" 119 + id="radialGradient1389" 120 + gradientUnits="userSpaceOnUse" 121 + gradientTransform="matrix(0.66230313,-1.6430738,1.0154487,0.40931507,-290.06307,177.39489)" 122 + cx="4.02069" 123 + cy="287.79269" 124 + fx="4.02069" 125 + fy="287.79269" 126 + r="1.0866126" /> 127 + <linearGradient 128 + inkscape:collect="always" 129 + xlink:href="#linearGradient1403" 130 + id="linearGradient1405" 131 + x1="8.3939333" 132 + y1="288.1091" 133 + x2="7.0158253" 134 + y2="287.32819" 135 + gradientUnits="userSpaceOnUse" /> 136 + <linearGradient 137 + inkscape:collect="always" 138 + xlink:href="#linearGradient938" 139 + id="linearGradient940" 140 + x1="7.609839" 141 + y1="288.73215" 142 + x2="7.609839" 143 + y2="283.78305" 144 + gradientUnits="userSpaceOnUse" /> 145 + <linearGradient 146 + inkscape:collect="always" 147 + xlink:href="#linearGradient954" 148 + id="linearGradient956" 149 + x1="3.0150654" 150 + y1="285.94464" 151 + x2="3.0150654" 152 + y2="282.40109" 153 + gradientUnits="userSpaceOnUse" /> 154 + <linearGradient 155 + inkscape:collect="always" 156 + xlink:href="#linearGradient938" 157 + id="linearGradient960" 158 + gradientUnits="userSpaceOnUse" 159 + x1="7.609839" 160 + y1="288.73215" 161 + x2="7.609839" 162 + y2="283.78305" /> 163 + <linearGradient 164 + inkscape:collect="always" 165 + xlink:href="#linearGradient954" 166 + id="linearGradient1138" 167 + gradientUnits="userSpaceOnUse" 168 + x1="3.0150654" 169 + y1="285.94464" 170 + x2="3.0150654" 171 + y2="284.62277" /> 172 + <linearGradient 173 + inkscape:collect="always" 174 + xlink:href="#linearGradient938" 175 + id="linearGradient1150" 176 + gradientUnits="userSpaceOnUse" 177 + x1="7.609839" 178 + y1="288.73215" 179 + x2="7.609839" 180 + y2="283.78305" /> 181 + <linearGradient 182 + inkscape:collect="always" 183 + xlink:href="#linearGradient938" 184 + id="linearGradient1152" 185 + gradientUnits="userSpaceOnUse" 186 + x1="7.609839" 187 + y1="288.73215" 188 + x2="7.609839" 189 + y2="283.78305" 190 + gradientTransform="translate(-3.1738256,6.8821903)" /> 191 + <linearGradient 192 + inkscape:collect="always" 193 + xlink:href="#linearGradient954" 194 + id="linearGradient1154" 195 + gradientUnits="userSpaceOnUse" 196 + x1="3.0150654" 197 + y1="285.94464" 198 + x2="3.0150654" 199 + y2="282.40109" 200 + gradientTransform="translate(-3.1738256,6.8821903)" /> 201 + <linearGradient 202 + inkscape:collect="always" 203 + xlink:href="#linearGradient954" 204 + id="linearGradient1156" 205 + gradientUnits="userSpaceOnUse" 206 + x1="3.0150654" 207 + y1="285.94464" 208 + x2="3.0150654" 209 + y2="284.62277" /> 210 + <linearGradient 211 + inkscape:collect="always" 212 + xlink:href="#linearGradient938" 213 + id="linearGradient1170" 214 + gradientUnits="userSpaceOnUse" 215 + x1="7.609839" 216 + y1="288.73215" 217 + x2="7.609839" 218 + y2="283.78305" 219 + gradientTransform="matrix(0.93088299,0,0,0.93088299,0.40825643,19.623427)" /> 220 + <linearGradient 221 + inkscape:collect="always" 222 + xlink:href="#linearGradient954" 223 + id="linearGradient1172" 224 + gradientUnits="userSpaceOnUse" 225 + x1="3.0150654" 226 + y1="285.94464" 227 + x2="3.0150654" 228 + y2="282.40109" 229 + gradientTransform="matrix(0.93088299,0,0,0.93088299,0.40825643,19.623427)" /> 230 + <linearGradient 231 + inkscape:collect="always" 232 + xlink:href="#linearGradient954" 233 + id="linearGradient1174" 234 + gradientUnits="userSpaceOnUse" 235 + x1="3.0150654" 236 + y1="285.94464" 237 + x2="3.0150654" 238 + y2="284.62277" /> 239 + </defs> 240 + <sodipodi:namedview 241 + id="base" 242 + pagecolor="#181818" 243 + bordercolor="#666666" 244 + borderopacity="1.0" 245 + inkscape:pageopacity="0" 246 + inkscape:pageshadow="2" 247 + inkscape:zoom="3.959798" 248 + inkscape:cx="0.97863268" 249 + inkscape:cy="46.024492" 250 + inkscape:document-units="mm" 251 + inkscape:current-layer="layer1" 252 + showgrid="false" 253 + units="px" 254 + inkscape:window-width="1920" 255 + inkscape:window-height="1042" 256 + inkscape:window-x="0" 257 + inkscape:window-y="38" 258 + inkscape:window-maximized="0" 259 + showguides="false" 260 + fit-margin-top="0" 261 + fit-margin-left="0" 262 + fit-margin-right="0" 263 + fit-margin-bottom="0" /> 264 + <metadata 265 + id="metadata5"> 266 + <rdf:RDF> 267 + <cc:Work 268 + rdf:about=""> 269 + <dc:format>image/svg+xml</dc:format> 270 + <dc:type 271 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 272 + <dc:title></dc:title> 273 + </cc:Work> 274 + </rdf:RDF> 275 + </metadata> 276 + <g 277 + inkscape:label="Layer 1" 278 + inkscape:groupmode="layer" 279 + id="layer1" 280 + transform="translate(-2.6134661,-283.36966)"> 281 + <g 282 + id="g1168" 283 + transform="matrix(0.92817904,-0.24870482,0.24870482,0.92817904,-70.834504,21.905842)" 284 + style="stroke-width:1.04066753"> 285 + <path 286 + d="m 3.1152344,284.35547 c -0.1591337,0 -0.2949219,0.13579 -0.2949219,0.29492 v 2.9668 c 0,0.15913 0.1357882,0.29492 0.2949219,0.29492 h 4.3945312 c 0.1591337,0 0.2949219,-0.13579 0.2949219,-0.29492 v -2.9668 c 0,-0.15913 -0.1357882,-0.29492 -0.2949219,-0.29492 z" 287 + id="rect958" 288 + style="opacity:0.25200004;vector-effect:none;fill:url(#linearGradient960);fill-opacity:1;stroke:none;stroke-width:0.18445945;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 289 + inkscape:original="M 3.1152344 284.55078 C 3.0598344 284.55078 3.015625 284.59499 3.015625 284.65039 L 3.015625 287.61719 C 3.015625 287.67259 3.0598344 287.7168 3.1152344 287.7168 L 7.5097656 287.7168 C 7.5651656 287.7168 7.609375 287.67259 7.609375 287.61719 L 7.609375 284.65039 C 7.609375 284.59499 7.5651656 284.55078 7.5097656 284.55078 L 3.1152344 284.55078 z " 290 + inkscape:radius="0.19498466" 291 + sodipodi:type="inkscape:offset" 292 + transform="matrix(0.93088299,0,0,0.93088299,0.40825643,19.623427)" /> 293 + <rect 294 + rx="0.093088299" 295 + y="284.50693" 296 + x="3.2149298" 297 + height="2.9467573" 298 + width="4.2771964" 299 + id="rect932" 300 + style="opacity:1;vector-effect:none;fill:url(#linearGradient1170);fill-opacity:1;stroke:none;stroke-width:0.17171016;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> 301 + <path 302 + d="m 3.015625,284.38867 a 0.16537863,0.16537863 0 0 0 -0.089844,0.30469 l 2.296875,1.50391 a 0.16537863,0.16537863 0 0 0 0.1796876,0 l 2.296875,-1.50391 a 0.16537863,0.16537863 0 0 0 -0.089844,-0.30469 z" 303 + id="path1136" 304 + style="opacity:0.13699999;fill:url(#linearGradient1174);fill-opacity:1;stroke:none;stroke-width:0.18445943;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 305 + inkscape:original="M 3.015625 284.55469 L 5.3125 286.05859 L 7.609375 284.55469 L 3.015625 284.55469 z " 306 + inkscape:radius="0.16536209" 307 + sodipodi:type="inkscape:offset" 308 + transform="matrix(0.93088299,0,0,0.93088299,0.40825643,19.623427)" /> 309 + <path 310 + sodipodi:nodetypes="cccc" 311 + inkscape:connector-curvature="0" 312 + d="M 7.4105013,284.507 5.3535277,285.91094 3.3022018,284.5076 Z" 313 + style="fill:url(#linearGradient1172);fill-opacity:1;stroke:none;stroke-width:0.17171013;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 314 + id="path929" /> 315 + </g> 316 + <g 317 + id="g1162"> 318 + <path 319 + transform="translate(-3.1738256,6.8821903)" 320 + sodipodi:type="inkscape:offset" 321 + inkscape:radius="0.19498466" 322 + inkscape:original="M 3.1152344 284.55078 C 3.0598344 284.55078 3.015625 284.59499 3.015625 284.65039 L 3.015625 287.61719 C 3.015625 287.67259 3.0598344 287.7168 3.1152344 287.7168 L 7.5097656 287.7168 C 7.5651656 287.7168 7.609375 287.67259 7.609375 287.61719 L 7.609375 284.65039 C 7.609375 284.59499 7.5651656 284.55078 7.5097656 284.55078 L 3.1152344 284.55078 z " 323 + style="opacity:0.25200004;vector-effect:none;fill:url(#linearGradient1150);fill-opacity:1;stroke:none;stroke-width:0.16500001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 324 + id="path1142" 325 + d="m 3.1152344,284.35547 c -0.1591337,0 -0.2949219,0.13579 -0.2949219,0.29492 v 2.9668 c 0,0.15913 0.1357882,0.29492 0.2949219,0.29492 h 4.3945312 c 0.1591337,0 0.2949219,-0.13579 0.2949219,-0.29492 v -2.9668 c 0,-0.15913 -0.1357882,-0.29492 -0.2949219,-0.29492 z" /> 326 + <rect 327 + style="opacity:1;vector-effect:none;fill:url(#linearGradient1152);fill-opacity:1;stroke:none;stroke-width:0.16500001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" 328 + id="rect1144" 329 + width="4.5947733" 330 + height="3.1655507" 331 + x="-0.15875995" 332 + y="291.43301" 333 + rx="0.1" /> 334 + <path 335 + id="path1146" 336 + style="fill:url(#linearGradient1154);fill-opacity:1;stroke:none;stroke-width:0.16499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 337 + d="m 4.4360131,291.43669 -2.2973866,1.50456 -2.29738662,-1.50456 z" 338 + inkscape:connector-curvature="0" 339 + sodipodi:nodetypes="cccc" /> 340 + <path 341 + transform="translate(-3.1738256,6.8821903)" 342 + sodipodi:type="inkscape:offset" 343 + inkscape:radius="0.16536209" 344 + inkscape:original="M 3.015625 284.55469 L 5.3125 286.05859 L 7.609375 284.55469 L 3.015625 284.55469 z " 345 + style="opacity:0.13699999;fill:url(#linearGradient1156);fill-opacity:1;stroke:none;stroke-width:0.16499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" 346 + id="path1148" 347 + d="m 3.015625,284.38867 a 0.16537863,0.16537863 0 0 0 -0.089844,0.30469 l 2.296875,1.50391 a 0.16537863,0.16537863 0 0 0 0.1796876,0 l 2.296875,-1.50391 a 0.16537863,0.16537863 0 0 0 -0.089844,-0.30469 z" /> 348 + </g> 349 + </g> 350 +</svg>
Modified static/style.scss from [dc435bcc7e] to [fa60ad7c82].
224 224 transform: scale(1.2); 225 225 } 226 226 } 227 227 > a[href].bell { 228 228 content: url(/s/bell.svg); 229 229 height: 2em; 230 230 padding: 0.125in 0.10in; 231 + filter: drop-shadow(1px 1px 3px tone(-5%)); 231 232 &:hover { 232 - filter: drop-shadow(0 0 10px tone(-5%)); 233 + filter: drop-shadow(1px 1px 3px tone(-5%)) 234 + drop-shadow(0 0 10px tone(-5%)); 233 235 } 234 236 } 235 237 } 236 238 } 237 239 } 238 240 239 241 main { ................................................................................ 380 382 padding: 0.4in; 381 383 > .msg { 382 384 text-align: center; 383 385 padding: 0.3in; 384 386 } 385 387 > .msg:first-child { padding-top: 0; } 386 388 > .user { 387 - width: min-content; margin: auto; 389 + width: max-content; margin: auto; 388 390 background: tone(-20%,-0.3); 389 391 border: 1px solid black; 390 392 color: tone(-50%); 391 393 padding: 0.1in; 392 - > img { width: 1in; height: 1in; border: 1px solid black; } 394 + > img { display: block; width: 1in; height: 1in; margin: auto; border: 1px solid black; } 393 395 > .name { @extend %serif; text-align: center; font-size: 130%; font-weight: bold; margin-top: 0.08in; } 394 396 } 395 397 >form { 396 398 display: grid; 397 399 grid-template-columns: 1fr 1fr; 398 400 grid-template-rows: 1.2em 1fr 1fr; 399 401 grid-gap: 5px; ................................................................................ 535 537 font-size: 110%; 536 538 text-align: justify; 537 539 color: tone(25%); 538 540 } 539 541 > a[href].permalink { 540 542 display: block; 541 543 grid-column: 4/5; grid-row: 2/3; 542 - font-size: 80%; 544 + font-size: 90%; 543 545 text-align: right; 544 546 padding: 0.1in; 545 547 padding-right: 0.15in; 546 548 font-style: italic; 547 549 background: linear-gradient(to left, tone(-55%,-0.5), transparent); 548 550 } 549 551 div.stats { ................................................................................ 555 557 padding-left: 1.3em; 556 558 background-size: 1.1em; 557 559 background-repeat: no-repeat; 558 560 min-width: 0.3em; 559 561 &:focus { 560 562 outline: none; 561 563 opacity: 0.9 !important; 562 - filter: brightness(1.7) drop-shadow(0 0 15px rgb(255,150,200)); 564 + filter: drop-shadow(0 0 7px tone(-10%)); 563 565 } 564 566 &:empty { 565 567 transition: 0.3s; 566 568 opacity: 0.0001; // qutebrowser won't show hints if opacity=0 :( 567 569 &:hover, &:focus { opacity: 0.6 !important; } 568 570 } 569 571 } ................................................................................ 949 951 grid-row: 1/2; grid-column: 2/3; 950 952 text-decoration: none; 951 953 } 952 954 > .post { 953 955 grid-row: 2/3; grid-column: 1/3; 954 956 } 955 957 } 958 + 959 +body.notices { 960 + form { text-align: center; } 961 + div.notice { 962 + padding: 0.15in; 963 + background: linear-gradient(to bottom, tone(10%, -0.9), transparent); 964 + border: 1px solid tone(-60%); 965 + & + div.notice { border-top: none; } 966 + &.rt, &.like, &.reply { &::before { 967 + display: inline-block; 968 + width: 1em; height: 1em; 969 + margin-right: 1ex; 970 + background-size: contain; 971 + vertical-align: bottom; 972 + content: ""; // 🙄 973 + }} 974 + &.rt::before { background-image: url(/s/retweet.webp); } 975 + &.like::before { background-image: url(/s/heart.webp); } 976 + &.reply::before { background-image: url(/s/reply.webp); } 977 + > .action { 978 + display: inline-block; 979 + color: tone(5%); 980 + > .id { 981 + display: inline-block; 982 + > img { 983 + width: 1em; height: 1em; 984 + vertical-align: middle; 985 + margin-right: 0.5ex; 986 + } 987 + } 988 + } 989 + > a[href].quote { 990 + &::before { content: "“"; } 991 + &::after { content: "”"; } 992 + font-style: italic; color: tone(20%); 993 + text-decoration: none; 994 + } 995 + > article.post { 996 + margin: 0.1in 0.2in; 997 + margin-left: 0.4in; 998 + } 999 + } 1000 +}
Modified store.t from [e1429862ec] to [54fed43947].
7 7 }; 8 8 noticetype = lib.enum { 9 9 'none', 'mention', 'reply', 'like', 'rt', 'react' 10 10 }; 11 11 12 12 relation = lib.set { 13 13 'follow', 14 + 'subscribe', -- get a notification for every post 14 15 'mute', -- posts will be completely hidden at all times 15 16 'block', -- no interactions will be permitted, but posts will remain visible 16 17 'silence', -- messages will not be accepted 17 18 'collapse', -- posts will be collapsed by default 18 19 'disemvowel', -- posts will be ritually humiliated, but shown 19 20 'avoid', -- posts will be kept out of the timeline but will show on users' posts and in conversations 20 21 'exclude', -- own posts will not be visible to this user ................................................................................ 220 221 -- ephemera 221 222 localpost: bool 222 223 accent: int16 223 224 rts: uint32 224 225 likes: uint32 225 226 rtdby: uint64 -- 0 if not rt 226 227 rtact: uint64 -- 0 if not rt, id of rt action otherwise 228 + isreply: bool 227 229 source: &m.source 228 230 229 231 -- save :: bool -> {} (defined in acl.t due to dep. hell) 230 232 } 231 233 232 234 m.user_conf_funcs = function(be,n,ty,rty,rty2) 233 235 rty = rty or ty ................................................................................ 251 253 struct m.notice { 252 254 kind: m.noticetype.t 253 255 when: uint64 254 256 who: uint64 255 257 what: uint64 256 258 union { 257 259 reply: uint64 258 - reaction: int8[16] 260 + reaction: int8[32] -- are you shitting me, unichode 259 261 } 260 262 } 261 263 262 264 struct m.inet { 263 265 pv: uint8 -- 0 = null, 4 = ipv4, 6 = ipv6 264 266 union { 265 267 v4: uint8[4] ................................................................................ 389 391 -- origin: inet 390 392 -- cookie issue time: m.timepoint 391 393 actor_auth_register_uid: {&m.source, uint64, uint64} -> {} 392 394 -- notifies the backend module of the UID that has been assigned for 393 395 -- an authentication ID 394 396 -- aid: uint64 395 397 -- uid: uint64 396 - actor_notice_enum: {&m.source, uint64} -> lib.mem.lstptr(m.notice) 398 + actor_notice_enum: {&m.source, uint64} -> lib.mem.ptr(m.notice) 397 399 actor_rel_create: {&m.source, uint16, uint64, uint64} -> {} 398 400 actor_rel_destroy: {&m.source, uint16, uint64, uint64} -> {} 399 401 actor_rel_calc: {&m.source, uint64, uint64} -> m.relationship 400 402 401 403 auth_enum_uid: {&m.source, uint64} -> lib.mem.lstptr(m.auth) 402 404 auth_enum_handle: {&m.source, rawstring} -> lib.mem.lstptr(m.auth) 403 405 auth_attach_pw: {&m.source, uint64, bool, pstr, pstr} -> {}
Modified str.t from [7fbe47e2ae] to [004fceba8a].
160 160 if sz <= self.run then return end 161 161 self.run = sz 162 162 if self.space - self.sz < self.run then 163 163 self.space = self.sz + self.run 164 164 self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space)) 165 165 end 166 166 end 167 + 168 +terra m.acc:reset() -- semantic convenience function 169 + self.sz = 0 170 +end 167 171 168 172 terra m.acc:push(str: rawstring, len: intptr) 169 173 --var llen = len 170 174 if str == nil then return self end 171 175 --if str[len - 1] == 0xA then llen = llen - 1 end -- don't display newlines in debug output 172 176 -- lib.dbg('pushing "',{str,llen},'" onto accumulator') 173 177 if self.buf == nil then self:init(self.run) end
Modified view/load.lua from [dd2878563c] to [1dbf5e584d].
5 5 local path = ... 6 6 local sources = { 7 7 'docskel'; 8 8 'confirm'; 9 9 'tweet'; 10 10 'profile'; 11 11 'compose'; 12 + 'notice'; 12 13 13 14 'login-username'; 14 15 'login-challenge'; 15 16 16 17 'conf'; 17 18 'conf-profile'; 18 19 'conf-sec';
Added view/notice.tpl version [6c1a6f12b0].
1 +<div class="notice @kind"> 2 + <div class="action"> 3 + <div class="id"> 4 + <img src="@avatar"> 5 + <a class="username" href="@pflink">@nym</a> 6 + </div> @act 7 + </div> @ref 8 +</div>
Modified view/tweet.tpl from [80bcf01f8a] to [5d1f823e24].
1 1 <article class="post"@attr> 2 2 <div class="avatar"><img src="@:avatar"></div> 3 3 <a class="username" href="/@:acctlink">@nym</a> 4 - <div class="content"> 4 + <div class="content">@extra 5 5 <div class="subject">@!subject</div> 6 6 <div class="text">@text</div> 7 7 </div> 8 8 @stats 9 9 <a class="permalink" href="@permalink"><time>@when</time></a> 10 10 </article>