App detail page, stylin', icons
This commit is contained in:
parent
e932010e81
commit
cc3ee90f0b
7
elm.json
7
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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
<!-- CSS goes here -->
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<link rel="stylesheet"
|
||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
|
||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
|
||||
<!--<link rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/fontawesome.min.css">-->
|
||||
<script src="https://kit.fontawesome.com/60c2d44730.js" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- JavaScript goes here -->
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue