reorganize docs site, simplify type alias with 6.0.8--beta

This commit is contained in:
Ryan Haskell-Glatz 2021-02-21 15:38:21 -06:00
parent 19df55bd85
commit c2c77e9abf
52 changed files with 351 additions and 7588 deletions

View File

@ -1,4 +1,4 @@
# [![elm-spa](https://v6-elm-spa.netlify.app/images/outlined-to-edge.png)](https://elm-spa.dev)
# [![elm-spa](https://elm-spa.dev/images/outlined-to-edge.png)](https://elm-spa.dev)
# **Installation**

View File

@ -2,6 +2,13 @@
publish = "public"
command = "npm i elm-spa@beta && node scripts/generate-index.js && npx elm-spa build"
# Prevents missing markdown files from redirecting to index.html
[[redirects]]
from = "/content/*"
to = "/content/:splat"
status = 200
force = true
[[redirects]]
from = "/*"
to = "/index.html"

View File

@ -1,4 +1,4 @@
# Guide
# Docs
Welcome to __elm-spa__, a framework for building web applications with [Elm](https://elm-lang.org)!
If you are new to Elm, you should check out [the official guide](https://guide.elm-lang.org), which
@ -44,7 +44,7 @@ npx elm-spa server
So far, we've used [npx](https://www.npmjs.com/package/npx) so we don't need to install __elm-spa__ directly. If you'd like to run commands from the terminal, without the `npx` prefix, you can install __elm-spa__ like this:
```terminal
npm install -g elm-spa@next
npm install -g elm-spa@latest
```
You can verify the install succeeded by running `elm-spa help` from your terminal:
@ -61,11 +61,11 @@ elm-spa build . . . . . one-time production build
elm-spa watch . . . . . . runs build as you code
elm-spa server . . . . . start a live dev server
Visit https://next.elm-spa.dev for more!
Visit https://elm-spa.dev for more!
```
---
__Ready for more?__
Let's check out [the CLI](/guide/cli) to learn more about those five commands!
Let's check out [the CLI](/docs/cli) to learn more about those five commands!

View File

@ -3,16 +3,16 @@
At the end of the last section, we installed the __elm-spa__ CLI using [npm](https://npmjs.org) like this:
```terminal
npm install -g elm-spa@next
npm install -g elm-spa@latest
```
This gave us the ability to run a few commands:
1. __[`elm-spa new`](#elm-spa-new)__ - creates a new project
1. __[`elm-spa server`](#elm-spa-server)__ - runs a dev server as you code
1. __[`elm-spa watch`](#elm-spa-watch)__ - builds as you code
1. __[`elm-spa build`](#elm-spa-build)__ - one-time production build
1. __[`elm-spa add`](#elm-spa-add)__ - adds a page to an existing project
1. [__elm-spa new__](#elm-spa-new) - creates a new project
1. [__elm-spa server__](#elm-spa-server) - runs a dev server as you code
1. [__elm-spa watch__](#elm-spa-watch) - builds as you code
1. [__elm-spa build__](#elm-spa-build) - one-time production build
1. [__elm-spa add__](#elm-spa-add) - adds a page to an existing project
What do these do? This section of the guide dives into more detail on each command!
@ -57,7 +57,7 @@ If you want the automatic compilation on change, but don't need a HTTP server, y
elm-spa watch
```
This will automatically generate and compile on save, but without the server. This is a great choice when combining __elm-spa__ with another tool like [Parcel](https://parceljs.org/elm.html)
This will automatically generate code and compile your Elm files on save, but without the server. This is a great command to combine __elm-spa__ with another tool like [Parcel](https://parceljs.org/elm.html).
## elm-spa build

View File

@ -13,11 +13,11 @@ view =
}
```
This homepage renders the tab `title`, and a HTML `body` onto the page. This is great when you have a static page that just needs to render some elements.
This homepage renders the tab `title`, and a HTML `body` onto the page. This is great when you have a static page that just needs to render some HTML.
Because the file is named `Home_.elm`, we know it's the homepage. These 8 lines of code are all we need to tell __elm-spa__ we'd like to render this when users visit the homepage.
For real world applications, we'll need pages that can do more. That's where the `Page` module comes in handy.
For real world applications, our pages will need to do more than print "Hello, world!". Let's upgrade!
### Upgrading "Hello World!"
@ -26,13 +26,12 @@ Let's start by introducing the `page` function, marking the start of our journey
```elm
module Pages.Home_ exposing (page)
-- our other imports
import Html
import Page exposing (Page)
import Request exposing (Request)
import Shared
page :
Shared.Model
-> Request Params
-> Page () Never
page : Shared.Model -> Request -> Page
page shared req =
Page.static
{ view = view
@ -46,13 +45,13 @@ view =
Here, our code hasn't changed very much- except now we have this new `page` function that:
1. Takes in two inputs: `Shared.Model` and `Request Params`
2. Returns a `Page () Never` value.
3. Is exposed at the top of our `Pages.Home_` module.
1. Accepts two inputs: `Shared.Model` and `Request`
2. Returns a `Page` value
3. Has been __exposed__ at the top of the file
> Without exposing `page`, __elm-spa__ will not understand how to compile your application. Make sure to _always_ expose `page` from modules within the `src/Pages` folder.
> Exposing `page` from this module lets __elm-spa__ know to use it instead of the plain `view` function from before.
This new `page` will always get the latest `Shared.Model` and URL information, which means you don't have to worry about tracking that stuff yourself.
This new `page` will always get the latest `Shared.Model` and a `Request` value (that contains URL information).
This is great, but there is still more that our `page` function can do other than render a view!
@ -152,28 +151,50 @@ Notice how the type annotations of `init` and `update` changed to accept their i
## Page.static
```elm
module Pages.Example exposing (page)
```
```elm
Page.static
{ view : View Never
{ view = view
}
```
```elm
view : View Never
```
( video introducing concept )
## Page.sandbox
```elm
module Pages.Example exposing (Model, Msg, page)
```
```elm
Page.sandbox
{ init : Model
, update : Msg -> Model -> Model
, view : Model -> View Msg
{ init = init
, update = update
, view = view
}
```
```elm
init : Model
update : Msg -> Model -> Model
view : Model -> View Msg
```
( video introducing concept )
## Page.element
```elm
module Pages.Example exposing (Model, Msg, page)
```
```elm
Page.element
{ init : ( Model, Cmd Msg )
@ -187,6 +208,10 @@ Page.element
## Page.advanced
```elm
module Pages.Example exposing (Model, Msg, page)
```
```elm
Page.advanced
{ init : ( Model, Effect Msg )

View File

@ -1,6 +1,6 @@
# Requests
Every URL that a user visits in your application contains useful information. When __elm-spa__ gets an updated URL, it passes that information to every [Page](/guide/pages) as a `Request` value.
Every URL that a user visits in your application contains useful information. When __elm-spa__ gets an updated URL, it passes that information to every [Page](/docs/pages) as a `Request` value.
This section of the guide breaks down the [Request](https://package.elm-lang.org/packages/ryannhg/elm-spa/latest/ElmSpa-Request) type exposed by the official Elm package:
@ -17,7 +17,7 @@ type alias Request params =
## URL Parameters
Every request has parameters that you can rely on. If you are on a [dynamic route](/guide/routing#dynamic-routes), you have access to that route's URL parameters:
Every request has parameters that you can rely on. If you are on a [dynamic route](/docs/routing#dynamic-routes), you have access to that route's URL parameters:
URL | Params
--- | ---
@ -36,7 +36,7 @@ greet req =
"Hello, " ++ req.params.name ++ "!"
```
__Note:__ When working with [shared state](/guide/shared-state), all requests are `Request ()`.
__Note:__ When working with [shared state](/docs/shared-state), all requests are `Request ()`.
## Query Parameters

View File

@ -16,7 +16,7 @@ In this section, we'll cover the 3 kinds of routes you can find in an __elm-spa_
## The homepage
The `src/Pages/Home_.elm` is a reserved filename that handles requests to /. The easiest way to make a new homepage is with the [`add` command](/guide/cli#adding-a-homepage) covered in the CLI section:
The `src/Pages/Home_.elm` is a reserved filename that handles requests to /. The easiest way to make a new homepage is with the [`add` command](/docs/cli#adding-a-homepage) covered in the CLI section:
```terminal
elm-spa add /
@ -78,7 +78,7 @@ The __trailing underscore__ at the end of the filename (`Name_.elm`) indicates t
The name of the route parameter variable (`name` in this example) is determined by the name of the file! If we named the file `Id_.elm`, the dynamic value would be available at `params.id` instead.
Every page gets access to these dynamic parameters, via the [`Request params`](/guide/pages#requests) value passed in. We'll cover that in the next section!
Every page gets access to these dynamic parameters, via the [`Request params`](/docs/pages#requests) value passed in. We'll cover that in the next section!
### Nested dynamic routes

View File

@ -1,4 +1,4 @@
# Shared State
# Shared state
With __elm-spa__, every time you navigate from one page to another, the `init` function for that page is called. This means that the `Model` for the page you we're previously looking at has been cleared out. Most of the time, that's a good thing!
@ -22,7 +22,7 @@ init : Flags -> Request () -> Model -> ( Model, Effect Msg )
The `init` function is called when your page loads for the first time. It takes in two inputs:
- `Flags` - initial JSON value passed in from `public/main.js
- `Request ()` - a [Request](/guide/request) value with the current URL information
- `Request ()` - a [Request](/docs/request) value with the current URL information
The `init` function returns the initial `Model`, as well as any `Effect`s you'd like to run (like initial HTTP requests, etc)

View File

@ -1 +1,7 @@
# Examples
# Examples
Here are real-world applications using __elm-spa__:
- This site
- Realworld example app
- User featured projects

View File

@ -1 +0,0 @@
# User Authentication

View File

@ -0,0 +1 @@
# Guides

View File

@ -0,0 +1 @@
# Getting started

View File

@ -0,0 +1 @@
# Page transitions

View File

@ -0,0 +1,3 @@
# Local storage
TODO

View File

@ -0,0 +1,3 @@
# User authentication
TODO

View File

@ -0,0 +1 @@
# Using Elm UI

View File

@ -0,0 +1 @@
# Testing

View File

@ -16,7 +16,7 @@
--color--green: #407742;
--color--green-light: #d7ead8;
--size--h1: 4em;
--size--h1: 3em;
--size--h2: 2em;
--size--h3: 1.5em;
--size--h4: 1.2em;
@ -64,6 +64,16 @@ pre {
background-color: white;
}
.aside {
white-space: nowrap;
}
.table-of-contents {
min-width: 14em;
max-width: 14em;
white-space: nowrap;
}
main {
animation: fadeIn 200ms 400ms ease-in forwards;
opacity: 0;
@ -163,12 +173,14 @@ hr { border: 0; }
line-height: 1.4;
}
.markdown p code {
.markdown p code,
.markdown li code {
font-size: 0.92em;
color: var(--color--green);
}
.markdown p code::before { content: '`'; opacity: 0.75; pointer-events: none; user-select: none; }
.markdown p code::after { content: '`'; opacity: 0.75; pointer-events: none; user-select: none; }
.markdown p code::before, .markdown li code::before { content: '`'; opacity: 0.75; pointer-events: none; user-select: none; }
.markdown p code::after, .markdown li code::after { content: '`'; opacity: 0.75; pointer-events: none; user-select: none; }
.markdown blockquote {
padding-left: 1rem;
@ -243,9 +255,7 @@ hr { border: 0; }
}
.markdown th,
.markdown td {
padding: 0.75em;
}
.markdown td { padding: 0.75em }
.markdown tbody tr:nth-child(2n + 1) {
background-color: var(--color--grey-100);

View File

@ -6,6 +6,10 @@ const config = {
output: path.join(__dirname, '..', 'public', 'dist')
}
// Terminal color output
const green = ``
const reset = ``
// Recursively lists all files in the given folder
const listContainedFiles = async (folder) => {
let files = []
@ -54,7 +58,7 @@ const main = () =>
await fs.mkdir(config.output, { recursive: true })
return fs.writeFile(path.join(config.output, 'flags.js'), contents, { encoding: 'utf-8' })
})
.then(_ => console.info(`\n ✓ Indexed the content folder\n`))
.then(_ => console.info(`\n ${green}${reset} Indexed the content folder\n`))
.catch(console.error)
// Run the program

View File

@ -106,7 +106,8 @@ sections : Index -> List Section
sections index =
let
sectionOrder =
[ "Guide"
[ "Docs"
, "Guides"
, "Examples"
]

View File

@ -145,6 +145,6 @@ subscriptions model =
-- REQUESTS
request : { model | url : Url, key : Key } -> Request ()
request : { model | url : Url, key : Key } -> Request
request model =
Request.create () model.url model.key

19
docs/src/Pages/Docs.elm Normal file
View File

@ -0,0 +1,19 @@
module Pages.Docs exposing (Model, Msg, page)
import Page
import Request
import Shared
import UI.Docs
page : Shared.Model -> Request.With params -> Page.With Model Msg
page =
UI.Docs.page
type alias Model =
UI.Docs.Model
type alias Msg =
UI.Docs.Msg

View File

@ -0,0 +1,19 @@
module Pages.Docs.Section_ exposing (Model, Msg, page)
import Page
import Request
import Shared
import UI.Docs
page : Shared.Model -> Request.With params -> Page.With Model Msg
page =
UI.Docs.page
type alias Model =
UI.Docs.Model
type alias Msg =
UI.Docs.Msg

View File

@ -1,12 +1,12 @@
module Pages.Examples exposing (Model, Msg, page)
import Page exposing (Page)
import Request exposing (Request)
import Page
import Request
import Shared
import UI.Docs
page : Shared.Model -> Request params -> Page Model Msg
page : Shared.Model -> Request.With params -> Page.With Model Msg
page =
UI.Docs.page

View File

@ -1,19 +0,0 @@
module Pages.Examples.Section_ exposing (Model, Msg, page)
import Page exposing (Page)
import Request exposing (Request)
import Shared
import UI.Docs
page : Shared.Model -> Request params -> Page Model Msg
page =
UI.Docs.page
type alias Model =
UI.Docs.Model
type alias Msg =
UI.Docs.Msg

View File

@ -1,19 +0,0 @@
module Pages.Guide exposing (Model, Msg, page)
import Page exposing (Page)
import Request exposing (Request)
import Shared
import UI.Docs
page : Shared.Model -> Request params -> Page Model Msg
page =
UI.Docs.page
type alias Model =
UI.Docs.Model
type alias Msg =
UI.Docs.Msg

View File

@ -1,19 +0,0 @@
module Pages.Guide.Section_ exposing (Model, Msg, page)
import Page exposing (Page)
import Request exposing (Request)
import Shared
import UI.Docs
page : Shared.Model -> Request params -> Page Model Msg
page =
UI.Docs.page
type alias Model =
UI.Docs.Model
type alias Msg =
UI.Docs.Msg

19
docs/src/Pages/Guides.elm Normal file
View File

@ -0,0 +1,19 @@
module Pages.Guides exposing (Model, Msg, page)
import Page
import Request
import Shared
import UI.Docs
page : Shared.Model -> Request.With params -> Page.With Model Msg
page =
UI.Docs.page
type alias Model =
UI.Docs.Model
type alias Msg =
UI.Docs.Msg

View File

@ -0,0 +1,19 @@
module Pages.Guides.Section_ exposing (Model, Msg, page)
import Page
import Request
import Shared
import UI.Docs
page : Shared.Model -> Request.With params -> Page.With Model Msg
page =
UI.Docs.page
type alias Model =
UI.Docs.Model
type alias Msg =
UI.Docs.Msg

View File

@ -1,15 +1,15 @@
module Pages.Home_ exposing (Model, Msg, page)
import Gen.Params.Home_ exposing (Params)
import Page exposing (Page)
import Request exposing (Request)
import Page
import Request
import Shared
import UI
import UI.Layout
import View exposing (View)
page : Shared.Model -> Request Params -> Page Model Msg
page : Shared.Model -> Request.With Params -> Page.With Model Msg
page =
UI.Layout.page
{ view = view
@ -36,7 +36,7 @@ view =
## Build reliable applications.
I need to verify that the line height for paragraphs is reasonable, because if it isn't then I'll need to tweak it a bit until it's actually readable.
Only the most readable lines should be included in the __official__ [guide](/guide), ya dig?
Only the most readable lines should be included in the __official__ [guide](/docs), ya dig?
Bippity boppity, my guy.

View File

@ -1,15 +1,15 @@
module Pages.NotFound exposing (Model, Msg, page)
import Gen.Params.NotFound exposing (Params)
import Page exposing (Page)
import Request exposing (Request)
import Page
import Request
import Shared
import UI
import UI.Layout
import View exposing (View)
page : Shared.Model -> Request Params -> Page Model Msg
page : Shared.Model -> Request.With Params -> Page.With Model Msg
page =
UI.Layout.page
{ view = view

View File

@ -36,7 +36,7 @@ type Msg
-- INIT
init : Request () -> Flags -> ( Model, Cmd Msg )
init : Request -> Flags -> ( Model, Cmd Msg )
init _ flags =
( Model
(flags
@ -51,7 +51,7 @@ init _ flags =
-- UPDATE
update : Request () -> Msg -> Model -> ( Model, Cmd Msg )
update : Request -> Msg -> Model -> ( Model, Cmd Msg )
update request msg model =
case msg of
NoOp ->
@ -62,6 +62,6 @@ update request msg model =
-- SUBSCRIPTIONS
subscriptions : Request () -> Model -> Sub Msg
subscriptions : Request -> Model -> Sub Msg
subscriptions request model =
Sub.none

View File

@ -1,8 +1,8 @@
module UI.Docs exposing (Model, Msg, page)
import Http
import Page exposing (Page)
import Request exposing (Request)
import Page
import Request
import Shared
import UI
import UI.Layout
@ -10,7 +10,7 @@ import Url exposing (Url)
import View exposing (View)
page : Shared.Model -> Request params -> Page Model Msg
page : Shared.Model -> Request.With params -> Page.With Model Msg
page shared req =
Page.element
{ init = init req.url

View File

@ -13,6 +13,7 @@ module UI.Layout exposing
-}
import Gen.Route as Route exposing (Route)
import Html exposing (Html)
import Html.Attributes as Attr
import Page exposing (Page)
@ -72,9 +73,9 @@ viewDocumentation :
-> List (Html msg)
viewDocumentation options markdownContent view =
[ navbar options
, Html.div [ Attr.class "container pad-lg" ]
[ UI.row.lg [ UI.align.top, UI.padY.lg ]
[ Html.aside [ Attr.class "only-desktop sticky pad-y-lg", Attr.style "width" "13em" ]
, Html.div [ Attr.class "container pad-md" ]
[ UI.row.xl [ UI.align.top, UI.padY.lg ]
[ Html.aside [ Attr.class "only-desktop sticky pad-y-lg aside" ]
[ UI.Sidebar.viewSidebar
{ index = options.shared.index
, url = options.url
@ -83,7 +84,7 @@ viewDocumentation options markdownContent view =
, Html.main_ [ Attr.class "flex" ]
[ UI.row.lg [ UI.align.top ]
[ Html.div [ Attr.class "col flex" ] view
, Html.div [ Attr.class "hidden-mobile sticky pad-y-lg", Attr.style "width" "16em" ]
, Html.div [ Attr.class "hidden-mobile sticky pad-y-lg table-of-contents" ]
[ UI.Sidebar.viewTableOfContents
{ content = markdownContent
, url = options.url
@ -105,12 +106,12 @@ navbar :
-> Html msg
navbar { onMsg, model, shared, url } =
let
navLink : { text : String, url : String } -> Html msg
navLink : { text : String, route : Route } -> Html msg
navLink options =
Html.a
[ Attr.class "link"
, Attr.href options.url
, Attr.classList [ ( "bold text-blue", String.startsWith options.url url.path ) ]
, Attr.href (Route.toHref options.route)
, Attr.classList [ ( "bold text-blue", String.startsWith (Route.toHref options.route) url.path ) ]
]
[ Html.text options.text ]
in
@ -119,9 +120,9 @@ navbar { onMsg, model, shared, url } =
[ Html.div [ Attr.class "row align-center gap-md" ]
[ Html.a [ Attr.href "/" ] [ UI.logo ]
, Html.nav [ Attr.class "row gap-md hidden-mobile pad-left-xs" ]
[ navLink { text = "guide", url = "/guide" }
, navLink { text = "docs", url = "/docs" }
, navLink { text = "examples", url = "/examples" }
[ navLink { text = "docs", route = Route.Docs }
, navLink { text = "guides ", route = Route.Guides }
, navLink { text = "examples", route = Route.Examples }
]
]
, Html.div [ Attr.class "row gap-md spread" ]
@ -144,7 +145,7 @@ navbar { onMsg, model, shared, url } =
-- PAGE
page : { view : View Msg } -> Shared.Model -> Request params -> Page Model Msg
page : { view : View Msg } -> Shared.Model -> Request.With params -> Page.With Model Msg
page options shared req =
Page.sandbox
{ init = init

View File

@ -6,7 +6,7 @@
This project requires the latest LTS version of [Node.js](https://nodejs.org/)
```bash
npm install -g elm elm-spa
npm install -g elm-spa@latest
```
## running locally

View File

@ -9,7 +9,7 @@ module ElmSpa.Page exposing
# **( These docs are for CLI contributors )**
### If you are using **elm-spa**, check out [the official guide](https://v6.elm-spa.dev/guide) instead!
### If you are using **elm-spa**, check out [the official guide](https://elm-spa.dev/guide) instead!
---

View File

@ -6,7 +6,7 @@ module ElmSpa.Request exposing (Request, create)
# **( These docs are for CLI contributors )**
### If you are using **elm-spa**, check out [the official guide](https://v6.elm-spa.dev/guide) instead!
### If you are using **elm-spa**, check out [the official guide](https://elm-spa.dev/guide) instead!
---

7373
src/cli/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "elm-spa",
"version": "6.0.7--beta",
"version": "6.0.8--beta",
"description": "single page apps made easy",
"bin": "dist/src/index.js",
"scripts": {
@ -45,4 +45,4 @@
"terser": "5.3.8",
"websocket": "1.0.32"
}
}
}

View File

@ -19,5 +19,5 @@ ${bold(`elm-spa ${cyan(`build`)}`)} . . . . . . one-time production build
${bold(`elm-spa ${cyan(`watch`)}`)} . . . . . . . runs build as you code
${bold(`elm-spa ${cyan(`server`)}`)} . . . . . . start a live dev server
Visit ${green(`https://next.elm-spa.dev`)} for more!
Visit ${green(`https://elm-spa.dev`)} for more!
`

View File

@ -1,13 +1,14 @@
module Page exposing
( Page
( Page, With
, static, sandbox, element, advanced
, protected
)
{-|
@docs Page
@docs Page, With
@docs static, sandbox, element, advanced
@docs protected
-}
@ -20,6 +21,58 @@ import View exposing (View)
-- PAGES
type alias Page =
With () Never
type alias With model msg =
ElmSpa.Page Shared.Model Route (Effect msg) (View msg) model msg
static :
{ view : View Never
}
-> Page
static =
ElmSpa.static Effect.none
sandbox :
{ init : model
, update : msg -> model -> model
, view : model -> View msg
}
-> With model msg
sandbox =
ElmSpa.sandbox Effect.none
element :
{ init : ( model, Cmd msg )
, update : msg -> model -> ( model, Cmd msg )
, view : model -> View msg
, subscriptions : model -> Sub msg
}
-> With model msg
element =
ElmSpa.element Effect.fromCmd
advanced :
{ init : ( model, Effect msg )
, update : msg -> model -> ( model, Effect msg )
, view : model -> View msg
, subscriptions : model -> Sub msg
}
-> With model msg
advanced =
ElmSpa.advanced
-- PROTECTED PAGES
@ -41,84 +94,36 @@ Here, you can provide logic on where to redirect if a user is not signed in. Her
ElmSpa.RedirectTo Gen.Route.SignIn
-}
beforeProtectedInit : Shared.Model -> Request () -> ElmSpa.Protected User Route
beforeProtectedInit : Shared.Model -> Request -> ElmSpa.Protected User Route
beforeProtectedInit shared req =
ElmSpa.RedirectTo Gen.Route.NotFound
-- PAGES
type alias Page model msg =
ElmSpa.Page Shared.Model Route (Effect msg) (View msg) model msg
static :
{ view : View Never
}
-> Page () Never
static =
ElmSpa.static Effect.none
sandbox :
{ init : model
, update : msg -> model -> model
, view : model -> View msg
}
-> Page model msg
sandbox =
ElmSpa.sandbox Effect.none
element :
{ init : ( model, Cmd msg )
, update : msg -> model -> ( model, Cmd msg )
, view : model -> View msg
, subscriptions : model -> Sub msg
}
-> Page model msg
element =
ElmSpa.element Effect.fromCmd
advanced :
{ init : ( model, Effect msg )
, update : msg -> model -> ( model, Effect msg )
, view : model -> View msg
, subscriptions : model -> Sub msg
}
-> Page model msg
advanced =
ElmSpa.advanced
protected :
{ static :
{ view : User -> View msg
}
-> Page () msg
-> With () msg
, sandbox :
{ init : User -> model
, update : User -> msg -> model -> model
, view : User -> model -> View msg
}
-> Page model msg
-> With model msg
, element :
{ init : User -> ( model, Cmd msg )
, update : User -> msg -> model -> ( model, Cmd msg )
, view : User -> model -> View msg
, subscriptions : User -> model -> Sub msg
}
-> Page model msg
-> With model msg
, advanced :
{ init : User -> ( model, Effect msg )
, update : User -> msg -> model -> ( model, Effect msg )
, view : User -> model -> View msg
, subscriptions : User -> model -> Sub msg
}
-> Page model msg
-> With model msg
}
protected =
ElmSpa.protected2

View File

@ -3,6 +3,6 @@ module Pages.NotFound exposing (view)
import View exposing (View)
view : View Never
view : View msg
view =
View.placeholder "Page not found."

View File

@ -1,4 +1,16 @@
module Request exposing (Request, create, pushRoute, replaceRoute)
module Request exposing
( Request, With
, create
, pushRoute, replaceRoute
)
{-|
@docs Request, With
@docs create
@docs pushRoute, replaceRoute
-}
import Browser.Navigation exposing (Key)
import ElmSpa.Request as ElmSpa
@ -6,20 +18,24 @@ import Gen.Route as Route exposing (Route)
import Url exposing (Url)
type alias Request params =
type alias Request =
With ()
type alias With params =
ElmSpa.Request Route params
create : params -> Url -> Key -> Request params
create : params -> Url -> Key -> With params
create params url key =
ElmSpa.create (Route.fromUrl url) params url key
pushRoute : Route -> Request params -> Cmd msg
pushRoute : Route -> With params -> Cmd msg
pushRoute route req =
Browser.Navigation.pushUrl req.key (Route.toHref route)
replaceRoute : Route -> Request params -> Cmd msg
replaceRoute : Route -> With params -> Cmd msg
replaceRoute route req =
Browser.Navigation.replaceUrl req.key (Route.toHref route)

View File

@ -23,18 +23,18 @@ type Msg
= NoOp
init : Request () -> Flags -> ( Model, Cmd Msg )
init : Request -> Flags -> ( Model, Cmd Msg )
init _ _ =
( {}, Cmd.none )
update : Request () -> Msg -> Model -> ( Model, Cmd Msg )
update : Request -> Msg -> Model -> ( Model, Cmd Msg )
update _ msg model =
case msg of
NoOp ->
( model, Cmd.none )
subscriptions : Request () -> Model -> Sub Msg
subscriptions : Request -> Model -> Sub Msg
subscriptions _ _ =
Sub.none

View File

@ -4,7 +4,7 @@ import Html
import View exposing (View)
view : View Never
view : View msg
view =
{ title = "Homepage"
, body = [ Html.text "Hello, world!" ]

View File

@ -1,10 +1,10 @@
export default (page : string[]) : string => `
export default (page: string[]): string => `
module Pages.${page.join('.')} exposing (view)
import View exposing (View)
view : View Never
view : View msg
view =
View.placeholder "${page.join('.')}"

View File

@ -2,13 +2,14 @@ module Pages.{{module}} exposing (Model, Msg, page)
import Effect exposing (Effect)
import Gen.Params.{{module}} exposing (Params)
import Page exposing (Page)
import Request exposing (Request)
import Page
import Request
import Shared
import View exposing (View)
import Page
page : Shared.Model -> Request Params -> Page Model Msg
page : Shared.Model -> Request.With Params -> Page.With Model Msg
page shared req =
Page.advanced
{ init = init

View File

@ -1,13 +1,13 @@
module Pages.{{module}} exposing (Model, Msg, page)
import Gen.Params.{{module}} exposing (Params)
import Page exposing (Page)
import Request exposing (Request)
import Page
import Request
import Shared
import View exposing (View)
page : Shared.Model -> Request Params -> Page Model Msg
page : Shared.Model -> Request.With Params -> Page.With Model Msg
page shared req =
Page.element
{ init = init

View File

@ -1,13 +1,13 @@
module Pages.{{module}} exposing (Model, Msg, page)
import Gen.Params.{{module}} exposing (Params)
import Page exposing (Page)
import Request exposing (Request)
import Page
import Request
import Shared
import View exposing (View)
page : Shared.Model -> Request Params -> Page Model Msg
page : Shared.Model -> Request.With Params -> Page.With Model Msg
page shared req =
Page.sandbox
{ init = init

View File

@ -2,18 +2,18 @@ module Pages.{{module}} exposing (page)
import Gen.Params.{{module}} exposing (Params)
import Page exposing (Page)
import Request exposing (Request)
import Request
import Shared
import View exposing (View)
page : Shared.Model -> Request Params -> Page () Never
page : Shared.Model -> Request.With Params -> Page
page shared req =
Page.static
{ view = view
}
view : View Never
view : View msg
view =
View.placeholder "{{module}}"

View File

@ -1,6 +1,31 @@
import config from "../config"
import { routeTypeDefinition, indent, routeParserList, paramsImports, Options, routeToHref } from "./utils"
export default (pages : string[][], _options : Options) : string => `
const routeParserOrder = (pages: string[][]) =>
[...pages].sort(sorter)
const isHomepage = (list: string[]) => list.join('.') === config.reserved.homepage
const isDynamic = (piece: string) => piece.endsWith('_')
const alphaSorter = (a: string, b: string) => a < b ? -1 : b < a ? 1 : 0
const sorter = (a: string[], b: string[]): (-1 | 1 | 0) => {
if (isHomepage(a)) return -1
if (isHomepage(b)) return 1
if (a.length < b.length) return -1
if (a.length > b.length) return 1
for (let i in a) {
const [isA, isB] = [isDynamic(a[i]), isDynamic(b[i])]
if (isA && isB) return alphaSorter(a[i], b[i])
if (isA) return 1
if (isB) return -1
}
return 0
}
export default (pages: string[][], _options: Options): string => `
module Gen.Route exposing
( Route(..)
, fromUrl
@ -22,7 +47,7 @@ fromUrl =
routes : List (Parser (Route -> a) a)
routes =
${indent(routeParserList(pages), 1)}
${indent(routeParserList(routeParserOrder(pages)), 1)}
toHref : Route -> String