diff --git a/package-lock.json b/package-lock.json
index bb88d1d..2718723 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-slot": "^1.2.3",
+ "@tanstack/react-query": "^5.90.12",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.548.0",
@@ -1734,13 +1735,38 @@
"vite": "^5.2.0 || ^6 || ^7"
}
},
+ "node_modules/@tanstack/query-core": {
+ "version": "5.90.12",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.12.tgz",
+ "integrity": "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/react-query": {
+ "version": "5.90.12",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.12.tgz",
+ "integrity": "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/query-core": "5.90.12"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19"
+ }
+ },
"node_modules/@trivago/prettier-plugin-sort-imports": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-5.2.2.tgz",
"integrity": "sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"@babel/generator": "^7.26.5",
"@babel/parser": "^7.26.7",
@@ -1811,7 +1837,6 @@
"integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
@@ -1820,7 +1845,8 @@
"version": "1.26.5",
"resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz",
"integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@types/react": {
"version": "19.2.2",
@@ -1828,7 +1854,6 @@
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -1839,7 +1864,6 @@
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -3291,7 +3315,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -3334,7 +3357,6 @@
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -3443,7 +3465,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -3464,7 +3485,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -3825,7 +3845,6 @@
"integrity": "sha512-J1QRxf8zlYNvjAY1fB6zW+FLr0K26/IpKFrGM+Za0Ko6meJUMlHBk+LV19gAb8sfSluH4/6dyWKVS2dvNU4RLQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@oxc-project/runtime": "0.96.0",
"fdir": "^6.5.0",
diff --git a/package.json b/package.json
index 7f3ae47..81f3b57 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-slot": "^1.2.3",
+ "@tanstack/react-query": "^5.90.12",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.548.0",
diff --git a/src/app/auto-splitters.tsx b/src/app/auto-splitters.tsx
new file mode 100644
index 0000000..4c96d8a
--- /dev/null
+++ b/src/app/auto-splitters.tsx
@@ -0,0 +1,9 @@
+import { AppGitHubGenericMarkdown } from "@/components/libresplit/AppGitHubGenericMarkdown";
+
+export function AutoSplitters() {
+ return (
+
+ );
+}
diff --git a/src/app/home.tsx b/src/app/home.tsx
index c11e654..af5fdcc 100644
--- a/src/app/home.tsx
+++ b/src/app/home.tsx
@@ -1,11 +1,11 @@
-import { AppGitHubReadme } from "@/components/libresplit/AppGitHubReadme";
+import { AppGitHubGenericMarkdown } from "@/components/libresplit/AppGitHubGenericMarkdown";
import { AppHero } from "@/components/libresplit/AppHero";
export function Home() {
return (
);
}
diff --git a/src/app/settings-keybinds.tsx b/src/app/settings-keybinds.tsx
new file mode 100644
index 0000000..9bda018
--- /dev/null
+++ b/src/app/settings-keybinds.tsx
@@ -0,0 +1,9 @@
+import { AppGitHubGenericMarkdown } from "@/components/libresplit/AppGitHubGenericMarkdown";
+
+export function SettingsKeybinds() {
+ return (
+
+ );
+}
diff --git a/src/app/split-files.tsx b/src/app/split-files.tsx
new file mode 100644
index 0000000..ced460a
--- /dev/null
+++ b/src/app/split-files.tsx
@@ -0,0 +1,9 @@
+import { AppGitHubGenericMarkdown } from "@/components/libresplit/AppGitHubGenericMarkdown";
+
+export function SplitFiles() {
+ return (
+
+ );
+}
diff --git a/src/app/themes.tsx b/src/app/themes.tsx
new file mode 100644
index 0000000..3d06a38
--- /dev/null
+++ b/src/app/themes.tsx
@@ -0,0 +1,9 @@
+import { AppGitHubGenericMarkdown } from "@/components/libresplit/AppGitHubGenericMarkdown";
+
+export function Themes() {
+ return (
+
+ );
+}
diff --git a/src/app/troubleshooting.tsx b/src/app/troubleshooting.tsx
new file mode 100644
index 0000000..284ba03
--- /dev/null
+++ b/src/app/troubleshooting.tsx
@@ -0,0 +1,9 @@
+import { AppGitHubGenericMarkdown } from "@/components/libresplit/AppGitHubGenericMarkdown";
+
+export function Troubleshooting() {
+ return (
+
+ );
+}
diff --git a/src/components/libresplit/AppGitHubGenericMarkdown.tsx b/src/components/libresplit/AppGitHubGenericMarkdown.tsx
new file mode 100644
index 0000000..edb6179
--- /dev/null
+++ b/src/components/libresplit/AppGitHubGenericMarkdown.tsx
@@ -0,0 +1,37 @@
+import { AppLoading } from "./AppLoading";
+import { Markdown } from "@/lib/markdown";
+import { useQuery } from "@tanstack/react-query";
+
+async function fetchMarkdown(url: string): Promise {
+ const res = await fetch(url);
+
+ if (!res.ok) {
+ throw new Error("Failed to fetch markdown from GitHub.");
+ }
+
+ return res.text();
+}
+
+type AppGitHubGenericMarkdownProps = {
+ url: string;
+};
+
+export function AppGitHubGenericMarkdown({
+ url,
+}: AppGitHubGenericMarkdownProps) {
+ const { data, isLoading, error } = useQuery({
+ queryKey: ["markdown-text"],
+ queryFn: () => fetchMarkdown(url),
+ enabled: !!url,
+ });
+
+ if (isLoading) return ;
+ if (error) return Failed to fetch markdown from GitHub.
;
+ if (!data) return Failed to fetch markdown from GitHub.
;
+
+ return (
+
+
+
+ );
+}
diff --git a/src/components/libresplit/AppGitHubReadme.tsx b/src/components/libresplit/AppGitHubReadme.tsx
deleted file mode 100644
index 464b0f6..0000000
--- a/src/components/libresplit/AppGitHubReadme.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { useEffect, useState } from "react";
-
-import { AppLoading } from "./AppLoading";
-import { Markdown } from "@/lib/markdown";
-
-export function AppGitHubReadme() {
- const [readme, setReadme] = useState("Loading...");
- const [isLoading, setIsLoading] = useState(true);
-
- const urlReadme =
- "https://raw.githubusercontent.com/LibreSplit/LibreSplit/refs/heads/main/README.md";
-
- // Fetch markdown from GitHub page for LibreSplit, place into the readme state.
- useEffect(() => {
- fetch(urlReadme)
- .then((res) => {
- if (!res.ok) throw new Error(`HTTP Error! Status: ${res.status}`);
- return res.text();
- })
- .then((text) => setReadme(text))
- .catch(() => setReadme("Failed to load README from GitHub."))
- .finally(() => setIsLoading(false));
- }, []);
-
- if (isLoading) {
- return ;
- }
-
- return (
-
-
-
- );
-}
diff --git a/src/main.tsx b/src/main.tsx
index 8610034..6609c20 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -2,21 +2,26 @@ import { StrictMode } from "react";
import App from "./app";
import "./index.css";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ThemeProvider } from "next-themes";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router";
+const queryClient = new QueryClient();
+
createRoot(document.getElementById("root")!).render(
-
-
-
-
-
+
+
+
+
+
+
+
,
);
diff --git a/src/router.tsx b/src/router.tsx
index fcf97aa..3b96332 100644
--- a/src/router.tsx
+++ b/src/router.tsx
@@ -1,6 +1,11 @@
+import { AutoSplitters } from "./app/auto-splitters";
import { Converter } from "./app/converter";
import { Home } from "./app/home";
import { NotFound } from "./app/not-found";
+import { SettingsKeybinds } from "./app/settings-keybinds";
+import { SplitFiles } from "./app/split-files";
+import { Themes } from "./app/themes";
+import { Troubleshooting } from "./app/troubleshooting";
import { Route, Routes } from "react-router";
export default function AppRouter() {
@@ -9,6 +14,13 @@ export default function AppRouter() {
} />
} />
+ {/* Documentation pages pulled from GitHub. */}
+ } />
+ } />
+ } />
+ } />
+ } />
+
{/* Fall back on app's 404 page. This is because of the SPA routing trick with 404.html used in GitHub Pages. */}
} />
diff --git a/vite.config.ts b/vite.config.ts
index 4ea20f7..5c8d2c1 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -13,7 +13,14 @@ export default defineConfig({
copyIndexTo404(),
sitemap({
hostname: "https://libresplit.org",
- dynamicRoutes: ["/converter"],
+ dynamicRoutes: [
+ "/converter",
+ "/docs/auto-splitters.md",
+ "/docs/settings-keybinds.md",
+ "/docs/split-files.md",
+ "/docs/themes.md",
+ "/docs/troubleshooting.md",
+ ],
exclude: ["/404"],
}),
],