parsav  Check-in [1ba4bbc92f]

Overview
Comment:various cleanups, notices no longer originated from self
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 1ba4bbc92f8d9564ff4b2cb308d012d72c8cae34121c97725dd9b27fc6a78c11
User & Date: lexi on 2021-01-11 23:33:55
Other Links: manifest | tags
Context
2021-01-13
00:04
add full relationship control screen, more timelines, minor fixes and cleanups check-in: d3fe1d11af user: lexi tags: trunk
2021-01-11
23:33
various cleanups, notices no longer originated from self check-in: 1ba4bbc92f user: lexi tags: trunk
02:17
enable revoking credentials check-in: 41cbbca855 user: lexi tags: trunk
Changes

Modified backend/pgsql.t from [05f7cb1a74] to [c81652b018].

831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
local con = symbol(&lib.pq.PGconn)
local function sqlsquash(s) return s
	:gsub('%%include (.-)%%',function(f)
		return sqlsquash(lib.util.ingest('backend/schema/' .. f))
	end) -- include dependencies
	:gsub('%-%-.-\n','') -- remove disruptive line comments
	:gsub('%-%-.-$','') -- remove unnecessary terminal comments
	:gsub('<(%g-)>',function(r) return tostring(sqlvars[r]) end)
	:gsub('%s+',' ') -- remove whitespace
	:gsub('^%s*(.-)%s*$','%1') -- chomp
end

-- to simplify queries and reduce development headaches in general, we
-- offload as much logic as possible into views. to avoid versioning
-- difficulties, these views are not part of the schema, but are rather







|







831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
local con = symbol(&lib.pq.PGconn)
local function sqlsquash(s) return s
	:gsub('%%include (.-)%%',function(f)
		return sqlsquash(lib.util.ingest('backend/schema/' .. f))
	end) -- include dependencies
	:gsub('%-%-.-\n','') -- remove disruptive line comments
	:gsub('%-%-.-$','') -- remove unnecessary terminal comments
	:gsub('<(%g%g-)>',function(r) return tostring(sqlvars[r]) end)
	:gsub('%s+',' ') -- remove whitespace
	:gsub('^%s*(.-)%s*$','%1') -- chomp
end

-- to simplify queries and reduce development headaches in general, we
-- offload as much logic as possible into views. to avoid versioning
-- difficulties, these views are not part of the schema, but are rather

Modified backend/schema/pgsql-views.sql from [0fea8fa8b6] to [ac2cb76c4f].

226
227
228
229
230
231
232

233
234
235
		from parsav_rels as r
			left  join ntimes as nt on nt.uid = r.relatee
		where
			r.since >= coalesce(nt.when,0) and
			r.kind = <rel:follow>
	), allnotices as (table acts union table replies union table follows)


	table allnotices order by (notice).when desc
);








>
|


226
227
228
229
230
231
232
233
234
235
236
		from parsav_rels as r
			left  join ntimes as nt on nt.uid = r.relatee
		where
			r.since >= coalesce(nt.when,0) and
			r.kind = <rel:follow>
	), allnotices as (table acts union table replies union table follows)

	select * from allnotices where rcpt <> (notice).who
	order by (notice).when desc
);

Modified render/conf.t from [a292c2030a] to [fa9db8630d].

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
local terra 
render_conf([co], [path], notify: pstr)
	var menu = co:stra(256)
	menu:lpush('<hr>') 

	-- build menu
	do var p = co.who.rights.powers
		if p:affect_users() then menu:lpush '<a href="/conf/users">users</a>' end
		if p.censor() then menu:lpush '<a href="/conf/censor">badthink alerts</a>' end
		if p.config() then menu:lpush([
			'<a href="/conf/srv">server &amp; policy</a>' ..
			'<a href="/conf/badge">badges</a>' ..
			'<a href="/conf/emoji">emoji packs</a>'
		]) end
		if p.rebrand() then menu:lpush '<a href="/conf/brand">instance branding</a>' end
	end

	-- select the appropriate panel
	var [panel] = pstr { ptr = ''; ct = 0 }
	if path.ct >= 2 then [invoker] end

	-- avoid the hr if we didn't add any elements







