on master help sign in
A bit prettier interface
commit1b25928bdcc877a8c94d3babc27c8401acd5ee53 authoriko <ilyakooo0@gmail.com> dateTue 26 Jul 2022, 15:35 (4 years ago) parentcc304be
15 files changed+381−62
appname.desktop+1−1 backend/Bridge.purs+2−1 backend/Main.purs+6−2 bridge.yaml+1 elm.json+2−2 frontend/Bridge.elm+13−5 frontend/Main.elm+101−48 frontend/Notification.elm+50 frontend/Page.elm+24 frontend/Pages/Loader.elm+10 frontend/Pages/Login.elm+81 frontend/Pages/Navigation.elm+24 frontend/Utils.elm+23−2 index.html+1−1 style.css+42
appname.desktop+1−1
@@ -1,6 +1,6 @@
11[Desktop Entry]
22Name=App Title
3−Exec=webapp-container --inspector=9223 --app-id="appname.iko" $@ index.html
3+Exec=webapp-container --local-content-can-access-remote-urls --app-id="appname.iko" $@ index.html
44Icon=logo.svg
55Terminal=false
66Type=Application
backend/Bridge.purs+2−1
@@ -39,7 +39,8 @@ derive instance eqCmd :: Eq Cmd
3939derive instance ordCmd :: Ord Cmd
4040
4141data Sub =
42− Hello
42+ GotEverything String
43+ | Hello
4344
4445instance encodeJsonSub :: EncodeJson Sub where
4546 encodeJson = genericEncodeAeson Argonaut.defaultOptions
backend/Main.purs+6−2
@@ -24,12 +24,16 @@ import FFI as FFI
2424main :: Effect Unit
2525main = do
2626 app <- FFI.startElm "elm"
27+ let
28+ processResult res = do
29+ log res
30+ Elm.send app (GotEverything res)
2731 Elm.subscribe app \(Bridge.Login (Bridge.Cmd_Login {email, server, password})) -> do
2832 log $ "Got cmd"
2933 services <- WB.getServices
3034 runAff_ (\res -> case res of
31− Left e -> log $ show e
32− Right x -> log $ show x
35+ Left e -> processResult $ show e
36+ Right x -> processResult $ show x
3337 ) do
3438 unauthedApi <- Aff.liftAff $ Promise.toAff $ services.getApi
3539 { base : toNullable $ Just server,
bridge.yaml+1
@@ -1,5 +1,6 @@
11Sub:
22- Hello
3+- GotEverything: String
34
45Cmd:
56- Login:
elm.json+2−2
@@ -10,10 +10,10 @@
1010 "elm/browser": "1.0.2",
1111 "elm/core": "1.0.5",
1212 "elm/html": "1.0.0",
13− "elm/json": "1.1.3"
13+ "elm/json": "1.1.3",
14+ "elm/time": "1.0.0"
1415 },
1516 "indirect": {
16− "elm/time": "1.0.0",
1717 "elm/url": "1.0.0",
1818 "elm/virtual-dom": "1.0.3"
1919 }
frontend/Bridge.elm+13−5
@@ -46,14 +46,22 @@ jsonEncCmd (Login v1) =
4646
4747
4848type Sub =
49− Hello
49+ GotEverything String
50+ | Hello
5051
5152jsonDecSub : Json.Decode.Decoder ( Sub )
5253jsonDecSub =
53− Json.Decode.lazy (\_ -> Json.Decode.succeed Hello)
54−
54+ let jsonDecDictSub = Dict.fromList
55+ [ ("GotEverything", Json.Decode.lazy (\_ -> Json.Decode.map GotEverything (Json.Decode.string)))
56+ , ("Hello", Json.Decode.lazy (\_ -> Json.Decode.succeed Hello))
57+ ]
58+ jsonDecObjectSetSub = Set.fromList []
59+ in decodeSumTaggedObject "Sub" "tag" "contents" jsonDecDictSub jsonDecObjectSetSub
5560
5661jsonEncSub : Sub -> Value
57−jsonEncSub (Hello ) =
58− Json.Encode.list identity []
62+jsonEncSub val =
63+ let keyval v = case v of
64+ GotEverything v1 -> ("GotEverything", encodeValue (Json.Encode.string v1))
65+ Hello -> ("Hello", encodeValue (Json.Encode.list identity []))
66+ in encodeSumTaggedObject "tag" "contents" keyval val
5967
frontend/Main.elm+101−48
@@ -6,95 +6,148 @@ import FFI exposing (getBridge)
66import Html exposing (..)
77import Html.Attributes as Attr
88import Html.Events as Ev
9+import Notification
10+import Pages.Loader exposing (loader)
11+import Pages.Login as Login
12+import Pages.Navigation as Navigation
913import Utils exposing (..)
1014
1115
1216type Msg
1317 = RecieveMessage String
14− | Error String
15− | UpdateEmail String
16− | UpdateServer String
17− | UpdatePassword String
18− | Submit
18+ | ShowError String
19+ | CloseNotification
20+ | Submit { email : String, password : String, server : String }
21+ | LoginMsg Login.Msg
1922
2023
2124type alias Model =
2225 { messages : List String
23− , error : Maybe String
24− , server : String
25− , email : String
26− , password : String
26+ , notification : Maybe Notification.Config
27+ , page : PageModel
2728 }
2829
2930
31+type PageModel
32+ = LoginModel Login.Model
33+ | LoadingPage
34+
35+
36+showPage : PageModel -> ( String, List (Html Msg) )
37+showPage page =
38+ case page of
39+ LoginModel model ->
40+ let
41+ p =
42+ Login.page loginCallbacks LoginMsg
43+ in
44+ ( p.title model, p.view model )
45+
46+ LoadingPage ->
47+ ( "", [ loader ] )
48+
49+
3050main : Program () Model Msg
3151main =
3252 Browser.element
3353 { init = \_ -> ( init, Cmd.none )
3454 , view = view
3555 , update = update
36− , subscriptions = \_ -> getBridge Error (always (RecieveMessage "Got it!"))
56+ , subscriptions =
57+ \_ ->
58+ getBridge ShowError
59+ (\msg ->
60+ case msg of
61+ Bridge.Hello ->
62+ RecieveMessage "Got it!"
63+
64+ Bridge.GotEverything everything ->
65+ RecieveMessage everything
66+ )
3767 }
3868
3969
4070init : Model
4171init =
4272 { messages = []
43− , error = Nothing
44− , server = "bitwarden.iko.soy"
45− , email = "mail@iko.soy"
46− , password = ""
73+ , notification = Nothing
74+ , page = LoadingPage
4775 }
4876
4977
5078view : Model -> Html Msg
5179view model =
80+ let
81+ ( title, body ) =
82+ showPage model.page
83+ in
5284 div []
53− (maybeList model.error (text >> List.singleton >> h2 [])
54− ++ [ h1 [] [ text "HELLO" ]
55− , ul [] (model.messages |> List.map (text >> List.singleton >> li []))
56− , h4 [] [ text "Email" ]
57− , input [ Attr.type_ "text", Attr.value model.email, Ev.onInput UpdateEmail ] []
58− , h4 [] [ text "Password" ]
59− , input [ Attr.type_ "text", Attr.value model.password, Ev.onInput UpdatePassword ] []
60− , h4 [] [ text "Server" ]
61− , input [ Attr.type_ "text", Attr.value model.server, Ev.onInput UpdateServer ] []
62− , button [ Ev.onClick Submit ] [ text "Submit" ]
63− , table []
64− [ tbody []
65− (List.repeat 10 (tr [] [ td [] [ text "test" ] ]))
66− ]
67− ]
68− )
85+ [ Navigation.navigation { back = False, title = title }
86+ , main_ []
87+ (maybeList model.notification (Notification.notification CloseNotification)
88+ ++ body
89+ )
90+ ]
6991
7092
7193update : Msg -> Model -> ( Model, Cmd Msg )
7294update msg model =
95+ let
96+ processPage : (pageModel -> PageModel) -> ( Result String pageModel, Cmd Msg ) -> ( Model, Cmd Msg )
97+ processPage liftModel ( resultModel, cmd ) =
98+ case resultModel of
99+ Ok mdl ->
100+ ( { model | page = liftModel mdl }, cmd )
101+
102+ Err err ->
103+ ( { model
104+ | notification =
105+ Just
106+ { title = "An error had occured"
107+ , message = err
108+ , severity = Notification.Error
109+ }
110+ }
111+ , cmd
112+ )
113+ in
73114 case msg of
74115 RecieveMessage x ->
75116 ( { model | messages = x :: model.messages }
76117 , Cmd.none
77118 )
78119
79− Error err ->
80− ( { model | error = Just err }, Cmd.none )
81−
82− UpdateEmail email ->
83− ( { model | email = email }, Cmd.none )
84−
85− UpdateServer server ->
86− ( { model | server = server }, Cmd.none )
120+ ShowError err ->
121+ ( { model
122+ | notification =
123+ Just
124+ { title = "Something went wrong"
125+ , message = err
126+ , severity = Notification.Error
127+ }
128+ }
129+ , Cmd.none
130+ )
87131
88− UpdatePassword password ->
89− ( { model | password = password }, Cmd.none )
132+ CloseNotification ->
133+ ( { model | notification = Nothing }
134+ , Cmd.none
135+ )
90136
91− Submit ->
137+ Submit data ->
92138 ( model
93− , FFI.sendBridge
94− (Bridge.Login
95− { email = model.email
96− , server = model.server
97− , password = model.password
98− }
99− )
139+ , FFI.sendBridge (Bridge.Login data)
100140 )
141+
142+ LoginMsg imsg ->
143+ case model.page of
144+ LoginModel page ->
145+ (Login.page loginCallbacks LoginMsg).update imsg page |> processPage LoginModel
146+
147+ _ ->
148+ ( model, Cmd.none )
149+
150+
151+loginCallbacks : Login.Callbacks Msg
152+loginCallbacks =
153+ { submit = Submit }
frontend/Notification.elmnew file+50
@@ -0,0 +1,50 @@
1+module Notification exposing
2+ ( Config
3+ , Severity(..)
4+ , notification
5+ )
6+
7+import Html exposing (..)
8+import Html.Attributes as Attr
9+import Html.Events as Ev
10+
11+
12+type alias Config =
13+ { message : String
14+ , title : String
15+ , severity : Severity
16+ }
17+
18+
19+type Severity
20+ = Info
21+ | Warning
22+ | Error
23+ | Success
24+
25+
26+notification : msg -> Config -> Html msg
27+notification close { message, title, severity } =
28+ div
29+ [ Attr.class "floating-notifications"
30+ , Attr.class
31+ (case severity of
32+ Info ->
33+ "p-notification--information"
34+
35+ Error ->
36+ "p-notification--negative"
37+
38+ Warning ->
39+ "p-notification--caution"
40+
41+ Success ->
42+ "p-notification--positive"
43+ )
44+ ]
45+ [ div [ Attr.class "p-notification__content" ]
46+ [ h5 [ Attr.class "p-notification__title" ] [ text title ]
47+ , p [ Attr.class "notification__message" ] [ text message ]
48+ , button [ Attr.class "p-notification__close", Ev.onClick close ] []
49+ ]
50+ ]
frontend/Page.elmnew file+24
@@ -0,0 +1,24 @@
1+module Page exposing (..)
2+
3+import Html exposing (..)
4+import Html.Attributes as Attr exposing (..)
5+import Html.Events exposing (..)
6+import Time
7+
8+
9+type alias Env =
10+ {}
11+
12+
13+type alias Page init model imsg emsg =
14+ (imsg -> emsg)
15+ -> InitializedPage init model imsg emsg
16+
17+
18+type alias InitializedPage init model imsg emsg =
19+ { init : init -> ( model, Cmd emsg )
20+ , view : model -> List (Html emsg)
21+ , update : imsg -> model -> ( Result String model, Cmd emsg )
22+ , subscriptions : model -> Sub emsg
23+ , title : model -> String
24+ }
frontend/Pages/Loader.elmnew file+10
@@ -0,0 +1,10 @@
1+module Pages.Loader exposing (loader)
2+
3+import Html exposing (..)
4+import Html.Attributes as Attr
5+import Utils exposing (..)
6+
7+
8+loader : Html msg
9+loader =
10+ flexCenter [ i [ Attr.class "p-icon--spinner u-animation--spin spinner" ] [] ]
frontend/Pages/Login.elmnew file+81
@@ -0,0 +1,81 @@
1+module Pages.Login exposing (Callbacks, Model, Msg, page)
2+
3+import Html exposing (..)
4+import Html.Attributes as Attr
5+import Html.Events as Ev
6+import Page exposing (..)
7+import Utils exposing (..)
8+
9+
10+type alias Model =
11+ { server : String
12+ , email : String
13+ , password : String
14+ }
15+
16+
17+type Msg
18+ = UpdateEmail String
19+ | UpdateServer String
20+ | UpdatePassword String
21+ | Submit
22+
23+
24+type alias Callbacks emsg =
25+ { submit : { email : String, server : String, password : String } -> emsg
26+ }
27+
28+
29+page : Callbacks emsg -> Page () Model Msg emsg
30+page callbacks liftMsg =
31+ { init = \() -> Tuple.mapSecond (Cmd.map liftMsg) init
32+ , view = \model -> view model |> List.map (Html.map liftMsg)
33+ , update = \msg model -> update callbacks liftMsg msg model
34+ , subscriptions = \model -> subscriptions model |> Sub.map liftMsg
35+ , title = always "Log into your bitwarden account"
36+ }
37+
38+
39+init : ( Model, Cmd Msg )
40+init =
41+ ( { server = "https://bitwarden.iko.soy"
42+ , email = "mail@iko.soy"
43+ , password = ""
44+ }
45+ , Cmd.none
46+ )
47+
48+
49+update : Callbacks emsg -> (Msg -> emsg) -> Msg -> Model -> ( Result String Model, Cmd emsg )
50+update { submit } liftMsg msg model =
51+ case msg of
52+ UpdateEmail email ->
53+ ( Ok { model | email = email }, Cmd.none )
54+
55+ UpdateServer server ->
56+ ( Ok { model | server = server }, Cmd.none )
57+
58+ UpdatePassword password ->
59+ ( Ok { model | password = password }, Cmd.none )
60+
61+ Submit ->
62+ ( Ok model, pureCmd (submit model) )
63+
64+
65+subscriptions : Model -> Sub Msg
66+subscriptions model =
67+ Sub.none
68+
69+
70+view : Model -> List (Html Msg)
71+view model =
72+ [ form []
73+ [ label [] [ text "Server" ]
74+ , input [ Attr.type_ "url", Attr.value model.server, Ev.onInput UpdateServer ] []
75+ , label [] [ text "Email" ]
76+ , input [ Attr.type_ "email", Attr.value model.email, Ev.onInput UpdateEmail ] []
77+ , label [] [ text "Password" ]
78+ , input [ Attr.type_ "password", Attr.value model.password, Ev.onInput UpdatePassword ] []
79+ , alignRight [ button [ Ev.onClick Submit ] [ text "Log in" ] ]
80+ ]
81+ ]
frontend/Pages/Navigation.elmnew file+24
@@ -0,0 +1,24 @@
1+module Pages.Navigation exposing (Config, navigation)
2+
3+import Html exposing (..)
4+import Html.Attributes as Attr
5+import Utils exposing (..)
6+
7+
8+type alias Config =
9+ { back : Bool
10+ , title : String
11+ }
12+
13+
14+navigation : Config -> Html msg
15+navigation { back, title } =
16+ nav [ Attr.class "p-tabs p-tabs__list" ]
17+ [ h3 []
18+ [ button
19+ (Attr.class "p-button--base is-inline u-no-margin" :: optional (not back) (Attr.style "visibility" "hidden"))
20+ [ i [ Attr.class "p-icon--chevron-up ninety-counter" ] []
21+ ]
22+ , text title
23+ ]
24+ ]
frontend/Utils.elm+23−2
@@ -1,5 +1,7 @@
11module Utils exposing (..)
22
3+import Html exposing (..)
4+import Html.Attributes as Attr
35import Task
46
57
@@ -33,8 +35,8 @@ result err ok r =
3335 err e
3436
3537
36−optionals : Bool -> a -> List a
37−optionals b a =
38+optional : Bool -> a -> List a
39+optional b a =
3840 if b then
3941 [ a ]
4042
@@ -42,6 +44,15 @@ optionals b a =
4244 []
4345
4446
47+optionals : Bool -> List a -> List a
48+optionals b a =
49+ if b then
50+ a
51+
52+ else
53+ []
54+
55+
4556maybeList : Maybe a -> (a -> b) -> List b
4657maybeList m f =
4758 case m of
@@ -50,3 +61,13 @@ maybeList m f =
5061
5162 Nothing ->
5263 []
64+
65+
66+alignRight : List (Html msg) -> Html msg
67+alignRight inner =
68+ div [ Attr.class "u-align--right" ] inner
69+
70+
71+flexCenter : List (Html msg) -> Html msg
72+flexCenter =
73+ div [ Attr.class "simple-flex-center" ]
index.html+1−1
@@ -5,8 +5,8 @@
55 <meta charset="UTF-8">
66 <meta http-equiv="X-UA-Compatible" content="IE=edge">
77 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
8− <link rel="stylesheet" href="style.css">
98 <link rel="stylesheet" href="vanilla/style.css">
9+ <link rel="stylesheet" href="style.css">
1010 <title>Test.</title>
1111 <script src="elm.js"></script>
1212</head>
style.css+42
@@ -0,0 +1,42 @@
1+
2+:root {
3+ --color-light: #F7F7F7;
4+}
5+
6+main {
7+ margin: 1rem;
8+}
9+
10+
11+nav.p-tabs__list {
12+ top: 0;
13+ position: sticky;
14+ background-color: white;
15+ padding-bottom: 1rem;
16+ padding-bottom: 0;
17+}
18+
19+.ninety-counter {
20+ transform: rotate(90deg);
21+}
22+
23+.floating-notifications {
24+ position: fixed;
25+ top: 1rem;
26+ right: 1rem;
27+ left: 1rem;
28+ z-index: 9999;
29+}
30+
31+.simple-flex-center {
32+ display: flex;
33+ flex-direction: row;
34+ flex-wrap: wrap;
35+ justify-content: center;
36+ align-items: center;
37+ align-content: center;
38+}
39+
40+.spinner{
41+ padding: 1rem;
42+}