Merge remote-tracking branch 'origin/develop' into lf/total-rewrite

This commit is contained in:
Liam Fitzgerald 2024-05-28 08:34:46 -04:00
commit 5f8e76b71a
33 changed files with 4398 additions and 1193 deletions

View File

@ -0,0 +1,60 @@
|%
++ svg
|= [viewbox=tape body=manx]
;svg
=xmlns "http://www.w3.org/2000/svg"
=viewBox viewbox
=width "1em"
=style "display: flex;"
=fill "currentColor"
;+ body
==
++ chevron-left
%+ svg "0 -960 960 960"
;path
=d "M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z"
;
==
++ chevron-right
%+ svg "0 -960 960 960"
;path
=d "M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"
;
==
++ close
%+ svg "0 -960 960 960"
;path
=d "m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"
;
==
++ outline
%+ svg "0 -960 960 960"
;path
=d "M120-240v-80h240v80H120Zm0-200v-80h480v80H120Zm0-200v-80h720v80H120Z"
;
==
++ minimize
%+ svg "0 -960 960 960"
;path
=d "M240-120v-80h480v80H240Z"
;
==
++ loading
%+ svg "0 0 44 44"
;g(fill "none", fill-rule "evenodd", stroke-width "2", stroke "#fff")
;circle(cx "22", cy "22", r "1")
;animate(attributeName "r", begin "0s", dur "1.8s", values "1; 20", calcMode "spline", keyTimes "0; 1", keySplines "0.165, 0.84, 0.44, 1", repeatCount "indefinite");
;animate(attributeName "stroke-opacity", begin "0s", dur "1.8s", values "1; 0", calcMode "spline", keyTimes "0; 1", keySplines "0.3, 0.61, 0.355, 1", repeatCount "indefinite");
==
;circle(cx "22", cy "22", r "1")
;animate(attributeName "r", begin "-0.9s", dur "1.8s", values "1; 20", calcMode "spline", keyTimes "0; 1", keySplines "0.165, 0.84, 0.44, 1", repeatCount "indefinite");
;animate(attributeName "stroke-opacity", begin "-0.9s", dur "1.8s", values "1; 0", calcMode "spline", keyTimes "0; 1", keySplines "0.3, 0.61, 0.355, 1", repeatCount "indefinite");
==
==
++ add
%+ svg "0 -960 960 960"
;path
=d "M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"
;
==
--

View File

@ -0,0 +1,73 @@
/@ sky-settings
|%
++ state %sky-settings
++ poke (sy %sky-settings ~)
++ kids *kids:neo
++ deps *deps:neo
++ form
^- form:neo
|_ [=bowl:neo =ever:neo state-vase=vase *]
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo vase)
:- ~
vax
++ init
|= vas=(unit vase)
^- (quip card:neo vase)
:- ~
!>
:*
%- malt
^- (list [@t @t])
:~
:- 'font' 'Urbit Sans'
:- 'font-mono' 'monospace'
:- 'mono-scale' '0.8'
:- 'letter-spacing' '0.024em'
:- 'line-height' '1.4'
:- '1in' '4px'
::
:- 'sky-opacity' '0.88'
:- 'sky-bg-size' 'contain'
:- 'sky-bg-url' ''
:- 'sky-outer-gap' '8px'
:- 'sky-inner-gap' '8px'
::
:- 'light-b-3' '#dd5522'
:- 'light-b-2' '#ddaa33'
:- 'light-b-1' '#55dd33'
:- 'light-b0' '#dddddd'
:- 'light-b1' '#cccccc'
:- 'light-b2' '#bbbbbb'
:- 'light-b3' '#aaaaaa'
:- 'light-b4' '#999999'
:- 'light-f-3' '#993311'
:- 'light-f-2' '#aaaa22'
:- 'light-f-1' '#339911'
:- 'light-f0' '#111111'
:- 'light-f1' '#333333'
:- 'light-f2' '#444444'
:- 'light-f3' '#555555'
:- 'light-f4' '#777777'
::
:- 'dark-b-3' '#551111'
:- 'dark-b-2' '#555511'
:- 'dark-b-1' '#225511'
:- 'dark-b0' '#222222'
:- 'dark-b1' '#333333'
:- 'dark-b2' '#444444'
:- 'dark-b3' '#555555'
:- 'dark-b4' '#666666'
:- 'dark-f-3' '#ee7755'
:- 'dark-f-2' '#ccbb33'
:- 'dark-f-1' '#55cc33'
:- 'dark-f0' '#eeeeee'
:- 'dark-f1' '#cccccc'
:- 'dark-f2' '#bbbbbb'
:- 'dark-f3' '#aaaaaa'
:- 'dark-f4' '#888888'
==
==
--
--

View File

@ -0,0 +1,60 @@
|%
++ svg
|= [viewbox=tape body=manx]
;svg
=xmlns "http://www.w3.org/2000/svg"
=viewBox viewbox
=width "1em"
=fill "currentColor"
=style "display: flex;"
;+ body
==
++ chevron-left
%+ svg "0 -960 960 960"
;path
=d "M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z"
;
==
++ chevron-right
%+ svg "0 -960 960 960"
;path
=d "M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"
;
==
++ close
%+ svg "0 -960 960 960"
;path
=d "m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"
;
==
++ outline
%+ svg "0 -960 960 960"
;path
=d "M120-240v-80h240v80H120Zm0-200v-80h480v80H120Zm0-200v-80h720v80H120Z"
;
==
++ minimize
%+ svg "0 -960 960 960"
;path
=d "M240-120v-80h480v80H240Z"
;
==
++ loading
%+ svg "0 0 44 44"
;g(fill "none", fill-rule "evenodd", stroke-width "2", stroke "#fff")
;circle(cx "22", cy "22", r "1")
;animate(attributeName "r", begin "0s", dur "1.8s", values "1; 20", calcMode "spline", keyTimes "0; 1", keySplines "0.165, 0.84, 0.44, 1", repeatCount "indefinite");
;animate(attributeName "stroke-opacity", begin "0s", dur "1.8s", values "1; 0", calcMode "spline", keyTimes "0; 1", keySplines "0.3, 0.61, 0.355, 1", repeatCount "indefinite");
==
;circle(cx "22", cy "22", r "1")
;animate(attributeName "r", begin "-0.9s", dur "1.8s", values "1; 20", calcMode "spline", keyTimes "0; 1", keySplines "0.165, 0.84, 0.44, 1", repeatCount "indefinite");
;animate(attributeName "stroke-opacity", begin "-0.9s", dur "1.8s", values "1; 0", calcMode "spline", keyTimes "0; 1", keySplines "0.3, 0.61, 0.355, 1", repeatCount "indefinite");
==
==
++ add
%+ svg "0 -960 960 960"
;path
=d "M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"
;
==
--

View File

