diff --git a/package-lock.json b/package-lock.json index b01a2cf..e0de0a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "react-dom": "^18", "react-markdown": "^9.0.1", "rehype-raw": "^7.0.0", - "remark-gfm": "^4.0.0" + "remark-gfm": "^4.0.0", + "use-sound": "^4.0.1" }, "devDependencies": { "@types/node": "^20", @@ -573,6 +574,11 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/howler": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz", + "integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==" + }, "node_modules/html-url-attributes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.0.tgz", @@ -1950,6 +1956,17 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/use-sound": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/use-sound/-/use-sound-4.0.1.tgz", + "integrity": "sha512-hykJ86kNcu6y/FzlSHcQxhjSGMslZx2WlfLpZNoPbvueakv4OF3xPxEtGV2YmculrIaH0tPp9LtG4jgy17xMWg==", + "dependencies": { + "howler": "^2.1.3" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, "node_modules/vfile": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", diff --git a/package.json b/package.json index 472ed24..7f53eca 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "react-dom": "^18", "react-markdown": "^9.0.1", "rehype-raw": "^7.0.0", - "remark-gfm": "^4.0.0" + "remark-gfm": "^4.0.0", + "use-sound": "^4.0.1" }, "devDependencies": { "@types/node": "^20", diff --git a/qna.txt b/qna.txt new file mode 100644 index 0000000..0c8798c --- /dev/null +++ b/qna.txt @@ -0,0 +1,4 @@ +fetch("https://retrospring.net/ajax/ask", { + "body": "{\"rcpt\":\"111212083514464878\",\"question\":\"hi sneex it is me abtmtr. i am not in your house right now but hypothetically if i was. where do you keep your hams\",\"anonymousQuestion\":\"true\"}", + "method": "POST" +}); \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index c9d68bb..d33174f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import localFont from "next/font/local"; import "@/styles/style.css"; +import { Sounds } from "@/components/Sounds"; const lexendDeca = localFont({ src: "../../public/fonts/Lexend Deca/Variable.ttf"}); const materialSymbols = localFont({ src: "../../public/fonts/Material Symbols/Variable.ttf"}); diff --git a/src/app/page.tsx b/src/app/page.tsx index c353e5c..ce20ddf 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,6 +1,7 @@ import { MainLayout } from "@/layout/MainLayout/MainLayout"; import Link from "next/link"; import buttons from "@/buttons.json"; +import Searchbar from "@/components/Searchbar/Searchbar"; export default async function Home() { const data = await fetch("https://pronouns.cc/api/v1/users/mtr").then(x=>x.json()); @@ -12,6 +13,7 @@ export default async function Home() { return ( WELCOME! Enjoy your stay at abtmtr.link! +

abtmtr.link is a domain for a suite of services, ranging from micro-blogging to web search.

I'm {goodNames[0].value}, otherwise known as {goodNames.slice(1).map((name:{value:string}, idx:number) => ( idx == goodNames.length - 2 ? (<>or {name.value}) : (<>{name.value}{goodNames.length <= 2 ? ", " : " "}) diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx new file mode 100644 index 0000000..2507fbc --- /dev/null +++ b/src/app/search/page.tsx @@ -0,0 +1,10 @@ +import Searchbar from "@/components/Searchbar/Searchbar"; +import { MainLayout } from "@/layout/MainLayout/MainLayout"; + +export default function Page() { + return ( + + + + ) +} \ No newline at end of file diff --git a/src/app/search/search/page.tsx b/src/app/search/search/page.tsx new file mode 100644 index 0000000..7c1441c --- /dev/null +++ b/src/app/search/search/page.tsx @@ -0,0 +1,144 @@ +import { MainLayout } from "@/layout/MainLayout/MainLayout"; +import styles from "./styles.module.css"; +import Link from "next/link"; +import { ConditionalNull, ConditionalParent } from "@/components/utility/Conditional"; +import Searchbar from "@/components/Searchbar/Searchbar"; +// + +export default async function Home({ + searchParams +}:{ + searchParams: { + q: string, + page: string + } +}) { + const curPage = parseInt(searchParams?.page) || 1; + const searchResults = await fetch(`https://s.abtmtr.link/search?q=${searchParams.q}&pageno=${curPage}&format=json`, { + headers: [ + ["Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"] + ] + }).then(x => x.json()); + return ( + + +

+ {searchResults.infoboxes?.map((box:{ + infobox: string, + attributes?: { + label: string, + value?: string, + image?: { + src: string, + alt: string, + title: string, + width: number, + height: number, + type: string, + themes: string, + colorinvertable: boolean, + contenttype: string + } + }[], + id?: string, + content?: string, + img_src?: string, + urls: { + title: string, + url: string + }[], + engine: string, + engines: string[] + }) => { + return ( +
+

{box.infobox}

+ 0} + parent={(x => ( +
+ + {x} +
+ ))} + > + +
+ {box.id}
+

{box.content}

+
+
+
+ {box.attributes?.map(attribute => (
+

{attribute.label}

+ +

{attribute.value}

+
+ + {attribute.image?.alt} + +
))} + {box.urls.map(url => (

+ {url.title} +

))} + {box.engines?.join(" ") ?? box.engine} +
+ ); + })} +
+ {searchResults.results?.map((result:{ + url: string, + title: string, + content?: string, + img_src?: string, + engine: string, + parsed_url: string[], + engines: string[], + positions: number[], + score: number, + category: string + }) => { + const content = result.content?.match(/^.+?(?:\.|$)/m); + return ( +
+

+ {result.title} +
+ {result.url} +

+ 0} + parent={(x => ( +
+ + {x} +
+ ))} + > +
+ + "{content?.[0].replace(/"/g, "")}"
+
+ {result.engines?.join(" ") ?? result.engine} +
+
+
+ ) + })} +
+ 1}> + Previous + + 0}> + Next + +
+
+ ) +} \ No newline at end of file diff --git a/src/app/search/search/styles.module.css b/src/app/search/search/styles.module.css new file mode 100644 index 0000000..3ef60c7 --- /dev/null +++ b/src/app/search/search/styles.module.css @@ -0,0 +1,31 @@ +.SearchResult { + margin: 16px 0; +} + +.SearchInfobox { + /* border: 1px solid var(--fg-2); */ + background-color: var(--bg-3); + color: var(--fg-3); + border-radius: 4px; + padding: 8px; + margin: 16px 0; +} + +.SearchInfobox h2 { + /* margin-left: 8px; */ + margin-top: 0; + margin-bottom: 8px; +} + +.SideBySideImage { + display: grid; + grid-template-columns: auto 1fr; + gap: 8px; +} + +.SideBySideImage img { + max-height: 100%; + max-width: 150px !important; + border: 1px solid var(--fg-3); + border-radius: 4px; +} \ No newline at end of file diff --git a/src/components/Searchbar/Searchbar.tsx b/src/components/Searchbar/Searchbar.tsx new file mode 100644 index 0000000..bfa28ea --- /dev/null +++ b/src/components/Searchbar/Searchbar.tsx @@ -0,0 +1,69 @@ +"use client"; +import Link from "next/link"; +import styles from "./styles.module.css"; +import { FormEvent, KeyboardEvent, useRef, useState } from "react"; +import { stringify } from "querystring"; +import { ConditionalNull } from "@/components/utility/Conditional"; +import { useRouter } from "next/navigation"; + +export default function Searchbar({value}:{value?:string}) { + const [href, setHref] = useState(""); + const [arr, setArr] = useState([]); + const searchRouter = useRouter(); + + let currentTimeout: number | NodeJS.Timeout; + function suggestTimeout(e:FormEvent) { + const target = e.target as HTMLInputElement; + if (target.value.length < 1) + setHref(""); + else + setHref(`/search/search/?${stringify({q:target.value})}`); + clearTimeout(currentTimeout); + currentTimeout = setTimeout(executeAC, 500, e); + } + + async function executeAC(e:FormEvent) { + const target = e.target as HTMLInputElement; + console.log(target.value); + const rows = await fetch(`https://s.abtmtr.link/autocompleter?${stringify({ + q: target.value + })}`).then(x => x.json()); + if (rows == null) return; + setArr(rows[1]); + } + + function onKeypress(e:KeyboardEvent) { + if (e.key === "Enter") { + // Cancel the default action, if needed + e.preventDefault(); + searchRouter.push(href); + + } + } + + return (<> +
+ + search +
+ 0}> +
+ {arr.map(result => ( +
+ + {result} + +
+ ))} +
+
+ ) +} \ No newline at end of file diff --git a/src/components/Searchbar/styles.module.css b/src/components/Searchbar/styles.module.css new file mode 100644 index 0000000..71afc8a --- /dev/null +++ b/src/components/Searchbar/styles.module.css @@ -0,0 +1,48 @@ +.SearchBox { + margin: 16px 0; + width: 100%; + border-radius: 4px; + height: 2em; + background-color: var(--bg-3); + color: var(--fg-3); + display: grid; + grid-template-columns: 1fr auto; + /* overflow: hidden; */ +} + +.SearchBoxForm { + border-radius: 4px 0 0 4px; + padding: 2px 8px !important; + font-family: var(--font-LexendDeca); + vertical-align: middle; + border: none; + background-color: transparent; + color: currentColor; +} + +.SearchBoxForm::placeholder { + color: var(--fg-1); +} + +.SearchBoxButton { + display: inline-block; + border-radius: 0 4px 4px 0; + font-family: var(--font-MaterialSymbols); + font-size: 24px; + padding: 0 8px; + vertical-align: middle; + line-height: 1.25em; + cursor: pointer; + text-decoration: none; +} + +.SuggestionBox { + margin-top: 8px; + width: 100%; + border-radius: 4px; + background-color: var(--bg-3); + color: var(--fg-2); + padding: 8px; +} + +.SuggestionBoxIndex {} \ No newline at end of file diff --git a/src/components/Sounds/index.ts b/src/components/Sounds/index.ts new file mode 100644 index 0000000..a0a2249 --- /dev/null +++ b/src/components/Sounds/index.ts @@ -0,0 +1,24 @@ +'use client'; + +export const Sounds = { + alternative: new Audio("/sfx/s_alternative.mp3"), + busy: new Audio("/sfx/s_busy.mp3"), + happy: new Audio("/sfx/s_happy.mp3"), + hover: new Audio("/sfx/s_hover.mp3"), + impossible: new Audio("/sfx/s_impossible.mp3"), + notice: new Audio("/sfx/s_notice.mp3"), + open: new Audio("/sfx/s_open.mp3"), + possible_alt: new Audio("/sfx/s_possible_alt.mp3"), + sad: new Audio("/sfx/s_sad.mp3"), +}; + +export function preload() { + Object.values(Sounds).forEach((sound) => { + sound.preload = "auto"; + }) +} + +export function playSound(audio:HTMLAudioElement) { + audio.currentTime = 0; + audio.play(); +} \ No newline at end of file diff --git a/src/layout/MainLayout/MainLayout.module.css b/src/layout/MainLayout/MainLayout.module.css index 8d12d08..bff32f6 100644 --- a/src/layout/MainLayout/MainLayout.module.css +++ b/src/layout/MainLayout/MainLayout.module.css @@ -54,6 +54,7 @@ background-color: var(--bg-1); color: var(--fg-1); border-right: 1px solid var(--neutral); + overflow-y: scroll; } .MainLayout_Aside.Modifier_Open {} @@ -72,6 +73,7 @@ background-color: var(--bg-2); color: var(--fg-2); border-bottom: 1px solid var(--neutral); + overflow: hidden; display: grid; grid-template-columns: auto; @@ -86,7 +88,7 @@ .MainLayout_Inner_Header.Modifier_Back { padding: 6px 8px; - grid-template-columns: 32px auto; + grid-template-columns: 32px 1fr; } .MainLayout_Inner_Header_Back_Button { @@ -106,18 +108,30 @@ justify-content: center; align-items: flex-start; align-content: center; + width: 100%; + overflow: hidden; } .MainLayout_Inner_Header_Title h1 { + display: inline-block; margin: 0; vertical-align: middle; font-size: 1em; + text-wrap: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; } .MainLayout_Inner_Header_Title span { + display: inline-block; margin: 0; vertical-align: middle; font-size: 0.75em; + text-wrap: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; } .MainLayout_Inner_Main { diff --git a/src/layout/MainLayout/MainLayout.tsx b/src/layout/MainLayout/MainLayout.tsx index b5db99f..c2ab2bc 100644 --- a/src/layout/MainLayout/MainLayout.tsx +++ b/src/layout/MainLayout/MainLayout.tsx @@ -16,5 +16,5 @@ export function MainLayout({ sidebar?: React.ReactNode, currentPage: string }) { - return {children} + return }>{children} } \ No newline at end of file diff --git a/src/layout/MainLayout/Sidebar/Main/Main.module.css b/src/layout/MainLayout/Sidebar/Main/Main.module.css index 31cc5f0..b778100 100644 --- a/src/layout/MainLayout/Sidebar/Main/Main.module.css +++ b/src/layout/MainLayout/Sidebar/Main/Main.module.css @@ -21,10 +21,24 @@ background-color: var(--bg-2); } -.Main_List_Button { +/* .Main_List_Button { transition: scale 0.0625s; } .Main_List_Button:active { scale: 0.95; -} \ No newline at end of file +} + +*/ .Main_List_Button_Slim { + padding: 2px 8px !important; + background-color: var(--bg-3); + color: var(--fg-2); +} +.Main_List_Button_Slim:hover { + background-color: var(--bg-2); + color: var(--fg-1); +} + +/* .Main_List_Button_Slim:active { + scale: 1; +} */ \ No newline at end of file diff --git a/src/layout/MainLayout/Sidebar/Main/Main.tsx b/src/layout/MainLayout/Sidebar/Main/Main.tsx index 518df6d..a149b91 100644 --- a/src/layout/MainLayout/Sidebar/Main/Main.tsx +++ b/src/layout/MainLayout/Sidebar/Main/Main.tsx @@ -1,62 +1,133 @@ +'use client'; import Link from "next/link"; import styles from "./Main.module.css"; +// import useSound from 'use-sound'; export function SidebarMain({currentPage}:{currentPage:string}) { + // const [openPlay] = useSound("/sfx/s_open.mp3"); + // const [impossiblePlay] = useSound("/sfx/s_impossible.mp3"); + // const [hoverPlay] = useSound("/sfx/s_hover.mp3"); return <>

abtmtr.link

{/*
*/}
- + currentPage === "/" ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
home Root
- + currentPage === "/" ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + > +
+ search + Search +
+ + currentPage.includes("/projects/") ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
folder Projects
- + currentPage.includes("/characters/") ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
group Characters
- + currentPage.includes("/blog/") ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
description Blog
- + currentPage.includes("/gallery/") ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
image Gallery
- + currentPage.includes("/stories/") ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
book Stories
- + currentPage.includes("/links/") ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
link Links
- + currentPage.includes("/oao/") ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
campaign Opinions & Objections
- + currentPage.includes("/about/") ? impossiblePlay() : openPlay()} + // onMouseEnter={hoverPlay} + >
info About