@@ -2,27 +2,34 @@ module Spago.Search.App.SearchResults where
22
33import Prelude
44
5+import Spago.Search.App.SearchField (Message(..))
56import Spago.Search.Declarations (loadDeclarations)
67import Spago.Search.Extra (whenJust)
78import Spago.Search.Index (SearchIndex, SearchResult, mkSearchIndex)
89
10+import CSS (textWhitespace, whitespacePreWrap)
911import Data.Array as Array
1012import Data.Either (Either(..))
1113import Data.List as List
12−import Data.Maybe (Maybe(..), isNothing)
14+import Data.Maybe (Maybe(..), isNothing, isJust)
1315import Data.Newtype (unwrap, wrap)
1416import Data.Search.Trie as Trie
1517import Data.String (length) as String
16−import Data.String.CodeUnits (toCharArray) as String
18+import Data.String.CodeUnits (toCharArray, stripSuffix) as String
1719import Data.String.Common (toLower) as String
20+import Data.String.Pattern (Pattern(..)) as String
1821import Effect.Aff (Aff)
1922import Effect.Console (error)
2023import Halogen as H
2124import Halogen.HTML as HH
25+import Halogen.HTML.CSS as HS
26+import Halogen.HTML.Events as HE
2227import Halogen.HTML.Properties as HP
23−import Spago.Search.App.SearchField (Message(..))
2428import Web.DOM.Element (Element)
2529import Web.DOM.Element as Element
30+import Web.HTML as HTML
31+import Web.HTML.Location as Location
32+import Web.HTML.Window as Window
2633
2734type State = { mbIndex :: Maybe SearchIndex
2835 , results :: Array SearchResult
@@ -33,16 +40,19 @@ type State = { mbIndex :: Maybe SearchIndex
3340data Query a
3441 = SearchFieldMessage Message a
3542
36−mkComponent :: forall i o. Element -> H.Component HH.HTML Query i o Aff
43+data Action
44+ = SearchResultClicked String
45+
46+mkComponent :: forall o i. Element -> H.Component HH.HTML Query i o Aff
3747mkComponent contents =
3848 H.mkComponent
39− { initialState:
40− const { mbIndex: Nothing, results: [], input: "", contents }
49+ { initialState: const { mbIndex: Nothing, results: [], input: "", contents }
4150 , render
42− , eval: H.mkEval $ H.defaultEval { handleQuery = handleQuery }
51+ , eval: H.mkEval $ H.defaultEval { handleQuery = handleQuery
52+ , handleAction = handleAction }
4353 }
4454
45−handleQuery :: forall o a. Query a -> H.HalogenM State Unit () o Aff (Maybe a)
55+handleQuery :: forall o a. Query a -> H.HalogenM State Action () o Aff (Maybe a)
4656handleQuery (SearchFieldMessage Focused next) = do
4757 state <- H.get
4858 when (isNothing state.mbIndex) do
@@ -72,40 +82,63 @@ handleQuery (SearchFieldMessage (InputUpdated input) next) = do
7282 let path = List.fromFoldable $
7383 String.toCharArray $
7484 String.toLower input
75−
7685 H.modify_ (_ { results = Array.concat $
7786 List.toUnfoldable $
7887 map List.toUnfoldable $
7988 Trie.queryValues path $
8089 index })
81−
8290 pure Nothing
8391
84−showPageContents :: forall o. H.HalogenM State Unit () o Aff Unit
92+handleAction :: forall o. Action -> H.HalogenM State Action () o Aff Unit
93+handleAction = case _ of
94+ SearchResultClicked moduleName -> do
95+ -- Decide if we are going to load a new page or to jump to a hash on the
96+ -- current page. In the latter case, hide search results and show the main
97+ -- page contents.
98+ onThisPage <- H.liftEffect do
99+ window <- HTML.window
100+ location <- Window.location window
101+ pathname <- Location.pathname location
102+ pure $ isJust $
103+ String.stripSuffix (String.Pattern $ moduleName <> ".html") pathname
104+
105+ when onThisPage do
106+ showPageContents
107+ H.modify_ (_ { input = "" })
108+
109+showPageContents :: forall o. H.HalogenM State Action () o Aff Unit
85110showPageContents = do
86111 state <- H.get
87112 H.liftEffect do
88113 Element.removeAttribute "style" state.contents
89114
90−hidePageContents :: forall o. H.HalogenM State Unit () o Aff Unit
115+hidePageContents :: forall o. H.HalogenM State Action () o Aff Unit
91116hidePageContents = do
92117 state <- H.get
93118 H.liftEffect do
94119 Element.setAttribute "style" "display: none" state.contents
95120
96−render :: forall m. State -> H.ComponentHTML Unit () m
121+render :: forall m. State -> H.ComponentHTML Action () m
97122render { mbIndex: Nothing } =
98123 HH.div_ []
99124render { input: "" } =
100125 HH.div_ []
101126render state =
102− HH.div [ HP.classes [ wrap "container"
103− , wrap "clearfix"
104− ]
105− ]
127+ HH.div [ HP.classes [ wrap "container", wrap "clearfix" ] ] $
128+ pure $
129+
130+ HH.div [ HP.classes [ wrap "col", wrap "col--main" ] ] $
131+
132+ [ HH.h1_ [ HH.text "Search results" ] ] <>
133+
106134 if Array.null state.results
107135 then
108− [ renderSummary "No search results" ]
136+ [ HH.div [ HP.classes [ wrap "result", wrap "result--empty" ] ]
137+ [ HH.text "Your search for "
138+ , HH.strong_ [ HH.text state.input ]
139+ , HH.text " did not yield any results."
140+ ]
141+ ]
109142 else
110143 [ renderSummary $
111144 "Found " <>
@@ -123,11 +156,23 @@ renderSummary text =
123156 [ HH.text text
124157 ]
125158
126−renderResult :: forall a b. SearchResult -> Array (HH.HTML a b)
159+renderResult :: forall a. SearchResult -> Array (HH.HTML a Action)
127160renderResult = unwrap >>> \result ->
128161 [ HH.div [ HP.class_ (wrap "result") ]
129162 [ HH.h3 [ HP.class_ (wrap "result__title") ]
130− [ HH.a [ HP.class_ (wrap "result__link") ]
163+ [ HH.a [ HP.class_ (wrap "result__link")
164+ , HE.onClick $ const $ Just $ SearchResultClicked result.moduleName
165+ , HP.href $
166+ result.moduleName <> ".html#" <>
167+
168+ ( case result.declType of
169+ "value" -> "v"
170+ "alias" -> "v"
171+ _ -> "t"
172+ ) <>
173+
174+ ":" <> result.name
175+ ]
131176 [ HH.text result.name ]
132177 ]
133178 ]
@@ -139,9 +184,9 @@ renderResult = unwrap >>> \result ->
139184 ] <>
140185
141186 case result.comments of
142− Just comments -> [ HH.pre_
143− [ HH.text comments
144− ]
187+ Just comments -> [ HH.pre [ HS.style do
188+ textWhitespace whitespacePreWrap ]
189+ [ HH.text comments ]
145190 ]
146191 Nothing -> [ ]
147192