feat(preact): migrate react to lightweight preact

This commit is contained in:
Vrezh Fedora 2025-02-23 20:10:11 +01:00
parent 53efb5d87d
commit fc07f4989a
9 changed files with 2924 additions and 1705 deletions

View file

@ -2,7 +2,7 @@
import { defineConfig } from 'astro/config'
import tailwind from '@astrojs/tailwind'
import react from '@astrojs/react'
import preact from '@astrojs/preact'
import sitemap from '@astrojs/sitemap'
@ -10,7 +10,7 @@ import sitemap from '@astrojs/sitemap'
export default defineConfig({
integrations: [
tailwind(),
react(),
preact({ compat: true }),
sitemap({
// TODO: Maybe? Maybe not?
// filter: (page) => !page.includes('mods/'),

4558
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -10,10 +10,14 @@
"wrangler": "wrangler",
"astro": "astro"
},
"overrides": {
"react": "npm:@preact/compat@latest",
"react-dom": "npm:@preact/compat@latest"
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/cloudflare": "^12.2.1",
"@astrojs/react": "^4.2.0",
"@astrojs/preact": "^4.0.4",
"@astrojs/rss": "^4.0.11",
"@astrojs/sitemap": "^3.2.1",
"@astrojs/tailwind": "^6.0.0",
@ -21,8 +25,6 @@
"@fortawesome/fontawesome-svg-core": "^6.7.1",
"@fortawesome/free-brands-svg-icons": "^6.7.1",
"@fortawesome/free-solid-svg-icons": "^6.7.1",
"@types/react": "^19.0.1",
"@types/react-dom": "^19.0.2",
"astro": "^5.3.0",
"astro-navbar": "^2.3.7",
"autoprefixer": "10.4.14",
@ -32,11 +34,10 @@
"lucide-react": "^0.475.0",
"motion": "^11.13.5",
"postcss": "^8.5.1",
"preact": "^10.26.2",
"prettier": "^3.3.3",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.6.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"sharp": "^0.33.5",
"tailwindcss": "^3.4.15",
"typescript": "^5.6.3"

View file

@ -1,9 +1,9 @@
import React, { useState } from 'react'
import { useState } from 'preact/hooks'
import MyLogo from './Mylogo'
import { Menu } from 'lucide-react'
import ThemeSwitch from './ThemeSwitch/ThemeSwitch'
const MobileNavbar: React.FC = () => {
const MobileNavbar = () => {
const [isMenuOpen, setMenuOpen] = useState(false)
const menuTransformClass = isMenuOpen ? 'translate-x-0' : 'translate-x-full'

View file

@ -1,5 +1,4 @@
import type React from 'react'
import { useState, useEffect } from 'react'
import { useState, useEffect } from 'preact/hooks'
import type { ZenTheme } from '../mods'
import { library, icon } from '@fortawesome/fontawesome-svg-core'
import { faSort, faSortUp, faSortDown } from '@fortawesome/free-solid-svg-icons'
@ -48,15 +47,17 @@ export default function ModsList({ mods }: ModsListProps) {
return defaultSortIcon
}
function handleSearch(e: React.ChangeEvent<HTMLInputElement>) {
setSearch(e.target.value)
function handleSearch(e: Event) {
const target = e.target as HTMLInputElement
setSearch(target.value)
}
function handleLimitChange(e: React.ChangeEvent<HTMLSelectElement>) {
setLimit(Number.parseInt(e.target.value, 10))
function handleLimitChange(e: Event) {
const target = e.target as HTMLSelectElement
setLimit(Number.parseInt(target.value, 10))
}
function handlePageSubmit(e: React.FormEvent) {
function handlePageSubmit(e: Event) {
e.preventDefault()
const newPage = Number.parseInt(pageInput, 10)
if (!Number.isNaN(newPage) && newPage >= 1 && newPage <= totalPages) {
@ -67,27 +68,24 @@ export default function ModsList({ mods }: ModsListProps) {
}
}
function handlePageInputChange(e: React.ChangeEvent<HTMLInputElement>) {
setPageInput(e.target.value)
function handlePageInputChange(e: Event) {
const target = e.target as HTMLInputElement
setPageInput(target.value)
}
function getPageUrl(pageNum: number) {
const params = new URLSearchParams(searchParams)
if (pageNum > 1) {
params.set('page', pageNum.toString())
} else {
params.delete('page')
}
const queryString = params.toString()
return `/mods${queryString ? `?${queryString}` : ''}`
}
function renderPagination() {
if (totalPages <= 1) return null
// Render page input for larger page counts
return (
<div className="mx-auto mb-12 flex items-center justify-center gap-4 px-8">
<a
@ -105,7 +103,7 @@ export default function ModsList({ mods }: ModsListProps) {
<input
type="text"
value={pageInput}
onChange={handlePageInputChange}
onInput={handlePageInputChange}
className="w-16 rounded border border-dark bg-transparent px-2 py-1 text-center text-sm"
aria-label="Page number"
/>
@ -137,7 +135,7 @@ export default function ModsList({ mods }: ModsListProps) {
className="w-full rounded-full border-2 border-dark bg-transparent px-6 py-2 text-lg outline-none"
placeholder="Type to search..."
value={search}
onChange={handleSearch}
onInput={handleSearch}
/>
</div>
@ -179,7 +177,7 @@ export default function ModsList({ mods }: ModsListProps) {
<select
id="limit"
value={limit}
onChange={handleLimitChange}
onInput={handleLimitChange}
className="rounded border border-dark bg-transparent px-2 py-1 text-sm [&>option]:text-black"
>
<option value="12">12</option>

View file

@ -1,10 +1,8 @@
import React from 'react'
interface MyLogoProps {
className?: string
}
const MyLogo: React.FC<MyLogoProps> = ({ className }) => (
const MyLogo = ({ className }: MyLogoProps) => (
<svg
className={className}
width="32"

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import { useEffect, useState } from 'preact/hooks'
import './index.css'
interface Props {
@ -6,8 +6,8 @@ interface Props {
className?: string
}
const ThemeSwitch: React.FC<Props> = ({ label, className }) => {
const [isLight, setIsLight] = useState<boolean>(() => {
const ThemeSwitch = ({ label, className = '' }: Props) => {
const [isLight, setIsLight] = useState(() => {
if (typeof window !== 'undefined') {
return localStorage.getItem('theme') === 'light'
}
@ -43,7 +43,7 @@ const ThemeSwitch: React.FC<Props> = ({ label, className }) => {
<path
d="M12 9c1.654 0 3 1.346 3 3s-1.346 3-3 3-3-1.346-3-3 1.346-3 3-3zm0-2c-2.762 0-5 2.238-5 5s2.238 5 5 5 5-2.238 5-5-2.238-5-5-5zm-4.184-.599l-3.593-3.594-1.415 1.414 3.595 3.595c.401-.537.876-1.013 1.413-1.415zm4.184-1.401c.34 0 .672.033 1 .08v-5.08h-2v5.08c.328-.047.66-.08 1-.08zm5.598 2.815l3.595-3.595-1.414-1.414-3.595 3.595c.537.402 1.012.878 1.414 1.414zm-12.598 4.185c0-.34.033-.672.08-1h-5.08v2h5.08c-.047-.328-.08-.66-.08-1zm11.185 5.598l3.594 3.593 1.415-1.414-3.594-3.593c-.403.536-.879 1.012-1.415 1.414zm-9.784-1.414l-3.593 3.593 1.414 1.414 3.593-3.593c-.536-.402-1.011-.877-1.414-1.414zm12.519-5.184c.047.328.08.66.08 1s-.033.672-.08 1h5.08v-2h-5.08zm-6.92 8c-.34 0-.672-.033-1-.08v5.08h2v-5.08c-.328.047-.66.08-1 .08z"
fill="currentColor"
></path>
/>
</svg>
<svg
className="ac-theme-switch-icon ac-theme-switch-icon--light"
@ -52,7 +52,7 @@ const ThemeSwitch: React.FC<Props> = ({ label, className }) => {
<path
d="M10.719 2.082c-2.572 2.028-4.719 5.212-4.719 9.918 0 4.569 1.938 7.798 4.548 9.895-4.829-.705-8.548-4.874-8.548-9.895 0-5.08 3.808-9.288 8.719-9.918zm1.281-2.082c-6.617 0-12 5.383-12 12s5.383 12 12 12c1.894 0 3.87-.333 5.37-1.179-3.453-.613-9.37-3.367-9.37-10.821 0-7.555 6.422-10.317 9.37-10.821-1.74-.682-3.476-1.179-5.37-1.179zm0 10.999c1.437.438 2.562 1.564 2.999 3.001.44-1.437 1.565-2.562 3.001-3-1.436-.439-2.561-1.563-3.001-3-.437 1.436-1.562 2.561-2.999 2.999zm8.001.001c.958.293 1.707 1.042 2 2.001.291-.959 1.042-1.709 1.999-2.001-.957-.292-1.707-1.042-2-2-.293.958-1.042 1.708-1.999 2zm-1-9c-.437 1.437-1.563 2.562-2.998 3.001 1.438.44 2.561 1.564 3.001 3.002.437-1.438 1.563-2.563 2.996-3.002-1.433-.437-2.559-1.564-2.999-3.001z"
fill="currentColor"
></path>
/>
</svg>
{label ? (
<span className="ac-theme-switch-label">{label}</span>

View file

@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'
import { useEffect, useState } from 'preact/hooks'
import type { ZenTheme } from '../mods'
type SortOrder = 'default' | 'asc' | 'desc'
@ -70,7 +70,9 @@ export function useModsSearch(mods: ZenTheme[]) {
searchParams.delete('limit')
}
const newUrl = `${window.location.pathname}${searchParams.toString() ? `?${searchParams.toString()}` : ''}`
const newUrl = `${window.location.pathname}${
searchParams.toString() ? `?${searchParams.toString()}` : ''
}`
window.history.replaceState({}, '', newUrl)
}, [state, searchParams])

View file

@ -2,6 +2,6 @@
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react"
"jsxImportSource": "preact"
}
}