A music player that connects to your cloud/distributed storage.
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

Basic setup for theming (#427)

* feat: Reorganise Elm views into something that resembles themes

* feat: Add 'change theme' item to command palette

* feat: Add 'change theme' nav button

* feat: Store & load selected theme

authored by

Steven Vandevelde and committed by
GitHub
76f31a31 6287575d

+716 -507
+5 -5
Justfile
··· 65 65 {{NPM_DIR}}/.bin/tailwind \ 66 66 --input {{SRC_DIR}}/Css/Application.css \ 67 67 --output {{BUILD_DIR}}/application.css \ 68 - --content "{{SRC_DIR}}/Static/Html/**/*.*,{{SRC_DIR}}/Applications/UI/**/*.elm,{{SRC_DIR}}/Applications/UI.elm,{{SRC_DIR}}/Library/**/*.elm,{{SRC_DIR}}/Javascript/**/*.ts" \ 68 + --content "{{SRC_DIR}}/Static/Html/**/*.*,{{SRC_DIR}}/Core/Themes/**/*.elm,{{SRC_DIR}}/Core/UI/**/*.elm,{{SRC_DIR}}/Core/UI.elm,{{SRC_DIR}}/Library/**/*.elm,{{SRC_DIR}}/Javascript/**/*.ts" \ 69 69 --config {{SYSTEM_DIR}}/Css/Tailwind.js \ 70 70 --postcss {{SYSTEM_DIR}}/Css/PostCSS.js \ 71 71 --jit \ ··· 74 74 75 75 @elm: 76 76 echo "> Compiling Elm application" 77 - {{NPM_DIR}}/.bin/elm make {{SRC_DIR}}/Applications/Brain.elm --output {{BUILD_DIR}}/js/brain.elm.js 78 - {{NPM_DIR}}/.bin/elm make {{SRC_DIR}}/Applications/UI.elm --output {{BUILD_DIR}}/js/ui.elm.js 77 + {{NPM_DIR}}/.bin/elm make {{SRC_DIR}}/Core/Brain.elm --output {{BUILD_DIR}}/js/brain.elm.js 78 + {{NPM_DIR}}/.bin/elm make {{SRC_DIR}}/Core/UI.elm --output {{BUILD_DIR}}/js/ui.elm.js 79 79 80 80 81 81 @elm-prod: 82 82 echo "> Compiling Elm application (optimised)" 83 - {{NPM_DIR}}/.bin/elm make {{SRC_DIR}}/Applications/Brain.elm --output {{BUILD_DIR}}/js/brain.elm.js --optimize 84 - {{NPM_DIR}}/.bin/elm make {{SRC_DIR}}/Applications/UI.elm --output {{BUILD_DIR}}/js/ui.elm.js --optimize 83 + {{NPM_DIR}}/.bin/elm make {{SRC_DIR}}/Core/Brain.elm --output {{BUILD_DIR}}/js/brain.elm.js --optimize 84 + {{NPM_DIR}}/.bin/elm make {{SRC_DIR}}/Core/UI.elm --output {{BUILD_DIR}}/js/ui.elm.js --optimize 85 85 86 86 {{NPM_DIR}}/.bin/esbuild {{BUILD_DIR}}/js/brain.elm.js \ 87 87 --minify --outfile={{BUILD_DIR}}/js/brain.elm.tmp.js
+60 -63
elm.json
··· 1 1 { 2 - "type": "application", 3 - "source-directories": [ 4 - "src/Applications", 5 - "src/Library" 6 - ], 7 - "elm-version": "0.19.1", 8 - "dependencies": { 9 - "direct": { 10 - "FabienHenon/elm-infinite-list-view": "3.2.0", 11 - "Fresheyeball/elm-return": "7.1.0", 12 - "Gizra/elm-all-set": "1.0.1", 13 - "Gizra/elm-debouncer": "2.0.0", 14 - "Herteby/enum": "1.0.1", 15 - "NoRedInk/elm-json-decode-pipeline": "1.0.1", 16 - "arturopala/elm-monocle": "2.2.0", 17 - "avh4/elm-color": "1.0.0", 18 - "elm/browser": "1.0.2", 19 - "elm/core": "1.0.5", 20 - "elm/file": "1.0.5", 21 - "elm/html": "1.0.0", 22 - "elm/http": "2.0.0", 23 - "elm/json": "1.1.3", 24 - "elm/random": "1.0.0", 25 - "elm/regex": "1.0.0", 26 - "elm/svg": "1.0.1", 27 - "elm/time": "1.0.0", 28 - "elm/url": "1.0.0", 29 - "elm/virtual-dom": "1.0.3", 30 - "elm-community/dict-extra": "2.4.0", 31 - "elm-community/html-extra": "3.4.0", 32 - "elm-community/list-extra": "8.7.0", 33 - "elm-community/maybe-extra": "5.3.0", 34 - "elm-explorations/markdown": "1.0.0", 35 - "icidasset/elm-binary": "2.1.0", 36 - "icidasset/elm-material-icons": "11.0.0", 37 - "icidasset/elm-sha": "2.0.2", 38 - "jinjor/elm-xml-parser": "2.0.0", 39 - "jzxhuang/http-extras": "2.1.0", 40 - "lobanov/elm-taskport": "2.0.1", 41 - "mpizenberg/elm-pointer-events": "4.0.2", 42 - "newlandsvalley/elm-binary-base64": "1.0.3", 43 - "noahzgordon/elm-color-extra": "1.0.2", 44 - "ohanhi/keyboard": "2.0.1", 45 - "prozacchiwawa/elm-urlbase64": "1.0.6", 46 - "robinheghan/murmur3": "1.0.0", 47 - "rtfeldman/elm-hex": "1.0.0", 48 - "ryannhg/date-format": "2.3.0", 49 - "truqu/elm-base64": "2.0.4", 50 - "truqu/elm-md5": "1.1.0", 51 - "wernerdegroot/listzipper": "4.0.0", 52 - "ymtszw/elm-xml-decode": "3.2.2" 53 - }, 54 - "indirect": { 55 - "elm/bytes": "1.0.8", 56 - "elm/parser": "1.1.0", 57 - "fredcy/elm-parseint": "2.0.1", 58 - "miniBill/elm-xml-parser": "1.0.1", 59 - "pzp1997/assoc-list": "1.0.0", 60 - "zwilias/elm-utf-tools": "2.0.1" 61 - } 2 + "type": "application", 3 + "source-directories": ["src/Core", "src/Library"], 4 + "elm-version": "0.19.1", 5 + "dependencies": { 6 + "direct": { 7 + "FabienHenon/elm-infinite-list-view": "3.2.0", 8 + "Fresheyeball/elm-return": "7.1.0", 9 + "Gizra/elm-all-set": "1.0.1", 10 + "Gizra/elm-debouncer": "2.0.0", 11 + "Herteby/enum": "1.0.1", 12 + "NoRedInk/elm-json-decode-pipeline": "1.0.1", 13 + "arturopala/elm-monocle": "2.2.0", 14 + "avh4/elm-color": "1.0.0", 15 + "elm/browser": "1.0.2", 16 + "elm/core": "1.0.5", 17 + "elm/file": "1.0.5", 18 + "elm/html": "1.0.0", 19 + "elm/http": "2.0.0", 20 + "elm/json": "1.1.3", 21 + "elm/random": "1.0.0", 22 + "elm/regex": "1.0.0", 23 + "elm/svg": "1.0.1", 24 + "elm/time": "1.0.0", 25 + "elm/url": "1.0.0", 26 + "elm/virtual-dom": "1.0.3", 27 + "elm-community/dict-extra": "2.4.0", 28 + "elm-community/html-extra": "3.4.0", 29 + "elm-community/list-extra": "8.7.0", 30 + "elm-community/maybe-extra": "5.3.0", 31 + "elm-explorations/markdown": "1.0.0", 32 + "icidasset/elm-binary": "2.1.0", 33 + "icidasset/elm-material-icons": "11.0.0", 34 + "icidasset/elm-sha": "2.0.2", 35 + "jinjor/elm-xml-parser": "2.0.0", 36 + "jzxhuang/http-extras": "2.1.0", 37 + "lobanov/elm-taskport": "2.0.1", 38 + "mpizenberg/elm-pointer-events": "4.0.2", 39 + "newlandsvalley/elm-binary-base64": "1.0.3", 40 + "noahzgordon/elm-color-extra": "1.0.2", 41 + "ohanhi/keyboard": "2.0.1", 42 + "prozacchiwawa/elm-urlbase64": "1.0.6", 43 + "robinheghan/murmur3": "1.0.0", 44 + "rtfeldman/elm-hex": "1.0.0", 45 + "ryannhg/date-format": "2.3.0", 46 + "truqu/elm-base64": "2.0.4", 47 + "truqu/elm-md5": "1.1.0", 48 + "wernerdegroot/listzipper": "4.0.0", 49 + "ymtszw/elm-xml-decode": "3.2.2" 62 50 }, 63 - "test-dependencies": { 64 - "direct": {}, 65 - "indirect": {} 51 + "indirect": { 52 + "elm/bytes": "1.0.8", 53 + "elm/parser": "1.1.0", 54 + "fredcy/elm-parseint": "2.0.1", 55 + "miniBill/elm-xml-parser": "1.0.1", 56 + "pzp1997/assoc-list": "1.0.0", 57 + "zwilias/elm-utf-tools": "2.0.1" 66 58 } 59 + }, 60 + "test-dependencies": { 61 + "direct": {}, 62 + "indirect": {} 63 + } 67 64 }
src/Applications/Brain.elm src/Core/Brain.elm
src/Applications/Brain/Common/State.elm src/Core/Brain/Common/State.elm
src/Applications/Brain/Other/State.elm src/Core/Brain/Other/State.elm
src/Applications/Brain/Ports.elm src/Core/Brain/Ports.elm
src/Applications/Brain/Sources/Processing/Common.elm src/Core/Brain/Sources/Processing/Common.elm
src/Applications/Brain/Sources/Processing/State.elm src/Core/Brain/Sources/Processing/State.elm
src/Applications/Brain/Sources/Processing/Steps.elm src/Core/Brain/Sources/Processing/Steps.elm
src/Applications/Brain/Sources/Processing/Types.elm src/Core/Brain/Sources/Processing/Types.elm
src/Applications/Brain/Task/Ports.elm src/Core/Brain/Task/Ports.elm
src/Applications/Brain/Tracks/State.elm src/Core/Brain/Tracks/State.elm
src/Applications/Brain/Types.elm src/Core/Brain/Types.elm
src/Applications/Brain/User/Hypaethral.elm src/Core/Brain/User/Hypaethral.elm
src/Applications/Brain/User/State.elm src/Core/Brain/User/State.elm
src/Applications/Brain/User/Types.elm src/Core/Brain/User/Types.elm
+7
src/Applications/UI.elm src/Core/UI.elm
··· 109 109 , pressedKeys = [] 110 110 , processAutomatically = True 111 111 , serviceWorkerStatus = serviceWorkerStatus 112 + , theme = Nothing 112 113 , uuidSeed = Random.initialSeed flags.initialTime 113 114 , url = url 114 115 , version = flags.version ··· 352 353 ----------------------------------------- 353 354 -- Interface 354 355 ----------------------------------------- 356 + AssistWithChangingTheme -> 357 + Interface.assistWithChangingTheme 358 + 355 359 Blur -> 356 360 Interface.blur 361 + 362 + ChangeTheme a -> 363 + Interface.changeTheme a 357 364 358 365 ContextMenuConfirmation a b -> 359 366 Interface.contextMenuConfirmation a b
src/Applications/UI/Adjunct.elm src/Core/UI/Adjunct.elm
src/Applications/UI/Alfred/State.elm src/Core/UI/Alfred/State.elm
+1 -1
src/Applications/UI/Alfred/View.elm src/Core/Themes/Sunrise/Alfred/View.elm
··· 1 - module UI.Alfred.View exposing (view) 1 + module Themes.Sunrise.Alfred.View exposing (view) 2 2 3 3 import Alfred exposing (..) 4 4 import Chunky exposing (..)
src/Applications/UI/Audio/State.elm src/Core/UI/Audio/State.elm
src/Applications/UI/Audio/Types.elm src/Core/UI/Audio/Types.elm
src/Applications/UI/Backdrop.elm src/Core/UI/Backdrop.elm
+5 -1
src/Applications/UI/Commands/Alfred.elm src/Core/UI/Commands/Alfred.elm
··· 301 301 list 302 302 ) 303 303 in 304 - [ { icon = Just (Icons.favorite 14) 304 + [ { icon = Just (Icons.brush 14) 305 + , title = "Change application theme" 306 + , value = Command UI.AssistWithChangingTheme 307 + } 308 + , { icon = Just (Icons.favorite 14) 305 309 , title = toggle model.favouritesOnly "favourites-only mode" 306 310 , value = Command (UI.TracksMsg Tracks.ToggleFavouritesOnly) 307 311 }
src/Applications/UI/Commands/State.elm src/Core/UI/Commands/State.elm
+16 -17
src/Applications/UI/Common/State.elm src/Core/UI/Common/State.elm
··· 1 1 module UI.Common.State exposing (..) 2 2 3 - import Browser.Dom 4 3 import Browser.Navigation as Nav 5 4 import Common exposing (..) 6 5 import ContextMenu exposing (ContextMenu) ··· 9 8 import Monocle.Lens as Lens exposing (Lens) 10 9 import Notifications exposing (Notification) 11 10 import Return exposing (return) 12 - import Task 13 - import Tracks 14 11 import UI.Notifications 15 12 import UI.Page as Page exposing (Page) 16 13 import UI.Playlists.Directory 17 14 import UI.Syncing.Types as Syncing 18 - import UI.Tracks.Scene.Covers 19 - import UI.Tracks.Scene.List 20 15 import UI.Types as UI exposing (Manager, Model, Msg) 21 16 import User.Layer exposing (Method) 22 17 ··· 64 59 65 60 forceTracksRerender : Manager 66 61 forceTracksRerender model = 67 - let 68 - containerId = 69 - case model.scene of 70 - Tracks.Covers -> 71 - UI.Tracks.Scene.Covers.containerId 72 - 73 - Tracks.List -> 74 - UI.Tracks.Scene.List.containerId 75 - in 76 - Browser.Dom.setViewportOf containerId 0 1 77 - |> Task.attempt (always UI.Bypass) 78 - |> return model 62 + -- 63 + -- TODO: 64 + -- 65 + -- let 66 + -- containerId = 67 + -- case model.scene of 68 + -- Tracks.Covers -> 69 + -- UI.Tracks.Scene.Covers.containerId 70 + -- Tracks.List -> 71 + -- UI.Tracks.Scene.List.containerId 72 + -- in 73 + -- Browser.Dom.setViewportOf containerId 0 1 74 + -- |> Task.attempt (always UI.Bypass) 75 + -- |> return model 76 + -- 77 + Return.singleton model 79 78 80 79 81 80 generateDirectoryPlaylists : Manager
src/Applications/UI/Common/Types.elm src/Core/UI/Common/Types.elm
+1 -1
src/Applications/UI/Console.elm src/Core/Themes/Sunrise/Console.elm
··· 1 - module UI.Console exposing (view) 1 + module Themes.Sunrise.Console exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Conditional exposing (..)
+1 -1
src/Applications/UI/ContextMenu.elm src/Core/Themes/Sunrise/ContextMenu.elm
··· 1 - module UI.ContextMenu exposing (view) 1 + module Themes.Sunrise.ContextMenu exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Conditional exposing (..)
src/Applications/UI/Demo.elm src/Core/UI/Demo.elm
src/Applications/UI/DnD.elm src/Core/UI/DnD.elm
src/Applications/UI/Equalizer/State.elm src/Core/UI/Equalizer/State.elm
+43
src/Applications/UI/Interface/State.elm src/Core/UI/Interface/State.elm
··· 1 1 module UI.Interface.State exposing (..) 2 2 3 + import Alfred 3 4 import Debouncer.Basic as Debouncer 4 5 import Maybe.Extra as Maybe 5 6 import Notifications 6 7 import Return exposing (return) 7 8 import Return.Ext as Return 9 + import Theme 8 10 import Tracks 11 + import UI.Alfred.State as Alfred 9 12 import UI.Common.State as Common 10 13 import UI.Common.Types exposing (DebounceManager) 11 14 import UI.DnD as DnD ··· 13 16 import UI.Playlists.State as Playlists 14 17 import UI.Ports as Ports 15 18 import UI.Queue.State as Queue 19 + import UI.Theme 16 20 import UI.Types exposing (..) 21 + import UI.User.State.Export exposing (saveEnclosedUserData) 17 22 18 23 19 24 20 25 -- 🔱 21 26 22 27 28 + assistWithChangingTheme : Manager 29 + assistWithChangingTheme model = 30 + { action = 31 + \{ result } -> 32 + case result of 33 + Just { value } -> 34 + value 35 + |> Alfred.command 36 + |> Maybe.map List.singleton 37 + |> Maybe.withDefault [] 38 + 39 + Nothing -> 40 + [] 41 + , index = 42 + [ { name = Just "Themes" 43 + , items = 44 + List.map 45 + (\theme -> 46 + { icon = Just (theme.icon 16) 47 + , title = theme.title 48 + , value = Alfred.Command (ChangeTheme { id = theme.id }) 49 + } 50 + ) 51 + UI.Theme.list 52 + } 53 + ] 54 + , message = "Choose a theme." 55 + , operation = Alfred.Query 56 + } 57 + |> Alfred.create 58 + |> (\a -> Alfred.assign a model) 59 + 60 + 23 61 blur : Manager 24 62 blur model = 25 63 Return.singleton { model | focusedOnInput = False, pressedKeys = [] } 64 + 65 + 66 + changeTheme : Theme.Id -> Manager 67 + changeTheme id model = 68 + saveEnclosedUserData { model | theme = Just id } 26 69 27 70 28 71 contextMenuConfirmation : String -> Msg -> Manager
+1 -1
src/Applications/UI/Kit.elm src/Core/Themes/Sunrise/Kit.elm
··· 1 - module UI.Kit exposing (..) 1 + module Themes.Sunrise.Kit exposing (..) 2 2 3 3 import Chunky exposing (..) 4 4 import Color
+1 -1
src/Applications/UI/List.elm src/Core/Themes/Sunrise/List.elm
··· 1 - module UI.List exposing (Action, Item, Variant(..), view) 1 + module Themes.Sunrise.List exposing (Action, Item, Variant(..), view) 2 2 3 3 import Chunky exposing (..) 4 4 import Conditional exposing (..)
+2 -26
src/Applications/UI/Navigation.elm src/Core/Themes/Sunrise/Navigation.elm
··· 1 - module UI.Navigation exposing (Action(..), Icon(..), Label(..), LabelType(..), global, local, localWithTabindex) 1 + module Themes.Sunrise.Navigation exposing (global, local, localWithTabindex) 2 2 3 3 import Alfred exposing (Alfred) 4 4 import Chunky exposing (..) ··· 10 10 import Html.Events.Extra.Mouse as Mouse 11 11 import Material.Icons.Types exposing (Coloring(..)) 12 12 import Maybe.Extra as Maybe 13 - import Svg exposing (Svg) 13 + import UI.Navigation exposing (..) 14 14 import UI.Page as Page exposing (Page) 15 - 16 - 17 - 18 - -- 🌳 19 - 20 - 21 - type Action msg 22 - = NavigateToPage Page 23 - | OpenLinkInNewPage String 24 - | PerformMsg msg 25 - | PerformMsgWithMouseEvent (Mouse.Event -> msg) 26 - 27 - 28 - type Icon msg 29 - = Icon (Int -> Coloring -> Svg msg) 30 - 31 - 32 - type Label 33 - = Label String LabelType 34 - 35 - 36 - type LabelType 37 - = Hidden 38 - | Shown 39 15 40 16 41 17
+2 -63
src/Applications/UI/Notifications.elm src/Core/Themes/Sunrise/Notifications.elm
··· 1 - module UI.Notifications exposing (Model, dismiss, show, showWithModel, view) 1 + module Themes.Sunrise.Notifications exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Color exposing (Color) ··· 10 10 import Html.Lazy 11 11 import Maybe.Extra as Maybe 12 12 import Notifications exposing (..) 13 - import Process 14 - import Task 13 + import UI.Notifications exposing (Model) 15 14 import UI.Types exposing (Msg(..)) 16 - 17 - 18 - 19 - -- 🌳 20 - 21 - 22 - type alias Model = 23 - List (Notification Msg) 24 - 25 - 26 - 27 - -- 📣 28 - 29 - 30 - dismiss : Model -> { id : Int } -> ( Model, Cmd Msg ) 31 - dismiss collection { id } = 32 - ( List.map 33 - (\notification -> 34 - if Notifications.id notification == id then 35 - Notifications.dismiss notification 36 - 37 - else 38 - notification 39 - ) 40 - collection 41 - , Task.perform 42 - (\_ -> RemoveNotification { id = id }) 43 - (Process.sleep 500) 44 - ) 45 - 46 - 47 - show : Notification Msg -> Model -> ( Model, Cmd Msg ) 48 - show notification collection = 49 - let 50 - existingNotificationIds = 51 - List.map Notifications.id collection 52 - in 53 - if List.member (Notifications.id notification) existingNotificationIds then 54 - -- Don't show duplicate notifications 55 - ( collection 56 - , Cmd.none 57 - ) 58 - 59 - else 60 - ( notification :: collection 61 - -- Hide notification after a certain amount of time, 62 - -- unless it's a sticky notification. 63 - , if (Notifications.options notification).sticky then 64 - Cmd.none 65 - 66 - else 67 - Task.perform 68 - (\_ -> DismissNotification { id = Notifications.id notification }) 69 - (Process.sleep 7500) 70 - ) 71 - 72 - 73 - showWithModel : Model -> Notification Msg -> ( Model, Cmd Msg ) 74 - showWithModel model notification = 75 - show notification model 76 15 77 16 78 17
src/Applications/UI/Other/State.elm src/Core/UI/Other/State.elm
src/Applications/UI/Page.elm src/Core/UI/Page.elm
src/Applications/UI/Playlists/Alfred.elm src/Core/UI/Playlists/Alfred.elm
src/Applications/UI/Playlists/ContextMenu.elm src/Core/UI/Playlists/ContextMenu.elm
src/Applications/UI/Playlists/Directory.elm src/Core/UI/Playlists/Directory.elm
src/Applications/UI/Playlists/Page.elm src/Core/UI/Playlists/Page.elm
src/Applications/UI/Playlists/State.elm src/Core/UI/Playlists/State.elm
+30 -29
src/Applications/UI/Playlists/View.elm src/Core/Themes/Sunrise/Playlists/View.elm
··· 1 - module UI.Playlists.View exposing (view) 1 + module Themes.Sunrise.Playlists.View exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Color exposing (Color) ··· 10 10 import Material.Icons.Round as Icons 11 11 import Material.Icons.Types exposing (Coloring(..)) 12 12 import Playlists exposing (..) 13 - import UI.Kit exposing (ButtonType(..)) 14 - import UI.List 13 + import Themes.Sunrise.Kit as Kit exposing (ButtonType(..)) 14 + import Themes.Sunrise.List 15 + import Themes.Sunrise.Navigation as Navigation 15 16 import UI.Navigation exposing (..) 16 17 import UI.Page as Page 17 18 import UI.Playlists.Page exposing (..) ··· 25 26 26 27 view : Page -> List Playlist -> Maybe Playlist -> Maybe { oldName : String, newName : String } -> Maybe Color -> Bool -> Html Msg 27 28 view page playlists selectedPlaylist editContext bgColor authMethodSupportsPublicData = 28 - UI.Kit.receptacle 29 + Kit.receptacle 29 30 { scrolling = True } 30 31 (case page of 31 32 Edit encodedName -> ··· 126 127 [ ----------------------------------------- 127 128 -- Navigation 128 129 ----------------------------------------- 129 - UI.Navigation.local 130 + Navigation.local 130 131 [ ( Icon Icons.arrow_back 131 132 , Label Common.backToIndex Hidden 132 133 , NavigateToPage Page.Index ··· 145 146 [ "relative" ] 146 147 [ chunk 147 148 [ "absolute", "left-0", "top-0" ] 148 - [ UI.Kit.canister [ UI.Kit.h1 "Playlists" ] ] 149 + [ Kit.canister [ Kit.h1 "Playlists" ] ] 149 150 ] 150 151 151 152 else 152 - UI.Kit.canister 153 - [ UI.Kit.h1 "Playlists" 153 + Kit.canister 154 + [ Kit.h1 "Playlists" 154 155 155 156 -- Intro 156 157 -------- ··· 164 165 else 165 166 raw 166 167 [ category "Your Playlists" 167 - , UI.List.view 168 - UI.List.Normal 168 + , Themes.Sunrise.List.view 169 + Themes.Sunrise.List.Normal 169 170 (List.map customPlaylistListItem customPlaylists) 170 171 ] 171 172 ··· 177 178 else 178 179 raw 179 180 [ category "Autogenerated Directory Playlists" 180 - , UI.List.view 181 - UI.List.Normal 181 + , Themes.Sunrise.List.view 182 + Themes.Sunrise.List.Normal 182 183 (List.map directoryPlaylistListItem directoryPlaylists) 183 184 ] 184 185 ] 185 186 186 187 -- 187 188 , if List.isEmpty playlists then 188 - UI.Kit.centeredContent 189 + Kit.centeredContent 189 190 [ slab 190 191 Html.a 191 192 [ href (Page.toString <| Page.Playlists New) ] ··· 223 224 , text "There's also directory playlists, which are playlists derived from root directories." 224 225 ] 225 226 |> raw 226 - |> UI.Kit.intro 227 + |> Kit.intro 227 228 228 229 229 230 category : String -> Html Msg ··· 242 243 ------------ 243 244 , "dark:text-base04" 244 245 ] 245 - [ UI.Kit.inlineIcon Icons.folder 246 + [ Kit.inlineIcon Icons.folder 246 247 , inline [ "font-bold", "ml-2" ] [ text cat ] 247 248 ] 248 249 249 250 250 - selectedPlaylistListItem : Playlist -> Maybe Color -> UI.List.Item Msg 251 + selectedPlaylistListItem : Playlist -> Maybe Color -> Themes.Sunrise.List.Item Msg 251 252 selectedPlaylistListItem playlist bgColor = 252 253 let 253 254 selectionColor = 254 - Maybe.withDefault UI.Kit.colors.selection bgColor 255 + Maybe.withDefault Kit.colors.selection bgColor 255 256 in 256 257 { label = 257 258 brick ··· 285 286 [ ----------------------------------------- 286 287 -- Navigation 287 288 ----------------------------------------- 288 - UI.Navigation.local 289 + Navigation.local 289 290 [ ( Icon Icons.arrow_back 290 291 , Label "Back to list" Hidden 291 292 , NavigateToPage (Page.Playlists Index) ··· 295 296 ----------------------------------------- 296 297 -- Content 297 298 ----------------------------------------- 298 - , [ UI.Kit.h2 "Name your playlist" 299 + , [ Kit.h2 "Name your playlist" 299 300 300 301 -- 301 302 , [ onInput SetPlaylistCreationContext 302 303 , placeholder "The Classics" 303 304 ] 304 - |> UI.Kit.textField 305 + |> Kit.textField 305 306 |> chunky [ "max-w-md", "mx-auto" ] 306 307 307 308 -- Button 308 309 --------- 309 310 , chunk 310 311 [ "mt-10" ] 311 - [ UI.Kit.button 312 + [ Kit.button 312 313 Normal 313 314 Bypass 314 315 (text "Create playlist") 315 316 ] 316 317 ] 317 - |> UI.Kit.canisterForm 318 + |> Kit.canisterForm 318 319 |> List.singleton 319 - |> UI.Kit.centeredContent 320 + |> Kit.centeredContent 320 321 |> List.singleton 321 322 |> slab 322 323 Html.form ··· 337 338 [ ----------------------------------------- 338 339 -- Navigation 339 340 ----------------------------------------- 340 - UI.Navigation.local 341 + Navigation.local 341 342 [ ( Icon Icons.arrow_back 342 343 , Label "Back to list" Hidden 343 344 , NavigateToPage (Page.Playlists Index) ··· 347 348 ----------------------------------------- 348 349 -- Content 349 350 ----------------------------------------- 350 - , [ UI.Kit.h2 "Name your playlist" 351 + , [ Kit.h2 "Name your playlist" 351 352 352 353 -- 353 354 , [ onInput (SetPlaylistModificationContext playlist.name) ··· 365 366 Nothing -> 366 367 value playlist.name 367 368 ] 368 - |> UI.Kit.textField 369 + |> Kit.textField 369 370 |> chunky [ "max-w-md", "mx-auto" ] 370 371 371 372 -- Button 372 373 --------- 373 374 , chunk 374 375 [ "mt-10" ] 375 - [ UI.Kit.button 376 + [ Kit.button 376 377 Normal 377 378 Bypass 378 379 (text "Save") 379 380 ] 380 381 ] 381 - |> UI.Kit.canisterForm 382 + |> Kit.canisterForm 382 383 |> List.singleton 383 - |> UI.Kit.centeredContent 384 + |> Kit.centeredContent 384 385 |> List.singleton 385 386 |> slab 386 387 Html.form
src/Applications/UI/Ports.elm src/Core/UI/Ports.elm
src/Applications/UI/Queue/ContextMenu.elm src/Core/UI/Queue/ContextMenu.elm
src/Applications/UI/Queue/Fill.elm src/Core/UI/Queue/Fill.elm
src/Applications/UI/Queue/Page.elm src/Core/UI/Queue/Page.elm
src/Applications/UI/Queue/State.elm src/Core/UI/Queue/State.elm
src/Applications/UI/Queue/Types.elm src/Core/UI/Queue/Types.elm
+21 -20
src/Applications/UI/Queue/View.elm src/Core/Themes/Sunrise/Queue/View.elm
··· 1 - module UI.Queue.View exposing (view) 1 + module Themes.Sunrise.Queue.View exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Common ··· 10 10 import Material.Icons.Round as Icons 11 11 import Material.Icons.Types exposing (Coloring(..)) 12 12 import Queue exposing (..) 13 + import Themes.Sunrise.Kit as Kit 14 + import Themes.Sunrise.List 15 + import Themes.Sunrise.Navigation as Navigation 13 16 import UI.DnD as DnD 14 - import UI.Kit 15 - import UI.List 16 17 import UI.Navigation exposing (..) 17 18 import UI.Page as Page 18 19 import UI.Queue.Page as Queue exposing (Page(..)) ··· 48 49 49 50 futureView : List Queue.Item -> Maybe Queue.Item -> DnD.Model Int -> Html UI.Msg 50 51 futureView playingNext selectedQueueItem dnd = 51 - UI.Kit.receptacle 52 + Kit.receptacle 52 53 { scrolling = not (DnD.isDragging dnd) } 53 54 [ ----------------------------------------- 54 55 -- Navigation 55 56 ----------------------------------------- 56 - UI.Navigation.local 57 + Navigation.local 57 58 [ ( Icon Icons.arrow_back 58 59 , Label Common.backToIndex Hidden 59 60 , NavigateToPage Page.Index ··· 80 81 [ "relative" ] 81 82 [ chunk 82 83 [ "absolute", "left-0", "top-0" ] 83 - [ UI.Kit.canister [ UI.Kit.h1 "Up next" ] ] 84 + [ Kit.canister [ Kit.h1 "Up next" ] ] 84 85 ] 85 86 86 87 else 87 - UI.Kit.canister 88 - [ UI.Kit.h1 "Up next" 88 + Kit.canister 89 + [ Kit.h1 "Up next" 89 90 , playingNext 90 91 |> List.indexedMap (futureItem selectedQueueItem) 91 - |> UI.List.view 92 - (UI.List.Draggable 92 + |> Themes.Sunrise.List.view 93 + (Themes.Sunrise.List.Draggable 93 94 { model = dnd 94 95 , toMsg = UI.DnD 95 96 } ··· 99 100 100 101 -- 101 102 , if List.isEmpty playingNext then 102 - UI.Kit.centeredContent 103 + Kit.centeredContent 103 104 [ slab 104 105 Html.a 105 106 [ href (Page.toString <| Page.Sources UI.Sources.Page.New) ] ··· 120 121 ] 121 122 122 123 123 - futureItem : Maybe Item -> Int -> Queue.Item -> UI.List.Item UI.Msg 124 + futureItem : Maybe Item -> Int -> Queue.Item -> Themes.Sunrise.List.Item UI.Msg 124 125 futureItem selectedQueueItem idx item = 125 126 let 126 127 ( identifiers, track ) = ··· 222 223 223 224 historyView : List Queue.Item -> DnD.Model Int -> Html UI.Msg 224 225 historyView playedPreviously dnd = 225 - UI.Kit.receptacle 226 + Kit.receptacle 226 227 { scrolling = not (DnD.isDragging dnd) } 227 228 [ ----------------------------------------- 228 229 -- Navigation 229 230 ----------------------------------------- 230 - UI.Navigation.local 231 + Navigation.local 231 232 [ ( Icon Icons.arrow_back 232 233 , Label Common.backToIndex Hidden 233 234 , NavigateToPage Page.Index ··· 246 247 [ "relative" ] 247 248 [ chunk 248 249 [ "absolute", "left-0", "top-0" ] 249 - [ UI.Kit.canister [ UI.Kit.h1 "History" ] ] 250 + [ Kit.canister [ Kit.h1 "History" ] ] 250 251 ] 251 252 252 253 else 253 - UI.Kit.canister 254 - [ UI.Kit.h1 "History" 254 + Kit.canister 255 + [ Kit.h1 "History" 255 256 , playedPreviously 256 257 |> List.reverse 257 258 |> List.indexedMap historyItem 258 - |> UI.List.view UI.List.Normal 259 + |> Themes.Sunrise.List.view Themes.Sunrise.List.Normal 259 260 |> chunky [ "mt-3" ] 260 261 ] 261 262 262 263 -- 263 264 , if List.isEmpty playedPreviously then 264 - UI.Kit.centeredContent 265 + Kit.centeredContent 265 266 [ chunk 266 267 [ "opacity-30" ] 267 268 [ Icons.music_note 64 Inherit ] ··· 278 279 ] 279 280 280 281 281 - historyItem : Int -> Queue.Item -> UI.List.Item UI.Msg 282 + historyItem : Int -> Queue.Item -> Themes.Sunrise.List.Item UI.Msg 282 283 historyItem idx ({ identifiedTrack } as item) = 283 284 let 284 285 ( _, track ) =
src/Applications/UI/Routing/State.elm src/Core/UI/Routing/State.elm
src/Applications/UI/Services/State.elm src/Core/UI/Services/State.elm
+30 -25
src/Applications/UI/Settings.elm src/Core/Themes/Sunrise/Settings.elm
··· 1 - module UI.Settings exposing (Dependencies, view) 1 + module Themes.Sunrise.Settings exposing (Dependencies, view) 2 2 3 3 import Chunky exposing (..) 4 4 import Color exposing (Color) ··· 13 13 import Material.Icons.Round as Icons 14 14 import Material.Icons.Types exposing (Coloring(..)) 15 15 import Maybe.Extra as Maybe 16 + import Themes.Sunrise.Kit as Kit 17 + import Themes.Sunrise.Navigation as Navigation 18 + import Themes.Sunrise.Settings.Data 19 + import Themes.Sunrise.Settings.Sync 16 20 import Time 17 21 import UI.Backdrop as Backdrop exposing (backgroundPositioning) 18 - import UI.Kit 19 22 import UI.Navigation exposing (..) 20 23 import UI.Page as Page 21 - import UI.Settings.Data 22 24 import UI.Settings.Page as Settings exposing (..) 23 - import UI.Settings.Sync 24 25 import UI.Sources.Types as Sources 25 26 import UI.Tracks.Types as Tracks 26 27 import UI.Types exposing (Msg(..)) ··· 51 52 view page deps = 52 53 case page of 53 54 Data -> 54 - UI.Settings.Data.view deps.syncMethod 55 + Themes.Sunrise.Settings.Data.view deps.syncMethod 55 56 56 57 Index -> 57 - UI.Kit.receptacle { scrolling = True } (index deps) 58 + Kit.receptacle { scrolling = True } (index deps) 58 59 59 60 Sync -> 60 - UI.Settings.Sync.view deps.syncMethod 61 + Themes.Sunrise.Settings.Sync.view deps.syncMethod 61 62 62 63 63 64 ··· 69 70 [ ----------------------------------------- 70 71 -- Navigation 71 72 ----------------------------------------- 72 - UI.Navigation.local 73 + Navigation.local 73 74 [ ( Icon Icons.account_circle 74 75 , Label "Data & Sync" Shown 75 76 , NavigateToPage (Page.Settings Sync) 76 77 ) 78 + , ( Icon Icons.brush 79 + , Label "Change theme" Shown 80 + , PerformMsg AssistWithChangingTheme 81 + ) 77 82 , ( Icon Icons.help_outline 78 83 , Label "Help" Shown 79 84 , OpenLinkInNewPage "about/" ··· 87 92 |> content 88 93 |> chunk [ "pb-4" ] 89 94 |> List.singleton 90 - |> UI.Kit.canister 95 + |> Kit.canister 91 96 ] 92 97 93 98 ··· 96 101 [ ----------------------------------------- 97 102 -- Title 98 103 ----------------------------------------- 99 - UI.Kit.h1 "Settings" 104 + Kit.h1 "Settings" 100 105 101 106 ----------------------------------------- 102 107 -- Version ··· 229 234 [ chunk 230 235 [ "w-full", "md:w-1/2" ] 231 236 [ label "Downloaded tracks" 232 - , UI.Kit.buttonWithColor 233 - UI.Kit.Gray 234 - UI.Kit.Normal 237 + , Kit.buttonWithColor 238 + Kit.Gray 239 + Kit.Normal 235 240 (TracksMsg Tracks.ClearCache) 236 241 (text "Clear cache") 237 242 ] ··· 245 250 -- 246 251 , case ( deps.lastFm.authenticating, deps.lastFm.sessionKey ) of 247 252 ( _, Just _ ) -> 248 - UI.Kit.checkbox 253 + Kit.checkbox 249 254 { checked = True 250 255 , toggleMsg = DisconnectLastFm 251 256 } 252 257 253 258 ( True, Nothing ) -> 254 - UI.Kit.buttonWithColor 255 - UI.Kit.Gray 256 - UI.Kit.Normal 259 + Kit.buttonWithColor 260 + Kit.Gray 261 + Kit.Normal 257 262 Bypass 258 263 (text "Connecting") 259 264 260 265 ( False, Nothing ) -> 261 - UI.Kit.buttonWithColor 262 - UI.Kit.Gray 263 - UI.Kit.Normal 266 + Kit.buttonWithColor 267 + Kit.Gray 268 + Kit.Normal 264 269 ConnectLastFm 265 270 (text "Connect") 266 271 ] ··· 274 279 [ chunk 275 280 [ "w-full", "md:w-1/2" ] 276 281 [ label "Hide Duplicates" 277 - , UI.Kit.checkbox 282 + , Kit.checkbox 278 283 { checked = deps.hideDuplicateTracks 279 284 , toggleMsg = TracksMsg Tracks.ToggleHideDuplicates 280 285 } ··· 282 287 , chunk 283 288 [ "w-full", "md:w-1/2" ] 284 289 [ label "Process sources automatically" 285 - , UI.Kit.checkbox 290 + , Kit.checkbox 286 291 { checked = deps.processAutomatically 287 292 , toggleMsg = SourcesMsg Sources.ToggleProcessAutomatically 288 293 } ··· 297 302 [ chunk 298 303 [ "w-full", "md:w-1/2" ] 299 304 [ label "Remember position on long tracks" 300 - , UI.Kit.checkbox 305 + , Kit.checkbox 301 306 { checked = deps.rememberProgress 302 307 , toggleMsg = ToggleRememberProgress 303 308 } ··· 305 310 , chunk 306 311 [ "w-full", "md:w-1/2" ] 307 312 [ label "Cover selection reduces track pool" 308 - , UI.Kit.checkbox 313 + , Kit.checkbox 309 314 { checked = deps.coverSelectionReducesPool 310 315 , toggleMsg = TracksMsg Tracks.ToggleCoverSelectionReducesPool 311 316 } ··· 318 323 label l = 319 324 chunk 320 325 [ "mb-3", "mt-6", "pb-px" ] 321 - [ UI.Kit.label [] l ] 326 + [ Kit.label [] l ] 322 327 323 328 324 329
+1 -1
src/Applications/UI/Settings/Common.elm src/Core/Themes/Sunrise/Settings/Common.elm
··· 1 - module UI.Settings.Common exposing (..) 1 + module Themes.Sunrise.Settings.Common exposing (..) 2 2 3 3 import Material.Icons.Round as Icons 4 4 import UI.Navigation exposing (..)
+10 -9
src/Applications/UI/Settings/Data.elm src/Core/Themes/Sunrise/Settings/Data.elm
··· 1 - module UI.Settings.Data exposing (view) 1 + module Themes.Sunrise.Settings.Data exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Html exposing (Html, text) 5 5 import Material.Icons.Round as Icons 6 - import UI.Kit exposing (ButtonColor(..), ButtonType(..)) 6 + import Themes.Sunrise.Kit as Kit exposing (ButtonColor(..), ButtonType(..)) 7 + import Themes.Sunrise.Navigation as Navigation 8 + import Themes.Sunrise.Settings.Common exposing (changePassphrase) 7 9 import UI.Navigation exposing (..) 8 10 import UI.Page as Page 9 - import UI.Settings.Common exposing (changePassphrase) 10 11 import UI.Settings.Page exposing (Page(..)) 11 12 import UI.Types exposing (Msg(..)) 12 13 import User.Layer exposing (Method(..)) ··· 18 19 19 20 view : Maybe Method -> Html Msg 20 21 view activeMethod = 21 - UI.Kit.receptacle 22 + Kit.receptacle 22 23 { scrolling = True } 23 24 [ ----------------------------------------- 24 25 -- Navigation ··· 49 50 , NavigateToPage (Page.Settings Sync) 50 51 ) 51 52 ] 52 - |> UI.Navigation.local 53 + |> Navigation.local 53 54 54 55 ----------------------------------------- 55 56 -- Content ··· 58 59 [ "relative" ] 59 60 [ chunk 60 61 [ "absolute", "left-0", "top-0" ] 61 - [ UI.Kit.canister [ UI.Kit.h1 "Data Backup" ] ] 62 + [ Kit.canister [ Kit.h1 "Data Backup" ] ] 62 63 ] 63 64 64 65 -- 65 - , UI.Kit.focusScreen 66 + , Kit.focusScreen 66 67 { icon = Icons.archive 67 68 , iconHref = Nothing 68 69 , text = ··· 75 76 } 76 77 [ chunk 77 78 [ "flex", "space-x-2.5" ] 78 - [ UI.Kit.button 79 + [ Kit.button 79 80 Normal 80 81 RequestImport 81 82 (text "Import snapshot") 82 83 83 84 -- 84 - , UI.Kit.buttonWithColor 85 + , Kit.buttonWithColor 85 86 Accent 86 87 Filled 87 88 Export
src/Applications/UI/Settings/Page.elm src/Core/UI/Settings/Page.elm
+11 -10
src/Applications/UI/Settings/Sync.elm src/Core/Themes/Sunrise/Settings/Sync.elm
··· 1 - module UI.Settings.Sync exposing (view) 1 + module Themes.Sunrise.Settings.Sync exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Html exposing (Html, text) 5 5 import Material.Icons.Round as Icons 6 6 import Maybe.Extra as Maybe 7 - import UI.Kit 8 - import UI.List 7 + import Themes.Sunrise.Kit as Kit 8 + import Themes.Sunrise.List 9 + import Themes.Sunrise.Navigation as Navigation 10 + import Themes.Sunrise.Settings.Common exposing (changePassphrase) 9 11 import UI.Navigation exposing (..) 10 12 import UI.Page as Page 11 - import UI.Settings.Common exposing (changePassphrase) 12 13 import UI.Settings.Page exposing (Page(..)) 13 14 import UI.Svg.Elements 14 15 import UI.Syncing.Common exposing (startDropbox, startFission, startIpfs, startRemoteStorage) ··· 23 24 24 25 view : Maybe Method -> Html Msg 25 26 view activeMethod = 26 - UI.Kit.receptacle 27 + Kit.receptacle 27 28 { scrolling = True } 28 29 [ ----------------------------------------- 29 30 -- Navigation ··· 54 55 , NavigateToPage (Page.Settings Data) 55 56 ) 56 57 ] 57 - |> UI.Navigation.local 58 + |> Navigation.local 58 59 59 60 ----------------------------------------- 60 61 -- Content ··· 63 64 [ "relative" ] 64 65 [ chunk 65 66 [ "absolute", "left-0", "top-0" ] 66 - [ UI.Kit.canister [ UI.Kit.h1 "Storage Service" ] ] 67 + [ Kit.canister [ Kit.h1 "Storage Service" ] ] 67 68 ] 68 69 69 70 -- 70 - , UI.Kit.focusScreen 71 + , Kit.focusScreen 71 72 { icon = Icons.account_circle 72 73 , iconHref = Nothing 73 74 , text = ··· 84 85 , ipfsMethod 85 86 ] 86 87 |> List.map (methodView activeMethod) 87 - |> UI.List.view UI.List.Normal 88 + |> Themes.Sunrise.List.view Themes.Sunrise.List.Normal 88 89 |> List.singleton 89 90 |> chunk [ "max-w-full", "w-96" ] 90 91 ] 91 92 ] 92 93 93 94 94 - methodInfoAction : Bool -> Maybe Method -> Method -> UI.List.Action Msg 95 + methodInfoAction : Bool -> Maybe Method -> Method -> Themes.Sunrise.List.Action Msg 95 96 methodInfoAction isSelected activeMethod method = 96 97 { icon = 97 98 \a b ->
src/Applications/UI/Sources/ContextMenu.elm src/Core/UI/Sources/ContextMenu.elm
+36 -61
src/Applications/UI/Sources/Form.elm src/Core/Themes/Sunrise/Sources/Form.elm
··· 1 - module UI.Sources.Form exposing (..) 1 + module Themes.Sunrise.Sources.Form exposing (..) 2 2 3 3 import Chunky exposing (..) 4 4 import Common exposing (boolFromString, boolToString) ··· 12 12 import Material.Icons.Types exposing (Coloring(..)) 13 13 import Sources exposing (..) 14 14 import Sources.Services as Services 15 - import UI.Kit exposing (ButtonType(..), select) 15 + import Themes.Sunrise.Kit as Kit exposing (ButtonType(..), select) 16 + import Themes.Sunrise.Navigation as Navigation 16 17 import UI.Navigation exposing (..) 17 18 import UI.Page as Page 18 19 import UI.Sources.Page as Sources ··· 20 21 21 22 22 23 23 - -- 🌳 24 - 25 - 26 - initialModel : Form 27 - initialModel = 28 - { step = Where 29 - , context = defaultContext 30 - } 31 - 32 - 33 - defaultContext : Source 34 - defaultContext = 35 - { id = "CHANGE_ME_PLEASE" 36 - , data = Services.initialData defaultService 37 - , directoryPlaylists = True 38 - , enabled = True 39 - , service = defaultService 40 - } 41 - 42 - 43 - defaultService : Service 44 - defaultService = 45 - Dropbox 46 - 47 - 48 - 49 24 -- NEW 50 25 51 26 ··· 71 46 [ ----------------------------------------- 72 47 -- Navigation 73 48 ----------------------------------------- 74 - UI.Navigation.local 49 + Navigation.local 75 50 [ ( Icon Icons.arrow_back 76 51 , Label "Back to list" Hidden 77 52 -- ··· 88 63 ----------------------------------------- 89 64 , (\h -> 90 65 form TakeStep 91 - [ UI.Kit.canisterForm h ] 66 + [ Kit.canisterForm h ] 92 67 ) 93 - [ UI.Kit.h2 "Where is your music stored?" 68 + [ Kit.h2 "Where is your music stored?" 94 69 95 70 -- Dropdown 96 71 ----------- ··· 111 86 --------- 112 87 , chunk 113 88 [ "mt-10" ] 114 - [ UI.Kit.button 89 + [ Kit.button 115 90 IconOnly 116 91 Bypass 117 92 (Icons.arrow_forward 17 Inherit) ··· 125 100 [ ----------------------------------------- 126 101 -- Navigation 127 102 ----------------------------------------- 128 - UI.Navigation.local 103 + Navigation.local 129 104 [ ( Icon Icons.arrow_back 130 105 , Label "Take a step back" Shown 131 106 , PerformMsg TakeStepBackwards ··· 139 114 form TakeStep 140 115 [ chunk 141 116 [ "text-left", "w-full" ] 142 - [ UI.Kit.canister h ] 117 + [ Kit.canister h ] 143 118 ] 144 119 ) 145 - [ UI.Kit.h3 "Where exactly?" 120 + [ Kit.h3 "Where exactly?" 146 121 147 122 -- Note 148 123 ------- ··· 174 149 --------- 175 150 , chunk 176 151 [ "mt-3", "text-center" ] 177 - [ UI.Kit.button 152 + [ Kit.button 178 153 IconOnly 179 154 Bypass 180 155 (Icons.arrow_forward 17 Inherit) ··· 199 174 [ ----------------------------------------- 200 175 -- Navigation 201 176 ----------------------------------------- 202 - UI.Navigation.local 177 + Navigation.local 203 178 [ ( Icon Icons.arrow_back 204 179 , Label "Take a step back" Shown 205 180 , PerformMsg TakeStepBackwards ··· 211 186 ----------------------------------------- 212 187 , (\h -> 213 188 form AddSourceUsingForm 214 - [ UI.Kit.canisterForm h ] 189 + [ Kit.canisterForm h ] 215 190 ) 216 - [ UI.Kit.h2 "One last thing" 217 - , UI.Kit.label [] "What are we going to call this source?" 191 + [ Kit.h2 "One last thing" 192 + , Kit.label [] "What are we going to call this source?" 218 193 219 194 -- Input 220 195 -------- ··· 230 205 , "justify-center" 231 206 , "w-full" 232 207 ] 233 - [ UI.Kit.textField 208 + [ Kit.textField 234 209 [ name "name" 235 210 , onInput (SetFormData "name") 236 211 , value nameValue ··· 269 244 270 245 -- Button 271 246 --------- 272 - , UI.Kit.button 247 + , Kit.button 273 248 Normal 274 249 Bypass 275 250 (text "Add source") ··· 281 256 corsWarning id = 282 257 [ chunk 283 258 [ "text-sm", "flex", "items-center", "justify-center", "leading-snug", "opacity-50" ] 284 - [ UI.Kit.inlineIcon Icons.warning 259 + [ Kit.inlineIcon Icons.warning 285 260 , inline 286 261 [ "font-semibold" ] 287 262 [ text "Make sure CORS is enabled" ] ··· 289 264 , chunk 290 265 [ "text-sm", "leading-snug", "mb-8", "mt-1", "opacity-50" ] 291 266 [ text "You can find the instructions over " 292 - , UI.Kit.link { label = "here", url = "about/cors/#" ++ id } 267 + , Kit.link { label = "here", url = "about/cors/#" ++ id } 293 268 ] 294 269 ] 295 270 ··· 303 278 [ ----------------------------------------- 304 279 -- Navigation 305 280 ----------------------------------------- 306 - UI.Navigation.local 281 + Navigation.local 307 282 [ ( Icon Icons.arrow_back 308 283 , Label "Go Back" Shown 309 284 , PerformMsg ReturnToIndex ··· 317 292 form EditSourceUsingForm 318 293 [ chunk 319 294 [ "text-left", "w-full" ] 320 - [ UI.Kit.canister h ] 295 + [ Kit.canister h ] 321 296 ] 322 297 ) 323 - [ UI.Kit.h3 "Edit source" 298 + [ Kit.h3 "Edit source" 324 299 325 300 -- Note 326 301 ------- ··· 352 327 --------- 353 328 , chunk 354 329 [ "mt-3", "text-center" ] 355 - [ UI.Kit.button 330 + [ Kit.button 356 331 Normal 357 332 Bypass 358 333 (text "Save") ··· 369 344 renderProperty context property = 370 345 chunk 371 346 [ "mb-8" ] 372 - [ UI.Kit.label 347 + [ Kit.label 373 348 [ for property.key ] 374 349 property.label 375 350 ··· 386 361 in 387 362 chunk 388 363 [ "mt-2", "pt-1" ] 389 - [ UI.Kit.checkbox 364 + [ Kit.checkbox 390 365 { checked = bool 391 366 , toggleMsg = 392 367 bool ··· 397 372 ] 398 373 399 374 else 400 - UI.Kit.textField 375 + Kit.textField 401 376 [ name property.key 402 377 , onInput (SetFormData property.key) 403 378 , placeholder property.placeholder ··· 425 400 , "flex-shrink-0" 426 401 , "text-center" 427 402 ] 428 - [ UI.Kit.centeredContent html ] 403 + [ Kit.centeredContent html ] 429 404 430 405 431 406 note : Service -> Html Msg ··· 501 476 howNote 502 477 [ inline 503 478 [ "font-semibold" ] 504 - [ UI.Kit.inlineIcon Icons.warning 479 + [ Kit.inlineIcon Icons.warning 505 480 , text "This app requires a proper implementation of " 506 - , UI.Kit.link 481 + , Kit.link 507 482 { label = "CORS" 508 483 , url = "https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" 509 484 } ··· 514 489 , text " CORS properly, if at all." 515 490 , lineBreak 516 491 , text " Some servers, like " 517 - , UI.Kit.link 492 + , Kit.link 518 493 { label = "this one" 519 494 , url = "https://github.com/hacdias/webdav" 520 495 } 521 496 , text ", do. You can find the configuration for that server " 522 - , UI.Kit.link 497 + , Kit.link 523 498 { label = "here" 524 499 , url = "about/cors/#CORS__WebDAV" 525 500 } ··· 536 511 [ ----------------------------------------- 537 512 -- Navigation 538 513 ----------------------------------------- 539 - UI.Navigation.local 514 + Navigation.local 540 515 [ ( Icon Icons.arrow_back 541 516 , Label "Go Back" Shown 542 517 , PerformMsg ReturnToIndex ··· 548 523 ----------------------------------------- 549 524 , (\h -> 550 525 form RenameSourceUsingForm 551 - [ UI.Kit.canisterForm h ] 526 + [ Kit.canisterForm h ] 552 527 ) 553 - [ UI.Kit.h2 "Name your source" 528 + [ Kit.h2 "Name your source" 554 529 555 530 -- Input 556 531 -------- ··· 558 533 , onInput (SetFormData "name") 559 534 , value (Dict.fetch "name" "" context.data) 560 535 ] 561 - |> UI.Kit.textField 536 + |> Kit.textField 562 537 |> chunky [ "max-w-md", "mx-auto" ] 563 538 564 539 -- Button 565 540 --------- 566 541 , chunk 567 542 [ "mt-10" ] 568 - [ UI.Kit.button 543 + [ Kit.button 569 544 Normal 570 545 Bypass 571 546 (text "Save")
src/Applications/UI/Sources/Page.elm src/Core/UI/Sources/Page.elm
src/Applications/UI/Sources/Query.elm src/Core/UI/Sources/Query.elm
src/Applications/UI/Sources/State.elm src/Core/UI/Sources/State.elm
src/Applications/UI/Sources/Types.elm src/Core/UI/Sources/Types.elm
+16 -15
src/Applications/UI/Sources/View.elm src/Core/Themes/Sunrise/Sources/View.elm
··· 1 - module UI.Sources.View exposing (view) 1 + module Themes.Sunrise.Sources.View exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Conditional exposing (ifThenElse) ··· 10 10 import Material.Icons.Round as Icons 11 11 import Material.Icons.Types exposing (Coloring(..)) 12 12 import Sources exposing (..) 13 - import UI.Kit 14 - import UI.List 13 + import Themes.Sunrise.Kit as Kit 14 + import Themes.Sunrise.List 15 + import Themes.Sunrise.Navigation as Navigation 16 + import Themes.Sunrise.Sources.Form as Form 15 17 import UI.Navigation exposing (..) 16 18 import UI.Page as Page 17 - import UI.Sources.Form as Form 18 19 import UI.Sources.Page as Sources exposing (..) 19 20 import UI.Sources.Types exposing (Msg(..)) 20 21 import UI.Types as UI exposing (Model) ··· 70 71 71 72 72 73 receptacle = 73 - UI.Kit.receptacle { scrolling = True } 74 + Kit.receptacle { scrolling = True } 74 75 75 76 76 77 ··· 83 84 -- Navigation 84 85 ----------------------------------------- 85 86 if List.isEmpty model.sources then 86 - UI.Navigation.local 87 + Navigation.local 87 88 [ ( Icon Icons.add 88 89 , Label "Add a new source" Shown 89 90 , NavigateToPage (Page.Sources New) ··· 91 92 ] 92 93 93 94 else 94 - UI.Navigation.local 95 + Navigation.local 95 96 [ ( Icon Icons.add 96 97 , Label "Add a new source" Shown 97 98 , NavigateToPage (Page.Sources New) ··· 120 121 [ "relative" ] 121 122 [ chunk 122 123 [ "absolute", "left-0", "top-0" ] 123 - [ UI.Kit.canister [ UI.Kit.h1 "Sources" ] ] 124 + [ Kit.canister [ Kit.h1 "Sources" ] ] 124 125 ] 125 126 126 127 else 127 - UI.Kit.canister 128 - [ UI.Kit.h1 "Sources" 128 + Kit.canister 129 + [ Kit.h1 "Sources" 129 130 130 131 -- Intro 131 132 -------- ··· 144 145 , isSelected = False 145 146 } 146 147 ) 147 - |> UI.List.view UI.List.Normal 148 + |> Themes.Sunrise.List.view Themes.Sunrise.List.Normal 148 149 ] 149 150 150 151 -- 151 152 , if List.isEmpty model.sources then 152 - UI.Kit.centeredContent 153 + Kit.centeredContent 153 154 [ slab 154 155 Html.a 155 156 [ href (Page.toString <| Page.Sources New) ] ··· 195 196 , text " in your collection." 196 197 ] 197 198 |> raw 198 - |> UI.Kit.intro 199 + |> Kit.intro 199 200 200 201 201 - sourceActions : List ( String, Float ) -> Maybe { error : String, sourceId : String } -> Source -> List (UI.List.Action Msg) 202 + sourceActions : List ( String, Float ) -> Maybe { error : String, sourceId : String } -> Source -> List (Themes.Sunrise.List.Action Msg) 202 203 sourceActions processingContext processingError source = 203 204 let 204 205 processIndex = ··· 243 244 244 245 ( Nothing, Just { error, sourceId } ) -> 245 246 if sourceId == source.id then 246 - [ { icon = \size _ -> Icons.error_outline size (Color UI.Kit.colors.error) 247 + [ { icon = \size _ -> Icons.error_outline size (Color Kit.colors.error) 247 248 , msg = Nothing 248 249 , title = error 249 250 }
src/Applications/UI/Svg/Elements.elm src/Core/UI/Svg/Elements.elm
+9 -11
src/Applications/UI/Syncing/Common.elm src/Core/UI/Syncing/Common.elm
··· 3 3 import Chunky exposing (..) 4 4 import Html 5 5 import Svg 6 - import UI.Kit 7 6 import UI.Svg.Elements 8 7 import UI.Syncing.Types exposing (..) 9 8 import UI.Types exposing (Msg(..)) ··· 34 33 { icon = \size _ -> Svg.map never (UI.Svg.Elements.remoteStorageLogo size) 35 34 , placeholder = "example@5apps.com" 36 35 , question = 37 - UI.Kit.askForInput 38 - { question = 39 - "What's your user address?" 40 - , info = 41 - [ Html.text "The format is " 42 - , inline 43 - [] 44 - [ Html.text "username@server.domain" ] 45 - ] 46 - } 36 + { question = 37 + "What's your user address?" 38 + , info = 39 + [ Html.text "The format is " 40 + , inline 41 + [] 42 + [ Html.text "username@server.domain" ] 43 + ] 44 + } 47 45 , value = "" 48 46 } 49 47 |> AskForInput remoteStorageMethod
src/Applications/UI/Syncing/ContextMenu.elm src/Core/UI/Syncing/ContextMenu.elm
+15 -17
src/Applications/UI/Syncing/State.elm src/Core/UI/Syncing/State.elm
··· 26 26 import Time 27 27 import UI.Backdrop as Backdrop 28 28 import UI.Common.State as Common exposing (showNotification, showNotificationWithModel) 29 - import UI.Kit 30 29 import UI.Ports as Ports 31 30 import UI.Sources.State as Sources 32 31 import UI.Svg.Elements ··· 546 545 { icon = \size _ -> Svg.map never (UI.Svg.Elements.ipfsLogo size) 547 546 , placeholder = "//localhost:5001" 548 547 , question = 549 - UI.Kit.askForInput 550 - { question = 551 - "Where's your IPFS API located?" 552 - , info = 553 - [ Html.text "You can find this address on the IPFS Web UI." 554 - , Html.br [] [] 555 - , Html.text "Most likely you'll also need to setup CORS." 556 - , Html.br [] [] 557 - , Html.text "You can find the instructions for that " 558 - , Html.a 559 - [ Html.Attributes.class "border-b border-current-color font-semibold inline-block leading-tight" 560 - , Html.Attributes.href "about/cors/#CORS__IPFS" 561 - , Html.Attributes.target "_blank" 562 - ] 563 - [ Html.text "here" ] 548 + { question = 549 + "Where's your IPFS API located?" 550 + , info = 551 + [ Html.text "You can find this address on the IPFS Web UI." 552 + , Html.br [] [] 553 + , Html.text "Most likely you'll also need to setup CORS." 554 + , Html.br [] [] 555 + , Html.text "You can find the instructions for that " 556 + , Html.a 557 + [ Html.Attributes.class "border-b border-current-color font-semibold inline-block leading-tight" 558 + , Html.Attributes.href "about/cors/#CORS__IPFS" 559 + , Html.Attributes.target "_blank" 564 560 ] 565 - } 561 + [ Html.text "here" ] 562 + ] 563 + } 566 564 , value = "//localhost:5001" 567 565 } 568 566
+1 -1
src/Applications/UI/Syncing/Types.elm src/Core/UI/Syncing/Types.elm
··· 27 27 type alias Question = 28 28 { icon : Int -> Coloring -> Svg Msg 29 29 , placeholder : String 30 - , question : Html Msg 30 + , question : { question : String, info : List (Html Msg) } 31 31 , value : String 32 32 } 33 33
+18 -18
src/Applications/UI/Syncing/View.elm src/Core/Themes/Sunrise/Syncing/View.elm
··· 1 - module UI.Syncing.View exposing (view) 1 + module Themes.Sunrise.Syncing.View exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Html exposing (Html, text) ··· 10 10 import Json.Decode 11 11 import Material.Icons.Round as Icons 12 12 import Material.Icons.Types exposing (Coloring(..)) 13 - import UI.Kit 13 + import Themes.Sunrise.Kit as Kit 14 14 import UI.Syncing.Types as Syncing exposing (..) 15 15 import UI.Types as UI exposing (..) 16 16 ··· 28 28 view_ state = 29 29 case state of 30 30 InputScreen _ opts -> 31 - UI.Kit.receptacle 31 + Kit.receptacle 32 32 { scrolling = False } 33 33 [ inputScreen opts ] 34 34 35 35 NewEncryptionKeyScreen method pass -> 36 - UI.Kit.receptacle 36 + Kit.receptacle 37 37 { scrolling = False } 38 38 [ encryptionKeyScreen 39 39 { ableToCancel = False ··· 43 43 ] 44 44 45 45 UpdateEncryptionKeyScreen method pass -> 46 - UI.Kit.receptacle 46 + Kit.receptacle 47 47 { scrolling = False } 48 48 [ encryptionKeyScreen 49 49 { ableToCancel = True ··· 62 62 63 63 encryptionKeyScreen : { ableToCancel : Bool, withEncryption : Syncing.Msg, withoutEncryption : Syncing.Msg } -> Html Syncing.Msg 64 64 encryptionKeyScreen { ableToCancel, withEncryption, withoutEncryption } = 65 - UI.Kit.focusScreen 65 + Kit.focusScreen 66 66 { icon = Icons.lock 67 67 , iconHref = Nothing 68 68 , text = [ text "Optional passphrase to encrypt/decrypt your data" ] ··· 80 80 -- 81 81 , "sm:px-0" 82 82 ] 83 - [ UI.Kit.textArea 83 + [ Kit.textArea 84 84 [ attribute "autocapitalize" "none" 85 85 , attribute "autocomplete" "off" 86 86 , attribute "autocorrect" "off" ··· 102 102 , "items-stretch" 103 103 , "space-x-2.5" 104 104 ] 105 - [ UI.Kit.buttonWithOptions 105 + [ Kit.buttonWithOptions 106 106 Html.button 107 107 [ A.class "flex-1" ] 108 - UI.Kit.Gray 109 - UI.Kit.Filled 108 + Kit.Gray 109 + Kit.Filled 110 110 (Just Syncing.Bypass) 111 111 (text "Continue") 112 112 113 113 -- 114 114 , if ableToCancel then 115 - UI.Kit.buttonWithOptions 115 + Kit.buttonWithOptions 116 116 Html.button 117 117 [ A.class "flex-1" 118 118 , E.stopPropagationOn "click" (Json.Decode.succeed ( CancelInput, True )) 119 119 ] 120 - UI.Kit.Gray 121 - UI.Kit.Normal 120 + Kit.Gray 121 + Kit.Normal 122 122 Nothing 123 123 (text "Cancel") 124 124 ··· 149 149 150 150 inputScreen : Question -> Html Syncing.Msg 151 151 inputScreen question = 152 - UI.Kit.focusScreen 152 + Kit.focusScreen 153 153 { icon = question.icon 154 154 , iconHref = Nothing 155 - , text = [ question.question ] 155 + , text = [ Kit.askForInput question.question ] 156 156 , textHref = Nothing 157 157 } 158 158 [ slab ··· 167 167 -- 168 168 , "sm:px-0" 169 169 ] 170 - [ UI.Kit.textFieldAlt 170 + [ Kit.textFieldAlt 171 171 [ attribute "autocapitalize" "off" 172 172 , placeholder question.placeholder 173 173 , A.class "shadow" 174 174 , E.onInput Input 175 175 , value question.value 176 176 ] 177 - , UI.Kit.button 178 - UI.Kit.Filled 177 + , Kit.button 178 + Kit.Filled 179 179 Syncing.Bypass 180 180 (text "Continue") 181 181 ]
src/Applications/UI/Tracks/ContextMenu.elm src/Core/UI/Tracks/ContextMenu.elm
src/Applications/UI/Tracks/Covers.elm src/Core/UI/Tracks/Covers.elm
+1 -1
src/Applications/UI/Tracks/Scene.elm src/Core/Themes/Sunrise/Tracks/Scene.elm
··· 1 - module UI.Tracks.Scene exposing (..) 1 + module Themes.Sunrise.Tracks.Scene exposing (..) 2 2 3 3 import Chunky exposing (..) 4 4 import Conditional exposing (..)
+5 -5
src/Applications/UI/Tracks/Scene/Covers.elm src/Core/Themes/Sunrise/Tracks/Scene/Covers.elm
··· 1 - module UI.Tracks.Scene.Covers exposing (containerId, scrollToNowPlaying, scrollToTop, view) 1 + module Themes.Sunrise.Tracks.Scene.Covers exposing (containerId, scrollToNowPlaying, scrollToTop, view) 2 2 3 3 import Browser.Dom as Dom 4 4 import Chunky exposing (..) ··· 16 16 import Material.Icons.Types exposing (Coloring(..)) 17 17 import Maybe.Extra as Maybe 18 18 import Task 19 + import Themes.Sunrise.Tracks.Scene as Scene 20 + import Themes.Sunrise.Tracks.Scene.List 19 21 import Tracks exposing (..) 20 - import UI.Tracks.Scene as Scene 21 - import UI.Tracks.Scene.List 22 22 import UI.Tracks.Types exposing (Msg(..)) 23 23 import UI.Types as UI exposing (Msg(..)) 24 24 ··· 226 226 singleCoverView cover deps = 227 227 let 228 228 derivedColors = 229 - UI.Tracks.Scene.List.deriveColors 229 + Themes.Sunrise.Tracks.Scene.List.deriveColors 230 230 { bgColor = deps.bgColor 231 231 , darkMode = deps.darkMode 232 232 } ··· 298 298 -- 299 299 , cover.tracks 300 300 |> List.indexedMap 301 - (UI.Tracks.Scene.List.defaultItemView 301 + (Themes.Sunrise.Tracks.Scene.List.defaultItemView 302 302 { derivedColors = derivedColors 303 303 , favouritesOnly = deps.favouritesOnly 304 304 , nowPlaying = deps.nowPlaying
+8 -8
src/Applications/UI/Tracks/Scene/List.elm src/Core/Themes/Sunrise/Tracks/Scene/List.elm
··· 1 - module UI.Tracks.Scene.List exposing (Dependencies, DerivedColors, containerId, defaultItemView, deriveColors, scrollToNowPlaying, scrollToTop, view) 1 + module Themes.Sunrise.Tracks.Scene.List exposing (Dependencies, DerivedColors, containerId, defaultItemView, deriveColors, scrollToNowPlaying, scrollToTop, view) 2 2 3 3 import Browser.Dom as Dom 4 4 import Chunky exposing (..) ··· 17 17 import Material.Icons.Types exposing (Coloring(..)) 18 18 import Maybe.Extra as Maybe 19 19 import Task 20 + import Themes.Sunrise.Kit as Kit 21 + import Themes.Sunrise.Tracks.Scene as Scene 20 22 import Tracks exposing (..) 21 23 import UI.DnD as DnD 22 - import UI.Kit 23 24 import UI.Queue.Types as Queue 24 - import UI.Tracks.Scene as Scene 25 25 import UI.Tracks.Types exposing (Msg(..)) 26 26 import UI.Types as UI exposing (Msg(..)) 27 27 ··· 327 327 deriveColors { bgColor, darkMode } = 328 328 let 329 329 color = 330 - Maybe.withDefault UI.Kit.colors.text bgColor 330 + Maybe.withDefault Kit.colors.text bgColor 331 331 in 332 332 if darkMode then 333 333 { background = Color.toCssString color ··· 828 828 829 829 favColors = 830 830 { gray = Color.toCssString (Color.rgb255 220 220 220) 831 - , red = Color.toCssString UI.Kit.colorKit.base08 831 + , red = Color.toCssString Kit.colorKit.base08 832 832 } 833 833 834 834 835 835 rowFontColors = 836 - { gray = Color.toCssString UI.Kit.colorKit.base04 836 + { gray = Color.toCssString Kit.colorKit.base04 837 837 , white = Color.toCssString (Color.rgb 1 1 1) 838 838 } 839 839 ··· 843 843 let 844 844 color = 845 845 if darkMode then 846 - UI.Kit.colors.gray_300 846 + Kit.colors.gray_300 847 847 848 848 else 849 - UI.Kit.colorKit.base03 849 + Kit.colorKit.base03 850 850 in 851 851 style "box-shadow" ("0 1px 0 0 " ++ Color.toCssString color ++ " inset")
+4 -17
src/Applications/UI/Tracks/State.elm src/Core/UI/Tracks/State.elm
··· 31 31 import UI.Page 32 32 import UI.Ports as Ports 33 33 import UI.Queue.State as Queue 34 + import UI.Theme 34 35 import UI.Tracks.ContextMenu as Tracks 35 36 import UI.Tracks.Covers as Covers 36 - import UI.Tracks.Scene.Covers 37 - import UI.Tracks.Scene.List 38 37 import UI.Tracks.Types as Tracks exposing (..) 39 38 import UI.Types exposing (Manager, Model, Msg(..)) 40 39 import UI.User.State.Export as User ··· 775 774 if List.member Keyboard.Shift model.pressedKeys then 776 775 return 777 776 { model | selectedCover = Nothing } 778 - (UI.Tracks.Scene.Covers.scrollToNowPlaying 779 - model.viewport.width 780 - model.covers.harvested 781 - ( identifiers, track ) 782 - ) 777 + (UI.Theme.scrollToNowPlaying Covers ( identifiers, track ) model) 783 778 784 779 else 785 780 model.covers.harvested ··· 790 785 List -> 791 786 return 792 787 { model | selectedCover = Nothing } 793 - (UI.Tracks.Scene.List.scrollToNowPlaying 794 - model.tracks.harvested 795 - ( identifiers, track ) 796 - ) 788 + (UI.Theme.scrollToNowPlaying List ( identifiers, track ) model) 797 789 ) 798 790 |> Maybe.map 799 791 (UI.Page.Index ··· 1071 1063 -- Command 1072 1064 ----------------------------------------- 1073 1065 , if scrollContextChanged then 1074 - case model.scene of 1075 - Covers -> 1076 - UI.Tracks.Scene.Covers.scrollToTop 1077 - 1078 - List -> 1079 - UI.Tracks.Scene.List.scrollToTop 1066 + UI.Theme.scrollTracksToTop model.scene 1080 1067 1081 1068 else 1082 1069 Cmd.none
src/Applications/UI/Tracks/Types.elm src/Core/UI/Tracks/Types.elm
+22 -21
src/Applications/UI/Tracks/View.elm src/Core/Themes/Sunrise/Tracks/View.elm
··· 1 - module UI.Tracks.View exposing (view) 1 + module Themes.Sunrise.Tracks.View exposing (view) 2 2 3 3 import Chunky exposing (..) 4 4 import Color exposing (Color) ··· 14 14 import Material.Icons.Types exposing (Coloring(..)) 15 15 import Maybe.Extra as Maybe 16 16 import Playlists exposing (Playlist) 17 + import Themes.Sunrise.Kit as Kit 18 + import Themes.Sunrise.Navigation as Navigation 19 + import Themes.Sunrise.Tracks.Scene.Covers 20 + import Themes.Sunrise.Tracks.Scene.List 17 21 import Tracks exposing (..) 18 22 import UI.Audio.Types exposing (nowPlayingIdentifiedTrack) 19 - import UI.Kit 20 23 import UI.Navigation exposing (..) 21 24 import UI.Page as Page 22 25 import UI.Playlists.Page ··· 24 27 import UI.Sources.Page as Sources 25 28 import UI.Syncing.Common as Syncing 26 29 import UI.Syncing.Types as Syncing 27 - import UI.Tracks.Scene.Covers 28 - import UI.Tracks.Scene.List 29 30 import UI.Tracks.Types exposing (..) 30 31 import UI.Types as UI exposing (..) 31 32 import User.Layer as User ··· 88 89 else 89 90 case model.scene of 90 91 Covers -> 91 - UI.Tracks.Scene.Covers.view 92 + Themes.Sunrise.Tracks.Scene.Covers.view 92 93 { bgColor = model.extractedBackdropColor 93 94 , cachedCovers = model.cachedCovers 94 95 , covers = model.covers.harvested ··· 116 117 else 117 118 Just model.dnd 118 119 ) 119 - |> UI.Tracks.Scene.List.view 120 + |> Themes.Sunrise.Tracks.Scene.List.view 120 121 { bgColor = model.extractedBackdropColor 121 122 , darkMode = model.darkMode 122 123 , height = model.viewport.height ··· 267 268 ] 268 269 [ "cursor-pointer" ] 269 270 [ if favouritesOnly then 270 - Icons.favorite 16 (Color UI.Kit.colorKit.base08) 271 + Icons.favorite 16 (Color Kit.colorKit.base08) 271 272 272 273 else 273 274 Icons.favorite_border 16 Inherit ··· 325 326 326 327 -- 327 328 , bgColor 328 - |> Maybe.withDefault UI.Kit.colorKit.base01 329 + |> Maybe.withDefault Kit.colorKit.base01 329 330 |> Color.toCssString 330 331 |> style "background-color" 331 332 ] ··· 358 359 , ----------------------------------------- 359 360 -- Part 2 360 361 ----------------------------------------- 361 - UI.Navigation.localWithTabindex 362 + Navigation.localWithTabindex 362 363 tabindex_ 363 364 [ ( Icon Icons.waves 364 365 , Label "Playlists" Hidden ··· 453 454 , "flex" 454 455 , "flex-grow" 455 456 ] 456 - [ UI.Kit.centeredContent 457 + [ Kit.centeredContent 457 458 [ if List.length processingContext > 0 then 458 459 message "Processing Tracks" 459 460 ··· 506 507 -- 507 508 , chunk 508 509 [ "flex", "mt-5", "space-x-3" ] 509 - [ UI.Kit.button 510 - UI.Kit.Normal 510 + [ Kit.button 511 + Kit.Normal 511 512 InsertDemo 512 513 (Html.text "Insert Demo") 513 - , UI.Kit.buttonWithColor 514 - UI.Kit.Accent 515 - UI.Kit.Filled 514 + , Kit.buttonWithColor 515 + Kit.Accent 516 + Kit.Filled 516 517 (ChangeUrlUsingPage <| Page.Sources Sources.New) 517 518 (Html.text "Add Music") 518 519 , case userLayerMethod of 519 520 Just method -> 520 - UI.Kit.buttonWithColor 521 - UI.Kit.Gray 522 - UI.Kit.Filled 521 + Kit.buttonWithColor 522 + Kit.Gray 523 + Kit.Filled 523 524 (SyncingMsg Syncing.StopSync) 524 525 (text "Stop syncing") 525 526 526 527 Nothing -> 527 - UI.Kit.buttonWithOptions 528 + Kit.buttonWithOptions 528 529 Html.button 529 530 [ Mouse.onClick (SyncingMsg << Syncing.ShowSyncDataMenu) ] 530 - UI.Kit.Gray 531 - UI.Kit.Filled 531 + Kit.Gray 532 + Kit.Filled 532 533 Nothing 533 534 (Html.text "Sync data") 534 535 ]
+4
src/Applications/UI/Types.elm src/Core/UI/Types.elm
··· 24 24 import Queue 25 25 import Random 26 26 import Sources exposing (Source) 27 + import Theme 27 28 import Time 28 29 import Tracks exposing (..) 29 30 import UI.Audio.Types exposing (DurationChangeEvent, ErrorAudioEvent, GenericAudioEvent, NowPlaying, PlaybackStateEvent, TimeUpdatedEvent) ··· 76 77 , pressedKeys : List Keyboard.Key 77 78 , processAutomatically : Bool 78 79 , serviceWorkerStatus : ServiceWorkerStatus 80 + , theme : Maybe Theme.Id 79 81 , uuidSeed : Random.Seed 80 82 , url : Url 81 83 , version : String ··· 228 230 ----------------------------------------- 229 231 -- Interface 230 232 ----------------------------------------- 233 + | AssistWithChangingTheme 231 234 | Blur 235 + | ChangeTheme Theme.Id 232 236 | ContextMenuConfirmation String Msg 233 237 | CopyToClipboard String 234 238 | DismissNotification { id : Int }
+1
src/Applications/UI/User/State/Export.elm src/Core/UI/User/State/Export.elm
··· 65 65 , shuffle = model.shuffle 66 66 , sortBy = model.sortBy 67 67 , sortDirection = model.sortDirection 68 + , theme = model.theme 68 69 } 69 70 |> encodeEnclosedData 70 71 |> Alien.broadcast Alien.SaveEnclosedUserData
+1
src/Applications/UI/User/State/Import.elm src/Core/UI/User/State/Import.elm
··· 220 220 , searchTerm = data.searchTerm 221 221 , sortBy = data.sortBy 222 222 , sortDirection = data.sortDirection 223 + , theme = data.theme 223 224 } 224 225 -- 225 226 , Equalizer.adjustAllKnobs newEqualizerSettings
+32 -50
src/Applications/UI/View.elm src/Core/Themes/Sunrise/Theme.elm
··· 1 - module UI.View exposing (view) 1 + module Themes.Sunrise.Theme exposing (theme) 2 2 3 3 import Alfred exposing (Alfred) 4 - import Browser 5 4 import Chunky exposing (..) 6 5 import Common exposing (Switch(..)) 7 6 import Conditional exposing (..) ··· 11 10 import Html.Events exposing (on) 12 11 import Html.Lazy as Lazy 13 12 import Json.Decode 13 + import Material.Icons as Icons 14 14 import Maybe.Extra as Maybe 15 - import UI.Alfred.View as Alfred 15 + import Theme exposing (Theme) 16 + import Themes.Sunrise.Alfred.View as Alfred 17 + import Themes.Sunrise.Console 18 + import Themes.Sunrise.ContextMenu as ContextMenu 19 + import Themes.Sunrise.Navigation as Navigation 20 + import Themes.Sunrise.Notifications as Notifications 21 + import Themes.Sunrise.Playlists.View as Playlists 22 + import Themes.Sunrise.Queue.View as Queue 23 + import Themes.Sunrise.Settings as Settings 24 + import Themes.Sunrise.Sources.View as Sources 25 + import Themes.Sunrise.Syncing.View as Syncing 26 + import Themes.Sunrise.Tracks.View as Tracks 16 27 import UI.Backdrop as Backdrop 17 - import UI.Console 18 - import UI.ContextMenu 19 - import UI.Navigation as Navigation 20 - import UI.Notifications 21 28 import UI.Page as Page 22 - import UI.Playlists.View as Playlists 23 - import UI.Queue.View as Queue 24 - import UI.Settings as Settings 25 29 import UI.Settings.Page 26 30 import UI.Sources.Page 27 - import UI.Sources.View as Sources 28 31 import UI.Svg.Elements 29 32 import UI.Syncing.Common as Syncing 30 - import UI.Syncing.View as Syncing 31 - import UI.Tracks.View as Tracks 32 33 import UI.Types exposing (..) 33 34 import User.Layer 34 35 35 36 37 + theme : Theme Msg Model 38 + theme = 39 + { id = "sunrise" 40 + , title = "Sunrise" 41 + , icon = Icons.wb_sunny 42 + , view = view 43 + } 36 44 37 - -- 🗺 38 45 39 46 40 - view : Model -> Browser.Document Msg 41 - view model = 42 - { title = "Diffuse" 43 - , body = [ body model ] 44 - } 47 + -- ㊙️ 45 48 46 49 47 - body : Model -> Html Msg 48 - body model = 50 + view : Model -> Html Msg 51 + view model = 49 52 section 50 53 (if Maybe.isJust model.contextMenu || Maybe.isJust model.alfred then 51 54 [ on "tap" (Json.Decode.succeed HideOverlay) ] ··· 82 85 ----------------------------------------- 83 86 -- Context Menu 84 87 ----------------------------------------- 85 - , Lazy.lazy2 UI.ContextMenu.view model.viewport.width model.contextMenu 88 + , Lazy.lazy2 ContextMenu.view model.viewport.width model.contextMenu 86 89 87 90 ----------------------------------------- 88 91 -- Notifications 89 92 ----------------------------------------- 90 - , Lazy.lazy2 UI.Notifications.view model.extractedBackdropColor model.notifications 93 + , Lazy.lazy2 Notifications.view model.extractedBackdropColor model.notifications 91 94 92 95 ----------------------------------------- 93 96 -- Overlay ··· 97 100 ----------------------------------------- 98 101 -- Content 99 102 ----------------------------------------- 100 - , let 101 - opts = 102 - { justifyCenter = False 103 - , scrolling = not model.isDragging 104 - } 105 - in 106 - if model.isLoading then 107 - content 108 - { opts | justifyCenter = True } 109 - [ loadingAnimation 110 - , chunk 111 - [ "italic" 112 - , "mt-5" 113 - , "text-white" 114 - , "text-opacity-30" 115 - ] 116 - [ Html.text "Transmitting particles" ] 117 - ] 118 - 119 - else 120 - content opts (defaultScreen model) 103 + , content 104 + { justifyCenter = False 105 + , scrolling = not model.isDragging 106 + } 107 + (defaultScreen model) 121 108 ] 122 109 123 110 ··· 189 176 ----------------------------------------- 190 177 -- Controls 191 178 ----------------------------------------- 192 - , UI.Console.view 179 + , Themes.Sunrise.Console.view 193 180 model.nowPlaying 194 181 model.repeat 195 182 model.shuffle ··· 251 238 _ -> 252 239 Json.Decode.fail "NOT_INPUT" 253 240 ) 254 - 255 - 256 - loadingAnimation : Html msg 257 - loadingAnimation = 258 - Html.map never UI.Svg.Elements.loading 259 241 260 242 261 243 overlay : Maybe (Alfred Msg) -> Maybe (ContextMenu Msg) -> Html Msg
+30
src/Core/UI/Navigation.elm
··· 1 + module UI.Navigation exposing (Action(..), Icon(..), Label(..), LabelType(..)) 2 + 3 + import Html.Events.Extra.Mouse as Mouse 4 + import Material.Icons.Types exposing (Coloring) 5 + import Svg exposing (Svg) 6 + import UI.Page exposing (Page) 7 + 8 + 9 + 10 + -- 🌳 11 + 12 + 13 + type Action msg 14 + = NavigateToPage Page 15 + | OpenLinkInNewPage String 16 + | PerformMsg msg 17 + | PerformMsgWithMouseEvent (Mouse.Event -> msg) 18 + 19 + 20 + type Icon msg 21 + = Icon (Int -> Coloring -> Svg msg) 22 + 23 + 24 + type Label 25 + = Label String LabelType 26 + 27 + 28 + type LabelType 29 + = Hidden 30 + | Shown
+66
src/Core/UI/Notifications.elm
··· 1 + module UI.Notifications exposing (Model, dismiss, show, showWithModel) 2 + 3 + import Notifications exposing (..) 4 + import Process 5 + import Task 6 + import UI.Types exposing (Msg(..)) 7 + 8 + 9 + 10 + -- 🌳 11 + 12 + 13 + type alias Model = 14 + List (Notification Msg) 15 + 16 + 17 + 18 + -- 📣 19 + 20 + 21 + dismiss : Model -> { id : Int } -> ( Model, Cmd Msg ) 22 + dismiss collection { id } = 23 + ( List.map 24 + (\notification -> 25 + if Notifications.id notification == id then 26 + Notifications.dismiss notification 27 + 28 + else 29 + notification 30 + ) 31 + collection 32 + , Task.perform 33 + (\_ -> RemoveNotification { id = id }) 34 + (Process.sleep 500) 35 + ) 36 + 37 + 38 + show : Notification Msg -> Model -> ( Model, Cmd Msg ) 39 + show notification collection = 40 + let 41 + existingNotificationIds = 42 + List.map Notifications.id collection 43 + in 44 + if List.member (Notifications.id notification) existingNotificationIds then 45 + -- Don't show duplicate notifications 46 + ( collection 47 + , Cmd.none 48 + ) 49 + 50 + else 51 + ( notification :: collection 52 + -- Hide notification after a certain amount of time, 53 + -- unless it's a sticky notification. 54 + , if (Notifications.options notification).sticky then 55 + Cmd.none 56 + 57 + else 58 + Task.perform 59 + (\_ -> DismissNotification { id = Notifications.id notification }) 60 + (Process.sleep 7500) 61 + ) 62 + 63 + 64 + showWithModel : Model -> Notification Msg -> ( Model, Cmd Msg ) 65 + showWithModel model notification = 66 + show notification model
+31
src/Core/UI/Sources/Form.elm
··· 1 + module UI.Sources.Form exposing (..) 2 + 3 + import Sources exposing (..) 4 + import Sources.Services as Services 5 + import UI.Sources.Types exposing (..) 6 + 7 + 8 + 9 + -- 🌳 10 + 11 + 12 + initialModel : Form 13 + initialModel = 14 + { step = Where 15 + , context = defaultContext 16 + } 17 + 18 + 19 + defaultContext : Source 20 + defaultContext = 21 + { id = "CHANGE_ME_PLEASE" 22 + , data = Services.initialData defaultService 23 + , directoryPlaylists = True 24 + , enabled = True 25 + , service = defaultService 26 + } 27 + 28 + 29 + defaultService : Service 30 + defaultService = 31 + Dropbox
+114
src/Core/UI/Theme.elm
··· 1 + module UI.Theme exposing (..) 2 + 3 + import Chunky exposing (..) 4 + import Dict exposing (Dict) 5 + import Html exposing (Html) 6 + import Material.Icons.Types exposing (Icon) 7 + import Theme exposing (Theme) 8 + import Themes.Sunrise.Theme as Sunrise 9 + import Themes.Sunrise.Tracks.Scene.Covers 10 + import Themes.Sunrise.Tracks.Scene.List 11 + import Tracks exposing (IdentifiedTrack, Scene) 12 + import UI.Svg.Elements 13 + import UI.Types exposing (Model, Msg(..)) 14 + 15 + 16 + 17 + -- 🔮 18 + 19 + 20 + list : List (Theme Msg Model) 21 + list = 22 + [ Sunrise.theme 23 + ] 24 + 25 + 26 + default : Theme Msg Model 27 + default = 28 + Sunrise.theme 29 + 30 + 31 + 32 + -- 🚧 33 + 34 + 35 + dict : Dict String (Theme Msg Model) 36 + dict = 37 + list 38 + |> List.map 39 + (\theme -> 40 + ( theme.id, theme ) 41 + ) 42 + |> Dict.fromList 43 + 44 + 45 + view : Model -> Html Msg 46 + view model = 47 + if model.isLoading then 48 + loadingAnimation 49 + 50 + else 51 + case model.theme of 52 + Just { id } -> 53 + case Dict.get id dict of 54 + Just theme -> 55 + theme.view model 56 + 57 + Nothing -> 58 + default.view model 59 + 60 + Nothing -> 61 + default.view model 62 + 63 + 64 + loadingAnimation = 65 + chunk 66 + [ "flex" 67 + , "flex-col" 68 + , "items-center" 69 + , "justify-center" 70 + , "screen-height" 71 + , "w-screen" 72 + ] 73 + [ loadingAnimationSvg 74 + , chunk 75 + [ "italic" 76 + , "mt-5" 77 + , "text-white" 78 + , "text-opacity-30" 79 + ] 80 + [ Html.text "Transmitting particles" ] 81 + ] 82 + 83 + 84 + loadingAnimationSvg = 85 + Html.map never UI.Svg.Elements.loading 86 + 87 + 88 + 89 + -- TODO 90 + 91 + 92 + scrollTracksToTop : Scene -> Cmd Msg 93 + scrollTracksToTop scene = 94 + case scene of 95 + Tracks.Covers -> 96 + Themes.Sunrise.Tracks.Scene.List.scrollToTop 97 + 98 + Tracks.List -> 99 + Themes.Sunrise.Tracks.Scene.Covers.scrollToTop 100 + 101 + 102 + scrollToNowPlaying : Scene -> IdentifiedTrack -> Model -> Cmd Msg 103 + scrollToNowPlaying scene ( identifiers, track ) model = 104 + case scene of 105 + Tracks.Covers -> 106 + Themes.Sunrise.Tracks.Scene.Covers.scrollToNowPlaying 107 + model.viewport.width 108 + model.covers.harvested 109 + ( identifiers, track ) 110 + 111 + Tracks.List -> 112 + Themes.Sunrise.Tracks.Scene.List.scrollToNowPlaying 113 + model.tracks.harvested 114 + ( identifiers, track )
+16
src/Core/UI/View.elm
··· 1 + module UI.View exposing (view) 2 + 3 + import Browser 4 + import UI.Theme 5 + import UI.Types exposing (Model, Msg) 6 + 7 + 8 + 9 + -- 🗺 10 + 11 + 12 + view : Model -> Browser.Document Msg 13 + view model = 14 + { title = "Diffuse" 15 + , body = [ UI.Theme.view model ] 16 + }
+28
src/Library/Theme.elm
··· 1 + module Theme exposing (..) 2 + 3 + import Html exposing (Html) 4 + import Json.Decode as Decode 5 + import Json.Encode as Encode 6 + import Material.Icons.Types exposing (Icon) 7 + 8 + 9 + type alias Id = 10 + { id : String } 11 + 12 + 13 + type alias Theme msg model = 14 + { id : String 15 + , title : String 16 + , icon : Icon msg 17 + , view : model -> Html msg 18 + } 19 + 20 + 21 + idDecoder : Decode.Decoder Id 22 + idDecoder = 23 + Decode.map (\s -> { id = s }) Decode.string 24 + 25 + 26 + encodeId : Id -> Encode.Value 27 + encodeId { id } = 28 + Encode.string id
+5 -1
src/Library/User/Layer.elm
··· 30 30 import Sources 31 31 import Sources.Encoding as Sources 32 32 import Task exposing (Task) 33 + import Theme 33 34 import Time 34 35 import Time.Ext as Time 35 36 import Tracks ··· 84 85 , shuffle : Bool 85 86 , sortBy : Tracks.SortBy 86 87 , sortDirection : Tracks.SortDirection 88 + , theme : Maybe Theme.Id 87 89 } 88 90 89 91 ··· 260 262 |> optional "shuffle" Json.bool False 261 263 |> optional "sortBy" Tracks.sortByDecoder Tracks.Album 262 264 |> optional "sortDirection" Tracks.sortDirectionDecoder Tracks.Asc 265 + |> optional "theme" (Json.maybe Theme.idDecoder) Nothing 263 266 264 267 265 268 encodeEnclosedData : EnclosedData -> Json.Value 266 - encodeEnclosedData { cachedTracks, equalizerSettings, grouping, onlyShowCachedTracks, onlyShowFavourites, repeat, scene, searchTerm, selectedPlaylist, shuffle, sortBy, sortDirection } = 269 + encodeEnclosedData { cachedTracks, equalizerSettings, grouping, onlyShowCachedTracks, onlyShowFavourites, repeat, scene, searchTerm, selectedPlaylist, shuffle, sortBy, sortDirection, theme } = 267 270 Json.Encode.object 268 271 [ ( "cachedTracks", Json.Encode.list Json.Encode.string cachedTracks ) 269 272 , ( "equalizerSettings", Equalizer.encodeSettings equalizerSettings ) ··· 277 280 , ( "shuffle", Json.Encode.bool shuffle ) 278 281 , ( "sortBy", Tracks.encodeSortBy sortBy ) 279 282 , ( "sortDirection", Tracks.encodeSortDirection sortDirection ) 283 + , ( "theme", Maybe.unwrap Json.Encode.null Theme.encodeId theme ) 280 284 ] 281 285 282 286
+5 -7
src/README.md
··· 1 - # Infrastructure 1 + # Elm code 2 2 3 3 Elm directories: 4 - 5 - - Applications/Brain 6 - - Applications/UI 7 - - Library 4 + - src/Core 5 + - src/Library 8 6 9 - `UI` is the Elm application that'll be executed on the main thread (ie. the UI thread) and `Brain` is the Elm application that'll live inside a web worker. `UI` will be the main application and `Brain` does the heavy lifting. The code shared between these two applications lives in `Library`. The library also contains the more "generic" code that's not necessarily tied to one or the other. 7 + `UI` is the Elm application that'll be executed on the main thread (ie. the UI thread) and `Brain` is the Elm application that'll live inside a web worker. `UI` will be the main application and `Brain` does the heavy lifting. The code shared between these two applications lives in `Library`. The library also contains the more "generic" code that's not necessarily tied to one or the other. Additionally you have `Themes` which is a layer on top of the UI code. 10 8 11 9 12 10 ··· 20 18 🗺 Views 21 19 22 20 🧠 Brain 23 - 🔱 Functions 21 + 🛠️ Functions 24 22 🖼 Styles 25 23 ㊙️ Secret 26 24 ```