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

Configure Feed

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

Add new flow for adding a source

+361 -127
+3 -3
src/App/Equalizer/View.elm
··· 30 30 entry : TopLevel.Model -> Html TopLevel.Msg 31 31 entry model = 32 32 div 33 - [ Html.Attributes.classList 34 - [ ( toString InsulationContent, True ) 35 - , ( toString InsulationForEqualizer, True ) 33 + [ cssClasses 34 + [ InsulationContent 35 + , InsulationFlexContent 36 36 ] 37 37 ] 38 38 [ ------------------------------------
+1 -1
src/App/Sources/Services/AmazonS3.elm
··· 25 25 26 26 defaults = 27 27 { directoryPath = "/" 28 - , name = "Amazon S3 source" 28 + , name = "Music from Amazon S3" 29 29 , region = "eu-west-1" 30 30 } 31 31
+1 -1
src/App/Sources/Services/Ipfs.elm
··· 22 22 23 23 defaults = 24 24 { gateway = "http://localhost:8080" 25 - , name = "IPFS source" 25 + , name = "Music from IPFS" 26 26 } 27 27 28 28
+55 -15
src/App/Sources/State.elm
··· 24 24 initialModel flags = 25 25 { collection = decodeSources flags 26 26 , isProcessing = Nothing 27 - , newSource = initialSource 27 + , form = NewForm 1 initialSource 28 28 , processingErrors = [] 29 29 , timestamp = Date.fromTime 0 30 30 } ··· 214 214 -- Forms 215 215 ------------------------------------ 216 216 -- 217 - -- Set 217 + -- Assign 218 218 -- 219 - SetNewSourceProperty source key value -> 219 + AssignFormProperty key value -> 220 220 let 221 - newSource = 222 - { source | data = Dict.insert key value source.data } 221 + updateSource = 222 + \source -> 223 + { source | data = Dict.insert key value source.data } 224 + 225 + updatedForm = 226 + case model.form of 227 + NewForm step source -> 228 + NewForm step (updateSource source) 229 + 230 + EditForm source -> 231 + EditForm (updateSource source) 223 232 in 224 - (!) { model | newSource = newSource } [] 233 + (!) { model | form = updatedForm } [] 225 234 226 235 -- 227 - -- Change 228 - -- 229 - SetNewSourceType typeString -> 236 + AssignFormService serviceKey -> 230 237 let 231 238 service = 232 - Services.keyToType typeString 239 + Services.keyToType serviceKey 233 240 234 241 newSource = 235 242 makeSource service (Services.initialData service) 243 + 244 + updatedForm = 245 + case model.form of 246 + NewForm step _ -> 247 + NewForm step newSource 248 + 249 + EditForm _ -> 250 + EditForm newSource 236 251 in 237 - (!) { model | newSource = newSource } [] 252 + (!) { model | form = updatedForm } [] 253 + 254 + -- 255 + AssignFormStep newStep -> 256 + let 257 + updatedForm = 258 + case model.form of 259 + NewForm _ source -> 260 + NewForm newStep source 261 + 262 + EditForm source -> 263 + EditForm source 264 + in 265 + (!) { model | form = updatedForm } [] 238 266 239 267 -- 240 268 -- Submit 241 269 -- 242 - SubmitNewSourceForm -> 270 + SubmitForm -> 243 271 let 244 272 ns = 245 - model.newSource 273 + case model.form of 274 + NewForm _ source -> 275 + source 276 + 277 + EditForm source -> 278 + source 246 279 247 280 newSource = 248 281 { ns | data = Dict.map (always String.trim) ns.data } ··· 253 286 ($) 254 287 { model 255 288 | collection = newCollection 256 - , newSource = initialSource 289 + , form = NewForm 1 initialSource 257 290 } 258 291 [] 259 292 [ do TopLevel.ProcessSources 260 - , Navigation.newUrl "/" 293 + , Navigation.newUrl 294 + (case List.length model.collection of 295 + 0 -> 296 + "/" 297 + 298 + _ -> 299 + "/sources" 300 + ) 261 301 , updateEnabledSourceIds newCollection 262 302 , storeSources newCollection 263 303 ]
+10 -4
src/App/Sources/Types.elm
··· 93 93 -- CRUD 94 94 | Destroy SourceId 95 95 -- Forms 96 - | SetNewSourceProperty Source String String 97 - | SetNewSourceType String 98 - | SubmitNewSourceForm 96 + | AssignFormProperty String String 97 + | AssignFormService String 98 + | AssignFormStep Int 99 + | SubmitForm 99 100 -- Other 100 101 | ToggleSource Source 101 102 ··· 106 107 107 108 type alias Model = 108 109 { collection : List Source 110 + , form : Form 109 111 , isProcessing : IsProcessing 110 - , newSource : Source 111 112 , processingErrors : List ( SourceId, String ) 112 113 , timestamp : Date 113 114 } ··· 115 116 116 117 117 118 -- Other Types 119 + 120 + 121 + type Form 122 + = NewForm Int Source 123 + | EditForm Source 118 124 119 125 120 126 type Page
+220 -86
src/App/Sources/View.elm
··· 6 6 import Html.Attributes exposing (..) 7 7 import Html.Events exposing (onClick, onInput, onSubmit) 8 8 import Html.Keyed 9 - import Html.Lazy exposing (lazy, lazy3) 9 + import Html.Lazy exposing (lazy, lazy2, lazy3) 10 10 import List.Extra as List 11 11 import Material.Icons.Alert as Icons 12 12 import Material.Icons.Action as Icons ··· 20 20 import Sources.Services as Services 21 21 import Sources.Types as Sources exposing (..) 22 22 import Types as TopLevel exposing (Model, Msg(..)) 23 - import Utils exposing (cssClass) 23 + import Utils exposing (..) 24 24 import Variables exposing (colorDerivatives) 25 25 26 26 ··· 28 28 29 29 import Form.Styles as FormStyles 30 30 import List.Styles exposing (Classes(..)) 31 - import Styles exposing (Classes(Button, ContentBox, InsulationContent, Intro)) 31 + import Styles exposing (Classes(..)) 32 32 33 33 34 34 -- 🍯 ··· 45 45 model.sources.processingErrors 46 46 47 47 New -> 48 - lazy pageNew model.sources.newSource 48 + lazy 49 + pageNew 50 + model.sources.form 49 51 50 52 51 53 ··· 192 194 -- {Page} New 193 195 194 196 195 - pageNew : Source -> Html TopLevel.Msg 196 - pageNew newSource = 197 + pageNew : Sources.Form -> Html TopLevel.Msg 198 + pageNew sForm = 197 199 div 198 - [ cssClass InsulationContent ] 199 - [ ------------------------------------ 200 - -- Navigation 201 - ------------------------------------ 202 - Navigation.inside 203 - [ ( span 204 - [] 205 - [ Icons.list colorDerivatives.text 16 206 - , label [] [ text "Go to index" ] 207 - ] 208 - , "/sources" 209 - ) 200 + [ cssClasses 201 + [ InsulationContent 202 + , InsulationFlexContent 210 203 ] 211 - 212 - ------------------------------------ 213 - -- Form 214 - ------------------------------------ 215 - , Html.map SourcesMsg (pageNewForm newSource) 216 204 ] 205 + (case sForm of 206 + NewForm step source -> 207 + [ ------------------------------------ 208 + -- Navigation 209 + ------------------------------------ 210 + Navigation.insideCustom 211 + (case step of 212 + 1 -> 213 + [ ( span 214 + [] 215 + [ Icons.list colorDerivatives.text 16 216 + , label [] [ text "" ] 217 + ] 218 + , RoutingMsg (GoToUrl "/sources") 219 + ) 220 + ] 217 221 222 + _ -> 223 + [ ( span 224 + [] 225 + [ Icons.arrow_back colorDerivatives.text 16 226 + , label [] [ text "Take a step back" ] 227 + ] 228 + , SourcesMsg (AssignFormStep (step - 1)) 229 + ) 230 + ] 231 + ) 218 232 219 - pageNewForm : Source -> Html Sources.Msg 220 - pageNewForm newSource = 233 + ------------------------------------ 234 + -- Form 235 + ------------------------------------ 236 + , Html.map 237 + SourcesMsg 238 + (pageNewForm step source) 239 + ] 240 + 241 + _ -> 242 + [ text "Cannot use this model.form on this page" ] 243 + ) 244 + 245 + 246 + pageNewForm : Int -> Source -> Html Sources.Msg 247 + pageNewForm step source = 221 248 Html.form 222 - [ cssClass ContentBox 223 - , onSubmit Sources.SubmitNewSourceForm 224 - ] 225 - [ -- Title 226 - -- 227 - h1 228 - [] 229 - [ text "New source" ] 249 + [ cssClasses 250 + [ InsulationContent 251 + , InsulationFlexContent 252 + , InsulationCentered 253 + ] 254 + , style 255 + [ ( "position", "relative" ) 256 + , ( "text-align", "center" ) 257 + ] 258 + , onSubmit 259 + (case step of 260 + 1 -> 261 + Sources.AssignFormStep 2 230 262 231 - -- Intro 232 - -- 233 - , p 234 - [ cssClass Styles.Intro ] 235 - [ text "Choose a type of source, fill in its credentials and add it." 236 - , br 237 - [] 238 - [] 239 - , strong 240 - [] 241 - [ text """ 242 - Make sure CORS is enabled for IPFS and Amazon S3 repositories. 243 - """ 263 + 2 -> 264 + Sources.AssignFormStep 3 265 + 266 + 3 -> 267 + Sources.SubmitForm 268 + 269 + _ -> 270 + Sources.AssignFormStep 1 271 + ) 272 + ] 273 + [ div 274 + [ cssClasses 275 + [ InsulationFlexContent ] 276 + , style 277 + [ ( "position", "relative" ) 278 + , ( "width", "100%" ) 279 + , ( "z-index", "9" ) 244 280 ] 245 - , br 246 - [] 247 - [] 248 - , text "You can find the instructions over " 249 - , a 250 - [ href "https://gist.github.com/icidasset/c1883d594574a958ae4b4a5a91db1070#cors" 251 - , target "blank" 281 + ] 282 + [ div 283 + [ cssClasses 284 + [ InsulationContent 285 + , InsulationCentered 286 + , ContentBox 287 + ] 288 + , style 289 + [ ( "padding-top", "2.25rem" ) 290 + ] 252 291 ] 253 - [ text "here" ] 254 - , text "." 255 - , br 256 - [] 257 - [] 258 - , br 259 - [] 260 - [] 261 - , Icons.warning colorDerivatives.text 16 262 - , text "In order to use IPFS you currently must use " 263 - , a [ href "https://github.com/icidasset/go-ipfs" ] [ text "my fork" ] 264 - , text ", I'm still waiting for " 265 - , a [ href "https://github.com/ipfs/go-ipfs/pull/4073" ] [ text "my pull-request" ] 266 - , text " to be merged." 292 + [ case step of 293 + 1 -> 294 + pageNewStep1 source step 295 + 296 + 2 -> 297 + pageNewStep2 source step 298 + 299 + 3 -> 300 + pageNewStep3 source step 301 + 302 + _ -> 303 + text "" 304 + ] 267 305 ] 306 + , div 307 + [ cssClass LogoBackdrop ] 308 + [] 309 + ] 268 310 269 - -- Select the type of the source 270 - -- 271 - , label 311 + 312 + pageNewStep1 : Source -> Int -> Html Sources.Msg 313 + pageNewStep1 source step = 314 + div 315 + [] 316 + [ h2 272 317 [] 273 - [ text "Source type/service" ] 318 + [ text "Where is your music stored?" ] 274 319 , div 275 - [ cssClass FormStyles.SelectBox ] 320 + [ cssClass FormStyles.SelectBox 321 + , style 322 + [ ( "max-width", "350px" ) 323 + , ( "width", "100%" ) 324 + ] 325 + ] 276 326 [ select 277 - [ onInput SetNewSourceType 278 - ] 327 + [ onInput AssignFormService ] 279 328 (List.map 280 329 (\( typStr, labe ) -> 281 330 option 282 - [ selected <| (toString newSource.service) == typStr 331 + [ selected <| (toString source.service) == typStr 283 332 , value typStr 284 333 ] 285 334 [ text labe ] ··· 288 337 ) 289 338 , Icons.expand_more (Color.greyscale 0.325) 20 290 339 ] 340 + , button 341 + [ cssClass Button, type_ "submit" ] 342 + [ Icons.arrow_forward Color.black 16 ] 343 + ] 291 344 292 - -- Source properties 293 - -- 345 + 346 + pageNewStep2 : Source -> Int -> Html Sources.Msg 347 + pageNewStep2 source step = 348 + div 349 + [] 350 + [ h3 351 + [] 352 + [ text "Where exactly?" ] 294 353 , div 354 + [ cssClasses 355 + [ Columns ] 356 + , style 357 + [ ( "text-align", "left" ) ] 358 + ] 359 + (renderSourceProperties source) 360 + , br 361 + [] 295 362 [] 296 - (renderSourceProperties newSource) 363 + , br 364 + [] 365 + [] 366 + , button 367 + [ cssClass Button, type_ "submit" ] 368 + [ Icons.arrow_forward Color.black 16 ] 369 + ] 370 + 297 371 298 - -- Submit button 299 - -- 372 + pageNewStep3 : Source -> Int -> Html Sources.Msg 373 + pageNewStep3 source step = 374 + div 375 + [] 376 + [ h2 377 + [] 378 + [ text "One last thing" ] 300 379 , div 301 - [] 302 - [ button 303 - [ type_ "submit" ] 304 - [ text "Create source" ] 380 + [ style 381 + [ ( "margin", "0 auto" ) 382 + , ( "max-width", "420px" ) 383 + , ( "width", "100%" ) 384 + ] 305 385 ] 386 + [ label 387 + [] 388 + [ text "What are we going to call this source?" ] 389 + , br 390 + [] 391 + [] 392 + , div 393 + [ cssClass FormStyles.InputBox ] 394 + [ input 395 + [ name "name" 396 + , onInput (Sources.AssignFormProperty "name") 397 + , placeholder 398 + (source.service 399 + |> Services.properties 400 + |> List.reverse 401 + |> List.head 402 + |> Maybe.map (\( _, l, _, _ ) -> l) 403 + |> Maybe.withDefault "Label" 404 + ) 405 + , required True 406 + , type_ "text" 407 + , value 408 + (source.data 409 + |> Dict.get "name" 410 + |> Maybe.withDefault "" 411 + ) 412 + ] 413 + [] 414 + ] 415 + ] 416 + , div 417 + [ cssClass Styles.Intro ] 418 + [ Icons.warning colorDerivatives.text 16 419 + , strong 420 + [] 421 + [ text "Make sure CORS is enabled" ] 422 + , br 423 + [] 424 + [] 425 + , text "You can find the instructions over " 426 + , a 427 + [ href "https://gist.github.com/icidasset/c1883d594574a958ae4b4a5a91db1070#cors" 428 + , target "blank" 429 + ] 430 + [ text "here" ] 431 + ] 432 + , button 433 + [ cssClass Button, type_ "submit" ] 434 + [ text "Add source" ] 306 435 ] 307 436 308 437 ··· 321 450 [ cssClass FormStyles.InputBox ] 322 451 [ input 323 452 [ name propKey 324 - , onInput (Sources.SetNewSourceProperty source propKey) 453 + , onInput (Sources.AssignFormProperty propKey) 325 454 , placeholder propPlaceholder 326 455 , required True 327 456 , type_ ··· 343 472 344 473 renderSourceProperties : Source -> List (Html Sources.Msg) 345 474 renderSourceProperties source = 346 - List.map (propertyRenderer source) (Services.properties source.service) 475 + source.service 476 + |> Services.properties 477 + |> List.reverse 478 + |> List.drop 1 479 + |> List.reverse 480 + |> List.map (propertyRenderer source)
+1 -1
src/App/Tracks/View.elm
··· 204 204 { stopPropagation = False 205 205 , preventDefault = True 206 206 } 207 - ("/sources" 207 + ("/sources/new" 208 208 |> GoToUrl 209 209 |> RoutingMsg 210 210 |> Decode.succeed
-5
src/Css/Equalizer/Styles.elm
··· 10 10 type Classes 11 11 = Equalizer 12 12 | EqualizerContainer 13 - | InsulationForEqualizer 14 13 | KnobColumn 15 14 | KnobLabel 16 15 | KnobLayerA ··· 60 59 , top zero 61 60 ] 62 61 ] 63 - ] 64 - , class InsulationForEqualizer 65 - [ displayFlex 66 - , flexDirection column 67 62 ] 68 63 69 64 --
+2 -3
src/Css/Form/Mixins.elm
··· 9 9 boxStyles : Style 10 10 boxStyles = 11 11 batch 12 - [ marginBottom (gr 6) 12 + [ margin3 zero auto (gr 6) 13 13 ] 14 14 15 15 ··· 30 30 31 31 -- 32 32 , focus 33 - [ borderColor (cssColor colorDerivatives.focusBorder) 34 - , outline none 33 + [ outline none 35 34 ] 36 35 ] 37 36
+8 -2
src/Css/Form/Styles.elm
··· 3 3 import Css exposing (..) 4 4 import Css.Elements exposing (form, label, input, select, svg) 5 5 import Form.Mixins exposing (..) 6 - import Traits exposing (cssColor, gr) 6 + import Traits exposing (basem, cssColor, cssColorOpac, gr) 7 7 import Variables exposing (colorDerivatives) 8 8 9 9 ··· 58 58 -- 59 59 , descendants 60 60 [ svg 61 - [ position absolute 61 + [ fontSize (basem 20) 62 + , position absolute 62 63 , property "pointer-events" "none" 63 64 , right (gr 2) 64 65 , top (pct 50) ··· 79 80 , borderBottom3 (px 1) solid (cssColor colorDerivatives.inputBorder) 80 81 , borderRadius zero 81 82 , padding zero 83 + 84 + -- 85 + , pseudoElement "placeholder" 86 + [ color (cssColorOpac 0.375 colorDerivatives.text) 87 + ] 82 88 ] 83 89 , class InputBox 84 90 [ boxStyles
+55 -6
src/Css/Styles.elm
··· 47 47 | BackgroundImage 48 48 | Basic 49 49 | Button 50 + | Columns 50 51 | ContentBox 51 52 | Important 52 53 | Insulation 54 + | InsulationCentered 53 55 | InsulationContent 56 + | InsulationFlexContent 54 57 | InTheMiddle 55 58 | Intro 56 59 | LogoBackdrop ··· 144 147 , position relative 145 148 , width (pct 100) 146 149 ] 150 + , class InsulationCentered 151 + [ alignItems center 152 + , justifyContent center 153 + ] 147 154 , class InsulationContent 148 155 [ flex (int 1) 149 156 , overflowX hidden 150 157 , overflowY auto 158 + ] 159 + , class InsulationFlexContent 160 + [ displayFlex 161 + , flexDirection column 151 162 ] 152 163 153 164 ------------------------------------------------------ ··· 189 200 , padding3 (basem 4) (basem 10) (basem 3) 190 201 , textTransform uppercase 191 202 ] 203 + , h2 204 + [ fontSize (Css.rem 1.4) 205 + , headerFont 206 + , margin3 (gr -2) zero (gr 4) 207 + , textAlign center 208 + ] 209 + , h3 210 + [ fontSize (Css.rem 1.4) 211 + , headerFont 212 + , margin3 (gr -2) zero (gr 6) 213 + , textAlign left 214 + ] 192 215 , a 193 216 [ color inherit 194 217 , textDecoration none ··· 249 272 , border3 250 273 (px 2) 251 274 solid 252 - (colors.base0B 253 - |> Color.Manipulate.fadeOut 0.575 275 + (colors.base08 254 276 |> cssColor 255 277 ) 256 278 , borderRadius (px 3) 257 - , color (cssColor colors.base0B) 279 + , color (cssColor colors.base08) 258 280 , displayFlex 259 281 , fontWeight (int 700) 260 282 , lineHeight (int 1) ··· 277 299 , backgroundSize cover 278 300 , bottom zero 279 301 , left zero 280 - , opacity (num 0.075) 302 + , opacity (num 0.05) 281 303 , position absolute 282 304 , right zero 283 305 , top zero ··· 288 310 ------------------------------------------------------ 289 311 , (each [ class Button, button ]) 290 312 [ backgroundColor transparent 291 - , border3 (px 1) solid (cssColor colorDerivatives.success) 313 + , border3 (px 2) solid (cssColor colorDerivatives.success) 292 314 , borderRadius borderRadiuses.smallElements 293 315 , boxSizing contentBox 294 316 , color (cssColor colorDerivatives.success) ··· 296 318 , display inlineBlock 297 319 , fontFamily inherit 298 320 , fontSize (Css.rem 0.95) 299 - , fontWeight (int 600) 321 + , fontWeight (int 700) 300 322 , height (gr 6) 301 323 , lineHeight (gr 6) 302 324 , padding3 (px 1) (gr 2) zero ··· 304 326 -- 305 327 , focus 306 328 [ outline none 329 + ] 330 + 331 + -- 332 + , descendants 333 + [ svg 334 + [ fontSize (Css.em 1.2) 335 + , marginTop (px -2) 336 + , verticalAlign middle 337 + ] 338 + , selector "g" 339 + [ fill currentColor 340 + ] 307 341 ] 308 342 ] 309 343 ··· 358 392 , top zero 359 393 , width (vw 100) 360 394 , zIndex (int 900) 395 + ] 396 + 397 + ------------------------------------------------------ 398 + -- Columns 399 + ------------------------------------------------------ 400 + , class Columns 401 + [ property "columns" "2" 402 + , property "column-gap" (.value (gr 8)) 403 + 404 + -- 405 + , children 406 + [ div 407 + [ property "break-inside" "avoid" 408 + ] 409 + ] 361 410 ] 362 411 ]
+5
src/Css/Traits.elm
··· 64 64 batch [ fontFamilies [ "Overpass", "sans-serif" ] ] 65 65 66 66 67 + headerFont : Style 68 + headerFont = 69 + batch [ fontFamilies [ "Montserrat", "sans-serif" ] ] 70 + 71 + 67 72 68 73 -- Css / Colors 69 74