Overview
| Comment: | look ma, im tweetin |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
8f954221a11a00d23ad86812516851d3 |
| User & Date: | lexi on 2020-12-27 04:08:20 |
| Other Links: | manifest | tags |
Context
|
2020-12-28
| ||
| 23:42 | vastly improve the setup process check-in: d228cd7fcb user: lexi tags: trunk | |
|
2020-12-27
| ||
| 04:08 | look ma, im tweetin check-in: 8f954221a1 user: lexi tags: trunk | |
| 02:31 | permissions work now check-in: bbfea467bf user: lexi tags: trunk | |
Changes
Modified backend/pgsql.t from [36b1398523] to [2c2a215381].
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 ... 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 ... 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 |
$1::bigint, case when $2::text = '' then null else $2::text end, $3::text, $4::text, now(), now(), array[]::bigint[], array[]::bigint[] ) returning id ]]; -- TODO array handling }; instance_timeline_fetch = { params = {uint64, uint64, uint64, uint64}, sql = [[ select true, p.id, p.author, p.subject, p.acl, p.body, extract(epoch from p.posted )::bigint, extract(epoch from p.discovered)::bigint, p.parent, null::text from parsav_posts as p ................................................................................ else return pqr {ct, res} end end end local terra row_to_post(r: &pqr, row: intptr): lib.mem.ptr(lib.store.post) --lib.io.fmt("body ptr %p len %llu\n", r:string(row,5), r:len(row,5)) --lib.io.fmt("acl ptr %p len %llu\n", r:string(row,4), r:len(row,4)) var subj: rawstring, sblen: intptr if r:null(row,3) then subj = nil sblen = 0 else subj = r:string(row,3) sblen = r:len(row,3)+1 end var p = [ lib.str.encapsulate(lib.store.post, { subject = { `subj, `sblen }; acl = {`r:string(row,4), `r:len(row,4)+1}; body = {`r:string(row,5), `r:len(row,5)+1}; --convoheaduri = { `nil, `0 }; --FIXME }) ] p.ptr.id = r:int(uint64,row,1) p.ptr.author = r:int(uint64,row,2) p.ptr.posted = r:int(uint64,row,6) p.ptr.discovered = r:int(uint64,row,7) if r:null(row,8) then p.ptr.parent = 0 ................................................................................ var r = queries.post_create.exec(src,post.author,post.subject,post.acl,post.body) if r.sz == 0 then return 0 end defer r:free() var id = r:int(uint64,0,0) return id end]; instance_timeline_fetch = [terra(src: &lib.store.source, rg: lib.store.range) var r = pqr { sz = 0 } if rg.mode == 0 then r = queries.instance_timeline_fetch.exec(src,rg.from_time,rg.to_time,0,0) elseif rg.mode == 1 then r = queries.instance_timeline_fetch.exec(src,rg.from_time,0,rg.to_idx,0) elseif rg.mode == 2 then r = queries.instance_timeline_fetch.exec(src,0,rg.to_time,0,rg.from_idx) elseif rg.mode == 3 then r = queries.instance_timeline_fetch.exec(src,0,0,rg.to_idx,rg.from_idx) end var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz) for i=0,r.sz do ret.ptr[i] = row_to_post(&r, i) end -- MUST FREE ALL return ret end]; |
| > > > > > > > > > > > > > > > > > > > > > < < > > > > > | | | | < > | | < > | < | > > > > > > > > > |
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 ... 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 ... 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 |
$1::bigint, case when $2::text = '' then null else $2::text end, $3::text, $4::text, now(), now(), array[]::bigint[], array[]::bigint[] ) returning id ]]; -- TODO array handling }; post_enum_author_uid = { params = {uint64,uint64,uint64,uint64, uint64}, sql = [[ select a.origin is null, p.id, p.author, p.subject, p.acl, p.body, extract(epoch from p.posted )::bigint, extract(epoch from p.discovered)::bigint, p.parent, p.convoheaduri from parsav_posts as p inner join parsav_actors as a on p.author = a.id where p.author = $5::bigint and ($1::bigint = 0 or p.posted <= to_timestamp($1::bigint)) and ($2::bigint = 0 or to_timestamp($2::bigint) < p.posted) order by (p.posted, p.discovered) desc limit case when $3::bigint = 0 then null else $3::bigint end offset $4::bigint ]] }; -- maybe there's some way to unify these two, idk, im tired timeline_instance_fetch = { params = {uint64, uint64, uint64, uint64}, sql = [[ select true, p.id, p.author, p.subject, p.acl, p.body, extract(epoch from p.posted )::bigint, extract(epoch from p.discovered)::bigint, p.parent, null::text from parsav_posts as p ................................................................................ else return pqr {ct, res} end end end local terra row_to_post(r: &pqr, row: intptr): lib.mem.ptr(lib.store.post) var subj: rawstring, sblen: intptr var cvhu: rawstring, cvhlen: intptr if r:null(row,3) then subj = nil sblen = 0 else subj = r:string(row,3) sblen = r:len(row,3)+1 end if r:null(row,9) then cvhu = nil cvhlen = 0 else cvhu = r:string(row,9) cvhlen = r:len(row,9)+1 end var p = [ lib.str.encapsulate(lib.store.post, { subject = { `subj, `sblen }; acl = {`r:string(row,4), `r:len(row,4)+1}; body = {`r:string(row,5), `r:len(row,5)+1}; convoheaduri = { `cvhu, `cvhlen }; --FIXME }) ] p.ptr.id = r:int(uint64,row,1) p.ptr.author = r:int(uint64,row,2) p.ptr.posted = r:int(uint64,row,6) p.ptr.discovered = r:int(uint64,row,7) if r:null(row,8) then p.ptr.parent = 0 ................................................................................ var r = queries.post_create.exec(src,post.author,post.subject,post.acl,post.body) if r.sz == 0 then return 0 end defer r:free() var id = r:int(uint64,0,0) return id end]; timeline_instance_fetch = [terra(src: &lib.store.source, rg: lib.store.range) var r = pqr { sz = 0 } var A,B,C,D = rg:matrix() -- :/ r = queries.timeline_instance_fetch.exec(src,A,B,C,D) var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz) for i=0,r.sz do ret.ptr[i] = row_to_post(&r, i) end -- MUST FREE ALL return ret end]; post_enum_author_uid = [terra( src: &lib.store.source, uid: uint64, rg: lib.store.range ): lib.mem.ptr(lib.mem.ptr(lib.store.post)) var r = pqr { sz = 0 } var A,B,C,D = rg:matrix() -- :/ r = queries.post_enum_author_uid.exec(src,A,B,C,D,uid) var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz) for i=0,r.sz do ret.ptr[i] = row_to_post(&r, i) end -- MUST FREE ALL return ret end]; |
Modified doc/acl.md from [ea4e893c12] to [53956f184b].
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
* **mutuals**: matches users you follow who also follow you * **followed**: matches users you follow * **followers**: matches users who follow you * **groupies**: matches users who follow you, but whom you do not follow * **mentioned**: matches users who are mentioned in the post * **staff**: matches instance staff (equivalent to `~%0`) * **admin**: matches the individual named as the instance administrator, if any * **@**`handle`: matches the user `handle` * **+**`circle`: matches users you have categorized under `circle` * **#**`room`: matches users who are members of `room` * **%**`rank`: matches users of `rank` or higher (e.g. `%3` matches users of rank 3, 2, and 1). as a special case, `%0` matches ordinary users * **#**`room`**%**`rank`: matches users who hold `rank` in `room` * **<**`title`**>**: matches peers of the net who have been created `title` by the sovereign * **#**`room`**<**`title`**>**: matches peers of the chat who have been created `title` by `room` staff to evaluate an ACL expression, `parsav` reads each term from start to finish. for each term, it considers whether it describes the user who is attempting to access the content. if the term matches, its policy is applied and the expression completes. if the term doesn't match, the server proceeds on to the next term and the process repeats until it finds a matching term or runs out of terms, applying the fallback policy. **policy** is whether a term grants or denies access. the default term policy is **allow**, but you can control the policy with the keywords `allow` and `deny`. if a term finishes evaluating without any match being found, a fallback policy is applied; this fallback is the opposite of whatever the current policy is. this sounds confusing but makes ACL expressions much more intuitive; `allow @bob` and `deny trent` do exactly what you'd expect — the former allows bob and only bob in; the latter denies access only to trent, but grants access to the rest of the world. expressions must contain at least one term to be valid. if they consist only of policy keywords, they will be rejected. |
| | | | | | | |
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
* **mutuals**: matches users you follow who also follow you * **followed**: matches users you follow * **followers**: matches users who follow you * **groupies**: matches users who follow you, but whom you do not follow * **mentioned**: matches users who are mentioned in the post * **staff**: matches instance staff (equivalent to `~%0`) * **admin**: matches the individual named as the instance administrator, if any * **@**_handle_: matches the user *handle* * **+**_circle_: matches users you have categorized under *circle* * **#**_room_: matches users who are members of *room* * **%**_rank_: matches users of *rank* or higher (e.g. `%3` matches users of rank 3, 2, and 1). as a special case, `%0` matches ordinary users * **#**_room_**%**_rank_: matches users who hold *rank* in *room* * **<**_title_**>**: matches peers of the net who have been created *title* by the sovereign * **#**_room_**<**_title_**>**: matches peers of the chat who have been created *title* by *room* staff to evaluate an ACL expression, `parsav` reads each term from start to finish. for each term, it considers whether it describes the user who is attempting to access the content. if the term matches, its policy is applied and the expression completes. if the term doesn't match, the server proceeds on to the next term and the process repeats until it finds a matching term or runs out of terms, applying the fallback policy. **policy** is whether a term grants or denies access. the default term policy is **allow**, but you can control the policy with the keywords `allow` and `deny`. if a term finishes evaluating without any match being found, a fallback policy is applied; this fallback is the opposite of whatever the current policy is. this sounds confusing but makes ACL expressions much more intuitive; `allow @bob` and `deny trent` do exactly what you'd expect — the former allows bob and only bob in; the latter denies access only to trent, but grants access to the rest of the world. expressions must contain at least one term to be valid. if they consist only of policy keywords, they will be rejected. |
Modified parsav.t from [8c471232dd] to [1c10e6f8f8].
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
end
lib.load {
'srv';
'render:nav';
'render:login';
'render:profile';
'render:userpage';
'render:compose';
'render:tweet';
'render:timeline';
'render:docpage';
'route';
}
do
local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when)
|
< > |
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
end
lib.load {
'srv';
'render:nav';
'render:login';
'render:profile';
'render:compose';
'render:tweet';
'render:userpage';
'render:timeline';
'render:docpage';
'route';
}
do
local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when)
|
Modified render/profile.t from [d063b74f92] to [efe49adad0].
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
var auxp: pstr
if co.aid ~= 0 and co.who.id == actor.id then
auxp = lib.str.plit '<a href="/conf/profile">alter</a>'
elseif co.aid ~= 0 then
aux:compose('<a href="/', actor.xid, '/follow">follow</a><a href="/',
actor.xid, '/chat">chat</a>')
if co.who.rights.powers:affect_users() then
aux:push('<a href="/',11):push(actor.xid,0):push('/ctl">control</a>',17)
end
auxp = aux:finalize()
else
aux:compose('<a href="/', actor.xid, '/follow">remote follow</a>')
auxp = aux:finalize()
end
var avistr: lib.str.acc if actor.origin == 0 then
|
| |
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
var auxp: pstr
if co.aid ~= 0 and co.who.id == actor.id then
auxp = lib.str.plit '<a href="/conf/profile">alter</a>'
elseif co.aid ~= 0 then
aux:compose('<a href="/', actor.xid, '/follow">follow</a><a href="/',
actor.xid, '/chat">chat</a>')
if co.who.rights.powers:affect_users() then
aux:lpush('<a href="/'):push(actor.xid,0):lpush('/ctl">control</a>')
end
auxp = aux:finalize()
else
aux:compose('<a href="/', actor.xid, '/follow">remote follow</a>')
auxp = aux:finalize()
end
var avistr: lib.str.acc if actor.origin == 0 then
|
Modified render/timeline.t from [e2a4558814] to [873aeea861].
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
var stoptime = lib.osclock.time(nil)
var posts = [lib.mem.vec(lib.mem.ptr(lib.store.post))] {
sz = 0, run = 0
}
if mode == modes.follow then
elseif mode == modes.srvlocal then
posts = co.srv:instance_timeline_fetch(lib.store.range {
mode = 1; -- T->I
from_time = stoptime;
to_idx = 64;
})
elseif mode == modes.fediglobal then
elseif mode == modes.circle then
end
|
| |
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
var stoptime = lib.osclock.time(nil)
var posts = [lib.mem.vec(lib.mem.ptr(lib.store.post))] {
sz = 0, run = 0
}
if mode == modes.follow then
elseif mode == modes.srvlocal then
posts = co.srv:timeline_instance_fetch(lib.store.range {
mode = 1; -- T->I
from_time = stoptime;
to_idx = 64;
})
elseif mode == modes.fediglobal then
elseif mode == modes.circle then
end
|
Modified render/tweet.t from [71eb9101d9] to [00c7b6fd89].
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
return pstr { ptr = s, ct = lib.str.sz(s) }
end
local terra
render_tweet(co: &lib.srv.convo, p: &lib.store.post, acc: &lib.str.acc)
var author: &lib.store.actor
for j = 0, co.actorcache.top do
lib.io.fmt('scanning cache for author %llu (%llu/%llu)\n', p.author, j, co.actorcache.top)
if p.author == co.actorcache(j).ptr.id then
author = co.actorcache(j).ptr
lib.io.fmt('cache hit on idx %llu, skipping db lookup\n', j)
goto foundauth
end
end
lib.io.fmt('cache miss, checking db for id %llu\n', p.author)
author = co.actorcache:insert(co.srv:actor_fetch_uid(p.author)).ptr
lib.io.fmt('got author %s\n', author.handle)
::foundauth::
var avistr: lib.str.acc if author.origin == 0 then
avistr:compose('/avi/',author.handle)
end
var timestr: int8[26] lib.osclock.ctime_r(&p.posted, ×tr[0])
lib.io.fmt('got body %s\n', author.handle)
var bhtml = lib.smackdown.html([lib.mem.ptr(int8)] {ptr=p.body,ct=0}) defer bhtml:free()
var idbuf: int8[lib.math.shorthand.maxlen]
var idlen = lib.math.shorthand.gen(p.id, idbuf)
var permalink: lib.str.acc permalink:compose('/post/',{idbuf,idlen})
|
< < < < < |
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
return pstr { ptr = s, ct = lib.str.sz(s) }
end
local terra
render_tweet(co: &lib.srv.convo, p: &lib.store.post, acc: &lib.str.acc)
var author: &lib.store.actor
for j = 0, co.actorcache.top do
if p.author == co.actorcache(j).ptr.id then
author = co.actorcache(j).ptr
goto foundauth
end
end
author = co.actorcache:insert(co.srv:actor_fetch_uid(p.author)).ptr
::foundauth::
var avistr: lib.str.acc if author.origin == 0 then
avistr:compose('/avi/',author.handle)
end
var timestr: int8[26] lib.osclock.ctime_r(&p.posted, ×tr[0])
var bhtml = lib.smackdown.html([lib.mem.ptr(int8)] {ptr=p.body,ct=0}) defer bhtml:free()
var idbuf: int8[lib.math.shorthand.maxlen]
var idlen = lib.math.shorthand.gen(p.id, idbuf)
var permalink: lib.str.acc permalink:compose('/post/',{idbuf,idlen})
|
Modified render/userpage.t from [9774faf032] to [edce0da550].
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
render_userpage(co: &lib.srv.convo, actor: &lib.store.actor)
var ti: lib.str.acc
if co.aid ~= 0 and co.who.id == actor.id then
ti:compose('my profile')
else
ti:compose('profile :: ', actor.handle)
end
var pftxt = lib.render.profile(co,actor) defer pftxt:free()
var tiptr = ti:finalize()
co:stdpage([lib.srv.convo.page] {
title = tiptr; body = pftxt;
class = lib.str.plit 'profile';
})
tiptr:free()
end
return render_userpage
|
> > > > > > > > > > > > > > > > > > | | > |
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
render_userpage(co: &lib.srv.convo, actor: &lib.store.actor)
var ti: lib.str.acc
if co.aid ~= 0 and co.who.id == actor.id then
ti:compose('my profile')
else
ti:compose('profile :: ', actor.handle)
end
var tiptr = ti:finalize()
var acc: lib.str.acc acc:init(1024)
var pftxt = lib.render.profile(co,actor) defer pftxt:free()
acc:ppush(pftxt)
var stoptime = lib.osclock.time(nil)
var posts = co.srv:post_enum_author_uid(actor.id, lib.store.range {
mode = 1; -- T->I
from_time = stoptime;
to_idx = 64;
})
for i = 0, posts.sz do
lib.render.tweet(co, posts(i).ptr, &acc)
posts(i):free()
end
posts:free()
var bdf = acc:finalize()
co:stdpage([lib.srv.convo.page] {
title = tiptr; body = bdf;
class = lib.str.plit 'profile';
})
tiptr:free()
bdf:free()
end
return render_userpage
|
Modified srv.t from [8c264568c9] to [8808dbd7a5].
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
} terra cfgcache:free() -- :/ self.secret:free() self.instance:free() end terra srv:instance_timeline_fetch(r: lib.store.range): lib.mem.vec(lib.mem.ptr(lib.store.post)) var all: lib.mem.vec(lib.mem.ptr(lib.store.post)) all:init(64) for i=0,self.sources.ct do var src = self.sources.ptr + i if src.handle ~= nil and src.backend.instance_timeline_fetch ~= nil then var lst = src:instance_timeline_fetch(r) all:assure(all.sz + lst.ct) for j=0, lst.ct do all:push(lst.ptr[j]) end lst:free() end end return all end |
| | | > > > > > > > > > > > > > |
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
} terra cfgcache:free() -- :/ self.secret:free() self.instance:free() end terra srv:post_enum_author_uid(uid: uint64, r: lib.store.range): lib.mem.vec(lib.mem.ptr(lib.store.post)) var all: lib.mem.vec(lib.mem.ptr(lib.store.post)) all:init(64) for i=0,self.sources.ct do var src = self.sources.ptr + i if src.handle ~= nil and src.backend.timeline_instance_fetch ~= nil then var lst = src:post_enum_author_uid(uid,r) all:assure(all.sz + lst.ct) for j=0, lst.ct do all:push(lst.ptr[j]) end lst:free() end end return all end terra srv:timeline_instance_fetch(r: lib.store.range): lib.mem.vec(lib.mem.ptr(lib.store.post)) var all: lib.mem.vec(lib.mem.ptr(lib.store.post)) all:init(64) for i=0,self.sources.ct do var src = self.sources.ptr + i if src.handle ~= nil and src.backend.timeline_instance_fetch ~= nil then var lst = src:timeline_instance_fetch(r) all:assure(all.sz + lst.ct) for j=0, lst.ct do all:push(lst.ptr[j]) end lst:free() end end return all end |
Modified static/style.scss from [9520b92c84] to [b0a8082b0c].
157 158 159 160 161 162 163 164 165 166 167 168 169 170 ... 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 ... 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 ... 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 ... 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 ... 469 470 471 472 473 474 475 476 |
background-color: adjust-color($color, $lightness: -53%, $alpha: -0.7);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
background-color: adjust-color($color, $lightness: -53%, $alpha: -0.1);
}
}
header {
position: fixed;
height: min-content;
width: 100vw;
margin: 0;
padding: 0;
border-bottom: 1px solid black;
................................................................................
all: unset;
display: flex;
justify-content: flex-end;
align-items: center;
grid-column: 2/3; grid-row: 1/2;
> a[href] {
display: block;
padding: 0.25in 0.15in;
//padding: calc((25% - 1em)/2) 0.15in;
&, &::after { transition: 0.3s; }
text-shadow: 1px 1px 1px black;
&:hover{
transform: scale(120%);
}
}
................................................................................
border: {
left: 1px solid black;
right: 1px solid black;
}
}
div.profile {
@extend %box;
padding: 0.1in;
position: relative;
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-rows: 1fr 1fr;
width: 100%;
> .banner {
grid-column: 1 / 3;
grid-row: 1 / 2;
display: grid;
grid-template-columns: 1.1in 1fr;
grid-template-rows: 0.3in 1fr;
> .avatar {
display: block;
width: 1in; height: 1in;
grid-column: 1 / 2;
grid-row: 1 / 3;
border: 1px solid black;
}
................................................................................
}
}
> .stats {
grid-column: 3 / 4;
grid-row: 1 / 3;
}
> .menu {
grid-column: 1 / 3;
grid-row: 2 / 3;
display: flex;
justify-content: center;
align-items: center;
> a[href] {
@extend %button;
display: block;
margin: 0 0.05in;
}
> hr {
all: unset;
display: block;
height: 0.3in;
width: 1px;
border-left: 1px solid rgba(0,0,0,0.6);
................................................................................
padding: 0.1in;
&:hover { font-weight: bold; }
}
}
code {
@extend %teletype;
background: tone(-50%);
border: 1px solid tone(-20%);
padding: 2px 6px;
text-shadow: 2px 2px black;
}
div.post {
@extend %box;
display: grid;
grid-template-columns: 1in 1fr max-content;
grid-template-rows: 1fr max-content;
margin-bottom: 0.1in;
>.avatar {
grid-column: 1/2; grid-row: 1/2;
width: 1in;
}
>a[href].username {
display: block;
grid-column: 1/3;
grid-row: 2/3;
text-align: left;
text-decoration: none;
................................................................................
@extend %teletype;
}
body.doc main {
@extend %serif;
li { margin-top: 0.05in; }
li:first-child { margin-top: 0; }
}
|
> > | < > | | | | > | | | | > > > > > | | > > > > > > | > |
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 ... 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 ... 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 ... 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 ... 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 ... 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
background-color: adjust-color($color, $lightness: -53%, $alpha: -0.7);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
background-color: adjust-color($color, $lightness: -53%, $alpha: -0.1);
}
}
h1 { margin-top: 0 }
header {
position: fixed;
height: min-content;
width: 100vw;
margin: 0;
padding: 0;
border-bottom: 1px solid black;
................................................................................
all: unset;
display: flex;
justify-content: flex-end;
align-items: center;
grid-column: 2/3; grid-row: 1/2;
> a[href] {
display: block;
padding: 0.25in 0.10in;
//padding: calc((25% - 1em)/2) 0.15in;
&, &::after { transition: 0.3s; }
text-shadow: 1px 1px 1px black;
&:hover{
transform: scale(120%);
}
}
................................................................................
border: {
left: 1px solid black;
right: 1px solid black;
}
}
div.profile {
padding: 0.1in;
position: relative;
display: grid;
margin-bottom: 0.4in;
grid-template-columns: 2fr 1fr;
grid-template-rows: max-content 1fr;
width: 100%;
> .banner {
grid-column: 1 / 3;
grid-row: 1 / 2;
display: grid;
grid-template-columns: 1.1in 1fr;
grid-template-rows: max-content 1fr;
> .avatar {
display: block;
width: 1in; height: 1in;
grid-column: 1 / 2;
grid-row: 1 / 3;
border: 1px solid black;
}
................................................................................
}
}
> .stats {
grid-column: 3 / 4;
grid-row: 1 / 3;
}
> .menu {
grid-column: 1 / 3; grid-row: 2 / 3;
padding-top: 0.075in;
flex-wrap: wrap;
display: flex;
justify-content: center;
align-items: center;
> a[href] {
@extend %button;
display: block;
margin: 0.025in 0.05in;
}
> hr {
all: unset;
display: block;
height: 0.3in;
width: 1px;
border-left: 1px solid rgba(0,0,0,0.6);
................................................................................
padding: 0.1in;
&:hover { font-weight: bold; }
}
}
code {
@extend %teletype;
background: tone(-55%);
border: 1px inset tone(-20%);
padding: 2px 6px;
font-size: 1.5ex !important;
letter-spacing: 1.3px;
padding-bottom: 3px;
border-radius: 2px;
vertical-align: baseline;
box-shadow: 1px 1px 1px black;
}
div.post {
@extend %box;
display: grid;
grid-template-columns: 1in 1fr max-content;
grid-template-rows: min-content max-content;
margin-bottom: 0.1in;
>.avatar {
grid-column: 1/2; grid-row: 1/2;
img { display: block; width: 1in; margin:0; }
background: linear-gradient(to bottom, tone(-53%), tone(-57%));
}
>a[href].username {
display: block;
grid-column: 1/3;
grid-row: 2/3;
text-align: left;
text-decoration: none;
................................................................................
@extend %teletype;
}
body.doc main {
@extend %serif;
li { margin-top: 0.05in; }
li:first-child { margin-top: 0; }
h1, h2, h3, h4, h5, h6 {
background: linear-gradient(to right, tone(-50%), transparent);
margin-left: -0.4in;
padding-left: 0.2in;
text-shadow: 0 2px 0 black;
}
}
|
Modified store.t from [5b8778f17f] to [4959208545].
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
from_idx: uint64
}
union {
to_time: m.timepoint
to_idx: uint64
}
}
struct m.post {
id: uint64
author: uint64
subject: str
body: str
acl: str
posted: m.timepoint
discovered: m.timepoint
mentions: lib.mem.ptr(uint64)
circles: lib.mem.ptr(uint64) --only meaningful if scope is set to circle
convo: uint64
parent: uint64
-- ephemera
localpost: bool
source: &m.source
}
local cnf = terralib.memoize(function(ty,rty)
................................................................................
-- uid: uint64
actor_conf_str: cnf(rawstring, lib.mem.ptr(int8))
actor_conf_int: cnf(intptr, lib.stat(intptr))
post_save: {&m.source, &m.post} -> {}
post_create: {&m.source, &m.post} -> uint64
actor_post_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(m.post)
convo_fetch_xid: {&m.source,rawstring} -> lib.mem.ptr(m.post)
convo_fetch_uid: {&m.source,uint64} -> lib.mem.ptr(m.post)
actor_timeline_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
instance_timeline_fetch: {&m.source, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
}
struct m.source {
backend: &m.backend
id: lib.mem.ptr(int8)
handle: &opaque
string: lib.mem.ptr(int8)
|
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
from_idx: uint64
}
union {
to_time: m.timepoint
to_idx: uint64
}
}
terra m.range:matrix()
if self.mode == 0 then
return self.from_time,self.to_time,0,0
elseif self.mode == 1 then
return self.from_time,0,self.to_idx,0
elseif self.mode == 2 then
return 0,self.to_time,0,self.from_idx
elseif self.mode == 3 then
return 0,0,self.to_idx,self.from_idx
else lib.bail('invalid mode on timeline range!') end
end
struct m.post {
id: uint64
author: uint64
subject: str
body: str
acl: str
posted: m.timepoint
discovered: m.timepoint
mentions: lib.mem.ptr(uint64)
circles: lib.mem.ptr(uint64) --only meaningful if scope is set to circle
convoheaduri: str
parent: uint64
-- ephemera
localpost: bool
source: &m.source
}
local cnf = terralib.memoize(function(ty,rty)
................................................................................
-- uid: uint64
actor_conf_str: cnf(rawstring, lib.mem.ptr(int8))
actor_conf_int: cnf(intptr, lib.stat(intptr))
post_save: {&m.source, &m.post} -> {}
post_create: {&m.source, &m.post} -> uint64
post_enum_author_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
convo_fetch_xid: {&m.source,rawstring} -> lib.mem.ptr(m.post)
convo_fetch_uid: {&m.source,uint64} -> lib.mem.ptr(m.post)
timeline_actor_fetch_uid: {&m.source, uint64, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
timeline_instance_fetch: {&m.source, m.range} -> lib.mem.ptr(lib.mem.ptr(m.post))
}
struct m.source {
backend: &m.backend
id: lib.mem.ptr(int8)
handle: &opaque
string: lib.mem.ptr(int8)
|
Modified view/tweet.tpl from [e1b2184d52] to [43ed0b36e9].
1 2 3 4 5 6 7 8 9 10 11 |
<div class="post"> <img class="avatar" src="@avatar"> <a class="username" href="/@acctlink"> <span class="nym">@nym</span> [<span class="handle">@xid</span>] </a> <div class="content"> <div class="subject">@subject</div> <div class="text">@text</div> </div> <a class="permalink" href="@permalink">@when</a> </div> |
| |
1 2 3 4 5 6 7 8 9 10 11 |
<div class="post"> <div class="avatar"><img src="@avatar"></div> <a class="username" href="/@acctlink"> <span class="nym">@nym</span> [<span class="handle">@xid</span>] </a> <div class="content"> <div class="subject">@subject</div> <div class="text">@text</div> </div> <a class="permalink" href="@permalink">@when</a> </div> |