Merge pull request 'Homepage re-jig' (#32) from filter-rejig into main
continuous-integration/drone/push Build is passing Details

Reviewed-on: #32
This commit is contained in:
3wordchant 2023-03-28 17:42:59 +00:00
commit 41ccf212a9
6 changed files with 442 additions and 323 deletions

View File

@ -16,6 +16,7 @@
"elm/url": "1.0.0",
"elm-community/json-extra": "4.3.0",
"elm-community/string-extra": "4.0.1",
"fapian/elm-html-aria": "1.4.0",
"pablohirafuji/elm-markdown": "2.0.5"
},
"indirect": {

480
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,6 @@
"npm-run-all": "4.1.5"
},
"dependencies": {
"elm-format": "^0.8.5"
"elm-format": "^0.8.6"
}
}

View File

@ -29,7 +29,27 @@ i.fas, i.fab {
}
/* Categories */
/* Filtering */
#filter {
position: fixed;
left: 0;
background-color: var(--light-blue);
padding-top: 1rem;
height: 100%;
}
#filter > form > div {
margin: 1rem 0;
}
#filter h3 {
font-size: 18px;
}
#filter label {
display: block;
}
.category-tile {
cursor: pointer;
@ -41,6 +61,12 @@ i.fas, i.fab {
border-radius: 5px;
}
/* Intro */
.card#intro {
margin: 1em 0;
}
/* Cards */
.app-category {
@ -100,31 +126,6 @@ i.fas, i.fab {
}
/* Search bar*/
.search-bar-container {
margin: 2em;
display: flex;
flex-flow: row wrap;
align-items: center;
}
.search-bar-input, .search-dropdown {
margin: 0.5em;
height: calc(1.5em + .75rem + 2px);
background-color: var(--white);
border: 1px solid var(--dark-pink);
border-radius: .5rem;
}
.search-bar-input {
width: 30rem;
}
.search-dropdown {
width: 10rem;
}
/* Navbar */
.navbar-text {
color: var(--dark-blue);
@ -146,3 +147,10 @@ i.fas, i.fab {
.card-body p {
}
}
@media (max-width: 768px) {
#filter {
width: 100%;
position: relative;
margin-bottom: 1rem;
}

View File

@ -272,9 +272,9 @@ viewApp app readme =
]
, div [ class "card-footer" ]
[ h5 [] [ text "Versions" ]
, ul [] (
List.map (\version -> li [] [ text (version) ]) app.versions
)]
, ul []
(List.map (\version -> li [] [ text version ]) app.versions)
]
]
]
@ -319,8 +319,6 @@ featuresDecoder =
]
versionsDecoder : Decode.Decoder (List String)
versionsDecoder =
Decode.list (Decode.keyValuePairs Decode.value)
@ -332,7 +330,6 @@ buildVersions versions =
List.concatMap (List.map (\( version, _ ) -> version)) versions
appDecoder : Decode.Decoder App
appDecoder =
Decode.succeed App

View File

