diff options
Diffstat (limited to 'desk/lib/kaji.hoon')
-rw-r--r-- | desk/lib/kaji.hoon | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/desk/lib/kaji.hoon b/desk/lib/kaji.hoon new file mode 100644 index 0000000..113fd84 --- /dev/null +++ b/desk/lib/kaji.hoon @@ -0,0 +1,379 @@ +/+ sr=sortug +/* kaji-js %js /lib/kaji-min/js +/* kaji-css %css /lib/kaji/css +|% ++$ kbowl + $: src=@p + now=@da + mob=? + == ++$ eyre-order [id=@ta req=inbound-request:eyre] ++$ req-line + $: pat=(pole knot) :: path + ext=(unit @ta) :: extension + par=(map @t @t) :: params + mob=? :: is-mobile + == ++$ form-data [action=@t input=(map @t @t)] +++ enc |= a=* ^- tape (scow:parsing:sr %uw (jam a)) +++ dec |* [a=@t m=mold] ^- (unit m) + =/ hash (slaw:parsing:sr %uw a) + ?~ hash ~ + ((soft m) (cue u.hash)) +++ dec-i |* [i=(map @t @t) key=@t =mold] ^- (unit mold) + =/ val (~(get by i) key) ?~ val ~ + =/ atm (slaw:parsing:sr %uw u.val) ?~ atm ~ + ((soft mold) (cue u.atm)) + + +:: ++ dec-form |* [=form-data d=(list [key=@t =mold])] +:: =| res=* +:: |- +:: ?~ d res +:: =/ val (~(get by in) key.i.d) +:: ?~ val ~ +:: =/ uw (scow %uw u.val) +:: ?~ uw +:: =/ is-t ((sane @t) (crip u.val)) +:: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ +:: it's a @t +:: ${res [res (crip u.val), d t.d] +:: =/ dec-res ((soft mold.i.d) (cue u.uw)) +:: ?~ dec-res ~| "Failed to decode {(trip key.i.d)}" ~ +:: =/ nr [res u.dec-res] +:: $(res nr, d t.d) + +:: =df |* wer=(list [key=@t =mold]) +:: |= in=(map @t @t) +:: ?~ wer ~ +:: :_ ((df t.wer) in) +:: =/ val (~(get by in) key.i.wer) +:: ?~ val ~| "key {(trip key.i.wer)} not found in map" ~ +:: =/ uw (slaw %uw u.val) ?~ uw +:: ~& uw=uw +:: =/ is-t ((sane %t) u.val) +:: ~& is-t=is-t +:: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ +:: u.val +:: =/ dec-res ((soft mold.i.wer) (cue u.uw)) +:: ?~ dec-res ~| "Failed to decode {(trip key.i.wer)}" ~ +:: u.dec-res + +:: =df |* [in=(map @t @t) d=(list [key=@t =mold])] +:: =| res=(unit) +:: |- +:: ~& res=res +:: ?~ d res +:: ~& key=key.i.d +:: =/ val (~(get by in) key.i.d) +:: ~& val=val +:: ?~ val ~ +:: =/ uw (slaw %uw u.val) ?~ uw +:: ~& uw=uw +:: =/ is-t ((sane %t) u.val) +:: ~& is-t=is-t +:: ?. is-t ~| "%kaji.- passed value {u.val} of wrong format" ~ +:: =/ nr ?~ res (some u.val) (some [(need res) u.val]) +:: $(res nr, d t.d) +:: =/ dec-res ((soft mold.i.d) (cue u.uw)) +:: ~& dec-res=dec-res +:: ?~ dec-res ~| "Failed to decode {(trip key.i.d)}" ~ +:: =/ nr ?~ res (some u.dec-res) (some [(need res) u.dec-res]) +:: $(res nr, d t.d) + +:: =m (malt `(list [@t @t])`~[['a' 'alpha'] ['b' (scot %uw (jam [our now]))]]) +:: =d `(list [@t mold])`~[['a' @] ['b' ,[@p @da]]] + + + + ++$ kaji-res +$% [%res eyre-res] + [%sse sse-res] +== ++$ sse-res + $: wire=kaji-wire + e=(list effect) + == ++$ kaji-wire + $% [%tab ~] + [%custom p=(list wire)] + [%all ~] + == ++$ eyre-res + $% [%full p=simple-payload:http] + [%page p=manx] + [%html p=manx] :: fragment + [%mime type=path p=@t] + [%glob p=mime] + == ++$ where + $% [%top ~] + [%bottom ~] + [%before sibling=@t] + == ++$ effect +$% [%redi url=@t] :: redirects; will replace the whole html of the site and update the tab history + [%swap =manx sel=@t inner=?] :: swaps a selector + [%add =manx container=@t =where] :: adds marl to a div + [%focus sel=@t] :: focuses on some selector + [%scroll sel=@t] :: scrolls to some selector + [%url url=@t] :: updates the url bar + [%modal =manx] :: opens a modal + [%alert =manx dur=@ud] :: opens an alert for given duration in ms + [%refresh ~] + [%custom =manx data=json] :: custom, you can set a handle for the 'kaji-fact' event in JS +== ++$ sse-card [%give %fact (list path) [%kaji vase]] + +++ ui-fact +|= [tab=@t res=(list effect)] ^- sse-card +=/ wire /sse/[tab] +[%give %fact ~[wire] [%kaji !>(res)]] + +++ live-fact +|= res=(list effect) ^- sse-card +[%give %fact ~[/ui] [%kaji !>(res)]] + +++ give-fact +|= [wires=(list path) res=(list effect)] ^- sse-card +[%give %fact wires [%kaji !>(res)]] + + +:: sse templates +++ ui + |_ tab-id=@t + ++ fact + |= res=(list effect) (ui-fact tab-id res) + ++ alert + =/ dur 2.000 + |= a=tape + =/ manx ;span:"{a}" + %+ ui-fact tab-id [%alert manx dur]^~ + ++ refresh-card :: wipe browser cache + %+ ui-fact tab-id [%refresh ~]^~ + -- +:: +:: response builders +:: eyre responses +++ error-response +|= code=@ud ^- eyre-res + :- %html (error-page code) +:: inline sse commands + +:: some helpers +:: manx builders +++ wrap-marl +|= m=marl ^- manx +;div + ;* m +== +++ error-page +|= code=@ud + ;html + ;body + ;p:"Error {<code>}" + == + == +++ fetch +|= pat=path +;div(kaji "fetch", src "{(trip (spat pat))}"); + + +++ add-error +|= m=manx ^- manx +=. a.g.m (snoc a.g.m [%kaji-error "true"]) +m +++ hide-manx +|= m=manx ^- manx +=. a.g.m :_ a.g.m [n=%hidden v=""] +m +++ modal +|= children=marl ^- manx +;div#kaji-modal-bg + ;div#kaji-modal-fg + ;* children + == +== +:: + +++ parse-formdata + |= body=(unit octs) ^- (unit (list [key=@t val=@t])) + ?~ body ~ + (rush q.u.body yquy:de-purl:html) + +++ get-redirect + |= redirect=cord + ^- simple-payload:http + [[303 ['location' redirect]~] ~] + +++ doctype "<!DOCTYPE html>" + +++ is-mobile + |= req=inbound-request:eyre ^- ? + =/ headers (malt header-list.request.req) + =/ ua (~(get by headers) 'user-agent') + =/ swidth (~(get by headers) 'x-kaji-vw') + ?~ ua ?~ swidth .n + =/ width (rush u.swidth dem) ?~ width .n + (lte u.width 800) + + ?| (cfind:sr 'android' u.ua .n) + (cfind:sr 'iphone' u.ua .n) + :: (cfind:sr 'ipad' u.ua .n) + == + +:: core functionality ++$ request-line-s + $: [ext=(unit @ta) site=(list @t)] + args=(list [key=@t value=@t]) + == +++ parse-req +|= req=inbound-request:eyre ^- req-line + =/ rl=(unit request-line-s) (rush url.request.req ;~(plug apat:de-purl:html yque:de-purl:html)) + ?~ rl + ~& >>> url-parsing-failed=url.request.req + !! + =/ is-mob (is-mobile req) + [path=site.u.rl ext.u.rl (malt args.u.rl) is-mob] + +++ manx-to-cord + |= [is-fragment=? =manx] ^- @t + %- crip + ?. is-fragment + %- en-xml:html manx + :: + %+ weld doctype + %- en-xml:html manx + +++ send-eyre-res + |= [eyre-id=@ta =simple-payload:http] + ^- (list card:agent:gall) + =/ header-cage + [%http-response-header !>(response-header.simple-payload)] + =/ data-cage + [%http-response-data !>(data.simple-payload)] + :~ [%give %fact ~[/http-response/[eyre-id]] header-cage] + [%give %fact ~[/http-response/[eyre-id]] data-cage] + [%give %kick ~[/http-response/[eyre-id]] ~] + == + +++ glob-payload + =| cache=_| + |= =mime ^- simple-payload:http + =/ content-type (rsh 3 (crip <p.mime>)) + =/ cache-header ?: cache + ['cache-control' 'max-age=86400'] + ['cache-control' 'no-cache, no-store, must-revalidate'] + :: ~& >>> ends-in=`@t`(swp 3 (end [3 5] (swp 3 q.q.mime))) + :_ `q.mime + [200 [['content-type' content-type] cache-header ~]] + +++ http-payload + =| cache=_| + |= [mime-type=path t=@t] ^- simple-payload:http + =/ content-type (rsh 3 (crip <mime-type>)) + =/ octs (as-octs:mimes:html t) + =/ cache-header ?: cache + ['cache-control' 'max-age=86400'] + ['cache-control' 'no-cache, no-store, must-revalidate'] + :_ `octs + [200 [['content-type' content-type] cache-header ~]] +:: +++ js +|% + ++ collapsible ^~ %- trip + ''' + function createCollapsible(el){ + console.log("creating collapsible") + const targetID = el.getAttribute("target"); + const targetEl = document.getElementById(targetID); + targetEl.classList.toggle("hide"); + let show = false; + el.addEventListener('click', () => { + console.log(show, "clicked on toggle") + console.log(targetID) + console.log(targetEl) + show = !show; + // el.classList.toggle("") TODO would need to toggle the button itself + targetEl.classList.toggle("not-hide") + targetEl.classList.toggle("hide") + }) + } + document.querySelectorAll(".toggle").forEach(createCollapsible) + console.log(document.querySelectorAll(".toggle")) + ''' +-- +++ payload-bail ^- simple-payload:http +%+ http-payload /text/plain 'Error' + +++ init +|* [=bowl:gall app-state=mold kaji-req=mold] +|% + +$ request + $% [%eyre p=eyre-order] + [%kaji tab=@t req=kaji-req] + == + +$ router $-([request bowl:gall app-state] kaji-res) + ++ route + |= [=router r=request state=app-state] + |^ ^- (list card:agent:gall) + ?- -.r + %eyre + =/ =req-line (parse-req req.p.r) + %+ send-eyre-res id.p.r + ?+ [pat ext]:req-line + :: default case + =/ resp (router r bowl state) + ?. ?=(%res -.resp) payload-bail + ?- +<.resp + %full p.resp + %page (http-payload /text/html (manx-to-cord .n (inject-head p.resp))) + %html (http-payload /text/html (manx-to-cord .y p.resp)) + %mime (http-payload type.resp p.resp) + %glob (glob-payload p.resp) + == + [[%session ~] [~ %js]] (http-payload /text/javascript docket-session-js) + [[%kaji-session ~] [~ %js]] (http-payload /text/javascript session-js) + [[%kaji ~] [~ %js]] (http-payload /text/javascript kaji-js) + [[%kaji ~] [~ %css]] (http-payload /text/css kaji-css) + + == + %kaji + =/ resp (router r bowl state) + ?. ?=(%sse -.resp) ~ :_ ~ + ?- -.wire.resp + %all (live-fact e.resp) + %tab (ui-fact tab.r e.resp) + %custom (give-fact p.wire.resp e.resp) + == + == + ++ inject-head + |= m=manx ^- manx + =/ sip (scow %p src.bowl) + =/ dap (trip dap.bowl) + =/ tags=marl :~ + ;link/"/kaji.css"(rel "stylesheet"); + ;script@"/kaji.js"; + ;script@"/kaji-session.js?ship={sip}&dap={dap}"; + == + |- + ?~ c.m m + ?: .=(%head n.g.i.c.m) + =. c.i.c.m (weld c.i.c.m tags) m + $(c.m t.c.m) + ++ docket-session-js ^~ + (rap 3 'window.ship = "' (rsh 3 (scot %p our.bowl)) '";' ~) + + ++ session-js ^~ %- crip + =/ ship (scow %p our.bowl) + =/ app (trip dap.bowl) + =/ live-ui "/ui" + """ + window.ship = '{ship}' + window.app = '{app}' + window.liveUI = '{live-ui}'; + """ + -- +-- +-- |