|
|

|
|
|

|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
local terra 
render_conf([co], [path], notify: pstr)
	var menu = co:stra(256)
	menu:lpush('<hr>') 

	-- build menu
	do var p = co.who.rights.powers
		if p:affect_users() then menu:lpush '<a class="button" href="/conf/users">users</a>' end
		if p.censor() then menu:lpush '<a class="button" href="/conf/censor">badthink alerts</a>' end
		if p.config() then menu:lpush([
			'<a class="button" href="/conf/srv">server &amp; policy</a>' ..
			'<a class="button" href="/conf/badge">badges</a>' ..
			'<a class="button" href="/conf/emoji">emoji packs</a>'
		]) end
		if p.rebrand() then menu:lpush '<a class="button" href="/conf/brand">instance branding</a>' end
	end

	-- select the appropriate panel
	var [panel] = pstr { ptr = ''; ct = 0 }
	if path.ct >= 2 then [invoker] end

	-- avoid the hr if we didn't add any elements

Modified render/conf/users.t from [88e528c638] to [46d40d63a3].

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
..
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
63
64
65


66
67
68
69
70
71
72
...
125
126
127
128
129
130
131
132








133
134
135
136
137
138
139
140
141
142
143
144
145
146

147
148
149
150
151
152
153
end)

local rnd = lib.crypt.random
local terra 
suggest_handle(a: &lib.str.acc)
	var start = a.sz
	var puncts = array('.','_','-')
	var xXx = rnd(uint8, 0, 9) == 0
	var leet = rnd(uint8, 0, 8) == 0
	var caps = rnd(uint8, 0, 10)
	var punct: rawstring = nil
	var useadj = rnd(uint8, 0, 4) == 0
	if rnd(uint8, 0, 4) == 0 then
		punct = puncts[rnd(intptr,0,[puncts.type.N])]
	end
................................................................................
		killer murderer thief arson fire ice frost hack
		hacker god master mistress slave rage freeze flayer
		pirate ninja shadow fog mist misery glory bear
		king queen empress emperor majesty space martian
		winter fall monk katana 420 warrior banana demon
		devil ghost wraith cuck legend hero heroine goblin
		gremlin troll dragon evil overlord radiance slop
		operator rage hog bog roach wizard

	]]
	var adjs = splitwords [[
		dark super supreme ultra ultimate total infinite
		omnipotent crazy final deathless immortal elite
		leet 1337 bloody fearless headless screaming insane
		brutal legendary space frozen flaming burning
		mighty flayed hidden secret lost mystery glorious
		nude naked bare first radiant martian fallen bog
		wandering dank demonic satanic invisible based woke
		deadly lethal heroic evil majestic luminous ethereal


	]]

	if xXx then a:lpush('xXx_') end

	if useadj then
		var len = rnd(uint8,1,3) 
		for i = 0, len do
................................................................................
		wank fae weird woke slurp spine skull fail elf elves mom
		dad dog cat kitten snake troll top bottom chungus dong wang
		420 hog lover lovers best worst love hate big bigger tiny
		little teeny spunky jazz wrack rump kink kinky crack meth
		whore cam live over under turbo pizza rat rats crotch crank
		chunky funky butt grab grabber grabbers thief steal slave
		slaves hug hugs hag hags hogs wimp thieves wizard wizards
		pussy pansy dark doom stank spunk dumb rage








	]]
	var tlds = splitwords [[
		tld club town space xxx house land ranch horse com io online
		shop site vip ltd win men lgbt cat adult army analytics art
		associates bar bible biz black blog broker cam camp careers
		catering church city coop dad date dating direct diy dog
		duck dot enterprises esq estate expert express fail farm foo
		forsale fun fund forum foundation gay global golf gop guru
		group hangout hot industries international info investments
		jobs land law life limited live lol mom network now party
		porn productions pub rehab rocks school sex sexy singles
		social software solutions space spot store sucks supplies
		systems university vacations ventures wang website work
		wow wtf world xyz soy live gym park 

	]]
	var sub = rnd(uint8,0,10) == 0
	if sub then a:ppush(words[rnd(intptr,0,[words.type.N])]):lpush('.') end
	a:ppush(words[rnd(intptr,0,[words.type.N])])
	if rnd(uint8,0,3) == 0 or not sub then
		a:ppush(words[rnd(intptr,0,[words.type.N])])
	end







