From 7cf1f21b0dd610fcce23749743cdc9d5ab4d2509 Mon Sep 17 00:00:00 2001 From: Ryan Haskell-Glatz Date: Sun, 2 Aug 2020 15:41:32 -0500 Subject: [PATCH] remove incomplete example for now --- examples/jangle/.gitignore | 11 - examples/jangle/README.md | 43 --- examples/jangle/api/README.md | 27 -- examples/jangle/api/endpoints/github-auth.js | 48 ---- examples/jangle/api/secrets/index.js | 10 - examples/jangle/api/secrets/package.json | 10 - examples/jangle/elm-analyse.json | 7 - examples/jangle/elm.json | 38 --- examples/jangle/netlify.toml | 12 - examples/jangle/package.json | 36 --- examples/jangle/public/favicon.png | Bin 1885 -> 0 bytes examples/jangle/public/index.html | 20 -- examples/jangle/public/main.js | 25 -- examples/jangle/public/style.css | 99 ------- examples/jangle/src/Api/Data.elm | 104 ------- examples/jangle/src/Api/Github.elm | 30 -- examples/jangle/src/Api/Project.elm | 80 ------ examples/jangle/src/Api/README.md | 2 - examples/jangle/src/Api/Token.elm | 19 -- examples/jangle/src/Api/User.elm | 44 --- examples/jangle/src/Components/Layout.elm | 96 ------- examples/jangle/src/Components/README.md | 2 - examples/jangle/src/Main.elm | 157 ---------- examples/jangle/src/Pages/NotFound.elm | 46 --- examples/jangle/src/Pages/Projects.elm | 180 ------------ .../jangle/src/Pages/Projects/Id_String.elm | 101 ------- examples/jangle/src/Pages/README.md | 2 - examples/jangle/src/Pages/SignIn.elm | 167 ----------- examples/jangle/src/Pages/Top.elm | 73 ----- examples/jangle/src/Ports.elm | 13 - examples/jangle/src/Shared.elm | 118 -------- examples/jangle/src/Spa/Document.elm | 26 -- examples/jangle/src/Spa/Page.elm | 272 ------------------ examples/jangle/src/Spa/README.md | 2 - examples/jangle/src/Spa/Url.elm | 49 ---- examples/jangle/src/Utils/Cmd.elm | 11 - examples/jangle/src/Utils/Json.elm | 26 -- examples/jangle/src/Utils/Maybe.elm | 10 - examples/jangle/src/Utils/README.md | 2 - examples/jangle/src/Utils/Time.elm | 17 -- examples/jangle/tests/Program/NotFound.elm | 24 -- examples/jangle/tests/Program/README.md | 2 - examples/jangle/tests/Program/Top.elm | 24 -- examples/jangle/tests/Program/Utils/Spa.elm | 54 ---- examples/jangle/tests/README.md | 2 - examples/jangle/tests/Unit/README.md | 2 - 46 files changed, 2143 deletions(-) delete mode 100644 examples/jangle/.gitignore delete mode 100644 examples/jangle/README.md delete mode 100644 examples/jangle/api/README.md delete mode 100644 examples/jangle/api/endpoints/github-auth.js delete mode 100644 examples/jangle/api/secrets/index.js delete mode 100644 examples/jangle/api/secrets/package.json delete mode 100644 examples/jangle/elm-analyse.json delete mode 100644 examples/jangle/elm.json delete mode 100644 examples/jangle/netlify.toml delete mode 100644 examples/jangle/package.json delete mode 100644 examples/jangle/public/favicon.png delete mode 100644 examples/jangle/public/index.html delete mode 100644 examples/jangle/public/main.js delete mode 100644 examples/jangle/public/style.css delete mode 100644 examples/jangle/src/Api/Data.elm delete mode 100644 examples/jangle/src/Api/Github.elm delete mode 100644 examples/jangle/src/Api/Project.elm delete mode 100644 examples/jangle/src/Api/README.md delete mode 100644 examples/jangle/src/Api/Token.elm delete mode 100644 examples/jangle/src/Api/User.elm delete mode 100644 examples/jangle/src/Components/Layout.elm delete mode 100644 examples/jangle/src/Components/README.md delete mode 100644 examples/jangle/src/Main.elm delete mode 100644 examples/jangle/src/Pages/NotFound.elm delete mode 100644 examples/jangle/src/Pages/Projects.elm delete mode 100644 examples/jangle/src/Pages/Projects/Id_String.elm delete mode 100644 examples/jangle/src/Pages/README.md delete mode 100644 examples/jangle/src/Pages/SignIn.elm delete mode 100644 examples/jangle/src/Pages/Top.elm delete mode 100644 examples/jangle/src/Ports.elm delete mode 100644 examples/jangle/src/Shared.elm delete mode 100644 examples/jangle/src/Spa/Document.elm delete mode 100644 examples/jangle/src/Spa/Page.elm delete mode 100644 examples/jangle/src/Spa/README.md delete mode 100644 examples/jangle/src/Spa/Url.elm delete mode 100644 examples/jangle/src/Utils/Cmd.elm delete mode 100644 examples/jangle/src/Utils/Json.elm delete mode 100644 examples/jangle/src/Utils/Maybe.elm delete mode 100644 examples/jangle/src/Utils/README.md delete mode 100644 examples/jangle/src/Utils/Time.elm delete mode 100644 examples/jangle/tests/Program/NotFound.elm delete mode 100644 examples/jangle/tests/Program/README.md delete mode 100644 examples/jangle/tests/Program/Top.elm delete mode 100644 examples/jangle/tests/Program/Utils/Spa.elm delete mode 100644 examples/jangle/tests/README.md delete mode 100644 examples/jangle/tests/Unit/README.md diff --git a/examples/jangle/.gitignore b/examples/jangle/.gitignore deleted file mode 100644 index b79078b6..00000000 --- a/examples/jangle/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Folders to ignore -elm-stuff -node_modules -public/dist -src/Spa/Generated - -# MacOS weird stuff -.DS_Store - -# Ignore local dev secrets -api/secrets/secrets.js \ No newline at end of file diff --git a/examples/jangle/README.md b/examples/jangle/README.md deleted file mode 100644 index 1416f67a..00000000 --- a/examples/jangle/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# new elm-spa project -> More documentation at https://elm-spa.dev - -## local development - -You can get this site up and running with one command: - -``` -npm start -``` - -__Important Note:__ Sign in won't work until you [setup the API correctly](./api/README.md) - -### other commands to know - -There are a handful of commands in the [package.json](./package.json). - -Command | Description -:-- | :-- -`npm run dev` | Run a dev server and automatically build changes. -`npm run test:watch` | Run tests as you code. -`npm run build` | Build the site for production. -`npm run test` | Run the test suite once, great for CI - - -## deploying - -After you run `npm run build`, the contents of the `public` folder can be hosted as a static site. If you haven't hosted a static site before, I'd recommend using [Netlify](https://netlify.com) (it's free!) - -### using netlify - -Add a `netlify.toml` file next to this README, for standard SPA routing: - -```toml -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 -``` - -__Build command:__ `npm run build` - -__Publish directory:__ `public` \ No newline at end of file diff --git a/examples/jangle/api/README.md b/examples/jangle/api/README.md deleted file mode 100644 index f5b10f5c..00000000 --- a/examples/jangle/api/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# API -> Using Netlify Functions to authenticate with GitHub - -There are important client secrets that I can't push to source control. For that reason, we'll need add API keys manually. - -## local development - -First, create a file called `~/api/config/secrets.js` - -You'll need to [create an GitHub application](https://github.com/settings/applications/new) and -copy your __Client ID__ and __Client Secret__ here. - -```js -module.exports = { - clientId: '', - clientSecret: '' -} -``` - -You'll also need to edit `flags.dev.githubClientId` in `~/public/main.js`: - -```js -const flags = { - production: { githubClientId: '2a8238fe92e1e04c9af2' }, - dev: { githubClientId: '' } -} -``` \ No newline at end of file diff --git a/examples/jangle/api/endpoints/github-auth.js b/examples/jangle/api/endpoints/github-auth.js deleted file mode 100644 index c0dd4bef..00000000 --- a/examples/jangle/api/endpoints/github-auth.js +++ /dev/null @@ -1,48 +0,0 @@ -const axios = require('axios') -const config = require('secrets') - -exports.handler = function (event, _context, callback) { - const code = event.queryStringParameters.code - - const sendToken = response => { - if (response.data && typeof response.data.access_token === 'string') { - callback(null, { - statusCode: 200, - body: JSON.stringify(response.data.access_token) - }) - } else { - callback(null, { - statusCode: 400, - body: JSON.stringify(null) - }) - } - } - - const sendGithubError = reason => { - callback(null, { - statusCode: 400, - body: typeof reason.message === 'string' - ? reason.message - : 'Something went wrong...' - }) - } - - if (code) { - axios.post( - 'https://github.com/login/oauth/access_token', - { - client_id: config.clientId, - client_secret: config.clientSecret, - code: code - }, - { headers: { 'Accept': 'application/json' } - }) - .then(sendToken) - .catch(sendGithubError) - } else { - callback(null, { - statusCode: 400, - body: "Please provide code as a query parameter." - }) - } -} \ No newline at end of file diff --git a/examples/jangle/api/secrets/index.js b/examples/jangle/api/secrets/index.js deleted file mode 100644 index c3310a1b..00000000 --- a/examples/jangle/api/secrets/index.js +++ /dev/null @@ -1,10 +0,0 @@ -try { - secrets = require('./secrets.js') -} catch (_) { - secrets = {} -} - -module.exports = { - clientId: process.env.CLIENT_ID || secrets.clientId, - clientSecret : process.env.CLIENT_SECRET || secrets.clientSecret -} \ No newline at end of file diff --git a/examples/jangle/api/secrets/package.json b/examples/jangle/api/secrets/package.json deleted file mode 100644 index 2c575c2f..00000000 --- a/examples/jangle/api/secrets/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "secrets", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": {}, - "keywords": [], - "author": "", - "license": "ISC" -} diff --git a/examples/jangle/elm-analyse.json b/examples/jangle/elm-analyse.json deleted file mode 100644 index 94ea2e43..00000000 --- a/examples/jangle/elm-analyse.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "checks": { - "ImportAll": false, - "SingleFieldRecord": false, - "UnusedImportAlias": false - } -} \ No newline at end of file diff --git a/examples/jangle/elm.json b/examples/jangle/elm.json deleted file mode 100644 index 336cf6f7..00000000 --- a/examples/jangle/elm.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "type": "application", - "source-directories": [ - "src" - ], - "elm-version": "0.19.1", - "dependencies": { - "direct": { - "elm/browser": "1.0.2", - "elm/core": "1.0.5", - "elm/html": "1.0.0", - "elm/http": "2.0.0", - "elm/json": "1.1.3", - "elm/time": "1.0.0", - "elm/url": "1.0.0", - "rtfeldman/elm-iso8601-date-strings": "1.1.3", - "ryannhg/date-format": "2.3.0", - "truqu/elm-base64": "2.0.4" - }, - "indirect": { - "elm/bytes": "1.0.8", - "elm/file": "1.0.5", - "elm/parser": "1.1.0", - "elm/regex": "1.0.0", - "elm/virtual-dom": "1.0.2" - } - }, - "test-dependencies": { - "direct": { - "avh4/elm-program-test": "3.2.0", - "elm-explorations/test": "1.2.2" - }, - "indirect": { - "avh4/elm-fifo": "1.0.4", - "elm/random": "1.0.0" - } - } -} diff --git a/examples/jangle/netlify.toml b/examples/jangle/netlify.toml deleted file mode 100644 index a1851474..00000000 --- a/examples/jangle/netlify.toml +++ /dev/null @@ -1,12 +0,0 @@ -[build] - functions = "api/endpoints" - -[[redirects]] - from = '/api/*' - to = '/.netlify/functions/:splat' - status = 200 - -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 diff --git a/examples/jangle/package.json b/examples/jangle/package.json deleted file mode 100644 index 708b2334..00000000 --- a/examples/jangle/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "jangle", - "version": "1.0.0", - "description": "a project created with elm-spa", - "scripts": { - "start": "npm install && npm run build:dev && npm run dev", - "test": "elm-test", - "test:watch": "elm-test --watch", - "build": "run-s build:elm-spa build:elm build:minify", - "build:dev": "run-s build:elm-spa build:dev:elm", - "dev": "run-p dev:elm-spa dev:elm dev:netlify", - "build:elm": "elm make src/Main.elm --optimize --output=public/dist/elm.compiled.js", - "build:dev:elm": "elm make src/Main.elm --debug --output=public/dist/elm.compiled.js || true", - "build:elm-spa": "elm-spa build .", - "build:minify": "uglifyjs public/dist/elm.compiled.js --compress 'pure_funcs=\"F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9\",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | uglifyjs --mangle --output=public/dist/elm.compiled.js", - "dev:elm": "elm-live src/Main.elm --no-server -- --debug --output=public/dist/elm.compiled.js", - "dev:elm-spa": "chokidar src/Pages -c \"elm-spa build .\"", - "dev:netlify": "(cd ../.. && netlify dev -o -p 8000)" - }, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "chokidar-cli": "2.1.0", - "elm": "0.19.1-3", - "elm-live": "4.0.2", - "elm-spa": "next", - "elm-test": "0.19.1-revision2", - "npm-run-all": "4.1.5", - "uglify-js": "3.9.4" - }, - "dependencies": { - "axios": "0.19.2", - "secrets": "file:api/secrets" - } -} diff --git a/examples/jangle/public/favicon.png b/examples/jangle/public/favicon.png deleted file mode 100644 index 68b5e95423d0ccb1cade7bb092f2c355f00249ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1885 zcmV-j2cr0iP)FAvh+4SSllRM-3Go3NlL!EJ_yCd#=?8x!`9|LH4(!^k5QNuUt1Ep>m z&^q@o4Z4#{nw|^%rNU`F+psp?`DKJZ{keB|T&izGld%{`q2`ZqAFWV_D_%{PT9iBkOrIl}T>7k}5 zKaDRmfy5WP$XxntVxFhuA8O0u<<(Ucl$QhuR8J%}bpwgK5Jkcac}wir`^e(K$cvMS6k{;PtpE z4fyc;yeM9snv$fyz(AGX5I(nx<#AzI7U^^bBbDM>*=)|<^&(?iUqVRx5h*wvUWZ#s zYE%K3Ac62Y+NC53)Pdka?HYQ551^_FeyZ>l&_(k10L2oKkN+-q`V5ZT$cUX)^l1YYB$8~MVW(pVh!<1< zNkpc45P%{S9L>K0JAK>Y{o#up13Qhgc@v7FAOuLG3jyIm0}!zjT}VKtdJu_lVa6{B zk?cUGq5#;*9wbDH8nBFR%yf#(&LxO+^o|)I)k9|I63k2*E7=9IuL6BN0AaJI4eRLd zk?p(goOlkhy$R#!ACS>D5PcQsH6Y=X)zyN$bRaudLqPr_86us`!Bj*(15~W zdF>q1vW6_)UwB9+5?7I_9wZ#@pC_9@BCfnb2QX~#x`UU>iDy*ij=qW_BnS{ynkgfJ5G8Cy3*8^#u=2;cWn>bH#Kn?`b~jt^IhA9!Lj#ZCBsII03q0W zu>w2yrBV!xTn-LKMi8v70^pMze{cw!MS0!+1{M}0OWWq;fzLonESY`Bpz`<2LF&d0 zzWDqE09KKFwhflew+9$Fx0;ZY)DJGdlrVL8-#*?qyc-Fq3MgV=sA_gMruFAncNgT# z#e}xiR6%YEEWuoQuZJvz?gpW-VC-dldWLvfW8Rn!1ceRQyGFvYhO^WJ68LnJ*) z^igv#PrNrBOmY=4y@})RVw~B*^}QP?S+E&r-6KUma>sw1y!P&NEIDu=R3TaEb+B-H z@q^4b^Dkl_u0UoI*hUlqKFBqpEtqG+N$Chsva|`Mc0L))EE;ul7NhE}0s+n8VtnJ{ zH(jTWdziqJO-P3yTXMoQnFqOp=y!XGE}zMtt>m>Dqh;G98JqzAkyy4}5P^~alO{J1 z?g$g@iK6Q|Uz>Cf&prPvwc~1wuCZ(z&JXy|^VUS=6vGdm$C{bMs0TDuUP4 zyT4QCocRkx* z8cP*LSt;&*Y@#~*1@H{RNE&oqy~>D@HFRC=;)RuKP!z$-8`n}6ETjEGJC(yKak`w4 z2xIQ~72?eM&9-fCJlW1$Klm#J4RVu-?!(a)OjG=!pNI$F_#vUG{!jNGWZ&+6w4OS{ z%*I(rDcQegA9eNPnKgG7Q}3S!R}RJa_wu)7vg1!*-`IEa6~iqJWrr{Z%WO% z`2P~k^gBMMwydtME;W?ALpG4dkyCAt3MrqIf+-?*bxQ~%IHcO*%}En#Z|g7ISC0Py Xe*r>w|8bX%00000NkvXXu0mjfDjS0g diff --git a/examples/jangle/public/index.html b/examples/jangle/public/index.html deleted file mode 100644 index 812d2bba..00000000 --- a/examples/jangle/public/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/jangle/public/main.js b/examples/jangle/public/main.js deleted file mode 100644 index ebb79e22..00000000 --- a/examples/jangle/public/main.js +++ /dev/null @@ -1,25 +0,0 @@ -// Initial data to pass in to Elm (linked with `Shared.Flags`) -// https://guide.elm-lang.org/interop/flags.html -const isLocalDevelopment = window.location.hostname === 'localhost' - -const Storage = { - save: (key, value) => localStorage.setItem(key, JSON.stringify(value)), - load: (key) => JSON.parse(localStorage.getItem(key)) -} - -const flags = { - production: { githubClientId: '2a8238fe92e1e04c9af2' }, - dev: { githubClientId: '20c33fe428b932816bb2' } -} - -// Start our Elm application -const app = Elm.Main.init({ - flags: { - ...(isLocalDevelopment ? flags.dev : flags.production), - token: Storage.load('user') - } -}) - -// Ports would go here: https://guide.elm-lang.org/interop/ports.html -app.ports.storeToken.subscribe(token => Storage.save('user', token)) -app.ports.clearToken.subscribe(_ => Storage.save('user', null)) \ No newline at end of file diff --git a/examples/jangle/public/style.css b/examples/jangle/public/style.css deleted file mode 100644 index 53a3c3f5..00000000 --- a/examples/jangle/public/style.css +++ /dev/null @@ -1,99 +0,0 @@ -/* responsive font scaling */ -html { font-size: 18px; } -@media screen and (min-width: 641px) { html { font-size: 16px; } } -@media screen and (min-width: 1281px) { html { font-size: 18px; } } - -html { background: #f8f4f4; color: #333; } -body { font-family: 'Nunito', sans-serif; } - -table { max-width: 100%;} -td { white-space: nowrap; line-height: 1.2; } - -input { min-width: 0; border-radius: 0; border: 0 } - -img { width: 100%; } - -.font-h1, .font-h2, .font-h3, .font-h4, -.font-h5, .font-h6, .font-body { - font-family: 'Nunito', sans-serif; -} - -.font-h1, .font-h2, .font-h3, .font-h4, .text-header { - font-weight: 800; -} -.text-wrap { white-space: normal; } -.text--small { font-size: 0.75rem; } - -.color--white { color: white; } -.color--shell { color: #f8f4f4; } -.color--orange { color: #ce6946; } -.color--faint { opacity: 0.65; } - -.bg--white { background: white; } -.bg--shell { background: #f8f4f4; } -.bg--orange { background: #ce6946; } -.bg--dark-orange { background: #a1482b;} - -.shadow { box-shadow: 0 0.5em 2em rgba(0, 0, 0, 0.25); } -.shadow--shell { box-shadow: 0 2rem 1rem #f8f4f4; } -.shadow--none { box-shadow: none !important; } - -.border--light { border: solid 1px #ccc; } - -.sticky { position: sticky; z-index: 1; top: 0; left: 0; right: 0; } - -.z-2 { z-index: 2; } - -.width--half { width: 50%; } -.width--sidebar { width: 14rem; } -.offset--sidebar { margin-left: 14rem; } - -.size--avatar { min-width: 1.5em; min-height: 1.5em; max-width: 1.5em; max-height: 1.5em; } - -.max-width--20 { max-width: 20rem; } -.max-width--10 { max-width: 10rem; } - -.ellipsis { max-width: 100%; text-overflow: ellipsis; white-space: nowrap; } - -.overflow-hidden { overflow: hidden; } - -.tr { display: table-row; } -.tr:nth-child(2n + 1) { background: #eee; } - -/* buttons */ -.button { - cursor: pointer; - color: white; - background: linear-gradient(coral, #ce6946); - padding: 0.6em 1.2em; - box-shadow: 0 0.25em 1em rgba(0, 0, 0, 0.25); - transition: opacity 200ms ease-in-out; -} - -.button--icon { padding: 0.6em; } - -.button:hover { opacity: 0.75; } -.button[disabled] { opacity: 0.5; } - -.button--white { color: #ce6946; background: linear-gradient(#ffffff, #f0f0f0); } - -.page { transition: opacity 300ms ease-in-out, visibility 300ms ease-in-out; } -.page--invisible { opacity: 0; visibility: hidden; } - -.borderless { border: 0; } - -/* Hover effects */ -.highlightable { cursor: pointer; transition: color 200ms ease-in-out; } -.highlightable:hover { color: dodgerblue; } - -.hoverable { cursor: pointer; transition: opacity 200ms ease-in-out; } -.hoverable:hover { opacity: 0.5; } - -/* Normalize icon size */ -.fas, .fab { - min-width: 1em; - min-height: 1em; - display: inline-flex; - align-items: center; - justify-content: center; -} \ No newline at end of file diff --git a/examples/jangle/src/Api/Data.elm b/examples/jangle/src/Api/Data.elm deleted file mode 100644 index 4c4d551e..00000000 --- a/examples/jangle/src/Api/Data.elm +++ /dev/null @@ -1,104 +0,0 @@ -module Api.Data exposing - ( Data(..) - , fromHttpResult - , isResolved - , isUnresolved - , toMaybe - , view - ) - -import Http - - -type Data value - = NotAsked - | Loading - | Success value - | Failure String - - -toMaybe : Data value -> Maybe value -toMaybe data = - case data of - Success value -> - Just value - - _ -> - Nothing - - - -{- - BadUrl String - | Timeout - | NetworkError - | BadStatus Int - | BadBody String --} - - -fromHttpResult : Result Http.Error value -> Data value -fromHttpResult result = - case result of - Ok value -> - Success value - - Err (Http.BadUrl _) -> - Failure "URL was invalid." - - Err Http.Timeout -> - Failure "Request timed out." - - Err Http.NetworkError -> - Failure "Couldn't connect to internet." - - Err (Http.BadStatus status) -> - Failure ("Got status " ++ String.fromInt status) - - Err (Http.BadBody reason) -> - Failure reason - - -view : - Data value - -> - { notAsked : result - , loading : result - , failure : String -> result - , success : value -> result - } - -> result -view data views = - case data of - NotAsked -> - views.notAsked - - Loading -> - views.loading - - Failure reason -> - views.failure reason - - Success value -> - views.success value - - -isResolved : Data value -> Bool -isResolved data = - case data of - NotAsked -> - False - - Loading -> - False - - Success _ -> - True - - Failure _ -> - True - - -isUnresolved : Data value -> Bool -isUnresolved = - not << isResolved diff --git a/examples/jangle/src/Api/Github.elm b/examples/jangle/src/Api/Github.elm deleted file mode 100644 index 851311d0..00000000 --- a/examples/jangle/src/Api/Github.elm +++ /dev/null @@ -1,30 +0,0 @@ -module Api.Github exposing (get) - -import Api.Data exposing (Data) -import Api.Token exposing (Token) -import Http -import Json.Decode exposing (Decoder) -import Json.Encode as Json - - -get : - { token : Token - , query : String - , decoder : Decoder value - , toMsg : Data value -> msg - } - -> Cmd msg -get options = - Http.request - { method = "POST" - , url = "https://api.github.com/graphql" - , headers = [ Http.header "Authorization" ("Bearer " ++ Api.Token.toString options.token) ] - , body = - Http.jsonBody <| - Json.object - [ ( "query", Json.string options.query ) - ] - , expect = Http.expectJson (Api.Data.fromHttpResult >> options.toMsg) options.decoder - , timeout = Just (1000 * 60) - , tracker = Nothing - } diff --git a/examples/jangle/src/Api/Project.elm b/examples/jangle/src/Api/Project.elm deleted file mode 100644 index d0374ba0..00000000 --- a/examples/jangle/src/Api/Project.elm +++ /dev/null @@ -1,80 +0,0 @@ -module Api.Project exposing (Project, get, readme) - -import Api.Data exposing (Data) -import Api.Github -import Api.Token exposing (Token) -import Api.User exposing (User) -import Http -import Iso8601 -import Json.Decode as D exposing (Decoder) -import Time -import Utils.Json - - -type alias Project = - { name : String - , url : String - , description : String - , updatedAt : Time.Posix - } - - -get : { token : Token, toMsg : Data (List Project) -> msg } -> Cmd msg -get options = - Api.Github.get - { token = options.token - , decoder = D.at [ "data", "viewer", "repositories", "nodes" ] (D.list decoder) - , toMsg = options.toMsg - , query = """ - query { - viewer { - repositories(first: 10, affiliations: [OWNER], orderBy: { field: UPDATED_AT, direction: DESC }) { - nodes { - name, - description - url, - updatedAt - } - } - } - } - """ - } - - -decoder : Decoder Project -decoder = - D.map4 Project - (D.field "name" D.string) - (D.field "url" D.string) - (D.field "description" D.string |> Utils.Json.withDefault "") - (D.field "updatedAt" Iso8601.decoder) - - -readme : { user : User, repo : String, toMsg : Data String -> msg } -> Cmd msg -readme options = - restApiGet - { token = options.user.token - , path = "/repos/" ++ options.user.login ++ "/" ++ options.repo ++ "/readme" - , decoder = D.field "content" Utils.Json.base64 - , toMsg = options.toMsg - } - - -restApiGet : - { token : Token - , path : String - , decoder : Decoder value - , toMsg : Data value -> msg - } - -> Cmd msg -restApiGet options = - Http.request - { method = "GET" - , headers = [ Http.header "Authorization" ("Bearer " ++ Api.Token.toString options.token) ] - , url = "https://api.github.com" ++ options.path - , expect = Http.expectJson (Api.Data.fromHttpResult >> options.toMsg) options.decoder - , body = Http.emptyBody - , timeout = Just (1000 * 60) - , tracker = Nothing - } diff --git a/examples/jangle/src/Api/README.md b/examples/jangle/src/Api/README.md deleted file mode 100644 index 388b4423..00000000 --- a/examples/jangle/src/Api/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# src/Api -> Call backend API services diff --git a/examples/jangle/src/Api/Token.elm b/examples/jangle/src/Api/Token.elm deleted file mode 100644 index f13e5e89..00000000 --- a/examples/jangle/src/Api/Token.elm +++ /dev/null @@ -1,19 +0,0 @@ -module Api.Token exposing - ( Token - , fromString - , toString - ) - - -type Token - = Token String - - -fromString : String -> Token -fromString = - Token - - -toString : Token -> String -toString (Token token) = - token diff --git a/examples/jangle/src/Api/User.elm b/examples/jangle/src/Api/User.elm deleted file mode 100644 index 57883aae..00000000 --- a/examples/jangle/src/Api/User.elm +++ /dev/null @@ -1,44 +0,0 @@ -module Api.User exposing (User, current) - -import Api.Data exposing (Data) -import Api.Github -import Api.Token exposing (Token) -import Json.Decode as D exposing (Decoder) - - -type alias User = - { token : Token - , login : String - , avatarUrl : String - , name : String - } - - -current : { token : Token, toMsg : Data User -> msg } -> Cmd msg -current options = - Api.Github.get - { token = options.token - , decoder = D.at [ "data", "viewer" ] (decoder options.token) - , toMsg = options.toMsg - , query = """ - query { - viewer { - login - avatarUrl - name - } - } - """ - } - - -decoder : Token -> Decoder User -decoder token = - D.map3 (User token) - (D.field "login" D.string) - (D.field "avatarUrl" D.string) - (D.oneOf - [ D.field "name" D.string - , D.field "login" D.string |> D.map (String.append "@") - ] - ) diff --git a/examples/jangle/src/Components/Layout.elm b/examples/jangle/src/Components/Layout.elm deleted file mode 100644 index 5913c5d9..00000000 --- a/examples/jangle/src/Components/Layout.elm +++ /dev/null @@ -1,96 +0,0 @@ -module Components.Layout exposing (view) - -import Api.User exposing (User) -import Html exposing (..) -import Html.Attributes as Attr exposing (alt, class, classList, href, src) -import Html.Events as Events -import Spa.Generated.Route as Route exposing (Route) - - -view : - { model : { model | user : User } - , page : List (Html msg) - , onSignOutClicked : msg - , currentRoute : Route - } - -> List (Html msg) -view options = - [ viewMobile options - , viewDesktop options - ] - - -type alias Options model msg = - { model : { model | user : User } - , onSignOutClicked : msg - , page : List (Html msg) - , currentRoute : Route - } - - -viewMobile : Options model msg -> Html msg -viewMobile { onSignOutClicked, model, page } = - div [ class "visible-mobile column fill" ] - [ viewMobileNavbar onSignOutClicked model - , main_ [ class "flex" ] page - ] - - -viewDesktop : Options model msg -> Html msg -viewDesktop { currentRoute, onSignOutClicked, model, page } = - div [ class "hidden-mobile fill relative" ] - [ div [ class "relative bg--shell row fill-y align-top stretch" ] - [ div [ class "fixed z-2 width--sidebar align-top align-left fill-y bg--orange color--white" ] [ viewSidebar currentRoute onSignOutClicked model ] - , main_ [ class "offset--sidebar column flex" ] page - ] - ] - - -viewSidebar : Route -> msg -> { model | user : User } -> Html msg -viewSidebar currentRoute onSignOutClicked model = - aside [ class "column fill-y py-medium spacing-large" ] - [ a [ class "row font-h3 center-x", href (Route.toString Route.Projects) ] [ text "Jangle" ] - , div [ class "column flex" ] <| - List.map (viewSidebarLink currentRoute) - [ { label = "Projects", icon = "fa-list", route = Route.Projects } - , { label = "Users", icon = "fa-user", route = Route.NotFound } - , { label = "Docs", icon = "fa-book", route = Route.NotFound } - , { label = "Settings", icon = "fa-cog", route = Route.NotFound } - ] - , div [ class "column px-medium spacing-tiny" ] - [ viewUser onSignOutClicked model.user - ] - ] - - -viewSidebarLink : Route -> { label : String, icon : String, route : Route } -> Html msg -viewSidebarLink currentRoute link = - a - [ class "row spacing-small px-medium py-small" - , classList [ ( "bg--dark-orange", link.route == currentRoute ) ] - , href (Route.toString link.route) - ] - [ span [ class ("fas " ++ link.icon) ] [] - , span [] [ text link.label ] - ] - - -viewMobileNavbar : msg -> { model | user : User } -> Html msg -viewMobileNavbar onSignOutClicked model = - header [ class "row padding-small relative z-2 bg--orange color--white spread center-y" ] - [ a [ class "font-h3", href (Route.toString Route.Projects) ] [ text "Jangle" ] - , div [ class "column center-x spacing-tiny" ] - [ viewUser onSignOutClicked model.user - ] - ] - - -viewUser : msg -> User -> Html msg -viewUser onSignOutClicked user = - button [ Events.onClick onSignOutClicked, class "button button--white font--small" ] - [ div [ class "row spacing-tiny center-y" ] - [ div [ class "row rounded-circle bg-orange size--avatar" ] - [ img [ src user.avatarUrl, alt user.name ] [] ] - , span [ class "ellipsis" ] [ text "Sign out" ] - ] - ] diff --git a/examples/jangle/src/Components/README.md b/examples/jangle/src/Components/README.md deleted file mode 100644 index 384e490c..00000000 --- a/examples/jangle/src/Components/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# src/Components -> Reusable views and things diff --git a/examples/jangle/src/Main.elm b/examples/jangle/src/Main.elm deleted file mode 100644 index a9bd8e18..00000000 --- a/examples/jangle/src/Main.elm +++ /dev/null @@ -1,157 +0,0 @@ -module Main exposing (main) - -import Browser -import Browser.Navigation as Nav -import Shared exposing (Flags) -import Spa.Document as Document exposing (Document) -import Spa.Generated.Pages as Pages -import Spa.Generated.Route as Route exposing (Route) -import Url exposing (Url) -import Utils.Cmd - - -main : Program Flags Model Msg -main = - Browser.application - { init = init - , update = update - , subscriptions = subscriptions - , view = view >> Document.toBrowserDocument - , onUrlRequest = LinkClicked - , onUrlChange = UrlChanged - } - - -fromUrl : Url -> Route -fromUrl = - Route.fromUrl >> Maybe.withDefault Route.NotFound - - - --- INIT - - -type alias Model = - { url : Url - , key : Nav.Key - , isTransitioning : Bool - , shared : Shared.Model - , page : Pages.Model - } - - -init : Flags -> Url -> Nav.Key -> ( Model, Cmd Msg ) -init flags url key = - let - ( shared, sharedCmd ) = - Shared.init flags key - - route = - fromUrl url - - ( page, pageCmd ) = - Pages.init route shared url - in - ( Model url key False shared page - , Cmd.batch - [ Cmd.map Pages pageCmd - , Cmd.map Shared sharedCmd - ] - ) - - - --- UPDATE - - -type Msg - = LinkClicked Browser.UrlRequest - | UrlChanged Url - | FadeInPage Url - | Shared Shared.Msg - | Pages Pages.Msg - - -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = - case msg of - LinkClicked (Browser.Internal url) -> - ( model - , Nav.pushUrl model.key (Url.toString url) - ) - - LinkClicked (Browser.External href) -> - ( model - , Nav.load href - ) - - UrlChanged url -> - if url == model.url then - ( model, Cmd.none ) - - else if url.path == model.url.path then - ( model, Utils.Cmd.delay 0 (FadeInPage url) ) - - else - ( { model | isTransitioning = True } - , Utils.Cmd.delay 300 (FadeInPage url) - ) - - FadeInPage url -> - let - route = - fromUrl url - - ( page, cmd ) = - Pages.init route model.shared url - - shared = - Pages.save page model.shared - in - ( { model | url = url, page = page, shared = shared, isTransitioning = False } - , Cmd.map Pages cmd - ) - - Shared sharedMsg -> - let - ( shared, sharedCmd ) = - Shared.update sharedMsg model.shared - - ( page, pageCmd ) = - Pages.load model.page shared - in - ( { model | page = page, shared = shared } - , Cmd.batch - [ Cmd.map Pages pageCmd - , Cmd.map Shared sharedCmd - ] - ) - - Pages pageMsg -> - let - ( page, cmd ) = - Pages.update pageMsg model.page - - shared = - Pages.save page model.shared - in - ( { model | page = page, shared = shared } - , Cmd.map Pages cmd - ) - - -view : Model -> Document Msg -view model = - Shared.view - { page = Pages.view model.page |> Document.map Pages - , shared = model.shared - , toMsg = Shared - , isTransitioning = model.isTransitioning - , route = fromUrl model.url - } - - -subscriptions : Model -> Sub Msg -subscriptions model = - Pages.subscriptions model.page - |> Sub.map Pages diff --git a/examples/jangle/src/Pages/NotFound.elm b/examples/jangle/src/Pages/NotFound.elm deleted file mode 100644 index 513f4f00..00000000 --- a/examples/jangle/src/Pages/NotFound.elm +++ /dev/null @@ -1,46 +0,0 @@ -module Pages.NotFound exposing (Model, Msg, Params, page) - -import Api.User exposing (User) -import Browser.Navigation as Nav -import Html exposing (..) -import Html.Attributes exposing (class, href) -import Html.Events as Events -import Spa.Document exposing (Document) -import Spa.Generated.Route as Route -import Spa.Page as Page exposing (Page) -import Spa.Url as Url exposing (Url) - - -type alias Params = - () - - -type alias Model = - Page.Protected Params { user : User, url : Url Params } - - -type alias Msg = - Never - - -page : Page Params Model Msg -page = - Page.protectedStatic - { view = view - } - - -view : User -> Url Params -> Document Msg -view _ _ = - { title = "Jangle" - , body = - [ div [ class "column fill center" ] - [ div [ class "column bg--white padding-medium shadow spacing-small max-width--20 rounded-tiny fill-x center-x" ] - [ h1 [ class "font-h2 text-center" ] [ text "Page not Found" ] - , div [ class "row" ] - [ a [ class "button", href (Route.toString Route.Top) ] [ text "Back to projects" ] - ] - ] - ] - ] - } diff --git a/examples/jangle/src/Pages/Projects.elm b/examples/jangle/src/Pages/Projects.elm deleted file mode 100644 index 9fc19b52..00000000 --- a/examples/jangle/src/Pages/Projects.elm +++ /dev/null @@ -1,180 +0,0 @@ -module Pages.Projects exposing (Model, Msg, Params, page) - -import Api.Data exposing (Data) -import Api.Project exposing (Project) -import Api.User as User exposing (User) -import Browser.Navigation as Nav -import Shared -import Html exposing (..) -import Html.Attributes as Attr exposing (class, classList, href) -import Html.Events as Events -import Spa.Document exposing (Document) -import Spa.Generated.Route as Route -import Spa.Page as Page exposing (Page) -import Spa.Url as Url exposing (Url) -import Utils.Time - - -type alias Params = - () - - -type alias Model = - Page.Protected Params ProtectedModel - - -page : Page Params Model Msg -page = - Page.protectedFull - { init = init - , update = update - , subscriptions = subscriptions - , view = view - , save = always identity - , load = always identity - } - - -type alias ProtectedModel = - { key : Nav.Key - , user : User - , signOutRequested : Bool - , query : String - , projects : Data (List Project) - } - - -init : User -> Shared.Model -> Url Params -> ( ProtectedModel, Cmd Msg ) -init user shared _ = - ( ProtectedModel - shared.key - user - False - "" - Api.Data.Loading - , Api.Project.get - { token = user.token - , toMsg = GotProjects - } - ) - - -type Msg - = GotProjects (Data (List Project)) - | UpdatedSearchInput String - | SubmittedSearch - | ClickedRow Project - - -update : Msg -> ProtectedModel -> ( ProtectedModel, Cmd Msg ) -update msg model = - case msg of - GotProjects projects -> - ( { model | projects = projects } - , Cmd.none - ) - - UpdatedSearchInput query -> - ( { model | query = query } - , Cmd.none - ) - - SubmittedSearch -> - ( { model | query = "" } - , Cmd.none - ) - - ClickedRow _ -> - ( model, Cmd.none ) - - -subscriptions : ProtectedModel -> Sub Msg -subscriptions _ = - Sub.none - - -view : ProtectedModel -> Document Msg -view model = - { title = "Jangle" - , body = - [ div [ class "column spacing-medium" ] - [ div [ class "column overflow-hidden bg--shell shadow--shell sticky" ] - [ div [ class "row wrap padding-medium spacing-tiny spread center-y" ] - [ h1 [ class "font-h3" ] [ text "Projects" ] - , viewSearchbar - { value = model.query - , placeholder = "Find a project..." - , onInput = UpdatedSearchInput - , onSubmit = SubmittedSearch - } - ] - ] - , div - [ class "column spacing-medium scrollable page" - , classList [ ( "page--invisible", Api.Data.isUnresolved model.projects ) ] - ] - [ Api.Data.view model.projects - { notAsked = text "" - , loading = span [ class "px-medium color--faint" ] [ text "" ] - , failure = \reason -> span [ class "error px-medium" ] [ text reason ] - , success = viewProjects - } - ] - ] - ] - } - - -viewProjects : List Project -> Html Msg -viewProjects projects = - viewTable - { columns = - [ { header = th [ class "pl-medium" ] [ text "Name" ] - , viewItem = \item -> td [ class "py-small pl-medium" ] [ strong [] [ text item.name ] ] - } - , { header = th [] [ text "Updated On" ] - , viewItem = \item -> td [] [ text (Utils.Time.format item.updatedAt) ] - } - , { header = th [] [ text "Description" ] - , viewItem = \item -> td [ class "color--faint" ] [ text item.description ] - } - ] - , items = projects - , viewRow = \item -> a [ class "tr highlightable", href (Route.toString <| Route.Projects__Id_String { id = item.name }) ] - } - - -viewTable : - { columns : List { header : Html msg, viewItem : item -> Html msg } - , items : List item - , viewRow : item -> List (Html msg) -> Html msg - } - -> Html msg -viewTable options = - table [ class "borderless" ] - [ thead [] [ tr [] <| List.map .header options.columns ] - , tbody [] <| - List.map - (\item -> options.viewRow item (List.map (\column -> column.viewItem item) options.columns)) - options.items - ] - - -viewSearchbar : - { value : String - , placeholder : String - , onInput : String -> msg - , onSubmit : msg - } - -> Html msg -viewSearchbar options = - Html.form [ Events.onSubmit options.onSubmit, class "row stretch border--light" ] - [ input - [ class "max-width--10 rounded-none" - , Attr.placeholder options.placeholder - , Attr.value options.value - , Events.onInput options.onInput - ] - [ text "Search bar" ] - , button [ class "button button--icon button--white rounded-none shadow--none" ] [ span [ class "fas fa-search" ] [] ] - ] diff --git a/examples/jangle/src/Pages/Projects/Id_String.elm b/examples/jangle/src/Pages/Projects/Id_String.elm deleted file mode 100644 index 6168e2df..00000000 --- a/examples/jangle/src/Pages/Projects/Id_String.elm +++ /dev/null @@ -1,101 +0,0 @@ -module Pages.Projects.Id_String exposing (Model, Msg, Params, page) - -import Api.Data exposing (Data(..)) -import Api.Project -import Api.User exposing (User) -import Html exposing (..) -import Html.Attributes as Attr exposing (class, href, target) -import Spa.Document exposing (Document) -import Spa.Page as Page exposing (Page) -import Spa.Url exposing (Url) - - -type alias Params = - { id : String } - - -type alias Model = - Page.Protected Params ProtectedModel - - -type Msg - = GotReadme (Data String) - - -page : Page Params Model Msg -page = - Page.protectedElement - { init = init - , update = update - , view = view - , subscriptions = always Sub.none - } - - - --- INIT - - -type alias ProtectedModel = - { user : User - , url : Url Params - , readme : Data String - } - - -init : User -> Url Params -> ( ProtectedModel, Cmd Msg ) -init user url = - ( ProtectedModel user url Loading - , Api.Project.readme - { user = user - , repo = url.params.id - , toMsg = GotReadme - } - ) - - -update : Msg -> ProtectedModel -> ( ProtectedModel, Cmd Msg ) -update msg model = - case msg of - GotReadme readme -> - ( { model | readme = readme } - , Cmd.none - ) - - - --- VIEW - - -view : ProtectedModel -> Document Msg -view model = - let - repoUrl : String - repoUrl = - "https://www.github.com/" ++ model.user.login ++ "/" ++ model.url.params.id - in - { title = model.url.params.id ++ " | Jangle" - , body = - [ div [ class "column overflow-hidden" ] - [ div [ class "row wrap padding-medium spacing-small center-y bg--shell" ] - [ h1 [ class "font-h3" ] [ text model.url.params.id ] - , a [ class "font-h3 hoverable", href repoUrl, target "_blank" ] [ span [ class "fab fa-github-square" ] [] ] - ] - ] - , Api.Data.view model.readme - { notAsked = text "" - , loading = text "" - , failure = text - , success = - text - >> List.singleton - >> code [] - >> List.singleton - >> pre - [ class "padding-medium" - , Attr.style "white-space" "pre-wrap" - , Attr.style "line-height" "1.2" - ] - } - ] - } diff --git a/examples/jangle/src/Pages/README.md b/examples/jangle/src/Pages/README.md deleted file mode 100644 index 56145bcb..00000000 --- a/examples/jangle/src/Pages/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# src/Pages -> Correspond to a URL route diff --git a/examples/jangle/src/Pages/SignIn.elm b/examples/jangle/src/Pages/SignIn.elm deleted file mode 100644 index 4dce5145..00000000 --- a/examples/jangle/src/Pages/SignIn.elm +++ /dev/null @@ -1,167 +0,0 @@ -module Pages.SignIn exposing (Model, Msg, Params, page) - -import Api.Data exposing (Data(..)) -import Api.Token exposing (Token) -import Api.User exposing (User) -import Browser.Navigation as Nav -import Dict -import Shared -import Html exposing (..) -import Html.Attributes exposing (class, disabled, href) -import Http -import Json.Decode as D -import Ports -import Spa.Document exposing (Document) -import Spa.Generated.Route as Route -import Spa.Page as Page exposing (Page) -import Spa.Url exposing (Url) - - -type alias Params = - () - - -page : Page Params Model Msg -page = - Page.application - { init = init - , update = update - , subscriptions = subscriptions - , view = view - , save = save - , load = load - } - - - --- INIT - - -type alias Model = - { githubClientId : String - , token : Data Token - , user : Data User - , key : Nav.Key - } - - -init : Shared.Model -> Url Params -> ( Model, Cmd Msg ) -init shared { query } = - case Api.Data.toMaybe shared.user of - Just user -> - ( Model shared.githubClientId Loading (Success user) shared.key - , Nav.pushUrl shared.key (Route.toString Route.Projects) - ) - - Nothing -> - case Dict.get "code" query of - Just code -> - ( { githubClientId = shared.githubClientId - , token = Loading - , user = NotAsked - , key = shared.key - } - , requestAuthToken code - ) - - Nothing -> - ( { githubClientId = shared.githubClientId - , token = NotAsked - , user = NotAsked - , key = shared.key - } - , Cmd.none - ) - - -requestAuthToken : String -> Cmd Msg -requestAuthToken code = - Http.get - { url = "/api/github-auth?code=" ++ code - , expect = Http.expectJson GotAuthToken D.string - } - - -load : Shared.Model -> Model -> ( Model, Cmd Msg ) -load shared model = - ( model, Cmd.none ) - - - --- UPDATE - - -type Msg - = GotAuthToken (Result Http.Error String) - | GotUser (Data User) - - -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = - case msg of - GotAuthToken (Ok token) -> - ( { model | token = Success (Api.Token.fromString token) } - , Cmd.batch - [ Ports.storeToken token - , Api.User.current - { token = Api.Token.fromString token - , toMsg = GotUser - } - ] - ) - - GotAuthToken (Err _) -> - ( { model | token = Failure "Failed to sign in." } - , Cmd.none - ) - - GotUser user -> - ( { model | user = user } - , Nav.pushUrl model.key (Route.toString Route.Projects) - ) - - -save : Model -> Shared.Model -> Shared.Model -save model shared = - { shared | user = model.user } - - -subscriptions : Model -> Sub Msg -subscriptions _ = - Sub.none - - -view : Model -> Document Msg -view model = - { title = "Sign In | Jangle" - , body = - [ div [ class "column fill center" ] - [ div [ class "column bg--white padding-medium shadow spacing-small max-width--20 rounded-tiny fill-x center-x" ] - [ div [ class "column text-center spacing-tiny" ] - [ h1 [ class "font-h1 text-center" ] [ text "Jangle" ] - , h2 [ class "font-body" ] [ text "a cms for humans" ] - ] - , div [ class "row" ] <| - case model.token of - NotAsked -> - [ a [ class "button", href ("https://github.com/login/oauth/authorize?client_id=" ++ model.githubClientId) ] - [ text "Sign in with GitHub" ] - ] - - Loading -> - [ button [ class "button button--white", disabled True ] [ text "Signing in..." ] ] - - Success _ -> - [ button [ class "button button--white", disabled True ] [ text "Success!" ] ] - - Failure reason -> - [ div [ class "column center-x" ] - [ text reason - , a [ class "link", href ("https://github.com/login/oauth/authorize?client_id=" ++ model.githubClientId) ] - [ text "Try again?" ] - ] - ] - ] - ] - ] - } diff --git a/examples/jangle/src/Pages/Top.elm b/examples/jangle/src/Pages/Top.elm deleted file mode 100644 index e0dacf42..00000000 --- a/examples/jangle/src/Pages/Top.elm +++ /dev/null @@ -1,73 +0,0 @@ -module Pages.Top exposing (Model, Msg, Params, page) - -import Api.Data -import Browser.Navigation as Nav -import Shared -import Html exposing (..) -import Spa.Document exposing (Document) -import Spa.Generated.Route as Route -import Spa.Page as Page exposing (Page) -import Spa.Url as Url exposing (Url) - - -type alias Params = - () - - -type alias Model = - {} - - -type Msg - = ReplaceMe - - -page : Page Params Model Msg -page = - Page.application - { init = init - , update = update - , subscriptions = subscriptions - , view = view - , save = save - , load = load - } - - -init : Shared.Model -> Url Params -> ( Model, Cmd Msg ) -init shared _ = - case Api.Data.toMaybe shared.user of - Just _ -> - ( {}, Nav.pushUrl shared.key (Route.toString Route.Projects) ) - - Nothing -> - ( {}, Nav.pushUrl shared.key (Route.toString Route.SignIn) ) - - -load : Shared.Model -> Model -> ( Model, Cmd Msg ) -load shared model = - ( model, Cmd.none ) - - -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = - case msg of - ReplaceMe -> - ( model, Cmd.none ) - - -save : Model -> Shared.Model -> Shared.Model -save model shared = - shared - - -subscriptions : Model -> Sub Msg -subscriptions model = - Sub.none - - -view : Model -> Document Msg -view model = - { title = "Top" - , body = [] - } diff --git a/examples/jangle/src/Ports.elm b/examples/jangle/src/Ports.elm deleted file mode 100644 index 973bcf4e..00000000 --- a/examples/jangle/src/Ports.elm +++ /dev/null @@ -1,13 +0,0 @@ -port module Ports exposing - ( clearToken - , storeToken - ) - --- A place to interact with JavaScript --- https://guide.elm-lang.org/interop/ports.html - - -port storeToken : String -> Cmd msg - - -port clearToken : () -> Cmd msg diff --git a/examples/jangle/src/Shared.elm b/examples/jangle/src/Shared.elm deleted file mode 100644 index 876ec6c5..00000000 --- a/examples/jangle/src/Shared.elm +++ /dev/null @@ -1,118 +0,0 @@ -module Shared exposing - ( Flags - , Model - , Msg - , init - , subscriptions - , update - , view - ) - -import Api.Data exposing (Data(..)) -import Api.Token exposing (Token) -import Api.User exposing (User) -import Browser.Navigation as Nav -import Components.Layout -import Html exposing (..) -import Html.Attributes exposing (class, classList) -import Ports -import Spa.Document exposing (Document) -import Spa.Generated.Route as Route exposing (Route) - - -type alias Flags = - { githubClientId : String - , token : Maybe String - } - - -type alias Model = - { key : Nav.Key - , githubClientId : String - , user : Data User - } - - -init : Flags -> Nav.Key -> ( Model, Cmd Msg ) -init flags key = - let - possibleToken = - flags.token |> Maybe.map Api.Token.fromString - - user = - if possibleToken == Nothing then - NotAsked - - else - Loading - in - ( Model key - flags.githubClientId - user - , case possibleToken of - Just token -> - Api.User.current { token = token, toMsg = GotUser } - - Nothing -> - Cmd.none - ) - - -type Msg - = GotUser (Data User) - | ClickedSignOut - - -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = - case msg of - GotUser user -> - ( { model | user = user } - , Cmd.none - ) - - ClickedSignOut -> - ( { model | user = NotAsked } - , Cmd.batch - [ Ports.clearToken () - , Nav.pushUrl model.key (Route.toString Route.SignIn) - ] - ) - - -subscriptions : Model -> Sub Msg -subscriptions _ = - Sub.none - - -view : - { route : Route - , page : Document msg - , shared : Model - , toMsg : Msg -> msg - , isTransitioning : Bool - } - -> Document msg -view { route, page, shared, toMsg, isTransitioning } = - { title = page.title - , body = - Api.Data.view shared.user - { notAsked = page.body - , loading = [] - , failure = text >> List.singleton - , success = - \user -> - Components.Layout.view - { model = { user = user } - , page = - [ div - [ class "column fill page" - , classList [ ( "page--invisible", isTransitioning ) ] - ] - page.body - ] - , onSignOutClicked = toMsg ClickedSignOut - , currentRoute = route - } - } - } diff --git a/examples/jangle/src/Spa/Document.elm b/examples/jangle/src/Spa/Document.elm deleted file mode 100644 index bac06814..00000000 --- a/examples/jangle/src/Spa/Document.elm +++ /dev/null @@ -1,26 +0,0 @@ -module Spa.Document exposing - ( Document - , map - , toBrowserDocument - ) - -import Browser -import Html exposing (Html) - - -type alias Document msg = - { title : String - , body : List (Html msg) - } - - -map : (msg1 -> msg2) -> Document msg1 -> Document msg2 -map fn doc = - { title = doc.title - , body = List.map (Html.map fn) doc.body - } - - -toBrowserDocument : Document msg -> Browser.Document msg -toBrowserDocument doc = - doc diff --git a/examples/jangle/src/Spa/Page.elm b/examples/jangle/src/Spa/Page.elm deleted file mode 100644 index 178ca4c4..00000000 --- a/examples/jangle/src/Spa/Page.elm +++ /dev/null @@ -1,272 +0,0 @@ -module Spa.Page exposing - ( Page - , static, sandbox, element, application - , Protected - , protectedStatic, protectedSandbox, protectedElement, protectedFull - , Upgraded, Bundle, upgrade - ) - -{-| - -@docs Page -@docs static, sandbox, element, application -@docs Protected -@docs protectedStatic, protectedSandbox, protectedElement, protectedFull -@docs Upgraded, Bundle, upgrade - --} - -import Api.Data exposing (Data(..)) -import Api.User exposing (User) -import Browser.Navigation as Nav -import Shared -import Spa.Document as Document exposing (Document) -import Spa.Generated.Route as Route -import Spa.Url exposing (Url) -import Url - - -type alias Page params model msg = - { init : Shared.Model -> Url params -> ( model, Cmd msg ) - , update : msg -> model -> ( model, Cmd msg ) - , view : model -> Document msg - , subscriptions : model -> Sub msg - , save : model -> Shared.Model -> Shared.Model - , load : Shared.Model -> model -> ( model, Cmd msg ) - } - - -noEffect : model -> ( model, Cmd msg ) -noEffect model = - ( model, Cmd.none ) - - -static : - { view : Url params -> Document msg - } - -> Page params (Url params) msg -static page = - { init = \_ url -> ( url, Cmd.none ) - , update = \_ model -> ( model, Cmd.none ) - , view = page.view - , subscriptions = \_ -> Sub.none - , save = always identity - , load = always (identity >> noEffect) - } - - -sandbox : - { init : Url params -> model - , update : msg -> model -> model - , view : model -> Document msg - } - -> Page params model msg -sandbox page = - { init = \_ url -> ( page.init url, Cmd.none ) - , update = \msg model -> ( page.update msg model, Cmd.none ) - , view = page.view - , subscriptions = \_ -> Sub.none - , save = always identity - , load = always (identity >> noEffect) - } - - -element : - { init : Url params -> ( model, Cmd msg ) - , update : msg -> model -> ( model, Cmd msg ) - , view : model -> Document msg - , subscriptions : model -> Sub msg - } - -> Page params model msg -element page = - { init = \_ params -> page.init params - , update = \msg model -> page.update msg model - , view = page.view - , subscriptions = page.subscriptions - , save = always identity - , load = always (identity >> noEffect) - } - - -application : - { init : Shared.Model -> Url params -> ( model, Cmd msg ) - , update : msg -> model -> ( model, Cmd msg ) - , view : model -> Document msg - , subscriptions : model -> Sub msg - , save : model -> Shared.Model -> Shared.Model - , load : Shared.Model -> model -> ( model, Cmd msg ) - } - -> Page params model msg -application = - identity - - - --- PROTECTED, redirect to sign in if not signed in - - -type Protected params model - = Protected model - | Unprotected (Url params) - - -protectedStatic : - { view : User -> Url params -> Document msg - } - -> Page params (Protected params { user : User, url : Url params }) msg -protectedStatic page = - protected - { init = \user _ url -> ( { url = url, user = user }, Cmd.none ) - , update = \_ model -> ( model, Cmd.none ) - , subscriptions = always Sub.none - , view = \{ user, url } -> page.view user url - , save = always identity - , load = always identity - } - - -protectedSandbox : - { init : User -> Url params -> model - , update : msg -> model -> model - , view : model -> Document msg - } - -> Page params (Protected params model) msg -protectedSandbox page = - protected - { init = \user _ url -> ( page.init user url, Cmd.none ) - , update = \msg model -> ( page.update msg model, Cmd.none ) - , view = page.view - , subscriptions = always Sub.none - , save = always identity - , load = always identity - } - - -protectedElement : - { init : User -> Url params -> ( model, Cmd msg ) - , update : msg -> model -> ( model, Cmd msg ) - , view : model -> Document msg - , subscriptions : model -> Sub msg - } - -> Page params (Protected params model) msg -protectedElement page = - protected - { init = \user _ url -> page.init user url - , update = page.update - , view = page.view - , subscriptions = page.subscriptions - , save = always identity - , load = always identity - } - - -protectedFull : - { init : User -> Shared.Model -> Url params -> ( model, Cmd msg ) - , update : msg -> model -> ( model, Cmd msg ) - , view : model -> Document msg - , subscriptions : model -> Sub msg - , save : model -> Shared.Model -> Shared.Model - , load : Shared.Model -> model -> model - } - -> Page params (Protected params model) msg -protectedFull = - protected >> application - - -protected : - { init : User -> Shared.Model -> Url params -> ( model, Cmd msg ) - , update : msg -> model -> ( model, Cmd msg ) - , view : model -> Document msg - , subscriptions : model -> Sub msg - , save : model -> Shared.Model -> Shared.Model - , load : Shared.Model -> model -> model - } - -> Page params (Protected params model) msg -protected page = - let - init : Shared.Model -> Url params -> ( Protected params model, Cmd msg ) - init shared url = - case shared.user of - NotAsked -> - ( Unprotected url - , Nav.pushUrl shared.key (Route.toString Route.SignIn) - ) - - Loading -> - ( Unprotected url - , Cmd.none - ) - - Success user -> - page.init user shared url |> Tuple.mapFirst Protected - - Failure _ -> - ( Unprotected url - , Nav.pushUrl shared.key (Route.toString Route.SignIn) - ) - - protect : (model -> value) -> value -> Protected params model -> value - protect fromModel fallback protectedModel = - case protectedModel of - Protected model -> - fromModel model - - Unprotected _ -> - fallback - in - { init = init - , update = - \msg model_ -> - protect - (\model -> page.update msg model |> Tuple.mapFirst Protected) - ( model_, Cmd.none ) - model_ - , view = protect page.view { title = "", body = [] } - , subscriptions = protect page.subscriptions Sub.none - , save = \model_ shared -> protect (\model -> page.save model shared) shared model_ - , load = - \shared model_ -> - case model_ of - Protected model -> - page.load shared model |> Protected |> noEffect - - Unprotected url -> - init shared url - } - - - --- UPGRADING - - -type alias Upgraded pageParams pageModel pageMsg model msg = - { init : pageParams -> Shared.Model -> Url.Url -> ( model, Cmd msg ) - , update : pageMsg -> pageModel -> ( model, Cmd msg ) - , bundle : pageModel -> Bundle model msg - } - - -type alias Bundle model msg = - { view : Document msg - , subscriptions : Sub msg - , save : Shared.Model -> Shared.Model - , load : Shared.Model -> ( model, Cmd msg ) - } - - -upgrade : - (pageModel -> model) - -> (pageMsg -> msg) - -> Page pageParams pageModel pageMsg - -> Upgraded pageParams pageModel pageMsg model msg -upgrade toModel toMsg page = - { init = \params shared url -> page.init shared (Spa.Url.create params url) |> Tuple.mapBoth toModel (Cmd.map toMsg) - , update = \msg model -> page.update msg model |> Tuple.mapBoth toModel (Cmd.map toMsg) - , bundle = - \model -> - { view = page.view model |> Document.map toMsg - , subscriptions = page.subscriptions model |> Sub.map toMsg - , save = page.save model - , load = \shared -> page.load shared model |> Tuple.mapBoth toModel (Cmd.map toMsg) - } - } diff --git a/examples/jangle/src/Spa/README.md b/examples/jangle/src/Spa/README.md deleted file mode 100644 index f3436033..00000000 --- a/examples/jangle/src/Spa/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# src/Spa -> elm-spa configuration and generated code diff --git a/examples/jangle/src/Spa/Url.elm b/examples/jangle/src/Spa/Url.elm deleted file mode 100644 index 76ce7d70..00000000 --- a/examples/jangle/src/Spa/Url.elm +++ /dev/null @@ -1,49 +0,0 @@ -module Spa.Url exposing (Url, create) - -import Dict exposing (Dict) -import Url - - -type alias Url params = - { params : params - , query : Dict String String - , rawUrl : Url.Url - } - - -create : params -> Url.Url -> Url params -create params url = - { params = params - , rawUrl = url - , query = - url.query - |> Maybe.map toQueryDict - |> Maybe.withDefault Dict.empty - } - - - --- INTERNALS --- Works with parameters like `?key=value` but not things like `?key` --- You can use `url.rawUrl.query` to handle checking for the second type --- of query parameter. - - -toQueryDict : String -> Dict String String -toQueryDict queryString = - let - second : List a -> Maybe a - second list = - list |> List.drop 1 |> List.head - - toTuple : List String -> Maybe ( String, String ) - toTuple list = - Maybe.map2 Tuple.pair - (List.head list) - (second list) - in - queryString - |> String.split "&" - |> List.map (String.split "=") - |> List.filterMap toTuple - |> Dict.fromList diff --git a/examples/jangle/src/Utils/Cmd.elm b/examples/jangle/src/Utils/Cmd.elm deleted file mode 100644 index f53218f9..00000000 --- a/examples/jangle/src/Utils/Cmd.elm +++ /dev/null @@ -1,11 +0,0 @@ -module Utils.Cmd exposing (delay) - -import Process -import Task - - -delay : Float -> msg -> Cmd msg -delay ms msg = - Process.sleep ms - |> Task.map (\_ -> msg) - |> Task.perform identity diff --git a/examples/jangle/src/Utils/Json.elm b/examples/jangle/src/Utils/Json.elm deleted file mode 100644 index 88381522..00000000 --- a/examples/jangle/src/Utils/Json.elm +++ /dev/null @@ -1,26 +0,0 @@ -module Utils.Json exposing (base64, withDefault) - -import Base64 -import Json.Decode as D exposing (Decoder) - - -withDefault : value -> Decoder value -> Decoder value -withDefault fallback decoder = - D.oneOf - [ decoder - , D.succeed fallback - ] - - -base64 : Decoder String -base64 = - D.string - |> D.andThen - (\encodedString -> - case Base64.decode (String.replace "\n" "" encodedString) of - Ok str -> - D.succeed str - - Err reason -> - D.fail reason - ) diff --git a/examples/jangle/src/Utils/Maybe.elm b/examples/jangle/src/Utils/Maybe.elm deleted file mode 100644 index 47c5c1fe..00000000 --- a/examples/jangle/src/Utils/Maybe.elm +++ /dev/null @@ -1,10 +0,0 @@ -module Utils.Maybe exposing (view) - -import Html exposing (Html) - - -view : Maybe value -> (value -> Html msg) -> Html msg -view maybe toHtml = - maybe - |> Maybe.map toHtml - |> Maybe.withDefault (Html.text "") diff --git a/examples/jangle/src/Utils/README.md b/examples/jangle/src/Utils/README.md deleted file mode 100644 index c0764a9c..00000000 --- a/examples/jangle/src/Utils/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# src/Utils -> Helpful modules around data structures diff --git a/examples/jangle/src/Utils/Time.elm b/examples/jangle/src/Utils/Time.elm deleted file mode 100644 index c61e14bd..00000000 --- a/examples/jangle/src/Utils/Time.elm +++ /dev/null @@ -1,17 +0,0 @@ -module Utils.Time exposing (format) - -import DateFormat -import Time - - -format : Time.Posix -> String -format = - DateFormat.format - [ DateFormat.monthNameFull - , DateFormat.text " " - - -- , DateFormat.dayOfMonthSuffix - -- , DateFormat.text ", " - , DateFormat.yearNumber - ] - Time.utc diff --git a/examples/jangle/tests/Program/NotFound.elm b/examples/jangle/tests/Program/NotFound.elm deleted file mode 100644 index bdbb20ab..00000000 --- a/examples/jangle/tests/Program/NotFound.elm +++ /dev/null @@ -1,24 +0,0 @@ -module Program.NotFoundTest exposing (all) - -import Pages.NotFound as Page -import ProgramTest exposing (ProgramTest, expectViewHas) -import Program.Utils.Spa -import Test exposing (..) -import Test.Html.Selector exposing (text) - - -start : ProgramTest Page.Model Page.Msg (Cmd Page.Msg) -start = - Program.Utils.Spa.createStaticPage - { view = Page.view - } - - -all : Test -all = - describe "Pages.NotFound" - [ test "should say page not found" <| - \() -> - start - |> expectViewHas [ text "Page not found" ] - ] diff --git a/examples/jangle/tests/Program/README.md b/examples/jangle/tests/Program/README.md deleted file mode 100644 index 3a1b4e1a..00000000 --- a/examples/jangle/tests/Program/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# tests/Program -> Write tests for pages \ No newline at end of file diff --git a/examples/jangle/tests/Program/Top.elm b/examples/jangle/tests/Program/Top.elm deleted file mode 100644 index 5006d6a5..00000000 --- a/examples/jangle/tests/Program/Top.elm +++ /dev/null @@ -1,24 +0,0 @@ -module Program.TopTest exposing (all) - -import Pages.Top as Page -import ProgramTest exposing (ProgramTest, expectViewHas) -import Program.Utils.Spa -import Test exposing (..) -import Test.Html.Selector exposing (text) - - -start : ProgramTest Page.Model Page.Msg (Cmd Page.Msg) -start = - Program.Utils.Spa.createStaticPage - { view = Page.view - } - - -all : Test -all = - describe "Pages.Top" - [ test "should say homepage" <| - \() -> - start - |> expectViewHas [ text "Homepage" ] - ] diff --git a/examples/jangle/tests/Program/Utils/Spa.elm b/examples/jangle/tests/Program/Utils/Spa.elm deleted file mode 100644 index 6274182f..00000000 --- a/examples/jangle/tests/Program/Utils/Spa.elm +++ /dev/null @@ -1,54 +0,0 @@ -module Program.Utils.Spa exposing - ( createElementPage - , createSandboxPage - , createStaticPage - ) - -import ProgramTest exposing (ProgramTest) -import Spa.Document exposing (Document) -import Spa.Url exposing (Url) - - -createStaticPage : - { view : Document msg - } - -> ProgramTest () msg (Cmd msg) -createStaticPage page = - ProgramTest.createDocument - { init = \_ -> ( (), Cmd.none ) - , update = \_ model -> ( model, Cmd.none ) - , view = \_ -> page.view |> Spa.Document.toBrowserDocument - } - |> ProgramTest.start () - - -createSandboxPage : - { init : model - , update : msg -> model -> model - , view : model -> Document msg - } - -> ProgramTest model msg (Cmd msg) -createSandboxPage page = - ProgramTest.createDocument - { init = \_ -> ( page.init, Cmd.none ) - , update = \msg model -> ( page.update msg model, Cmd.none ) - , view = page.view >> Spa.Document.toBrowserDocument - } - |> ProgramTest.start () - - -createElementPage : - Url params - -> - { init : Url params -> ( model, Cmd msg ) - , update : msg -> model -> ( model, Cmd msg ) - , view : model -> Document msg - } - -> ProgramTest model msg (Cmd msg) -createElementPage params page = - ProgramTest.createDocument - { init = page.init - , update = page.update - , view = page.view >> Spa.Document.toBrowserDocument - } - |> ProgramTest.start params diff --git a/examples/jangle/tests/README.md b/examples/jangle/tests/README.md deleted file mode 100644 index a7e8f8ce..00000000 --- a/examples/jangle/tests/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# tests -> A place for function and program tests \ No newline at end of file diff --git a/examples/jangle/tests/Unit/README.md b/examples/jangle/tests/Unit/README.md deleted file mode 100644 index 2f5f4126..00000000 --- a/examples/jangle/tests/Unit/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# tests/Unit -> Write tests for functions \ No newline at end of file