diff options
Diffstat (limited to 'pages')
-rw-r--r-- | pages/_app.tsx | 13 | ||||
-rw-r--r-- | pages/index.tsx | 72 | ||||
-rw-r--r-- | pages/post/[id].tsx | 123 | ||||
-rw-r--r-- | pages/search.tsx | 165 |
4 files changed, 190 insertions, 183 deletions
diff --git a/pages/_app.tsx b/pages/_app.tsx index 62c1c9b..662f841 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,20 +1,19 @@ import Head from 'next/head'; +import '../styles/button.css'; import '../styles/colors.css'; -import '../styles/layout.css'; import '../styles/globals.css'; -import '../styles/navbar.css'; -import '../styles/button.css'; import '../styles/image.css'; -import '../styles/tags.css'; +import '../styles/layout.css'; +import '../styles/navbar.css'; import '../styles/search.css'; +import '../styles/tags.css'; export default function Blog({ Component, pageProps }) { return <div> <Head> - <link rel="stylesheet" href="/font/font.css"/> + <link rel='stylesheet' href='/font/font.css' /> </Head> <Component {...pageProps} /> - </div> + </div>; } - diff --git a/pages/index.tsx b/pages/index.tsx index 96b8684..65b53cb 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,52 +1,52 @@ -import Navbar, { NavbarItem } from '../components/navbar'; import Chapters, { chapter } from '../components/chapters'; +import Navbar, { NavbarItem } from '../components/navbar'; import Seperator from '../components/seperator'; -import { getStaticProps as getBlogPage, ArticleMeta, RenderedArticle } from './post/[id]'; +import { ArticleMeta, getStaticProps as getBlogPage, RenderedArticle } from './post/[id]'; -var posts = ["index", "index", "index"]; +var posts = ['index', 'index', 'index']; export default function Home(props: { posts: Array<{ props: { - content: string, - meta: ArticleMeta - } - }> + content: string; + meta: ArticleMeta; + }; + }>; }) { return <div> - <div className="centeredPage"> - <div className="titleWrapper"> + <div className='centeredPage'> + <div className='titleWrapper'> <h1>{props.posts[0].props.meta.title}</h1> </div> - <div className="navAreaWrapper"> - <div className="sticky"> - <Navbar page="home"/> - <NavbarItem title="Pinned posts:" classList={["pinned"]}/> - <Chapters chapters={[ - ...props.posts.slice(1).map(post => { - return { - children: post.props.meta.chapters, - name: post.props.meta.title, - sectionLink: "/post/" + post.props.meta.id - } as chapter - }) - ]}/> + <div className='navAreaWrapper'> + <div className='sticky'> + <Navbar page='home' /> + <NavbarItem title='Pinned posts:' classList={['pinned']} /> + <Chapters + chapters={[ + ...props.posts.slice(1).map(post => { + return { + children: post.props.meta.chapters, + name: post.props.meta.title, + sectionLink: '/post/' + post.props.meta.id, + } as chapter; + }), + ]} + /> </div> </div> - <div className="contentWrapper"> - { - props.posts.map((post, index) => { - return <> - { index != 0 && <h1>{post.props.meta.title}</h1> } - <RenderedArticle content={post.props.content}/> - { index + 1 != props.posts.length && <Seperator/> } - </> - }) - } + <div className='contentWrapper'> + {props.posts.map((post, index) => { + return <> + {index != 0 && <h1>{post.props.meta.title}</h1>} + <RenderedArticle content={post.props.content} /> + {index + 1 != props.posts.length && <Seperator />} + </>; + })} </div> </div> - </div> + </div>; } export function getStaticProps() { @@ -54,9 +54,9 @@ export function getStaticProps() { posts.forEach(id => { postsContent.push(getBlogPage({ params: { id } })); - }) + }); var staticProps = { props: { posts: postsContent } }; - - return staticProps + + return staticProps; } diff --git a/pages/post/[id].tsx b/pages/post/[id].tsx index b68b790..c0d4e9d 100644 --- a/pages/post/[id].tsx +++ b/pages/post/[id].tsx @@ -1,14 +1,14 @@ -import { ReactNode } from 'react'; import ReactMarkdownWithHTML from 'react-markdown/with-html'; import { readdirSync, readFileSync } from 'fs'; import { join } from 'path'; +import { ReactNode } from 'react'; import gfm from 'remark-gfm'; -import Seperator from '../../components/seperator'; import Navbar from '../../components/navbar'; +import Seperator from '../../components/seperator'; // import Button from '../../components/button'; -import Image from '../../components/image'; import Chapters, { chapter } from '../../components/chapters'; +import Image from '../../components/image'; import Tags from '../../components/tag'; export interface ArticleMeta { @@ -21,70 +21,72 @@ export interface ArticleMeta { id?: string; } -export function RenderedArticle(props: { content: string }) { +export function RenderedArticle(props: { content: string; }) { return <ReactMarkdownWithHTML - plugins={[gfm]} - allowDangerousHtml - children={props.content} - renderers={{ - image: Image, - thematicBreak: Seperator, - heading: Heading, - }}/>; + plugins={[gfm]} + allowDangerousHtml + children={props.content} + renderers={{ + image: Image, + thematicBreak: Seperator, + heading: Heading, + }} + />; } var headingLevel = (input: string) => input?.match(/^[#]+/)[0]?.length || 0; -var sectionID = (input: string) => input - .replace(/[()\[\]{}!@#$%^&*<>?,./\;':"\\|=+]/g, "") - .replace(/\s/g, "-") - .toLowerCase(); +var sectionID = (input: string) => + input + .replace(/[()\[\]{}!@#$%^&*<>?,./\;':"\\|=+]/g, '') + .replace(/\s/g, '-') + .toLowerCase(); function Heading(props: { children?: ReactNode; level?: number; }) { - var HeadingTag = "h" + props.level as keyof JSX.IntrinsicElements; - return <HeadingTag id={sectionID(props.children[0].props.children)} children={props.children}/> + var HeadingTag = 'h' + props.level as keyof JSX.IntrinsicElements; + return <HeadingTag id={sectionID(props.children[0].props.children)} children={props.children} />; } export default function Post(props: { - content: string, - meta: ArticleMeta + content: string; + meta: ArticleMeta; }) { return <div> - <div className="centeredPage"> - <div className="titleWrapper"> + <div className='centeredPage'> + <div className='titleWrapper'> <h1>{props.meta.title}</h1> - <p className="subtile">{props.meta.subtitle}</p> - { props.meta.tags && <Tags tags={props.meta.tags}/> } + <p className='subtile'>{props.meta.subtitle}</p> + {props.meta.tags && <Tags tags={props.meta.tags} />} </div> - <div className="navAreaWrapper"> - <div className="sticky"> - <Navbar/> - <Chapters chapters={props.meta.chapters}/> + <div className='navAreaWrapper'> + <div className='sticky'> + <Navbar /> + <Chapters chapters={props.meta.chapters} /> </div> </div> - <div className="contentWrapper"> - <RenderedArticle content={props.content}/> + <div className='contentWrapper'> + <RenderedArticle content={props.content} /> </div> </div> - </div> + </div>; } var parseTag = { - "title": (val: string) => val, - "subtitle": (val: string) => val, - "author": (val: string) => val, - "tags": (val: string) => val.split(",").map(i => i.trim()), - "date": (val: string) => new Date(val).toDateString(), -} + 'title': (val: string) => val, + 'subtitle': (val: string) => val, + 'author': (val: string) => val, + 'tags': (val: string) => val.split(',').map(i => i.trim()), + 'date': (val: string) => new Date(val).toDateString(), +}; function parseMeta(file: Array<string>): ArticleMeta { var meta: ArticleMeta = {}; file.forEach(line => { - if (!line.startsWith("[meta]: ")) return; + if (!line.startsWith('[meta]: ')) return; var tags = line.match(/\[meta\]:\s+\<(.+?)\>\s+\((.+?)\)/); if (!tags || !tags[1] || !tags[2]) return; if (!parseTag.hasOwnProperty(tags[1])) return; @@ -98,7 +100,7 @@ function parseToCRecursive(headings: Array<string>): Array<chapter> { interface WIPchapter extends chapter { unparsedChildren?: Array<string>; } - var children: Array<WIPchapter> = [] + var children: Array<WIPchapter> = []; var lowestLevel = headingLevel(headings[0]); var currentChildIndex = -1; @@ -108,44 +110,44 @@ function parseToCRecursive(headings: Array<string>): Array<chapter> { var chapterName = headings[i].match(/^[#]+\s+(.+)/)[1]; children.push({ name: chapterName, - sectionLink: "#" + sectionID(chapterName), + sectionLink: '#' + sectionID(chapterName), unparsedChildren: [], }); currentChildIndex += 1; } else { - children[currentChildIndex].unparsedChildren.push(headings[i]) + children[currentChildIndex].unparsedChildren.push(headings[i]); } } children.map(child => { - child.children = parseToCRecursive(child.unparsedChildren) + child.children = parseToCRecursive(child.unparsedChildren); delete child.unparsedChildren; - return child - }) + return child; + }); return children as Array<chapter>; } function parseToC(file: Array<string>): Array<chapter> { - var fileAsStr = file.join("\n"); - fileAsStr = fileAsStr.replace(/```.*?```/gs, ""); // filter out code blocks from table of contents - var fileAsArr = fileAsStr.split("\n"); - var chapterStrings = fileAsArr.filter(line => line.startsWith("#")); + var fileAsStr = file.join('\n'); + fileAsStr = fileAsStr.replace(/```.*?```/gs, ''); // filter out code blocks from table of contents + var fileAsArr = fileAsStr.split('\n'); + var chapterStrings = fileAsArr.filter(line => line.startsWith('#')); return parseToCRecursive(chapterStrings); } function preprocessor(fileContent: string) { - var fileAsArr = fileContent.split("\n"); + var fileAsArr = fileContent.split('\n'); var meta = parseMeta(fileAsArr); meta.chapters = parseToC(fileAsArr); - var result = fileAsArr.join("\n").trim() - return { meta, result } + var result = fileAsArr.join('\n').trim(); + return { meta, result }; } -export function getStaticProps(props: {params: { id: string }}) { - var filename = join("posts/", props.params.id + ".md") - var filecontent = readFileSync(filename).toString().trim() +export function getStaticProps(props: { params: { id: string; }; }) { + var filename = join('posts/', props.params.id + '.md'); + var filecontent = readFileSync(filename).toString().trim(); var parsed = preprocessor(filecontent); parsed.meta.id = props.params.id; @@ -155,21 +157,20 @@ export function getStaticProps(props: {params: { id: string }}) { content: parsed.result, meta: parsed.meta, }, - } + }; } export function getStaticPaths() { - var files = readdirSync("posts").filter(f => f.endsWith(".md")); + var files = readdirSync('posts').filter(f => f.endsWith('.md')); return { paths: files.map((f) => { return { params: { - id: f.substr(0, f.length - 3) - } - } + id: f.substr(0, f.length - 3), + }, + }; }), fallback: false, - } + }; } - 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>; } - |