@ -0,0 +1,420 @@
|_ a=manx
:: named
::
:: first child with name=tape, or null
::
++ named
|= name=tape
^- (unit manx)
=/ n
%+ skim pre-flatten
|= =manx
=((~(gut by (malt a.g.manx)) %name "") name)
?: =(0 (lent n)) ~
`(snag 0 n)
:: get
::
:: tape at attribute, or null
::
++ get
|= =mane
^- (unit tape)
(~(get by (malt a.g.a)) mane)
:: got
::
:: cord of attribute, or crash
::
++ got
|= =mane
^- cord
~| (crip "cannont find attribute {<mane>}")
(crip (need (get mane)))
:: val
::
:: value (tape) attribute of first named descendant, or null
::
++ val
|= name=tape
^- (unit tape)
?~ t=(named name) ~
=. a u.t
(get %value)
:: vol
::
:: value (cord) attribute of first named descendant, or crash
::
++ vol
|= name=tape
^- cord
~| (crip "cannont find element with name '{<name>}'")
(crip (need (val name)))
:: whitelisted
::
:: check all tags are in whitelist
::
++ whitelisted
|= b=(set mane)
^- ?
%- post-fold
|= [g=marx w=?]
?. w w
(~(has in b) n.g)
:: whitelisted
::
:: check whether any tags are in blacklist
::
++ blacklisted
|= b=(set mane)
^- ?
%- post-fold
|= [g=marx w=_|]
?: w w
(~(has in b) n.g)
:: get-max-depth
::
:: deepest node depth (root is 0)
::
++ get-max-depth
^- @ud
|-
?~ c.a 0
%+ max
.+ $(c.a c.i.c.a)
$(c.a t.c.a)
:: apply-elem:
::
:: apply gate to tags/attrs
::
++ apply-elem
|= b=$-(marx marx)
|^ ^- manx
[(b g.a) (cloop c.a)]
++ cloop
|= c=marl
?~ c ~
[^$(a i.c) (cloop t.c)]
--
:: apply-elem-chain
::
:: apply gate to tags/attrs with parentage given
::
:: gate takes [a b] where a is the current marx
:: and b is the list of parent marxes in ascending
:: order (i is the direct parent)
::
++ apply-elem-chain
=/ ch=(lest marx) ~[g.a]
|= b=$-([marx (list marx)] marx)
|^ ^- manx
[(b ch) (cloop c.a)]
++ cloop
|= c=marl
?~ c ~
[^$(a i.c, ch [g.i.c ch]) (cloop t.c)]
--
:: post-apply-nodes
::
:: apply gate to nodes in postorder
::
:: (unlike apply-elem, the gate takes the
:: whole manx instead of just marx)
::
++ post-apply-nodes
|= b=$-(manx manx)
|^ ^- manx
(b [g.a (cloop c.a)])
++ cloop
|= c=marl
?~ c ~
[^$(a i.c) (cloop t.c)]
--
:: apply-attrs
::
:: apply a gate to all attributes
::
++ apply-attrs
|= b=$-([mane tape] [mane tape])
^- manx
%- apply-elem
|= g=marx
=| y=mart
|-
?~ a.g g(a (flop y))
$(a.g t.a.g, y [(b i.a.g) y])
:: apply-text
::
:: apply a gate to all ordinary text
::
++ apply-text
|= b=$-(tape tape)
^- manx
%- apply-elem
|= g=marx
?. ?=(%$ n.g) g
?~ a.g g
?. ?=(%$ n.i.a.g) g
?^ t.a.g g
=. v.i.a.g (b v.i.a.g) g
:: post-fold
::
:: fold over tags/attrs in postorder
::
++ post-fold
|* b=_|=([marx *] +<+)
^+ ,.+<+.b
|-
?~ c.a (b g.a +<+.b)
$(a a(c t.c.a), +<+.b $(a i.c.a))
:: pre-fold
::
:: fold over tags/attrs in preorder
::
++ pre-fold
|* b=_|=([marx *] +<+)
^+ ,.+<+.b
|-
?~ c.a
?: =(%$^%$ n.g.a)
+<+.b
(b g.a +<+.b)
%= $
a [[%$^%$ ~] t.c.a]
+<+.b
%= $
a i.c.a
+<+.b
?: =(%$^%$ n.g.a)
+<+.b
(b g.a +<+.b)
==
==
:: lvl-fold
::
:: fold over tags/attrs in level order
::
++ lvl-fold
|* b=_|=([marx *] +<+)
|^ ^+ ,.+<+.b
=. +<+.b (b g.a +<+.b)
(cloop-a c.a +<+.b)
++ cloop-a
|= [c=marl acc=_+<+.b]
=/ l c
|-
?~ l (cloop-b c acc)
$(l t.l, acc (b g.i.l acc))
++ cloop-b
|= [c=marl acc=_+<+.b]
?~ c acc
$(c t.c, acc (cloop-a c.i.c acc))
--
:: prune
::
:: delete nodes when applied gate produces %.y
::
++ prune
|= b=$-(manx ?)
|^ ^- (unit manx)
?: (b a) ~
[~ g.a (cloop c.a)]
++ cloop
=| fro=marl
|= to=marl
?~ to (flop fro)
=+ u=^$(a i.to)
?~ u $(to t.to)
$(to t.to, fro [u.u fro])
--
:: prune-tag
::
:: delete nodes by tag
::
++ prune-tag
|= b=mane
^- (unit manx)
(prune |=(x=manx =(b n.g.x)))
::
:: prune-tags
::
:: delete nodes by tags
::
++ prune-tags
|= b=(set mane)
^- (unit manx)
(prune |=(x=manx (~(has in b) n.g.x)))
:: prune-namespace
::
:: delete nodes by tag namespace
::
++ prune-namespace
|= b=@tas
^- (unit manx)
(prune |=(x=manx ?@(n.g.x %.n =(b -.n.g.x))))
:: prune-namespaces
::
:: delete nodes by tag namespaces
::
++ prune-namespaces
|= b=(set @tas)
^- (unit manx)
(prune |=(x=manx ?@(n.g.x %.n (~(has in b) -.n.g.x))))
:: prune-attr
::
:: delete nodes by attribute name
::
++ prune-attr
|= b=mane
^- (unit manx)
%- prune
|= x=manx
%+ roll a.g.x
|= [[n=mane v=tape] w=_|]
?:(w w =(n b))
:: prune-attrs
::
:: delete nodes by attribute names
::
++ prune-attrs
|= b=(set mane)
^- (unit manx)
%- prune
|= x=manx
%+ roll a.g.x
|= [[n=mane v=tape] w=_|]
?: w w
(~(has in b) n)
:: prune-depth
::
:: delete nodes deeper than b (root is 0)
::
++ prune-depth
|= b=@ud
|^ ^- (unit manx)
?: =(0 b) ~
[~ g.a (cloop c.a)]
++ cloop
|= to=marl
=| fro=marl
|-
?~ to (flop fro)
=/ x (prune-depth(a i.to) (dec b))
?~ x $(to t.to)
$(to t.to, fro [u.x fro])
--
:: del-attrs
::
:: delete attributes by name
::
++ del-attrs
|= b=(set mane)
^- manx
%- apply-elem
|= g=marx
=| y=mart
|-
?~ a.g g(a (flop y))
?: (~(has in b) n.i.a.g)
$(a.g t.a.g)
$(a.g t.a.g, y [i.a.g y])
:: keep-attrs
::
:: delete all attributes except those
:: with the given names
::
++ keep-attrs
|= b=(set mane)
^- manx
%- apply-elem
|= g=marx
=| y=mart
|-
?~ a.g g(a (flop y))
?. (~(has in b) n.i.a.g)
$(a.g t.a.g)
$(a.g t.a.g, y [i.a.g y])
:: post-flatten
::
:: get a list of elements by postorder traversal
::
++ post-flatten
^- marl
(flop (post-fold |=([g=marx l=marl] [[g ~] l])))
:: pre-flatten
::
:: get a list of elements by preorder traversal
::
++ pre-flatten
^- marl
(flop (pre-fold |=([g=marx l=marl] [[g ~] l])))
:: lvl-flatten
::
:: get a list of elements by level order traversal
::
++ lvl-flatten
^- marl
(flop (lvl-fold |=([g=marx l=marl] [[g ~] l])))
:: post-get-text
::
:: get a list of plain text by postorder traversal
::
++ post-get-text
^- wall
%- flop
%- post-fold
|= [g=marx l=wall]
?. ?=(%$ n.g) l
?~ a.g l
?. ?=(%$ n.i.a.g) l
?^ t.a.g l
:- v.i.a.g l
:: pre-get-text
::
:: get a list of plain text by preorder traversal
::
++ pre-get-text
^- wall
%- flop
%- pre-fold
|= [g=marx l=wall]
?. ?=(%$ n.g) l
?~ a.g l
?. ?=(%$ n.i.a.g) l
?^ t.a.g l
:- v.i.a.g l
:: lvl-get-text
::
:: get a list of plain text by level order traversal
::
++ lvl-get-text
^- wall
%- flop
%- lvl-fold
|= [g=marx l=wall]
?. ?=(%$ n.g) l
?~ a.g l
?. ?=(%$ n.i.a.g) l
?^ t.a.g l
:- v.i.a.g l
:: search-text
::
:: find plain text containing the given cord
::
++ search-text
|= b=@t
^- wall
%- flop
%- post-fold
|= [g=marx l=wall]
?. ?=(%$ n.g) l
?~ a.g l
?. ?=(%$ n.i.a.g) l
?^ t.a.g l
=+ par=(cury (jest b) *hair)
?. |-
?~ v.i.a.g %.n
?^ (tail (par v.i.a.g))
%.y
$(v.i.a.g t.v.i.a.g)
l
[v.i.a.g l]
--

View File

@ -0,0 +1,11 @@
$%
[%theme mode=?(%light %dark) palette=(map @t @t)]
[%hawks hawks=(list pith) slots=@]
[%new-tab ~]
[%move-tab slot=@ud =pith]
[%minimize slot=@ud]
[%maximize slot=@ud]
[%close slot=@ud]
[%slide-up slot=@ud]
[%slide-down slot=@ud]
==

View File

@ -0,0 +1 @@
,(map @t @t)

View File

@ -1,5 +1,4 @@
$:
theme=?(%light %dark %system)
hawks=(list pith)
slots=@
hawks=(list (pair @da pith))
open=@ud
==

View File

@ -0,0 +1,64 @@
/@ diary
:- [%diary %htmx]
|= dia=diary
|= =bowl:neo
^- manx
|^ shell
++ form-put-entry
::
;form.fc.g2
=hx-post "{(en-tape:pith:neo :(weld /neo/hawk here.bowl))}?stud=diary-diff"
=hx-on-submit "this.reset()"
=hx-target "this"
=hx-swap "afterend"
=head "put-entry"
;date-now(name "id");
;textarea.p2.border.br1
=name "text"
=placeholder ". . . text"
=oninput "this.setAttribute('value', this.value)"
=rows "4"
=required ""
=autocomplete "off"
;
==
;button.p2.b1.br1.wfc.hover
; create
==
==
::
++ link-entry
::
|= [pax=pith =pail:neo]
=/ tape (trip !<(@t q.pail))
=/ subject-end (fall (find [10]~ tape) 56)
=/ subject (scag subject-end tape)
=/ id (trip (snag 0 (pout pax)))
;div.fr.g2
;a.p2.br1.grow.fc.g1.js.as.g2.b1.hover
=href "{(en-tape:pith:neo (weld /neo/hawk here.bowl))}/{id}"
;span: {id}
;span.bold: {subject}
==
;button.p2.br1.fr.g2.b1.hover.fc.ac.jc
=onclick "alert('not yet implemented. no tombstoning?')"
; X
==
==
::
++ shell
::
;div.p2
=label "Diary"
;div.ma.fc.g2
=style "max-width: 650px;"
;+ form-put-entry
;*
%+ turn
%+ sort ~(tap by kids.bowl)
|= [a=[=pith *] b=[=pith *]]
(gth ->.pith.a ->.pith.b)
link-entry
==
==
--

View File

@ -0,0 +1,682 @@
:- [%ford-out %htmx]
=/ debug |
|= fod=[cache=(unit vase) ~]
|= =bowl:neo
^- manx
=< apex
|%
++ dprint
=>
:: dprint-types
|%
:: $overview: an overview of all named things in the type.
::
:: each element in the overview list is either a documentation for a sublist
:: or an association betwen a term and documentation for it
+$ overview (list overview-item)
::
:: $overview-item: an element of an overview
+$ overview-item
$% [%header doc=what children=overview]
[%item name=tape doc=what]
==
::
:: $item: the part of a type being inspected
+$ item
$%
:: overview of a type
::
[%view items=overview]
:: inspecting a full core
$: %core
name=tape :: arm that built it
docs=what ::
sut=type :: [%core *]
children=(unit item) :: compiled against
==
:: inspecting a single arm on a core
$: %arm
name=tape :: arm name
adoc=what :: arm doc
pdoc=what :: product doc
cdoc=what :: $ arm/prod doc
gen=hoon :: arm hoon AST
sut=type :: subject of arm
==
:: inspecting a face and what's behind it
$: %face
name=tape :: name of face
docs=what ::
children=(unit item) :: face referent
==
:: inspecting a single chapter on a core
$: %chapter
name=tape :: name of chapter
docs=what ::
sut=type :: [%core *]
tom=tome :: tome of chapter
==
==
::
--
:: dprint
::
:: core containing doccords search and printing utilities
|%
:: contains arms used for looking for docs inside of a type
::
:: the entrypoint for finding docs within a type is +find-item-in-type.
+| %searching
:: +find-item-in-type: returns the item to print while searching through topic
::
:: this gate is a thin wrapper around _hunt for usability, since the only entry
:: point most users should care about is find-item:hunt
::
++ find-item-in-type
|= [topics=(list term) sut=type]
?~ topics !!
=/ top=(lest term) topics
~(find-item hunt [top sut])
::
:: +hunt: door used for refining the type while searching for doccords
::
++ hunt
=| gil=(set type)
|_ [topics=(lest term) sut=type]
+* this .
::
+| %find
::
++ find-item
~? >> debug %find-item
^- (unit item)
?- sut
%noun ~
%void ~
[%atom *] ~
[%cell *] find-cell
[%core *] find-core
[%face *] find-face
[%fork *] find-fork
[%hint *] find-hint
[%hold *] find-item:this(sut (~(play ut p.sut) q.sut))
==
::
++ find-cell
~? >> debug %find-cell
^- (unit item)
?> ?=([%cell *] sut)
=/ lhs find-item:this(sut p.sut)
?~ lhs
find-item:this(sut q.sut)
lhs
::
++ find-core
~? >> debug %find-core
^- (unit item)
?> ?=([%core *] sut)
?: check-arm
?: check-search
?: check-arm-core
return-arm-core
return-arm
recurse-arm-core
?: check-chap
?: check-search
return-chap
recurse-chap
recurse-core
::
++ find-face
~? >> debug %find-face
^- (unit item)
?> ?=([%face *] sut)
?. ?=(term p.sut)
::TODO: handle $tune case
find-item:this(sut q.sut)
?. =(i.topics p.sut)
~
?~ t.topics
return-face
find-item:this(sut q.sut, topics t.topics)
::
++ find-fork
~? >> debug %find-fork
^- (unit item)
?> ?=([%fork *] sut)
=/ types=(list type) ~(tap in p.sut)
|-
?~ types ~
=+ res=find-item:this(sut i.types)
?~ res
$(types t.types)
res
::
++ find-hint
~? >> debug %find-hint
^- (unit item)
|^
?> ?=([%hint *] sut)
?. ?=([%help *] q.p.sut)
find-item:this(sut q.sut)
?+ q.sut ~
[%cell *] find-cell:this(sut q.sut)
[%core *] find-hint-core
[%face *] find-hint-face
[%fork *] find-fork:this(sut q.sut)
[%hint *] find-hint:this(sut q.sut)
[%hold *] find-hint:this(q.sut (~(play ut p.q.sut) q.q.sut))
==
::
++ find-hint-core
~? >> debug %find-hint-core
^- (unit item)
?> &(?=([%hint *] sut) ?=([%help *] q.p.sut) ?=([%core *] q.sut))
::
?. ?& ((sane %tas) summary.crib.p.q.p.sut)
=(summary.crib.p.q.p.sut i.topics)
==
find-core:this(sut q.sut)
?~ t.topics
return-hint-core
find-item:this(sut q.sut, topics t.topics)
::
++ find-hint-face
~? >> debug %find-hint-face
^- (unit item)
?> &(?=([%hint *] sut) ?=([%help *] q.p.sut) ?=([%face *] q.sut))
?: check-face:this(sut q.sut)
?~ t.topics
return-hint-face
find-item:this(sut q.q.sut, topics t.topics)
find-item:this(sut q.q.sut)
--
::
::+| %recurse
++ recurse-core
~? >> debug %recurse-core
^- (unit item)
?> ?=([%core *] sut)
find-item:this(sut p.sut)
++ recurse-chap
~? >> debug %recurse-chap
^- (unit item)
?> ?=([%core *] sut)
?~ t.topics !!
find-item:this(topics t.topics)
++ recurse-arm-core
~? >> debug %recurse-arm-core
^- (unit item)
?> ?=([%core *] sut)
?~ t.topics !!
find-item:this(sut arm-type, topics t.topics)
::
+| %check
::
++ check-arm
~? >> debug %recurse-core
^- ?
!=(~ (find ~[i.topics] (sloe sut)))
++ check-chap
~? >> debug %check-chap
^- ?
?> ?=([%core *] sut)
(~(has by q.r.q.sut) i.topics)
++ check-face
~? >> debug %check-face
^- ?
?> ?=([%face *] sut)
?. ?=(term p.sut)
::TODO: handle $tune case
%.n
=(p.sut i.topics)
++ check-search
~? >> debug %check-search
^- ?
=(~ t.topics)
++ check-arm-core
~? >> debug %check-arm-core
^- ?
=+ arm-list=(sloe (~(play ut sut) arm-hoon))
&(!=(arm-list ~) !=(arm-list ~[%$]) ?=([%core *] arm-type))
::
+| %return
::
++ return-cell
~? >>> debug %return-cell
^- (unit item)
?> ?=([%cell *] sut)
(join-items return-item:this(sut p.sut) return-item:this(sut q.sut))
::
++ return-core
~? >>> debug %return-core
^- (unit item)
?> ?=([%core *] sut)
=* compiled-against return-item:this(sut p.sut)
`[%core (trip i.topics) *what sut compiled-against]
::
++ return-face
~? >>> debug %return-face
^- (unit item)
?> ?=([%face *] sut)
:: TODO: handle tune case
?. ?=(term p.sut)
return-item:this(sut q.sut)
=* compiled-against return-item:this(sut q.sut)
`[%face (trip p.sut) *what compiled-against]
::
++ return-fork
~? >>> debug %return-fork
^- (unit item)
?> ?=([%fork *] sut)
=* types ~(tap in p.sut)
=* items (turn types |=(a=type return-item:this(sut a)))
(roll items join-items)
::
++ return-hint
~? >>> debug %return-hint
^- (unit item)
?> ?=([%hint *] sut)
=* res return-item:this(sut q.sut)
?. ?=([%help *] q.p.sut)
~
?: ?=([%core *] q.sut)
return-hint-core
?: ?=([%face *] q.sut)
return-hint-face
`[%view [%header `crib.p.q.p.sut (item-as-overview res)]~]
::
++ return-arm
~? >>> debug %return-arm
^- (unit item)
?> ?=([%core *] sut)
=+ [adoc pdoc cdoc]=(arm-docs i.topics sut)
::TODO: should this p.sut be sut? or the compiled type of the arm?
`[%arm (trip i.topics) adoc pdoc cdoc arm-hoon sut]
::
++ return-chap
~? >>> debug %return-chap
^- (unit item)
?> ?=([%core *] sut)
=/ tom=tome (~(got by q.r.q.sut) i.topics)
`[%chapter (trip i.topics) p.tom sut (~(got by q.r.q.sut) i.topics)]
::
++ return-arm-core
~? >>> debug %return-arm-core
^- (unit item)
?> ?=([%core *] sut)
=+ [adoc pdoc cdoc]=(arm-docs i.topics sut)
=/ dox=what ?~(adoc ?~(pdoc ~ pdoc) adoc)
=/ at arm-type
?> ?=([%core *] at)
=* compiled-against return-item:this(sut p.sut)
`[%core (trip i.topics) dox at compiled-against]
::
++ return-item
~? >>> debug %return-item
^- (unit item)
?- sut
%noun ~
%void ~
[%atom *] ~
[%cell *] return-cell
[%core *] return-core
[%face *] return-face
[%fork *] return-fork
[%hint *] return-hint
[%hold *]
?: (~(has in gil) sut)
~
=< return-item
%= this
gil (~(put in gil) sut)
sut (~(play ut p.sut) q.sut)
==
==
::
++ return-hint-core
~? >>> debug %return-hint-core
^- (unit item)
?> &(?=([%hint *] sut) ?=([%core *] q.sut))
(apply-hint return-core:this(sut q.sut))
::
++ return-hint-face
~? >>> debug %return-hint-face
^- (unit item)
?> &(?=([%hint *] sut) ?=([%face *] q.sut))
(apply-hint return-face:this(sut q.sut))
::
++ apply-hint
~? >> debug %apply-hint
|= uit=(unit item)
^- (unit item)
?~ uit ~
?> &(?=([%hint *] sut) ?=([%help *] q.p.sut))
?+ u.uit ~
?([%core *] [%face *]) (some u.uit(docs `crib.p.q.p.sut))
==
::
+| %misc
++ arm-hoon
^- hoon
?> ?=([%core *] sut)
(^arm-hoon i.topics sut)
::
++ arm-type
^- type
?> ?=([%core *] sut)
(^arm-type i.topics sut)
--
::
:: +arm-hoon: looks for an arm in a core type and returns its hoon
++ arm-hoon
|= [nom=term sut=type]
^- hoon
?> ?=([%core *] sut)
=/ tomes=(list [p=term q=tome]) ~(tap by q.r.q.sut)
|-
?~ tomes !!
=+ gen=(~(get by q.q.i.tomes) nom)
?~ gen
$(tomes t.tomes)
u.gen
::
:: +arm-type: looks for an arm in a core type and returns its type
++ arm-type
|= [nom=term sut=type]
^- type
?> ?=([%core *] sut)
(~(play ut sut) (arm-hoon nom sut))
::
:: +hint-doc: returns docs if type is %help $hint w/ matching cuff
++ hint-doc
|= [=cuff sut=type]
^- what
?. &(?=([%hint *] sut) ?=([%help *] q.p.sut) =(cuff cuff.p.q.p.sut))
~
`crib.p.q.p.sut
::
:: +arm-doc: returns arm doc of an arm
::
:: we just check if the $cuff is from a ++ or +$ arm but this will
:: probably need to be revisited once more sophisticated cuffs are used
++ arm-doc
|= [nom=term sut=type]
^- what
?~ (hint-doc [%funk nom]~ sut)
(hint-doc [%plan nom]~ sut)
(hint-doc [%funk nom]~ sut)
::
:: +prod-doc: wrapper for +hint-doc with empty cuff
++ prod-doc
|= sut=type
^- what
(hint-doc ~ sut)
::
:: +buc-doc: checks if type is core and returns docs on $ arm if it exists
++ buc-doc
|= sut=type
^- what
?. ?=([%core *] sut)
~
?~ (find [%$]~ (sloe sut))
~
=/ sat=type (arm-type %$ sut)
?~ (arm-doc %$ sat)
(prod-doc sat)
(arm-doc %$ sat)
::
:: +arm-docs: grabs the docs for an arm.
::
:: there are three possible places with relevant docs for an arm:
:: docs for the arm itself, docs for the product of the arm, and
:: if the arm builds a core, docs for the default arm of that core.
::
:: .adoc: docs written above the the arm
:: .pdoc: docs for the product of the arm
:: .cdoc: docs for the default arm of the core produced by the arm
++ arm-docs
|= [nom=term sut=type]
^- [what what what]
?> ?=([%core *] sut)
=/ sat=type (~(play ut sut) (arm-hoon nom sut))
=/ adoc=what (arm-doc nom sat)
=/ pdoc=what
?~ adoc
(prod-doc sat)
?> ?=([%hint *] sat)
(prod-doc q.sat)
=/ cdoc=what
?~ adoc
?~ pdoc
(buc-doc sat)
?> ?=([%hint *] sat)
(buc-doc q.sat)
?~ pdoc
?> ?=([%hint *] sat)
(buc-doc q.sat)
?> &(?=([%hint *] sat) ?=([%hint *] q.sat))
(buc-doc q.q.sat)
[adoc pdoc cdoc]
::
:: +arm-and-chapter-overviews: returns an overview of a core's contents
::
:: returns an overview for arms which are part of unnamed chapters, and
:: an overview of the named chapters
::
++ arm-and-chapter-overviews
|= =item
^- [overview overview]
?> &(?=([%core *] item) ?=([%core *] sut.item))
=| [adocs=overview cdocs=overview]
=/ tomes ~(tap by q.r.q.sut.item)
|-
?~ tomes
[(sort-overview adocs) (sort-overview cdocs)]
?~ p.i.tomes
:: chapter has no name. add documentation for its arms to arm-docs
=. adocs (weld adocs (tome-as-overview q.i.tomes sut.item))
$(tomes t.tomes)
:: chapter has a name. add to list of chapters
=. cdocs
%+ weld cdocs
^- overview
[%item :(weld "^" name.item "|" (trip -.i.tomes)) p.q.i.tomes]~
$(tomes t.tomes)
::
:: +arms-in-chapter: returns an overview of the arms in a specific chapter
++ arms-in-chapter
|= [sut=type tom=tome]
^- overview
(sort-overview (tome-as-overview tom sut))
::
:: +sort-overview: sort items in an overview in alphabetical order
++ sort-overview
|= ovr=overview
^- overview
%+ sort ovr
|= [lhs=overview-item rhs=overview-item]
(aor (get-overview-name lhs) (get-overview-name rhs))
::
:: +get-overview-name: returns the name of an overview
++ get-overview-name
|= ovr=overview-item
?- ovr
[%header *] ""
[%item *] name.ovr
==
::
:: +tome-as-overview: translate a tome into an overview
++ tome-as-overview
|= [tom=tome sut=type]
^- overview
%+ turn ~(tap by q.tom)
|= ar=(pair term hoon)
:* %item
::TODO make this distinguish between ++ and +$ arms
(weld "+" (trip p.ar))
=/ adoc (arm-doc p.ar (~(play ut sut) q.ar))
=/ pdoc (prod-doc (~(play ut sut) q.ar))
?~ adoc
pdoc
adoc
==
::
:: +item-as-overview: changes an item into an overview
++ item-as-overview
|= uit=(unit item)
~? >> debug %item-as-overview
^- overview
?~ uit ~
=+ itm=(need uit)
?- itm
[%view *] items.itm
::
[%core *]
?~ name.itm
(item-as-overview children.itm)
:- [%item (weld "^" name.itm) docs.itm]
(item-as-overview children.itm)
::
[%arm *]
:_ ~
::TODO make this distinguish between ++ and +$ arms
:* %item (weld "+" name.itm)
?~ adoc.itm
?~ pdoc.itm
cdoc.itm
pdoc.itm
adoc.itm
==
::
[%chapter *]
[%item (weld "|" name.itm) docs.itm]~
::
[%face *]
?~ name.itm
~
[%item (weld "." name.itm) docs.itm]~
==
::
:: +join-items: combines two (unit items) together
++ join-items
|= [lhs=(unit item) rhs=(unit item)]
^- (unit item)
?~ lhs rhs
?~ rhs lhs
`[%view (weld (item-as-overview lhs) (item-as-overview rhs))]
--
:: XX: non-std
++ post-href
|= =post:neo
^- path
?> ?=(@ q.post)
=/ dsk
/neo/hawk/out/std
%+ welp dsk
/[p.post]/[q.post]
::
++ apex
;div
;+
?~ cache.fod
empty
(have u.cache.fod)
==
++ empty
;h4: No build result here
++ fallback
|= vax=vase
;div
;*
=/ arms (sloe p.vax)
%+ turn arms
|= a=term
^- manx
(desc-arm a p.vax)
==
++ over-to-manx
|= ove=overview:dprint
^- manx
;div
;*
%+ turn ove
|= tem=overview-item:dprint
^- manx
(over-item-to-manx tem)
==
++ what-to-manx
|= wat=what
^- manx
?~ wat
;div: Nothing here
;div.what
;h6: {(trip p.u.wat)}
;div
;* ^- (list manx)
%- zing
^- (list (list manx))
%+ turn q.u.wat
|= sec=sect
^- (list manx)
%+ turn sec
|= pic=pica
^- manx
?: p.pic
;div: {(trip q.pic)}
;code.pre: {(trip q.pic)}
==
==
++ over-item-to-manx
|= tem=overview-item:dprint
^- manx
?- -.tem
%header
;div.over-item-head
;+ (what-to-manx doc.tem)
;+ (over-to-manx children.tem)
==
::
%item
;div.over-item-item
;h6: {name.tem}
;+ (what-to-manx doc.tem)
==
==
++ desc-arm
|= [arm=term sut=type]
^- manx
=/ tem (find-item-in-type:dprint ~[arm] sut)
~& tem/tem
(over-to-manx (item-as-overview:dprint tem))
++ have
|= vax=vase
=/ fim=(unit firm:neo)
(mole |.(!<(firm:neo vax)))
?> ?=(^ fim)
;div.p2.fc.g2
;h4: Shrub implementation
;h5: State
;button.b1.br1.p2.hover.wfc
=hx-get (spud (post-href %pro state:u.fim))
=hx-target "closest .hawk"
=hx-swap "innerHTML"
; {<state:u.fim>}
==
;h5: Pokes
;div.frw.g2
;*
%+ turn ~(tap in poke:u.fim)
|= =stud:neo
^- manx
;button.p2.br1.b1.hover
=hx-get (spud (post-href %pro stud))
=hx-target "closest .hawk"
=hx-swap "innerHTML"
; {<stud>}
==
==
==
--

View File

@ -0,0 +1,70 @@
/@ htmx
:- [%hoon %htmx]
|= hon=@t
|= =bowl:neo
=/ =name:neo
[our here]:bowl
=/ =file:ford:neo
(scan (trip hon) (rein:ford:neo name))
=/ src=wain
(to-wain:format hon)
^- manx
=< apex
|%
:: XX: non-std
++ post-href
|= =post:neo
^- path
?> ?=(@ q.post)
=/ dsk
/neo/hawk/src/std
%+ welp dsk
/[p.post]/[q.post]
::
++ apex
^- manx
;div.scroll-x.p3
;+ imports
;+ contents
==
++ imports
;div.p2
;div.p2.border.br1.fc.g2
;h4.bold: Protocols
;div.frw.g2
;*
%+ turn pro.file
|= =pro:ford:neo
^- manx
;a.p2.br1.b1.hover
=hx-get (spud (post-href %pro stud.pro))
=hx-target "closest .hawk"
=hx-swap "innerHTML"
; {<stud.pro>}
==
==
==
==
++ contents
;form.fc.g2.wf.relative.p2
=hx-put "{(en-tape:pith:neo (welp /neo/hawk here.bowl))}?stud=hoon"
;div.p2.wf.z1
=style "position: sticky; top: 0; right: 0;"
;button.p2.br1.b1.hover.loader.wf
;span.loaded: save
;span.loading: ...
==
==
;textarea.p2.border.br1.ma.scroll-x.pre.mono.wf
=style "max-width: 650px;"
=autocomplete "off"
=rows "45"
=name "text"
=oninput "this.setAttribute('value', this.value);"
;*
%+ turn src
|= lin=@t
;/ "{(trip lin)}\0a"
==
==
--

View File

@ -0,0 +1,37 @@
/@ iframe
:- [%iframe %htmx]
|= =iframe
|= =bowl:neo
^- manx
|^ shell
::
++ shell
::
=/ url (trip iframe)
;div.wf.hf.fc
=label "iframe"
=here (en-tape:pith:neo here.bowl)
;form.fr
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=iframe"
=hx-swap "none"
=style "border-bottom: 1px solid #777;"
;input.p2.grow
=type "text"
=name "text"
=value url
=is "atom-input"
=oninput "this.parentNode.nextElementSibling.src = this.value;"
;
==
;button.p2.b1
; Save
==
==
;iframe.wf.hf.bd0
=style "background-color: #eee;"
=id "iframe-{url}"
=src url
;
==
==
--

View File

@ -0,0 +1,11 @@
/@ node
/@ diary-diff
/- _/manx-utils
:- [%node %diary-diff]
|= nod=node
^- diary-diff
=/ mu ~(. manx-utils nod)
=/ head (@tas (got:mu %head))
=/ id (slav %da (vol:mu "id"))
=/ text (vol:mu "text")
[%put-entry id text]

View File

@ -0,0 +1,7 @@
/@ hoon
/@ node
/- _/manx-utils
:- [%node %hoon]
|= nod=node
^- hoon
(~(vol manx-utils nod) "text")

View File

@ -0,0 +1,7 @@
/@ node
/@ iframe
/- _/manx-utils
:- [%node %iframe]
|= nod=node
^- iframe
(~(vol manx-utils nod) "text")

View File

@ -0,0 +1,40 @@
/@ node
/@ sail
/- _/manx-utils
:- [%node %sail]
|= nod=node
|^
^- sail
=/ mu ~(. manx-utils nod)
=/ code
=/ raw=tape (need (val:mu "code"))
?: =((rear raw) '\0a') (crip (snip raw))
(crip raw)
=/ class (vol:mu "classes")
[code class `(render-udon code)]
++ render-udon
|= code=@t
^- (each manx tang)
=/ newline (trip 10)
=/ udon
:: format as udon document
%- crip
;: welp
";>" newline newline
(trip code) newline
==
=/ mul
%- mule
|.
!< manx
%+ slap
;: slop
!>(..zuse)
!>(manx-utils=manx-utils)
==
(ream udon)
?- -.mul
%.y [%.y (manx p.mul)]
%.n [%.n (tang p.mul)]
==
--

View File

@ -0,0 +1,23 @@
/@ sky-diff
/@ node
/- _/manx-utils
:- [%node %sky-diff]
|= nod=node
^- sky-diff
=* mu ~(. manx-utils nod)
=/ head (@tas (got:mu %head))
?+ head !!
%new-tab
[%new-tab ~]
%minimize
[%minimize (slav %ud (got:mu %hawk-slot))]
%slide-up
[%slide-up (slav %ud (got:mu %hawk-slot))]
%slide-down
[%slide-down (slav %ud (got:mu %hawk-slot))]
%maximize
[%maximize (slav %ud (got:mu %hawk-slot))]
%close
[%close (slav %ud (got:mu %hawk-slot))]
::
==

View File

@ -0,0 +1,12 @@
/@ sky-settings
/@ node
/- _/manx-utils
:- [%node %sky-settings]
|= nod=node
^- sky-settings
%- ~(pre-fold manx-utils nod)
|= [=marx x=(map @t @t)]
=/ var (~(get by (malt a.marx)) %var)
?~ var x
%+ ~(put by x) (crip u.var)
(crip (~(got by (malt a.marx)) %value))

View File

@ -0,0 +1,12 @@
/@ sky
/@ node
/- _/manx-utils
:- [%node %sky]
|= nod=node
^- sky
:_ (slav %ud (~(got manx-utils nod) %slots))
%+ murn c.nod
|= =manx
=/ here (rush (~(got manx-utils manx) %here) stap)
?~ here ~
`[*@da (pave:neo u.here)]

View File

@ -0,0 +1,49 @@
/@ node
/@ task-diff
/- _/manx-utils
:- [%node %task-diff]
|= nod=node
^- task-diff
=/ mu ~(. manx-utils nod)
=/ head (@tas (got:mu %head))
%- task-diff
?+ head
~| [%unknown-head head]
!!
%become
=/ path (stab (vol:mu "path"))
[head (pave:neo path)]
::
%nest
=/ name (vol:mu "name")
[head name '' | ~]
::
%prep
=/ name (vol:mu "name")
[head name '' | ~]
::
%oust
=/ path (stab (got:mu %pith))
[head (pave:neo path)]
::
%edit
=/ text (vol:mu "text")
=/ done-el (need (named:mu "done"))
=/ done (~(has by (malt a.g.done-el)) %checked)
[head text done]
::
%kid-done
=/ path (stab (got:mu %pith))
[head (pave:neo path)]
::
%reorder
=/ piths
%+ turn c.nod
|= =manx
=/ here (get:mu %here)
?~ here
~& >>> [%bad-here manx]
!!
(pave:neo /[(rear (stab (crip (need here))))])
[head piths]
==

View File

@ -0,0 +1,8 @@
/@ node
/@ txt
/- _/manx-utils
:- [%node %txt]
|= nod=node
^- txt
(~(vol manx-utils nod) "text")

View File

@ -0,0 +1,856 @@
/@ sail
/- _/feather-icons
:- [%sail %htmx]
|= =sail
|= =bowl:neo
|^
;div.fc.relative.hf.scroll-hidden
;+ controls
;div.frw.js.as.scroll-y.hf
=id "tabs-{id}"
;+ editor
;+ viewer
;+ docs
==
==
++ id
^- tape
%- zing
%+ turn (pout here.bowl)
|= smeg=@ta
%+ weld "--"
(trip smeg)
++ controls
;div.p2.frw.jc.ac.g3.sticky.wf
=style "top:0; left: 0;"
;button.p-1.br1.b1.hover
=type "button"
=onclick
"""
$('#tabs-{id}').children().addClass('hidden');
$('#editor-{id}').removeClass('hidden');
$(this).siblings().removeClass('toggled');
$(this).addClass('toggled');
"""
; edit
==
;button.p-1.br1.b1.hover
=type "button"
=onclick
"""
$('#tabs-{id}').children().addClass('hidden');
$('#viewer-{id}').removeClass('hidden');
$('#editor-{id}').removeClass('hidden');
$(this).siblings().removeClass('toggled');
$(this).addClass('toggled');
"""
; both
==
;button.p-1.br1.b1.hover.toggled
=type "button"
=onclick
"""
$('#tabs-{id}').children().addClass('hidden');
$('#viewer-{id}').removeClass('hidden');
$(this).siblings().removeClass('toggled');
$(this).addClass('toggled');
"""
;
; view
==
;label.fr.je.g1.grow.hidden
;input
=name "view"
=type "radio"
=oninput "$('#tabs-{id}').children().addClass('hidden');$('#docs-{id}').removeClass('hidden');"
;
==
;span: docs
==
==
++ editor
;form.fc.p1.g1.hidden.grow.basis-half.scroll-y.relative
=id "editor-{id}"
=style "min-width: 300px; height: 100%;"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=sail"
=hx-swap "innerHTML"
=hx-select "main > div"
=hx-target "#viewer-{id}"
=hx-trigger "input changed delay:0.4s from:find textarea, input changed delay:0.4s from:find input"
;input.p2.mono.bd1.br1
=name "classes"
=placeholder "prose p3"
=type "text"
=autocomplete "off"
=value (trip class.sail)
=oninput "$(this).attr('value', this.value);"
;
==
;textarea.p2.pre.mono.scroll-x.grow.bd1.m0.br1
=name "code"
=oninput "this.setAttribute('value', this.value);"
=spellcheck "false"
=value ""
=placeholder "# new document"
; {(trip code.sail)}
==
;div.absolute
=style "top: 14px; right: 14px;"
;div.loader
;span.loaded(style "opacity: 0;"): ---
;span.loading
;+ loading.feather-icons
==
==
==
==
++ error
|= =tang
;div.fc.g3.p3.s0
;div.pre.mono
;*
%+ turn (scag 25 tang)
|= =tank
;span: {(of-wall:format (~(win re tank) 0 80))}
==
;div.pre.numbered.mono
;span: ;>
;span;
;*
%+ turn (to-wain:format code.sail)
|= t=@t
;span: {(trip t)}
==
==
++ viewer
;main.grow.basis-half.scroll-x.scroll-y.br1
=id "viewer-{id}"
=style "min-width: 300px; height: 100%;"
;+
?~ result.sail
;div.prose.p3
;h1: nothing rendered
;p: edit the sail to begin rendering
==
=/ res (need result.sail)
?- -.res
%.n (error +.res)
%.y
=- -(a.g [[%class (trip class.sail)] a.g.-])
^- manx
+.res
==
==
:: XX import from source file instead of copying
++ docs
;div.grow.border.basis-half.scroll-x.scroll-y.hidden
=id "docs-{id}"
=style "min-width: 300px; height: 100%;"
;div.prose.p3
# Intro to Feather
Feather is a _Design System_ which gives
Sail developers easy access to a small set of
predefined styles.
Feather is implemented as a library of CSS classes,
and is bundled with Sky and Hawk.
Benefits of opting into
Feather's constraints:
- Feather uses CSS variables that...
- the user can override
- respect OS light/dark theme
- UIs styled with Feather fit in
with the style of Sky and Hawk
- "birds of a feather flock together"
-----------------------------------------------
## The `prose` Class
the `.prose` class adds blog-like spacing,
sizing, and readability styling to semantic
children such as `p`
`li` `h1` `h2` `a` etc.
This document uses it.
```
;article.prose
# cool
- neat
- fine
==
```
-----------------------------------------------
## Flexbox
;*
%+ turn
:~
"fr jb"
"fr ja"
"fr jc"
"fr js"
"fr je"
"fc ac"
"fc as"
"fc ae"
"fc af"
==
|= =tape
;div.fc.g1.br1(style "margin-top: 20px;")
;code: {tape}
;div
=class "bd1 br1 p3 g1 {tape}"
;* %+ turn (gulf 1 3)
|= n=@
;b.b1.f3.p1.br1: X
==
==
;div.fc.g3(style "margin-top: 50px;")
;*
%+ turn
:~
"fr g0"
"fr g1"
"fr g2"
"fr g3"
"fr g4"
"fr g5"
"fr g6"
"fr g7"
"fr g8"
==
|= =tape
;div
=class "s-2 mono {tape}"
;div.bd1.p2: {tape}
;* %+ turn (gulf 1 3)
|= n=@
;div.bd1.p2;
==
==
;div.fr.g2(style "margin-top: 50px;")
;*
%+ turn
:~
"fc g0"
"fc g1"
"fc g2"
"fc g3"
"fc g4"
"fc g5"
"fc g6"
"fc g7"
"fc g8"
==
|= =tape
;div
=class "s-2 mono {tape}"
;div.bd1.p1(style "width: min-content;"): {tape}
;* %+ turn (gulf 1 3)
|= n=@
;div.bd1.p2;
==
==
;div.frw.g2(style "margin-top: 50px;")
;*
%+ turn (gulf 1 10)
|= n=@
;div.p2.bd1.mono: frw g2
==
;div.f2.mono
;div.fr.g4.p2.bd1.br1(style "margin-top: 50px;")
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
;div.p2.br1.b1;
==
;div.fr.g4.p2.bd1.br1(style "margin-top: 20px;")
;div.p2.br1.b1;
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
==
;div.fr.g4.p2.bd1.br1(style "margin-top: 20px;")
;div.p2.br1.b1.tc.grow: grow
;div.p2.br1.b1;
;div.p2.br1.b1.tc.grow: grow
==
==
-----------------------------------------------
## Typography
;div.frw.g1.br1.ac.jc
;*
%+ turn
:~
"s-2"
"s-1"
"s0"
"s2"
"s3"
"s4"
"s5"
"s6"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
;div.frw.g1.br1.ac.jc
;*
%+ turn
:~
"mono"
"bold"
"italic"
"underline"
"strike"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Text Alignment
;*
%+ turn
:~
"tl"
"tc"
"tr"
==
|= =tape
;div
=class "mono {tape}"
; {tape}
==
-----------------------------------------------
## Foreground & Background Colors
;div.frw.g1.br1.ac.jc.mono
;*
%+ turn
:~
"f-3"
"f-2"
"f-1"
"f0"
"f1"
"f2"
"f3"
"f4"
==
|= =tape
;span
=class "p2 bold {tape}"
; {tape}
==
==
;div.frw.g1.br1.ac.jc.mono
;*
%+ turn
:~
"b-3"
"b-2"
"b-1"
"b0"
"b1"
"b2"
"b3"
"b4"
==
|= =tape
;span
=class "p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Padding
;div.fc.ac.g2
;*
%+ turn
:~
"p-8"
"p-7"
"p-6"
"p-5"
"p-4"
"p-3"
"p-2"
"p-1"
"p0"
"p1"
"p2"
"p3"
"p4"
"p5"
"p6"
"p7"
"p8"
"p-page"
==
|= =tape
;div
=class "wfc mono f2 b1 {tape}"
; {tape}
==
==
-----------------------------------------------
## Margin
;div
;*
%+ turn
:~
"m0"
"ma"
"mt1"
"mt2"
"mt3"
==
|= =tape
;div
=class "mono f2 b2 br1 wfc p2 {tape}"
; {tape}
==
==
-----------------------------------------------
## Opacity
;div.frw.g2.ac.jc
;*
%+ turn
:~
"o0"
"o1"
"o2"
"o3"
"o4"
"o5"
"o6"
"o7"
"o8"
"o9"
"o10"
==
|= =tape
;div.fc.g1.ac.jc
;span.mono.s-1.f2: {tape}
;div
=class "wfc mono f0 b1 p4 bd1 {tape}"
;
==
==
==
-----------------------------------------------
## Borders
;div.frw.ac.g2(style "margin-top: 20px;")
;*
%+ turn
:~
"bd0"
"bd1"
"bd2"
"bd3"
==
|= =tape
;div
=class "wfc mono f2 p2 {tape}"
; {tape}
==
==
;div.frw.ac.g2(style "margin-top: 20px;")
;*
%+ turn
:~
"br0"
"br1"
"br2"
"br3"
==
|= =tape
;div
=class "wfc mono f2 p2 bd1 {tape}"
; {tape}
==
==
-----------------------------------------------
## Dimensions
- `wf` width: full
- `wfc` width: fit-content
- `mw-page` max-width: page (650px)
- `hf` height: full
- `hfc` height: fit-content
-----------------------------------------------
## Special
;*
%+ turn
:~
"toggled"
"hover"
==
|= =tape
;button(style "margin: 5px;")
=class "wfc mono f0 b0 p2 bd1 {tape}"
; {tape}
==
the `hidden` class hides the element.
-----------------------------------------------
## Request indicators
`loader` indicator parent
`loading` loading state
`loaded` loaded state
;details.mt1
;summary: Example
;button.mt1.b1.p1.hover.br1.bd1.f1.loader
=onclick "$(this).toggleClass('htmx-request')"
;span.loaded: toggle load state
;span.loading.f1: ...loading
==
```
;button.loader
=onclick "$(this).toggleClass('htmx-request')"
;span.loaded: toggle load state
;span.loading: ...loading
==
```
==
-----------------------------------------------
## Misc
`scroll-y`\
scroll-y: auto
`scroll-x`\
scroll-x: auto
`relative`\
position: relative
`sticky`\
position: sticky
`absolute`\
position: absolute
`fixed`\
postion: fixed
`block`\
display: block
`inline`\
display: inline-block
`pre`\
white-space: pre
`pre-line`\
white-space: pre-line
`break`\
word-break: break-word
`action`\
touch-action: manipulation
-----------------------------------------------
## Feather Sutra
> Order requires constraints.
### Primary Constraint
Interfaces must work on a mobile web browser.
### Consequent Constraints
- no element should need to be wider than 350px
- avoid horizontal scrolling
- left-click is the only mouse event
### Locality of Behavior
- co-locate actionable elements with the elements on which they act
- put styling inline
- put javascript inline
### Mechanical Simplicity
- don't fight the browser
- avoid animations
- prefer [bubbling-event](https://htmx.org/attributes/hx-on/)
architectures
- store state as text attributes in the DOM, not javascript state
### UX low-hanging fruit
- network requests should always have indicators
- prefer autosave to manually saving
- be semantic with your tags
-----------------------------------------------
## Feather Tantra
> Life evolves through a vital chaos.
```
;div.any.class(style "any: css;");
;div
=class "any class"
=style
"""
any: "css";
that-you: "want;
"""
;
==
;style
;+ ;/ %- trip
'''
.any-css {
that-you: "want";
}
'''
==
;script
;+ ;/ %- trip
'''
// any javascript you want
'''
==
```
;div.end;
;style
;+ ;/ %- trip
'''
details {
display: flex !important;
flex-direction: column;
padding: 12px;
background: var(--b1);
box-sizing: border-box;
}
.end {
margin-bottom: 450px;
}
hr {
margin: 100px 0;
}
'''
==
==
==
--

View File

@ -0,0 +1,16 @@
/@ sky-diff
/- _/feather-icons
:- [%sky-diff %htmx]
|= diff=sky-diff
|= =bowl:neo
^- manx
;div.loading
=hx-get "/neo/sky"
=hx-params "none"
=hx-indicator "closest .loader"
=hx-target "#air"
=hx-select "#air"
=hx-swap "outerHTML"
=hx-trigger "load once"
;+ loading.feather-icons
==

View File

@ -0,0 +1,259 @@
/@ sky
/@ sky-settings
/- _/feather-icons
:- [%sky %htmx]
|= =sky
|= =bowl:neo
^- manx
|^
;div.wf.hf.relative
;a-i-r.wf.hf.relative
=style "opacity: var(--sky-opacity); padding: var(--sky-outer-gap);"
=id "air"
=hawks "{<open.sky>}"
=morph-retain "closed"
;+ menu-btn
;+ menu-btn-style
;+ theme-style
;+ nav
;* p:(spin (scag open.sky hawks.sky) 0 ha-wk)
==
;+ eye
==
::
++ map-to-css-tape
|= m=(map @t @t)
^- tape
%- zing
%+ turn ~(tap by m)
|= [key=@t val=@t]
"""
--{(trip key)}: {(trip val)};
"""
++ theme-style
=/ settings
^- (unit sky-settings)
=/ s (~(get by kids.bowl) /settings)
?~ s ~
:- ~
!< sky-settings
q.u.s
;style
;+ ;/
?~ settings
""
"""
html \{
{(map-to-css-tape u.settings)}
}
"""
==
++ menu-btn
;button.hover.f2.b2.fc.ac.jc.air-btn.wf
=slot "button"
=onclick "$(this).closest('a-i-r').attr('closed', !$(this).parent().attr('closed'))"
;div.fc.ac.jc.bold.s3.f3(style "height: 2rem;"): ~
==
++ menu-btn-style
;style
;+ ;/ %- trip
'''
.air-btn {
position: relative;
padding: 4px;
border-radius: 3px;
border: 2px solid var(--b2);
}
@media(max-width: 900px) {
.air-btn {
position: absolute;
bottom: 25px;
right: 25px;
padding: 30px;
width: 70px;
height: 70px;
z-index: 10;
border-radius: 50px;
border: 1px solid var(--b3);
}
a-i-r {
padding: 0 !important;
}
}
'''
==
++ ha-wk
|= [[id=@da =pith] a=@]
:_ +(a)
=/ ext
?: =(pith /) ""
(en-tape:pith:neo pith)
=/ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn)))))
;div.wf.hf.br1
=slot "s{<a>}"
=id "hawk-windshield-{idt}"
;div.wf.hf.fc.jc.ac.f2.s3.spinner
=id "hawk-{idt}"
=morph-if-class "spinner"
;+ loading.feather-icons
==
;div.hidden
=hx-get "/neo/hawk{ext}?slot={<a>}&id={<id>}&no-save"
=hx-trigger "load"
=hx-target "#hawk-{idt}"
=hx-swap "morph"
;
==
==
++ nav
;nav.wf.hf.p2.fc.g2
=slot "nav"
;div.mt2.o0;
;+ new-tab
;*
=< p
%^ spin
hawks.sky
0
|= [[id=@da =pith] a=@]
:_ +(a)
=/ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn)))))
=/ color (trip ?:((lth a open.sky) 'b2' 'b1'))
;div
=id "hawk-tab-{idt}"
=class "fr ac br1 {color}"
;button
=class "loader p2 tl br1 hover grow {color}"
=hx-post "/neo/hawk/sky?stud=sky-diff"
=hx-target "find .loading"
=hx-swap "outerHTML"
=head "maximize"
=hawk-slot "{<a>}"
;span.loaded: {(en-tape:pith:neo pith)}
;span.loading
;+ loading.feather-icons
==
==
;button
=class "loader p2 tl br1 hover {color}"
=hx-post "/neo/hawk/sky?stud=sky-diff"
=hx-target "find .loading"
=hx-swap "outerHTML"
=head "close"
=hawk-slot "{<a>}"
;span.loaded.f3
;+ close.feather-icons
==
;span.loading
;+ loading.feather-icons
==
==
==
==
++ new-tab
;button.loader.b2.p2.tc.br1.hover.wfc.s-1
=hx-post "/neo/hawk/sky?stud=sky-diff"
=hx-target "find .loading"
=hx-swap "outerHTML"
=type "button"
=head "new-tab"
;span.loaded.fr.ac.js.g2
;+ add.feather-icons
;span.f3: new tab
==
;span.loading
;+ loading:feather-icons
==
==
++ eye
;div#eye.fixed.hidden
=style "bottom: 30px; left: 30px;"
=morph-no-swap ""
;script
;+ ;/ %- trip
'''
function handleKey(e) {
let focused = document.activeElement;
let textarea = ['TEXTAREA'].includes(focused.nodeName)
let textinput = ['text', 'number', 'email', 'password'].includes(focused.getAttribute('type'));
if (textarea || textinput) {
if (e.key === 'Escape') {
closeEye();
document.activeElement.blur();
}
return;
}
if (e.key === ' ') {
e.preventDefault();
if (window.eye.open) {
closeEye();
} else {
openEye();
}
} else if (e.key === 'Escape') {
e.preventDefault();
document.activeElement.blur();
} else if (!e.ctrlKey && !e.metaKey && !e.altKey) {
if (window.eye?.open) {
e.preventDefault();
let area = window.eye?.spots?.filter(s => s[0][0] === e.key);
if (area.length === 1) {
let btn = area[0][1];
btn.click();
btn.focus();
closeEye();
}
else if (!!area.length) {
let news = area.map(c => (c[0].length < 2) ? c : [c[0].slice(1), c[1]]);
window.eye.spots = news;
closeEye(true);
openEye();
} else {
closeEye();
}
}
}
}
function openEye() {
window.eye.open = true;
document.getElementById('eye').classList.remove('hidden');
buildGazeSpots();
}
function closeEye(keep) {
window.eye.open = false;
if (!keep) {
window.eye.spots = null;
}
document.getElementById('eye').classList.add('hidden');
document.querySelectorAll('.gaze').forEach(g => g.remove());
}
function buildGazeSpots() {
let buttons = window.eye?.spots?.map(s => s[1]) ||
document.querySelectorAll(
'a, button, summary, [role="button"], input, textarea, .clickable'
);
let chars = ['a', 's', 'd', 'f', 'k', 'm', 'n', 'r', 't', 'y', 'u', 'i', 'c', 'v', 'b'];
buttons.forEach((b, i) => {
let d = b.getBoundingClientRect();
if (d.right > 0 && d.right > 0) {
let t = document.createElement('div');
var lent = Math.floor((i / chars.length) + 1);
var word = ''
while (lent > 0) {
let ch = chars[i % chars.length];
word = `${word}${ch}`;
lent = lent - 1;
}
t.textContent = word.slice(-1);
t.className = 'b-1 br2 p1 s0 bold fixed gaze z2'
t.style = `top: ${Math.max(0, d.top - 10)}px; left: ${Math.max(0, d.left - 10)}px;`
document.getElementById('eye')?.parentNode.appendChild(t);
window.eye.spots = [[word, b], ...(window.eye?.spots || [])]
}
})
}
window.addEventListener('keydown', handleKey);
'''
==
==
--

View File

@ -0,0 +1,297 @@
/@ sky-settings
:- [%sky-settings %htmx]
|= settings=sky-settings
|= =bowl:neo
^- manx
|^
;div.wf.p-page
=label "Settings"
;form.fc.g5.mw-page.ma
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=sky-settings"
=hx-swap "none"
;+ script
;+ background-image
;+ spacing
;+ typography
;+ (colors "light")
;+ (colors "dark")
;+ style
;div.frw.g2
;button.p3.br1.b1.hover
=onclick "document.body.removeAttribute('style')"
=hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}"
=hx-target "closest .hawk"
=hx-select ".hawk"
;span: Reset
==
;button.p3.br1.b1.hover.loader
;span.loaded: Save
;span.loading: ---
==
==
==
==
++ curr
|= var=cord
(trip (~(gut by settings) var ''))
++ selected
|= [f=? =manx]
%= manx
a.g
?. f a.g.manx
[[%selected ""] a.g.manx]
==
++ background-image
;div.fc.js.g2.ja.p2
;label.fc.g1
;span.s-1: Background Image
;input.bd1.border.p2.br1
=oninput "setCss('sky-bg-url', `url('$\{this.value}')`); $(this).attr('value', `url('$\{this.value}')`);"
=value (curr 'sky-bg-url')
=var "sky-bg-url"
=type "text"
;
==
==
;label
;span.s-1: Position
;select.br1.bd1.p2
=oninput "setCss('sky-bg-size', this.value); $(this).attr('value', this.value);"
=value (curr 'sky-bg-size')
=var "sky-bg-size"
;*
%+ turn
:~
"initial"
"contain"
"cover"
==
|= =tape
%+ selected =(tape (curr 'sky-bg-size'))
;option(value tape): {tape}
==
==
;label.fc.g1
;span.s-1: Opacity
;input.bd1.border.p2.br1
=oninput "setCss('sky-opacity', this.value); $(this).attr('value', this.value);"
=value (trip (~(gut by settings) 'sky-opacity' '1'))
=var "sky-opacity"
=type "range"
=min "0.6"
=max "1.0"
=step "0.01"
;
==
==
==
++ spacing
;div.fc.g2
;label.fc.g1
;span.s-1: Outer Gap
;input.bd1.border.p2.br1
=oninput "setCss('sky-outer-gap', `$\{this.value}px`); $(this).attr('value', this.value);"
=value (curr 'sky-outer-gap')
=var "sky-outer-gap"
=type "range"
=min "0"
=max "30"
=step "1"
;
==
==
;label.fc.g1
;span.s-1: Inner Gap
;input.bd1.border.p2.br1
=oninput "setCss('sky-inner-gap', `$\{this.value}px`); $(this).attr('value', this.value);"
=value (curr 'sky-inner-gap')
=var "sky-inner-gap"
=type "range"
=min "0"
=max "30"
=step "1"
;
==
==
==
++ typography
;div.fc.js.g2.ja.p2
;label.fc.g1.mt1
;span.s-1: Main font
;select.br1.bd1.p2
=oninput "setCss('font', this.value); $(this).attr('value', this.value);"
=value (curr 'font')
=var "font"
;*
%+ turn
:~
"Urbit Sans"
"Montserrat"
"Verdana"
"Gill Sans"
"Helvetica Neue"
"Open Sans"
"Roboto"
"Arial"
"Futura"
"PT Sans"
==
|= =tape
%+ selected =(tape (curr 'font'))
;option(value tape): {tape}
==
==
;label.fc.g1
;span.s-1: Base size
;input.br1.border
=oninput "setCss('1in', this.value+'px'); $(this).attr('value', this.value);"
=value (snip (snip (trip (~(gut by settings) '1in' ''))))
=var "1in"
=type "range"
=min "2"
=max "10"
=step "0.1"
;
==
==
;label.fc.g1
;span.s-1: Monospace font
;select.br1.bd1.p2
=oninput "setCss('font-mono', `'$\{this.value}'`); $(this).attr('value', this.value);"
=value (curr 'font-mono')
=var "font-mono"
;*
%+ turn
:~
"Andale Mono"
"Urbit Mono"
"Courier New"
"Monaco"
"Spot Mono"
==
|= =tape
%+ selected =(tape (curr 'font-mono'))
;option(value tape): {tape}
==
==
;label.fc.g1
;span.s-1: Mono scale
;input.br1.border
=oninput "setCss('mono-scale', this.value); $(this).attr('value', this.value);"
=value (trip (~(gut by settings) 'mono-scale' ''))
=var "mono-scale"
=type "range"
=min "0.5"
=max "1.2"
=step "0.05"
;
==
==
;label.fc.g1
;span.s-1: Letter spacing
;input.br1.border
=oninput "setCss('letter-spacing', this.value+'px'); $(this).attr('value', this.value);"
=value (snip (snip (trip (~(gut by settings) 'letter-spacing' ''))))
=var "letter-spacing"
=type "range"
=min "-1"
=max "3"
=step "0.001"
;
==
==
;label.fc.g1
;span.s-1: Line Height
;input.br1.border
=oninput "setCss('line-height', this.value); $(this).attr('value', this.value);"
=value (trip (~(gut by settings) 'line-height' ''))
=var "line-height"
=type "range"
=min "1"
=max "2"
=step "0.1"
;
==
==
==
++ color
|= [mode=tape var=tape]
=/ val (~(gut by settings) (crip "{mode}-{var}") '')
;label.fr.af.js.g1.mono
;span.fr.ac.je(style "width:5ch;"): {var}
;input.grow.fc.ac.jc
=oninput "setCss('{mode}-{var}', this.value); $(this).attr('value', this.value);"
=var "{mode}-{var}"
=type "color"
=value (trip val)
;
==
==
++ colors
|= [mode=tape]
;div
=class "sky-settings-{mode} frw g2 js p2"
;div.fc.g1.ac.jc
;*
%+ turn
:~
"f-3"
"f-2"
"f-1"
"f0"
"f1"
"f2"
"f3"
"f4"
==
|= =tape
(color mode tape)
==
;div.fc.g1.ac.jc
;*
%+ turn
:~
"b-3"
"b-2"
"b-1"
"b0"
"b1"
"b2"
"b3"
"b4"
==
|= =tape
(color mode tape)
==
==
++ script
;script
;+ ;/ %- trip
'''
function setCss(name, val) {
document.documentElement.style
.setProperty('--'+name, val, 'important');
}
'''
==
++ style
;style
;+ ;/ %- trip
'''
.sky-settings-dark {
display: none !important;
}
.sky-settings-light {
display: flex !important;
}
@media (prefers-color-scheme: dark) {
.sky-settings-dark {
display: flex !important;
}
.sky-settings-light {
display: none !important;
}
}
'''
==
--

View File

@ -0,0 +1,275 @@
/@ task
:- [%task %htmx]
|= t=task
|= =bowl:neo
|^
shell
++ kids ~(tap by kids.bowl)
++ id
^- tape
%- zing
%+ turn (pout here.bowl)
|= smeg=@ta
%+ weld "--"
(trip smeg)
++ form-edit
^- manx
;form.fc.g2.br1
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=hx-trigger "input changed delay:0.4s from:find textarea, input from:find input"
=hx-swap "none"
=head "edit"
;label.fr.g2.ac.js
;+ =- ?. done.t:+ -
-(a.g [[%checked ""] a.g.-])
^- manx
;input
=type "checkbox"
=name "done"
=onclick (trip 'if (this.checked) { this.setAttribute("checked", "")} else {this.removeAttribute("checked")}')
;
==
;span.grow: Done
;div.htmx-indicator
; ---
==
==
;textarea.wf.p2.border.br1.ma.mono
=name "text"
=autocomplete "off"
=spellcheck "false"
=rows "{<(add 2 (lent (fand ~[10] (trip text.t))))>}"
=oninput "this.setAttribute('value', this.value); this.rows = this.value.split('\\n').length"
=value (trip (@t text.t))
; {(trip (@t text.t))}
==
==
++ form-create
|= [head=@tas label=tape]
^- manx
;div.fc.g1
;button.b0.br1.hover.p2.wfc.mono.f3
=onclick
"""
this.classList.toggle('toggled');
this.nextElementSibling.classList.toggle('hidden');
this.nextElementSibling.firstChild.focus();
"""
; {label}
==
;form.fr.g1.hidden
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=head (trip head)
=hx-swap "outerHTML"
=hx-target "find button .loading"
;input.wf.p1.border.br1.grow
=name "name"
=autocomplete "off"
=type "text"
=pattern (trip '[a-z]{1}[a-z0-9\\-]+')
=title "lowercase and heps"
=required ""
=placeholder "name"
=oninput "this.setAttribute('value', this.value);"
;
==
;button.b1.br1.hover.p1.wfc.loader
;span.loaded: create
;span.loading: ---
==
==
==
++ part-kid
|= [=pith =pail:neo]
=/ t=task !<(task q.pail)
=- ?. done.t -
-(a.g [[%done ""] a.g.-])
^- manx
;div.fc.g1
=here (en-tape:pith:neo (welp here.bowl pith))
;div.fr.g1
;button
=class "b0 br1 hover p1 tl action mono fr g3 f2"
=style "padding: 4px 9px;"
=type "button"
=onclick
"""
this.textContent = this.textContent === "=" ? "|" : "="; toggleChildren(this);
"""
;span.bold: =
==
;+ =-
=/ that -
=/ classes
%+ weld
"b0 br1 hover p1 grow tl action mono fr g3"
?:(done.t " strike f3" "")
that(a.g [[%class classes] a.g.that])
^- manx
;button
=type "button"
=onclick
"""
this.classList.toggle('toggled'); this.parentNode.nextElementSibling.classList.toggle('hidden');
"""
;span.bold: {(trip -:(pout pith))}
;span.break.f2: {(scag (fall (find [10 ~] (trip text.t)) 30) (trip text.t))}
==
;a
=class "b0 br1 hover p1 loader f3"
=hx-indicator "this"
=href "/neo/hawk{(en-tape:pith:neo here.bowl)}{(en-tape:pith:neo pith)}"
=hx-swap "innerHTML"
;span.loaded: →
;span.loading: .
==
==
;div.border.p2.br1.frw.g2.hidden
=hx-disinherit "hx-indicator"
=style "margin-left: 20px;"
;button.b1.br1.p2.hover
=onclick "this.parentNode.parentNode.parentNode?.insertAdjacentElement('beforeend', this.parentNode.parentNode); center(this);"
; ↧
==
;button.b1.br1.p2.hover
=onclick "this.parentNode.parentNode.nextElementSibling?.insertAdjacentElement('afterend', this.parentNode.parentNode); center(this);"
; ↓
==
;button.b1.br1.p2.hover
=onclick "this.parentNode.parentNode.previousElementSibling?.insertAdjacentElement('beforebegin', this.parentNode.parentNode); center(this);"
; ↑
==
;button.b1.br1.p2.hover
=onclick "this.parentNode.parentNode.parentNode?.insertAdjacentElement('afterbegin', this.parentNode.parentNode); center(this);"
; ↥
==
;div.htmx-indicator.reorder-indicator.p2.f2
; ---
==
;div.basis-full;
;button.b1.br1.p2.hover.loader
=type "button"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=hx-swap "outerHTML"
=hx-target "find .loading"
=head "kid-done"
=pith (en-tape:pith:neo pith)
;span.loaded: toggle
;span.loading: ---
==
;button.b1.br1.p2.hover.loader
=type "button"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=hx-swap "none"
=hx-on--after-request "this.parentNode.parentNode.remove();"
=head "oust"
=pith (en-tape:pith:neo pith)
;span.loaded: delete
;span.loading: ---
==
;button.b1.br1.p2.hover
=type "button"
=onclick "this.nextElementSibling.classList.toggle('hidden'); this.classList.toggle('toggled');"
; become
==
;div.basis-full.hidden.fr.g1
=hx-post "/neo/hawk{(en-tape:pith:neo (welp here.bowl pith))}?stud=task-diff"
=hx-trigger "become"
=hx-target "find .loading"
=hx-swap "outerHTML"
=head "become"
;input.grow.p2.br1.border
=type "text"
=name "path"
=value (en-tape:pith:neo (welp here.bowl pith))
=oninput "this.setAttribute('value', this.value);"
;
==
;button.p2.b1.hover.br1.loader
=type "button"
=onclick "this.dispatchEvent(new CustomEvent('become', \{composed:true, bubbles: true}))"
;span.loaded: become
;span.loading: ---
==
==
;div.basis-full.p2.pre.mono.scroll-x
; {(trip text.t)}
==
==
;div.fc.g2.hidden
=hx-disinherit "hx-indicator"
=style "margin-left: 20px;"
;
==
==
::
++ script
;script
;+ ;/ %- trip
'''
function center(el) {
el.scrollIntoView({
block: "center",
inline: "start",
behavior: "instant"
})
}
function toggleChildren(el) {
let kidsDiv = el.parentNode.nextElementSibling.nextElementSibling;
if (!kidsDiv.children.length) {
let here = el.parentNode.parentNode.getAttribute('here');
let stub = document.createElement("div");
stub.setAttribute("hx-get", `/neo/hawk${here}`);
stub.setAttribute("hx-trigger", 'load');
stub.setAttribute("hx-target", 'this');
stub.setAttribute("hx-select", '.kids');
stub.textContent = "+ + +"
stub.className = "fc as jc"
stub.style = "padding:10px; padding-left: 20px;"
stub.setAttribute("hx-swap", "outerHTML");
kidsDiv.appendChild(stub);
htmx.process(kidsDiv);
}
kidsDiv.classList.toggle('hidden');
}
'''
==
++ form-ordered-kids
;form.fc.g1
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=task-diff"
=head "reorder"
=hx-indicator ".reorder-indicator"
=hx-swap "none"
;*
%+ turn order.t
|= =pith
=/ kid (~(get by kids.bowl) pith)
?~ kid
;div: does not exist {(en-tape:pith:neo pith)}
(part-kid [pith (need kid)])
::;*
::=/ orphans
:: %+ skim kids
:: |= [=pith *]
:: =(~ (find [pith ~] order.t))
::%+ turn
:: %+ sort orphans
:: |= [a=[=pith *] b=[=pith *]]
:: (lth ->.pith.a ->.pith.b)
::part-kid
==
++ shell
;div.fc.js.af.p2.wf.p1.g5.ma
=here (en-tape:pith:neo here.bowl)
=style "max-width: 650px; padding-bottom: 50vh; padding-top: 30px;"
;+ script
;+ form-edit
;div.fc.g1.kids
::;+ ?~ (lent order.t) ;/("") (form-create %prep "+")
::;+ ?~ (lent order.t) (form-create %nest "+") ;/("")
;+ form-ordered-kids
::;+ ?~ (lent order.t) ;/("") (form-create %nest "+")
;+ (form-create %nest "+")
==
==
--

View File

@ -0,0 +1,101 @@
/@ sky
/@ sky-diff
|%
++ state %sky
++ poke (sy %sky %sky-diff ~)
++ kids
%- ~(gas by *kids:neo)
:~
:- [&/%settings |]
[%sky-settings %sky-settings]
==
++ deps *deps:neo
++ form
^- form:neo
|_ [=bowl:neo =ever:neo state-vase=vase *]
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo vase)
?+ stud !!
%sky [~ vax]
%sky-diff
=/ poke !<(sky-diff vax)
=/ this !<(sky state-vase)
?+ -.poke !!
%new-tab
:- ~
=. hawks.this [[now.bowl /home] hawks.this]
=. open.this (min 4 +(open.this))
!>(this)
%move-tab
:- ~
=. hawks.this (snap hawks.this slot.poke [now.bowl pith.poke])
!>(this)
%minimize
:- ~
=. hawks.this
;: welp
(scag slot.poke hawks.this)
(slag +(slot.poke) hawks.this)
[(snag slot.poke hawks.this) ~]
==
=. open.this (dec open.this)
!>(this)
%maximize
:- ~
=. hawks.this
;: welp
[(snag slot.poke hawks.this) ~]
(scag slot.poke hawks.this)
(slag +(slot.poke) hawks.this)
==
=? open.this
(gte slot.poke open.this)
(min 4 +(open.this))
!>(this)
%close
:- ~
=. hawks.this (oust [slot.poke 1] hawks.this)
=? open.this
(lth slot.poke open.this)
(dec open.this)
!>(this)
%slide-up
:- ~
=? hawks.this
(gth slot.poke 0)
;: welp
(scag (dec slot.poke) hawks.this)
[(snag slot.poke hawks.this) ~]
[(snag (dec slot.poke) hawks.this) ~]
(slag +(slot.poke) hawks.this)
==
!>(this)
%slide-down
:- ~
=? hawks.this
(lth slot.poke 3)
;: welp
(scag slot.poke hawks.this)
[(snag +(slot.poke) hawks.this) ~]
[(snag slot.poke hawks.this) ~]
(slag (add 2 slot.poke) hawks.this)
==
!>(this)
::
==
::
==
++ init
|= vas=(unit vase)
^- (quip card:neo vase)
:-
:~ [(welp here.bowl /settings) %make %sky-settings ~ ~]
==
!>
:_ 1
:~
[now.bowl ~[%home]]
==
--
--

View File

@ -16,9 +16,6 @@ class extends HTMLElement {
::slotted(*) {
overflow: auto;
}
button {
border: none;
}
:host {
display: grid;
width: 100%;
@ -27,14 +24,14 @@ class extends HTMLElement {
overflow: hidden;
margin: 0;
grid-template-columns: 230px auto;
grid-template-rows: 50px auto;
grid-template-rows: auto 1fr;
grid-template-areas:
"btn main"
"nav main";
}
:host(.closed) {
grid-template-columns: 50px auto;
grid-template-rows: 50px auto;
grid-template-rows: auto 1fr;
grid-template-areas:
"btn main"
". main";
@ -51,85 +48,26 @@ class extends HTMLElement {
gap: 12px;
overflow: auto;
}
main.s0 {
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-template-areas:
".";
}
main.s0 #s1,
main.s0 #s2,
main.s0 #s3,
main.s0 #s4 {
display: none;
}
main.s1 {
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-template-areas:
"s1";
}
main.s1 #s1 {
display: block;
}
main.s1 #s2,
main.s1 #s3,
main.s1 #s4 {
display: none;
}
main.s2 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr;
grid-template-areas:
"s1 s2";
}
main.s2 #s1,
main.s2 #s2 {
display: block;
}
main.s2 #s3,
main.s2 #s4 {
display: none;
}
main.s3 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-template-areas:
"s1 s2"
"s1 s3";
}
main.s3 #s1,
main.s3 #s2,
main.s3 #s3 {
display: block;
}
main.s3 #s4 {
display: none;
}
main.s4 {
grid-template-columns: 2fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-template-areas:
"s1 s2 s2"
"s1 s3 s4";
}
main.s4 #s1,
main.s4 #s2,
main.s4 #s3,
main.s4 #s4 {
display: block;
}
button {
grid-area: btn;
}
/*
* grid display
*
*/
main {
display: grid;
grid-area: main;
overflow: hidden;
padding-left: var(--sky-inner-gap);
}
#s1, #s2, #s3, #s4 {
#s0, #s1, #s2, #s3 {
overflow: auto;
}
#button {
grid-area: btn;
height: fit-content;
}
#s0 {
grid-area: s0;
}
#s1 {
grid-area: s1;
}
@ -139,31 +77,124 @@ class extends HTMLElement {
#s3 {
grid-area: s3;
}
#s4 {
grid-area: s4;
main.open-0 {
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-template-areas:
".";
}
button {
background-color: var(--b1);
color: var(--f1);
margin: 8px;
border: 1px solid var(--f4);
border-radius: 4px;
main.open-0 #s0,
main.open-0 #s1,
main.open-0 #s2,
main.open-0 #s3 {
display: none;
}
main.open-1 {
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-template-areas:
"s0";
}
main.open-1 #s0 {
display: block;
}
main.open-1 #s1,
main.open-1 #s2,
main.open-1 #s3 {
display: none;
}
main.open-2 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr;
grid-template-areas:
"s0 s1";
}
main.open-2 #s0,
main.open-2 #s1 {
display: block;
}
main.open-2 #s2,
main.open-2 #s3 {
display: none;
}
main.open-3 {
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-template-areas:
"s0 s1"
"s0 s2";
}
main.open-3 #s0,
main.open-3 #s1,
main.open-3 #s2 {
display: block;
}
main.open-3 #s3 {
display: none;
}
main.open-4 {
grid-template-columns: 2fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
grid-template-areas:
"s0 s1 s1"
"s0 s2 s3";
}
main.open-4 #s0,
main.open-4 #s1,
main.open-4 #s2,
main.open-4 #s3 {
display: block;
}
/*
* gaps
*
*/
main.open-1 #s0 {
padding-right: 0;
}
main.open-2 #s0,
main.open-3 #s0,
main.open-4 #s0 {
padding-right: var(--sky-inner-gap);
}
main.open-1 #s1,
main.open-2 #s1 {
padding-bottom: 0;
}
main.open-3 #s1,
main.open-4 #s1 {
padding-bottom: var(--sky-inner-gap);
}
main.open-1 #s2,
main.open-2 #s2,
main.open-3 #s2 {
padding-right: 0;
}
main.open-4 #s2 {
padding-right: var(--sky-inner-gap);
}
/*
* mobile
*
*/
@media (max-width: 900px) {
:host {
grid-template-columns: auto;
grid-template-rows: auto 50px;
grid-template-rows: 1fr auto;
grid-template-areas:
"main"
"btn";
}
:host(.closed) {
grid-template-columns: auto;
grid-template-rows: auto 50px;
grid-template-rows: 1fr auto;
grid-template-areas:
"nav"
"btn";
}
button {
height: min-content;
}
:host(.closed) main {
display: none;
}
@ -172,10 +203,21 @@ class extends HTMLElement {
grid-template-columns: auto;
grid-template-rows: auto;
grid-template-areas:
"s1";
"s0";
}
#s1 {
#nav {
--rem: 24px;
}
main {
padding: 0;
}
main #s0 {
display: block;
padding: 0;
padding-right: 0 !important;
}
main #s1 {
display: none !important;
}
main #s2 {
display: none !important;
@ -183,9 +225,6 @@ class extends HTMLElement {
main #s3 {
display: none !important;
}
main #s4 {
display: none !important;
}
:host(.closed) #nav {
display: flex;
}
@ -194,8 +233,9 @@ class extends HTMLElement {
}
}
</style>
<slot name="button">
<slot name="button" id="button">
<button
style="border: 2px solid var(--b3);"
onclick="this.getRootNode().host.dispatchEvent(new CustomEvent('sky-open', {bubbles:true, composed: true}))"
>
~
@ -203,10 +243,10 @@ class extends HTMLElement {
</slot>
<slot id="nav" name="nav"></slot>
<main>
<slot name="s0" id="s0"></slot>
<slot name="s1" id="s1"></slot>
<slot name="s2" id="s2"></slot>
<slot name="s3" id="s3"></slot>
<slot name="s4" id="s4"></slot>
</main>
<slot id="default" style="display: none;"></slot>
`
@ -230,7 +270,7 @@ class extends HTMLElement {
if (name === "closed") {
this.classList.toggle("closed");
} else if (name === "hawks") {
this.qs("main").className = `s${this.hawks}`;
this.qs("main").className = `open-${this.hawks}`;
}
}
});

View File

@ -1,62 +0,0 @@
customElements.define('error-tray',
class extends HTMLElement {
static get observedAttributes() {
return ["open"];
}
constructor() {
//
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.adoptedStyleSheets = [sharedStyles];
this.shadowRoot.innerHTML = `
<style>
:host {
display: none;
flex-flow: column nowrap;
width: 100%;
height: 100%;
background-color: var(--b1);
align-items: center;
justify-content: center;
top: 0;
left: 0;
opacity: 0.95;
}
</style>
<div
class="p3 wf hf fc g2 scroll-y"
style="max-width: 400px; max-height: 400px;"
>
<slot id="slot"></slot>
<button
class="b2 br1 p2 hover"
onclick="this.getRootNode().host.removeAttribute('open')"
>
close
</button>
</div>
`;
}
connectedCallback() {
this.gid("slot").addEventListener("slotchange", (e) => {
if (this.slotted("slot")) {
this.setAttribute("open", "");
} else {
this.removeAttribute("open");
}
})
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === "open") {
this.style.display = newValue === null ? 'none' : 'flex';
}
}
slotted(id) {
//
return (this.gid(id)?.assignedElements() || [null])[0];
}
gid(id) {
//
return this.shadowRoot.getElementById(id);
}
});

