diff --git a/README.md b/README.md index 864b957b..31ceafc7 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,9 @@ __A music player which connects to your cloud/distributed storage__, in the form - [Elm](https://elm-lang.org/) programming language - [Haskell](https://docs.haskellstack.org/en/stable/README/) programming language -- [Elm Proofread](https://github.com/icidasset/elm-proofread) documentation tests -- [Devd](https://github.com/cortesi/devd) web server for development -- [Watchexec](https://github.com/watchexec/watchexec) watching for file changes +- [Elm Proofread](https://github.com/icidasset/elm-proofread) documentation tests (optional) +- [Devd](https://github.com/cortesi/devd) web server for development (optional) +- [Watchexec](https://github.com/watchexec/watchexec) watching for file changes (optional) ```shell diff --git a/src/Applications/UI/Kit.elm b/src/Applications/UI/Kit.elm index e3d61055..98d61084 100644 --- a/src/Applications/UI/Kit.elm +++ b/src/Applications/UI/Kit.elm @@ -43,6 +43,7 @@ colors = { errorBorder = colorKit.base08 , inputBorder = rgb 225 225 225 , subtleBorder = rgb 238 238 238 + , verySubtleBorder = rgb 248 248 248 -- States , success = colorKit.base0B @@ -323,6 +324,7 @@ receptacle = , T.bg_white , T.flex , T.flex_column + , T.z_999 ] diff --git a/src/Applications/UI/List.elm b/src/Applications/UI/List.elm index d3bde0fd..0d993aba 100644 --- a/src/Applications/UI/List.elm +++ b/src/Applications/UI/List.elm @@ -76,4 +76,4 @@ listStyles = itemStyles : List Css.Style itemStyles = - [ Css.borderBottom3 (px 1) solid (Color.toElmCssColor UI.Kit.colors.subtleBorder) ] + [ Css.borderBottom3 (px 1) solid (Color.toElmCssColor UI.Kit.colors.verySubtleBorder) ] diff --git a/src/Applications/UI/Navigation.elm b/src/Applications/UI/Navigation.elm index 0c97c22a..4f1f9924 100644 --- a/src/Applications/UI/Navigation.elm +++ b/src/Applications/UI/Navigation.elm @@ -65,23 +65,28 @@ globalItem activePage totalItems idx ( page, label ) = isLastItem = idx + 1 == totalItems in - slab - Html.a - [ attribute "data-keep-focus" "t" - , css (globalItemStyles isActivePage) - , href (Page.toString page) - ] + chunk [ T.dib - , T.lh_copy - , T.no_underline - , T.pointer - , T.pt2 - - -- - , ifThenElse isActivePage T.bb T.bn - , ifThenElse isLastItem T.mr0 T.mr4 + , ifThenElse isLastItem T.mr0 T.mr1 + ] + [ slab + Html.a + [ attribute "data-keep-focus" "t" + , css (globalItemStyles isActivePage) + , href (Page.toString page) + ] + [ T.dib + , T.lh_copy + , T.no_underline + , T.pointer + , T.pt2 + + -- + , ifThenElse isActivePage T.bb T.bn + , ifThenElse isLastItem T.mr0 T.mr4 + ] + [ text label ] ] - [ text label ] globalColors : { active : Css.Color, border : Css.Color, default : Css.Color } @@ -94,7 +99,7 @@ globalColors = globalStyles : List Css.Style globalStyles = - [ Css.fontSize (px 11.5) ] + [ Css.fontSize (px 11.25) ] globalItemStyles : Bool -> List Css.Style diff --git a/src/Applications/UI/Tracks.elm b/src/Applications/UI/Tracks.elm index 5a925b30..39dd8902 100644 --- a/src/Applications/UI/Tracks.elm +++ b/src/Applications/UI/Tracks.elm @@ -1,14 +1,27 @@ module UI.Tracks exposing (Model, Msg(..), initialModel, makeParcel, resolveParcel, update, view) import Chunky exposing (..) +import Color +import Color.Ext as Color +import Css import Html.Styled as Html exposing (Html, text) +import Html.Styled.Attributes exposing (css, placeholder, title, value) +import Html.Styled.Events exposing (onClick, onInput) +import Html.Styled.Ext exposing (onEnterKey) +import Html.Styled.Lazy exposing (..) import Json.Decode +import Material.Icons.Action as Icons +import Material.Icons.Av as Icons +import Material.Icons.Content as Icons +import Material.Icons.Editor as Icons import Replying exposing (R3D3) import Return3 +import Tachyons.Classes as T import Tracks exposing (..) import Tracks.Collection exposing (..) import Tracks.Encoding as Encoding import UI.Kit +import UI.Navigation exposing (..) import UI.Reply exposing (Reply(..)) @@ -50,12 +63,19 @@ initialModel = type Msg = Bypass ----------------------------------------- - -- Collection, Pt. 1 + -- Collection ----------------------------------------- + | Add Json.Decode.Value ----------------------------------------- - -- Collection, Pt. 2 + -- Favourites ----------------------------------------- - | Add Json.Decode.Value + | ToggleFavouritesOnly + ----------------------------------------- + -- Search + ----------------------------------------- + | ClearSearch + | Search (Maybe String) + | SetSearchTerm String update : Msg -> Model -> R3D3 Model Msg Reply @@ -65,10 +85,7 @@ update msg model = Return3.withNothing model ----------------------------------------- - -- Collection, Pt. 1 - ----------------------------------------- - ----------------------------------------- - -- Collection, Pt. 2 + -- Collection ----------------------------------------- -- # Add -- > Add tracks to the collection. @@ -85,6 +102,24 @@ update msg model = |> add tracks |> resolveParcel model + ----------------------------------------- + -- Favourites + ----------------------------------------- + ToggleFavouritesOnly -> + Return3.withNothing { model | favouritesOnly = not model.favouritesOnly } + + ----------------------------------------- + -- Search + ----------------------------------------- + ClearSearch -> + Return3.withNothing { model | searchTerm = Nothing } + + Search maybeTerm -> + Return3.withNothing { model | searchTerm = maybeTerm } + + SetSearchTerm term -> + Return3.withNothing { model | searchTerm = Just term } + -- 📣 ░░ PARCEL @@ -126,8 +161,173 @@ resolveParcel model ( _, newCollection ) = view : Model -> Html Msg view model = - raw - (List.map - (\t -> text t.tags.title) - model.collection.untouched - ) + chunk + [] + [ lazy2 + navigation + model.favouritesOnly + model.searchTerm + + -- + , chunk + [] + (List.map + (\t -> text <| t.tags.artist ++ " - " ++ t.tags.title) + model.collection.untouched + ) + ] + + +navigation : Bool -> Maybe String -> Html Msg +navigation favouritesOnly searchTerm = + chunk + [ T.flex ] + [ ----------------------------------------- + -- Part 1 + ----------------------------------------- + brick + [ css searchStyles ] + [ T.flex_grow_1 + , T.overflow_hidden + , T.relative + ] + [ -- Input + -------- + slab + Html.input + [ css searchInputStyles + , onEnterKey (Search searchTerm) + , onInput SetSearchTerm + , placeholder "Search" + , value (Maybe.withDefault "" searchTerm) + ] + [ T.bg_transparent + , T.bn + , T.flex + , T.h_100 + , T.items_center + , T.outline_0 + , T.relative + , T.w_100 + , T.z_1 + ] + [] + + -- Search icon + -------------- + , brick + [ css searchIconStyles ] + [ T.absolute + , T.bottom_0 + , T.flex + , T.items_center + , T.left_0 + , T.top_0 + , T.z_0 + ] + [ Html.fromUnstyled (Icons.search searchIconColor 16) ] + + -- Actions + ---------- + , brick + [ css searchActionsStyles ] + [ T.absolute + , T.flex + , T.items_center + , T.right_0 + , T.z_2 + ] + [ -- 1 + case searchTerm of + Just _ -> + brick + [ css searchActionIconStyle + , onClick ClearSearch + , title "Clear search" + ] + [ T.pointer ] + [ Html.fromUnstyled (Icons.clear searchIconColor 16) ] + + Nothing -> + empty + + -- 2 + , brick + [ css searchActionIconStyle + , onClick ToggleFavouritesOnly + , title "Toggle favourites-only" + ] + [ T.pointer ] + [ case favouritesOnly of + True -> + Html.fromUnstyled (Icons.favorite UI.Kit.colorKit.base08 16) + + False -> + Html.fromUnstyled (Icons.favorite_border searchIconColor 16) + ] + + -- 3 + , empty + ] + ] + , ----------------------------------------- + -- Part 2 + ----------------------------------------- + UI.Navigation.local + [ ( Icon Icons.format_list_numbered + , Label "Playlists" Hidden + , PerformMsg Bypass + ) + , ( Icon Icons.event_seat + , Label "Queue" Hidden + , PerformMsg Bypass + ) + , ( Icon Icons.equalizer + , Label "Equalizer" Hidden + , PerformMsg Bypass + ) + ] + ] + + + +-- 🖼 + + +searchStyles : List Css.Style +searchStyles = + [ Css.borderBottom3 (Css.px 1) Css.solid (Color.toElmCssColor UI.Kit.colors.subtleBorder) + , Css.borderRight3 (Css.px 1) Css.solid (Color.toElmCssColor UI.Kit.colors.subtleBorder) + ] + + +searchActionsStyles : List Css.Style +searchActionsStyles = + [ Css.marginTop (Css.px 1) + , Css.paddingRight (Css.px <| 13 - 6) + , Css.top (Css.pct 50) + , Css.transform (Css.translateY <| Css.pct -50) + ] + + +searchActionIconStyle : List Css.Style +searchActionIconStyle = + [ Css.marginRight (Css.px 6) ] + + +searchIconColor : Color.Color +searchIconColor = + Color.rgb255 205 205 205 + + +searchIconStyles : List Css.Style +searchIconStyles = + [ Css.paddingLeft (Css.px 13) ] + + +searchInputStyles : List Css.Style +searchInputStyles = + [ Css.paddingLeft (Css.px <| 13 + 16 + 9) + , Css.fontSize (Css.px 14) + , Css.height (Css.pct 98) + ] diff --git a/src/Library/Html/Styled/Ext.elm b/src/Library/Html/Styled/Ext.elm new file mode 100644 index 00000000..6a28856b --- /dev/null +++ b/src/Library/Html/Styled/Ext.elm @@ -0,0 +1,22 @@ +module Html.Styled.Ext exposing (ifEnterKey, onEnterKey) + +import Html.Styled exposing (Attribute) +import Html.Styled.Events exposing (keyCode, on) +import Json.Decode as Json + + +{-| Event binding for the `Enter` key. +-} +onEnterKey : msg -> Attribute msg +onEnterKey msg = + on "keydown" (Json.andThen (ifEnterKey msg) keyCode) + + +ifEnterKey : msg -> Int -> Json.Decoder msg +ifEnterKey msg key = + case key of + 13 -> + Json.succeed msg + + _ -> + Json.fail "Another key, that isn't enter, was pressed"