|







 







|
>





|




>
>







 







|
>
>
>
>
>
>
>
>











|
|
|
>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
..
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
end)

local rnd = lib.crypt.random
local terra 
suggest_handle(a: &lib.str.acc)
	var start = a.sz
	var puncts = array('.','_','-')
	var xXx = rnd(uint8, 0, 30) == 0
	var leet = rnd(uint8, 0, 8) == 0
	var caps = rnd(uint8, 0, 10)
	var punct: rawstring = nil
	var useadj = rnd(uint8, 0, 4) == 0
	if rnd(uint8, 0, 4) == 0 then
		punct = puncts[rnd(intptr,0,[puncts.type.N])]
	end
................................................................................
		killer murderer thief arson fire ice frost hack
		hacker god master mistress slave rage freeze flayer
		pirate ninja shadow fog mist misery glory bear
		king queen empress emperor majesty space martian
		winter fall monk katana 420 warrior banana demon
		devil ghost wraith cuck legend hero heroine goblin
		gremlin troll dragon evil overlord radiance slop
		operator rage hog bog roach wizard steel madness
		reign
	]]
	var adjs = splitwords [[
		dark super supreme ultra ultimate total infinite
		omnipotent crazy final deathless immortal elite
		leet 1337 bloody fearless headless screaming insane
		brutal legendary space frozen flaming burning lazy
		mighty flayed hidden secret lost mystery glorious
		nude naked bare first radiant martian fallen bog
		wandering dank demonic satanic invisible based woke
		deadly lethal heroic evil majestic luminous ethereal
		perfect first fantastic special great steel insane
		royal imperial celestial cosmic mystic sublime
	]]

	if xXx then a:lpush('xXx_') end

	if useadj then
		var len = rnd(uint8,1,3) 
		for i = 0, len do
................................................................................
		wank fae weird woke slurp spine skull fail elf elves mom
		dad dog cat kitten snake troll top bottom chungus dong wang
		420 hog lover lovers best worst love hate big bigger tiny
		little teeny spunky jazz wrack rump kink kinky crack meth
		whore cam live over under turbo pizza rat rats crotch crank
		chunky funky butt grab grabber grabbers thief steal slave
		slaves hug hugs hag hags hogs wimp thieves wizard wizards
		pussy pansy dark doom stank spunk dumb rage worship orb
		terror fear blood slime slab warp waggle tit boob bird derp
		birb goat horde masto mastodon social global tweet post
		house home prison jail box pit hole haven town trump putin
		truth liberty zone land ranch butt butts sex pimp cop mail
		slut goblin goblins no good bad only gtfo electro electric
		dragon space mars earth venus neptune pluto saturn star
		moon lunar catastrophe catastro cuck honk war lap cuddle
		planet
	]]
	var tlds = splitwords [[
		tld club town space xxx house land ranch horse com io online
		shop site vip ltd win men lgbt cat adult army analytics art
		associates bar bible biz black blog broker cam camp careers
		catering church city coop dad date dating direct diy dog
		duck dot enterprises esq estate expert express fail farm foo
		forsale fun fund forum foundation gay global golf gop guru
		group hangout hot industries international info investments
		jobs land law life limited live lol mom network now party
		porn productions pub rehab rocks school sex sexy singles
		social software solutions spot store sucks supplies cuck
		uwu systems university vacations ventures wang website work
		wow wtf world xyz soy live gym park worship orb zone mail
		war honk derp planet
	]]
	var sub = rnd(uint8,0,10) == 0
	if sub then a:ppush(words[rnd(intptr,0,[words.type.N])]):lpush('.') end
	a:ppush(words[rnd(intptr,0,[words.type.N])])
	if rnd(uint8,0,3) == 0 or not sub then
		a:ppush(words[rnd(intptr,0,[words.type.N])])
	end

Modified render/profile.t from [f79f7a1ea9] to [4c6c4c1279].

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
..
73
74
75
76
77
78
79

80
81
82
83



