diff options
Diffstat (limited to 'pages/search.tsx')
-rw-r--r-- | pages/search.tsx | 165 |
1 files changed, 86 insertions, 79 deletions
diff --git a/pages/search.tsx b/pages/search.tsx index c9b27a5..8eff8d8 100644 --- a/pages/search.tsx +++ b/pages/search.tsx @@ -1,65 +1,69 @@ -import { useState, useEffect } from 'react'; import Fuse from 'fuse.js'; +import { useEffect, useState } from 'react'; import Navbar from '../components/navbar'; -import Tags from '../components/tag' +import Tags from '../components/tag'; import SearchOutlinedIcon from '@material-ui/icons/SearchOutlined'; -function SearchBar(props: { searchFunction: () => void }) { - return <div className="searchBar"> +function SearchBar(props: { searchFunction: () => void; }) { + return <div className='searchBar'> <input - className="input" - id="searchInput" - placeholder="Search for posts..." - onChange={() => props.searchFunction()} - spellCheck="false" - autoComplete="off"/> - <button className="button" onClick={() => props.searchFunction()}><SearchOutlinedIcon/></button> - </div> + className='input' + id='searchInput' + placeholder='Search for posts...' + onChange={() => props.searchFunction()} + spellCheck='false' + autoComplete='off' + /> + <button className='button' onClick={() => props.searchFunction()}> + <SearchOutlinedIcon /> + </button> + </div>; } interface Post { - title: string - subtitle: string - author: string - date: string - urlname: string - tags: Array<string> + title: string; + subtitle: string; + author: string; + date: string; + urlname: string; + tags: Array<string>; } interface PostsInfo { - valid_tags: Array<string> - posts: Array<Post> + valid_tags: Array<string>; + posts: Array<Post>; } -function Post(props: { post: Post }) { - return <a className="post" href={"/post/" + props.post.urlname}> - <b className="title">{props.post.title}</b> - {props.post.subtitle && <p className="subtitle">{props.post.subtitle}</p>} - <p className="authordate">Written by {props.post.author} on {new Date(props.post.date).toLocaleString("en-us", { - month: "long", day: "numeric" - })}</p> - <Tags tags={props.post.tags}/> +function Post(props: { post: Post; }) { + return <a className='post' href={'/post/' + props.post.urlname}> + <b className='title'>{props.post.title}</b> + {props.post.subtitle && <p className='subtitle'>{props.post.subtitle}</p>} + <p className='authordate'> + Written by {props.post.author} on {new Date(props.post.date).toLocaleString('en-us', { + month: 'long', + day: 'numeric', + })} + </p> + <Tags tags={props.post.tags} /> </a>; } -function Posts(props: { posts: Array<Post> }) { - return <div className="searchResults"> - { - props.posts.map(post => <Post post={post} key={Math.random().toString()}/>) - } +function Posts(props: { posts: Array<Post>; }) { + return <div className='searchResults'> + {props.posts.map(post => <Post post={post} key={Math.random().toString()} />)} </div>; } function searchFilter(query: string, tags: Array<string>) { var output = { - query: "", - tags: [] - } + query: '', + tags: [], + }; // remove string literals from tag matching - var queryWithoutLiterals = query.replace(/\".+?\"/g, ""); + var queryWithoutLiterals = query.replace(/\".+?\"/g, ''); // find tags and remove them from the query tags.forEach(tag => { @@ -67,55 +71,56 @@ function searchFilter(query: string, tags: Array<string>) { if (index == -1) return; // remove tag from query - queryWithoutLiterals = - queryWithoutLiterals.substr(0, index) + - queryWithoutLiterals.substr(index + tag.length); + queryWithoutLiterals = queryWithoutLiterals.substr(0, index) + + queryWithoutLiterals.substr(index + tag.length); output.tags.push(tag); }); // add back in the string literals (janky just gets pasted on end) - output.query = - queryWithoutLiterals + " " + - (query.match(/\".+?\"/g) + output.query = queryWithoutLiterals + ' ' + + (query.match(/\".+?\"/g) ?.map(r => r.substr(1, r.length - 2)) - .join(" ") || ""); + .join(' ') || ''); return output; } export default function SearchPage() { var [posts, setPosts] = useState<PostsInfo>({ posts: [], valid_tags: [] }); - var [query, setQuery] = useState("-"); + var [query, setQuery] = useState('-'); var [visiblePosts, setVisiblePosts] = useState<Array<Post>>([]); var fuse = new Fuse(posts.posts, { keys: [ - "title", - "subtitle", - "author", - "date", - "urlname", - "tags" + 'title', + 'subtitle', + 'author', + 'date', + 'urlname', + 'tags', ], - isCaseSensitive: false - }) + isCaseSensitive: false, + }); - useEffect(() => {(async () => { - var query = new URLSearchParams(window.location.search).get("q") || ""; - if(query) - (document.getElementById("searchInput") as HTMLInputElement).value = query; + useEffect(() => { + (async () => { + var query = new URLSearchParams(window.location.search).get('q') || ''; + if (query) { + (document.getElementById('searchInput') as HTMLInputElement).value = query; + } - var posts = await fetch("/posts.json"); - var postsJson: PostsInfo = await posts.json(); - postsJson.posts = postsJson.posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) - setPosts(postsJson); - setQuery(query); - })()}, []); + var posts = await fetch('/posts.json'); + var postsJson: PostsInfo = await posts.json(); + postsJson.posts = postsJson.posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); + setPosts(postsJson); + setQuery(query); + })(); + }, []); useEffect(() => { var search = searchFilter(query, posts.valid_tags); - if(search.query.length == 0) { + if (search.query.length == 0) { var results = posts.posts; } else { var fuseSearch = fuse.search(search.query); @@ -123,32 +128,34 @@ export default function SearchPage() { } results = results.filter(result => { - for(var i in search.tags) { - if (!result.tags.includes(search.tags[i])) + for (var i in search.tags) { + if (!result.tags.includes(search.tags[i])) { return false; + } } return true; }); - setVisiblePosts(results) + setVisiblePosts(results); }, [query]); return <div> - <div className="centeredPage"> - <div className="titleWrapper"> + <div className='centeredPage'> + <div className='titleWrapper'> <h1>Search for posts</h1> </div> - <div className="navAreaWrapper"> - <div className="sticky"> - <Navbar page="search"/> + <div className='navAreaWrapper'> + <div className='sticky'> + <Navbar page='search' /> </div> </div> - <div className="contentWrapper"> - <SearchBar searchFunction={() => { - setTimeout(() => setQuery((document.getElementById("searchInput") as HTMLInputElement).value)); - }}/> - <Posts posts={visiblePosts}/> + <div className='contentWrapper'> + <SearchBar + searchFunction={() => { + setTimeout(() => setQuery((document.getElementById('searchInput') as HTMLInputElement).value)); + }} + /> + <Posts posts={visiblePosts} /> </div> </div> - </div> + </div>; } - |