diff --git a/pkg/arvo/neo/cod/std/src/con/http-request-sky-diff.hoon b/pkg/arvo/neo/cod/std/src/con/http-request-sky-diff.hoon new file mode 100644 index 0000000000..d17ee23c72 --- /dev/null +++ b/pkg/arvo/neo/cod/std/src/con/http-request-sky-diff.hoon @@ -0,0 +1,23 @@ +/@ sky-diff +/@ http-request +/- serv=sky-server +:- [%http-request %$ %sky-diff] +|= =http-request +=/ pam (~(uni by pam:(parse-url:serv http-request)) (parse-form-body:serv http-request)) +=/ bod ~(. by pam) +=/ head (@tas (got:bod 'head')) +^- sky-diff +?+ head ~|(bad-head/head !!) + %new-hawk + [head (slav %da (got:bod 'now'))] + %close + [head (slav %ud (got:bod 'slot'))] + %maximize + [head (slav %ud (got:bod 'slot'))] + %slide-up + [head (slav %ud (got:bod 'slot'))] + %slide-down + [head (slav %ud (got:bod 'slot'))] + %minimize + [head (slav %ud (got:bod 'slot'))] +== diff --git a/pkg/arvo/neo/cod/std/src/con/node-sky-diff.hoon b/pkg/arvo/neo/cod/std/src/con/node-sky-diff.hoon index c5fe5414e8..a37cd94826 100644 --- a/pkg/arvo/neo/cod/std/src/con/node-sky-diff.hoon +++ b/pkg/arvo/neo/cod/std/src/con/node-sky-diff.hoon @@ -10,17 +10,5 @@ %menu =/ c ?~((get:mu %closed) %.y %.n) [%menu c] - %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))] :: == diff --git a/pkg/arvo/neo/cod/std/src/con/sky-htmx.hoon b/pkg/arvo/neo/cod/std/src/con/sky-htmx.hoon index b5f054d885..115741346b 100644 --- a/pkg/arvo/neo/cod/std/src/con/sky-htmx.hoon +++ b/pkg/arvo/neo/cod/std/src/con/sky-htmx.hoon @@ -1,31 +1,65 @@ /@ sky /@ sky-settings /- feather-icons +/* date-now +/* a-i-r +/* feather +/* reset +/* hawk-icon +/* jquery +/* htmx-js +/* htmx-response-targets +/* htmx-idiomorph :- [%sky %$ %htmx] |= =sky |= =bowl:neo ^- manx |^ - ;div.wf.hf.relative - ;+ - =; m - ?: menu.sky m - m(a.g [[%closed ""] a.g.m]) - ^- manx - ;a-i-r.wf.hf.relative - =style "opacity: var(--sky-opacity); padding: var(--sky-outer-gap);" - =id "air" - =hawks "{}" - =morph-retain "closed" - ;+ menu-btn - ;+ menu-btn-style - ;+ theme-style - ;+ nav - ;* p:(spin (scag open.sky hawks.sky) 0 ha-wk) - == - ;+ eye + =; m + %- lift + ?: menu.sky m + m(a.g [[%closed ""] a.g.m]) + ^- manx + ;a-i-r.wf.hf.relative + =style "opacity: var(--sky-opacity); padding: var(--sky-outer-gap);" + =id "air" + =hawks "{}" + =morph-retain "closed" + =hx-on-hawks-moved hawks-moved-js + =hx-on-htmx-after-request + """ + let verb = event.detail.requestConfig.verb; + let url = new URL(event.detail.xhr.responseURL); + let pams = new URLSearchParams(url.search); + if (verb === 'get' && + url.pathname.startsWith('/neo/hawk/~') && + !pams.has('no-save') + ) \{ + $('.nav-refresher').emit('refresh'); + } + """ + ;* p:(spin (scag open.sky hawks.sky) 0 ha-wk) + ;+ menu-btn + ;+ nav == :: +++ hawks-moved-js + :: js to run whenever the order or number of hawks changed. + :: it will: + :: - trigger a refresh of the nav + :: - loop through any slotted hawks and reslot them starting from 0 + %- trip + ''' + let air = $(this); + let num = parseInt(air.attr('hawks')); + let hawks = air.children('[slot]').filter('.hawk').get(); + hawks.sort((a, b) => { + return (a.getAttribute('slot') < b.getAttribute('slot')) ? -1 : 1; + }).forEach((h, i) => { + h.setAttribute('slot', `s${i}`); + }); + air.find('.nav-refresher').emit('refresh'); + ''' ++ map-to-css-tape |= m=(map @t @t) ^- tape @@ -102,26 +136,30 @@ ?: =(pith /) "" (en-tape:pith:neo pith) =/ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn))))) - ;div.wf.hf.br1 + ;div.wf.hf.fc.jc.ac.f2.s3.spinner =slot "s{}" - =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={}&hawk-id={}&no-save" - =hx-trigger "load" - =hx-target "#hawk-{idt}" - =hx-swap "morph" - ; - == + =id "hawk-{idt}" + =hx-get "/neo/hawk{ext}?slot={}&hawk-id={}&no-save" + =morph-retain "slot" + =hx-trigger "load" + =hx-target "this" + =hx-swap "morph" + ;+ loading.feather-icons == ++ nav - ;nav.wf.hf.p2.fc.g2 + ;nav.wf.hf.p2.fc.g2.sky-nav =slot "nav" - ;div.mt2.o0; + ;div.nav-refresher.loader.p3 + =hx-get "/neo/sky" + =hx-swap "outerHTML" + =hx-target "closest nav" + =hx-select "nav.sky-nav" + =hx-trigger "refresh" + ;span.loaded; + ;span.loading + ;+ loading.feather-icons + == + == ;+ new-tab ;* =< p @@ -132,16 +170,46 @@ :_ +(a) =/ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn))))) =/ color (trip ?:((lth a open.sky) 'b2' 'b1')) + =/ close-hawk-js + %- trip + ''' + let toClose = parseInt(this.getAttribute('close')); + let air = $('a-i-r'); + let num = parseInt(air.attr('hawks')); + let hawks = air.children('[slot]').filter('.hawk'); + if (toClose < num) { + air.attr('hawks', hawks.length-1); + } + hawks.each(function() { + let slot = parseInt($(this).attr('slot').slice(1)); + if (slot == toClose) { + $(this).remove(); + } + }); + $(this).emit('hawks-moved'); + ''' + :: =/ maximize-hawk-js + :: %- trip + :: ''' + :: let air = $('a-i-r'); + :: let num = parseInt(air.attr('hawks')); + :: air.attr('hawks', num+1); + :: let toMax = '#hawk-' + this.getAttribute('hawk'); + :: $(toMax).attr('slot', 's-1'); + :: $(this).emit('hawks-moved'); + :: ''' ;div =id "hawk-tab-{idt}" + =hx-ext "ignore:html-enc" =class "fr ac br1 {color}" ;button =class "loader p2 tl br1 hover grow {color}" - =hx-post "/neo/hawk/{}/sky?stud=sky-diff" + =hx-post "/neo/hawk/{}/sky?stud=sky-diff&head=maximize&slot={}" + :: XX optimistically render + ::=hx-on-htmx-after-request maximize-hawk-js + =hawk idt =hx-target "find .loading" =hx-swap "outerHTML" - =head "maximize" - =hawk-slot "{}" ;span.loaded: {(en-tape:pith:neo pith)} ;span.loading ;+ loading.feather-icons @@ -149,11 +217,10 @@ == ;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 "{}" + =close "{}" + =hx-post "/neo/hawk/{}/sky?stud=sky-diff&head=close&slot={}" + =hx-swap "none" + =hx-on-htmx-after-request close-hawk-js ;span.loaded.f3 ;+ close.feather-icons == @@ -164,12 +231,15 @@ == == ++ new-tab + :: XX optimistically render ;button.loader.b2.p2.tc.br1.hover.wfc.s-1 - =hx-post "/neo/hawk/{}/sky?stud=sky-diff" + =hx-ext "ignore:html-enc" + =hx-post "/neo/hawk/{}/sky?stud=sky-diff&head=new-hawk" =hx-target "find .loading" =hx-swap "outerHTML" + =hx-on-htmx-after-request "$(this).emit('hawks-moved')" =type "button" - =head "new-tab" + =hx-vals (trip 'js:{now: urbitTimestamp()}') ;span.loaded.fr.ac.js.g2 ;+ add.feather-icons ;span.f3: new window @@ -269,4 +339,194 @@ ''' == == +++ icon-url + ^~ + %- trip + %^ cat + 3 + 'data:image/png;base64,' + %- ~(en base64:mimes:html & |) + (as-octs:mimes:html hawk-icon) +++ favicon + ^~ + =; m m(a.g [[%href icon-url] a.g.m]) + ^- manx + ;link + =rel "icon" + =type "image/png" + ; + == +++ manifest-url + ^~ + %- trip + %^ cat + 3 + 'data:application/json;utf-8,' + %- en:json:html + %- pairs:enjs:format + :~ + ['name' s+'sky'] + ['description' s+'an urbit namespace viewer'] + ['start_url' s+'http://localhost/neo/sky'] :: XX + ['display' s+'standalone'] + ['background_color' s+'black'] + :+ 'icons' %a + :~ + %- pairs:enjs:format + :~ + ['src' s+(crip icon-url)] + ['sizes' s+'196x196'] + ['type' s+'image/png'] + == + == + == +++ manifest + ^~ + =; m m(a.g [[%href manifest-url] a.g.m]) + ^- manx + ;link + =rel "manifest" + ; + == +++ htmx-extensions + :: htmx extension which encodes the request + :: as the serialized HTML of the calling element + :: + :: XX usage of this should be optional. + :: requests should default to form-encoded. + %- trip + ''' + htmx.defineExtension('html-enc', { + onEvent: function (name, evt) { + if (name === "htmx:configRequest") { + evt.detail.headers['Content-Type'] = "text/html"; + } + }, + encodeParameters : function(xhr, parameters, elt) { + xhr.overrideMimeType('text/html'); + let xmls = new XMLSerializer(); + return (xmls.serializeToString(elt)); + } + }); + Idiomorph.defaults.ignoreActive = true; + Idiomorph.defaults.callbacks.beforeAttributeUpdated = (name, node, type) => { + if (node.hasAttribute('morph-retain')) { + let ribs = node.getAttribute('morph-retain').split(',').map(t => t.trim()); + if (ribs.includes(name)) { + return false; + } + } + } + Idiomorph.defaults.callbacks.beforeNodeMorphed = (oldNode, newNode) => { + if (oldNode?.nodeName !== "#text") { + if (oldNode.hasAttribute('morph-no-swap') && oldNode.id === newNode.id) { + return false; + } + else if ( + newNode.hasAttribute('morph-if-class') && + !oldNode.classList.contains(newNode.getAttribute('morph-if-class')) + ) { + return false; + } + } + } + ''' +:: +++ lift + |= in=manx + ^- manx + ;html + ;head + ;meta(charset "UTF-8"); + ;title: s k y + ;script: {(trip jquery)} + ;script: {(trip htmx-js)} + ;script: {(trip htmx-response-targets)} + ;script: {(trip htmx-idiomorph)} + ;script: {htmx-extensions} + ;meta + =name "viewport" + =content + """ + width=device-width, + initial-scale=1.0, + maximum-scale=1.0 + """ + ; + == + ;meta + =name "htmx-config" + =content (trip '{"ignoreTitle":"true"}') + ; + == + ::;style + :: ;+ ;/ %- trip + :: ''' + :: @font-face { + :: font-family: 'Urbit Sans'; + :: src: url("https://media.urbit.org/fonts/UrbitSans/UrbitSansVFWeb-Regular.woff2") format("woff2"); + :: font-style: normal; + :: font-weight: 100 700; + :: } + :: ''' + ::== + ;style: {(trip reset)} + ;style: {(trip feather)} + ;script + ;+ ;/ %- trip + ''' + window.log = function() { + if (this.console) { + console.log(Array.prototype.slice.call(arguments)); + } + }; + jQuery.fn.log = function (msg) { + console.log(msg, this); + return this; + }; + jQuery.fn.emit = function (name) { + (this[0]).dispatchEvent( + new Event( + name, + { bubbles: true, cancelable: true, composed: true } + ) + ); + return this; + }; + function urbitTimestamp() { + let now = new Date(); + let year = now.getFullYear(); + let month = now.getMonth() + 1; + let date = now.getDate(); + let hour = String(now.getHours()).padStart(2, '0'); + let min = String(now.getMinutes()).padStart(2, '0'); + let sec = String(now.getSeconds()).padStart(2, '0'); + return `~${year}.${month}.${date}..${hour}.${min}.${sec}`; + } + ''' + == + ;script: {(trip a-i-r)} + ;script: {(trip date-now)} + ;+ favicon + ;+ manifest + == + ;body + =hx-ext "html-enc,response-targets,morph" + =hx-swap "outerHTML" + =hx-boost "true" + =hx-history "false" + =hx-replace-url "/neo/sky" + =style + """ + background-color: var(--b1); + background-image: var(--sky-bg-url); + background-size: var(--sky-bg-size); + background-repeat: var(--sky-bg-repeat); + """ + ;+ in + ;+ eye + ;+ menu-btn-style + ;+ theme-style + == + == -- diff --git a/pkg/arvo/neo/cod/std/src/imp/hawk-eyre-handler.hoon b/pkg/arvo/neo/cod/std/src/imp/hawk-eyre-handler.hoon index 1846070e05..d65d9c67af 100644 --- a/pkg/arvo/neo/cod/std/src/imp/hawk-eyre-handler.hoon +++ b/pkg/arvo/neo/cod/std/src/imp/hawk-eyre-handler.hoon @@ -3,6 +3,7 @@ /- serv=sky-server /> htmx /< node +/< http-request =< ^- kook:neo |% @@ -38,7 +39,7 @@ :_ [stud vase] =/ purl (parse-url:serv request.req) =/ id=@da (slav %da (~(gut by pam.purl) 'hawk-id' '~2000.1.1')) - =/ slot=@ud (slav %ud (~(gut by pam.purl) 'slot' '99')) + =/ slot=@ud (slav %ud (~(gut by pam.purl) 'slot' '999')) =/ meta [id slot] ?~ src=(~(get by deps.bowl) %src) =/ stub @@ -115,12 +116,21 @@ :: %'POST' =/ purl (parse-url:serv request.req) + =/ content-type (~(gut by pam.purl) 'content-type' 'text/html') + ~& content-type =/ body (parse-body:serv request.req) =/ poke-stud ^- stud:neo ~| %no-stud-specified (~(got by pam.purl) 'stud') - =/ mul (mule |.((node [poke-stud body]))) + =/ mul + %- mule + |. + ?: =(content-type 'application/x-www-form-urlencoded') + ~& poke-stud + =/ fine (http-request [poke-stud `request:http`request.req]) + fine + (node [poke-stud body]) ?- -.mul %.n %: eyre-cards @@ -277,12 +287,27 @@ ?@(f (trip f) (scow f)) ++ id -.meta ++ slot +.meta + ++ slot-tag + :: XX oh boy this is hacky. + :: working with slots in ssr is tough + ?: =(slot 999) "s-1" + "s{}" ++ idt `tape`(zing (scan +:(scow %da id) (most dot (star ;~(less dot prn))))) + ++ vals + %^ cat 3 'js:{' + %^ cat 3 '"hawk-id": $(event?.target)?.closest("[slot]").attr("hawk-id") || "~2001.1.1"' + %^ cat 3 ', ' + %^ cat 3 'slot: $(event?.target)?.closest("[slot]").attr("slot")?.slice(1) || "0"' + '}' ++ lift ^- manx ;div.hawk.fc.wf.hf + =id "hawk-{idt}" + =hawk-id (scow %da id) + =slot slot-tag =hx-params "hawk-id,slot" - =hx-vals "\{\"hawk-id\": \"{}\", \"slot\": \"{}\"}" + =hx-vals (trip vals) + =hx-target "closest .hawk" =hx-target-x "closest .rendered" =hx-target-404 "this" ;+ header @@ -368,12 +393,24 @@ == ;div.fr.ac.jc.g1.hawk-actions =id "hawk-actions-{idt}" + =hx-ext "ignore:html-enc" ;button.p1.hover.b2.br1.loader.s-1 - =hx-post "/neo/hawk/{our-tape}/sky?stud=sky-diff" - =hx-target "find .loading" - =hx-swap "outerHTML" - =head "slide-up" - =hawk-slot "{}" + =hx-post "/neo/hawk/{our-tape}/sky?stud=sky-diff&head=slide-up" + =hx-on-htmx-after-request + """ + let swaper = $(this).closest('[slot]'); + let slot = parseInt(swaper.attr('slot').slice(1)); + let swapee = $(this).closest('a-i-r').find(`[slot='s$\{slot-1}']`); + if (swaper.length && swapee.length) \{ + let ee = swapee.attr('slot'); + let er = swaper.attr('slot'); + swapee.attr('slot', er); + swaper.attr('slot', ee); + } + $(this).emit('hawks-moved'); + """ + =type "button" + =hx-swap "none" ;span.loaded ;+ chevron-left:feather-icons == @@ -382,11 +419,22 @@ == == ;button.p1.hover.b2.br1.loader.s-1 - =hx-post "/neo/hawk/{our-tape}/sky?stud=sky-diff" - =hx-target "find .loading" - =hx-swap "outerHTML" - =head "slide-down" - =hawk-slot "{}" + =hx-post "/neo/hawk/{our-tape}/sky?stud=sky-diff&head=slide-down" + =hx-on-htmx-after-request + """ + let swaper = $(this).closest('[slot]'); + let slot = parseInt(swaper.attr('slot').slice(1)); + let swapee = $(this).closest('a-i-r').find(`[slot='s$\{slot+1}']`); + if (swaper.length && swapee.length) \{ + let ee = swapee.attr('slot'); + let er = swaper.attr('slot'); + swapee.attr('slot', er); + swaper.attr('slot', ee); + } + $(this).emit('hawks-moved'); + """ + =hx-swap "none" + =type "button" ;span.loaded ;+ chevron-right:feather-icons == @@ -395,11 +443,17 @@ == == ;button.p1.hover.b2.br1.loader.s-1 - =hx-post "/neo/hawk/{our-tape}/sky?stud=sky-diff" - =hx-target "find .loading" - =hx-swap "outerHTML" - =head "minimize" - =hawk-slot "{}" + =hx-post "/neo/hawk/{our-tape}/sky?stud=sky-diff&head=minimize" + =hx-swap "none" + =type "button" + =hx-on-htmx-after-request + """ + let air = $(this).closest('a-i-r'); + let now = parseInt(air.attr('hawks')) - 1; + air.attr('hawks', now); + $(this).closest('[slot]')[0].removeAttribute('slot'); + $(this).emit('hawks-moved'); + """ ;span.loaded ;+ minimize:feather-icons == diff --git a/pkg/arvo/neo/cod/std/src/imp/sky-eyre-handler.hoon b/pkg/arvo/neo/cod/std/src/imp/sky-eyre-handler.hoon index 0ff5b46139..183d05c343 100644 --- a/pkg/arvo/neo/cod/std/src/imp/sky-eyre-handler.hoon +++ b/pkg/arvo/neo/cod/std/src/imp/sky-eyre-handler.hoon @@ -1,253 +1,62 @@ /@ htmx -/- feather-icons -/* date-now -/* a-i-r -/* feather -/* reset -/* hawk-icon -/* jquery -/* htmx-js -/* htmx-response-targets -/* htmx-idiomorph -=< - ^- kook:neo - |% - ++ state pro/%eyre-task - ++ poke *(set stud:neo) - ++ kids - :+ ~ %y - %- ~(gas by *lads:neo) - ~ - ++ deps - %- ~(gas by *band:neo) - :~ :- %src - ^- fief:neo - :- req=| - ^- quay:neo - :- [pro/%htmx ~] - ^- (unit port:neo) - :+ ~ %y - %- ~(gas by *lads:neo) - :~ :- & - `lash:neo`[any/~ ~] - == - == - :: - ++ form - |_ [=bowl:neo =aeon:neo =pail:neo] - ++ poke - |= [=stud:neo vax=vase] - ^- (quip card:neo pail:neo) - `pail - ++ init - |= pal=(unit pail:neo) - =/ [=stud:neo =vase] (need pal) - =+ !<([eyre-id=@ta req=inbound-request:eyre] vase) - :_ [stud vase] - =/ =pith:neo #/[p/our.bowl]/$/eyre - =; =manx - =/ head=sign:eyre:neo [eyre-id %head [200 [['content-type' 'text/html'] ~]]] - =/ data=sign:eyre:neo [eyre-id %data `(manx-to-octs manx)] - =/ done=sign:eyre:neo [eyre-id %done ~] - :~ [pith %poke eyre-sign/!>(head)] - [pith %poke eyre-sign/!>(data)] - [pith %poke eyre-sign/!>(done)] - [here.bowl %cull ~] - == - ?~ src=(~(get by deps.bowl) %src) - ;div: 404 - =/ root=idea:neo (~(got of:neo q.u.src) /) - ?> =(%htmx p.pail.root) - =/ bol *bowl:neo - =. here.bol p.u.src - =. our.bol our.bowl - =. now.bol now.bowl - =. eny.bol eny.bowl - =. kids.bol q.u.src - :: XX src.bowl - (lift (!<(htmx q.pail.root) bol)) - -- - -- +^- kook:neo |% -++ manx-to-octs - |= man=manx - %- as-octt:mimes:html - %+ welp "" - (en-xml:html man) +++ state pro/%eyre-task +++ poke *(set stud:neo) +++ kids + :+ ~ %y + %- ~(gas by *lads:neo) + ~ +++ deps + %- ~(gas by *band:neo) + :~ :- %src + ^- fief:neo + :- req=| + ^- quay:neo + :- [pro/%htmx ~] + ^- (unit port:neo) + :+ ~ %y + %- ~(gas by *lads:neo) + :~ :- & + `lash:neo`[any/~ ~] + == + == :: -++ icon-url - ^~ - %- trip - %^ cat - 3 - 'data:image/png;base64,' - %- ~(en base64:mimes:html & |) - (as-octs:mimes:html hawk-icon) -++ favicon - ^~ - =; m m(a.g [[%href icon-url] a.g.m]) - ^- manx - ;link - =rel "icon" - =type "image/png" - ; - == -++ manifest-url - ^~ - %- trip - %^ cat - 3 - 'data:application/json;utf-8,' - %- en:json:html - %- pairs:enjs:format - :~ - ['name' s+'sky'] - ['description' s+'an urbit namespace viewer'] - ['start_url' s+'http://localhost/neo/sky'] :: XX - ['display' s+'standalone'] - ['background_color' s+'black'] - :+ 'icons' %a - :~ - %- pairs:enjs:format - :~ - ['src' s+(crip icon-url)] - ['sizes' s+'196x196'] - ['type' s+'image/png'] +++ form + |_ [=bowl:neo =aeon:neo =pail:neo] + ++ poke + |= [=stud:neo vax=vase] + ^- (quip card:neo pail:neo) + `pail + ++ init + |= pal=(unit pail:neo) + =/ [=stud:neo =vase] (need pal) + =+ !<([eyre-id=@ta req=inbound-request:eyre] vase) + :_ [stud vase] + =/ =pith:neo #/[p/our.bowl]/$/eyre + =; =manx + =/ octs + %- as-octt:mimes:html + %+ welp "" + (en-xml:html manx) + =/ head=sign:eyre:neo [eyre-id %head [200 [['content-type' 'text/html'] ~]]] + =/ data=sign:eyre:neo [eyre-id %data `octs] + =/ done=sign:eyre:neo [eyre-id %done ~] + :~ [pith %poke eyre-sign/!>(head)] + [pith %poke eyre-sign/!>(data)] + [pith %poke eyre-sign/!>(done)] + [here.bowl %cull ~] == - == - == -++ manifest - ^~ - =; m m(a.g [[%href manifest-url] a.g.m]) - ^- manx - ;link - =rel "manifest" - ; - == -++ htmx-extensions - :: htmx extension which encodes the request - :: as the serialized HTML of the calling element - %- trip - ''' - htmx.defineExtension('html-enc', { - onEvent: function (name, evt) { - if (name === "htmx:configRequest") { - evt.detail.headers['Content-Type'] = "text/html"; - } - }, - encodeParameters : function(xhr, parameters, elt) { - xhr.overrideMimeType('text/html'); - let xmls = new XMLSerializer(); - return (xmls.serializeToString(elt)); - } - }); - Idiomorph.defaults.ignoreActive = true; - Idiomorph.defaults.callbacks.beforeAttributeUpdated = (name, node, type) => { - if (node.hasAttribute('morph-retain')) { - let ribs = node.getAttribute('morph-retain').split(',').map(t => t.trim()); - if (ribs.includes(name)) { - return false; - } - } - } - Idiomorph.defaults.callbacks.beforeNodeMorphed = (oldNode, newNode) => { - if (oldNode?.nodeName !== "#text") { - if (oldNode.hasAttribute('morph-no-swap') && oldNode.id === newNode.id) { - return false; - } - else if ( - newNode.hasAttribute('morph-if-class') && - !oldNode.classList.contains(newNode.getAttribute('morph-if-class')) - ) { - return false; - } - } - } - ''' -:: -++ lift - |= in=manx - ^- manx - ;html - ;head - ;meta(charset "UTF-8"); - ;title: s k y - ;script: {(trip jquery)} - ;script: {(trip htmx-js)} - ;script: {(trip htmx-response-targets)} - ;script: {(trip htmx-idiomorph)} - ;script: {htmx-extensions} - ;meta - =name "viewport" - =content - """ - width=device-width, - initial-scale=1.0, - maximum-scale=1.0 - """ - ; - == - ;meta - =name "htmx-config" - =content (trip '{"ignoreTitle":"true"}') - ; - == - ::;style - :: ;+ ;/ %- trip - :: ''' - :: @font-face { - :: font-family: 'Urbit Sans'; - :: src: url("https://media.urbit.org/fonts/UrbitSans/UrbitSansVFWeb-Regular.woff2") format("woff2"); - :: font-style: normal; - :: font-weight: 100 700; - :: } - :: ''' - ::== - ;style: {(trip reset)} - ;style: {(trip feather)} - ;script - ;+ ;/ %- trip - ''' - window.log = function() { - if (this.console) { - console.log(Array.prototype.slice.call(arguments)); - } - }; - jQuery.fn.log = function (msg) { - console.log(msg, this); - return this; - }; - jQuery.fn.emit = function (name) { - (this[0]).dispatchEvent( - new Event( - name, - { bubbles: true, cancelable: true, composed: true } - ) - ); - return this; - }; - ''' - == - ;script: {(trip a-i-r)} - ;script: {(trip date-now)} - ;+ favicon - ;+ manifest - == - ;body - =hx-ext "html-enc,response-targets,morph" - =hx-swap "outerHTML" - =hx-boost "true" - =hx-history "false" - =hx-replace-url "/neo/sky" - =hx-target "closest .hawk" - =style - """ - background-color: var(--b1); - background-image: var(--sky-bg-url); - background-size: var(--sky-bg-size); - background-repeat: var(--sky-bg-repeat); - """ - ;+ in - == - == + ?~ src=(~(get by deps.bowl) %src) + ;div: 404 + =/ root=idea:neo (~(got of:neo q.u.src) /) + ?> =(%htmx p.pail.root) + =/ bol *bowl:neo + =. here.bol p.u.src + =. our.bol our.bowl + =. now.bol now.bowl + =. eny.bol eny.bowl + =. kids.bol q.u.src + (!<(htmx q.pail.root) bol) + -- -- diff --git a/pkg/arvo/neo/cod/std/src/imp/sky.hoon b/pkg/arvo/neo/cod/std/src/imp/sky.hoon index d552e29c1c..18e326d1df 100644 --- a/pkg/arvo/neo/cod/std/src/imp/sky.hoon +++ b/pkg/arvo/neo/cod/std/src/imp/sky.hoon @@ -27,9 +27,9 @@ :- ~ =. menu.this menu.poke sky/!>(this) - %new-tab + %new-hawk :- ~ - =. hawks.this [[now.bowl #/[p/our.bowl]/home] hawks.this] + =. hawks.this [[now.poke #/[p/our.bowl]/home] hawks.this] =. open.this (min 4 +(open.this)) sky/!>(this) %move-tab diff --git a/pkg/arvo/neo/cod/std/src/lib/sky-server.hoon b/pkg/arvo/neo/cod/std/src/lib/sky-server.hoon index 0e0b85aa82..bf0bd344e0 100644 --- a/pkg/arvo/neo/cod/std/src/lib/sky-server.hoon +++ b/pkg/arvo/neo/cod/std/src/lib/sky-server.hoon @@ -17,4 +17,14 @@ %+ fall (de-xml:html q:(fall body.request [p=0 q=''])) *manx +++ parse-form-body + |= =request:http + ^- (map @t @t) + =/ body q:(fall body.request [p=0 q='']) + =/ form (cat 3 '?' body) + %- malt + ^- (list [@t @t]) + %+ fall + (rush form yque:de-purl:html) + ~ -- diff --git a/pkg/arvo/neo/cod/std/src/pro/http-request.hoon b/pkg/arvo/neo/cod/std/src/pro/http-request.hoon new file mode 100644 index 0000000000..383a2cb7e3 --- /dev/null +++ b/pkg/arvo/neo/cod/std/src/pro/http-request.hoon @@ -0,0 +1 @@ +,request:http diff --git a/pkg/arvo/neo/cod/std/src/pro/sky-diff.hoon b/pkg/arvo/neo/cod/std/src/pro/sky-diff.hoon index 50692e8207..1f4adaff87 100644 --- a/pkg/arvo/neo/cod/std/src/pro/sky-diff.hoon +++ b/pkg/arvo/neo/cod/std/src/pro/sky-diff.hoon @@ -2,7 +2,7 @@ $% [%theme mode=?(%light %dark) palette=(map @t @t)] [%hawks hawks=(list pith) slots=@] [%menu menu=?] - [%new-tab ~] + [%new-hawk now=@da] [%move-tab slot=@ud =pith] [%minimize slot=@ud] [%maximize slot=@ud]