84
85
86
87
88
89
90
		aux:pcompose(&co.srv.pool,'<a accesskey="a" class="button" href="/conf/profile?go=/@',actor.handle,'">alter</a>')
	elseif co.aid ~= 0 then
		if not relationship.rel.follow() then
			aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="pos" name="act" value="follow">follow</button>')
		elseif relationship.rel.follow() then
			aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="neg" name="act" value="unfollow">unfollow</button>')
		end
		aux:lpush('<a accesskey="h" class="button" href="/'):push(actor.xid,0):lpush('/chat">chat</a>')
		if co.who.rights.powers:affect_users() and co.who:overpowers(actor) then
			aux:lpush('<a accesskey="n" class="button" href="/'):push(actor.xid,0):lpush('/ctl">control</a>')
		end
	else
		aux:pcompose(&co.srv.pool,'<a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>')
	end
	var auxp = aux:finalize()
	var timestr: int8[26] lib.osclock.ctime_r(&actor.knownsince, &timestr[0])

	var strfbuf: int8[28*4]
	var stats = co.srv:actor_stats(actor.id)
		var sn_posts     = cs(lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ]))
................................................................................
		if co.who.rights.rank ~= 0 then
			if co.who:outranks(actor) then
				comments:lpush('<li style="--co:50">underling</li>')
			elseif actor:outranks(co.who) then
				comments:lpush('<li style="--co:-50">outranks you</li>')
			end
		end


		if relationship.recip.follow() then
			comments:lpush('<li style="--co:30">follows you</li>')
		end



	end

	var profile = data.view.profile {
		nym = fullname;
		bio = bio;
		xid = cs(actor.xid);
		avatar = cs(actor.avatar);







|

|


|







 







>

|
|
|
>
>
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
..
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
		aux:pcompose(&co.srv.pool,'<a accesskey="a" class="button" href="/conf/profile?go=/@',actor.handle,'">alter</a>')
	elseif co.aid ~= 0 then
		if not relationship.rel.follow() then
			aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="pos" name="act" value="follow">follow</button>')
		elseif relationship.rel.follow() then
			aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="neg" name="act" value="unfollow">unfollow</button>')
		end
		aux:lpush(' <a accesskey="h" class="button" href="/'):push(actor.xid,0):lpush('/chat">chat</a>')
		if co.who.rights.powers:affect_users() and co.who:overpowers(actor) then
			aux:lpush(' <a accesskey="n" class="button" href="/conf/users/'):shpush(actor.id):lpush('">control</a>')
		end
	else
		aux:pcompose(&co.srv.pool,' <a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>')
	end
	var auxp = aux:finalize()
	var timestr: int8[26] lib.osclock.ctime_r(&actor.knownsince, &timestr[0])

	var strfbuf: int8[28*4]
	var stats = co.srv:actor_stats(actor.id)
		var sn_posts     = cs(lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ]))
................................................................................
		if co.who.rights.rank ~= 0 then
			if co.who:outranks(actor) then
				comments:lpush('<li style="--co:50">underling</li>')
			elseif actor:outranks(co.who) then
				comments:lpush('<li style="--co:-50">outranks you</li>')
			end
		end
	end

	if relationship.rel.block() then
		comments:lpush('<li style="--co:80">blocked</li>')
	end

	if relationship.recip.follow() then
		comments:lpush('<li style="--co:30">follows you</li>')
	end

	var profile = data.view.profile {
		nym = fullname;
		bio = bio;
		xid = cs(actor.xid);
		avatar = cs(actor.avatar);

Modified static/style.scss from [048cf30682] to [de5cdf2da4].

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
..
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
...
307
308
309
310
311
312
313


314

315
316
317
318
319




320


321
322

323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
...
420
421
422
423
424
425
426
427

428
429
430
431
432
433
434
...
453
454
455
456
457
458
459

460
461
462
463
464
465
466
...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
...
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
...
881
882
883
884
885
886
887

888
889

890
891
892
893
894
895
896
	text-underline-offset: 0.1em;
	&:hover, &:focus {
		color: white;
		text-shadow: 0 0 15px tone(20%);
		text-decoration-color: tone(10%,-0.1);
		outline: none;
	}
	&.button { @extend %button; }
}
a[href^="//"],
a[href^="http://"],
a[href^="https://"] { // external link
	&:hover::after {
		color: black;
		background-color: white;
................................................................................
	margin: auto;
}

%glow {
	box-shadow: 0 0 20px tone(0%,-0.8);
}

%button {
	@extend %sans;
	font-size: 14pt;
	box-sizing: border-box;
	padding: 0.1in 0.2in;
	border: 1px solid black;
	color: otone(25%);
	text-shadow: 1px 1px black;
................................................................................
			otone(-30%) 15%,
			otone(-30%) 75%,
			otone(-35%)
		);
	}
}

