Search WiP: Add searchbar component
This commit is contained in:
parent
02c7a48770
commit
f04fd2e591
2
TODO.txt
2
TODO.txt
|
@ -20,3 +20,5 @@
|
||||||
- need to support flags
|
- need to support flags
|
||||||
- need to support mod actions like saging a thread or deleting a post
|
- need to support mod actions like saging a thread or deleting a post
|
||||||
- need to display the current time you are at (or Latest) ✓
|
- need to display the current time you are at (or Latest) ✓
|
||||||
|
- add server sent event (only when in the "present" time wise) and listen
|
||||||
|
for new posts
|
||||||
|
|
|
@ -76,6 +76,7 @@ executable chandlr
|
||||||
Component.Thread.Files
|
Component.Thread.Files
|
||||||
Component.Thread.Intro
|
Component.Thread.Intro
|
||||||
Component.Thread.Model
|
Component.Thread.Model
|
||||||
|
Component.Thread.Embed
|
||||||
Component.BodyRender
|
Component.BodyRender
|
||||||
Routes
|
Routes
|
||||||
Common.AttachmentType
|
Common.AttachmentType
|
||||||
|
@ -84,6 +85,7 @@ executable chandlr
|
||||||
Parsing.EmbedParser
|
Parsing.EmbedParser
|
||||||
Parsing.PostPartType
|
Parsing.PostPartType
|
||||||
Component.TimeControl
|
Component.TimeControl
|
||||||
|
Component.Search
|
||||||
|
|
||||||
|
|
||||||
-- LANGUAGE extensions used by modules in this package.
|
-- LANGUAGE extensions used by modules in this package.
|
||||||
|
|
|
@ -15,5 +15,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input class="time-control" type="range" min=-500 max=0 step=1 value=0>
|
<input class="time-control" type="range" min=-500 max=0 step=1 value=0>
|
||||||
|
<form class="search_form" action="/search" method="GET">
|
||||||
|
<input type="submit" value="🔍">
|
||||||
|
<input type="text" name="search">
|
||||||
|
</form>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<form class="search_form" action="/search" method="GET">
|
||||||
|
<input type="submit" value="🔍">
|
||||||
|
<input type="text" name="search">
|
||||||
|
</form>
|
25
html/tc.css
25
html/tc.css
|
@ -41,3 +41,28 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search_form {
|
||||||
|
display: flex;
|
||||||
|
width: 70%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search_form input[name="search"] {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: .5em;
|
||||||
|
height: 2em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search_form input[type="submit"] {
|
||||||
|
flex-grow: 0;
|
||||||
|
height: 2em;
|
||||||
|
width: 2em;
|
||||||
|
text-align: middle;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
18
index.html
18
index.html
|
@ -10,24 +10,6 @@
|
||||||
<script language="javascript" src="./dist/build/chandlr/chandlr.jsexe/rts.js"></script>
|
<script language="javascript" src="./dist/build/chandlr/chandlr.jsexe/rts.js"></script>
|
||||||
<script language="javascript" src="./dist/build/chandlr/chandlr.jsexe/lib.js"></script>
|
<script language="javascript" src="./dist/build/chandlr/chandlr.jsexe/lib.js"></script>
|
||||||
<script language="javascript" src="./dist/build/chandlr/chandlr.jsexe/out.js"></script>
|
<script language="javascript" src="./dist/build/chandlr/chandlr.jsexe/out.js"></script>
|
||||||
<style>
|
|
||||||
.post.op.multifile,
|
|
||||||
.post.reply.multifile .body {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time-slider {
|
|
||||||
width: 70%;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page_heading * {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -15,6 +15,7 @@ import Network.Http (HttpResult)
|
||||||
import Network.SiteType (Site)
|
import Network.SiteType (Site)
|
||||||
import qualified Component.ThreadView as Thread
|
import qualified Component.ThreadView as Thread
|
||||||
import qualified Component.TimeControl as TC
|
import qualified Component.TimeControl as TC
|
||||||
|
import qualified Component.Search as Search
|
||||||
|
|
||||||
data GetThreadArgs = GetThreadArgs
|
data GetThreadArgs = GetThreadArgs
|
||||||
{ website :: Text
|
{ website :: Text
|
||||||
|
@ -30,6 +31,7 @@ data Action
|
||||||
| forall a. (FromJSON a) => ClientAction (HttpResult a -> Action) (C.Action a)
|
| forall a. (FromJSON a) => ClientAction (HttpResult a -> Action) (C.Action a)
|
||||||
| ThreadAction Thread.Action
|
| ThreadAction Thread.Action
|
||||||
| TimeAction TC.Time
|
| TimeAction TC.Time
|
||||||
|
| SearchAction Search.Action
|
||||||
| GoToTime UTCTime
|
| GoToTime UTCTime
|
||||||
| ChangeURI URI
|
| ChangeURI URI
|
||||||
| NoAction
|
| NoAction
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
module Component.Search
|
||||||
|
( view
|
||||||
|
, Interface (..)
|
||||||
|
, update
|
||||||
|
, Model (..)
|
||||||
|
, Action (..)
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Miso
|
||||||
|
( View
|
||||||
|
, class_
|
||||||
|
, action_
|
||||||
|
, method_
|
||||||
|
, input_
|
||||||
|
, type_
|
||||||
|
, value_
|
||||||
|
, name_
|
||||||
|
, form_
|
||||||
|
, onChange
|
||||||
|
, onSubmit
|
||||||
|
, Effect
|
||||||
|
, (<#)
|
||||||
|
, consoleLog
|
||||||
|
, noEff
|
||||||
|
)
|
||||||
|
import GHCJS.DOM.Types (JSString)
|
||||||
|
|
||||||
|
data Action = SearchChange JSString | OnSubmit | NoAction
|
||||||
|
|
||||||
|
data Model = Model
|
||||||
|
{ search_term :: JSString
|
||||||
|
} deriving Eq
|
||||||
|
|
||||||
|
data Interface a = Interface
|
||||||
|
{ passAction :: Action -> a
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update :: Interface a -> Action -> Model -> Effect a Model
|
||||||
|
update iface (SearchChange q) model = model { search_term = q } <# do
|
||||||
|
consoleLog q
|
||||||
|
return $ (passAction iface) NoAction
|
||||||
|
|
||||||
|
update iface OnSubmit model = model <# do
|
||||||
|
consoleLog $ "Submit!" <> search_term model
|
||||||
|
return $ (passAction iface) NoAction
|
||||||
|
|
||||||
|
update _ NoAction m = noEff m
|
||||||
|
|
||||||
|
view :: Interface a -> View a
|
||||||
|
view iface = form_
|
||||||
|
[ class_ "search_form"
|
||||||
|
, action_ "/search"
|
||||||
|
, method_ "GET"
|
||||||
|
, onSubmit $ pass OnSubmit
|
||||||
|
]
|
||||||
|
[ input_
|
||||||
|
[ type_ "submit"
|
||||||
|
, value_ "🔍"
|
||||||
|
]
|
||||||
|
, input_
|
||||||
|
[ type_ "text"
|
||||||
|
, name_ "search"
|
||||||
|
, onChange $ pass . SearchChange
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
where
|
||||||
|
pass = passAction iface
|
|
@ -184,7 +184,7 @@ reply m backlinks (post, parts) = div_
|
||||||
files_or_embed_view :: View a
|
files_or_embed_view :: View a
|
||||||
files_or_embed_view =
|
files_or_embed_view =
|
||||||
case (Post.embed post) of
|
case (Post.embed post) of
|
||||||
Just txt -> embed post
|
Just _ -> embed post
|
||||||
Nothing -> files (media_root m) site_ post
|
Nothing -> files (media_root m) site_ post
|
||||||
|
|
||||||
site_ :: Site
|
site_ :: Site
|
||||||
|
|
11
src/Main.hs
11
src/Main.hs
|
@ -50,6 +50,7 @@ import qualified Network.CatalogPostType as CatalogPost
|
||||||
import qualified Component.CatalogGrid as Grid
|
import qualified Component.CatalogGrid as Grid
|
||||||
import qualified Component.ThreadView as Thread
|
import qualified Component.ThreadView as Thread
|
||||||
import qualified Component.TimeControl as TC
|
import qualified Component.TimeControl as TC
|
||||||
|
import qualified Component.Search as Search
|
||||||
|
|
||||||
|
|
||||||
data Model = Model
|
data Model = Model
|
||||||
|
@ -60,6 +61,7 @@ data Model = Model
|
||||||
, media_root_ :: JSString
|
, media_root_ :: JSString
|
||||||
, current_time :: UTCTime
|
, current_time :: UTCTime
|
||||||
, tc_model :: TC.Model
|
, tc_model :: TC.Model
|
||||||
|
, search_model :: Search.Model
|
||||||
} deriving Eq
|
} deriving Eq
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,6 +97,7 @@ initialModel pgroot client_fetch_count media_root u t = Model
|
||||||
, media_root_ = media_root
|
, media_root_ = media_root
|
||||||
, current_time = t
|
, current_time = t
|
||||||
, tc_model = TC.initialModel 0
|
, tc_model = TC.initialModel 0
|
||||||
|
, search_model = Search.Model { Search.search_term = "" }
|
||||||
}
|
}
|
||||||
|
|
||||||
getMetadata :: String -> IO (Maybe JSString)
|
getMetadata :: String -> IO (Maybe JSString)
|
||||||
|
@ -164,6 +167,7 @@ mainView model = view
|
||||||
, time_ [] [ text $ pack $ show $ current_time model ]
|
, time_ [] [ text $ pack $ show $ current_time model ]
|
||||||
]
|
]
|
||||||
, TC.view iTime (tc_model m)
|
, TC.view iTime (tc_model m)
|
||||||
|
, Search.view iSearch
|
||||||
, Grid.view iGrid (grid_model model)
|
, Grid.view iGrid (grid_model model)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -247,6 +251,10 @@ mainUpdate (TimeAction ta) m =
|
||||||
TC.update iTime ta (tc_model m)
|
TC.update iTime ta (tc_model m)
|
||||||
>>= \tm -> noEff m { tc_model = tm }
|
>>= \tm -> noEff m { tc_model = tm }
|
||||||
|
|
||||||
|
mainUpdate (SearchAction sa) m =
|
||||||
|
Search.update iSearch sa (search_model m)
|
||||||
|
>>= \sm -> noEff m { search_model = sm }
|
||||||
|
|
||||||
iGrid :: Grid.Interface Action
|
iGrid :: Grid.Interface Action
|
||||||
iGrid = Grid.Interface
|
iGrid = Grid.Interface
|
||||||
{ Grid.passAction = GridAction
|
{ Grid.passAction = GridAction
|
||||||
|
@ -275,3 +283,6 @@ iTime = TC.Interface
|
||||||
{ TC.passAction = TimeAction
|
{ TC.passAction = TimeAction
|
||||||
, TC.goTo = GoToTime
|
, TC.goTo = GoToTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iSearch :: Search.Interface Action
|
||||||
|
iSearch = Search.Interface { passAction = SearchAction }
|
||||||
|
|
|
@ -294,8 +294,7 @@ input[type="text"],input[type="password"],textarea {
|
||||||
word-spacing: normal;
|
word-spacing: normal;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
|
padding:0px;
|
||||||
padding:0px!important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2015,3 +2014,49 @@ span.orangeQuote {
|
||||||
.options_general_tab--select_opt select {
|
.options_general_tab--select_opt select {
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deviations from original stylesheet specific to chandlr-miso
|
||||||
|
*/
|
||||||
|
|
||||||
|
.post.op.multifile,
|
||||||
|
.post.reply.multifile .body {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-slider {
|
||||||
|
width: 70%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page_heading * {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search_form {
|
||||||
|
display: flex;
|
||||||
|
width: 70%;
|
||||||
|
margin: 1em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search_form input[name="search"] {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: .5em;
|
||||||
|
height: 2em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.25em;
|
||||||
|
padding: 0 .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search_form input[type="submit"] {
|
||||||
|
flex-grow: 0;
|
||||||
|
height: 2em;
|
||||||
|
width: 2em;
|
||||||
|
text-align: middle;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue