@@ -0,0 +1,279 @@
1+port module Main exposing (main)
4+import Dict exposing (Dict)
5+import Element exposing (..)
6+import Element.Background as Background
7+import Element.Border as Border
8+import Element.Events as Events
9+import Element.Font as Font
10+import Element.Input as Input
11+import Element.Keyed as Keyed
12+import Heroicons.Outline
13+import Html.Attributes
15+import Json.Decode as JD
17+import Svg.Attributes exposing (opacity)
18+import Time exposing (Posix)
21+import Ur.Deconstructor as D
28+ "http://localhost:8080"
32+ { ship : Maybe String
34+ , initiatedSearch : Maybe String
35+ , searchResults : List SearchResult
36+ , resultTimelines : Dict String ( Animator.Timeline Int, Animator.Timeline Bool )
40+type alias SearchResult =
49+ | UpdateSearch String
51+ | UpdateSearchResults (List SearchResult)
56+main : Ur.Run.Program Model Msg
62+ , initiatedSearch = Nothing
64+ , resultTimelines = Dict.empty
67+ [ Ur.logIn url "lidlut-tabwed-pillex-ridrup"
68+ |> Cmd.map (always Noop)
69+ , Ur.getShipName url |> Cmd.map (result (always Noop) GotShipName)
74+ , view = \model -> { title = "%seax", body = [ view model |> layout [] ] }
75+ , subscriptions = \model -> Animator.toSubscription Tick model (animator model)
76+ , createEventSource = createEventSource
77+ , urbitSubscriptions =
78+ \{ initiatedSearch, ship } ->
79+ case ( initiatedSearch, ship ) of
80+ ( Just query, Just ship_ ) ->
83+ , path = [ "search", query ]
86+ D.list (D.cell D.cord D.cord)
90+ { title = title, link = link }
92+ >> UpdateSearchResults
98+ , onEventSourceMsg = onEventSourceMessage
99+ , urbitUrl = \_ -> url
103+view : Model -> Element Msg
105+ case model.initiatedSearch of
107+ column [ centerX, centerY, padding 8, spacing 16 ]
108+ [ el [ centerX, Font.size 67, Font.heavy ] (text "%seax")
113+ column [ width fill, padding 8, spacing 16 ]
115+ , Keyed.column [ width fill ]
116+ (model.searchResults
118+ (\{ title, link } ->
126+ (Dict.get link model.resultTimelines
127+ |> Maybe.map Tuple.second
128+ |> Maybe.withDefault (Animator.init False)
138+ , Html.Attributes.style "top"
140+ (Dict.get link model.resultTimelines
141+ |> Maybe.map Tuple.first
142+ |> Maybe.withDefault (Animator.init 0)
144+ (\i -> toFloat i * 47 |> Animator.at)
150+ , Html.Attributes.style "position" "absolute" |> htmlAttribute
156+ , Html.Attributes.style "text-overflow" "ellipsis" |> htmlAttribute
161+ , Html.Attributes.style "text-overflow" "ellipsis" |> htmlAttribute
163+ , Font.color (rgb 0.7 0.7 0.7)
172+searchView : { a | search : String } -> Element Msg
176+ { onChange = UpdateSearch
177+ , placeholder = Nothing
178+ , text = model.search
179+ , label = Input.labelHidden "search"
181+ , Input.button [ height fill ]
189+ , Border.color (rgb 0 0 0)
190+ , Background.color (rgb 0 0 0)
191+ , Font.color (rgb 1 1 1)
193+ [ Font.color (rgb 0 0 0)
194+ , Background.color (rgb 1 1 1)
197+ , onPress = Just (Search model.search)
202+update : Msg -> Model -> ( Model, Ur.Cmd.Cmd Msg )
206+ ( model, Ur.Cmd.none )
209+ ( { model | ship = Just ship }, Ur.Cmd.none )
211+ UpdateSearch search ->
212+ ( { model | search = search }, Ur.Cmd.none )
215+ ( { model | initiatedSearch = Just query }, Ur.Cmd.none )
217+ UpdateSearchResults results ->
220+ List.Extra.zip (List.range 0 (List.length results - 1)) results
222+ (\( index, result_ ) ->
224+ , case Dict.get result_.link model.resultTimelines of
226+ timeline |> Tuple.mapFirst (Animator.go Animator.slowly index)
229+ ( Animator.init index, Animator.init False |> Animator.go Animator.slowly True )
234+ ( { model | resultTimelines = foo, searchResults = results }, Ur.Cmd.none )
237+ ( model, Ur.Cmd.none )
240+ ( Animator.update time (animator model) model, Ur.Cmd.none )
243+animator : Model -> Animator.Animator Model
248+ |> Animator.watchingWith
249+ (\m -> Dict.get key m.resultTimelines |> Maybe.map Tuple.first |> Maybe.withDefault (Animator.init 0))
251+ { m | resultTimelines = m.resultTimelines |> Dict.update key (Maybe.map (\( _, x ) -> ( index, x ))) }
254+ |> Animator.watchingWith
255+ (\m -> Dict.get key m.resultTimelines |> Maybe.map Tuple.second |> Maybe.withDefault (Animator.init False))
257+ { m | resultTimelines = m.resultTimelines |> Dict.update key (Maybe.map (\( x, _ ) -> ( x, shown ))) }
260+ -- |> Animator.watching
263+ (Dict.keys model.resultTimelines)
266+result : (a -> c) -> (b -> c) -> Result a b -> c
276+port createEventSource : String -> Cmd msg
279+port onEventSourceMessage : (JD.Value -> msg) -> Sub msg