mirror of
https://github.com/ryannhg/elm-spa.git
synced 2024-11-22 09:44:55 +03:00
1 line
10 KiB
JSON
1 line
10 KiB
JSON
[{"name":"Spa","comment":" When you create an app with the [elm/browser](/packages/elm/browser/latest) package,\nyou can build anything from a static `Html msg` page to a fully-fledged web `Browser.application`.\n\n`elm-spa` uses the existing design at the page-level, so you can quickly add new pages to your Elm application!\n\n\n## the four kinds of pages:\n\n1. [static](#static-pages) – a page that only renders HTML.\n2. [sandbox](#sandbox-pages) – a page with state.\n3. [element](#element-pages) – a page with side-effects.\n4. [component](#component-pages) – a page with global state.\n\n\n# static pages\n\nJust like [Elm's intro \"Hello!\" example](https://elm-lang.org/examples/hello),\nsometimes you just want a page that renders some HTML, without having any state.\n\n@docs static\n\n**Note:** Static pages don't store data, so Model is always an empty tuple: ()\n\n\n# sandbox pages\n\nWhen you're ready to keep track of state, like in\n[Elm's \"Counter\" example](https://elm-lang.org/examples/buttons),\nyou can use a sandbox page.\n\nSimilar to `Browser.sandbox`, this allows you to init your model, and update it with messages!\n\n@docs sandbox\n\n\n# element pages\n\nIf you're ready to [send HTTP requests](https://elm-lang.org/examples/cat-gifs) or [listen to events](https://elm-lang.org/examples/time) for updates, it's time to upgrade to an element page!\n\nAdditionally, an element will give you access to Flags, so you can access things like URL parameters.\n\n@docs element\n\n**New to Cmd or Sub?** I recommend checking out Elm's official guide , that's a great place to wrap your head around these two concepts.\n\n\n# component pages\n\nIf you need to access shared state across all pages, or need to send a global commands like signing in/signing out a user, a component page is what you'll need.\n\nComponent pages gain access to the `Global.Model`, and return an additional `Cmd Global.Msg` so you can read/update the global state of your application.\n\n@docs component\n\n**Cool trick:** Don't need access to Global.Model in all of your functions? Use always to skip the first argument.\n\nIn the following example, only the view function receives Global.Model:\n\n import Global\n import Spa exposing (Page)\n\n page : Page Flags Model Msg Global.Model Global.Msg\n page =\n Spa.component\n { init = always init\n , update = always update\n , view = view -- not using \"always\"!\n , subscriptions = always subscriptions\n }\n\n\n# putting pages together\n\n**Note:** The [elm-spa cli tool](https://www.npmjs.com/package/elm-spa) will generate all the upcoming code\nfor you. You can continue reading to understand what it's doing under the hood!\n\n@docs Page\n\n\n## learning with an example\n\nLet's imagine we are building a website for a restaurant! This website has the following routes:\n\n1. `/home` - the homepage\n2. `/menu` - the menu\n3. `/faqs` - frequently asked questions\n\nWith `elm-spa` we'd create a module for each page, and import them together in one file.\n\n module Pages exposing (Model, Msg, init, update, view, subscriptions)\n\n import Pages.Home\n import Pages.Menu\n import Pages.Faqs\n\nIf we want to implement the `Pages.init` function, we'll need to return the same type of value. This means we need to make a shared model and a shared msg type to handle all the different pages in our application:\n\n type Model\n = Home_Model Pages.Home.Model\n | Menu_Model Pages.Menu.Model\n | Faqs_Model Pages.Faqs.Model\n\n type Msg\n = Home_Msg Pages.Home.Msg\n | Menu_Msg Pages.Menu.Msg\n | Faqs_Msg Pages.Faqs.Msg\n\nThese two types allow `init` to return `( Model, Cmd Msg, Cmd Global.Msg )` for any page that the user is looking at!\n\n\n## upgrading pages\n\nWith the custom types above:\n\n1. `Home_Model` can upgrade a `Pages.Home.Model` to a `Model`\n2. `Home_Msg` can upgrade a `Pages.Home.Msg` to a `Msg`\n\nWe use the upgrade function to return a record that makes writing the combined `init`/`update`/`view`/`subscriptions` functions clean and easy!\n\n@docs upgrade\n\n import Pages.Faqs\n import Pages.Home\n import Pages.Menu\n import Spa\n\n type alias UpgradedPage pageFlags pageModel pageMsg =\n { init : pageFlags -> Global.Model -> ( Model, Cmd Msg, Cmd Global.Msg )\n , update : pageMsg -> pageModel -> Global.Model -> ( Model, Cmd Msg, Cmd Global.Msg )\n , bundle : pageModel -> Global.Model -> Spa.Bundle Msg\n }\n\n type alias UpgradedPages =\n { home : UpgradedPage Pages.Home.Flags Pages.Home.Model Pages.Home.Msg\n , menu : UpgradedPage Pages.Menu.Flags Pages.Menu.Model Pages.Menu.Msg\n , faqs : UpgradedPage Pages.Faqs.Flags Pages.Faqs.Model Pages.Faqs.Msg\n }\n\n pages : UpgradedPages\n pages =\n { home = Pages.Home.page |> Spa.upgrade Home_Model Home_Msg\n , menu = Pages.Menu.page |> Spa.upgrade Menu_Model Menu_Msg\n , faqs = Pages.Faqs.page |> Spa.upgrade Faqs_Model Faqs_Msg\n }\n\nNow when we write `init`, we can use the upgraded `pages` variable to keep things easy to read.\n\n\n## implementing `init`\n\n import Route exposing (Route)\n\n init : Route -> Global.Model -> ( Model, Cmd Msg, Cmd Global.Msg )\n init route =\n case route of\n Route.Home ->\n pages.home.init ()\n\n Route.Menu ->\n pages.menu.init ()\n\n Route.Faqs ->\n pages.faqs.init ()\n\n\n## implementing `update`\n\n update : Msg -> Model -> Global.Model -> ( Model, Cmd Msg, Cmd Global.Msg )\n update bigMsg bigModel =\n case ( bigMsg, bigModel ) of\n ( Home_Msg msg, Home_Model model ) ->\n pages.home.update msg model\n\n ( Menu_Msg msg, Menu_Model model ) ->\n pages.menu.update msg model\n\n ( Faqs_Msg msg, Faqs_Model model ) ->\n pages.faqs.update msg model\n\n _ ->\n always ( bigModel, Cmd.none, Cmd.none )\n\n\n## implementing `bundle`\n\nWith `elm-spa`, we don't need to write out a case expression for both `view` and `subscriptions`.\nWe can just write one that bundles them together.\n\nWe can create `view` and `subscriptions` from this single function:\n\n@docs Bundle\n\n\n# that's it!\n\nYou can check out <https://elm-spa.dev> or join #elm-spa-users on the official Elm slack channel for any questions ❤️\n\n","unions":[],"aliases":[{"name":"Bundle","comment":"\n\n import Spa\n\n bundle : Model -> Global.Model -> Spa.Bundle Msg\n bundle bigModel =\n case bigModel of\n Home_Model model ->\n pages.home.bundle model\n\n Menu_Model model ->\n pages.menu.bundle model\n\n Faqs_Model model ->\n pages.faqs.bundle model\n\n view : Model -> Global.Model -> Document Msg\n view model =\n bundle model >> .view\n\n subscriptions : Model -> Global.Model -> Sub Msg\n subscriptions model =\n bundle model >> .subscriptions\n\n","args":["msg"],"type":"{ view : Browser.Document msg, subscriptions : Platform.Sub.Sub msg }"},{"name":"Page","comment":" What was the point of using the functions above? They all return the `Page` type,\nand we can use the `Spa.upgrade` function on any of them!\n\n(The following example will illustrate why that's a good thing)\n\n","args":["flags","model","msg","globalModel","globalMsg"],"type":"{ init : globalModel -> flags -> ( model, Platform.Cmd.Cmd msg, Platform.Cmd.Cmd globalMsg ), update : globalModel -> msg -> model -> ( model, Platform.Cmd.Cmd msg, Platform.Cmd.Cmd globalMsg ), view : globalModel -> model -> Browser.Document msg, subscriptions : globalModel -> model -> Platform.Sub.Sub msg }"}],"values":[{"name":"component","comment":"\n\n import Global\n import Spa exposing (Page)\n\n page : Page Flags Model Msg Global.Model Global.Msg\n page =\n Spa.component\n { init = init\n , update = update\n , view = view\n , subscriptions = subscriptions\n }\n\n","type":"{ init : globalModel -> flags -> ( model, Platform.Cmd.Cmd msg, Platform.Cmd.Cmd globalMsg ), update : globalModel -> msg -> model -> ( model, Platform.Cmd.Cmd msg, Platform.Cmd.Cmd globalMsg ), view : globalModel -> model -> Browser.Document msg, subscriptions : globalModel -> model -> Platform.Sub.Sub msg } -> Spa.Page flags model msg globalModel globalMsg"},{"name":"element","comment":"\n\n page : Page Flags Model Msg globalModel globalMsg\n page =\n Spa.element\n { init = init\n , update = update\n , view = view\n , subscriptions = subscriptions\n }\n\n","type":"{ init : flags -> ( model, Platform.Cmd.Cmd msg ), update : msg -> model -> ( model, Platform.Cmd.Cmd msg ), view : model -> Browser.Document msg, subscriptions : model -> Platform.Sub.Sub msg } -> Spa.Page flags model msg globalModel globalMsg"},{"name":"sandbox","comment":"\n\n import Spa exposing (Page)\n\n page : Page Flags Model Msg globalModel globalMsg\n page =\n Spa.sandbox\n { init = init\n , update = update\n , view = view\n }\n\n","type":"{ init : model, update : msg -> model -> model, view : model -> Browser.Document msg } -> Spa.Page flags model msg globalModel globalMsg"},{"name":"static","comment":"\n\n page : Page Flags Model Msg globalModel globalMsg\n page =\n Spa.static\n { view = view\n }\n\n","type":"{ view : Browser.Document msg } -> Spa.Page flags () msg globalModel globalMsg"},{"name":"upgrade","comment":" For each page we export from our `Pages.*` modules, we should call the `upgrade` function with the corresponding `Model` and `Msg` variants, like this:\n\n pages : UpgradedPages\n pages =\n { home = Pages.Home.page |> Spa.upgrade Home_Model Home_Msg\n , menu = Pages.Menu.page |> Spa.upgrade Menu_Model Menu_Msg\n , faqs = Pages.Faqs.page |> Spa.upgrade Faqs_Model Faqs_Msg\n }\n\n","type":"(pageModel -> model) -> (pageMsg -> msg) -> Spa.Page pageFlags pageModel pageMsg globalModel globalMsg -> { init : pageFlags -> globalModel -> ( model, Platform.Cmd.Cmd msg, Platform.Cmd.Cmd globalMsg ), update : pageMsg -> pageModel -> globalModel -> ( model, Platform.Cmd.Cmd msg, Platform.Cmd.Cmd globalMsg ), bundle : pageModel -> globalModel -> Spa.Bundle msg }"}],"binops":[]}] |