Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"typesafe-i18n": "typesafe-i18n",
"format": "biome format --write ./src",
"lint": "biome lint --fix && eslint --fix \"./src/**/*.{ts,tsx}\"",
"test:browser": "vitest"
"test:browser": "vitest --run"
},
"dependencies": {
"@radix-ui/react-dialog": "1.0.5",
Expand All @@ -28,7 +28,6 @@
"@radix-ui/react-visually-hidden": "1.0.3",
"@tanstack/react-query": "5.38.0",
"@tanstack/react-router": "^1.121.2",
"@tanstack/react-router-devtools": "^1.121.2",
"canvas-confetti": "^1.9.3",
"clsx": "2.1.1",
"dompurify": "3.1.4",
Expand All @@ -52,6 +51,7 @@
"@tailwindcss/container-queries": "0.1.1",
"@tanstack/eslint-plugin-query": "^5.35.6",
"@tanstack/react-query-devtools": "^5.38.0",
"@tanstack/react-router-devtools": "^1.121.2",
"@tanstack/router-cli": "^1.128.8",
"@tanstack/router-plugin": "^1.128.8",
"@total-typescript/ts-reset": "0.6.1",
Expand Down
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/achievements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ const init = {} as Record<
(typeof ACHIEVEMENTS_LIST)[number]["id"] | (string & {}),
() => boolean
>;
export const achivementConditionCheckByIdMap = ACHIEVEMENTS_LIST.reduce((acc, achievement) => {
export const achievementConditionCheckByIdMap = ACHIEVEMENTS_LIST.reduce((acc, achievement) => {
acc[achievement.id] = achievement.conditionCheck.bind(achievement);
return acc;
}, init);
18 changes: 14 additions & 4 deletions src/components/AppProviders.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as Portal from "@radix-ui/react-portal";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { createRouter, RouterProvider } from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
import { lazy, Suspense } from "react";
import type React from "react";
import { Toaster } from "react-hot-toast";

Expand All @@ -13,6 +12,13 @@ import { StopwatchContextProvider } from "./StopwatchContext";
import { ThemeContextProvider } from "./ThemeContext";
import { TooltipProvider } from "./Tooltip";

const ReactQueryDevtools = import.meta.env.DEV
? lazy(() => import("@tanstack/react-query-devtools").then((m) => ({ default: m.ReactQueryDevtools })))
: null;
const TanStackRouterDevtools = import.meta.env.DEV
? lazy(() => import("@tanstack/react-router-devtools").then((m) => ({ default: m.TanStackRouterDevtools })))
: null;

export const queryClient = new QueryClient({
defaultOptions: {
queries: {
Expand Down Expand Up @@ -50,8 +56,12 @@ export const AppProviders = () => {
}}
/>
</Portal.Root>
<ReactQueryDevtools initialIsOpen={false} />
<TanStackRouterDevtools router={router} />
{ReactQueryDevtools && TanStackRouterDevtools && (
<Suspense fallback={null}>
<ReactQueryDevtools initialIsOpen={false} />
<TanStackRouterDevtools router={router} />
</Suspense>
)}
</QueryClientProvider>
</TooltipProvider>
</StopwatchContextProvider>
Expand Down
6 changes: 2 additions & 4 deletions src/components/ResultDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as Dialog from "@radix-ui/react-dialog";
import * as Portal from "@radix-ui/react-portal";
import { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { useResetGame } from "../hooks/useResetGame";
import { useI18nContext } from "../i18n/i18n-react";
import {
Expand All @@ -12,6 +11,7 @@ import {
useIsWin,
useStartingArticle,
} from "../stores/GameStore";
import { copyNotification } from "../utils/toast";
import { ModalContent, ModalDescription, ModalRoot, ModalTitle, ModalTrigger } from "./Modal";
import { StartArrowEnd } from "./StartArrowEnd";
import { StopwatchDisplay } from "./StopwatchDisplay";
Expand All @@ -31,8 +31,6 @@ export const ResultDialog = () => {
const cheatingAttempts = useCheatingAttempts();
const missedWins = history.slice(0, -2).reduce((acc, el) => acc + el.winningLinks, 0);

const copyNotification = () => toast.success(LL["Copied to clipboard"](), { position: "top-center" });

useEffect(() => {
setOpen(isWin);
}, [isWin]);
Expand Down Expand Up @@ -83,7 +81,7 @@ export const ResultDialog = () => {
className="border-b-[1px] border-b-transparent hover:border-b-primary-blue focus-visible:border-b-primary-blue"
onClick={async () => {
await navigator.clipboard.writeText(window.location.href);
copyNotification();
copyNotification(LL["Copied to clipboard"]());
}}
>
{LL["Share Result"]()}
Expand Down
18 changes: 8 additions & 10 deletions src/components/Settings.helpers.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { useEffect } from "react";
import { toast } from "react-hot-toast";
import type { Article } from "../stores/GameStore";
import { useSettingsStoreActions } from "../stores/SettingsStore";
import { errorToast } from "../utils/toast";
import type { WikiRandom } from "./RandomButton/RandomButton.types";

export const getHighestLinksPage = (data: WikiRandom) => {
if (!data.query?.pages) return;
const highestLinksPage = Object.values(data.query.pages)
.filter((page) => Object.hasOwn(page, "linkshere"))
.reduce((prev, current) => {
const previousLinksphere = prev.linkshere ?? [];
const currentLinksphere = current.linkshere ?? [];
return previousLinksphere.length > currentLinksphere.length ? prev : current;
});
const pagesWithLinks = Object.values(data.query.pages).filter((page) => Object.hasOwn(page, "linkshere"));
if (pagesWithLinks.length === 0) return;
const highestLinksPage = pagesWithLinks.reduce((prev, current) => {
const previousLinksphere = prev.linkshere ?? [];
const currentLinksphere = current.linkshere ?? [];
return previousLinksphere.length > currentLinksphere.length ? prev : current;
});

const title = highestLinksPage.title;
const pageid = highestLinksPage.pageid;
Expand Down Expand Up @@ -47,8 +47,6 @@ interface RandomSuccessProps {
failText: string;
}

const errorToast = (text: string) => toast.error(text, { position: "bottom-center" });

export const handleOnRandomSuccess = ({ setArticle, data, failText }: RandomSuccessProps) => {
const articleWithLinks = getHighestLinksPage(data);
if (!articleWithLinks?.title || articleWithLinks.title.includes("(disambiguation)")) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ThemeContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const ThemeContext = React.createContext<ThemeContext | null>(null);

export const ThemeContextProvider = ({ children }: { children: React.ReactNode }) => {
const defaultDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const [colorMode, setTheme] = useLocalStorage("theme", defaultDark ? "dark" : "light");
const [colorMode, setTheme] = useLocalStorage("color-theme", defaultDark ? "dark" : "light");

const switchTheme = () => {
const newTheme = colorMode === "light" ? "dark" : "light";
Expand Down
3 changes: 1 addition & 2 deletions src/components/Wiki/Wiki.utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { useCallback, useEffect } from "react";
import { toast } from "react-hot-toast";
import { useI18nContext } from "../../i18n/i18n-react";
import { useGameStoreActions, useIsGameRunning } from "../../stores/GameStore";
import { useIsCtrlFEnabled } from "../../stores/SettingsStore";
import { errorToast } from "../../utils/toast";

const errorToast = (text: string) => toast.error(text, { position: "bottom-center" });
const isNotDev = process.env.NODE_ENV !== "development";

export const useNoCheating = () => {
Expand Down
4 changes: 1 addition & 3 deletions src/components/Wiki/WikiLogic.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { useNavigate } from "@tanstack/react-router";
import type { MouseEvent } from "react";
import { toast } from "react-hot-toast";
import { useI18nContext } from "../../i18n/i18n-react";
import { useGameStoreActions } from "../../stores/GameStore";
import { errorToast } from "../../utils/toast";
import { useStopwatchActions } from "../StopwatchContext";

const errorToast = (text: string) => toast.error(text, { position: "bottom-center" });

const IMAGE_EXT = [".jpg", ".jpeg", ".png", ".webp", ".avif", ".svg"];

const handleShowHideButton = (e: MouseEvent<HTMLDivElement>) => {
Expand Down
8 changes: 4 additions & 4 deletions src/components/WikiLanguageSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const LANGUAGES: readonly WikiLanguage[] = [
{ value: "arz", label: "مصرى", isoCode: "" },
{ value: "pl", label: "Polski", isoCode: "pl" },
{ value: "ja", label: "日本語", isoCode: "jp" },
{ value: "zh", label: "中国人", isoCode: "cn" },
{ value: "zh", label: "中文", isoCode: "zh" },
{ value: "vi", label: "Tiếng Việt", isoCode: "vi" },
{ value: "war", label: "Winaray", isoCode: "" },
{ value: "uk", label: "українська", isoCode: "" },
Expand Down Expand Up @@ -119,7 +119,7 @@ export const LANGUAGES: readonly WikiLanguage[] = [
{ label: "dansk", value: "da", isoCode: "" },
{ label: "български", value: "bg", isoCode: "" },
{ label: "Cymraeg", value: "cy", isoCode: "" },
{ label: "slovenčina", value: "sk ", isoCode: "" },
{ label: "slovenčina", value: "sk", isoCode: "" },
{ label: "تۆرکجه", value: "azb", isoCode: "" },
{ label: "eesti", value: "et", isoCode: "" },
{ label: "қазақша", value: "kk", isoCode: "" },
Expand All @@ -142,7 +142,7 @@ export const LANGUAGES: readonly WikiLanguage[] = [
{ label: "বাংলা", value: "bn", isoCode: "" },
{ label: "македонски", value: "mk", isoCode: "" },
{ label: "asturianu", value: "ast", isoCode: "" },
{ label: "粵語 zh", value: "yue", isoCode: "" },
{ label: "粵語", value: "yue", isoCode: "" },
{ label: "Ladin", value: "lld", isoCode: "" },
{ label: "latviešu", value: "lv", isoCode: "" },
{ label: "тоҷикӣ", value: "tg", isoCode: "" },
Expand Down Expand Up @@ -189,7 +189,7 @@ export const LANGUAGES: readonly WikiLanguage[] = [
{ label: "नेपाली", value: "ne", isoCode: "" },
{ label: "ગુજરાતી", value: "gu", isoCode: "" },
{ label: "ಕನ್ನಡ", value: "kn", isoCode: "" },
{ label: "Alemannisch", value: "als ", isoCode: "" },
{ label: "Alemannisch", value: "als", isoCode: "" },
{ label: "interlingua", value: "ia", isoCode: "" },
{ label: "Kotava", value: "avk", isoCode: "" },
{ label: "Boarisch", value: "bar", isoCode: "" },
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useStopwatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const useStopwatch = () => {
return {
min: pad(String(minutes), 2),
sec: pad(String(seconds), 2),
ms: pad(newMs.toFixed(0), 3),
ms: pad(String(Math.min(999, Math.round(newMs))), 3),
};
}, []);

Expand Down
6 changes: 2 additions & 4 deletions src/pages/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useIsFetching } from "@tanstack/react-query";
import { useNavigate } from "@tanstack/react-router";
import { type FormEvent, useState } from "react";
import { toast } from "react-hot-toast";
import ArticleAutocomplete from "../components/ArticleAutocomplete/ArticleAutocomplete";
import ArticlePreview from "../components/ArticlePreview/ArticlePreview";
import RandomButton from "../components/RandomButton/RandomButton";
Expand All @@ -21,6 +20,7 @@ import type { Article } from "../stores/GameStore";
import { useEndingArticle, useGameStoreActions, useStartingArticle } from "../stores/GameStore";
import { useIsCtrlFEnabled, useSettingsStoreActions, useWikiLanguage } from "../stores/SettingsStore";
import { useStatsStoreActions } from "../stores/StatisticsStore";
import { copyNotification } from "../utils/toast";

const Settings = () => {
const { LL } = useI18nContext();
Expand All @@ -46,8 +46,6 @@ const Settings = () => {
trackedStats: ["single_random_pressed", "multiple_random_pressed", "article_preview_pressed"],
});

const copyNotification = () => toast.success(LL["Copied to clipboard"](), { position: "top-center" });

const startGameHandler = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
resetGame();
Expand Down Expand Up @@ -117,7 +115,7 @@ const Settings = () => {
className="mt-4 w-fit border-b-[1px] border-b-transparent py-3 hover:border-b-primary-blue focus-visible:border-b-primary-blue"
onClick={async () => {
await navigator.clipboard.writeText(`${window.location.href}&lang=${wikiLang}`);
copyNotification();
copyNotification(LL["Copied to clipboard"]());
}}
>
{LL["Share settings"]()}
Expand Down
1 change: 0 additions & 1 deletion src/stores/GameStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ export const useStartingArticle = () => useGameStore((state) => state.startingAr
export const useEndingArticle = () => useGameStore((state) => state.endingArticle);
export const useHistory = () => useGameStore((state) => state.history);
export const useClicks = () => useGameStore((state) => (state.history.length > 1 ? state.history.length - 1 : 0));
export const useCurrentArticle = () => useGameStore((state) => state.history.slice(-1)[0]?.title);
export const useIsWin = () => useGameStore((state) => state.isWin);

export const useCheatingAttempts = () => useGameStore((state) => state.cheatingAttempts);
6 changes: 3 additions & 3 deletions src/stores/StatisticsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { produce } from "immer";
import { create } from "zustand";
import { createJSONStorage, devtools, persist } from "zustand/middleware";
import { immer } from "zustand/middleware/immer";
import { ACHIEVEMENTS_LIST, type Achievement, achivementConditionCheckByIdMap } from "../achievements";
import { ACHIEVEMENTS_LIST, type Achievement, achievementConditionCheckByIdMap } from "../achievements";

/*
Data gets persisted in local storage
Expand Down Expand Up @@ -160,7 +160,7 @@ export const useStatsStore = create<StatsStore>()(
const typedPersistedState = persistedState as PersistedStore;

const unlockedAchievements = produce(currentState.achievements, (draftState) => {
typedPersistedState.achievements.forEach((storageAchievement) => {
(typedPersistedState?.achievements ?? []).forEach((storageAchievement) => {
const completedAchievement = draftState.find(
(draftAchievement) => draftAchievement.id === storageAchievement.id,
);
Expand All @@ -186,7 +186,7 @@ export const useStatsStore = create<StatsStore>()(

export const checkAchievements = (achievements: readonly Achievement[]) => {
return achievements.filter((achievement) => {
const conditionFn = achivementConditionCheckByIdMap[achievement.id];
const conditionFn = achievementConditionCheckByIdMap[achievement.id];
return !achievement.unlocked && conditionFn();
});
};
Expand Down
1 change: 0 additions & 1 deletion src/types/typescript.ts

This file was deleted.

4 changes: 4 additions & 0 deletions src/utils/toast.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { toast } from "react-hot-toast";

export const errorToast = (text: string) => toast.error(text, { position: "bottom-center" });
export const copyNotification = (text: string) => toast.success(text, { position: "top-center" });