button { @extend %button;
	&:first-of-type {
		@extend %button;
		color: white;
		box-shadow: inset 0 1px  otone(-25%),
		            inset 0 -1px otone(-50%);
		background: linear-gradient(to bottom,
			otone(-35%),
			otone(-40%) 15%,
			otone(-40%) 75%,
................................................................................
	}
	> .stats {
		grid-column: 3 / 4;
		grid-row: 1 / 3;
		display: flex;
		flex-flow: column;
		> * { flex-grow: 1; }


		table { td, th { text-align: center; } }

	}
	> form.actions {
		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] {
			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);
		}
	}
}

.epithet {
	display: inline-block;
	background: tone(20%);
................................................................................
body.login {
	form.auth-select {
		@extend %box;
		width: 3in;
		padding: 0.4in;
		p { text-align: center; }
		menu {
			%button {
				display: block;
				width: 100%;
				& + %button { border-top: none; }
			}
		}
	}
	div.login {
		@extend %box;
		width: 4in;
		padding: 0.4in;
................................................................................
			grid-template-columns: 1fr 1fr;
			grid-template-rows: 1.2em max-content max-content;
			grid-gap: 5px;
			> label, input, button { display: block; }
			> label { grid-column: 1 / 3; grid-row: 1/2; font-weight: bold }
			> input, textarea  { grid-column: 1 / 3; grid-row: 2/3; }
			> button { grid-column: 2 / 3; grid-row: 3/4; }
			> a { @extend %button; grid-column: 1 / 2; grid-row: 3/4; }

		}
	}
}

form.compose {
	@extend %box;
	display: grid;
................................................................................
	text-align: center;
	padding: 0.09in 0.2in;
	background: tone(-40%);
	border: 1px solid black;
	font-weight: bold;
	text-decoration: none;
	cursor: help;

}

