From cc3ee90f0bda3450af3d5dfff2520208b534b9dc Mon Sep 17 00:00:00 2001 From: 3wc <3wc.git@doesthisthing.work> Date: Tue, 20 Apr 2021 01:31:11 +0200 Subject: [PATCH] App detail page, stylin', icons --- elm.json | 7 +- public/index.html | 5 +- public/style.css | 9 ++ src/Pages/App_String.elm | 228 +++++++++++++++++++++++++++++++++++++++ src/Pages/Top.elm | 30 +++--- 5 files changed, 263 insertions(+), 16 deletions(-) create mode 100644 src/Pages/App_String.elm diff --git a/elm.json b/elm.json index e2d0bce..4072e48 100644 --- a/elm.json +++ b/elm.json @@ -11,9 +11,12 @@ "elm/html": "1.0.0", "elm/http": "2.0.0", "elm/json": "1.1.3", - "elm/url": "1.0.0" + "elm/url": "1.0.0", + "pablohirafuji/elm-markdown": "2.0.5" }, "indirect": { + "elm/bytes": "1.0.8", + "elm/file": "1.0.5", "elm/time": "1.0.0", "elm/virtual-dom": "1.0.2" } @@ -25,8 +28,6 @@ }, "indirect": { "avh4/elm-fifo": "1.0.4", - "elm/bytes": "1.0.8", - "elm/file": "1.0.5", "elm/random": "1.0.0" } } diff --git a/public/index.html b/public/index.html index 12629d8..965a520 100644 --- a/public/index.html +++ b/public/index.html @@ -6,7 +6,10 @@ + href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"> + + diff --git a/public/style.css b/public/style.css index 04d021a..2c902c5 100644 --- a/public/style.css +++ b/public/style.css @@ -1,8 +1,17 @@ body { } +.container-fluid { + min-height: 92vh; +} + .card-img-top { width: 100%; height: 8vw; object-fit: cover; } + +i.fa, i.fab { + display: inline-block; + margin-right: 0.3rem; +} diff --git a/src/Pages/App_String.elm b/src/Pages/App_String.elm new file mode 100644 index 0000000..9b0ce23 --- /dev/null +++ b/src/Pages/App_String.elm @@ -0,0 +1,228 @@ +module Pages.App_String exposing (Model, Msg, Params, page) + +import Html exposing (Html, button, div, h2, h5, img, text, ul, li, a, p, span) +import Html.Attributes exposing (src, style, class, alt, href) +import Html.Events exposing (onClick) +import Http +import Markdown +import Json.Decode as Decode +import Spa.Document exposing (Document) +import Spa.Page as Page exposing (Page) +import Spa.Url as Url exposing (Url) + + +page : Page Params Model Msg +page = + Page.element + { init = init + , update = update + , view = view + , subscriptions = subscriptions + } + +-- INIT + + +type alias Params = + { app : String + } + +type alias App = + { name : String + , category : String + , repository : Maybe String + , versions : Maybe (List String) + , icon : Maybe String + , status : String + } + + +type alias Model = + { url : Url Params + , status : Status + , readme : String + } + + +type Status + = Failure + | Loading + | Success App + + +init : Url Params -> ( Model, Cmd Msg ) +init url = + ( { url = url, status = Loading, readme = "" }, loadData ) + + +default_image : String +default_image = "http://localhost:8000/logo.png" + + +-- UPDATE + + +type Msg + = MorePlease + | GotApps (Result Http.Error (List App)) + | GotText (Result Http.Error String) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + MorePlease -> + ( { model | status = Loading }, loadData ) + + GotApps result -> + case result of + Ok apps -> + let + apps_filtered = List.filter (\app -> app.name == model.url.params.app) apps + in + case List.head apps_filtered of + Nothing -> + ( { model | status = Failure }, Cmd.none ) + Just item -> + ( { model | status = Success (item) }, Cmd.none ) + + Err _ -> + ( { model | status = Failure }, Cmd.none ) + + GotText result -> + case result of + Ok content -> + ( { model | readme = content }, Cmd.none ) + + Err _ -> + ( { model | status = Failure }, Cmd.none ) + + + +subscriptions : Model -> Sub Msg +subscriptions model = + Sub.none + + + +-- VIEW + + +view : Model -> Document Msg +view model = + { title = "abra app" + , body = [ body model ] + } + + +body : Model -> Html Msg +body model = + div [ class "pt-3" ] + [ case model.status of + Failure -> + div [ ] + [ text "I could not load a random cat for some reason. " + , button [ onClick MorePlease ] [ text "Try Again!" ] + ] + + Loading -> + text "Loading..." + + Success app -> + div [] + [ div [ class "row" ] + [ viewApp app model.readme ] + ] + ] + +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" + in + span [ class ("card-link badge " ++ status_class) ] + [ text ("Score: " ++ app.status) ] + +viewApp : App -> String -> Html Msg +viewApp app readme = + let + icon_url = + case app.icon of + Just "" -> + default_image + Just i -> + i + Nothing -> + default_image + repository_link = + case app.repository of + Just i -> + a [ class "card-link", href i ] [ text "code" ] + Nothing -> + text "" + in + div [ class "col-md-6 col-sm-10 mb-3 offset-md-3 offset-sm-1" ] + [ div [ class "card" ] + [ div [ class "card-header" ] + [ span [ class "card-link badge badge-secondary" ] [ text app.category ] + , viewStatusBadge app + , repository_link + , a [ class "card-link", href "http://example.com" ] [ text "homepage" ] + ] + , img [ class "card-img-top", src icon_url, alt ("icon for " ++ app.name) ] [] + , div [ class "card-body" ] + [ div [] (Markdown.toHtml Nothing readme) + ] + , div [ class "card-footer" ] + [] + ] + ] + +-- HTTP + + +loadData : Cmd Msg +loadData = + Cmd.batch + [ Http.get + { url = "http://localhost:8000/abra-apps-list.json" + , expect = Http.expectJson GotApps appListDecoder } + , Http.get + { url = "http://localhost:1234/coop-cloud/adapt_authoring/raw/branch/main/README.md" + , expect = Http.expectString GotText } + ] + +featuresDecoder = + (Decode.oneOf + [ Decode.at [ "status" ] Decode.string + , Decode.succeed "" + ] + ) + + +appDecoder : Decode.Decoder App +appDecoder = + Decode.map6 + 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) + + +appListDecoder : Decode.Decoder (List App) +appListDecoder = + Decode.list appDecoder diff --git a/src/Pages/Top.elm b/src/Pages/Top.elm index 5270bc8..5424801 100644 --- a/src/Pages/Top.elm +++ b/src/Pages/Top.elm @@ -1,10 +1,11 @@ module Pages.Top exposing (Model, Msg, Params, page) -import Html exposing (Html, button, div, h2, h5, img, text, ul, li, a, p, span) +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) @@ -95,8 +96,8 @@ body model = [ viewApps model ] -renderStatusBadge : App -> Html Msg -renderStatusBadge app = +viewStatusBadge : App -> Html Msg +viewStatusBadge app = let status_class = case app.status of @@ -114,8 +115,8 @@ renderStatusBadge app = span [ class ("card-link badge " ++ status_class) ] [ text ("Score: " ++ app.status) ] -viewAppName : App -> Html Msg -viewAppName app = +viewApp : App -> Html Msg +viewApp app = let icon_url = case app.icon of @@ -127,8 +128,12 @@ viewAppName app = default_image repository_link = case app.repository of - Just i -> - a [ class "card-link", href i ] [ text "Code" ] + Just link -> + a [ class "card-link", href link ] + [ + i [ class "fab fa-git-alt" ] [] + , text "Code" + ] Nothing -> text "" in @@ -136,12 +141,13 @@ viewAppName app = [ div [ class "card" ] [ img [ class "card-img-top", src icon_url, alt ("icon for " ++ app.name) ] [] , div [ class "card-body" ] - [ h5 [ class "card-title" ] [ text app.name ] - , repository_link - ] + [ h5 [ class "card-title" ] + [ a [ href (Route.toString <| Route.App_String { app = app.name } ) ] [ text app.name ] ] + , repository_link + ] , div [ class "card-footer" ] [ span [ class "card-link badge badge-secondary" ] [ text app.category ] - , renderStatusBadge app + , viewStatusBadge app ] ] ] @@ -161,7 +167,7 @@ viewApps model = Success apps -> div [] [ div [ class "row" ] - (List.map viewAppName (List.sortBy .name apps)) + (List.map viewApp (List.sortBy .name apps)) ] -- HTTP