Merge pull request #7 from Team-1280/dejank

Massive dejankification
This commit is contained in:
Ananth Venkatesh 2024-02-17 23:31:50 -08:00 committed by GitHub
commit 9155090537
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 274 additions and 239 deletions

View file

@ -1,6 +1,6 @@
{
"extends": "next/core-web-vitals",
"rules": {
"@next/next/no-img-element": "off"
"@next/next/no-img-element": "error"
}
}

View file

@ -1,7 +1,15 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
unoptimized: true,
unoptimized: false,
remotePatterns: [
{
protocol: 'https',
hostname: 'upload.wikimedia.org',
port: '',
pathname: '/**',
},
],
},
}

3
package-lock.json generated
View file

@ -36,6 +36,9 @@
"prettier": "^3.2.5",
"tailwindcss": "^3.3.0",
"typescript": "^5"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": {

View file

@ -9,6 +9,9 @@
"lint": "next lint",
"format": "prettier --write ."
},
"engines": {
"node": ">=20.0.0"
},
"dependencies": {
"@tanstack/react-query": "^5.20.2",
"fnv-plus": "^1.3.1",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 921 KiB

After

Width:  |  Height:  |  Size: 907 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 MiB

After

Width:  |  Height:  |  Size: 6.9 MiB

View file

@ -4,6 +4,7 @@ import { Zilla_Slab } from 'next/font/google'
import findDocumentsByAffiliation from './findDocumentsByAffiliation'
import { Fragment } from 'react'
import DocumentCard from '@/app/components/DocumentCard'
import Image from 'next/image'
const zillaSlab = Zilla_Slab({ subsets: ['latin'], weight: ['500'] })
@ -12,6 +13,19 @@ export function generateStaticParams() {
return affiliationsList.map((shortName) => ({ shortName }))
}
const Description = ({ description }: Readonly<{ description: string }>) => {
return (
<>
{description.split('[linebreak]').map((d, i) => (
<>
<div className='text-lg sm:text-md font-serif'>{d}</div>
<br className='m-1' />
</>
))}
</>
)
}
export default function Page({
params,
}: Readonly<{ params: { shortName: string } }>) {
@ -23,25 +37,14 @@ export default function Page({
const affiliationDocuments = findDocumentsByAffiliation(shortName)
const Description = () => {
return (
<>
{description.split('[linebreak]').map((d, i) => (
<>
<div className='text-lg sm:text-md font-serif'>{d}</div>
<br className='m-1' />
</>
))}
</>
)
}
return (
<div>
<div className='grid grid-cols-1 max-w-3xl mx-auto'>
<div className='mx-auto mb-4 max-w-3xl md:w-auto md:h-[40vw] lg:h-[20vw] rounded-lg shadow-lg shadow-slate-400'>
<img
<Image
alt='profile'
width={1000}
height={1000}
className='rounded-lg mx-auto p-8 object-cover w-full h-full'
src={image}
/>
@ -57,7 +60,7 @@ export default function Page({
<div className='max-w-3xl mx-auto grid grid-cols-1'>
<hr className='mx-auto w-full h-1 border-0 bg-slate-200 my-2 rounded-md' />
<br />
<Description />
<Description description={description} />
</div>
{affiliationDocuments.length > 0 && (
<>

View file

@ -3,6 +3,7 @@ import { notFound } from 'next/navigation'
import { Zilla_Slab } from 'next/font/google'
import getAffiliations from './getAffiliations'
import { Fragment } from 'react'
import Image from 'next/image'
const zillaSlab = Zilla_Slab({ subsets: ['latin'], weight: ['500'] })
@ -24,8 +25,10 @@ const AffiliationCard = ({
<div className='m-4'>
<div className='grid grid-cols-1 max-w-3xl mx-auto'>
<div className='mx-auto mb-4 max-w-3xl md:w-auto md:h-[40vw] lg:h-[20vw] rounded-lg shadow-lg shadow-slate-400'>
<img
<Image
alt='profile'
width={1000}
height={1000}
className='rounded-lg mx-auto p-8 object-cover w-full h-full'
src={image}
/>

View file

@ -1,32 +1,22 @@
import Link from 'next/link'
import { Fragment, Suspense } from 'react'
import { affiliations, nationalities, authors } from '../../db/data'
import { Author, affiliations, authors } from '../../db/data'
import { Zilla_Slab } from 'next/font/google'
import { notFound } from 'next/navigation'
import DocumentCard from '@/app/components/DocumentCard'
import findDocumentsByAuthor from './findDocumentsByAuthor'
import cardEffects from '@/app/styles/cardEffects.module.css'
import KonamiSnowfall from './KonamiSnowfall'
import Image from 'next/image'
const zillaSlab = Zilla_Slab({ subsets: ['latin'], weight: ['500'] })
export default function AuthorDisplay({
author,
}: Readonly<{ author: string }>) {
const data = authors[author]
if (!data) {
notFound()
}
const MainAuthorPosition = ({ author }: { author: Author }) => {
const { name, affiliation, website } = author
const { name, affiliation, image, nationality, formerAffiliations } = data
const authorsDocuments = findDocumentsByAuthor(author)
const MainPosition = () => {
const mainAffiliationShort = affiliation[0].split('@')[1]
const mainPosition = affiliation[0].split('@')[0]
const mainAffiliation = affiliations[mainAffiliationShort]
const { website } = data
return (
<>
@ -49,25 +39,27 @@ export default function AuthorDisplay({
href={`/affiliation/${a.split('@')[1]}`}
className={`${cardEffects['card-small']} rounded-md`}
>
<img
<Image
src={affiliations[a.split('@')[1]].image}
alt={affiliations[a.split('@')[1]].name}
className='h-16 rounded-md p-2'
width={100}
height={100}
className='h-16 rounded-md p-2 object-contain'
/>
</Link>
))}
</div>
</>
)
}
}
const OtherAuthorPositions = ({ author }: { author: Author }) => {
const { affiliation } = author
const OtherPositions = () => {
if (affiliation.length === 1) return
return (
<>
<h1 className='text-3xl md:mt-6 mt-4 mb-2 font-serif'>
Other Positions
</h1>
<h1 className='text-3xl md:mt-6 mt-4 mb-2 font-serif'>Other Positions</h1>
{affiliation.slice(1).map((a: string, i: number) => {
const position = a.split('@')[0]
const affiliation = affiliations[a.split('@')[1]].name
@ -84,9 +76,11 @@ export default function AuthorDisplay({
})}
</>
)
}
}
const FormerAuthorPositions = ({ author }: { author: Author }) => {
const { formerAffiliations } = author
const FormerPositions = () => {
if (!formerAffiliations) return null
return (
<>
@ -110,10 +104,10 @@ export default function AuthorDisplay({
})}
</>
)
}
}
const Bio = () => {
const { bio } = data
const AuthorBio = ({ author }: { author: Author }) => {
const { bio } = author
if (!bio) return null
return (
@ -122,8 +116,20 @@ export default function AuthorDisplay({
<p className='mb-2'>{bio}</p>
</>
)
}
export default function AuthorDisplay({
author,
}: Readonly<{ author: string }>) {
const data = authors[author]
if (!data) {
notFound()
}
const { name, image, nationality } = data
const authorsDocuments = findDocumentsByAuthor(author)
return (
<>
<Suspense>
@ -131,9 +137,11 @@ export default function AuthorDisplay({
</Suspense>
<div className='grid grid-cols-1 md:grid-cols-2 items-center max-w-3xl mx-auto'>
<div className='aspect-square w-[60vw] md:w-[30vw] lg:w-[20vw] 2xl:w-[15vw] overflow-hidden mx-auto mb-4'>
<img
<Image
alt='profile'
className='rounded-full mx-auto object-cover w-full h-full border-slate-800 border-4'
width={500}
height={500}
src={image}
/>
</div>
@ -146,16 +154,16 @@ export default function AuthorDisplay({
{name.nickname ? ` "${name.nickname}"` : null} {name.last}
</span>
<div className='text-slate-600 text-md sm:text-lg mt-4'>
<MainPosition />
<MainAuthorPosition author={data} />
</div>
</div>
</div>
</div>
<div className='max-w-3xl mx-auto grid grid-cols-1 justify-center'>
<hr className='mx-auto w-full h-1 border-0 bg-slate-200 my-2 rounded-md' />
<OtherPositions />
<FormerPositions />
<Bio />
<OtherAuthorPositions author={data} />
<FormerAuthorPositions author={data} />
<AuthorBio author={data} />
{authorsDocuments.length > 0 && (
<>
<hr className='mx-auto w-full h-1 border-0 bg-slate-200 my-2 rounded-md mt-8' />

View file

@ -1,9 +1,28 @@
'use client'
import Konami from 'react-konami-code'
import { Snowfall } from 'react-snowfall'
import { useEffect, useState } from 'react'
import { Fragment, useEffect, useState } from 'react'
import { nationalities } from '@/app/db/data'
import { Fragment } from 'react'
import NextImage from 'next/image'
const NationalityDisplay = ({
nationality,
}: Readonly<{ nationality: string }>) => {
const nationalityData = nationalities[nationality]
const { demonym, flag } = nationalityData
return (
<div className='flex items-center'>
<NextImage
src={flag}
width={100}
height={100}
className='w-10 shadow-md shadow-slate-300'
alt={`${demonym} flag`}
/>
<span className='mx-3 font-semibold'>{demonym}</span>
</div>
)
}
export default function KonamiSnowfall({
nationalityList,
@ -28,23 +47,6 @@ export default function KonamiSnowfall({
setImages(imagesTemp)
}, [nationalityList])
const NationalityDisplay = ({
nationality,
}: Readonly<{ nationality: string }>) => {
const nationalityData = nationalities[nationality]
const { demonym, flag } = nationalityData
return (
<div className='flex items-center'>
<img
src={flag}
className='w-10 shadow-md shadow-slate-300'
alt={`${demonym} flag`}
/>
<span className='mx-3 font-semibold'>{demonym}</span>
</div>
)
}
return (
<>
<Konami action={handleKonami} />

View file

@ -93,12 +93,7 @@ export const Authors = ({
)
}
export const Reviewers = ({
reviewers,
showTitle = true,
}: Readonly<{ reviewers: reviewer[] | undefined; showTitle?: boolean }>) => {
if (!reviewers) return null
const ReviewerDisplay = ({ r }: Readonly<{ r: reviewer }>) => {
const ReviewerDisplay = ({ r }: Readonly<{ r: reviewer }>) => {
if (r.profile) {
return (
<Link href={`/author/${r.profile}`} target='_blank'>
@ -118,7 +113,13 @@ export const Reviewers = ({
{r.first} {r.last}
</span>
)
}
}
export const Reviewers = ({
reviewers,
showTitle = true,
}: Readonly<{ reviewers: reviewer[] | undefined; showTitle?: boolean }>) => {
if (!reviewers) return null
return (
<>

View file

@ -1,4 +1,4 @@
// these variants of the data display compnents are designed for client side components
// these variants of the data display components are designed for client side components
// and fetch data asynchronously
import { loadAllTopics, loadAllAuthors } from '@/app/db/loaders'
import { useSuspenseQuery } from '@tanstack/react-query'

View file

@ -13,9 +13,8 @@ const DocumentCard = ({ doc, href }: { doc: Document; href: string }) => {
const { title, authors, topics, dates, status, type } = manifest
return (
<Link href={href} className='no-link-style'>
<div
className={`${cardEffects['card-large']} border-4 rounded-lg border-gray-300 hover:border-blue-500 p-5 my-4 w-full cursor-pointer shadow-slate-300 shadow-md`}
role='button' // this is a critical DEI concern as we have marked this element as a button with ARIA role, yet we have not supported button accessiblity features
<button
className={`${cardEffects['card-large']} border-4 rounded-lg border-gray-300 hover:border-blue-500 p-5 my-4 w-full cursor-pointer shadow-slate-300 shadow-md text-left`}
>
<h2 className={`${zillaSlab.className} text-3xl`}>{title}</h2>
<p className='text-slate-500 py-2 text-md mt-2'>
@ -34,7 +33,7 @@ const DocumentCard = ({ doc, href }: { doc: Document; href: string }) => {
<p className='py-2 text-md text-slate-700 font-serif text-lg text-balance'>
{abstract.substring(0, 500) + (abstract.length > 500 ? '...' : '')}
</p>
</div>
</button>
</Link>
)
}

View file

@ -2,7 +2,7 @@ import styles from './loading.module.css'
const LoadingBar = () => {
return (
<div className='w-full fixed top-0 left-0'>
<div className='h-1.5 w-full bg-pink-100 overflow-hidden'>
<div className='h-1.5 w-full bg-blue-100 overflow-hidden'>
<div
className={`${styles.progress} w-full h-full bg-blue-500 ${styles['left-right']}`}
></div>

View file

@ -55,7 +55,7 @@ export default function MobileMenu() {
>
open-source contributors
</a>
.
{'.'}
</p>
</div>
</>

View file

@ -1,4 +1,3 @@
import styles from './container.module.css'
/**
* Renders a container component with the specified width, containing the provided children.
*
@ -8,9 +7,5 @@ import styles from './container.module.css'
export default function Container({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<div className={`${styles.container} pb-10 px-5 max-w-[1200px] mx-auto`}>
{children}
</div>
)
return <div className={`pb-10 px-5 max-w-[1200px] mx-auto`}>{children}</div>
}

View file

@ -1,11 +0,0 @@
/* @media only screen and (min-width: 48em) {
.container {
min-height: calc(100vh - 400px);
}
}
@media only screen and (max-width: 48em) {
.container {
min-height: 400px;
}
} */

View file

@ -366,7 +366,7 @@ On Day 1 we will discuss the ins and outs of the robot. The Electrical Sub team
'cifar 10',
'distance based cost',
'computer vision foundation',
'study of cost smoothnes',
'study of cost smoothness',
'adversarial attacks',
],
latest: 1,
@ -416,7 +416,7 @@ export const topics: Readonly<{ [key: string]: Topic }> = {
eecs: {
name: 'Electrical Engineering and Computer Science',
description:
'Electrical engineering and computer science are fields that combine engineering, science, and computing. The acronym EECS is derived from ther world-renowned electrical engineering and computer science program at the University of California, Berkeley.',
'Electrical engineering and computer science are fields that combine engineering, science, and computing. The acronym EECS is derived from their world-renowned electrical engineering and computer science program at the University of California, Berkeley.',
wiki: 'https://en.wikipedia.org/wiki/Computer_science_and_engineering',
},
ai: {
@ -453,7 +453,7 @@ authorName (as a slug): {
image: image url, can store in public/eexiv/img/profiles or link to a web resource
nationality: an array of ISO 3 letter country codes corresponding to your nationalities or ethniciities
nationality: an array of ISO 3 letter country codes corresponding to your nationalities
formerAffiliations: an array of former affiliation "slugs." they should also correspond to affiliations
in the affiliations data
@ -543,7 +543,7 @@ export const authors: Readonly<{ [key: string]: Author }> = {
},
affiliation: ['Vision Researcher@1280-eecs', 'Student@srvhs'],
image: '/img/profiles/gostler.jpg',
nationality: ['usa'],
nationality: ['fra', 'usa'],
website: 'https://github.com/gavinostler',
bio: `I'm Gavin, a high school student from the Bay Area. I am a fullstack developer and love making random things to fill my day. I'm interested in creating useful tools and software in the future.`,
},
@ -884,7 +884,7 @@ Raid Zero's influence extends beyond the technical achievements in robotics comp
name: `Team 1280, the Ragin' C-Biscuits`,
short: 'Team 1280',
image: '/img/logos/1280-main.png',
description: `We are the San Ramon Valley High School Robotics Team (FRC Team 1280) and we have been competing in the FIRST Robotics Challenge for 16 years. With just 6 weeks to design, build, program, and fundraise for a robot, FRC teaches us teamwork, business, engineering, machinery, and computer design. We are a team of over 50 students with 1 full time mentor, 2 part time mentors, and 1 staff liason.
description: `We are the San Ramon Valley High School Robotics Team (FRC Team 1280) and we have been competing in the FIRST Robotics Challenge for 16 years. With just 6 weeks to design, build, program, and fundraise for a robot, FRC teaches us teamwork, business, engineering, machinery, and computer design. We are a team of over 50 students with 1 full time mentor, 2 part time mentors, and 1 staff liaison.
[linebreak]
Throughout our FRC career, we have won several regional events and numerous awards including: the Rookie Inspiration Award, both the Radio Shack and Rockwell Automation Innovation in Control Awards, the Imagery Award, the Engineering Excellence Award, and the Creativity Award. While we do focus on the competitive aspect of robotics, we also strive to spread the knowledge of STEM through our outreach programs to those who might not otherwise have access to these opportunities.
[linebreak]

View file

@ -23,7 +23,7 @@ const checkIsStringArray = (data: unknown): data is string[] => {
onmessage = (e) => {
let authorIds: string[] = []
checkIsStringArray(e.data) && (authorIds = e.data as string[])
checkIsStringArray(e.data) && (authorIds = e.data)
let results = getAuthorsById(authorIds)
postMessage(results)

View file

@ -1,4 +1,4 @@
/* stylesheet for the eexiv UI and the base layout (search, logo, header, footer) */
/* stylesheet for the eeXiv UI and the base layout (search, logo, header, footer) */
.header {
width: 100%;
@ -35,7 +35,6 @@
.footerContent {
width: 100%;
height: 150px;
padding: 10px;
background-color: #c4840c;
color: white;

View file

@ -9,6 +9,7 @@ import MobileMenu from './components/MobileMenu'
import { ToastContainer } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
import Providers from './providers'
import Image from 'next/legacy/image'
/* The default font is Inter. If you want to use Zilla Slab (or any other Google Font,
which are pre-provided by Next.js in the 'next/font/google' module), you need to
@ -37,8 +38,11 @@ export default function RootLayout({
<div className={styles.header}>
<div className='max-w-[1200px] flex flex-nowrap mx-auto justify-between items-center'>
<Link href='/affiliation/1280-eecs'>
<img
className='h-[100px] mt-4'
<Image
className='mt-4'
layout='intrinsic'
width={244}
height={100}
src='/img/logos/eecs-wordmark.png'
alt='EECS'
/>
@ -52,7 +56,7 @@ export default function RootLayout({
>
open-source contributors
</a>
.
{'.'}
</p>
</div>
</div>

View file

@ -1,5 +1,11 @@
import Link from 'next/link'
import { documents, authors, affiliations, Author } from './db/data'
import {
documents,
authors,
affiliations,
Author,
Affiliation,
} from './db/data'
import News from './components/News'
import RandomDocs from './components/RandomDocs'
import RecentDocuments from './components/RecentDocuments'
@ -35,19 +41,19 @@ function sortAuthorsByDocumentsPublished(authors: {
return authorsWithId.map(({ id, author }) => ({ id, author }))
}
export default function Home() {
const AuthorDisplay = () => {
let i = 0
interface AuthorDisplayProps {
authors: { [key: string]: Author }
affiliations: { [key: string]: Affiliation }
}
const AuthorDisplay = ({ authors, affiliations }: AuthorDisplayProps) => {
return (
<ol className='list-decimal pl-4 space-y-2'>
{sortAuthorsByDocumentsPublished(authors).map(({ id, author }) => {
{sortAuthorsByDocumentsPublished(authors)
.slice(0, 10)
.map(({ id, author }) => {
let data = author
let affiliationSlug = data.affiliation[0].split('@')[1]
let affiliation = affiliations[affiliationSlug]
i++
if (i > 10) return
return (
<li key={id}>
<Link href={`/author/${id}`}>
@ -64,8 +70,9 @@ export default function Home() {
})}
</ol>
)
}
}
export default function Home() {
return (
<div className='text-slate-800 flex flex-wrap md:flex-row justify-center'>
<p className='font-serif text-lg basis-full md:basis-1/2 grow mr-1 text-balance'>
@ -101,7 +108,7 @@ export default function Home() {
<div className='font-serif text-xl'>
Our esteemed faculty and alumni (ranked by research output)
</div>
<AuthorDisplay />
<AuthorDisplay authors={authors} affiliations={affiliations} />
</div>
</div>
)

View file

@ -1,10 +1,14 @@
'use client'
import { useState } from 'react'
import { useMemo } from 'react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
export default function Providers({ children }) {
const [queryClient] = useState(
type ProvidersProps = {
children: React.ReactNode
}
export default function Providers({ children }: Readonly<ProvidersProps>) {
const queryClient = useMemo(
() =>
new QueryClient({
defaultOptions: {
@ -12,7 +16,8 @@ export default function Providers({ children }) {
staleTime: 60 * 1000,
},
},
})
}),
[]
)
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>

View file

@ -32,7 +32,7 @@ const SearchResult = ({
this click handling logic simply checks to see if the element clicked is a nested link
and fires a redirect if not, to avoid overriding links in the children
*/
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
let target = event.target as HTMLElement
while (target != null) {
if (target.nodeName === 'A') {
@ -44,10 +44,10 @@ const SearchResult = ({
}
return (
<div
className={`${cardEffects['card-large']} border-4 rounded-lg border-gray-300 hover:border-blue-500 p-5 my-4 w-full cursor-pointer`}
<button
className={`${cardEffects['card-large']} border-4 rounded-lg border-gray-300 hover:border-blue-500 p-5 my-4 w-full cursor-pointer text-left`}
onClick={handleClick}
role='button' // this is a critical DEI concern as we have marked this element as a button with ARIA role, yet we have not supported button accessiblity features
type='button'
>
<h2 className={`${zillaSlab.className} text-3xl`}>{title}</h2>
<p className='text-slate-500 py-2 text-md mt-2'>
@ -66,7 +66,7 @@ const SearchResult = ({
<p className='py-2 text-md text-slate-700 font-serif text-lg text-balance'>
{abstract.substring(0, 500) + (abstract.length > 500 ? '...' : '')}
</p>
</div>
</button>
)
}

View file

@ -2,7 +2,6 @@
.card-large {
@apply shadow-sm shadow-slate-300;
/* box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); */
transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
position: relative;
}
@ -29,7 +28,6 @@
.card-small {
@apply shadow-sm shadow-slate-300;
/* box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); */
transition: all 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
position: relative;
}

View file

@ -1,18 +1,30 @@
import React from 'react'
import { notFound } from 'next/navigation'
export default class ErrorBoundary extends React.Component {
constructor(props) {
interface ErrorBoundaryProps {
children: React.ReactNode
}
interface ErrorBoundaryState {
hasError: boolean
error: Error | null
}
export default class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
constructor(props: ErrorBoundaryProps) {
super(props)
this.state = { hasError: false, error: null }
}
static getDerivedStateFromError(error) {
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
// Update state so the next render will show the fallback UI.
return { hasError: true, error }
}
componentDidCatch(error, errorInfo) {
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
// You can also log the error to an error reporting service
console.error('Error caught by Error Boundary:', error, errorInfo)
}
@ -20,7 +32,7 @@ export default class ErrorBoundary extends React.Component {
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
if (this.state.error.message === '404') notFound()
if (this.state.error?.message === '404') notFound()
return <h1>Something went wrong.</h1>
}

View file

@ -30,12 +30,7 @@ export default function searchDocs(
worker.postMessage(query)
} else {
reject(
new Error(
`Web Workers are not supported in this environment. Please avoid using a prehistoric browser.
If nothing else seems wrong, this error message is probably showing up due to ghosts in your browser.`
)
)
return
}
})
}

View file

@ -1,3 +1,4 @@
// Youwen brainrot
export default function string2hex(str: string): string {
// Hash function to convert string to a number
let hash = 0