@ -1,8 +1,9 @@
module Pages.Top exposing (Model, Msg, Params, page)
import Enum exposing (Enum)
import Html exposing (Html, a, button, div, h2, h5, i, img, li, p, span, text, ul, form, label, select, option, input)
import Html.Attributes exposing (alt, class, href, src, style, id, for, value)
import Html exposing (Html, a, button, div, form, h2, h3, h5, i, img, input, label, li, option, p, select, span, text, ul)
import Html.Attributes exposing (alt, class, for, href, id, src, style, value)
import Html.Attributes.Aria exposing (ariaLabel)
import Html.Events exposing (onClick, onInput)
import Http
import Json.Decode as Decode
@ -26,6 +27,7 @@ page =
}
-- INIT
@ -52,8 +54,8 @@ type alias Model =
, filter_category : Maybe Category
, filter_text : Maybe String
, status : Status
, apps : (List App)
, results : (List App)
, apps : List App
, results : List App
}
@ -77,11 +79,10 @@ categories =
[ ( "Apps", Apps )
, ( "Utilities", Utilities )
, ( "Development", Development )
, ("All", All)
, ( "All", All )
]
init : Url Params -> ( Model, Cmd Msg )
init { params } =
( default_model, loadApps )
@ -94,8 +95,14 @@ default_image =
default_model : Model
default_model =
{ filter_score = Nothing, filter_category = Nothing, filter_text = Nothing,
status = Loading, apps = [], results = [] }
{ filter_score = Nothing
, filter_category = Nothing
, filter_text = Nothing
, status = Loading
, apps = []
, results = []
}
-- UPDATE
@ -113,41 +120,55 @@ filterAppsScore : List App -> Maybe Int -> List App
filterAppsScore apps score =
case score of
Just s ->
List.filter (\app ->
List.filter
(\app ->
app.status >= s
) apps
)
apps
Nothing ->
apps
filterAppsCategory : List App -> Maybe Category -> List App
filterAppsCategory apps category =
case category of
Just c ->
if c == All then
apps
else
List.filter (\app ->
app.category == categories.toString c
) apps
List.filter
(\app ->
app.category == categories.toString c
)
apps
Nothing ->
apps
filterAppsText : List App -> Maybe String -> List App
filterAppsText apps text =
case text of
Just "" ->
apps
Just t ->
List.filter (\app ->
String.contains (String.toLower t) (
String.toLower app.name ++ String.toLower (
Maybe.withDefault "" app.description
)
List.filter
(\app ->
String.contains (String.toLower t)
(String.toLower app.name
++ String.toLower
(Maybe.withDefault "" app.description)
)
)
) apps
apps
Nothing ->
apps
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
@ -156,51 +177,71 @@ update msg model =
FilterScore filter ->
let
filter_score = String.toInt filter
filter_score =
String.toInt filter
in
( { model
| filter_score = filter_score
, results = filterAppsScore (
filterAppsCategory (
filterAppsText model.apps model.filter_text
) model.filter_category
) (String.toInt filter)
}, Cmd.none )
( { model
| filter_score = filter_score
, results =
filterAppsScore
(filterAppsCategory
(filterAppsText model.apps model.filter_text)
model.filter_category
)
(String.toInt filter)
}
, Cmd.none
)
FilterCategory filter ->
let
category = categories.fromString filter
category =
categories.fromString filter
in
( { model
| filter_category = category
, results = filterAppsCategory (
filterAppsScore (
filterAppsText model.apps model.filter_text
)model.filter_score
) category
}, Cmd.none )
, results =
filterAppsCategory
(filterAppsScore
(filterAppsText model.apps model.filter_text)
model.filter_score
)
category
}
, Cmd.none
)
FilterText filter ->
( { model
| filter_text = Just filter
, results = filterAppsText (
filterAppsScore (
filterAppsCategory model.apps model.filter_category
) model.filter_score
) (Just filter)
}, Cmd.none )
, results =
filterAppsText
(filterAppsScore
(filterAppsCategory model.apps model.filter_category)
model.filter_score
)
(Just filter)
}
, Cmd.none
)
GotApps result ->
case result of
Ok apps ->
( { default_model
| status = Success
, apps = apps
, results = apps }, Cmd.none )
| status = Success
, apps = apps
, results = apps
}
, Cmd.none
)
Err _ ->
( { default_model
| status = Failure}, Cmd.none )
| status = Failure
}
, Cmd.none
)
subscriptions : Model -> Sub Msg
@ -221,7 +262,7 @@ view model =
body : Model -> Html Msg
body model =
div [ class "pt-3" ]
div []
[ viewApps model
]
@ -247,7 +288,7 @@ viewStatusBadge app =
"badge-dark"
in
span [ class ("card-link badge " ++ status_class) ]
[ text ("Status: " ++ String.fromInt app.status) ]
[ text ("Score: " ++ String.fromInt app.status) ]
viewApp : App -> Html Msg
@ -303,16 +344,14 @@ viewApp app =
, p [ class "card-description" ] [ text (ellipsis 100 (withDefault "" app.description)) ]
]
, div [ class "footer" ]
[ viewStatusBadge app, span [ class "badge app-category" ] [ text app.category ]]
[ viewStatusBadge app, span [ class "badge app-category" ] [ text app.category ] ]
]
]
viewCategories : (String, Category) -> Html Msg
viewCategories : ( String, Category ) -> Html Msg
viewCategories category =
div [ class "category-tile", onClick (FilterCategory (Tuple.first category)) ] [text (Tuple.first category)]
div [ class "category-tile", onClick (FilterCategory (Tuple.first category)) ] [ text (Tuple.first category) ]
viewApps : Model -> Html Msg
@ -335,32 +374,52 @@ viewApps model =
Success ->
div [ class "row justify-content-center" ]
[ div [ class "col-md-3" ] [
h2 [ class "app-headings" ] [text "Categories"]
, div [] (List.map viewCategories categories.list)
]
, div [ class "col-md-6" ]
[ div [ class "row" ]
[ div [ class "col-sm-12" ] [
div [] [
form [ class "search-bar-container" ] [
label [ for "text" ] [ text "Search" ]
, input [ class "search-bar-input", id "text", onInput FilterText ] []
, label [ for "level" ] [ text " and show only items that have at least " ]
, select [ class "search-dropdown", id "level", onInput FilterScore ] [
option [ ] [ text "any" ]
, option [ value "5" ] [ text "5 (production)" ]
, option [ value "4" ] [ text "4 (beta)" ]
, option [ value "3" ] [ text "3 (alpha)" ]
, option [ value "2" ] [ text "2 (pre-alpha)" ]
, option [ value "1" ] [ text "1 (work-in-progress)" ]
]
, text "builds "
]
[ div [ class "col-md-3", id "filter" ]
[ h2 [ class "app-headings" ] [ text "Finding things" ]
, form []
[ div []
[ h3 [] [ text "Categories" ]
, div [] (List.map viewCategories categories.list)
]
, div []
[ h3 [] [ text "Search" ]
, input [ ariaLabel "search", id "text", onInput FilterText ] []
]
, div []
[ h3 [] [ text "Status" ]
, label [ for "level" ] [ text "Minimum score:" ]
, select [ class "search-dropdown", id "level", onInput FilterScore ]
[ option [] [ text "any" ]
, option [ value "5" ] [ text "5 (amazing)" ]
, option [ value "4" ] [ text "4 (good)" ]
, option [ value "3" ] [ text "3 (ok)" ]
, option [ value "2" ] [ text "2 (basic)" ]
, option [ value "1" ] [ text "1 (chaos)" ]
]
]
]
, h2 [ class "app-headings" ] [ text "Apps" ]
]
, div [ class "col-md-6 offset-md-3" ]
[ div [ class "row" ]
[ div [ class "col-sm-12" ]
[ div []
[]
]
]
, div [ id "intro", class "card" ] [ div [ class "card-body" ] [
h2 [ class "app-headings card-title" ] [ text "Co-op Cloud Recipe Catalogue" ]
, text "You can use these recipes ("
, a [ href
"https://docs.coopcloud.tech/glossary/#recipe" ] [
text "What's a recipe?"
]
, text ") with "
, a [ href "https://coopcloud.tech" ] [
text "Co-op Cloud"
]
, text "."
]
]
, div [ class "row" ]
(List.map viewApp
(model.results
@ -371,9 +430,11 @@ viewApps model =
)
)
]
, div [class "col-md-3"] []
, div [ class "col-md-3" ] []
]
-- HTTP