Data

MatchHighlight

Marks where the words of a search appear in a text, in any case, every time they do.

#text#search#no-js

Demo

Preview
  • Deploying a Quillo app to Fly.io
  • Toronto, Ontario
  • No match here

Quillo renders components on the server, then resumes them in the browser from the state the server sent, so a page shows at once and reacts as soon as it is touched.

Get it

It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.

$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/match_highlight.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/match_highlight.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/match_highlight.qwe
let match_highlight_demo_text = "Quillo renders components on the server, then resumes them in the browser from the state the server sent, so a page shows at once and reacts as soon as it is touched."component MatchHighlightDemoLive() {    state q = "server state"    <div.demo-stack>        <SearchInput name="mh-q" label="Find in the text" value={q} on_input={(t) => { q = t }}/>        <p.demo-note.mh-demo-out><MatchHighlight text={match_highlight_demo_text} query={q}/></p>    </div>}view MatchHighlightDemo() =    <div.demo-stack>        <ul.demo-stack.mh-demo-list style="margin: 0; padding-left: 18px">            <li><MatchHighlight text="Deploying a Quillo app to Fly.io" query="quillo deploy"/></li>            <li><MatchHighlight text="Toronto, Ontario" query="to"/></li>            <li><MatchHighlight text="No match here" query="zebra"/></li>        </ul>        <MatchHighlightDemoLive/>    </div>

Source

ui/match_highlight.qwe
// MatchHighlight: a text with the parts that match a search marked, as <mark>, in// any case and wherever they are; each word of the query is looked for on its own.// A view: it needs no script, and components (SearchList) use it as they filter.////   <MatchHighlight text="Deploying a Quillo app to Fly.io" query="quillo deploy"/>//   <p>{for r in results => <MatchHighlight text={r.title} query={q}/>}</p>//// text: what to show. query: what was searched; split into words at spaces, and// each found in every place (so "to" marks both of "Toronto"). An empty query// marks nothing. class: added to the wrapping <span>.// match_highlight_parts(text, query) gives the pieces as [{ text, hit }], to mark// them some other way.let match_highlight_css = css`.ui-mh-mark {  padding: 0 1px; border-radius: 3px; background: color-mix(in srgb, var(--ui-warning) 26%, transparent); color: inherit;}@media (forced-colors: active) { .ui-mh-mark { background: Mark; color: MarkText; } }`// The words of a query in lower case, without repeats: "Rust  web" is ["rust", "web"].fn match_highlight_words(query: str) -> list =    re.split(lower(trim(query)), "\\s+") | filter((w) => w != "") | unique// The text in pieces: [{ text, hit }], hit where a word of the query is.fn match_highlight_parts(text: str, query: str) -> list {    let words = match_highlight_words(query) | map((w) => split(w, ""))    let cs = split(text, "")    let low = split(lower(text), "")    let n = len(cs)    if len(words) == 0 || n == 0 || len(low) != n { return [{ text, hit: false }] }    let parts = []    let run = ""    let run_hit = false    let reach = 0    let i = 0    while i < n {        let k = 0        while k < len(words) {            let w = words[k]            let lw = len(w)            if i + lw > reach && i + lw <= n {                let j = 0                while j < lw && low[i + j] == w[j] { j += 1 }                if j == lw { reach = i + lw }            }            k += 1        }        let hit = i < reach        if hit != run_hit && run != "" {            parts = parts | push({ text: run, hit: run_hit })            run = ""        }        run_hit = hit        run = run + cs[i]        i += 1    }    parts | push({ text: run, hit: run_hit })}view MatchHighlight(text: str, query: str = "", class: str? = null) {    style global match_highlight_css    <span class={class}>{for p in match_highlight_parts(text, query) => p.hit ? <mark.ui-mh-mark>{p.text}</mark> : p.text}</span>}
Thread
76Useful? Like it, or add to its thread below.

Thread 0 posts

On MatchHighlight: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.