diff --git a/justfile b/justfile index e64dfb26..b59c3838 100644 --- a/justfile +++ b/justfile @@ -98,14 +98,14 @@ setup-cargo-wasm: build-website-backtrace: (cd website/backtrace && wasm-pack build --target web) - rm -rf website/agb/src/app/vendor/backtrace - mkdir -p website/agb/src/app/vendor - cp website/backtrace/pkg website/agb/src/app/vendor/backtrace -r + rm -rf website/agb/src/vendor/backtrace + mkdir -p website/agb/src/vendor + cp website/backtrace/pkg website/agb/src/vendor/backtrace -r build-mgba-wasm: - rm -rf website/agb/src/app/mgba/vendor - mkdir website/agb/src/app/mgba/vendor - {{podman_command}} build --file website/mgba-wasm/BuildMgbaWasm --output=website/agb/src/app/mgba/vendor . + rm -rf website/agb/src/components/mgba/vendor + mkdir website/agb/src/components/mgba/vendor + {{podman_command}} build --file website/mgba-wasm/BuildMgbaWasm --output=website/agb/src/components/mgba/vendor . build-combo-rom-site: just _build-rom "examples/combo" "AGBGAMES" diff --git a/website/agb/src/app/colour/colour.tsx b/website/agb/src/app/colour/colour.tsx index 77d11789..c9770737 100644 --- a/website/agb/src/app/colour/colour.tsx +++ b/website/agb/src/app/colour/colour.tsx @@ -1,6 +1,6 @@ "use client"; -import { ContentBlock } from "../contentBlock"; +import { ContentBlock } from "../../components/contentBlock"; import { useState } from "react"; import { styled } from "styled-components"; @@ -69,44 +69,48 @@ export default function ColourPicker() { } return ( - -

agbrs colour converter

- - -

Regular RGB8

- setHexColour(evt.target.value)} - /> - setHexColour(evt.target.value)} - /> -
- -

GBA RGB5

- setGbaHexColour(evt.target.value)} - /> - setGbaHexColour(evt.target.value)} - /> - - setColour(fromRgb15(parseInt(evt.target.value, 16))) - } - /> -
-
-
+ <> + +

agbrs colour converter

+
+ + + +

Regular RGB8

+ setHexColour(evt.target.value)} + /> + setHexColour(evt.target.value)} + /> +
+ +

GBA RGB5

