Last active
July 14, 2020 05:42
-
-
Save BraxtonI/1a9fc0c56a03254de908c97b6deb1250 to your computer and use it in GitHub Desktop.
Revisions
-
BraxtonI revised this gist
Jul 14, 2020 . 4 changed files with 52 additions and 60 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,14 @@ module Common exposing (urlPrefix, Photo) urlPrefix : String urlPrefix = "http://elm-in-action.com/" type alias Photo = { title : String , url : String , size : Int , relatedUrls : List String } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ module Main exposing (main) import Browser exposing (Document) import Browser.Navigation as Nav @@ -8,7 +8,7 @@ import Html.Lazy exposing (lazy) import PhotoFolders as Folders import PhotoGallery as Gallery import Url exposing (Url) import Url.Parser as Parser exposing ((</>), Parser, s) @@ -91,7 +91,7 @@ viewHeader page = links = ul [] [ navLink Folders { url = "/", caption = "Folders" } , navLink Gallery { url = "/gallery", caption = "Gallery" } ] This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,39 +1,40 @@ module PhotoFolders exposing (Model, Msg, update, view, init) import Common exposing (urlPrefix, Photo) import Dict exposing (Dict) import Html exposing (..) import Html.Attributes exposing (class, href, src) import Html.Events exposing (onClick) import Http import Json.Decode as Decode exposing (Decoder, int, list, string) import Json.Decode.Pipeline exposing (required) type Folder = Folder { name : String , photoUrls : List String , subfolders : List Folder , expanded : Bool } type alias Model = { selectedPhotoUrl : Maybe String , photos : Dict String Photo , root : Folder } initialModel : Model initialModel = { selectedPhotoUrl = Nothing , photos = Dict.empty , root = Folder { name = "Loading..." , expanded = True , photoUrls = [] , subfolders = [] } } @@ -61,7 +62,7 @@ modelDecoder = type Msg = SelectPhotoUrl String | LoadPage (Result Http.Error Model) | ToggleExpanded FolderPath @@ -106,14 +107,6 @@ view model = ] viewPhoto : String -> Html Msg viewPhoto url = a [ href ("/photos/" ++ url), class "photo", onClick (SelectPhotoUrl url) ] @@ -160,7 +153,7 @@ viewFolder path (Folder folder) = contents = List.append (List.indexedMap viewSubfolder folder.subfolders) (List.map viewPhoto folder.photoUrls) in div [ class "folder expanded" ] [ folderLabel @@ -180,11 +173,6 @@ appendIndex index path = Subfolder subfolderIndex (appendIndex index remainingPath) type FolderPath = End | Subfolder Int FolderPath @@ -215,26 +203,26 @@ toggleExpanded path (Folder folder) = type alias JsonPhoto = { title : String , size : Int , relatedUrls : List String } jsonPhotoDecoder : Decoder JsonPhoto jsonPhotoDecoder = Decode.succeed JsonPhoto |> required "title" string |> required "size" int |> required "related_photos" (list string) finishPhoto : ( String, JsonPhoto ) -> ( String, Photo ) finishPhoto ( url, json ) = ( url , { url = url , size = json.size , title = json.title , relatedUrls = json.relatedUrls } ) @@ -264,17 +252,17 @@ folderDecoder = folderFromJson : String -> Dict String Photo -> List Folder -> Folder folderFromJson name photos subfolders = Folder { name = name , expanded = True , subfolders = subfolders , photoUrls = Dict.keys photos } modelPhotosDecoder : Decoder (Dict String Photo) modelPhotosDecoder = Decode.succeed modelPhotosFromJson |> required "photos" photosDecoder |> required "subfolders" (Decode.lazy (\_ -> list modelPhotosDecoder)) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,7 @@ port module PhotoGallery exposing (init, Model, Msg, subscriptions, update, view, reload) import Browser import Common exposing (urlPrefix, Photo) import Html exposing (..) import Html.Attributes as Attr exposing (checked, class, classList, id, name, src, title, type_) import Html.Events exposing (on, onClick) @@ -60,11 +61,6 @@ initialModel = type Msg = ClickedPhoto String | ClickedSize ThumbnailSize @@ -167,19 +163,13 @@ type alias FilterOptions = } photoDecoder : Decoder Photo photoDecoder = succeed Photo |> optional "title" string "(untitled)" |> required "url" string |> required "size" int |> optional "requiredUrl" (list string) [] type Status -
BraxtonI revised this gist
Jul 13, 2020 . 4 changed files with 665 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,60 @@ <!doctype html> <html> <head> <link rel="stylesheet" href="http://elm-in-action.com/styles.css"> <link rel="stylesheet" href="http://elm-in-action.com/range-slider.css"> <script src="http://elm-in-action.com/range-slider.js"></script> <script> class RangeSlider extends HTMLElement { connectedCallback() { var input = document.createElement("input"); this.appendChild(input); var jsr = new JSR(input, { max: this.max, values: [this.val], sliders: 1, grid: false }); var rangeSliderNode = this; jsr.addEventListener("update", function(elem, value) { var event = new CustomEvent("slide", { detail: {userSlidTo: value} }); rangeSliderNode.dispatchEvent(event); }); } } window.customElements.define("range-slider", RangeSlider); </script> </head> <body> <div id="app"></div> <script src="http://elm-in-action.com/pasta.js"></script> <script src="app.js"></script> <script> var app = Elm.Main.init({node: document.getElementById("app"), flags: Pasta.version}); app.ports.setFilters.subscribe(function(options) { requestAnimationFrame(function() { Pasta.apply(document.getElementById("main-canvas"), options); }); }); Pasta.addActivityListener(function(activity) { console.log("Got some activity to send to Elm:", activity); app.ports.activityChanges.send(activity); }); </script> </body> </html> File renamed without changes.This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,286 @@ module PhotoFolders exposing (Model, Msg, update, view, init) import Dict exposing (Dict) import Html exposing (..) import Html.Attributes exposing (class, href, src) import Html.Events exposing (onClick) import Http import Json.Decode as Decode exposing (Decoder, int, list, string) import Json.Decode.Pipeline exposing (required) type Folder = Folder { name : String , photoUrls : List String , subfolders : List Folder , expanded : Bool } type alias Model = { selectedPhotoUrl : Maybe String , photos : Dict String Photo , root : Folder } initialModel : Model initialModel = { selectedPhotoUrl = Nothing , photos = Dict.empty , root = Folder { name = "Loading..." , expanded = True , photoUrls = [] , subfolders = [] } } init : Maybe String -> ( Model, Cmd Msg ) init selectedFilename = ( { initialModel | selectedPhotoUrl = selectedFilename } , Http.get { url = "http://elm-in-action.com/folders/list" , expect = Http.expectJson LoadPage modelDecoder } ) modelDecoder : Decoder Model modelDecoder = Decode.map2 (\photos root -> { photos = photos, root = root, selectedPhotoUrl = Nothing } ) modelPhotosDecoder folderDecoder type Msg = SelectPhotoUrl String | LoadPage (Result Http.Error Model) | ToggleExpanded FolderPath update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of ToggleExpanded path -> ( { model | root = toggleExpanded path model.root }, Cmd.none ) SelectPhotoUrl url -> ( { model | selectedPhotoUrl = Just url }, Cmd.none ) LoadPage (Ok newModel) -> ( { newModel | selectedPhotoUrl = model.selectedPhotoUrl }, Cmd.none ) LoadPage (Err _) -> ( model, Cmd.none ) view : Model -> Html Msg view model = let photoByUrl : String -> Maybe Photo photoByUrl url = Dict.get url model.photos selectedPhoto : Html Msg selectedPhoto = case Maybe.andThen photoByUrl model.selectedPhotoUrl of Just photo -> viewSelectedPhoto photo Nothing -> text "" in div [ class "content" ] [ div [ class "folders" ] [ viewFolder End model.root ] , div [ class "selected-photo" ] [ selectedPhoto ] ] type alias Photo = { title : String , size : Int , relatedUrls : List String , url : String } viewPhoto : String -> Html Msg viewPhoto url = a [ href ("/photos/" ++ url), class "photo", onClick (SelectPhotoUrl url) ] [ text url ] viewSelectedPhoto : Photo -> Html Msg viewSelectedPhoto photo = div [ class "selected-photo" ] [ h2 [] [ text photo.title ] , img [ src (urlPrefix ++ "photos/" ++ photo.url ++ "/full") ] [] , span [] [ text (String.fromInt photo.size ++ "KB") ] , h3 [] [ text "Related" ] , div [ class "related-photos" ] (List.map viewRelatedPhoto photo.relatedUrls) ] viewRelatedPhoto : String -> Html Msg viewRelatedPhoto url = a [ href ("/photos/" ++ url) ] [ img [ class "related-photo" , onClick (SelectPhotoUrl url) , src (urlPrefix ++ "photos/" ++ url ++ "/thumb") ] [] ] viewFolder : FolderPath -> Folder -> Html Msg viewFolder path (Folder folder) = let viewSubfolder : Int -> Folder -> Html Msg viewSubfolder index subfolder = viewFolder (appendIndex index path) subfolder folderLabel = label [ onClick (ToggleExpanded path) ] [ text folder.name ] in if folder.expanded then let contents = List.append (List.indexedMap viewSubfolder folder.subfolders) (List.map viewPhoto folder.photoUrls) in div [ class "folder expanded" ] [ folderLabel , div [ class "contents" ] contents ] else div [ class "folder collapsed" ] [ folderLabel ] appendIndex : Int -> FolderPath -> FolderPath appendIndex index path = case path of End -> Subfolder index End Subfolder subfolderIndex remainingPath -> Subfolder subfolderIndex (appendIndex index remainingPath) urlPrefix : String urlPrefix = "http://elm-in-action.com/" type FolderPath = End | Subfolder Int FolderPath toggleExpanded : FolderPath -> Folder -> Folder toggleExpanded path (Folder folder) = case path of End -> Folder { folder | expanded = not folder.expanded } Subfolder targetIndex remainingPath -> let subfolders : List Folder subfolders = List.indexedMap transform folder.subfolders transform : Int -> Folder -> Folder transform currentIndex currentSubfolder = if currentIndex == targetIndex then toggleExpanded remainingPath currentSubfolder else currentSubfolder in Folder { folder | subfolders = subfolders } type alias JsonPhoto = { title : String , size : Int , relatedUrls : List String } jsonPhotoDecoder : Decoder JsonPhoto jsonPhotoDecoder = Decode.succeed JsonPhoto |> required "title" string |> required "size" int |> required "related_photos" (list string) finishPhoto : ( String, JsonPhoto ) -> ( String, Photo ) finishPhoto ( url, json ) = ( url , { url = url , size = json.size , title = json.title , relatedUrls = json.relatedUrls } ) fromPairs : List ( String, JsonPhoto ) -> Dict String Photo fromPairs pairs = pairs |> List.map finishPhoto |> Dict.fromList photosDecoder : Decoder (Dict String Photo) photosDecoder = Decode.keyValuePairs jsonPhotoDecoder |> Decode.map fromPairs folderDecoder : Decoder Folder folderDecoder = Decode.succeed folderFromJson |> required "name" string |> required "photos" photosDecoder |> required "subfolders" (Decode.lazy (\_ -> list folderDecoder)) folderFromJson : String -> Dict String Photo -> List Folder -> Folder folderFromJson name photos subfolders = Folder { name = name , expanded = True , subfolders = subfolders , photoUrls = Dict.keys photos } modelPhotosDecoder : Decoder (Dict String Photo) modelPhotosDecoder = Decode.succeed modelPhotosFromJson |> required "photos" photosDecoder |> required "subfolders" (Decode.lazy (\_ -> list modelPhotosDecoder)) modelPhotosFromJson : Dict String Photo -> List (Dict String Photo) -> Dict String Photo modelPhotosFromJson folderPhotos subfolderPhotos = List.foldl Dict.union folderPhotos subfolderPhotos This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,319 @@ port module PhotoGallery exposing (init, Model, Msg, subscriptions, update, view, reload) import Browser import Html exposing (..) import Html.Attributes as Attr exposing (checked, class, classList, id, name, src, title, type_) import Html.Events exposing (on, onClick) import Http import Json.Decode exposing (Decoder, at, string, int, list, succeed) import Json.Decode.Pipeline exposing (optional, required) import Json.Encode as Encode import Random main : Program Float Model Msg main = Browser.element { init = init , view = view , update = update , subscriptions = subscriptions } subscriptions : Model -> Sub Msg subscriptions model = activityChanges GotActivity init : Float -> ( Model, Cmd Msg ) init flags = let activity = "Initializing Pasta v" ++ String.fromFloat flags in ( { initialModel | activity = activity }, initialCmd ) type alias Model = { status : Status , activity : String , chosenSize : ThumbnailSize , hue : Int , ripple : Int , noise : Int } initialModel : Model initialModel = { status = Loading , activity = "" , chosenSize = Medium , hue = 5 , ripple = 5 , noise = 5 } urlPrefix : String urlPrefix = "http://elm-in-action.com/" type Msg = ClickedPhoto String | ClickedSize ThumbnailSize | ClickedSurpriseMe | GotActivity String | GotPhotos (Result Http.Error (List Photo)) | GotRandomPhoto Photo | SlidHue Int | SlidNoise Int | SlidRipple Int view : Model -> Html Msg view model = div [ class "content" ] <| case model.status of Loaded photos selectedUrl -> viewLoaded photos selectedUrl model Loading -> [] Errored errorMessage -> [ text ("Error: " ++ errorMessage) ] viewLoaded : List Photo -> String -> Model -> List (Html Msg) viewLoaded photos selectedUrl model = [ button [ onClick ClickedSurpriseMe ] [ text "Surprise Me!" ] , div [ class "activity" ] [ text model.activity ] , div [ class "filters" ] [ viewFilter SlidHue "Hue" model.hue , viewFilter SlidRipple "Ripple" model.ripple , viewFilter SlidNoise "Noise" model.noise ] , h3 [] [ text "Thumbnail Size:" ] , div [ id "choose-size" ] (List.map (viewSizeChooser model.chosenSize) [ Small, Medium, Large ]) , div [ id "thumbnails", class (sizeToString model.chosenSize) ] (List.map (viewThumbnail selectedUrl) photos) , canvas [ id "main-canvas", class "large" ] [] ] viewThumbnail : String -> Photo -> Html Msg viewThumbnail selectedUrl thumb = img [ src (urlPrefix ++ thumb.url) , title (thumb.title ++ " [" ++ String.fromInt thumb.size ++ " KB]") , classList [ ( "selected", selectedUrl == thumb.url ) ] , onClick (ClickedPhoto thumb.url) ] [] viewSizeChooser : ThumbnailSize -> ThumbnailSize -> Html Msg viewSizeChooser chosenSize size = label [] [ input [ type_ "radio", name "size", onClick (ClickedSize size) , if size == chosenSize then checked True else checked False ] [] , text (sizeToString size) ] sizeToString : ThumbnailSize -> String sizeToString size = case size of Small -> "small" Medium -> "med" Large -> "large" type ThumbnailSize = Small | Medium | Large port setFilters : FilterOptions -> Cmd msg port activityChanges : (String -> msg) -> Sub msg type alias FilterOptions = { url : String , filters : List { name : String, amount : Float } } type alias Photo = { url : String , size : Int , title : String } photoDecoder : Decoder Photo photoDecoder = succeed Photo |> required "url" string |> required "size" int |> optional "title" string "(untitled)" type Status = Loading | Loaded (List Photo) String | Errored String update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of GotRandomPhoto photo -> applyFilters { model | status = selectUrl photo.url model.status } ClickedPhoto url -> applyFilters { model | status = selectUrl url model.status } ClickedSize size -> ( { model | chosenSize = size }, Cmd.none ) ClickedSurpriseMe -> case model.status of Loaded (firstPhoto :: otherPhotos) _ -> Random.uniform firstPhoto otherPhotos |> Random.generate GotRandomPhoto |> Tuple.pair model Loaded [] _ -> ( model, Cmd.none ) Loading -> ( model, Cmd.none ) Errored errorMessage -> ( model, Cmd.none ) GotActivity activity -> ( { model | activity = activity }, Cmd.none ) GotPhotos (Ok photos) -> applyFilters { model | status = case photos of first :: rest -> Loaded photos first.url [] -> Loaded [] "" } GotPhotos (Err httpError) -> ( { model | status = Errored "Server error!" }, Cmd.none ) SlidHue hue -> applyFilters { model | hue = hue } SlidRipple ripple -> applyFilters { model | ripple = ripple } SlidNoise noise -> applyFilters { model | noise = noise } applyFilters : Model -> ( Model, Cmd Msg ) applyFilters model = case model.status of Loaded photos selectedUrl -> let filters = [ { name = "Hue", amount = toFloat model.hue / 11 } , { name = "Ripple", amount = toFloat model.ripple / 11 } , { name = "Noise", amount = toFloat model.noise / 11 } ] url = urlPrefix ++ "large/" ++ selectedUrl in ( model, setFilters { url = url, filters = filters } ) Loading -> ( model, Cmd.none ) Errored errorMessage -> ( model, Cmd.none ) selectUrl : String -> Status -> Status selectUrl url status = case status of Loaded photos _ -> Loaded photos url Loading -> status Errored errorMessage -> status initialCmd : Cmd Msg initialCmd = Http.get { url = "http://elm-in-action.com/photos/list.json" , expect = Http.expectJson GotPhotos (list photoDecoder) } reload : Model -> (Model, Cmd Msg) reload newModel = applyFilters newModel viewFilter : (Int -> Msg) -> String -> Int -> Html Msg viewFilter toMsg name magnitude = div [ class "filter-slider" ] [ label [] [ text name ] , rangeSlider [ Attr.max "11" , Attr.property "val" (Encode.int magnitude) , onSlide toMsg ] [] , label [] [ text (String.fromInt magnitude) ] ] rangeSlider attributes children = node "range-slider" attributes children onSlide : (Int -> msg) -> Attribute msg onSlide toMsg = at [ "detail", "userSlidTo" ] int |> Json.Decode.map toMsg |> on "slide" -
BraxtonI revised this gist
Jul 13, 2020 . No changes.There are no files selected for viewing
-
BraxtonI created this gist
Jul 13, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,248 @@ module Main exposing (main) import Browser exposing (Document) import Browser.Navigation as Nav import Html exposing (Html, a, footer, h1, li, nav, text, ul) import Html.Attributes exposing (classList, href) import Html.Lazy exposing (lazy) import PhotoFolders as Folders import PhotoGallery as Gallery import Url exposing (Url) import Url.Parser as Parser exposing ((</>), Parser, s, string) main : Program Float Model Msg main = Browser.application { init = init , view = view , update = update , subscriptions = subscriptions , onUrlChange = ChangedUrl , onUrlRequest = ClickedLink } init : Float -> Url -> Nav.Key -> ( Model, Cmd Msg ) init version url key = updateUrl url { page = NotFound , galleryModel = Tuple.first (Gallery.init version) , foldersModel = Tuple.first (Folders.init Nothing) , key = key , version = version } type alias Model = { page : Page , galleryModel : Gallery.Model , foldersModel : Folders.Model , key : Nav.Key , version : Float } type Page = FoldersPage | GalleryPage | NotFound type Route = Gallery | Folders | SelectedPhoto String view : Model -> Document Msg view model = let content = case model.page of FoldersPage -> Folders.view model.foldersModel |> Html.map GotFoldersMsg GalleryPage -> Gallery.view model.galleryModel |> Html.map GotGalleryMsg NotFound -> text "Not Found" in { title = "Photo Groove, SPA Style" , body = [ lazy viewHeader model.page , content , viewFooter ] } viewHeader : Page -> Html Msg viewHeader page = let logo = h1 [] [ text "Photo Groove" ] links = ul [] [ navLink Folders { url = "/", caption = "Folders" } , navLink Gallery { url = "/gallery", caption = "Gallery" } ] navLink : Route -> { url : String, caption : String } -> Html msg navLink route { url, caption } = li [ classList [ ( "active" , isActive { link = route, page = page } ) ] ] [ a [ href url ] [ text caption ] ] in nav [] [ logo, links ] parser : Parser (Route -> a) a parser = Parser.oneOf [ Parser.map Folders Parser.top , Parser.map Gallery (s "gallery") , Parser.map SelectedPhoto (s "photos" </> Parser.string) ] isActive : { link : Route, page : Page } -> Bool isActive { link, page } = case ( link, page ) of ( Gallery , GalleryPage ) -> True ( Gallery , _ ) -> False ( Folders , FoldersPage ) -> True ( Folders , _ ) -> False ( SelectedPhoto _, _ ) -> False viewFooter : Html msg viewFooter = footer [] [ text "One is never alone with a rubber duck. -Douglas Adams" ] update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of ClickedLink urlRequest -> case urlRequest of Browser.External href -> ( model, Nav.load href ) Browser.Internal url -> ( model, Nav.pushUrl model.key (Url.toString url) ) ChangedUrl url -> updateUrl url model GotFoldersMsg foldersMsg -> case model.page of FoldersPage -> toFolders model (Folders.update foldersMsg model.foldersModel) _ -> ( model, Cmd.none ) GotGalleryMsg galleryMsg -> case model.page of GalleryPage -> toGallery model (Gallery.update galleryMsg model.galleryModel) _ -> ( model, Cmd.none ) type Msg = ClickedLink Browser.UrlRequest | ChangedUrl Url | GotFoldersMsg Folders.Msg | GotGalleryMsg Gallery.Msg toFolders : Model -> ( Folders.Model, Cmd Folders.Msg ) -> ( Model, Cmd Msg ) toFolders model ( folders, cmd ) = ( { model | page = FoldersPage, foldersModel = folders } , Cmd.map GotFoldersMsg cmd ) toGallery : Model -> ( Gallery.Model, Cmd Gallery.Msg ) -> ( Model, Cmd Msg ) toGallery model ( gallery, cmd ) = ( { model | page = GalleryPage, galleryModel = gallery } , Cmd.map GotGalleryMsg cmd ) updateUrl : Url -> Model -> ( Model, Cmd Msg ) updateUrl url model = case Parser.parse parser url of Just Gallery -> toGallery model <| let initGalleryModel = (Gallery.init model.version) in -- if the gallery has not been initialized, proceed with regular initialization -- if the gallery has been initialized, model.galleryModel has the previous build, and should be used -- to reload the page via Gallery.reload, which also called Gallery.applyFilters to load the main-canvas if model.galleryModel == Tuple.first initGalleryModel then initGalleryModel else Gallery.reload model.galleryModel Just Folders -> toFolders model <| let initFoldersModel = (Folders.init Nothing) in -- if the folders page has not been initialized, proceed with regular initialization -- if the folders page has been initialized, model.foldersModel has the previous build, and should be used instead if model.foldersModel == Tuple.first initFoldersModel then initFoldersModel else ( model.foldersModel, Cmd.none ) Just (SelectedPhoto filename) -> let foldersModel = model.foldersModel in -- Update model.foldersModel.selectPhotoUrl to filename toFolders model ( { foldersModel | selectedPhotoUrl = (Just filename) }, Cmd.none ) Nothing -> ( { model | page = NotFound }, Cmd.none ) subscriptions : Model -> Sub Msg subscriptions model = case model.page of GalleryPage -> Gallery.subscriptions model.galleryModel |> Sub.map GotGalleryMsg _ -> Sub.none