forked from cadence/breezewiki
Compare commits
No commits in common. "e709b3cea55dbb485163a8034a943e92f2ef3826" and "71705d6e7486f7cfce4e58a821d3e87372ec9e34" have entirely different histories.
e709b3cea5
...
71705d6e74
6 changed files with 4 additions and 190 deletions
|
@ -1,6 +1,5 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
(require racket/string
|
(require racket/string
|
||||||
json
|
|
||||||
(prefix-in easy: net/http-easy)
|
(prefix-in easy: net/http-easy)
|
||||||
html-writing
|
html-writing
|
||||||
web-server/http
|
web-server/http
|
||||||
|
@ -95,13 +94,7 @@
|
||||||
,@(map (λ (url)
|
,@(map (λ (url)
|
||||||
`(link (@ (rel "stylesheet") (type "text/css") (href ,url))))
|
`(link (@ (rel "stylesheet") (type "text/css") (href ,url))))
|
||||||
(required-styles (format "https://~a.fandom.com" wikiname)))
|
(required-styles (format "https://~a.fandom.com" wikiname)))
|
||||||
(link (@ (rel "stylesheet") (type "text/css") (href "/static/main.css")))
|
(link (@ (rel "stylesheet") (type "text/css") (href "/static/main.css"))))
|
||||||
(script "const BWData = "
|
|
||||||
,(jsexpr->string (hasheq 'wikiname wikiname
|
|
||||||
'strict_proxy (config-true? 'strict_proxy))))
|
|
||||||
,(if (config-true? 'feature_search_suggestions)
|
|
||||||
'(script (@ (type "module") (src "/static/search-suggestions.js")))
|
|
||||||
""))
|
|
||||||
(body (@ (class ,body-class))
|
(body (@ (class ,body-class))
|
||||||
(div (@ (class "main-container"))
|
(div (@ (class "main-container"))
|
||||||
(div (@ (class "fandom-community-header__background tileHorizontally header")))
|
(div (@ (class "fandom-community-header__background tileHorizontally header")))
|
||||||
|
@ -110,12 +103,9 @@
|
||||||
(div (@ (class "custom-top"))
|
(div (@ (class "custom-top"))
|
||||||
(h1 (@ (class "page-title")) ,title)
|
(h1 (@ (class "page-title")) ,title)
|
||||||
(nav (@ (class "sitesearch"))
|
(nav (@ (class "sitesearch"))
|
||||||
(form (@ (action ,(format "/~a/search" wikiname))
|
(form (@ (action ,(format "/~a/search" wikiname)))
|
||||||
(class "bw-search-form")
|
(label "Search "
|
||||||
(id "bw-pr-search"))
|
(input (@ (type "text") (name "q")))))))
|
||||||
(label (@ (for "bw-search-input")) "Search ")
|
|
||||||
(input (@ (type "text") (name "q") (id "bw-search-input") (autocomplete "off")))
|
|
||||||
(div (@ (class "bw-ss__container"))))))
|
|
||||||
(div (@ (id "content") #;(class "page-content"))
|
(div (@ (id "content") #;(class "page-content"))
|
||||||
(div (@ (id "mw-content-text"))
|
(div (@ (id "mw-content-text"))
|
||||||
,content))
|
,content))
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
'((application_name . "BreezeWiki")
|
'((application_name . "BreezeWiki")
|
||||||
(canonical_origin . "")
|
(canonical_origin . "")
|
||||||
(debug . "false")
|
(debug . "false")
|
||||||
(feature_search_suggestions . "true")
|
|
||||||
(instance_is_official . "false") ; please don't turn this on, or you will make me very upset
|
(instance_is_official . "false") ; please don't turn this on, or you will make me very upset
|
||||||
(log_outgoing . "true")
|
(log_outgoing . "true")
|
||||||
(port . "10416")
|
(port . "10416")
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
(define hash-ext-mime-type
|
(define hash-ext-mime-type
|
||||||
(hash #".css" #"text/css"
|
(hash #".css" #"text/css"
|
||||||
#".js" #"text/javascript"
|
|
||||||
#".png" #"image/png"
|
#".png" #"image/png"
|
||||||
#".svg" #"image/svg+xml"
|
#".svg" #"image/svg+xml"
|
||||||
#".txt" #"text/plain"))
|
#".txt" #"text/plain"))
|
||||||
|
|
|
@ -225,66 +225,6 @@ figcaption, .lightbox-caption, .thumbcaption {
|
||||||
margin-left: 1.2em;
|
margin-left: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (breezewiki) search suggestions */
|
|
||||||
.bw-search-form {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto 1fr;
|
|
||||||
grid-gap: 0px 5px;
|
|
||||||
}
|
|
||||||
.bw-ss__container {
|
|
||||||
grid-column: 2;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.bw-ss__list {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
background: white;
|
|
||||||
color: black;
|
|
||||||
border: solid #808080;
|
|
||||||
border-width: 0px 1px 1px;
|
|
||||||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 99;
|
|
||||||
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.bw-ss__list--focus {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.bw-ss__list--loading {
|
|
||||||
background: #c0c0c0;
|
|
||||||
}
|
|
||||||
.bw-ss__input--accepted {
|
|
||||||
background: #fffbc0;
|
|
||||||
}
|
|
||||||
.bw-ss__preview {
|
|
||||||
padding: 0px 2px;
|
|
||||||
font-style: italic;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
.bw-ss__item {
|
|
||||||
display: grid; /* make buttons take the full size */
|
|
||||||
}
|
|
||||||
.bw-ss__item:hover {
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
.bw-ss__button {
|
|
||||||
appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
line-height: inherit;
|
|
||||||
background: none;
|
|
||||||
font: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0px 2px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* media queries */
|
/* media queries */
|
||||||
|
|
||||||
/* for reference, cell phone screens are generally 400 px wide, definitely less than 500 px */
|
/* for reference, cell phone screens are generally 400 px wide, definitely less than 500 px */
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,93 +0,0 @@
|
||||||
import {h, htm, render, useState, useEffect, createContext, useContext} from "./preact.js"
|
|
||||||
const html = htm.bind(h)
|
|
||||||
const classNames = classArr => classArr.filter(el => el).join(" ")
|
|
||||||
|
|
||||||
const form = document.getElementById("bw-pr-search")
|
|
||||||
|
|
||||||
const AcceptSuggestion = createContext(null)
|
|
||||||
const hitsPromise = new Map()
|
|
||||||
const hitsDone = new Set()
|
|
||||||
|
|
||||||
function Suggestion(props) {
|
|
||||||
const acceptSuggestion = useContext(AcceptSuggestion)
|
|
||||||
return html`<li class="bw-ss__item"><button type="button" class="bw-ss__button" onClick=${() => acceptSuggestion(props)}>${props.title}</button></li>`
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchSuggestions(query, setSuggestions) {
|
|
||||||
if (query === "") query = "\0"
|
|
||||||
if (hitsPromise.has(query)) return hitsPromise.get(query)
|
|
||||||
const url = new URL(`https://${BWData.wikiname}.fandom.com/api.php`)
|
|
||||||
url.searchParams.set("action", "opensearch")
|
|
||||||
url.searchParams.set("format", "json")
|
|
||||||
url.searchParams.set("namespace", "0") // wiki namespace, 0 is default
|
|
||||||
url.searchParams.set("origin", "*") // mediawiki api cors
|
|
||||||
url.searchParams.set("search", query)
|
|
||||||
const sendUrl = BWData.strict_proxy
|
|
||||||
? "/proxy?" + new URLSearchParams({dest: url})
|
|
||||||
: url
|
|
||||||
const promise = fetch(sendUrl).then(res => res.json()).then(root => {
|
|
||||||
hitsDone.add(query)
|
|
||||||
return Array(root[1].length).fill().map((_, i) => ({
|
|
||||||
title: root[1][i],
|
|
||||||
url: root[3][i]
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
hitsPromise.set(query, promise)
|
|
||||||
return promise
|
|
||||||
}
|
|
||||||
|
|
||||||
function SuggestionList(props) {
|
|
||||||
return html`
|
|
||||||
<div class="bw-ss__container">
|
|
||||||
<ul class=${classNames(["bw-ss__list", props.focus && "bw-ss__list--focus", `bw-ss__list--${props.st}`])}>
|
|
||||||
${props.hits.map(hit => html`<${Suggestion} ...${hit} />`)}
|
|
||||||
</ul>
|
|
||||||
</div>`
|
|
||||||
}
|
|
||||||
|
|
||||||
function ControlledInput() {
|
|
||||||
const [query, setQuery] = useState("")
|
|
||||||
const [focus, setFocus] = useState(false)
|
|
||||||
const [st, setSt] = useState("ready")
|
|
||||||
const [suggestions, setSuggestions] = useState([])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (st === "accepted") return
|
|
||||||
setSt("loading")
|
|
||||||
fetchSuggestions(query).then(s => {
|
|
||||||
setSuggestions(s)
|
|
||||||
if (hitsDone.size === hitsPromise.size) {
|
|
||||||
setSt("ready")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, [query])
|
|
||||||
|
|
||||||
function acceptSuggestion(suggestion) {
|
|
||||||
setQuery(suggestion.title)
|
|
||||||
setSt("accepted")
|
|
||||||
const dest = new URL(suggestion.url).pathname.match("/wiki/.*")
|
|
||||||
location = `/${BWData.wikiname}${dest}`
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
function listener(event) {
|
|
||||||
if (event.type === "focusin") setFocus(true)
|
|
||||||
else setFocus(false)
|
|
||||||
}
|
|
||||||
form.addEventListener("focusin", listener)
|
|
||||||
form.addEventListener("focusout", listener)
|
|
||||||
return () => {
|
|
||||||
form.removeEventListener("focusin", listener)
|
|
||||||
form.removeEventListener("focusout", listener)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<${AcceptSuggestion.Provider} value=${acceptSuggestion}>
|
|
||||||
<label for="bw-search-input">Search </label>
|
|
||||||
<input type="text" name="q" id="bw-search-input" autocomplete="off" onInput=${e => setQuery(e.target.value)} value=${query} class=${classNames(["bw-ss__input", `bw-ss__input--${st}`])} />
|
|
||||||
<${SuggestionList} hits=${suggestions} focus=${focus} st=${st}/>
|
|
||||||
</${AcceptSuggestion.Provider}`
|
|
||||||
}
|
|
||||||
|
|
||||||
render(html`<${ControlledInput} />`, form)
|
|
Loading…
Reference in a new issue