summaryrefslogtreecommitdiff
path: root/desk/web/search/search.hoon
diff options
context:
space:
mode:
Diffstat (limited to 'desk/web/search/search.hoon')
-rw-r--r--desk/web/search/search.hoon441
1 files changed, 441 insertions, 0 deletions
diff --git a/desk/web/search/search.hoon b/desk/web/search/search.hoon
new file mode 100644
index 0000000..1cf58d0
--- /dev/null
+++ b/desk/web/search/search.hoon
@@ -0,0 +1,441 @@
+/- boke, tp=trill-post, tlonc=tlon-channels, cnt=contact
+/+ plib=trill-utils, ui=trill-ui, sr=sortug, lib=boke, const=constants, kaji, wall
+/= post-text /web/components/post-text
+/= date-div /web/components/date
+/= user /web/components/user
+/= chat-manx /web/chat/chat
+|_ [s=state:boke =bowl:gall]
++* wal ~(. wall src.bowl)
+++ css ^~ %- trip
+'''
+#query-string{
+ font-weight: 700;
+ font-size: 1.3rem;
+}
+#search{
+
+ & .form{
+
+ & .row{
+ padding: 0.5rem;
+ border-bottom: 1px solid var(--text-color);
+ align-items: center;
+
+ & input{
+ line-height: 2rem;
+ flex-grow:1;
+ }
+ & h2{
+ margin: 0 1rem 0 0;
+ color: var(--text-color);
+ }
+}
+
+#filters{
+ display: flex;
+ justify-content: space-between;
+ padding-top: 0.5rem;
+
+ & select{
+ background-color: var(--background-color);
+ height: 2rem;
+ }
+}
+
+}
+ & fieldset{
+ display: block;
+}
+ & section{
+ margin: 2rem 0;
+
+ & h3 {
+ font-size: 1.6rem;
+ }
+ }
+ & .res{
+ border-bottom: 1px solid var(--text-color);
+ padding: 0.5rem;
+ & .name{
+ font-weight: 600;
+ }
+ & .snip{
+ padding: 0 1rem;
+ }
+
+ /* comments */
+ & .comment-meta{
+ display: flex;
+ flex-wrap: wrap;
+ font-size: 0.9rem;
+
+ & a{
+ font-size: 0.9rem;
+ }
+
+ & .sep{
+ margin: 0 0.3rem;
+ }
+ }
+
+ & a {
+ font-size: 1.3rem;
+ }
+ & .tag{
+ margin: 0 0.3rem;
+ padding: 0.1rem;
+ background-color: var(--huang);
+ opacity: 0.9;
+ font-size: 0.7rem;
+ cursor: pointer;
+ }
+ }
+ & .not-found{
+ margin-top: 4rem;
+ }
+& .highlight{
+ background-color: var(--huang);
+ }
+& button{
+ display: block;
+ margin: 1rem auto;
+ }
+& .spinner{
+ width: 50px;
+ height: 50px;
+ margin: 1rem auto;
+ }
+& #spinner-zh{
+ width: 100px;
+ height: 100px;
+}
+& .tabs {
+ box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
+ border-radius: 5px;
+ overflow: hidden;
+
+ & .tab {
+ background-color: #f1f1f1;
+ float: left;
+ border: none;
+ outline: none;
+ cursor: pointer;
+ padding: 14px 16px;
+ transition: 0.3s;
+ }
+
+ & .tab:hover {
+ background-color: #ddd;
+ }
+ /* Style for active tab */
+ & .tab.active {
+ background-color: #ccc;
+ }
+ }
+}
+@media (min-width: 800px){
+ #search{
+ width: 70%;
+ margin: auto;
+ }
+}
+'''
+++ script ^~ %- trip
+'''
+function highlight(){
+ const params = new URLSearchParams(new URL(window.location.href).search);
+ const query = params.get('query');
+ const div = document.getElementById("search");
+ const snips = div.querySelectorAll(".snip");
+ const titles = div.querySelectorAll(".title");
+ [...titles, ...snips].forEach(el => {
+ const h = el.innerHTML;
+ const r = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
+ const h2 = h.replace(r, `<span class="highlight">$1</span>`)
+ el.innerHTML = h2
+ });
+}
+document.addEventListener("kaji-scry", (e) => highlight());
+addEventListener('DOMContentLoaded', async () => highlight());
+addEventListener('kaji-scry', async () => highlight());
+'''
++$ section $?(%blog %comments %chat %threads %replies)
+++ cursor
+|= [=pars d=(unit time) up=?] ^- marl
+ ?~ d ~
+ =/ cursor-string (scow:parsing:sr %uw `@uw`u.d)
+ =/ name ?: up "before" "after"
+ =/ label ?: up "Newer Posts" "Older Posts"
+ =/ indicator ?: up "#spinner-up" "#spinner-down"
+ =/ button=manx
+ ;button
+ =kaji "iscroll"
+ =name name
+ =value cursor-string
+ =path "/search/f"
+ =cont "#search-results"
+ =indicator indicator
+ ; {label}
+ ==
+ =/ upc
+ ;div
+ ;+ button
+ ;img#spinner-up.spinner@"spinner.svg"(style "display: none;");
+ ==
+ =/ downc
+ ;div
+ ;img#spinner-down.spinner@"spinner.svg"(style "display: none;");
+ ;+ button
+ ==
+ ;+ ?: up upc downc
+
+++ blog-result
+|= [fn=full-node:tp snip=@t] ^- manx
+ =/ ttags (tags:wal ~(tap in tags.p.fn))
+ ;div.res
+ ;header.f1
+ ;div
+ ;a.title/"{(trip (spat (title-to-path:lib title.p.fn id.p.fn)))}":"{(trip title.p.fn)}"
+ ;div
+ ;* %+ turn ttags |= t=@t ;a.tag/"/blog?t={(trip t)}": {(trip t)}
+ ==
+ ==
+ ;div.post-date
+ ;* (date-div id.p.fn .y)
+ ==
+ ==
+ ;div.snip
+ ;p:"{(trip snip)}"
+ ==
+ ==
+++ comment-result
+|= [fn=full-node:tp snip=@t contacts=whoms:cnt] ^- manx
+ =/ thread (get:gorm:tp feed.s thread.p.fn)
+ ?~ thread ;span;
+ =/ thread-link=tape (trip (spat (title-to-path:lib title.u.thread id.u.thread))) :: TODO check for relative/absolute path
+ =/ thread-link=tape (find-board-path:lib paths.s u.thread)
+ =/ uid (enc:kaji [author.p.fn id.p.fn])
+ =/ permalink=tape %+ weld thread-link "/{uid}"
+ =/ time-string=tape (post-date-ago:lib id.p.fn now.bowl %yau)
+ =/ usr (user author.p.fn contacts 32)
+;div.res
+ =id "comment-{uid}"
+ ;div.comment-meta
+ ;a/"/u/{(scow %p author.p.fn)}"
+ ;+ name.usr
+ ==
+ ;span.sep:"|"
+ ;a/"{permalink}":"{time-string} ago"
+ ;span.sep:"|"
+ ;a/"{thread-link}":"On: {(trip title.u.thread)}"
+ ==
+ ;div.snip
+ ;p:"{(trip snip)}"
+ ==
+==
+++ thread-result
+|= [fn=full-node:tp snip=@t contacts=whoms:cnt] ^- manx
+ =/ thread-link=tape (find-board-path:lib paths.s p.fn)
+ =/ time-string=tape (post-date-ago:lib id.p.fn now.bowl %yau)
+ =/ usr (user author.p.fn contacts 32)
+ =/ ttags (tags:wal ~(tap in tags.p.fn))
+;div.res
+ ;header.f1
+ ;div
+ ;a.title/"/board/p/{thread-link}":"{(trip title.p.fn)}"
+ ;div
+ ;* %+ turn ttags |= t=@t ;a.tag/"/board?t={(trip t)}": {(trip t)}
+ ==
+ ==
+ ;div.post-date:"{time-string} ago"
+ ==
+ ;+ name.usr
+ ;div.snip
+ ;p:"{(trip snip)}"
+ ==
+==
+++ reply-result
+|= [fn=full-node:tp snip=@t contacts=whoms:cnt] ^- manx
+ =/ thread (get:gorm:tp feed.s thread.p.fn)
+ ?~ thread ;span;
+ =/ thread-link=tape (find-board-path:lib paths.s u.thread)
+ =/ uid (enc:kaji [author.p.fn id.p.fn])
+ =/ permalink=tape %+ weld thread-link "/{uid}"
+ =/ time-string=tape (post-date-ago:lib id.p.fn now.bowl %yau)
+ =/ ttags (tags:wal ~(tap in tags.p.fn))
+ =/ usr (user author.p.fn contacts 32)
+;div.res
+ ;header.f1
+ ;div
+ ;a/"/board/p/{permalink}":"{(trip title.p.fn)}"
+ ;div
+ ;* %+ turn ttags |= t=@t ;a.tag/"/board?t={(trip t)}": {(trip t)}
+ ==
+ ==
+ ;div.post-date:"{time-string} ago"
+ ==
+ ;+ name.usr
+ ;div.snip
+ ;p:"{(trip snip)}"
+ ==
+==
+::
+++ chat-result
+|= [r=reference:tlonc =whoms:cnt] ^- manx
+=/ chat-core ~(. chat-manx [whoms bowl])
+?- -.r
+%post (post-div:chat-core +<.post.r)
+%reply (post-div:chat-core +.reply.r)
+==
+++ make-params
+|= [query=@t res=page-req:tp]
+:: =/ newer ?~ newer.res "" "&before={(scow %uw `@uw`u.newer.res)}"
+:: =/ older ?~ older.res "" "&after={(scow %uw `@uw`u.older.res)}"
+:: =/ count ?: .=(count.res page-size:lib) "" "&count={(scow %ud count.res)}"
+:: %- en-urlt:html
+:: "?query={(trip query)}{newer}{older}{count}"
+"?query={(trip query)}"
+++ form
+|= =pars
+^- manx
+ ;form.form
+ =swap "swap"
+ =targ "#search-results"
+ =path "/search/f"
+ =show-params "show"
+ =indicator "#spinner-zh"
+
+ ;div.flex.row
+ ;a/"/search"
+ ;h2:"Search"
+ ==
+ ;input(type "text", name "query", value (trip query.pars))
+ =placeholder "Search all Bloody Shovel Content"
+ =kaji "search"
+ =bounce "1000"
+ ;
+ ==
+ :: ;fieldset
+ :: ;label
+ :: ; Tags
+ :: ;input(type "text", name "tags");
+ :: ==
+ :: ==
+ ==
+ ;div#filters.row
+ ;label
+ ; Section
+ ;select
+ =name "section"
+ =kaji "scry"
+ =path "/search/f"
+ ;* %+ turn ~["blog" "comments" "threads" "replies" "chat"] |= t=tape
+ ?: .=(section.pars (crip t))
+ ;option
+ =value t
+ =selected ""
+ ; {t}
+ ==
+ ;option
+ =value t
+ ; {t}
+ ==
+ ==
+ ==
+ ;label
+ ; Date
+ ;select
+ =name "interval"
+ =kaji "scry"
+ =path "/search/f"
+ ;option
+ =value "all"
+ ; All time
+ ==
+ ;option
+ =value "day"
+ :: =selected ""
+ ; Past 24h
+ ==
+ ;option
+ =value "week"
+ ; Last week
+ ==
+ ;option
+ =value "month"
+ ; Last month
+ ==
+ ;option
+ =value "year"
+ ; Last year
+ ==
+ ==
+ ==
+ ==
+ ==
++$ pars [=section query=@t tags=(list @t) req=page-req:tp]
+++ chat-cursor
+|= [query=@t p=chat-page:boke] ^- marl
+~
+++ chatp
+|= [query=@t r=page-req:tp p=chat-page:boke] ^- marl
+?~ p.p
+ ;+ ;p.xc:"No results for {(trip query)} on Bloody Shovel Chats"
+=/ contacts (get-contacts:cnt bowl)
+ %+ welp
+ ;* %+ turn p.p |= ref=reference:tlonc
+ (chat-result ref contacts)
+ ;* (chat-cursor query p)
+
+++ tp-page
+|= [=pars p=search-page:boke] ^- marl
+?~ res.p ~
+ :: ;+ ;p:"No results for {(trip query.pars)} under section {(trip section.pars)}"
+=/ contacts (get-contacts:cnt bowl)
+?- section.pars
+ %blog %+ welp
+ ;* %+ turn res.p |= [fn=full-node:tp snip=@t]
+ (blog-result fn snip)
+ ;* (cursor pars older.p .n)
+ %comments %+ welp
+ ;* %+ turn res.p |= [fn=full-node:tp snip=@t]
+ (comment-result fn snip contacts)
+ ;* (cursor pars older.p .n)
+ %threads %+ welp
+ ;* %+ turn res.p |= [fn=full-node:tp snip=@t]
+ (thread-result fn snip contacts)
+ ;* (cursor pars older.p .n)
+
+ %replies %+ welp
+ ;* %+ turn res.p |= [fn=full-node:tp snip=@t]
+ (reply-result fn snip contacts)
+ ;* (cursor pars older.p .n)
+ %chat ~
+==
+
+++ init ^- manx
+;div#search.fsy
+ ;style: {css}
+ ;+ (form [%blog '' ~ [~ ~ search-page-size:const]])
+ ;img#spinner-zh.gc@"spinner.svg"(style "display: none;");
+ ;div#search-results;
+ ;script: {script}
+==
+++ page
+|= [=pars res=search-res:boke] ^- manx
+;div#search.fsy
+ ;style: {css}
+ ;img#spinner-zh.gc@"spinner.svg"(style "display: none;");
+ ;+ (form pars)
+ ;* ?: .=(query.pars '') ;+ ;p:"Not found" ~
+ ;+ (results pars res)
+ ;script: {script}
+==
+++ results
+|= [=pars res=search-res:boke] ^- manx
+ ;div#search-results
+ ;* ?: ?=(%chat -.res)
+ (chatp query.pars req.pars +.res)
+ (tp-page pars +.res)
+ ==
+--