+ setGbaHexColour(evt.target.value)} + /> + setGbaHexColour(evt.target.value)} + /> + + setColour(fromRgb15(parseInt(evt.target.value, 16))) + } + /> +
+
+
+ ); } diff --git a/website/agb/src/app/crash/backtrace.tsx b/website/agb/src/app/crash/backtrace.tsx index 589d1137..0eb7425c 100644 --- a/website/agb/src/app/crash/backtrace.tsx +++ b/website/agb/src/app/crash/backtrace.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; -import { ContentBlock } from "../contentBlock"; +import { ContentBlock } from "../../components/contentBlock"; import { GameDeveloperSummary } from "./gameDeveloperSummary"; import { styled } from "styled-components"; import { Debug } from "./debug"; @@ -14,30 +14,39 @@ export function BacktracePage() { }, []); return ( - -

agbrs crash backtrace viewer

-

- You likely got here from the link / QR code that was displayed when a - game you were playing crashed. This is the default crash page for games - made using the agb library. -

-

- The creator of the game is very likely interested in the code - below along with a description of what you were doing at the - time.{" "} - Send these to the creator of the game you are playing. -

- -

- - The owners of this website are not necessarily the creators of the - game you are playing. - -

-

Backtrace

- {backtrace && } - -
+ <> + +

agbrs crash backtrace viewer

+
+ +

+ You likely got here from the link / QR code that was displayed when a + game you were playing crashed. This is the default crash page for + games made using the agb library. +

+

+ The creator of the game is very likely interested in the code + below along with a description of what you were doing at the + time.{" "} + + Send these to the creator of the game you are playing. + +

+ +

+ + The owners of this website are not necessarily the creators of the + game you are playing. + +

+

Backtrace

+ {backtrace && } + +
+ ); } diff --git a/website/agb/src/app/crash/debug.tsx b/website/agb/src/app/crash/debug.tsx index a573cef2..19eeb3cd 100644 --- a/website/agb/src/app/crash/debug.tsx +++ b/website/agb/src/app/crash/debug.tsx @@ -1,5 +1,9 @@ import { styled } from "styled-components"; -import { AddressInfo, AgbDebug, useAgbDebug } from "../useAgbDebug.hook"; +import { + AddressInfo, + AgbDebug, + useAgbDebug, +} from "../../hooks/useAgbDebug.hook"; import { ReactNode, useMemo, useState } from "react"; const BacktraceListWrapper = styled.div` diff --git a/website/agb/src/app/gba-parts/left.png b/website/agb/src/app/left.png similarity index 100% rename from website/agb/src/app/gba-parts/left.png rename to website/agb/src/app/left.png diff --git a/website/agb/src/app/page.tsx b/website/agb/src/app/page.tsx index 0f8e833a..225ede6d 100644 --- a/website/agb/src/app/page.tsx +++ b/website/agb/src/app/page.tsx @@ -1,30 +1,18 @@ "use client"; import styled from "styled-components"; -import { CenteredBlock, ContentBlock } from "./contentBlock"; -import MgbaWrapper from "./mgba/mgbaWrapper"; +import { CenteredBlock, ContentBlock } from "../components/contentBlock"; +import MgbaWrapper from "../components/mgba/mgbaWrapper"; import Image from "next/image"; -import left from "./gba-parts/left.png"; -import right from "./gba-parts/right.png"; -import { MobileController } from "./mobileController"; +import left from "./left.png"; +import right from "./right.png"; +import { MobileController } from "../components/mobileController/mobileController"; import { useMemo, useRef, useState } from "react"; -import { GbaKey } from "./mgba/bindings"; -import { useClientValue } from "./useClientValue.hook"; -import { MgbaHandle } from "./mgba/mgba"; - -const ExternalLink = styled.a` - text-decoration: none; - color: black; - background-color: #fad288; - border: solid #fad288 2px; - border-radius: 5px; - padding: 5px 10px; - - &:hover { - border: solid black 2px; - } -`; +import { GbaKey } from "../components/mgba/bindings"; +import { useClientValue } from "../hooks/useClientValue.hook"; +import { MgbaHandle } from "../components/mgba/mgba"; +import { ExternalLink } from "@/components/externalLink"; const HelpLinks = styled.div` display: flex; @@ -78,7 +66,7 @@ function shouldStartPlaying(isTouchScreen: boolean | undefined) { return !isTouchScreen; } -const COMBO_GAME = new URL("combo.gba.gz", import.meta.url); +const COMBO_GAME = new URL("../roms/combo.gba.gz", import.meta.url); function MgbaWithControllerSides() { const mgba = useRef(null); @@ -136,13 +124,13 @@ function MgbaWithControllerSides() { export default function Home() { return ( <> - +

agb - a rust framework for making Game Boy Advance games

