rewrite s-k-y and ha-wk in Sail

This commit is contained in:
Will Hanlen 2024-05-22 17:07:31 -05:00
parent 7bd3f693bf
commit ac61976231
19 changed files with 692 additions and 854 deletions

View File

@ -1,5 +1,5 @@
/- neo, sole-sur=sole
/+ default-agent, dbug, verb, shoe, serv=server
/+ default-agent, dbug, verb, shoe, serv=server, feather-icons
/* txt-hoon-imp %hoon /neo/src/std/imp/hoon/hoon
/* txt-term-imp %hoon /neo/src/std/imp/term/hoon
/* txt-ford-same %hoon /neo/src/std/imp/ford-same/hoon
@ -9,13 +9,11 @@
/* txt-ford-face %hoon /neo/src/std/imp/ford-face/hoon
/* txt-ford-reef %hoon /neo/src/std/imp/ford-reef/hoon
/* date-now %js /web/date-now/js
/* error-tray %js /web/error-tray/js
/* atom-input %js /web/atom-input/js
/* multiline-input %js /web/multiline-input/js
/* ha-wk %js /web/ha-wk/js
/* s-k-y %js /web/s-k-y/js
/* a-i-r %js /web/a-i-r/js
/* feather-css %css /web/feather/css
/* reset-css %css /web/reset/css
|%
++ pave pave:neo
++ ford ford:neo
@ -650,20 +648,146 @@
[~ ~]
--
++ dove
|_ here=pith:neo
++ curr
|_ [here=pith:neo slot=@ud id=@da]
++ ha-wk
;div.hawk.fc.wf.hf
=id "hawk-slot-{<id>}"
=hx-params "id,slot"
=hx-vals "\{\"id\": \"{<id>}\", \"slot\": \"{<slot>}\"}"
=morph-no-swap ""
;+ header
;+ raw
;+ rendered
==
++ header
;header.b2.p1.frw.g1.ac
=style "border: 2px solid var(--b2);"
;button.p1.hover.b2.br1
=onclick
"""
$(this).toggleClass('b3');
$(this).closest('.hawk').find('.raw').toggleClass('hidden');
$(this).closest('.hawk').find('.rendered').toggleClass('hidden');
$(this).closest('header').children('.hawk-tog').toggleClass('hidden');
"""
;+ outline:feather-icons
==
;a.p-1.hover.b2.br1.s0.hawk-tog.fc.ac.jc
=style "height: 2rem;"
=href "/neo/hawk"
; /
==
;*
=< p
%^ spin here
1
|= [=iota a=@]
:_ +(a)
;div.hawk-tog.fr.ac.g1
=style "height: 2rem;"
;div.f4.s-1: >
;a.hover.b2.br1.p1.s0
=hx-vals "\{\"id\": \"{<id>}\", \"slot\": \"{<slot>}\"}"
=href "/neo/hawk{(en-tape:pith:neo (scag a here))}"
; {(trip ?@(iota iota (scot iota)))}
==
==
;div.hawk-tog.grow;
;form.hawk-tog.hidden.grow.fr.ac.m0.relative
=style "height: 2rem;"
=hx-get "/neo/hawk"
=hx-target "closest .hawk"
;div.absolute
=style "top: 0.5rem; right: 0.5rem;"
;div.loader
;div.loaded(style "opacity: 0"): ---
;div.loading
;+ loading:feather-icons
==
==
==
;input.p-1.br1.b1.wf.s0.loaded.grow
=style "border: none;"
=type "text"
=value (en-tape:pith:neo here)
=oninput
"""
$(this).attr('value', this.value);
$(this).parent().attr('hx-get', '/neo/hawk'+this.value);
htmx.process(document.body);
"""
;
==
==
;div.fr.ac.jc.g1.hawk-actions
;button.p1.hover.b2.br1.loader.s-1
=hx-post "/neo/hawk/sky?stud=sky-diff"
=hx-target "find .loading"
=hx-swap "outerHTML"
=head "slide-up"
=slot "{<slot>}"
;span.loaded
;+ chevron-left:feather-icons
==
;span.loading
;+ loading.feather-icons
==
==
;button.p1.hover.b2.br1.loader.s-1
=hx-post "/neo/hawk/sky?stud=sky-diff"
=hx-target "find .loading"
=hx-swap "outerHTML"
=head "slide-down"
=slot "{<slot>}"
;span.loaded
;+ chevron-right:feather-icons
==
;span.loading
;+ loading.feather-icons
==
==
;button.p1.hover.b2.br1.loader.s-1
=hx-post "/neo/hawk/sky?stud=sky-diff"
=hx-target "find .loading"
=hx-swap "outerHTML"
=head "minimize"
=slot "{<slot>}"
;span.loaded
;+ minimize:feather-icons
==
;span.loading
;+ loading.feather-icons
==
==
;style
;+ ;/ %- trip
'''
@media(max-width: 900px) {
.hawk-actions {
display: none !important;
}
}
'''
==
==
==
++ rendered
::
=/ rom (get:of-top here)
=- -(a.g [[%here (en-tape:pith:neo here)] a.g.-])
^- manx
?~ rom
;div.wf.hf.fc.ac.jc(empty ""): nothing here
=/ =room:neo u.rom
=/ stud ^- @tas ?^(state.room mark.state.room state.room)
=- -(a.g [[%stud (trip stud)] a.g.-])
(val u.rom)
;div.rendered.wf.hf.b0.scroll-y.scroll-x
=id "hawk-rendered-{<id>}"
;+
?~ rom
;div.wf.hf.fc.ac.jc: nothing here
=/ =room:neo u.rom
=/ stud ^- @tas ?^(state.room mark.state.room state.room)
=- -(a.g [[%stud (trip stud)] a.g.-])
(val u.rom)
==
::
++ children
++ raw
::
=/ dirs
^- (list iota)
@ -672,9 +796,7 @@
%+ turn ~(tap by (kid:of-top here))
|= [=pith:neo *]
-.pith
;div.wf.hf.fc.g1.js.ac
=here (en-tape:pith:neo here)
=slot "tree"
;div.raw.hidden.b3.p2.fc.g1.js.ac.scroll-y.wf.hf
;*
?~ (lent dirs)
;=
@ -687,8 +809,8 @@
|= =iota
;button.p2.br1.b1.hover.wf.fr.js
=hx-get (en-tape:pith:neo :(weld /neo/hawk here /[iota]))
=hx-target "closest ha-wk"
=hx-swap "innerHTML"
=hx-target "closest .hawk"
=hx-swap "outerHTML"
; {(trip ?@(iota iota (scot iota)))}
==
==
@ -791,6 +913,13 @@
}
}
}
Idiomorph.defaults.callbacks.beforeNodeMorphed = (oldNode, newNode) => {
if (oldNode?.nodeName !== "#text") {
if (oldNode.hasAttribute('morph-no-swap') && oldNode.id === newNode.id) {
return false;
}
}
}
'''
::
++ lift
@ -838,22 +967,18 @@
*/
'''
==
;style: {(trip feather-css)}
;style: {(trip reset-css)}
;script
;+ ;/
"""
const sharedStyles = new CSSStyleSheet();
sharedStyles.replaceSync(`{(trip feather-css)}`);
document.adoptedStyleSheets = [sharedStyles];
window.log=function()\{if(this.console)\{console.log(Array.prototype.slice.call(arguments));}};
jQuery.fn.log=function (msg)\{console.log(msg, this); return this;};
"""
==
;script: {(trip date-now)}
;script: {(trip atom-input)}
;script: {(trip error-tray)}
;script: {(trip multiline-input)}
;script: {(trip ha-wk)}
;script: {(trip s-k-y)}
;script: {(trip a-i-r)}
;+ favicon
==
@ -863,7 +988,7 @@
=hx-boost "true"
=hx-history "false"
=hx-replace-url "/neo/sky"
=hx-target "closest ha-wk"
=hx-target "closest .hawk"
;+ in
==
==
@ -934,8 +1059,10 @@
*manx
::
=/ here=path (welp /[(scot %p our.bowl)] pax.purl)
=/ =pith (pave:neo pax.purl)
=* dov ~(. dove pith)
=/ =pith:neo (pave:neo pax.purl)
=/ slot (slav %ud (~(gut by pam.purl) 'slot' '0'))
=/ id (slav %da (~(gut by pam.purl) 'id' '~2000.1.1'))
=* dov ~(. dove pith slot id)
::
?: =('sky' i.t.site.line)
::
@ -946,33 +1073,33 @@
=/ bootstrap
^- (list card:neo)
:~
[(weld #/[p/our.bowl] here) %make %sky `!>([%system ~ 0]) ~]
[(weld #/[p/our.bowl] here) %make %sky ~ ~]
[#/[p/our.bowl]/home/diary %make %diary `!>('') ~]
[#/[p/our.bowl]/home/tasks %make %task `!>(['' | ~]) ~]
[#/[p/our.bowl]/home/sail %make %sail `!>(['' 'prose p3' ~]) ~]
[#/[p/our.bowl]/home/iframes/wiki %make %iframe `!>('https://en.wikipedia.org/wiki/Main_Page') ~]
==
|-
?~ bootstrap
%- send
%- manx-response:gen:serv
%- ~(lift dove pax.purl)
;div.wf.hf.fc.jc.ac
=hx-get "/neo/sky"
=hx-target "this"
=hx-swap "outerHTML"
=hx-trigger "load"
; initializing
==
=. run
%- poke-move
:- #/[p/our.bowl]/$/eyre/req/[eyre-id]
i.bootstrap
$(bootstrap t.bootstrap)
::
|-
?~ bootstrap
%- send
%- manx-response:gen:serv
%- ~(lift dove pax.purl 0 *@da)
;div.wf.hf.fc.jc.ac
=hx-get "/neo/sky"
=hx-target "this"
=hx-swap "outerHTML"
=hx-trigger "load"
; initializing
==
=. run
%- poke-move
:- #/[p/our.bowl]/$/eyre/req/[eyre-id]
i.bootstrap
$(bootstrap t.bootstrap)
::
%- send
%- manx-response:gen:serv
%- ~(lift dove pax.purl)
%- ~(lift dove pax.purl 0 *@da)
=+ !<(grow=$-(pail:neo $-(=bowl:neo manx)) (all-grow %htmx))
?> ?=(%icon -.seat.u.rum)
?~ man=(mole |.((grow [%sky state.icon.seat.u.rum])))
@ -1070,11 +1197,17 @@
::
:: %'GET' :: "read"
::
=/ s (~(get by pam.purl) 'slot')
=/ y (~(get by pam.purl) 'no-save')
=? run &(!=(~ s) =(~ y))
=/ slot (slav %ud (need s))
%- poke-move
:- #/[p/our.bowl]/$/eyre/req/[eyre-id]
[~[p/[our.bowl] %sky] %poke %sky-diff !>([%move-tab (dec slot) pith])]
%- send
%- manx-response:gen:serv
?: (~(has by pam.purl) 'tree')
children:dov
curr:dov
=? pith =(pith /sky) (welp pith /settings)
ha-wk:dov
::
=/ =path t.t.site.line
?: =(%'POST' method.request.req)
@ -1340,7 +1473,7 @@
==
++ take-agent
|= [=(pole knot) =sign:agent:gall]
~& pole/pole
::~& pole/pole
|^ ^+ run
?+ pole ~|(on-agent-bad-wire/pole !!)
[%sys rest=*] (take-agent:sys rest.pole sign)

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

@ -661,7 +661,7 @@
;h5: State
;button.b1.br1.p2.hover.wfc
=hx-get (spud (post-href %pro state:u.fim))
=hx-target "closest ha-wk"
=hx-target "closest .hawk"
=hx-swap "innerHTML"
; {<state:u.fim>}
==
@ -673,7 +673,7 @@
^- manx
;button.p2.br1.b1.hover
=hx-get (spud (post-href %pro stud))
=hx-target "closest ha-wk"
=hx-target "closest .hawk"
=hx-swap "innerHTML"
; {<stud>}
==

View File

@ -38,7 +38,7 @@
^- manx
;a.p2.br1.b1.hover
=hx-get (spud (post-href %pro stud.pro))
=hx-target "closest ha-wk"
=hx-target "closest .hawk"
=hx-swap "innerHTML"
; {<stud.pro>}
==

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 (dec (slav %ud (got:mu %slot)))]
%slide-up
[%slide-up (dec (slav %ud (got:mu %slot)))]
%slide-down
[%slide-down (dec (slav %ud (got:mu %slot)))]
%maximize
[%maximize (dec (slav %ud (got:mu %hawk-slot)))]
%close
[%close (dec (slav %ud (got:mu %hawk-slot)))]
::
==

View File

@ -9,4 +9,4 @@
|= =manx
=/ here (rush (~(got manx-utils manx) %here) stap)
?~ here ~
`(pave:neo u.here)
`[*@da (pave:neo u.here)]

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 "morph:outerHTML"
=hx-trigger "load"
;+ loading.feather-icons
==

View File

@ -1,5 +1,6 @@
/@ sky
/@ sky-settings
/- _/feather-icons
:- [%sky %htmx]
|= =sky
|= =bowl:neo
@ -17,6 +18,134 @@
--{(trip key)}: {(trip val)};
"""
++ shell
=/ settings
^- (unit sky-settings)
=/ s (~(get by kids.bowl) /settings)
?~ s ~
:- ~
!< sky-settings
q.u.s
;a-i-r.wf.hf.b1.relative
=id "air"
=hawks "{<slots.sky>}"
;button.hover.f2.b1.fc.ac.jc.air-btn
=slot "button"
=onclick "$(this).closest('a-i-r').attr('closed', !$(this).parent().attr('closed'))"
;div.fc.ac.jc.bold.s2: ~
==
;style
;+ ;/ %- trip
'''
.air-btn {
position: relative;
padding: 8px;
margin: 8px;
border-radius: 4px;
}
@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(--f3);
}
}
'''
==
;nav.wf.hf.p2.fc.g2
=slot "nav"
;hr.m0.wf.bd0.b3.o4(style "height: 1.5px;");
;+ new-tab
;*
=< p
%^ spin hawks.sky
1
|= [[id=@da =pith] a=@]
:_ +(a)
=/ color (trip ?:((lte a slots.sky) 'b2' 'b1'))
;div
=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
==
==
==
==
;*
=< p
%^ spin (scag slots.sky hawks.sky)
1
|= [[id=@da =pith] a=@]
:_ +(a)
=/ ext
?: =(pith /) ""
(en-tape:pith:neo pith)
;div.wf.hf.br1
=slot "s{<a>}"
=id "hawk-part-{<id>}"
;div.wf.hf.fc.jc.ac.f2.s3
=id "hawk-slot-{<id>}"
=morph-no-swap ""
=hx-get "/neo/hawk{ext}?slot={<a>}&id={<id>}&no-save"
=hx-trigger "load once"
=hx-target "this"
=hx-swap "outerHTML"
;+ loading.feather-icons
==
==
;style
;+ ;/
?~ settings
""
"""
html \{
{(map-to-css-tape u.settings)}
}
"""
==
==
++ new-tab
;button.loader.b2.p2.tc.br1.hover.o6.wfc.s-1
=hx-post "/neo/hawk/sky?stud=sky-diff"
=hx-target "find .loading"
=hx-swap "outerHTML"
=head "new-tab"
;span.loaded.fr.ac.js.g2
;+ add.feather-icons
;span: New tab
==
;span.loading
;+ loading:feather-icons
==
==
++ shell2
=/ settings
^- (unit sky-settings)
=/ s (~(get by kids.bowl) /settings)
@ -29,7 +158,7 @@
=< p
%^ spin hawks.sky
1
|= [=pith a=@]
|= [[id=@da =pith] a=@]
:_ +(a)
;ha-wk
=slot "s{<a>}"
@ -39,8 +168,8 @@
=hx-trigger "load"
=hx-target "this"
=hx-swap "outerHTML"
;div.wf.hf.fc.jc.ac.f2
; loading . . .
;div.wf.hf.fc.jc.ac.f2.s3
;+ loading.feather-icons
==
==
==

View File

@ -5,8 +5,8 @@
^- manx
|^
;div.wf.p-page
=label "Settings"
;form.fc.g5.mw-page.ma
=label "Settings"
=hx-post "/neo/hawk{(en-tape:pith:neo here.bowl)}?stud=sky-settings"
=hx-swap "none"
;+ script
@ -18,7 +18,8 @@
;button.p3.br1.b1.hover
=onclick "document.body.removeAttribute('style')"
=hx-get "/neo/hawk{(en-tape:pith:neo here.bowl)}"
=hx-select "ha-wk"
=hx-target "closest .hawk"
=hx-select ".hawk"
;span: Reset
==
;button.p3.br1.b1.hover.loader
@ -32,7 +33,7 @@
;div.fc.js.g2.ja.p2
;label.fc.g1.mt1
;span.s-1: Main font
;select.br1
;select.br1.bd1.p2
=oninput "setCss('font', this.value); $(this).attr('value', this.value);"
=value (trip (~(gut by settings) 'font' ''))
=var "font"
@ -69,7 +70,7 @@
==
;label.fc.g1
;span.s-1: Monospace font
;select.br1
;select.br1.bd1.p2
=oninput "setCss('font-mono', `'$\{this.value}'`); $(this).attr('value', this.value);"
=value (trip (~(gut by settings) 'font-mono' ''))
=var "font-mono"
@ -181,7 +182,7 @@
;+ ;/ %- trip
'''
function setCss(name, val) {
document.body.style
document.documentElement.style
.setProperty('--'+name, val, 'important');
}
'''

View File

@ -1,7 +1,8 @@
/@ sky
/@ sky-diff
|%
++ state %sky
++ poke (sy %sky ~)
++ poke (sy %sky %sky-diff ~)
++ kids
%- ~(gas by *kids:neo)
:~
@ -15,9 +16,72 @@
++ poke
|= [=stud:neo vax=vase]
^- (quip card:neo vase)
?> =(%sky stud)
=/ new (sky !<(sky vax))
[~ !>(new)]
?+ stud !!
%sky [~ vax]
%sky-diff
=/ poke !<(sky-diff vax)
=/ this !<(sky state-vase)
?+ -.poke !!
%new-tab
:- ~
=. hawks.this [[now.bowl /home] hawks.this]
=. slots.this (min 4 +(slots.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) ~]
==
=. slots.this (dec slots.this)
!>(this)
%maximize
:- ~
=. hawks.this
;: welp
[(snag slot.poke hawks.this) ~]
(scag slot.poke hawks.this)
(slag +(slot.poke) hawks.this)
==
=? slots.this (gth slot.poke slots.this) (min 4 +(slots.this))
!>(this)
%close
:- ~
=. hawks.this (oust [slot.poke 1] hawks.this)
!>(this)
%slide-up
:- ~
=? hawks.this
(gth slot.poke 0)
=/ ok
;: welp
(scag (dec slot.poke) hawks.this)
[(snag slot.poke hawks.this) ~]
[(snag (dec slot.poke) hawks.this) ~]
(slag +(slot.poke) hawks.this)
==
~& ok
ok
!>(this)
%slide-down
:- ~
=? hawks.this
(lth slot.poke 4)
;: 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)
@ -25,6 +89,9 @@
:~ [(welp here.bowl /settings) %make %sky-settings ~ ~]
==
!>
[~[~[%home]] 1]
:_ 1
:~
[now.bowl ~[%home]]
==
--
--

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

@ -1,4 +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

@ -1,4 +1,4 @@
$:
hawks=(list pith)
hawks=(list (pair @da pith))
slots=@ud
==

View File

@ -8,7 +8,6 @@ class extends HTMLElement {
//
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.adoptedStyleSheets = [sharedStyles];
this.shadowRoot.innerHTML = `
<style>
* {
@ -17,9 +16,6 @@ class extends HTMLElement {
::slotted(*) {
overflow: auto;
}
button {
border: none;
}
:host {
display: grid;
width: 100%;
@ -28,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";
@ -120,8 +116,9 @@ class extends HTMLElement {
main.s4 #s4 {
display: block;
}
button {
#button {
grid-area: btn;
height: fit-content;
}
main {
display: grid;
@ -133,35 +130,38 @@ class extends HTMLElement {
}
#s1 {
grid-area: s1;
padding: 3px;
}
#s2 {
grid-area: s2;
padding: 3px;
}
#s3 {
grid-area: s3;
padding: 3px;
}
#s4 {
grid-area: s4;
}
button {
background-color: var(--b1);
color: var(--f1);
padding: 3px;
}
@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,8 +172,12 @@ class extends HTMLElement {
grid-template-areas:
"s1";
}
#nav {
--rem: 24px;
}
#s1 {
display: block;
padding: 0;
}
main #s2 {
display: none !important;
@ -192,9 +196,9 @@ class extends HTMLElement {
}
}
</style>
<slot name="button">
<slot name="button" id="button">
<button
class="hover b1 bold s2"
style="border: 2px solid var(--b3);"
onclick="this.getRootNode().host.dispatchEvent(new CustomEvent('sky-open', {bubbles:true, composed: true}))"
>
~

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);
}
});

View File

@ -15,9 +15,9 @@
--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));
@ -133,41 +133,29 @@
--f4: var(--dark-f4);
}
}
* {
box-sizing: border-box;
font: inherit;
color: inherit;
font-size: var(--font-size);
}
form, a, input, p, li, ul, ol, div, button, h1, h2, h3, h4, h5, h6 {
margin: 0;
line-height: 1;
}
html {
height: 100%;
/*
@media (max-width: 900px) {
:root {
--font-size: calc(1.3 * var(--font-size));
}
}
*/
body {
margin: 0;
font-family: var(--font), sans-serif;
font-feature-settings: normal;
font-variation-settings: normal;
font-family: var(--font);
letter-spacing: var(--letter-spacing);
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 {
button {
border: unset;
background: unset;
color: unset;
}
img {
max-width: 100%;
}
.break {
word-break: break-word;
}
@ -227,12 +215,6 @@ img {
font-family: var(--font-mono), monospace;
font-size: calc(1em * var(--mono-scale));
}
b {
font-weight: bold;
}
i {
font-style: italic;
}
.italic {
font-style: italic;
}
@ -594,7 +576,9 @@ i {
.s6 {
font-size: 2.4rem;
}
.bd0 {
border: none;
}
.bd1 {
border: 0.8px solid var(--f3);
}
@ -619,30 +603,6 @@ i {
border-radius: 12px;
}
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%);
}
@ -745,7 +705,7 @@ button {
.prose ol ol {
margin-bottom: 0;
}
summary {
.prose summary {
user-select: none;
cursor: pointer;
}

View File

@ -1,344 +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;
font-size: 1rem !important;
background-color: var(--b0);
}
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"
hx-target="closest ha-wk"
hx-swap="innerHTML"
slot="crumbs"
>
</button>
</template>
<section id="section" class="fc g2">
<nav class="frw g1 ac">
<button
id="tree-btn"
class="b2 hover p1 br1 mono f2"
onclick="this.getRootNode().host.toggleAttribute('tree-open')"
slot="crumbs"
>
${this.iconFiles()}
</button>
<button
class="b2 hover p1 br1 mono f2"
onclick="this.getRootNode().host.toggleMore(event)"
slot="crumbs"
>
${this.iconMore()}
</button>
<div id="breadcrumbs">
<slot id="btns" name="crumbs"></slot>
</div>
<div id="actions" class="f2">
<button
class="b2 hover p1 br1 mono hidden"
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"
>
${this.chevronLeft()}
</button>
<button
class="b2 hover p1 br1 mono"
onclick="this.getRootNode().host.drop(event)"
slot="crumbs"
>
${this.chevronRight()}
</button>
<button
class="b2 hover p1 br1 mono"
onclick="this.getRootNode().host.burry(event)"
slot="crumbs"
>
${this.iconClose()}
</button>
<button
class="b2 hover p1 br1 mono hidden"
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);
}
chevronLeft() {
return `
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
width="1rem"
fill="currentColor"><path d="M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z"/></svg>
`
}
chevronRight() {
return `
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
width="1rem"
fill="currentColor"><path d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"/></svg>
`
}
iconClose() {
return `
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
width="1rem"
fill="currentColor">
<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"/></svg>
`
}
iconMore() {
return `
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
width="1rem"
fill="currentColor">
<path d="M480-160q-33 0-56.5-23.5T400-240q0-33 23.5-56.5T480-320q33 0 56.5
23.5T560-240q0 33-23.5 56.5T480-160Zm0-240q-33 0-56.5-23.5T400-480q0-33 23.5-56.5T480-560q33
0 56.5 23.5T560-480q0 33-23.5 56.5T480-400Zm0-240q-33 0-56.5-23.5T400-720q0-33 23.5-56.5T480-800q33
0 56.5 23.5T560-720q0 33-23.5 56.5T480-640Z"/></svg>
`
}
iconFiles() {
return `
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
width="1rem"
fill="currentColor">
<path d="M120-240v-80h240v80H120Zm0-200v-80h480v80H120Zm0-200v-80h720v80H120Z"/></svg>
`
}
})

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

@ -0,0 +1,91 @@
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* 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;
}
/* 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;
}
/* 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,307 +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 b1">
<nav slot="nav" class="wf hf scroll-y fc g2 p2">
<button
class="p2 tc hover br1 b1"
onclick="this.getRootNode().host.newTab()"
>
${this.iconAdd()}
</button>
<div class="fr g2 hidden">
<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="frw b1 br1" style="cursor: pointer;">
<button
class="action p2 b1 hover br1 hidden"
>+</button>
<button
class="action p2 b1 hover grow tl br1 break"
></button>
<button
class="action p2 hover br1"
>${this.iconClose()}</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);
if (f.hasAttribute("slot")) {
this.trueSlots();
} else {
this.grow();
}
})
del.addEventListener('click', (e) => {
e.preventDefault();
let cullp = f.hasAttribute("slot");
f.suicide();
if (cullp) {
this.cull();
} else {
this.trueSlots();
}
})
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("").trim()}</div>`
})
}
iconClose() {
return `
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
width="1rem"
fill="currentColor">
<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"/></svg>
`
}
iconAdd() {
return `
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -960 960 960"
width="1.2rem"
fill="currentColor">
<path d="M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z"/></svg>
`
}
});