module Pages.Top exposing (Model, Msg, Params, page) import Html exposing (Html, button, div, h2, h5, img, text, ul, li, a, p, span, i) import Html.Attributes exposing (src, style, class, alt, href) import Html.Events exposing (onClick) import Http import Json.Decode as Decode import Spa.Generated.Route as Route import Spa.Document exposing (Document) import Spa.Page as Page exposing (Page) import Spa.Url as Url exposing (Url) import Util exposing (by, andThen, Direction(..)) page : Page Params Model Msg page = Page.element { init = init , update = update , view = view , subscriptions = subscriptions } -- INIT type alias Params = () type alias App = { name : String , category : String , repository : Maybe String , versions : Maybe (List String) , icon : Maybe String , status : String , slug : String , website : Maybe String } type Model = Failure | Loading | Success (List App) init : Url Params -> ( Model, Cmd Msg ) init { params } = ( Loading, loadApps ) default_image : String default_image = "/logo.png" -- UPDATE type Msg = MorePlease | GotApps (Result Http.Error (List App)) update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of MorePlease -> ( Loading, loadApps ) GotApps result -> case result of Ok apps -> ( Success apps, Cmd.none ) Err _ -> ( Failure, Cmd.none ) subscriptions : Model -> Sub Msg subscriptions model = Sub.none -- VIEW view : Model -> Document Msg view model = { title = "abra apps" , body = [ body model ] } body : Model -> Html Msg body model = div [ class "pt-3" ] [ viewApps model ] appScore : App -> Int appScore app = case app.status of "1" -> 1 "2" -> 2 "3" -> 3 "4" -> 4 _ -> 5 viewStatusBadge : App -> Html Msg viewStatusBadge app = let status_class = case app.status of "1" -> "badge-success" "2" -> "badge-info" "3" -> "badge-warning" "4" -> "badge-danger" _ -> "badge-dark" status_score = case app.status of "" -> "?" score -> score in span [ class ("card-link badge " ++ status_class) ] [ text ("Score: " ++ status_score) ] viewApp : App -> Html Msg viewApp app = let icon_url = case app.icon of Just "" -> default_image Just i -> i Nothing -> default_image repository_link = case app.repository of Just link -> a [ class "card-link", href link ] [ i [ class "fab fa-git-alt" ] [] , text "code" ] Nothing -> text "" website_link = case app.website of Just link -> case link of "" -> text "" _ -> a [ class "card-link", href link ] [ i [ class "fas fa-home" ] [] , text "homepage" ] Nothing -> text "" app_href = Route.toString <| Route.App_String { app = app.slug } in div [ class "col-4 mb-3" ] [ div [ class "card" ] [ img [ class "card-img-top", src icon_url, alt ("icon for " ++ app.name) ] [] , div [ class "card-body" ] [ h5 [ class "card-title" ] [ a [ href app_href ] [ text app.name ] ] , repository_link , website_link , a [ class "card-link", href app_href ] [ i [ class "fas fa-book" ] [] , text "docs" ] ] , div [ class "card-footer" ] [ span [ class "card-link badge badge-secondary" ] [ text app.category ] , viewStatusBadge app ] ] ] viewApps : Model -> Html Msg viewApps model = case model of Failure -> div [ ] [ text "I could not load a random cat for some reason. " , button [ onClick MorePlease ] [ text "Try Again!" ] ] Loading -> text "Loading..." Success apps -> div [] [ div [ class "row" ] (List.map viewApp (apps |> List.sortWith (by appScore ASC |> andThen .name ASC)) ) ] -- HTTP loadApps : Cmd Msg loadApps = Http.get { url = "/abra-apps-list.json" , expect = Http.expectJson GotApps appListDecoder } featuresDecoder = (Decode.oneOf [ Decode.at [ "status" ] Decode.string , Decode.succeed "" ] ) appDecoder : Decode.Decoder App appDecoder = Decode.map8 App (Decode.field "name" Decode.string) (Decode.field "category" Decode.string) (Decode.maybe (Decode.field "repository" Decode.string)) (Decode.succeed Nothing) (Decode.maybe (Decode.field "icon" Decode.string)) (Decode.at [ "features" ] featuresDecoder) (Decode.field "slug" Decode.string) (Decode.maybe (Decode.field "website" Decode.string)) appListDecoder : Decode.Decoder (List App) appListDecoder = Decode.list appDecoder