Commit 56ef59b8 authored by Isaac Shapira's avatar Isaac Shapira
Browse files

New Website

parent 8b50b053
......@@ -8,3 +8,9 @@ client
roster.db
.vscode
*.tar.gz
*/docs/**/*.html
tags
/website/favicon.html
/website/assets/landing_logo.svg
.cache
stress*
......@@ -86,36 +86,37 @@ Dev Shell GHC 8.6.5 on Linux:
needs:
- Packages GHC 8.6.5 on Linux
script:
- nix-shell --run "echo works" --argstr compiler ghc865 --fallback
- nix-shell --run "echo works" --arg enableLibraryProfiling false --fallback
Dev Shell GHCJS 8.6 on Linux:
stage: Linux Shell
needs:
- Packages GHCJS 8.6 on Linux
script:
- nix-shell --run "echo works" --argstr compiler ghc865 --arg isJS true --fallback
- nix-shell --run "echo works" --arg enableLibraryProfiling false --arg isJS true --fallback
Dev Shell GHC 8.6.5 on Darwin:
stage: Darwin Shell
needs:
- Packages GHC 8.6.5 on Darwin
script:
- nix-build --run "echo works" --argstr compiler ghc865 --argstr system x86_64-darwin --fallback
- nix-build --run "echo works" --arg enableLibraryProfiling false --argstr system x86_64-darwin --fallback
Dev Shell GHCJS 8.6 on Darwin:
stage: Darwin Shell
needs:
- Packages GHCJS 8.6 on Darwin
script:
- nix-shell --run "echo works" --argstr compiler ghc865 --argstr system x86_64-darwin --arg isJS true --fallback
- nix-shell --run "echo works" --arg enableLibraryProfiling false --argstr system x86_64-darwin --arg isJS true --fallback
Antora:
Website:
stage: Documentation
needs:
- Check Style
- Hlint
- Packages GHCJS 8.6 on Linux
- Packages GHC 8.6.5 on Linux
script:
- nix-build docs --fallback
- nix-build website --arg ci true --fallback
Isreal:
stage: Push Artifacts
......@@ -133,7 +134,7 @@ Isreal:
pages:
stage: Push Artifacts
needs:
- Antora
- Website
- Packages GHCJS 8.6 on Linux
script:
- ./nix/build-pages.sh
......@@ -142,7 +143,6 @@ pages:
- public
only:
- master
- docs
Upload to Cachix:
stage: Push Artifacts
......
......@@ -6,7 +6,6 @@ image::docs/modules/ROOT/assets/images/logo.png[Eddie is loved forever,150,150]
https://gitlab.com/platonic/shpadoinkle/commits/master[image:https://gitlab.com/platonic/shpadoinkle/badges/master/pipeline.svg[pipeline
status]]
https://shpadoinkle.zulipchat.com/register[image:https://img.shields.io/badge/zulip-join_chat-orange.svg[Community]]
https://opensource.org/licenses/BSD-3-Clause[image:https://img.shields.io/badge/License-BSD%203--Clause-blue.svg[BSD-3]]
https://builtwithnix.org[image:https://img.shields.io/badge/built%20with-nix-41439a[built
with nix]]
https://shpadoinkle.cachix.org[image:https://img.shields.io/badge/Cachix-up%20to%20date-green[cachix]]
......@@ -15,7 +14,7 @@ https://hoogle.shpadoinkle.org[image:https://img.shields.io/badge/-Hoogle-lightg
= Shpadoinkle
https://www.youtube.com/watch?v=0CizU8aB3c8[Shpadoinkle] is a Haskell UI programming paradigm.
https://www.youtube.com/watch?v=0CizU8aB3c8[Shpadoinkle] is a new Functional UI programming paradigm.
== Documentation
......@@ -24,15 +23,9 @@ https://www.youtube.com/watch?v=0CizU8aB3c8[Shpadoinkle] is a Haskell UI program
* https://shpadoinkle.org/docs/tutorial/index.html[Tutorial]
* https://shpadoinkle.org/docs/packages/index.html[Packages]
=== Contribute to Documentation
Help is always appreciated on documentation. Haddocks and READMEs work using standard tooling. If you wish to contribute to the Antora Documentation, simply:
== Community
[source,bash]
----
$ nix-shell docs
$ serve-docs
----
Join the Shpadoinkle community on https://shpadoinkle.zulipchat.com/register[Zulip]!
== Snowman
......@@ -57,116 +50,7 @@ $ nix-shell nix/lint.nix --run 'hlint .'
Correct version of hlint is also available within `nix-shell`.
== Community
Join the Shpadoinkle community on https://shpadoinkle.zulipchat.com/register[Zulip]!
== Actively Maintained
This project is actively maintained by https://platonic.systems[image:https://platonic.systems/logo.svg[Platonic Systems, 25,25] Platonic Systems]
== Hackage Matrix
[options="header"]
|===
|Package |Version |Dependencies |Availablity
|Core
|https://hackage.haskell.org/package/Shpadoinkle[image:https://img.shields.io/hackage/v/Shpadoinkle.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle[image:https://img.shields.io/hackage-deps/v/Shpadoinkle.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle/badge[Hackage
CI]]
|Snabbdom
|https://hackage.haskell.org/package/Shpadoinkle-backend-snabbdom[image:https://img.shields.io/hackage/v/Shpadoinkle-backend-snabbdom.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-backend-snabbdom[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-backend-snabbdom.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-backend-snabbdom[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-backend-snabbdom/badge[Hackage
CI]]
|Static
|https://hackage.haskell.org/package/Shpadoinkle-backend-static[image:https://img.shields.io/hackage/v/Shpadoinkle-backend-static.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-backend-static[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-backend-static.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-backend-static[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-backend-static/badge[Hackage
CI]]
|ParDiff
|https://hackage.haskell.org/package/Shpadoinkle-backend-pardiff[image:https://img.shields.io/hackage/v/Shpadoinkle-backend-pardiff.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-backend-pardiff[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-backend-pardiff.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-backend-pardiff[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-backend-pardiff/badge[Hackage
CI]]
|Console
|https://hackage.haskell.org/package/Shpadoinkle-console[image:https://img.shields.io/hackage/v/Shpadoinkle-console.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-console[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-console.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-console[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-console/badge[Hackage
CI]]
|Developer Tools
|https://hackage.haskell.org/package/Shpadoinkle-developer-tools[image:https://img.shields.io/hackage/v/Shpadoinkle-developer-tools.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-developer-tools[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-developer-tools.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-developer-tools[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-developer-tools/badge[Hackage
CI]]
|Disembodied
|https://hackage.haskell.org/package/Shpadoinkle-disembodied[image:https://img.shields.io/hackage/v/Shpadoinkle-disembodied.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-disembodied[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-disembodied.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-Shpadoinkle-disembodied[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-disembodied/badge[Hackage
CI]]
|Lens
|https://hackage.haskell.org/package/Shpadoinkle-lens[image:https://img.shields.io/hackage/v/Shpadoinkle-lens.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-lens[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-lens.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-lens[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-lens/badge[Hackage
CI]]
|Html
|https://hackage.haskell.org/package/Shpadoinkle-html[image:https://img.shields.io/hackage/v/Shpadoinkle-html.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-html[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-html.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-html[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-html/badge[Hackage
CI]]
|Router
|https://hackage.haskell.org/package/Shpadoinkle-router[image:https://img.shields.io/hackage/v/Shpadoinkle-router.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-router[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-router.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-router[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-router/badge[Hackage
CI]]
|Streaming
|https://hackage.haskell.org/package/Shpadoinkle-streaming[image:https://img.shields.io/hackage/v/Shpadoinkle-streaming.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-streaming[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-streaming.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-streaming[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-streaming/badge[Hackage
CI]]
|Template
|https://hackage.haskell.org/package/Shpadoinkle-template[image:https://img.shields.io/hackage/v/Shpadoinkle-template.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-template[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-template.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-template[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-template/badge[Hackage
CI]]
|Widgets
|https://hackage.haskell.org/package/Shpadoinkle-widgets[image:https://img.shields.io/hackage/v/Shpadoinkle-widgets.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-widgets[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-widgets.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-widgets[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-widgets/badge[Hackage
CI]]
|Examples
|https://hackage.haskell.org/package/Shpadoinkle-examples[image:https://img.shields.io/hackage/v/Shpadoinkle-examples.svg[Hackage]]
|http://packdeps.haskellers.com/feed?needle=Shpadoinkle-examples[image:https://img.shields.io/hackage-deps/v/Shpadoinkle-examples.svg[Hackage
Deps]]
|https://matrix.hackage.haskell.org/#/package/Shpadoinkle-examples[image:https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-examples/badge[Hackage
CI]]
|===
......@@ -363,6 +363,8 @@ patch' parent old new = do
return new
{-# SPECIALIZE interpret' :: forall a. NFData a => (JSM ~> JSM) -> Html (ParDiffT a JSM) a -> ParDiffT a JSM (ParVNode a) #-}
interpret'
:: forall m a
. MonadJSM m
......
......@@ -20,13 +20,13 @@ In order to re-build `Shpadoinkle/Backend/Snabbdom/Setup.js`, it needs to be bun
```bash
# clone outside the source directory of Shpadoinkl
git clone git@gituhub.com:snabbdom/snabbdom.git
git clone git@github.com:snabbdom/snabbdom.git
# compile its typescript so we can bundle the javascript
cd snabbdom && npm install && npm run compile
# Setup_src.js imports the snabbdom sources locally, so we need to manually move it
cp path-to-shpadoinkle/backends/snabbdom/Shpadoinkle/Backend/Snabbdom/Setup_src.js build/package/
# nix is most reliable for running parcel
nix-shell -p nodePackages.parcel-bundler --command "parcel build Setup_src.js"
nix-shell -p nodePackages.parcel-bundler --command "parcel build build/package/Setup_src.js"
# copy the bundled output as Setup.js
cp dist/Setup_src.js path-to-shpadoinkle/backends/snabbdom/Shpadoinkle/Backend/Snabbdom/Setup.js
```
......
......@@ -47,7 +47,7 @@ import Control.Monad.Trans.Control (ComposeSt, MonadBaseControl (..),
import Control.Monad.Writer (MonadWriter)
import Data.FileEmbed (embedStringFile)
import Data.Map.Internal (Map (Bin, Tip))
import Data.Text (Text, words)
import Data.Text (Text, isPrefixOf, words)
import GHCJS.DOM (currentDocumentUnchecked)
import GHCJS.DOM.Document (createElement, getBodyUnsafe)
import GHCJS.DOM.Element (setAttribute, setInnerHTML)
......@@ -137,8 +137,10 @@ traverseWithKey_ f = go
go (Bin 1 k v _ _) = f k v
go (Bin _ k v l r) = go l *> f k v *> go r
{-# INLINE traverseWithKey_ #-}
{-# SPECIALIZE traverseWithKey_ :: (k -> a -> JSM ()) -> Map k a -> JSM () #-}
{-# SPECIALIZE props :: NFData a => (JSM ~> JSM) -> TVar a -> Props (SnabbdomT a JSM) a -> JSM Object #-}
props :: Monad m => NFData a => (m ~> JSM) -> TVar a -> Props (SnabbdomT a m) a -> JSM Object
props toJSM i (Props xs) = do
o <- create
......@@ -163,20 +165,20 @@ props toJSM i (Props xs) = do
[vnode] -> g vnode
[_, vnode] -> g vnode
_ -> return ()
unsafeSetProp "insert" f' hooksObj
unsafeSetProp "update" f' hooksObj
void $ jsg3 "insertHook" "insert" f' hooksObj
void $ jsg3 "insertHook" "update" f' hooksObj
PText t
| k == "className" -> forM_ (words t) $ \u ->
unsafeSetProp (toJSString u) jsTrue classesObj
| t /= "" -> do
t' <- valMakeText t
unsafeSetProp k' t' $ case k of
"style" -> attrsObj
"type" -> attrsObj
"autofocus" -> attrsObj
"checked" -> attrsObj
_ -> propsObj
"style" -> attrsObj
"type" -> attrsObj
"autofocus" -> attrsObj
"checked" -> attrsObj
d | "data-" `isPrefixOf` d -> attrsObj
_ -> propsObj
| otherwise -> do
t' <- valMakeText t
unsafeSetProp k' t' propsObj
......@@ -256,4 +258,5 @@ stage = liftJSM $ do
setInnerHTML b ""
_ <- appendChild b elm
RawNode <$> toJSVal elm
{-# SPECIALIZE stage :: SnabbdomT a JSM RawNode #-}
......@@ -2,7 +2,9 @@ parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcel
"use strict";function e(e,t,o,r,d){return{sel:e,data:t,children:o,text:r,elm:d,key:void 0===t?void 0:t.key}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.vnode=e;
},{}],"BfzD":[function(require,module,exports) {
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.primitive=e,exports.array=void 0;var r=Array.isArray;function e(r){return"string"==typeof r||"number"==typeof r}exports.array=r;
},{}],"B5vY":[function(require,module,exports) {
},{}],"VeuO":[function(require,module,exports) {
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.h=o;var e=require("./vnode.js"),r=i(require("./is.js"));function t(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return t=function(){return e},e}function i(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var r=t();if(r&&r.has(e))return r.get(e);var i={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var u=n?Object.getOwnPropertyDescriptor(e,o):null;u&&(u.get||u.set)?Object.defineProperty(i,o,u):i[o]=e[o]}return i.default=e,r&&r.set(e,i),i}function n(e,r,t){if(e.ns="http://www.w3.org/2000/svg","foreignObject"!==t&&void 0!==r)for(var i=0;i<r.length;++i){var o=r[i].data;void 0!==o&&n(o,r[i].children,r[i].sel)}}function o(t,i,o){var u,v,f,a={};if(void 0!==o?(null!==i&&(a=i),r.array(o)?u=o:r.primitive(o)?v=o:o&&o.sel&&(u=[o])):null!=i&&(r.array(i)?u=i:r.primitive(i)?v=i:i&&i.sel?u=[i]:a=i),void 0!==u)for(f=0;f<u.length;++f)r.primitive(u[f])&&(u[f]=(0,e.vnode)(void 0,void 0,void 0,u[f],void 0));return"s"!==t[0]||"v"!==t[1]||"g"!==t[2]||3!==t.length&&"."!==t[3]&&"#"!==t[3]||n(a,u,t),(0,e.vnode)(t,a,u,v,void 0)}
},{"./vnode.js":"RM4J","./is.js":"BfzD"}],"B5vY":[function(require,module,exports) {
"use strict";function e(e,t){return document.createElement(e,t)}function t(e,t,n){return document.createElementNS(e,t,n)}function n(e){return document.createTextNode(e)}function o(e){return document.createComment(e)}function r(e,t,n){e.insertBefore(t,n)}function i(e,t){e.removeChild(t)}function u(e,t){e.appendChild(t)}function c(e){return e.parentNode}function m(e){return e.nextSibling}function d(e){return e.tagName}function a(e,t){e.textContent=t}function f(e){return e.textContent}function l(e){return 1===e.nodeType}function p(e){return 3===e.nodeType}function s(e){return 8===e.nodeType}Object.defineProperty(exports,"__esModule",{value:!0}),exports.htmlDomApi=void 0;var x={createElement:e,createElementNS:t,createTextNode:n,createComment:o,insertBefore:r,removeChild:i,appendChild:u,parentNode:c,nextSibling:m,tagName:d,setTextContent:a,getTextContent:f,isElement:l,isText:p,isComment:s};exports.htmlDomApi=x;
},{}],"FyzG":[function(require,module,exports) {
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.init=s;var e=require("./vnode.js"),t=l(require("./is.js")),r=require("./htmldomapi.js");function n(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return n=function(){return e},e}function l(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=n();if(t&&t.has(e))return t.get(e);var r={},l=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=l?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}return r.default=e,t&&t.set(e,r),r}function o(e){return void 0===e}function i(e){return void 0!==e}var a=(0,e.vnode)("",{},[],void 0,void 0);function d(e,t){var r,n,l=e.key===t.key,o=(null===(r=e.data)||void 0===r?void 0:r.is)===(null===(n=t.data)||void 0===n?void 0:n.is);return e.sel===t.sel&&l&&o}function v(e){return void 0!==e.sel}function u(e,t,r){for(var n,l={},o=t;o<=r;++o){var i=null===(n=e[o])||void 0===n?void 0:n.key;void 0!==i&&(l[i]=o)}return l}var f=["create","update","remove","destroy","pre","post"];function s(n,l){var s,c,p={create:[],update:[],remove:[],destroy:[],pre:[],post:[]},h=void 0!==l?l:r.htmlDomApi;for(s=0;s<f.length;++s)for(p[f[s]]=[],c=0;c<n.length;++c){var m=n[c][f[s]];void 0!==m&&p[f[s]].push(m)}function g(e,t){return function(){if(0==--t){var r=h.parentNode(e);h.removeChild(r,e)}}}function x(e,r){var n,l,d,v=e.data;if(void 0!==v){var u=null===(n=v.hook)||void 0===n?void 0:n.init;i(u)&&(u(e),v=e.data)}var f=e.children,s=e.sel;if("!"===s)o(e.text)&&(e.text=""),e.elm=h.createComment(e.text);else if(void 0!==s){var c=s.indexOf("#"),m=s.indexOf(".",c),g=c>0?c:s.length,y=m>0?m:s.length,k=-1!==c||-1!==m?s.slice(0,Math.min(g,y)):s,b=e.elm=i(v)&&i(d=v.ns)?h.createElementNS(d,k,v):h.createElement(k,v);for(g<y&&b.setAttribute("id",s.slice(g+1,y)),m>0&&b.setAttribute("class",s.slice(y+1).replace(/\./g," ")),d=0;d<p.create.length;++d)p.create[d](a,e);if(t.array(f))for(d=0;d<f.length;++d){var j=f[d];null!=j&&h.appendChild(b,x(j,r))}else t.primitive(e.text)&&h.appendChild(b,h.createTextNode(e.text));var O=e.data.hook;i(O)&&(null===(l=O.create)||void 0===l||l.call(O,a,e),O.insert&&r.push(e))}else e.elm=h.createTextNode(e.text);return e.elm}function y(e,t,r,n,l,o){for(;n<=l;++n){var i=r[n];null!=i&&h.insertBefore(e,x(i,o),t)}}function k(e){var t,r,n=e.data;if(void 0!==n){null===(r=null===(t=null==n?void 0:n.hook)||void 0===t?void 0:t.destroy)||void 0===r||r.call(t,e);for(var l=0;l<p.destroy.length;++l)p.destroy[l](e);if(void 0!==e.children)for(var o=0;o<e.children.length;++o){var i=e.children[o];null!=i&&"string"!=typeof i&&k(i)}}}function b(e,t,r,n){for(var l,o;r<=n;++r){var a=void 0,d=void 0,v=t[r];if(null!=v)if(i(v.sel)){k(v),a=p.remove.length+1,d=g(v.elm,a);for(var u=0;u<p.remove.length;++u)p.remove[u](v,d);var f=null===(o=null===(l=null==v?void 0:v.data)||void 0===l?void 0:l.hook)||void 0===o?void 0:o.remove;i(f)?f(v,d):d()}else h.removeChild(e,v.elm)}}function j(e,t,r){var n,l,a,v,f,s=null===(n=t.data)||void 0===n?void 0:n.hook;null===(l=null==s?void 0:s.prepatch)||void 0===l||l.call(s,e,t);var c=t.elm=e.elm,m=e.children,g=t.children;if(e!==t){if(void 0!==t.data){for(var k=0;k<p.update.length;++k)p.update[k](e,t);null===(v=null===(a=t.data.hook)||void 0===a?void 0:a.update)||void 0===v||v.call(a,e,t)}o(t.text)?i(m)&&i(g)?m!==g&&function(e,t,r,n){for(var l,i,a,v=0,f=0,s=t.length-1,c=t[0],p=t[s],m=r.length-1,g=r[0],k=r[m];v<=s&&f<=m;)null==c?c=t[++v]:null==p?p=t[--s]:null==g?g=r[++f]:null==k?k=r[--m]:d(c,g)?(j(c,g,n),c=t[++v],g=r[++f]):d(p,k)?(j(p,k,n),p=t[--s],k=r[--m]):d(c,k)?(j(c,k,n),h.insertBefore(e,c.elm,h.nextSibling(p.elm)),c=t[++v],k=r[--m]):d(p,g)?(j(p,g,n),h.insertBefore(e,p.elm,c.elm),p=t[--s],g=r[++f]):(void 0===l&&(l=u(t,v,s)),o(i=l[g.key])?h.insertBefore(e,x(g,n),c.elm):(a=t[i]).sel!==g.sel?h.insertBefore(e,x(g,n),c.elm):(j(a,g,n),t[i]=void 0,h.insertBefore(e,a.elm,c.elm)),g=r[++f]);(v<=s||f<=m)&&(v>s?y(e,null==r[m+1]?null:r[m+1].elm,r,f,m,n):b(e,t,v,s))}(c,m,g,r):i(g)?(i(e.text)&&h.setTextContent(c,""),y(c,null,g,0,g.length-1,r)):i(m)?b(c,m,0,m.length-1):i(e.text)&&h.setTextContent(c,""):e.text!==t.text&&(i(m)&&b(c,m,0,m.length-1),h.setTextContent(c,t.text)),null===(f=null==s?void 0:s.postpatch)||void 0===f||f.call(s,e,t)}}return function(t,r){var n,l,o,i=[];for(n=0;n<p.pre.length;++n)p.pre[n]();for(v(t)||(t=function(t){var r=t.id?"#"+t.id:"",n=t.className?"."+t.className.split(" ").join("."):"";return(0,e.vnode)(h.tagName(t).toLowerCase()+r+n,{},[],void 0,t)}(t)),d(t,r)?j(t,r,i):(l=t.elm,o=h.parentNode(l),x(r,i),null!==o&&(h.insertBefore(o,r.elm,h.nextSibling(l)),b(o,[t],0,0))),n=0;n<i.length;++n)i[n].data.hook.insert(i[n]);for(n=0;n<p.post.length;++n)p.post[n]();return r}}
......@@ -14,9 +16,7 @@ parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcel
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.attributesModule=void 0;var t="http://www.w3.org/1999/xlink",e="http://www.w3.org/XML/1998/namespace",r=58,a=120;function i(i,o){var s,u=o.elm,d=i.data.attrs,b=o.data.attrs;if((d||b)&&d!==b){for(s in d=d||{},b=b||{}){var A=b[s];d[s]!==A&&(!0===A?u.setAttribute(s,""):!1===A?u.removeAttribute(s):s.charCodeAt(0)!==a?u.setAttribute(s,A):s.charCodeAt(3)===r?u.setAttributeNS(e,s,A):s.charCodeAt(5)===r?u.setAttributeNS(t,s,A):u.setAttribute(s,A))}for(s in d)s in b||u.removeAttribute(s)}}var o={create:i,update:i};exports.attributesModule=o;
},{}],"HAvm":[function(require,module,exports) {
"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(t)}function t(n,o,r){if("function"==typeof n)n.call(o,r,o);else if("object"===e(n))for(var i=0;i<n.length;i++)t(n[i],o,r)}function n(e,n){var o=e.type,r=n.data.on;r&&r[o]&&t(r[o],n,e)}function o(){return function e(t){n(t,e.vnode)}}function r(e,t){var n,r=e.data.on,i=e.listener,f=e.elm,s=t&&t.data.on,l=t&&t.elm;if(r!==s){if(r&&i)if(s)for(n in r)s[n]||f.removeEventListener(n,i,!1);else for(n in r)f.removeEventListener(n,i,!1);if(s){var u=t.listener=e.listener||o();if(u.vnode=t,r)for(n in s)r[n]||l.addEventListener(n,u,!1);else for(n in s)l.addEventListener(n,u,!1)}}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.eventListenersModule=void 0;var i={create:r,update:r,destroy:r};exports.eventListenersModule=i;
},{}],"VeuO":[function(require,module,exports) {
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.h=o;var e=require("./vnode.js"),r=i(require("./is.js"));function t(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return t=function(){return e},e}function i(e){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var r=t();if(r&&r.has(e))return r.get(e);var i={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var u=n?Object.getOwnPropertyDescriptor(e,o):null;u&&(u.get||u.set)?Object.defineProperty(i,o,u):i[o]=e[o]}return i.default=e,r&&r.set(e,i),i}function n(e,r,t){if(e.ns="http://www.w3.org/2000/svg","foreignObject"!==t&&void 0!==r)for(var i=0;i<r.length;++i){var o=r[i].data;void 0!==o&&n(o,r[i].children,r[i].sel)}}function o(t,i,o){var u,v,f,a={};if(void 0!==o?(null!==i&&(a=i),r.array(o)?u=o:r.primitive(o)?v=o:o&&o.sel&&(u=[o])):null!=i&&(r.array(i)?u=i:r.primitive(i)?v=i:i&&i.sel?u=[i]:a=i),void 0!==u)for(f=0;f<u.length;++f)r.primitive(u[f])&&(u[f]=(0,e.vnode)(void 0,void 0,void 0,u[f],void 0));return"s"!==t[0]||"v"!==t[1]||"g"!==t[2]||3!==t.length&&"."!==t[3]&&"#"!==t[3]||n(a,u,t),(0,e.vnode)(t,a,u,v,void 0)}
},{"./vnode.js":"RM4J","./is.js":"BfzD"}],"SL7Z":[function(require,module,exports) {
"use strict";var e=require("./init"),r=require("./modules/class"),t=require("./modules/props"),i=require("./modules/attributes"),u=require("./modules/eventlisteners"),n=require("./h");window.startApp=function(o){var s=(0,e.init)([r.classModule,t.propsModule,u.eventListenersModule,i.attributesModule]);window.patchh=function(e,r){return s(e,r)},window.vnode=n.h,window.potato=function(e,r){return e.elm.appendChild(r)},o()};
},{"./init":"FyzG","./modules/class":"C4g2","./modules/props":"FnDi","./modules/attributes":"QBBp","./modules/eventlisteners":"HAvm","./h":"VeuO"}]},{},["SL7Z"], null)
//# sourceMappingURL=/Setup.js.map
\ No newline at end of file
},{}],"gtJM":[function(require,module,exports) {
"use strict";var e=require("./h.js"),r=require("./init.js"),i=require("./modules/class.js"),t=require("./modules/props.js"),n=require("./modules/attributes.js"),s=require("./modules/eventlisteners.js");window.startApp=function(o){var u=(0,r.init)([t.propsModule,i.classModule,n.attributesModule,s.eventListenersModule]);window.patchh=function(e,r){return u(e,r)},window.vnode=e.h,window.potato=function(e,r){return e.elm.appendChild(r)},window.insertHook=function(e,r,i){var t=i[e];i[e]=function(e){t&&t(e),r(e)}},o()};
},{"./h.js":"VeuO","./init.js":"FyzG","./modules/class.js":"C4g2","./modules/props.js":"FnDi","./modules/attributes.js":"QBBp","./modules/eventlisteners.js":"HAvm"}]},{},["gtJM"], null)
//# sourceMappingURL=/Setup_src.js.map
\ No newline at end of file
......@@ -15,6 +15,14 @@ window.startApp = cb => {
]);
window.patchh = (a,b) => patch(a,b);
window.vnode = h;
window.potato = (n, e) => n.elm.appendChild(e);
window.potato = (n,e) => n.elm.appendChild(e);
window.insertHook = (k,f,o) => {
const p = o[k]
o[k] = (vnode) => {
if(p){ p(vnode); }
f(vnode);
}
};
cb();
};
......@@ -7,6 +7,7 @@ packages: core
, developer-tools
, disembodied
, lens
, website
, html
, router
, streaming
......@@ -17,4 +18,4 @@ packages: core
, isreal
tests: true
tests: True
......@@ -8,28 +8,4 @@
[![Hackage Deps](https://img.shields.io/hackage-deps/v/Shpadoinkle-console.svg)](http://packdeps.haskellers.com/reverse/Shpadoinkle-console)
[![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle-console/badge)](https://matrix.hackage.haskell.org/#/package/Shpadoinkle-console)
This package exposes some useful debugging functions for tracing the state of Shpadoinkle applications as they change over time. It exposes some type classes currently.
```haskell
class LogJS (c :: Type -> Constraint) where
logJS :: c a => a -> JSM ()
class LogJS c => Trapper c where
trapper :: c a => JSContextRef -> a -> a
class Assert (c :: Type -> Constraint) where
assert :: c a => Bool -> a -> JSM ()
```
These are intended to by used with `TypeApplications`, so you can choose the means of conversion before passing to `console.log`. For example:
```haskell
main :: IO ()
main = runJSorWarp 8080 $ do
ctx <- askJSM
simple runParDiff initial (view . trapper @ToJSON ctx) getBody
```
This will log all state by first encoding to JSON with Aeson, then then logging with `JSON.parse` so the browser console has the nice native display. If we change it to `trapper @Show ctx` it will use the `Show` instance instead.
We also export a handful of `console` bindings such as `console.time`, `console.table`, `console.info`, `console.warn`, `console.debug`, and of course `console.log`.
## [Documentation ->](https://shpadoinkle.org/package/console)
......@@ -8,186 +8,4 @@
[![Hackage Deps](https://img.shields.io/hackage-deps/v/Shpadoinkle.svg)](http://packdeps.haskellers.com/reverse/Shpadoinkle)
[![Hackage CI](https://matrix.hackage.haskell.org/api/v2/packages/Shpadoinkle/badge)](https://matrix.hackage.haskell.org/#/package/Shpadoinkle)
Shpadoinkle is a Haskell UI programming paradigm.
## The core concept
Is to model the user interface as a pure function from some model `a` to Html.
This is not a new idea in the slightest. Declaratively describing the view in terms
of the model through a data structure is the dominant approach in UI today. And
for good reason.
If all we need is to render something based on some `a` we can have `Html` be a
simple data structure where `Html :: Type`:
```haskell
view :: a -> Html
```
This might look something like:
```haskell
view :: Text -> Html
view username =
H "div" [ ("class", "greeting") ] [ Text $ "Hi there!" <> username ]
```
## Events and effects
Which is all well and good, and something we might expect from a static renderer,
like Heist, or Blaze. Shpadoinkle handles this by allowing for `Html` to have two
type variables associated with events, `Html :: (Type -> Type) -> Type -> Type`.
The first is typically some Monad you want to use in response to events `m`, and
the second is the payload of those events, typically the model for your view `a`.
These variables in `Html m a` are strickly about event listeners, so any view
that doesn't have event listeners should be parametic in both `m` and `a`.
look at a toggle as an example:
```haskell
toggle :: Applicative m => Bool -> Html m Bool
toggle b = h "div" []
[ text $ "Currently it's " <> if b then "ON" else "OFF"
, h "button" [ listen "click" (not b) ] [ text "Toggle" ]
]
```
That's it, we have a stateful view. When the user click's on
the "Toggle" button the state will switch. Because we do a pure
state transition in this function, `m` need only be `Applicative`.
We could put `Identity` here if we wanted to, but keeping `m` general
helps our views compose.
But what if we need to do _more_? Well we can update our `m` to
have more functionality. We can add some logging to the console:
```haskell
toggle :: Bool -> Html IO Bool
toggle b = h "div" []
[ text $ "Currently it's " <> if b then "ON" else "OFF"
, h "button"
[ listen' "click" $ do
putStrLn "We toggled!"
return $ not b
] [ text "Toggle" ]
]
```
What if we want to access some record of capabilities? Or update some
concurrent memory thing? Let's say we have an enterprise grade Monad:
```haskell
newtype App a = App { runApp :: RIO (TVar Metrics) a }
deriving (Functor, Applicative, Monad, MonadReader (TVar Metrics), MonadIO, MonadJSM)
toggle :: Bool -> Html App Bool
toggle b = h "div" []
[ text $ "Currently it's " <> if b then "ON" else "OFF"
, h "button"
[ listen' "click" $ do
metrics <- ask
liftIO $ do
atomically . modifyTVar metrics $
\m -> m { toggleCount = toggleCount m + 1 }
putStrLn "We toggled!"
return $ not b
] [ text "Toggle" ]
]
```
## Composing views
In Shpadoinkle we can compose views without impedance if the types match,
or are parametric. For example:
```haskell
hero :: Html m a
hero = h "h1" [] [ text "Online String Reverse" ]
input :: Html m Text
input = h "input" [ onInput id ] []
view :: Text -> Html m Text
view s = h "div" []
[ hero -- no impedance, this Html is fully generic
, input -- no impedance, this Html has matching types `(Text ~ Text)`
, text $ "Reversed: \"" <> reverse s <> "\""
]
```
If you have nesting, with different types,
we can resolve the mismatch using 'fmap' like so:
```haskell
input :: Html m Text
input = h "input" [ onInput id ] []
view :: (Int, Text) -> Html m (Int, Text)
view (i,t) = h "div" []
-- here we update the `Text` side of the model
-- with the value produced by `input`, and we
-- increment the `Int` as well.
[ (\t_ -> (i + 1, t_)) <$> input
, text $ "Reversed: \"" <> reverse t <> "\""
, text $ "you have reversed " <> pack (show i) <> " strings"
]
```
## The primitive
The Shpadoinkle programming model core primitive is the `shpadoinkle` function.
```haskell
shpadoinkle
:: (Shpadoinkle b m a, Territory t, Eq a) =>
=> (m ~> JSM) -> (t a -> b m ~> m) -- How to render
-> a -> t a -- What is our model
-> (a -> Html (b m) a) -- What to render
-> b m RawNode -> JSM () -- Actually render
```
This is the machine that runs a Shpadoinkle view. To run we need
the following ingredients: