@@ -1,13 +1,14 @@
1-- | This is the main module of the client-side Halogen app.
1-- | This is the main module of the client-side Halogen app.
2module Docs.Search.App where
2module Docs.Search.App where
6import Docs.Search.App.SearchField as SearchField
4import Docs.Search.App.SearchField as SearchField
7import Docs.Search.App.SearchResults as SearchResults
5import Docs.Search.App.SearchResults as SearchResults
6+import Docs.Search.App.Sidebar as Sidebar
8import Docs.Search.Extra (whenJust)
7import Docs.Search.Extra (whenJust)
8+import Docs.Search.ModuleIndex as ModuleIndex
9import Docs.Search.PackageIndex as PackageIndex
9import Docs.Search.PackageIndex as PackageIndex
11import Control.Coroutine as Coroutine
12import Control.Coroutine as Coroutine
12import Data.Maybe (Maybe(..))
13import Data.Maybe (Maybe(..))
13import Data.Newtype (wrap)
14import Data.Newtype (wrap)
@@ -17,6 +18,7 @@ import Halogen as H
17import Halogen.Aff as HA
18import Halogen.Aff as HA
18import Halogen.VDom.Driver (runUI)
19import Halogen.VDom.Driver (runUI)
19import MarkdownIt as MD
20import MarkdownIt as MD
21+import Web.DOM.ChildNode as ChildNode
20import Web.DOM.Document as Document
22import Web.DOM.Document as Document
21import Web.DOM.Element as Element
23import Web.DOM.Element as Element
22import Web.DOM.Node as Node
24import Web.DOM.Node as Node
@@ -24,10 +26,12 @@ import Web.DOM.ParentNode as ParentNode
24import Web.DOM.Text as Text
26import Web.DOM.Text as Text
25import Web.Event.EventTarget (addEventListener, eventListener)
27import Web.Event.EventTarget (addEventListener, eventListener)
26import Web.HTML as HTML
28import Web.HTML as HTML
29+import Web.HTML.Event.HashChangeEvent.EventTypes (hashchange)
27import Web.HTML.HTMLDocument as HTMLDocument
30import Web.HTML.HTMLDocument as HTMLDocument
28import Web.HTML.HTMLElement (fromElement)
31import Web.HTML.HTMLElement (fromElement)
29import Web.HTML.Window as Window
32import Web.HTML.Window as Window
30−import Web.HTML.Event.HashChangeEvent.EventTypes (hashchange)
33+import Web.HTML.Event.EventTypes (focus)
32main :: Effect Unit
36main :: Effect Unit
@@ -40,11 +44,21 @@ main = do
40 -- Initialize a `markdown-it` instance (we need it to render the docs as markdown)
44 -- Initialize a `markdown-it` instance (we need it to render the docs as markdown)
41 markdownIt <- MD.newMarkdownIt MD.Default mempty
45 markdownIt <- MD.newMarkdownIt MD.Default mempty
43− whenJust mbContainers \ { searchField, searchResults, pageContents } -> do
47+ whenJust mbContainers \ { searchField
51+ , realSidebar } -> do
53+ -- Hide real sidebar completely - we are going to recreate it as Halogen component.
54+ ChildNode.remove $ Element.toChildNode realSidebar
44 HA.runHalogenAff do
56 HA.runHalogenAff do
45 packageIndex <- PackageIndex.loadPackageIndex
57 packageIndex <- PackageIndex.loadPackageIndex
58+ moduleIndex <- ModuleIndex.loadModuleIndex
47 let initialSearchEngineState = { packageIndex: packageIndex
60 let initialSearchEngineState = { packageIndex: packageIndex
61+ , moduleIndex: moduleIndex
48 , index: mempty
62 , index: mempty
49 , typeIndex: mempty
63 , typeIndex: mempty
@@ -53,6 +67,9 @@ main = do
53 SearchResults.mkComponent initialSearchEngineState pageContents markdownIt
67 SearchResults.mkComponent initialSearchEngineState pageContents markdownIt
55 sfio <- runUI SearchField.component unit searchField
69 sfio <- runUI SearchField.component unit searchField
71+ component <- Sidebar.mkComponent moduleIndex
72+ runUI component unit sidebarContainer
56 srio <- runUI resultsComponent unit searchResults
73 srio <- runUI resultsComponent unit searchResults
58 sfio.subscribe $
75 sfio.subscribe $
@@ -72,6 +89,16 @@ main = do
73 addEventListener hashchange listener true (Window.toEventTarget win)
90 addEventListener hashchange listener true (Window.toEventTarget win)
92+ -- Subscribe to window focus events
96+ eventListener \event ->
98+ sbio.query $ H.tell Sidebar.UpdateModuleGrouping
100+ addEventListener focus listener true (Window.toEventTarget win)
76insertStyle :: Document.Document -> Effect Unit
103insertStyle :: Document.Document -> Effect Unit
77insertStyle doc = do
104insertStyle doc = do
@@ -102,24 +129,49 @@ insertStyle doc = do
102 /* Add a margin between badge icons and package/module names. */
129 /* Add a margin between badge icons and package/module names. */
103 margin-right: 0.25em;
130 margin-right: 0.25em;
137+ /* Make spaces narrower in the sidebar */
138+ .li-package > details > ul {
140+ margin-bottom: auto;
142+ #group-modules__label, #group-modules__input {
143+ display: inline-block;
144+ vertical-align: middle;
148+ letter-spacing: 1px;
149+ margin-bottom: -0.8em;
107 mbHead <-
156 mbHead <-
108 ParentNode.querySelector (wrap "head") (Document.toParentNode doc)
157 ParentNode.querySelector (wrap "head") (Document.toParentNode doc)
110 whenJust mbHead \head -> do
159 whenJust mbHead \head -> do
112 contents <- Document.createTextNode styleContents doc
160 contents <- Document.createTextNode styleContents doc
113 style <- Document.createElement "style" doc
161 style <- Document.createElement "style" doc
114 void $ Node.appendChild (Text.toNode contents) (Element.toNode style)
162 void $ Node.appendChild (Text.toNode contents) (Element.toNode style)
115 void $ Node.appendChild (Element.toNode style) (Element.toNode head)
163 void $ Node.appendChild (Element.toNode style) (Element.toNode head)
117-- | Query the DOM for specific elements that should always be present.
166-- | Query the DOM for specific elements that should always be present.
118getContainers
167getContainers
119 :: Document.Document
168 :: Document.Document
120 -> Effect (Maybe { searchField :: HTML.HTMLElement
169 -> Effect (Maybe { searchField :: HTML.HTMLElement
121 , searchResults :: HTML.HTMLElement
170 , searchResults :: HTML.HTMLElement
122− , pageContents :: Element.Element })
171+ , pageContents :: Element.Element
172+ , sidebarContainer :: HTML.HTMLElement
173+ , realSidebar :: Element.Element
123getContainers doc = do
175getContainers doc = do
124 let docPN = Document.toParentNode doc
176 let docPN = Document.toParentNode doc
125 mbBanner <-
177 mbBanner <-
@@ -128,13 +180,21 @@ getContainers doc = do
128 ParentNode.querySelector (wrap ".everything-except-footer") docPN
180 ParentNode.querySelector (wrap ".everything-except-footer") docPN
129 mbContainer <-
181 mbContainer <-
130 ParentNode.querySelector (wrap ".everything-except-footer > .container") docPN
182 ParentNode.querySelector (wrap ".everything-except-footer > .container") docPN
184+ ParentNode.querySelector (wrap ".everything-except-footer > main") docPN
186+ ParentNode.querySelector (wrap ".col--aside") docPN
131 case unit of
187 case unit of
132− _ | Just banner <- mbBanner
188+ _ | Just banner <- mbBanner
133− , Just everything <- mbEverything
189+ , Just everything <- mbEverything
134− , Just pageContents <- mbContainer -> do
190+ , Just pageContents <- mbContainer
191+ , Just mainContainer <- mbMainContainer
192+ , Just realSidebar <- mbRealSidebar -> do
135 search <- Document.createElement "div" doc
193 search <- Document.createElement "div" doc
136 void $ Node.appendChild (Element.toNode search) (Element.toNode banner)
194 void $ Node.appendChild (Element.toNode search) (Element.toNode banner)
137− pure $ fromElement search >>= \searchField ->
196+ searchField <- fromElement search
138− fromElement everything >>= \searchResults ->
197+ searchResults <- fromElement everything
198+ sidebarContainer <- fromElement mainContainer
139− pure { searchField, searchResults, pageContents }
199+ pure { searchField, searchResults, pageContents, realSidebar, sidebarContainer }
140 | otherwise -> pure Nothing
200 | otherwise -> pure Nothing