711
pkg/arvo/web/feather.css Normal file
View File

@ -0,0 +1,711 @@
/** feather.css
* ~2024.4.6
*
* styling resets
* and
* utility classes
*
**/
:root {
/* --font: 'Urbit Sans';
--font-mono: 'Monaco';
--mono-scale: 0.8;
--letter-spacing: 0.024em;
--line-height: 1.4;
*/
--0in: calc(0 * var(--1in));
--1in: 4px;
--font-size: calc(4 * var(--1in));
--2in: calc(2 * var(--1in));
--3in: calc(3 * var(--1in));
--4in: calc(4 * var(--1in));
--5in: calc(5 * var(--1in));
--6in: calc(6 * var(--1in));
--7in: calc(7 * var(--1in));
--8in: calc(8 * var(--1in));
--9in: calc(9 * var(--1in));
--10in: calc(10 * var(--1in));
--11in: calc(11 * var(--1in));
--12in: calc(12 * var(--1in));
--13in: calc(13 * var(--1in));
--14in: calc(14 * var(--1in));
--15in: calc(15 * var(--1in));
--16in: calc(16 * var(--1in));
--17in: calc(17 * var(--1in));
--18in: calc(18 * var(--1in));
--19in: calc(19 * var(--1in));
--20in: calc(20 * var(--1in));
--21in: calc(21 * var(--1in));
--22in: calc(22 * var(--1in));
--23in: calc(23 * var(--1in));
--24in: calc(24 * var(--1in));
--25in: calc(25 * var(--1in));
--26in: calc(26 * var(--1in));
--27in: calc(27 * var(--1in));
--28in: calc(28 * var(--1in));
--29in: calc(29 * var(--1in));
--30in: calc(30 * var(--1in));
--31in: calc(31 * var(--1in));
--32in: calc(32 * var(--1in));
--33in: calc(33 * var(--1in));
--34in: calc(34 * var(--1in));
--35in: calc(35 * var(--1in));
--36in: calc(36 * var(--1in));
--37in: calc(37 * var(--1in));
--38in: calc(38 * var(--1in));
--39in: calc(39 * var(--1in));
--40in: calc(40 * var(--1in));
/* --light-b-3: #dd5522;
--light-b-2: #ddaa33;
--light-b-1: #55dd33;
--light-b0: #dddddd;
--light-b1: #cccccc;
--light-b2: #bbbbbb;
--light-b3: #aaaaaa;
--light-b4: #999999;
--light-f-3: #993311;
--light-f-2: #aaaa22;
--light-f-1: #339911;
--light-f0: #111111;
--light-f1: #333333;
--light-f2: #444444;
--light-f3: #555555;
--light-f4: #777777;
--dark-b-3: #551111;
--dark-b-2: #555511;
--dark-b-1: #225511;
--dark-b0: #222222;
--dark-b1: #333333;
--dark-b2: #444444;
--dark-b3: #555555;
--dark-b4: #666666;
--dark-f-3: #ee7755;
--dark-f-2: #ccbb33;
--dark-f-1: #55cc33;
--dark-f0: #eeeeee;
--dark-f1: #cccccc;
--dark-f2: #bbbbbb;
--dark-f3: #aaaaaa;
--dark-f4: #888888;
*/
--b-3: var(--light-b-3);
--b-2: var(--light-b-2);
--b-1: var(--light-b-1);
--b0: var(--light-b0);
--b1: var(--light-b1);
--b2: var(--light-b2);
--b3: var(--light-b3);
--b4: var(--light-b4);
--f-3: var(--light-f-3);
--f-2: var(--light-f-2);
--f-1: var(--light-f-1);
--f0: var(--light-f0);
--f1: var(--light-f1);
--f2: var(--light-f2);
--f3: var(--light-f3);
--f4: var(--light-f4);
}
@media (prefers-color-scheme: dark) {
:root {
--b-3: var(--dark-b-3);
--b-2: var(--dark-b-2);
--b-1: var(--dark-b-1);
--b0: var(--dark-b0);
--b1: var(--dark-b1);
--b2: var(--dark-b2);
--b3: var(--dark-b3);
--b4: var(--dark-b4);
--f-3: var(--dark-f-3);
--f-2: var(--dark-f-2);
--f-1: var(--dark-f-1);
--f0: var(--dark-f0);
--f1: var(--dark-f1);
--f2: var(--dark-f2);
--f3: var(--dark-f3);
--f4: var(--dark-f4);
}
}
* {
font-size: var(--font-size);
}
/*
@media (max-width: 900px) {
:root {
--font-size: calc(1.3 * var(--font-size));
}
}
*/
body {
font-family: var(--font);
letter-spacing: var(--letter-spacing);
line-height: 1;
background-color: var(--b0);
color: var(--f1);
}
button {
border: inherit;
background: inherit;
color: inherit;
}
.break {
word-break: break-word;
}
.action {
touch-action: manipulation;
}
.hidden,
.folded {
display: none !important;
}
.jc {
justify-content: center;
}
.jb {
justify-content: space-between;
}
.ja {
justify-content: space-around;
}
.js {
justify-content: start;
}
.je {
justify-content: end;
}
.js {
justify-content: start;
}
.as {
align-items: start;
}
.af {
align-items: stretch;
}
.ae {
align-items: end;
}
.ac {
align-items: center;
}
.wfc {
width: fit-content;
}
.wf {
width: 100%;
}
.mw-page {
max-width: 650px;
}
.hf {
height: 100%;
}
.hfc {
height: fit-content;
}
.mono {
font-family: var(--font-mono), monospace;
font-size: calc(1em * var(--mono-scale));
}
.italic {
font-style: italic;
}
.underline {
text-decoration: underline;
}
.bold {
font-weight: bold;
}
.strike {
text-decoration: line-through;
}
.pre {
white-space: pre;
}
.pre-line {
white-space: pre-line;
}
.tl {
text-align: left;
}
.tc {
text-align: center;
}
.tr {
text-align: right;
}
.block {
display: block;
}
.inline {
display: inline-block;
}
.fc {
display: flex;
flex-direction: column;
}
.fcr {
display: flex;
flex-direction: column-reverse;
}
.fr {
display: flex;
flex-direction: row;
}
.frw {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.basis-full {
flex-basis: 100%;
}
.basis-half {
flex-basis: 50%;
flex-shrink: 0;
}
.basis-none {
flex-basis: 0%;
flex-shrink: 1;
}
.shrink-0 {
flex-shrink: 0;
}
.relative {
position: relative;
}
.absolute {
position: absolute;
}
.fixed {
position: fixed;
}
.sticky {
position: sticky;
}
.z-2 {
z-index: -20;
}
.z-1 {
z-index: -10;
}
.z0 {
z-index: 0;
}
.z1 {
z-index: 10;
}
.z2 {
z-index: 20;
}
.grow {
flex-grow: 1;
}
.g0 {
gap: 0;
}
.g1 {
gap: 4px;
}
.g2 {
gap: 8px;
}
.g3 {
gap: 12px;
}
.g4 {
gap: 16px;
}
.g5 {
gap: 20px;
}
.g6 {
gap: 24px;
}
.g7 {
gap: 32px;
}
.g8 {
gap: 40px;
}
.p-8 {
padding: 32px 64px;
}
.p-7 {
padding: 28px 56px;
}
.p-6 {
padding: 24px 48px;
}
.p-5 {
padding: 20px 40px;
}
.p-4 {
padding: 16px 32px;
}
.p-3 {
padding: 12px 24px;
}
.p-2 {
padding: 8px 16px;
}
.p-1 {
padding: 4px 8px;
}
.p0 {
padding: 0;
}
.p1 {
padding: 4px;
}
.p2 {
padding: 8px;
}
.p3 {
padding: 12px;
}
.p4 {
padding: 16px;
}
.p5 {
padding: 24px;
}
.p6 {
padding: 30px;
}
.p7 {
padding: 34px;
}
.p8 {
padding: 38px;
}
.p-page {
padding-top: 30px;
padding-bottom: 200px;
padding-left: 12px;
padding-right: 12px;
}
.ma {
margin: auto;
}
.mt1 {
margin-top: 1rem;
}
.mt2 {
margin-top: 2rem;
}
.mt3 {
margin-top: 3rem;
}
.m0 {
margin: 0;
}
.o0 {
opacity: 0%;
}
.o1 {
opacity: 10%;
}
.o2 {
opacity: 20%;
}
.o3 {
opacity: 30%;
}
.o4 {
opacity: 40%;
}
.o5 {
opacity: 50%;
}
.o6 {
opacity: 60%;
}
.o7 {
opacity: 70%;
}
.o8 {
opacity: 80%;
}
.o9 {
opacity: 90%;
}
.o10 {
opacity: 100%;
}
.scroll-y {
overflow-y: auto;
}
.scroll-x {
overflow-x: auto;
}
.scroll-hidden {
overflow: hidden;
}
.loader {
position: relative;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
.loader .loading {
opacity: 0;
transition: opacity 300ms;
}
.htmx-request .loader .loading,
.loader.htmx-request .loading {
opacity: 1;
}
.loader .loaded {
opacity: 1;
transition: opacity 300ms;
}
.htmx-request .loader .loaded,
.loader.htmx-request .loaded {
opacity: 0;
}
.f-3 {
color: var(--f-3);
}
.f-2 {
color: var(--f-2);
}
.f-1 {
color: var(--f-1);
}
.f0 {
color: var(--f0);
}
.f1 {
color: var(--f1);
}
.f2 {
color: var(--f2);
}
.f3 {
color: var(--f3);
}
.f4 {
color: var(--f4);
}
.b-3 {
background-color: var(--b-3);
}
.b-2 {
background-color: var(--b-2);
}
.b-1 {
background-color: var(--b-1);
}
.b0 {
background-color: var(--b0);
}
.b1 {
background-color: var(--b1);
}
.b2 {
background-color: var(--b2);
}
.b3 {
background-color: var(--b3);
}
.b4 {
background-color: var(--b4);
}
.s-2 {
font-size: 0.7rem;
}
.s-1 {
font-size: 0.85rem;
}
.s0 {
font-size: 1rem;
}
.s1 {
font-size: 1.15rem;
}
.s2 {
font-size: 1.3rem;
}
.s3 {
font-size: 1.45rem;
}
.s4 {
font-size: 1.6rem;
}
.s5 {
font-size: 2rem;
}
.s6 {
font-size: 2.4rem;
}
.bd0 {
border: none;
}
.bd1 {
border: 0.8px solid var(--b3);
}
.bd2 {
border: 0.8px solid var(--f3);
}
.bd3 {
border: 2px solid var(--f1);
}
/* deprecated */
.border {
border: 0.8px solid var(--f3);
}
.br1 {
border-radius: 3px;
}
.br2 {
border-radius: 6px;
}
.br3 {
border-radius: 12px;
}
.hover:hover {
filter: invert(20%);
}
.toggled {
filter: invert(100%);
}
.hover.toggled:hover {
filter: invert(100%);
}
.active,
.selected {
filter: invert(10%);
}
.hover.active:hover,
.hover.selected:hover {
filter: invert(25%);
}
.numbered > *:before {
content: counter(line);
display: inline-block;
border-right: 1px solid var(--f3);
padding: 0 .5em;
margin-right: .5em;
color: var(--f3);
min-width: 34px;
text-align: right;
}
.numbered > * {
display: block;
counter-increment: line;
}
.prose {
max-width: 650px;
margin: auto;
}
.prose h1 {
font-size: 1.45rem;
margin: 1rem 0;
}
.prose h2 {
font-size: 1.3rem;
margin: 1rem 0;
}
.prose h3 {
font-size: 1.15rem;
margin: 1rem 0;
}
.prose h1, .prose h2, .prose h3 {
font-weight: bold;
}
.prose p {
margin-bottom: 1rem;
line-height: var(--line-height);
}
.prose img {
max-width: 100%;
display: block;
max-height: 350px;
}
.prose details {
margin-bottom: 1rem;
}
.prose a {
text-decoration: underline;
}
.prose blockquote {
margin-left: 10px;
border-left: 2px solid var(--b3);
padding: 4px;
padding-left: 12px;
color: var(--f2);
}
.prose pre {
font-family: var(--font-mono);
font-size: calc(1em * var(--mono-scale));
overflow-x: auto;
width: 100%;
display: block;
padding: 8px;
}
.prose code {
font-family: var(--font-mono);
font-size: calc(1em * var(--mono-scale));
color: var(--f2);
}
.prose ul,
.prose ol {
padding-left: 29px;
line-height: calc(calc(1 + var(--line-height)) / 2);
margin-bottom: 0.6rem;
}
.prose ul p,
.prose ol p {
margin-bottom: 0;
line-height: var(--line-height);
}
.prose ul ul,
.prose ol ul,
.prose ul ol,
.prose ol ol {
margin-bottom: 0;
}
.prose summary {
user-select: none;
cursor: pointer;
}

View File

@ -1,291 +0,0 @@
customElements.define('ha-wk',
class extends HTMLElement {
static get observedAttributes() {
return ["stud", "here", "label", "tree-open"];
}
constructor() {
//
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.adoptedStyleSheets = [sharedStyles];
this.shadowRoot.innerHTML = `
<style>
:host {
display: flex;
height: 100%;
overflow: hidden;
flex-direction: column;
position: relative;
}
section {
position: sticky;
z-index: 10;
top: 0;
left: 0;
border: 2px solid var(--b3);
padding: 8px;
background-color: var(--b2);
}
#breadcrumbs {
display: flex;
flex-wrap: wrap;
gap: 4px;
flex-grow: 1;
background-color: var(--b2);
}
@media (max-width: 900px) {
#actions {
display: none;
}
}
</style>
<template id="button-template">
<button
class="b2 hover p1 br1 mono"
hx-target="closest ha-wk"
hx-swap="innerHTML"
slot="crumbs"
>
</button>
</template>
<section id="section" class="fc g2">
<nav class="fr g1">
<button
id="tree-btn"
class="b2 hover p1 br1 mono f2"
onclick="this.getRootNode().host.toggleAttribute('tree-open')"
slot="crumbs"
>
z
</button>
<button
class="b2 hover p1 br1 mono f2"
onclick="this.getRootNode().host.toggleMore(event)"
slot="crumbs"
>
#
</button>
<div id="breadcrumbs">
<slot id="btns" name="crumbs"></slot>
</div>
<div id="actions" class="f2">
<button
class="b2 hover p1 br1 mono"
onclick="this.getRootNode().host.clone(event)"
slot="crumbs"
>
c
</button>
<button
class="b2 hover p1 br1 mono"
onclick="this.getRootNode().host.raise(event)"
slot="crumbs"
>
&lt;
</button>
<button
class="b2 hover p1 br1 mono"
onclick="this.getRootNode().host.drop(event)"
slot="crumbs"
>
&gt;
</button>
<button
class="b2 hover p1 br1 mono"
onclick="this.getRootNode().host.burry(event)"
slot="crumbs"
>
_
</button>
<button
class="b2 hover p1 br1 mono"
onclick="this.getRootNode().host.suicide()"
slot="crumbs"
>
X
</button>
</div>
</nav>
<aside id="aside" class="hidden p3 b3 fc g3 br1">
<div class="frw g2">
<button
onclick="this.getRootNode().host.inspect()"
class="b3 hover p1 br1 mono"
id="stud"
></button>
</div>
</aside>
</div>
</section>
<div id="tree" class="hidden grow scroll-y scroll-x p2 b2">
<slot name="tree" id="tree-slot">Tree view</slot>
</div>
<slot id="slot">Nothing here</slot>
`;
}
connectedCallback() {
//
let treed = false;
this.gid("slot").addEventListener("slotchange", (e) => {
let nodes = e.target.assignedNodes();
let btns = this.gid("breadcrumbs");
this.gid("btns").assignedNodes().forEach(n => n.remove())
if (nodes.length) {
let wrapped = nodes[0];
if (wrapped.hasAttribute("empty")) {
this.setAttribute("tree-open", "")
} else {
this.removeAttribute("tree-open");
}
this.setAttribute("stud", wrapped.getAttribute("stud"));
if (wrapped.hasAttribute("here")) {
let here = wrapped.getAttribute("here");
here = here === "/" ? "" : here;
let label = wrapped.getAttribute("label");
this.setAttribute("here", here);
if (label) {
this.setAttribute("label", label)
} else {
this.removeAttribute("label");
}
//
let segments = here.split("/");
segments.forEach((s, i) => {
let btn = this.gid('button-template').content.cloneNode(true);
btn = btn.querySelector('button');
let dest = segments.slice(0, i+1).join("/")
btn.setAttribute("hx-get", `/neo/hawk${dest}`)
btn.textContent = s + "/";
this.appendChild(btn);
})
let tree = document.createElement("div");
let treeStub = document.createElement("div");
treeStub.setAttribute("hx-get", `/neo/hawk${here}?tree`);
treeStub.setAttribute("hx-target", `this`);
treeStub.setAttribute("hx-trigger", `load`);
treeStub.setAttribute("hx-swap", `outerHTML`);
tree.setAttribute("slot", "tree");
tree.appendChild(treeStub);
this.tree?.remove();
this.appendChild(tree);
htmx.process(document.body);
} else {
this.removeAttribute("here");
this.removeAttribute("label");
}
} else {
this.setAttribute("tree-open", "");
}
const event = new CustomEvent('here-change', {composed: true});
this.dispatchEvent(event);
})
}
attributeChangedCallback(name, oldValue, newValue) {
//
if (name === "stud") {
this.gid("stud").textContent = `%${newValue}`
} else if (name === "here") {
const event = new CustomEvent('true', {
bubbles: true,
composed: true,
});
this.dispatchEvent(event);
} else if (name === "label") {
const event = new CustomEvent('true', {
bubbles: true,
composed: true,
});
this.dispatchEvent(event);
} else if (name === "tree-open") {
let open = newValue !== null;
if (open) {
this.slotted.classList.add("hidden");
/* this.gid("section").classList.add("grow"); */
this.gid("tree").classList.remove("hidden");
this.gid("tree-btn").classList.add("b3");
} else {
this.slotted.classList.remove("hidden");
/* this.gid("section").classList.remove("grow"); */
this.gid("tree").classList.add("hidden");
this.gid("tree-btn").classList.remove("b3");
}
}
}
gid(id) {
//
return this.shadowRoot.getElementById(id);
}
get slotted() {
return (this.gid("slot").assignedNodes() || [null])[0]
}
get tree() {
return (this.gid("tree-slot").assignedNodes() || [null])[0]
}
inspect() {
const event = new CustomEvent('inspect-hawk', {
bubbles: true,
composed: true,
detail: {
stud: this.getAttribute("stud")
}
});
this.dispatchEvent(event);
}
toggleMore(e) {
this.gid("aside").classList.toggle("hidden");
e.target.classList.toggle("b3");
}
clone() {
const event = new CustomEvent('clone-hawk', {
bubbles: true,
composed: true,
detail: {
here: this.getAttribute("here"),
slot: this.getAttribute("slot"),
}
});
this.dispatchEvent(event);
}
burry() {
this.parentNode.insertAdjacentElement("beforeend", this);
const event = new CustomEvent('cull', {
bubbles: true,
composed: true,
});
this.dispatchEvent(event);
}
drop() {
this.nextElementSibling?.insertAdjacentElement("afterend", this);
const event = new CustomEvent('true', {
bubbles: true,
composed: true,
});
this.dispatchEvent(event);
}
raise() {
this.previousElementSibling?.insertAdjacentElement("beforebegin", this);
const event = new CustomEvent('true', {
bubbles: true,
composed: true,
});
this.dispatchEvent(event);
}
shoot() {
this.parentNode.insertAdjacentElement("afterbegin", this);
const event = new CustomEvent('true', {
bubbles: true,
composed: true,
});
this.dispatchEvent(event);
}
suicide() {
let par = this.parentNode;
this.remove();
const event = new CustomEvent('true', {
bubbles: true,
composed: true,
});
par.dispatchEvent(event);
}
})

99
pkg/arvo/web/reset.css Normal file
View File

@ -0,0 +1,99 @@
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
}
/* Prevent font size inflation */
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
/* Remove default margin in favour of better control in authored CSS */
body, h1, h2, h3, h4, p,
figure, blockquote, dl, dd {
margin-block-end: 0;
}
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role='list'],
ol[role='list'] {
list-style: none;
}
/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4,
button, input, label {
line-height: 1.1;
}
button, summary {
cursor: pointer;
}
/* Balance text wrapping on headings */
h1, h2,
h3, h4 {
text-wrap: balance;
}
a {
text-decoration: none;
color: currentColor;
}
/* Make images easier to work with */
img,
picture {
max-width: 100%;
display: block;
}
/* Inherit fonts for inputs and buttons */
input, button,
textarea, select {
font-family: inherit;
font-size: inherit;
border: inherit;
background: inherit;
color: inherit;
}
textarea {
resize: none;
}
/* Make sure textareas without a rows attribute are not tiny */
textarea:not([rows]) {
min-height: 10em;
}
/* Anything that has been anchored to should have extra scroll margin */
:target {
scroll-margin-block: 5ex;
}
html {
height: 100%;
}
body {
margin: 0;
color: var(--f0);
line-height: 1.1;
font-feature-settings: normal;
font-variation-settings: normal;
min-height: 100%;
}
b {
font-weight: bold;
}
i {
font-style: italic;
}