input.acl {
	@extend %teletype;
	background: url(/s/padlock.svg) no-repeat;
	background-size: 20pt;
	background-position: 0.05in 50%;
................................................................................
	z-index: 2;
	> div {
		height: 100%;
		overflow-y: scroll;
		>p:first-of-type { margin-top: 0; }
	}
	>a[href="#0"] { // close link
		@extend %button;
		cursor: default;
		display: block;
		position: absolute;
		top: -0.3in;
		right: 0.1in;
		margin: 0.1in;
		padding: 0.1in;
................................................................................
%navmenu, body.profile main > menu {
	margin-left: -0.25in;
	grid-column: 1/2; grid-row: 1/2;
	background: linear-gradient(to bottom, tone(-45%),tone(-55%));
	border: 1px solid black;
	padding: 0.1in;
	> a[href] {
		@extend %button;
		display: block;
		text-align: left;
	}
	> a[href] + a[href] {
		border-top: none;
	}
	hr {
................................................................................
		}
		> input, textarea, .txtbox {
			display: block;
			width: 100%;
		}
		> textarea { resize: vertical; min-height: 2in; }
	}
	body.conf & > %button { margin-left: 50%; width: 50%; }
	.elem-group {
		display: flex;
		flex-flow: row;
		> .elem {
			flex-shrink: 1;
			flex-grow: 1;
			margin-left: 0.1in;
................................................................................
	}
	&.vertical-float {
		flex-flow: column;
		float: right;
		width: 40%;
		margin-left: 0.1in;
	}
	> %button {
		flex-basis: min-content;
		flex-grow: 1;
		display: block; margin: 2px;
	}
}

.check-panel {
................................................................................
		text-align: center;
		padding: 0.3em 0;
		margin: 0.2em 0.1em;
		cursor: default;
	}
}


:is(%button, a[href]).neg { --co:  30 }
:is(%button, a[href]).pos { --co: -30 }


.pick-list {
	display: flex;
	flex-flow: row wrap;
	padding: 0.1in;
	background-color: tone(-50%);
	border: 1px solid tone(-53%);







<







 







|







 







|

|







 







>
>
|
>




|
>
>
>
>
|
>
>
|
|
>
|
|
|
|
<
<
<
<
<
<







 







|


|







 







|
>







 







>







 







<







 







<







 







|







 







|







 







>
|
|
>







33
34
35
36
37
38
39

40
41
42
43
44
45
46
..
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
...
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335






336
337
338
339
340
341
342
...
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
...
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
...
490
491
492
493
494
495
496

497
498
499
500
501
502
503
...
651
652
653
654
655
656
657

658
659
660
661
662
663
664
...
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
...
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
...
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
	text-underline-offset: 0.1em;
	&:hover, &:focus {
		color: white;
		text-shadow: 0 0 15px tone(20%);
		text-decoration-color: tone(10%,-0.1);
		outline: none;
	}

}
a[href^="//"],
a[href^="http://"],
a[href^="https://"] { // external link
	&:hover::after {
		color: black;
		background-color: white;
................................................................................
	margin: auto;
}

%glow {
	box-shadow: 0 0 20px tone(0%,-0.8);
}

.button, a[href].button { // 🙄
	@extend %sans;
	font-size: 14pt;
	box-sizing: border-box;
	padding: 0.1in 0.2in;
	border: 1px solid black;
	color: otone(25%);
	text-shadow: 1px 1px black;
................................................................................
			otone(-30%) 15%,
			otone(-30%) 75%,
			otone(-35%)
		);
	}
}

