diff --git a/bun.lockb b/bun.lockb index 29a569c..6815fcd 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/index.html b/index.html index f7afd88..cb1b53f 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,7 @@ + Minesweeper diff --git a/package.json b/package.json index a64205a..3fe4ab9 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "tailwind-merge": "^2.5.2", "tailwindcss": "^4.0.0-alpha.24", "use-sound": "^4.0.3", + "vite-imagetools": "^7.0.4", "wouter": "^3.3.5", "zod": "^3.23.8", "zustand": "^4.5.5" diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/src/Shell.tsx b/src/Shell.tsx index 1431f9a..587fd36 100644 --- a/src/Shell.tsx +++ b/src/Shell.tsx @@ -48,11 +48,11 @@ const Shell: React.FC = ({ children }) => { transition={{ type: "tween" }} >
-

- Minesweeper -
+

Business -

+
+ Minesweeper +
@@ -82,6 +82,7 @@ const Shell: React.FC = ({ children }) => { className="absolute left-4 bg-black border-white/10 border-y-1 border-r-1 rounded-l-none" variant="ghost" onClick={() => setIsOpen((isOpen) => !isOpen)} + aria-label="Menu" > diff --git a/src/components/Auth/LoginButton.tsx b/src/components/Auth/LoginButton.tsx index 7acbee6..66b1c23 100644 --- a/src/components/Auth/LoginButton.tsx +++ b/src/components/Auth/LoginButton.tsx @@ -61,9 +61,9 @@ const LoginButton = () => { .then(async (res) => { setToken(res.token); await wsClient.dispatch("user.loginWithToken", { - token: JSON.parse(res.token), + token: res.token, }); - queryClient.invalidateQueries(); + await queryClient.resetQueries(); }) .catch((e) => { setError(e); diff --git a/src/components/Auth/RegisterButton.tsx b/src/components/Auth/RegisterButton.tsx index 6936842..a0cc880 100644 --- a/src/components/Auth/RegisterButton.tsx +++ b/src/components/Auth/RegisterButton.tsx @@ -61,9 +61,9 @@ const RegisterButton = () => { .then(async (res) => { setToken(res.token); await wsClient.dispatch("user.loginWithToken", { - token: JSON.parse(res.token), + token: res.token, }); - queryClient.invalidateQueries(); + await queryClient.resetQueries(); }) .catch((e) => { setError(e); diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 805b955..e4fd70c 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -12,13 +12,17 @@ import LoginButton from "./Auth/LoginButton"; import { useWSMutation, useWSQuery } from "../hooks"; import RegisterButton from "./Auth/RegisterButton"; import { useQueryClient } from "@tanstack/react-query"; +import { useAtom } from "jotai"; +import { loginTokenAtom } from "../atoms"; const Header = () => { const [, setLocation] = useLocation(); const { data: username } = useWSQuery("user.getSelf", null); const queryClient = useQueryClient(); + const [, setToken] = useAtom(loginTokenAtom); const logout = useWSMutation("user.logout", () => { - queryClient.invalidateQueries(); + setToken(undefined); + queryClient.resetQueries(); }); return ( diff --git a/src/views/home/Home.tsx b/src/views/home/Home.tsx index 97bdb6d..5d6072f 100644 --- a/src/views/home/Home.tsx +++ b/src/views/home/Home.tsx @@ -4,9 +4,9 @@ import { useWSQuery } from "../../hooks"; import { Tag } from "../../components/Tag"; import RegisterButton from "../../components/Auth/RegisterButton"; import { Button } from "../../components/Button"; -import defusing from "../../assets/illustrations/defusing.png"; -import lootbox1 from "../../assets/illustrations/lootbox1.png"; -import mine from "../../assets/illustrations/mine.png"; +import defusing from "../../assets/illustrations/defusing.png?aspect=4:3&w=100;200;300;400&format=webp&quality=100&as=metadata"; +import lootbox1 from "../../assets/illustrations/lootbox1.png?aspect=1:1&w=100;200;300;400&format=webp&quality=100&as=metadata"; +import mine from "../../assets/illustrations/mine.png?aspect=1:1&w=100;200;300;400&format=webp&quality=100&as=metadata"; import Section from "./Section"; import Hr from "../../components/Hr"; import { Link } from "wouter"; diff --git a/src/views/home/Section.tsx b/src/views/home/Section.tsx index 8fa7eab..ad0cd5e 100644 --- a/src/views/home/Section.tsx +++ b/src/views/home/Section.tsx @@ -5,17 +5,30 @@ import { useScroll, useTransform, } from "framer-motion"; -import { useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import { cn } from "../../lib/utils"; interface SectionProps { text: string; - image: string; + image: OutputMetadata[]; left?: boolean; } const Section = ({ text, image, left }: SectionProps) => { const ref = useRef(null); + const wrapperRef = useRef(null); + const [width, setWidth] = useState(0); + useEffect(() => { + const resizeObserver = new ResizeObserver(() => { + if (wrapperRef.current) { + setWidth(wrapperRef.current.clientWidth); + } + }); + if (wrapperRef.current) { + resizeObserver.observe(wrapperRef.current); + } + return () => resizeObserver.disconnect(); + }, []); const { scrollYProgress } = useScroll({ target: ref, }); @@ -44,18 +57,29 @@ const Section = ({ text, image, left }: SectionProps) => { ease: "easeInOut", }} > - + className="h-[80%] min-h-36" + > + `${i.src} ${i.width}w`).join(", ")} + sizes={`${width}px`} + loading="lazy" + className="h-[80%]" + /> +
); diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 11f02fe..6a17aa3 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1 +1,27 @@ /// + +interface OutputMetadata { + src: string; // URL of the generated image + width: number; // Width of the image + height: number; // Height of the image + format: string; // Format of the generated image + + // The following options are the same as sharps input options + space: string; // Name of colour space interpretation + channels: number; // Number of bands e.g. 3 for sRGB, 4 for CMYK + density: number; // Number of pixels per inch + depth: string; // Name of pixel depth format + hasAlpha: boolean; // presence of an alpha transparency channel + hasProfile: boolean; // presence of an embedded ICC profile + isProgressive: boolean; // indicating whether the image is interlaced using a progressive scan +} + +declare module "*&as=metadata" { + const outputs: OutputMetadata[]; + export default outputs; +} + +declare module "*?as=metadata" { + const outputs: OutputMetadata[]; + export default outputs; +} diff --git a/vite.config.ts b/vite.config.ts index 50bf145..9163aca 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,8 +1,9 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react-swc"; import tailwindcss from "@tailwindcss/vite"; +import { imagetools } from "vite-imagetools"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react(), tailwindcss()], + plugins: [react(), tailwindcss(), imagetools()], });