Merge branch 'feat-search' into deployment

This commit is contained in:
Sat Naing
2022-09-16 00:00:05 +06:30
9 changed files with 379 additions and 14 deletions
+7 -6
View File
@@ -1,12 +1,13 @@
import { defineConfig } from "astro/config";
import tailwind from "@astrojs/tailwind";
import react from "@astrojs/react";
// https://astro.build/config
export default defineConfig({
site: "https://astro-paper.pages.dev/",
integrations: [
tailwind({
config: { applyBaseStyles: false },
}),
],
integrations: [tailwind({
config: {
applyBaseStyles: false
}
}), react()]
});
+180 -2
View File
@@ -9,11 +9,16 @@
"version": "0.0.1",
"dependencies": {
"@astrojs/rss": "^1.0.1",
"astro": "^1.1.7"
"@types/react": "^18.0.20",
"astro": "^1.1.7",
"fuse.js": "^6.6.2"
},
"devDependencies": {
"@astrojs/react": "^1.1.3",
"@astrojs/tailwind": "^1.0.0",
"@tailwindcss/typography": "^0.5.7"
"@tailwindcss/typography": "^0.5.7",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
},
"node_modules/@ampproject/remapping": {
@@ -110,6 +115,23 @@
"node": "^14.18.0 || >=16.12.0"
}
},
"node_modules/@astrojs/react": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@astrojs/react/-/react-1.1.3.tgz",
"integrity": "sha512-awhAEPvJslewJ3Txeapw6LiZtU8RqZrDiequeNDmwQt6iz4Ltn3nJPROKxv4cKesAHEpAZhXWM1q2HhpxWFW0Q==",
"dev": true,
"dependencies": {
"@babel/core": ">=7.0.0-0 <8.0.0",
"@babel/plugin-transform-react-jsx": "^7.17.12"
},
"engines": {
"node": "^14.18.0 || >=16.12.0"
},
"peerDependencies": {
"react": "^17.0.2 || ^18.0.0",
"react-dom": "^17.0.2 || ^18.0.0"
}
},
"node_modules/@astrojs/rss": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-1.0.1.tgz",
@@ -750,11 +772,31 @@
"resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz",
"integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g=="
},
"node_modules/@types/prop-types": {
"version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
},
"node_modules/@types/react": {
"version": "18.0.20",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.20.tgz",
"integrity": "sha512-MWul1teSPxujEHVwZl4a5HxQ9vVNsjTchVA+xRqv/VYGCuKGAU6UhfrTdF5aBefwD1BHUD8i/zq+O/vyCm/FrA==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/resolve": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
},
"node_modules/@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
},
"node_modules/@types/unist": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
@@ -1466,6 +1508,11 @@
"node": ">=4"
}
},
"node_modules/csstype": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
@@ -2178,6 +2225,14 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"node_modules/fuse.js": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz",
"integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==",
"engines": {
"node": ">=10"
}
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -2856,6 +2911,18 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -4439,6 +4506,31 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
},
"peerDependencies": {
"react": "^18.2.0"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -4829,6 +4921,15 @@
"suf-log": "^2.5.3"
}
},
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0"
}
},
"node_modules/section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
@@ -5921,6 +6022,16 @@
"prismjs": "^1.28.0"
}
},
"@astrojs/react": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@astrojs/react/-/react-1.1.3.tgz",
"integrity": "sha512-awhAEPvJslewJ3Txeapw6LiZtU8RqZrDiequeNDmwQt6iz4Ltn3nJPROKxv4cKesAHEpAZhXWM1q2HhpxWFW0Q==",
"dev": true,
"requires": {
"@babel/core": ">=7.0.0-0 <8.0.0",
"@babel/plugin-transform-react-jsx": "^7.17.12"
}
},
"@astrojs/rss": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-1.0.1.tgz",
@@ -6425,11 +6536,31 @@
"resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz",
"integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g=="
},
"@types/prop-types": {
"version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
},
"@types/react": {
"version": "18.0.20",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.20.tgz",
"integrity": "sha512-MWul1teSPxujEHVwZl4a5HxQ9vVNsjTchVA+xRqv/VYGCuKGAU6UhfrTdF5aBefwD1BHUD8i/zq+O/vyCm/FrA==",
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"@types/resolve": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
},
"@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
},
"@types/unist": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
@@ -6910,6 +7041,11 @@
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true
},
"csstype": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
},
"data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
@@ -7320,6 +7456,11 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"fuse.js": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz",
"integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA=="
},
"gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -7769,6 +7910,15 @@
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.0.1.tgz",
"integrity": "sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg=="
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -8751,6 +8901,25 @@
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
"dev": true
},
"react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0"
}
},
"react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
}
},
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -9033,6 +9202,15 @@
"suf-log": "^2.5.3"
}
},
"scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0"
}
},
"section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
+7 -2
View File
@@ -11,10 +11,15 @@
},
"dependencies": {
"@astrojs/rss": "^1.0.1",
"astro": "^1.1.7"
"@types/react": "^18.0.20",
"astro": "^1.1.7",
"fuse.js": "^6.6.2"
},
"devDependencies": {
"@astrojs/react": "^1.1.3",
"@astrojs/tailwind": "^1.0.0",
"@tailwindcss/typography": "^0.5.7"
"@tailwindcss/typography": "^0.5.7",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
+24
View File
@@ -0,0 +1,24 @@
import Datetime from "./Datetime";
import type { Frontmatter } from "@utils/types";
export interface Props {
href?: string;
post: Frontmatter;
}
export default function Card({ href, post }: Props) {
return (
<li className="my-6">
<a
href={href}
className="text-skin-accent font-medium text-lg underline-offset-4 decoration-dashed focus-visible:underline"
>
<h2 className="font-medium text-lg decoration-dashed hover:underline">
{post.title}
</h2>
</a>
<Datetime datetime={post.datetime} />
<p>{post.description}</p>
</li>
);
}
+26
View File
@@ -0,0 +1,26 @@
import formatDatetime from "@utils/formatDatetime";
export interface Props {
datetime: string;
size?: "sm" | "lg";
className?: string;
}
export default function Datetime({ datetime, size = "sm", className }: Props) {
return (
<div className={`opacity-80 flex items-center space-x-2 ${className}`}>
<svg
xmlns="http://www.w3.org/2000/svg"
className={`${
size === "sm" ? "scale-90" : "scale-100"
} w-6 h-6 inline-block fill-skin-base`}
>
<path d="M7 11h2v2H7zm0 4h2v2H7zm4-4h2v2h-2zm0 4h2v2h-2zm4-4h2v2h-2zm0 4h2v2h-2z"></path>
<path d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM19 8l.001 12H5V8h14z"></path>
</svg>
<span className={`italic ${size === "sm" ? "text-sm" : "text-base"}`}>
{formatDatetime(datetime)}
</span>
</div>
);
}
+13 -3
View File
@@ -1,8 +1,9 @@
---
import Hr from "./Hr.astro";
import LinkButton from "./LinkButton.astro";
export interface Props {
activeNav?: "posts" | "tags" | "about";
activeNav?: "posts" | "tags" | "about" | "search";
}
const { activeNav } = Astro.props;
@@ -38,13 +39,19 @@ const { activeNav } = Astro.props;
</li>
</ul>
<div class="button-wrapper">
<button class="focus-outline">
<LinkButton
href="/search"
className={`focus-outline p-1 ${
activeNav === "search" ? "active" : ""
}`}
>
<svg xmlns="http://www.w3.org/2000/svg"
><path
d="M19.023 16.977a35.13 35.13 0 0 1-1.367-1.384c-.372-.378-.596-.653-.596-.653l-2.8-1.337A6.962 6.962 0 0 0 16 9c0-3.859-3.14-7-7-7S2 5.141 2 9s3.14 7 7 7c1.763 0 3.37-.66 4.603-1.739l1.337 2.8s.275.224.653.596c.387.363.896.854 1.384 1.367l1.358 1.392.604.646 2.121-2.121-.646-.604c-.379-.372-.885-.866-1.391-1.36zM9 14c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5z"
></path>
</svg>
</button>
</LinkButton>
<button id="theme-btn" class="focus-outline">
<svg xmlns="http://www.w3.org/2000/svg" id="moon-svg"
><path
@@ -104,6 +111,9 @@ const { activeNav } = Astro.props;
.button-wrapper {
@apply flex my-2 sm:my-0 space-x-4;
}
.button-wrapper a.active svg {
@apply fill-skin-accent;
}
nav button {
@apply p-1;
}
+91
View File
@@ -0,0 +1,91 @@
// import type React from "react";
import Fuse from "fuse.js";
import { useEffect, useState } from "react";
import Card from "@components/Card";
import type { Frontmatter } from "@utils/types";
interface Props {
searchList: {
title: string;
description: string;
frontmatter: Frontmatter;
slug: string;
}[];
}
interface SearchResult {
item: {
title: string;
description: string;
frontmatter: Frontmatter;
slug: string;
};
refIndex: number;
}
export default function SearchBar({ searchList }: Props) {
const [inputVal, setInputVal] = useState("");
const [searchResults, setSearchResults] = useState<SearchResult[] | null>(
null
);
const handleChange = (e: React.FormEvent<HTMLInputElement>) => {
setInputVal(e.currentTarget.value);
};
const fuse = new Fuse(searchList, {
keys: ["title", "description"],
includeMatches: true,
threshold: 0.3,
});
useEffect(() => {
setSearchResults(fuse!.search!(inputVal!));
}, [inputVal]);
return (
<>
<label className="relative block">
<span className="sr-only">Search</span>
<span className="absolute inset-y-0 left-0 flex items-center pl-2 opacity-75">
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M19.023 16.977a35.13 35.13 0 0 1-1.367-1.384c-.372-.378-.596-.653-.596-.653l-2.8-1.337A6.962 6.962 0 0 0 16 9c0-3.859-3.14-7-7-7S2 5.141 2 9s3.14 7 7 7c1.763 0 3.37-.66 4.603-1.739l1.337 2.8s.275.224.653.596c.387.363.896.854 1.384 1.367l1.358 1.392.604.646 2.121-2.121-.646-.604c-.379-.372-.885-.866-1.391-1.36zM9 14c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5z"></path>
</svg>
</span>
<input
className="placeholder:italic placeholder:text-opacity-75 py-3 pl-10 pr-3
block bg-skin-fill w-full rounded
border border-skin-fill border-opacity-40
focus:outline-none focus:border-skin-fill"
placeholder="Search for anything..."
type="text"
name="search"
defaultValue={inputVal}
onChange={handleChange}
autoComplete="off"
/>
</label>
{searchResults && searchResults.length > 0 && (
<div className="mt-8">
Found {searchResults?.length}
{searchResults?.length && searchResults?.length > 1
? " results"
: " result"}{" "}
for '{inputVal}'
</div>
)}
<ul>
{searchResults &&
searchResults.map((result) => (
<Card
post={result.item.frontmatter}
href={`/posts/${result.item.slug}`}
key={`${result.refIndex}-${result.item.slug}`}
/>
))}
</ul>
</>
);
}
+29
View File
@@ -0,0 +1,29 @@
---
import Layout from "@layouts/Layout.astro";
import Main from "@layouts/Main.astro";
import Header from "@components/Header.astro";
import Footer from "@components/Footer.astro";
import Search from "@components/Search";
import type { Frontmatter } from "@utils/types";
localStorage.setItem("myCat", "Tom");
// Retrieve all articles
const posts = await Astro.glob<Frontmatter>("../contents/*.md");
// List of items to search in
const searchList = posts.map(({ frontmatter }) => ({
title: frontmatter.title,
description: frontmatter.description,
frontmatter,
slug: frontmatter.slug,
}));
---
<Layout title={`Search | ${import.meta.env.PUBLIC_SITE_TITLE}`}>
<Header activeNav="search" />
<Main pageTitle="Search" pageDesc="Search any article ...">
<Search client:load searchList={searchList} />
</Main>
<Footer />
</Layout>
+1
View File
@@ -37,6 +37,7 @@ module.exports = {
borderColor: {
skin: {
line: withOpacity("--color-border"),
fill: withOpacity("--color-text-base"),
},
},
fill: {