View File

@ -1,279 +0,0 @@
customElements.define('s-k-y',
class extends HTMLElement {
static get observedAttributes() {
//
return ["hawks"];
}
constructor() {
//
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.adoptedStyleSheets = [sharedStyles];
this.shadowRoot.innerHTML = `
<style>
:host {
width: 100%;
height: 100%;
}
</style>
<a-i-r class="wf hf">
<nav slot="nav" class="wf hf scroll-y fc g2 p2">
<button
class="p2 tc hover br1 b1"
onclick="this.getRootNode().host.newTab()"
>
+
</button>
<div class="fr g2">
<button
class="p1 br1 b1 grow hover"
onclick="this.getRootNode().host.cull()"
>
-
</button>
<button
class="p1 br1 b1 grow hover"
onclick="this.getRootNode().host.grow()"
>
+
</button>
</div>
<div id="tabs" class="fc g1 wf">
<template id="tab-template">
<div class="mono fr b1 br1" style="cursor: pointer;">
<button
class="action p2 b1 hover br1 hidden"
>+</button>
<button
class="action p2 b1 hover grow tl br1"
></button>
<button
class="action p2 hover br1"
>x</button>
</div>
</template>
</div>
</nav>
<slot slot="s1" name="s1"></slot>
<slot slot="s2" name="s2"></slot>
<slot slot="s3" name="s3"></slot>
<slot slot="s4" name="s4"></slot>
<slot style="display: none;"></slot>
</a-i-r>
`;
}
connectedCallback() {
//
if (this.isMobile) {
this.className = "fc grow wf af"
} else {
this.className = "fr wf hf"
}
this.gid("s0")?.addEventListener("slotchange", () => {this.reactSlot("s0")});
this.gid("s1")?.addEventListener("slotchange", () => {this.reactSlot("s1")});
this.gid("s2")?.addEventListener("slotchange", () => {this.reactSlot("s2")});
this.gid("s3")?.addEventListener("slotchange", () => {this.reactSlot("s3")});
this.gid("default")?.addEventListener("slotchange", (e) => this.reactDefault(e));
this.addEventListener("here-change", (e) => {
this.updateTabs();
this.syncTabs();
})
this.addEventListener("cull", (e) => {
this.cull();
this.updateTabs();
});
this.addEventListener("true", (e) => {
this.trueSlots();
this.updateTabs();
this.syncTabs();
});
this.addEventListener("grow", (e) => {
this.grow();
this.updateTabs();
});
this.addEventListener("clone-hawk", (e) => {
let here = e.detail.here;
let slot = e.detail.slot;
this.newTab(`/neo/hawk${here}`, slot);
this.updateTabs();
})
this.addEventListener("inspect-hawk", (e) => {
let stud = e.detail.stud
if (stud) {
this.newTab(`/neo/hawk/src/std/imp/${stud}`);
}
this.updateTabs();
})
}
attributeChangedCallback(name, oldValue, newValue) {
//
/* if (name === "open") { */
/* this.gid("aside").classList.toggle("hidden"); */
/* if (this.isMobile) { */
/* if (newValue === null) { */
/* this.gid("cs0").classList.remove("hidden"); */
/* } else { */
/* this.gid("cs0").classList.add("hidden"); */
/* } */
/* } else { */
/* this.gid("cs0").classList.remove("hidden"); */
/* } */
/* } else if (name === "hawks") { */
if (name === "hawks") {
this.qs("a-i-r").setAttribute("hawks", newValue);
this.trueSlots();
this.updateTabs();
}
}
get isMobile() {
return (window.innerWidth < 900)
}
get hawks() {
return parseInt(this.getAttribute("hawks") || "0");
}
get slottedHawks() {
return [...this.childNodes].filter(c => c.nodeName === 'HA-WK');
}
qs(sel) {
return this.shadowRoot.querySelector(sel);
}
gid(id) {
//
return this.shadowRoot.getElementById(id);
}
slotted(id) {
//
return (this.gid(id)?.assignedElements() || [null])[0];
}
trueSlots() {
//
let kids = [...this.childNodes].filter(c => c.nodeName === 'HA-WK');
let hawks = parseInt(this.getAttribute("hawks") || "1");
kids.forEach((k, i) => {
if (i < hawks) {
k.setAttribute("slot", `s${i+1}`)
} else {
k.removeAttribute("slot");
}
})
this.updateTabs();
}
reactSlot(id) {
//
let s = this.slotted(id);
let c = this.gid("c"+id);
let slot = parseInt(id.slice(1));
if (s && slot <= this.hawks) {
// display hawk
s.classList.add("b0");
s.classList.add("fc");
s.classList.add("js");
s.classList.add("scroll-y");
//
s.classList.add("grow");
c.classList.add("grow");
//
s.classList.add("basis-half");
c.classList.add("basis-half");
//
s.classList.remove("basis-none");
c.classList.remove("basis-none");
//
s.classList.remove('hidden');
c.classList.remove('hidden');
} else {
// hide hawk
if (s) {
s.classList.remove("grow");
s.classList.add("basis-none");
s.classList.remove("basis-half");
s.classList.add('hidden');
}
c.classList.remove("grow");
c.classList.add("basis-none");
c.classList.remove("basis-half");
c.classList.add('hidden');
}
this.updateTabs();
}
reactDefault(e) {
//
this.updateTabs();
}
updateTabs() {
//
let frames = [...this.childNodes].filter(c => c.nodeName === 'HA-WK');
let tabs = this.gid("tabs");
tabs.querySelectorAll('div').forEach(x => x.remove());
frames.forEach((f, i) => {
let here = f.getAttribute('here');
let label = f.getAttribute('label');
let open = f.hasAttribute('slot');
let tab = this.gid('tab-template').content.cloneNode(true);
tab = tab.querySelector('div');
if (open) {
tab.classList.add('active');
}
let add = tab?.firstElementChild;
let sel = add.nextElementSibling;
let del = sel.nextElementSibling;
sel.textContent = label || here || "/";
sel.addEventListener('click', (e) => {
e.preventDefault();
this.insertAdjacentElement("afterbegin", f);
this.trueSlots();
})
del.addEventListener('click', (e) => {
e.preventDefault();
f.suicide();
})
tabs.appendChild(tab);
})
}
newTab(here, slot) {
//
let hawk = document.createElement("ha-wk");
let stub = document.createElement("div");
stub.setAttribute("hx-get", here || "/neo/hawk/home");
stub.setAttribute("hx-target", "this");
stub.setAttribute("hx-swap", "outerHTML");
stub.setAttribute("hx-trigger", "load");
hawk.appendChild(stub);
hawk.setAttribute("here", "");
hawk.setAttribute("stud", "txt");
hawk.setAttribute("label", "Home");
let s = this.slotted(slot)
if (s) {
s.insertAdjacentElement("beforebegin", hawk);
} else {
this.insertAdjacentElement("afterbegin", hawk);
}
this.grow();
htmx.process(document.body);
this.updateTabs();
this.syncTabs();
}
cull() {
this.setAttribute("hawks", Math.max(0, this.hawks - 1));
this.trueSlots();
this.syncTabs();
}
grow() {
this.setAttribute("hawks", Math.min(4, this.slottedHawks.length, this.hawks + 1));
this.trueSlots();
this.syncTabs();
}
async syncTabs() {
let frames = [...this.childNodes].filter(c => c.nodeName === 'HA-WK');
let forms = frames.map(f => {
return `
<p here="${f.getAttribute('here')}"></p>
`
})
await fetch(`/neo/hawk/sky?stud=sky`, {
method: 'POST',
headers: {'content-type': 'text/html'},
body: `<div slots="${this.hawks}">${forms.join("")}</div>`
})
}
});