- + GitHub @@ -151,6 +139,7 @@ export default function Home() { Docs + Showcase diff --git a/website/agb/src/app/gba-parts/right.png b/website/agb/src/app/right.png similarity index 100% rename from website/agb/src/app/gba-parts/right.png rename to website/agb/src/app/right.png diff --git a/website/agb/src/app/showcase/[game]/page.tsx b/website/agb/src/app/showcase/[game]/page.tsx new file mode 100644 index 00000000..cf3b2138 --- /dev/null +++ b/website/agb/src/app/showcase/[game]/page.tsx @@ -0,0 +1,93 @@ +import { slugify } from "@/sluggify"; +import { Games, ShowcaseGame } from "../games"; +import { ContentBlock } from "@/components/contentBlock"; +import { ExternalLink } from "@/components/externalLink"; +import Link from "next/link"; +import Image, { StaticImageData } from "next/image"; +import { + ScreenshotsWrapper, + ScreenshotWrapper, + BackToShowcaseWrapper, + DescriptionAndScreenshots, + Description, +} from "./styled"; + +export async function generateStaticParams() { + return Games.map((game) => ({ + game: slugify(game.name), + })); +} + +export function getGame(slug: string) { + const game = Games.find((game) => slugify(game.name) === slug); + if (!game) { + throw new Error("Not valid game name, this should never happen"); + } + + return game; +} + +export function generateMetadata({ params }: { params: { game: string } }) { + const game = getGame(params.game); + return { title: game.name }; +} + +export default function Page({ params }: { params: { game: string } }) { + const game = getGame(params.game); + return ; +} + +function DeveloperNames({ names }: { names: string[] }) { + if (names.length === 0) { + throw new Error("You must specify developer names"); + } + if (names.length === 1) { + return names[0]; + } + if (names.length === 2) { + return names.join(" and "); + } + const first = names.slice(0, -1); + return first.join(", ") + `, and ${names[names.length - 1]}`; +} + +function Screenshots({ screenshots }: { screenshots: StaticImageData[] }) { + return ( + + {screenshots.map((screenshot) => ( + + + + ))} + + ); +} + +function Display({ game }: { game: ShowcaseGame }) { + return ( + <> + + + + < Back to showcase + + +

{game.name}

+
+ By: +
+
+ + + {game.description} + + + + + {game.itch && ( + View on itch.io + )} + + + ); +} diff --git a/website/agb/src/app/showcase/[game]/styled.tsx b/website/agb/src/app/showcase/[game]/styled.tsx new file mode 100644 index 00000000..8ee4f0ce --- /dev/null +++ b/website/agb/src/app/showcase/[game]/styled.tsx @@ -0,0 +1,36 @@ +"use client"; + +import { styled } from "styled-components"; + +export const ScreenshotsWrapper = styled.div` + flex: 4; +`; + +export const ScreenshotWrapper = styled.div` + text-align: center; + img { + width: 100%; + width: round(down, 100%, 240px); + height: auto; + image-rendering: pixelated; + } +`; + +export const Description = styled.div` + flex: 5; + :first-child { + margin-top: 0; + } +`; + +export const DescriptionAndScreenshots = styled.div` + display: flex; + gap: 16px; +`; + +export const BackToShowcaseWrapper = styled.div` + a { + text-decoration: none; + color: black; + } +`; diff --git a/website/agb/src/app/showcase/data/tapir/hatwiz/hatwiz.tsx b/website/agb/src/app/showcase/data/tapir/hatwiz/hatwiz.tsx new file mode 100644 index 00000000..efe9ad52 --- /dev/null +++ b/website/agb/src/app/showcase/data/tapir/hatwiz/hatwiz.tsx @@ -0,0 +1,43 @@ +import { ShowcaseGame, shuffle } from "../../../games"; +import h1 from "./the-hat-chooses-the-wizard-0.png"; +import h2 from "./the-hat-chooses-the-wizard-1.png"; +import h3 from "./the-hat-chooses-the-wizard-2.png"; +import h4 from "./the-hat-chooses-the-wizard-3.png"; + +const HatWizScreenshots = [h1, h2, h3, h4]; + +export const HatWiz: ShowcaseGame = { + name: "The Hat Chooses the Wizard", + developers: shuffle(["Corwin Kuiper", "Gwilym Inzani"]), + screenshots: HatWizScreenshots, + description: ( + <> +

+ ‘The Hat Chooses the Wizard’ is a 2D platformer. This game + was developed as an entry for the GMTK game jam 2021, with the theme + “joined together”. The entire game, except for the music, + was produced in just 48 hours. +

+

+ In this game, you play as a wizard searching for his missing staff. + However, the path to the staff is filled with dangerous obstacles and + monsters. Luckily, you have a powerful magic hat that can be thrown and + recalled, allowing you to fly towards it and reach otherwise + inaccessible platforms. +

+

+ With this unique mechanic, you can explore the game's levels and + defeat enemies. The game's simple but challenging gameplay will put + your platforming skills to the test as you try to reach the end. +

+

+ The music is by Otto Halmén released under creative commons attribution + 3.0 and can be found here:{" "} + + opengameart.org/content/sylvan-waltz-standard-looped-version + +

+ + ), + itch: new URL("https://lostimmortal.itch.io/the-hat-chooses-the-wizard"), +}; diff --git a/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-0.png b/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-0.png new file mode 100644 index 00000000..1dbe0a0f Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-0.png differ diff --git a/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-1.png b/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-1.png new file mode 100644 index 00000000..3c101a4d Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-1.png differ diff --git a/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-2.png b/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-2.png new file mode 100644 index 00000000..34e07902 Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-2.png differ diff --git a/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-3.png b/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-3.png new file mode 100644 index 00000000..17130c0a Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/hatwiz/the-hat-chooses-the-wizard-3.png differ diff --git a/website/agb/src/app/showcase/data/tapir/purple/purple.tsx b/website/agb/src/app/showcase/data/tapir/purple/purple.tsx new file mode 100644 index 00000000..34fa37ec --- /dev/null +++ b/website/agb/src/app/showcase/data/tapir/purple/purple.tsx @@ -0,0 +1,26 @@ +import { ShowcaseGame, shuffle } from "@/app/showcase/games"; +import p1 from "./the-purple-night-0.png"; +import p2 from "./the-purple-night-1.png"; + +const Screenshots = [p1, p2]; + +export const Purple: ShowcaseGame = { + name: "The Purple Night", + developers: shuffle(["Corwin Kuiper", "Gwilym Inzani", "Sam Williams"]), + screenshots: Screenshots, + description: ( + <> +

Save a lost soul and take them safely back to the afterlife!

+

+ The purple night is a platformer game where your health bar is your + sword. The more damage you take, the shorter your sword gets, making you + more nimble and your attacks faster, but also increasing your risk. +

+

+ Do you choose to stay at high health but low mobility, or low health and + higher mobility? +

+ + ), + itch: new URL("https://lostimmortal.itch.io/the-purple-night"), +}; diff --git a/website/agb/src/app/showcase/data/tapir/purple/the-purple-night-0.png b/website/agb/src/app/showcase/data/tapir/purple/the-purple-night-0.png new file mode 100644 index 00000000..3b39ff12 Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/purple/the-purple-night-0.png differ diff --git a/website/agb/src/app/showcase/data/tapir/purple/the-purple-night-1.png b/website/agb/src/app/showcase/data/tapir/purple/the-purple-night-1.png new file mode 100644 index 00000000..ad53bb8a Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/purple/the-purple-night-1.png differ diff --git a/website/agb/src/app/showcase/games.tsx b/website/agb/src/app/showcase/games.tsx new file mode 100644 index 00000000..3ba4a542 --- /dev/null +++ b/website/agb/src/app/showcase/games.tsx @@ -0,0 +1,27 @@ +import { StaticImageData } from "next/image"; +import { ReactNode } from "react"; +import { HatWiz } from "./data/tapir/hatwiz/hatwiz"; +import { Purple } from "./data/tapir/purple/purple"; + +export interface ShowcaseGame { + name: string; + developers: string[]; + rom?: URL; + screenshots: StaticImageData[]; + description: ReactNode; + itch?: URL; + otherLink?: URL; +} + +export function shuffle(a: T[]) { + var j, x, i; + for (i = a.length - 1; i > 0; i--) { + j = Math.floor(Math.random() * (i + 1)); + x = a[i]; + a[i] = a[j]; + a[j] = x; + } + return a; +} + +export const Games: ShowcaseGame[] = [HatWiz, Purple]; diff --git a/website/agb/src/app/showcase/page.tsx b/website/agb/src/app/showcase/page.tsx new file mode 100644 index 00000000..7387c023 --- /dev/null +++ b/website/agb/src/app/showcase/page.tsx @@ -0,0 +1,42 @@ +import { Metadata } from "next"; +import { ContentBlock } from "@/components/contentBlock"; +import { Games, ShowcaseGame } from "./games"; +import Link from "next/link"; +import { slugify } from "@/sluggify"; +import { GameDisplay, GameGrid, GameImage } from "./styles"; +import Image from "next/image"; + +export const metadata: Metadata = { + title: "Games made with agb", +}; + +export default function ColourPickerPage() { + return ( + <> + +

Showcase

+
+ + + {Games.map((game, idx) => ( + + ))} + + + + ); +} + +function Game({ game }: { game: ShowcaseGame }) { + const lastImage = game.screenshots[game.screenshots.length - 1]; + return ( + + + + {`Screenshot + +

{game.name}

+ +
+ ); +} diff --git a/website/agb/src/app/showcase/styles.tsx b/website/agb/src/app/showcase/styles.tsx new file mode 100644 index 00000000..0b7a5395 --- /dev/null +++ b/website/agb/src/app/showcase/styles.tsx @@ -0,0 +1,32 @@ +"use client"; + +import styled from "styled-components"; + +export const GameGrid = styled.div` + display: flex; + flex-wrap: wrap; + justify-content: center; +`; + +export const GameImage = styled.div` + img { + width: 100%; + width: round(down, 100%, 240px); + height: auto; + image-rendering: pixelated; + } +`; + +export const GameDisplay = styled.div` + width: 600px; + a { + text-align: center; + color: black; + text-decoration: none; + } + + h2 { + margin: 0; + margin-top: 8px; + } +`; diff --git a/website/agb/src/app/contentBlock.tsx b/website/agb/src/components/contentBlock.tsx similarity index 100% rename from website/agb/src/app/contentBlock.tsx rename to website/agb/src/components/contentBlock.tsx diff --git a/website/agb/src/components/externalLink.tsx b/website/agb/src/components/externalLink.tsx new file mode 100644 index 00000000..fe1aa40a --- /dev/null +++ b/website/agb/src/components/externalLink.tsx @@ -0,0 +1,16 @@ +"use client"; +import Link from "next/link"; +import { styled } from "styled-components"; + +export const ExternalLink = styled(Link)` + text-decoration: none; + color: black; + background-color: #fad288; + border: solid #fad288 2px; + border-radius: 5px; + padding: 5px 10px; + + &:hover { + border: solid black 2px; + } +`; diff --git a/website/agb/src/app/mgba/Slider.tsx b/website/agb/src/components/mgba/Slider.tsx similarity index 100% rename from website/agb/src/app/mgba/Slider.tsx rename to website/agb/src/components/mgba/Slider.tsx diff --git a/website/agb/src/app/mgba/bindings.tsx b/website/agb/src/components/mgba/bindings.tsx similarity index 100% rename from website/agb/src/app/mgba/bindings.tsx rename to website/agb/src/components/mgba/bindings.tsx diff --git a/website/agb/src/app/mgba/globalStyles.ts b/website/agb/src/components/mgba/globalStyles.ts similarity index 100% rename from website/agb/src/app/mgba/globalStyles.ts rename to website/agb/src/components/mgba/globalStyles.ts diff --git a/website/agb/src/app/mgba/mgba.tsx b/website/agb/src/components/mgba/mgba.tsx similarity index 100% rename from website/agb/src/app/mgba/mgba.tsx rename to website/agb/src/components/mgba/mgba.tsx diff --git a/website/agb/src/app/mgba/mgbaWrapper.tsx b/website/agb/src/components/mgba/mgbaWrapper.tsx similarity index 100% rename from website/agb/src/app/mgba/mgbaWrapper.tsx rename to website/agb/src/components/mgba/mgbaWrapper.tsx diff --git a/website/agb/src/app/mgba/useAvoidItchIoScrolling.ts b/website/agb/src/components/mgba/useAvoidItchIoScrolling.ts similarity index 100% rename from website/agb/src/app/mgba/useAvoidItchIoScrolling.ts rename to website/agb/src/components/mgba/useAvoidItchIoScrolling.ts diff --git a/website/agb/src/app/mgba/useController.hook.ts b/website/agb/src/components/mgba/useController.hook.ts similarity index 100% rename from website/agb/src/app/mgba/useController.hook.ts rename to website/agb/src/components/mgba/useController.hook.ts diff --git a/website/agb/src/app/mgba/useFrameSkip.hook.ts b/website/agb/src/components/mgba/useFrameSkip.hook.ts similarity index 100% rename from website/agb/src/app/mgba/useFrameSkip.hook.ts rename to website/agb/src/components/mgba/useFrameSkip.hook.ts diff --git a/website/agb/src/app/mgba/useLocalStorage.hook.ts b/website/agb/src/components/mgba/useLocalStorage.hook.ts similarity index 100% rename from website/agb/src/app/mgba/useLocalStorage.hook.ts rename to website/agb/src/components/mgba/useLocalStorage.hook.ts diff --git a/website/agb/src/app/mgba/useOnKeyUp.hook.ts b/website/agb/src/components/mgba/useOnKeyUp.hook.ts similarity index 100% rename from website/agb/src/app/mgba/useOnKeyUp.hook.ts rename to website/agb/src/components/mgba/useOnKeyUp.hook.ts diff --git a/website/agb/src/app/gba-parts/L.png b/website/agb/src/components/mobileController/gba-parts/L.png similarity index 100% rename from website/agb/src/app/gba-parts/L.png rename to website/agb/src/components/mobileController/gba-parts/L.png diff --git a/website/agb/src/app/gba-parts/R.png b/website/agb/src/components/mobileController/gba-parts/R.png similarity index 100% rename from website/agb/src/app/gba-parts/R.png rename to website/agb/src/components/mobileController/gba-parts/R.png diff --git a/website/agb/src/app/gba-parts/SELECT.png b/website/agb/src/components/mobileController/gba-parts/SELECT.png similarity index 100% rename from website/agb/src/app/gba-parts/SELECT.png rename to website/agb/src/components/mobileController/gba-parts/SELECT.png diff --git a/website/agb/src/app/gba-parts/START.png b/website/agb/src/components/mobileController/gba-parts/START.png similarity index 100% rename from website/agb/src/app/gba-parts/START.png rename to website/agb/src/components/mobileController/gba-parts/START.png diff --git a/website/agb/src/app/gba-parts/ab.png b/website/agb/src/components/mobileController/gba-parts/ab.png similarity index 100% rename from website/agb/src/app/gba-parts/ab.png rename to website/agb/src/components/mobileController/gba-parts/ab.png diff --git a/website/agb/src/app/gba-parts/dpad.png b/website/agb/src/components/mobileController/gba-parts/dpad.png similarity index 100% rename from website/agb/src/app/gba-parts/dpad.png rename to website/agb/src/components/mobileController/gba-parts/dpad.png diff --git a/website/agb/src/app/mobileController.tsx b/website/agb/src/components/mobileController/mobileController.tsx similarity index 97% rename from website/agb/src/app/mobileController.tsx rename to website/agb/src/components/mobileController/mobileController.tsx index d3537961..9fdd845d 100644 --- a/website/agb/src/app/mobileController.tsx +++ b/website/agb/src/components/mobileController/mobileController.tsx @@ -1,4 +1,4 @@ -import { FC, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import styled from "styled-components"; import Image from "next/image"; @@ -8,8 +8,8 @@ import DPad from "./gba-parts/dpad.png"; import ABButtons from "./gba-parts/ab.png"; import Select from "./gba-parts/SELECT.png"; import Start from "./gba-parts/START.png"; -import { GbaKey } from "./mgba/bindings"; -import { MgbaHandle } from "./mgba/mgba"; +import { GbaKey } from "../mgba/bindings"; +import { MgbaHandle } from "../mgba/mgba"; const MobileControls = styled.div` display: flex; diff --git a/website/agb/src/app/useAgbDebug.hook.ts b/website/agb/src/hooks/useAgbDebug.hook.ts similarity index 94% rename from website/agb/src/app/useAgbDebug.hook.ts rename to website/agb/src/hooks/useAgbDebug.hook.ts index 4ed74e4e..79fc477e 100644 --- a/website/agb/src/app/useAgbDebug.hook.ts +++ b/website/agb/src/hooks/useAgbDebug.hook.ts @@ -4,7 +4,7 @@ import debugInit, { DebugFile, InitOutput, AddressInfo, -} from "./vendor/backtrace/backtrace"; +} from "../vendor/backtrace/backtrace"; let agbDebug: Promise | undefined; diff --git a/website/agb/src/app/useClientValue.hook.ts b/website/agb/src/hooks/useClientValue.hook.ts similarity index 100% rename from website/agb/src/app/useClientValue.hook.ts rename to website/agb/src/hooks/useClientValue.hook.ts diff --git a/website/agb/src/sluggify.ts b/website/agb/src/sluggify.ts new file mode 100644 index 00000000..b02353b9 --- /dev/null +++ b/website/agb/src/sluggify.ts @@ -0,0 +1,3 @@ +export function slugify(x: string) { + return x.toLowerCase().split(" ").join("-"); +}