button { @extend .button;
	&:first-of-type {
		@extend .button;
		color: white;
		box-shadow: inset 0 1px  otone(-25%),
		            inset 0 -1px otone(-50%);
		background: linear-gradient(to bottom,
			otone(-35%),
			otone(-40%) 15%,
			otone(-40%) 75%,
................................................................................
	}
	> .stats {
		grid-column: 3 / 4;
		grid-row: 1 / 3;
		display: flex;
		flex-flow: column;
		> * { flex-grow: 1; }
		table {
			width: 100%;
			td, th { text-align: center; }
		}
	}
	> form.actions {
		grid-column: 1 / 3; grid-row: 2 / 3;
		padding-top: 0.075in;
		display: flex;
		flex-flow: column;
		justify-content: center;
		align-items: center;
		> div {
			display: flex;
			flex-wrap: wrap;
			flex-flow: row;
			justify-content: center;
			align-items: center;
			margin-bottom: 0.07in;
			> a[href] {
				display: block;
				margin: 0.025in 0.05in;
			}






		}
	}
}

.epithet {
	display: inline-block;
	background: tone(20%);
................................................................................
body.login {
	form.auth-select {
		@extend %box;
		width: 3in;
		padding: 0.4in;
		p { text-align: center; }
		menu {
			.button {
				display: block;
				width: 100%;
				& + button, & + a[href] { border-top: none; }
			}
		}
	}
	div.login {
		@extend %box;
		width: 4in;
		padding: 0.4in;
................................................................................
			grid-template-columns: 1fr 1fr;
			grid-template-rows: 1.2em max-content max-content;
			grid-gap: 5px;
			> label, input, button { display: block; }
			> label { grid-column: 1 / 3; grid-row: 1/2; font-weight: bold }
			> input, textarea  { grid-column: 1 / 3; grid-row: 2/3; }
			> button { grid-column: 2 / 3; grid-row: 3/4; }
			> a { grid-column: 1 / 2; grid-row: 3/4; }
			> textarea { @extend %teletype; font-size: 80% !important; height: 1.5in; }
		}
	}
}

form.compose {
	@extend %box;
	display: grid;
................................................................................
	text-align: center;
	padding: 0.09in 0.2in;
	background: tone(-40%);
	border: 1px solid black;
	font-weight: bold;
	text-decoration: none;
	cursor: help;
	max-width: 0.1in;
}

input.acl {
	@extend %teletype;
	background: url(/s/padlock.svg) no-repeat;
	background-size: 20pt;
	background-position: 0.05in 50%;
................................................................................
	z-index: 2;
	> div {
		height: 100%;
		overflow-y: scroll;
		>p:first-of-type { margin-top: 0; }
	}
	>a[href="#0"] { // close link

		cursor: default;
		display: block;
		position: absolute;
		top: -0.3in;
		right: 0.1in;
		margin: 0.1in;
		padding: 0.1in;
................................................................................
%navmenu, body.profile main > menu {
	margin-left: -0.25in;
	grid-column: 1/2; grid-row: 1/2;
	background: linear-gradient(to bottom, tone(-45%),tone(-55%));
	border: 1px solid black;
	padding: 0.1in;
	> a[href] {

		display: block;
		text-align: left;
	}
	> a[href] + a[href] {
		border-top: none;
	}
	hr {
................................................................................
		}
		> input, textarea, .txtbox {
			display: block;
			width: 100%;
		}
		> textarea { resize: vertical; min-height: 2in; }
	}
	body.conf & { > .button { margin-left: 50%; width: 50%; } }
	.elem-group {
		display: flex;
		flex-flow: row;
		> .elem {
			flex-shrink: 1;
			flex-grow: 1;
			margin-left: 0.1in;
................................................................................
	}
	&.vertical-float {
		flex-flow: column;
		float: right;
		width: 40%;
		margin-left: 0.1in;
	}
	> .button, a[href] {
		flex-basis: min-content;
		flex-grow: 1;
		display: block; margin: 2px;
	}
}

.check-panel {
................................................................................
		text-align: center;
		padding: 0.3em 0;
		margin: 0.2em 0.1em;
		cursor: default;
	}
}

.button, a[href] {
	.neg { --co:  30 }
	.pos { --co: -30 }
}

.pick-list {
	display: flex;
	flex-flow: row wrap;
	padding: 0.1in;
	background-color: tone(-50%);
	border: 1px solid tone(-53%);

Modified tpl.t from [db48a650e7] to [586a17ee3f].

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
	for i, s in ipairs(segs) do
		segs[i] = string.gsub(s, '\\'..tplchar, tplchar_o)
		constlen = constlen + string.len(segs[i])
	end

	for n,d in pairs(docs) do
		local html = string.format(
			'<div id="help-%s" class="modal"> <a href="#0">close</a> <div>%s</div></div>', n, d.text
		)
		segs[#segs] = segs[#segs] .. html
		constlen = constlen + #html
	end
	

	local runningtally = symbol(intptr)







|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
	for i, s in ipairs(segs) do
		segs[i] = string.gsub(s, '\\'..tplchar, tplchar_o)
		constlen = constlen + string.len(segs[i])
	end

	for n,d in pairs(docs) do
		local html = string.format(
			'<div id="help-%s" class="modal"> <a class="button" href="#0">close</a> <div>%s</div></div>', n, d.text
		)
		segs[#segs] = segs[#segs] .. html
		constlen = constlen + #html
	end
	

	local runningtally = symbol(intptr)

Modified view/conf-sec-credmg.tpl from [a2babc26c2] to [4bef3514c2].

1
2
3
4
5
6
7
8
9
10
11
<hr>
<form method="post">
	<p>this account can currently be accessed with the credentials listed below. if you fear a credential has been compromised, you can revoke or reset it.</p>
	<select size="6" name="cred">
		@credlist
	</select>
	<menu class="horizontal choice">
		<button name="act" value="reset">reset</button>
		<button name="act" value="revoke">revoke</button>
		@?auth
	</menu>



|







1
2
3
4
5
6
7
8
9
10
11
<hr>
<form method="post">
	<p>this account can currently be accessed with the credentials listed below. if you fear a credential has been compromised, you can revoke or reset it.</p>
	<select size="6" name="cred" required>
		@credlist
	</select>
	<menu class="horizontal choice">
		<button name="act" value="reset">reset</button>
		<button name="act" value="revoke">revoke</button>
		@?auth
	</menu>

Modified view/conf.tpl from [6af7c57c63] to [f4ba0e2cfa].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<menu>
	<a href="/conf/profile">profile</a>
	<a href="/conf/avi">avatar</a>
	<a href="/conf/ui">interface</a>
	<a href="/conf/sec">security</a>
	<a href="/conf/rel">relationships</a>
	<a href="/conf/qnt">quarantine</a>
	<a href="/conf/acl">ACL shortcuts</a>
	<a href="/conf/rooms">chatrooms</a>
	<a href="/conf/circles">circles</a>
	@menu
</menu>

<div class="panel">
	@panel
</div>

|
|
|
|
|
|
|
|
|






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<menu>
	<a class="button" href="/conf/profile">profile</a>
	<a class="button" href="/conf/avi">avatar</a>
	<a class="button" href="/conf/ui">interface</a>
	<a class="button" href="/conf/sec">security</a>
	<a class="button" href="/conf/rel">relationships</a>
	<a class="button" href="/conf/qnt">quarantine</a>
	<a class="button" href="/conf/acl">ACL shortcuts</a>
	<a class="button" href="/conf/rooms">chatrooms</a>
	<a class="button" href="/conf/circles">circles</a>
	@menu
</menu>

<div class="panel">
	@panel
</div>

Modified view/login-challenge.tpl from [cc4592543f] to [be2d94bab1].

5
6
7
8
9
10
11
12
13
14
	</div>
	<div class="msg">@challenge</div>
	<form action="/login" method="post">
		<label for="response">@label</label>
		<input type="hidden" name="user" value="@:handle">
		@inputfield
		<button type="submit" name="authmethod" value="@method">authenticate</button>
		<a href="/login">cancel</a>
	</form>
</div>







|


5
6
7
8
9
10
11
12
13
14
	</div>
	<div class="msg">@challenge</div>
	<form action="/login" method="post">
		<label for="response">@label</label>
		<input type="hidden" name="user" value="@:handle">
		@inputfield
		<button type="submit" name="authmethod" value="@method">authenticate</button>
		<a class="button" href="/login">cancel</a>
	</form>
</div>

Modified view/profile.tpl from [6a9a509b78] to [1a1f71cc57].

4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19

20
21
22
23
24


25

26
27
		<div class="id">@nym</div>
		<div class="bio">
			@bio
		</div>
	</div>
	<div class="stats">
		<table>
			<tr><th>posts</th> <th>mutuals</th></tr>
			<tr><td>@nposts</td> <td>@nmutuals</td></tr>
			<tr><th>following</th> <th>followers</th></tr>
			<tr><td>@nfollows</td> <td>@nfollowers</td></tr>

			<tr><th>@timephrase</th> <td>@tweetday</td></tr>
		</table>
		<ul class="remarks">@remarks</ul>
	</div>
	<form class="actions" method="post">

		<a class="button" href="/@:xid">posts</a>
		<a class="button" href="/@:xid/arc">archive</a>
		<a class="button" href="/@:xid/media">media</a>
		<a class="button" href="/@:xid/social">associates</a>
		<hr>


		@auxbtn

	</form>
</div>







|
|
|
|
>





>
|
|
|
|
<
>
>
|
>


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
		<div class="id">@nym</div>
		<div class="bio">
			@bio
		</div>
	</div>
	<div class="stats">
		<table>
			<tr><th>posts</th>       <th>mutuals</th></tr>
			<tr><td>@nposts</td>     <td>@nmutuals</td></tr>
			<tr><th>following</th>   <th>followers</th></tr>
			<tr><td>@nfollows</td>   <td>@nfollowers</td></tr>
		</table> <table>
			<tr><th>@timephrase</th> <td>@tweetday</td></tr>
		</table>
		<ul class="remarks">@remarks</ul>
	</div>
	<form class="actions" method="post">
		<div>
			<a class="button" href="/@:xid">posts</a>
			<a class="button" href="/@:xid/arc">archive</a>
			<a class="button" href="/@:xid/media">media</a>
			<a class="button" href="/@:xid/social">associates</a>

		</div>
		<div>
			@auxbtn
		</div>
	</form>
</div>