View File

@ -1,463 +0,0 @@
/** style.css
* ~2024.4.6
*
* styling resets
* and
* utility classes
*
**/
:root {
--x: 4px;
}
* {
box-sizing: border-box;
font: inherit;
color: inherit;
}
form, a, input, p, li, ul, ol, div, button, h1, h2, h3, h4, h5, h6 {
margin: 0;
line-height: 1;
}
html {
height: 100%;
font-size: 21px;
}
body {
margin: 0;
font-family: 'Urbit Sans';
font-feature-settings: normal;
font-variation-settings: normal;
letter-spacing: 0.024em;
line-height: 1;
background-color: var(--b0);
color: var(--f1);
min-height: 100%;
}
a {
cursor: pointer;
text-decoration: none;
font: inherit;
}
button, input, textarea, iframe {
border: unset;
}
img {
max-width: 100%;
}
.break {
word-break: break-word;
}
.action {
touch-action: manipulation;
}
.hidden,
.folded {
display: none !important;
}
.jc {
justify-content: center;
}
.jb {
justify-content: space-between;
}
.ja {
justify-content: space-around;
}
.js {
justify-content: start;
}
.je {
justify-content: end;
}
.js {
justify-content: start;
}
.as {
align-items: start;
}
.af {
align-items: stretch;
}
.ae {
align-items: end;
}
.ac {
align-items: center;
}
.wfc {
width: fit-content;
}
.wf {
width: 100%;
}
.mw-page {
max-width: 650px;
}
.hf {
height: 100%;
}
.hfc {
height: fit-content;
}
.mono {
font-variation-settings: "xtab" 500;
font-size: 0.8em;
}
.bold {
font-weight: bold;
}
.strike {
text-decoration: line-through;
}
.pre {
white-space: pre;
}
.pre-line {
white-space: pre-line;
}
.tl {
text-align: left;
}
.tc {
text-align: center;
}
.tr {
text-align: right;
}
.block {
display: block;
}
.fc {
display: flex;
flex-direction: column;
}
.fcr {
display: flex;
flex-direction: column-reverse;
}
.fr {
display: flex;
flex-direction: row;
}
.frw {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.basis-full {
flex-basis: 100%;
}
.basis-half {
flex-basis: 50%;
flex-shrink: 0;
}
.basis-none {
flex-basis: 0%;
flex-shrink: 1;
}
.shrink-0 {
flex-shrink: 0;
}
.relative {
position: relative;
}
.absolute {
position: absolute;
}
.fixed {
position: fixed;
}
.sticky {
position: sticky;
}
.z-2 {
z-index: -20;
}
.z-1 {
z-index: -10;
}
.z0 {
z-index: 0;
}
.z1 {
z-index: 10;
}
.z2 {
z-index: 20;
}
.grow {
flex-grow: 1;
}
.g1 {
gap: 4px;
}
.g2 {
gap: 8px;
}
.g3 {
gap: 12px;
}
.g4 {
gap: 16px;
}
.g5 {
gap: 20px;
}
.g6 {
gap: 24px;
}
.g7 {
gap: 28px;
}
.p-1 {
padding: 0px 4px;
}
.p0 {
padding: 0;
}
.p1 {
padding: 4px;
}
.p2 {
padding: 8px;
}
.p3 {
padding: 12px;
}
.p4 {
padding: 16px;
}
.p-page {
padding-top: 30px;
padding-bottom: 200px;
padding-left: 12px;
padding-right: 12px;
}
.ma {
margin: auto;
}
.scroll-y {
overflow-y: auto;
}
.scroll-x {
overflow-x: auto;
}
.scroll-hidden {
overflow: hidden;
}
.loader {
position: relative;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
}
.loader .loading {
opacity: 0;
transition: opacity 300ms;
}
.htmx-request .loader .loading,
.loader.htmx-request .loading {
opacity: 1;
}
.loader .loaded {
opacity: 1;
transition: opacity 300ms;
}
.htmx-request .loader .loaded,
.loader.htmx-request .loaded {
opacity: 0;
}
.f1 {
color: var(--f1);
}
.f2 {
color: var(--f2);
}
.f3 {
color: var(--f3);
}
.f-success {
color: var(--f-success);
}
.f-error {
color: var(--f-error);
}
.b0 {
background-color: var(--b0);
}
.b1 {
background-color: var(--b1);
}
.b2 {
background-color: var(--b2);
}
.b3 {
background-color: var(--b3);
}
.b-success {
background-color: var(--b-success);
}
.b-error {
background-color: var(--b-error);
}
.s-2 {
font-size: 0.7em;
}
.s-1 {
font-size: 0.85em;
}
.s0 {
font-size: 1em;
}
.s1 {
font-size: 1.15em;
}
.s2 {
font-size: 1.3em;
}
.s3 {
font-size: 1.45em;
}
.s4 {
font-size: 1.6em;
}
.border {
border: 1.2px solid var(--f3);
}
.border-2 {
border: 1px solid var(--f4);
}
.br1 {
border-radius: 3px;
}
.br2 {
border-radius: 6px;
}
input,
select {
outline: none;
border-radius: 0;
background-color: inherit;
color: inherit;
font: inherit;
line-height: inherit;
}
textarea {
display: block;
outline: none;
resize: none;
border-radius: 0;
border: 0;
background-color: inherit;
color: inherit;
}
button {
cursor: pointer;
background-color: inherit;
color: inherit;
}
.hover:hover {
filter: invert(20%);
}
.toggled {
filter: invert(100%);
}
.hover.toggled:hover {
filter: invert(100%);
}
.active,
.selected {
filter: invert(10%);
}
.hover.active:hover,
.hover.selected:hover {
filter: invert(25%);
}
.numbered > *:before {
content: counter(line);
display: inline-block;
border-right: 1px solid var(--f3);
padding: 0 .5em;
margin-right: .5em;
color: var(--f3);
min-width: 34px;
text-align: right;
}
.numbered > * {
display: block;
counter-increment: line;
}
.prose h1 {
font-size: 1.45rem;
margin: 1rem 0;
}
.prose h2 {
font-size: 1.3rem;
margin: 1rem 0;
}
.prose h3 {
font-size: 1.15rem;
margin: 1rem 0;
}
.prose h1, .prose h2, .prose h3 {
font-weight: bold;
}
.prose p {
margin-bottom: 1rem;
line-height: 1.3;
}
.prose img {
max-width: 100%;
display: block;
max-height: 350px;
}
.prose details {
margin-bottom: 1rem;
}
.prose a {
text-decoration: underline;
}
.prose mono {
font-size: 1em;
}
.prose pre {
font-variation-settings: "xtab" 500;
font-size: 0.8em;
overflow-x: auto;
width: 100%;
display: block;
padding: 8px;
}
.prose code {
white-space: pre;
overflow-x: auto;
width: 100%;
display: block;
padding: 8px;
}
.prose ul,
.prose ol {
padding-left: 19px;
line-height: 1.2;
margin-bottom: 1rem;
}
.prose ul p,
.prose ol p {
margin-bottom: 0;
line-height: 1.4;
}
.prose ul ul,
.prose ol ul,
.prose ul ol,
.prose ol ol {
margin-bottom: 0;
}
summary {
user-select: none;
cursor: pointer;
}