diff --git a/justfile b/justfile index e64dfb26..95e4a4b6 100644 --- a/justfile +++ b/justfile @@ -98,18 +98,19 @@ 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" - gzip -9 -c examples/target/examples/combo.gba > website/agb/src/app/combo.gba.gz + mkdir -p website/agb/src/roms + gzip -9 -c examples/target/examples/combo.gba > website/agb/src/roms/combo.gba.gz setup-app-build: build-mgba-wasm build-combo-rom-site build-website-backtrace 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/layout.tsx b/website/agb/src/app/layout.tsx index 60d9b5d5..1a751f95 100644 --- a/website/agb/src/app/layout.tsx +++ b/website/agb/src/app/layout.tsx @@ -1,6 +1,6 @@ import type { Metadata } from "next"; import "./globalStyles.css"; -import StyledComponentsRegistry from "./registry"; +import StyledComponentsRegistry, { BodyPixelRatio } from "./registry"; export const metadata: Metadata = { title: "agb - a rust framework for making Game Boy Advance games", @@ -13,9 +13,9 @@ export default function RootLayout({ }>) { return ( - - {children} - + + {children} + ); } 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..ca51a90d 100644 --- a/website/agb/src/app/page.tsx +++ b/website/agb/src/app/page.tsx @@ -1,35 +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; - } -`; - -const HelpLinks = styled.div` - display: flex; - justify-content: space-around; -`; +import { GbaKey } from "../components/mgba/bindings"; +import { useClientValue } from "../hooks/useClientValue.hook"; +import { MgbaHandle } from "../components/mgba/mgba"; +import { ExternalLink, ExternalLinkBlock } from "@/components/externalLink"; const GameDisplay = styled.div` height: min(calc(100vw / 1.5), min(90vh, 480px)); @@ -78,7 +61,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,14 +119,14 @@ function MgbaWithControllerSides() { export default function Home() { return ( <> - +

agb - a rust framework for making Game Boy Advance games

- - + + GitHub @@ -151,7 +134,8 @@ export default function Home() { Docs - + Showcase + ); diff --git a/website/agb/src/app/registry.tsx b/website/agb/src/app/registry.tsx index fa12293e..e19526b5 100644 --- a/website/agb/src/app/registry.tsx +++ b/website/agb/src/app/registry.tsx @@ -1,8 +1,8 @@ "use client"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useServerInsertedHTML } from "next/navigation"; -import { ServerStyleSheet, StyleSheetManager } from "styled-components"; +import styled, { ServerStyleSheet, StyleSheetManager } from "styled-components"; export default function StyledComponentsRegistry({ children, @@ -27,3 +27,18 @@ export default function StyledComponentsRegistry({ ); } + +const BodyWithPixelRatio = styled.body<{ + $pixel: number; +}>` + --device-pixel: calc(1px / ${(props) => props.$pixel}); +`; + +export function BodyPixelRatio({ children }: { children: React.ReactNode }) { + const [pixel, setPixel] = useState(1); + useEffect(() => { + setPixel(window.devicePixelRatio); + }, []); + + return {children}; +} 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..3431e798 --- /dev/null +++ b/website/agb/src/app/showcase/[game]/page.tsx @@ -0,0 +1,81 @@ +import { slugify } from "@/sluggify"; +import { Games, ShowcaseGame } from "../games"; +import { ContentBlock } from "@/components/contentBlock"; +import { ExternalLink, ExternalLinkBlock } from "@/components/externalLink"; +import Link from "next/link"; +import { + BackToShowcaseWrapper, + DescriptionAndScreenshots, + Description, + Screenshots, +} from "./styles"; + +export async function generateStaticParams() { + return Games.map((game) => ({ + game: slugify(game.name), + })); +} + +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 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]/styles.tsx b/website/agb/src/app/showcase/[game]/styles.tsx new file mode 100644 index 00000000..2b8e51f4 --- /dev/null +++ b/website/agb/src/app/showcase/[game]/styles.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { styled } from "styled-components"; +import Image, { StaticImageData } from "next/image"; + +export function Screenshots({ + screenshots, +}: { + screenshots: StaticImageData[]; +}) { + return ( + + {screenshots.map((screenshot) => ( + + ))} + + ); +} + +const ScreenshotsWrapper = styled.div` + flex: 4; + text-align: center; +`; + +const Screenshot = styled(Image)` + width: 100%; + width: max( + round(down, 100%, calc(240 * var(--device-pixel))), + calc(240 * var(--device-pixel)) + ); + 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; + + @media (max-width: 1000px) { + display: block; + } +`; + +export const BackToShowcaseWrapper = styled.div` + a { + text-decoration: none; + color: black; + } +`; diff --git a/website/agb/src/app/showcase/data/tapir/dungeon/dungeon.tsx b/website/agb/src/app/showcase/data/tapir/dungeon/dungeon.tsx new file mode 100644 index 00000000..1940f75b --- /dev/null +++ b/website/agb/src/app/showcase/data/tapir/dungeon/dungeon.tsx @@ -0,0 +1,30 @@ +import { ShowcaseGame, shuffle } from "@/app/showcase/games"; +import d1 from "./the-dungeon-puzzlers-lament-0.png"; +import d2 from "./the-dungeon-puzzlers-lament-1.png"; + +const Screenshots = [d1, d2]; + +export const Dungeon: ShowcaseGame = { + name: "The Dungeon Puzzler's Lament", + developers: shuffle(["Corwin Kuiper", "Gwilym Inzani"]), + screenshots: Screenshots, + description: ( + <> +

+ Get through as many levels as possible in this space themed, dice + rolling roguelike. +

+

+ Build up powerful combos to defeat enemies which keep getting stronger. + Slowly acquire more dice and upgrade them in order to handle the + increasing strength of the enemies you face. +

+ +

+ Hyperspace Roll was influenced by great games such as Slay the Spire, + FTL and the board game Escape: The Curse of the Temple. +

+ + ), + itch: new URL("https://setsquare.itch.io/dungeon-puzzlers-lament"), +}; diff --git a/website/agb/src/app/showcase/data/tapir/dungeon/the-dungeon-puzzlers-lament-0.png b/website/agb/src/app/showcase/data/tapir/dungeon/the-dungeon-puzzlers-lament-0.png new file mode 100644 index 00000000..7129214d Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/dungeon/the-dungeon-puzzlers-lament-0.png differ diff --git a/website/agb/src/app/showcase/data/tapir/dungeon/the-dungeon-puzzlers-lament-1.png b/website/agb/src/app/showcase/data/tapir/dungeon/the-dungeon-puzzlers-lament-1.png new file mode 100644 index 00000000..d73f1047 Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/dungeon/the-dungeon-puzzlers-lament-1.png differ 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/hyperspace/hyperspace-roll-0.png b/website/agb/src/app/showcase/data/tapir/hyperspace/hyperspace-roll-0.png new file mode 100644 index 00000000..d03f89eb Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/hyperspace/hyperspace-roll-0.png differ diff --git a/website/agb/src/app/showcase/data/tapir/hyperspace/hyperspace-roll-1.png b/website/agb/src/app/showcase/data/tapir/hyperspace/hyperspace-roll-1.png new file mode 100644 index 00000000..47f792df Binary files /dev/null and b/website/agb/src/app/showcase/data/tapir/hyperspace/hyperspace-roll-1.png differ diff --git a/website/agb/src/app/showcase/data/tapir/hyperspace/hyperspace.tsx b/website/agb/src/app/showcase/data/tapir/hyperspace/hyperspace.tsx new file mode 100644 index 00000000..945dc2dd --- /dev/null +++ b/website/agb/src/app/showcase/data/tapir/hyperspace/hyperspace.tsx @@ -0,0 +1,30 @@ +import { ShowcaseGame, shuffle } from "@/app/showcase/games"; +import h1 from "./hyperspace-roll-0.png"; +import h2 from "./hyperspace-roll-1.png"; + +const Screenshots = [h1, h2]; + +export const Hyperspace: ShowcaseGame = { + name: "Hyperspace Roll", + developers: shuffle(["Corwin Kuiper", "Gwilym Inzani", "Sam Williams"]), + screenshots: Screenshots, + description: ( + <> +

+ Get through as many levels as possible in this space themed, dice + rolling roguelike. +

+

+ Build up powerful combos to defeat enemies which keep getting stronger. + Slowly acquire more dice and upgrade them in order to handle the + increasing strength of the enemies you face. +

+ +

+ Hyperspace Roll was influenced by great games such as Slay the Spire, + FTL and the board game Escape: The Curse of the Temple. +

+ + ), + itch: new URL("https://lostimmortal.itch.io/hyperspace-roll"), +}; 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..952b1106 --- /dev/null +++ b/website/agb/src/app/showcase/games.tsx @@ -0,0 +1,34 @@ +import { StaticImageData } from "next/image"; +import { ReactNode } from "react"; +import { HatWiz } from "./data/tapir/hatwiz/hatwiz"; +import { Purple } from "./data/tapir/purple/purple"; +import { Hyperspace } from "./data/tapir/hyperspace/hyperspace"; +import { Dungeon } from "./data/tapir/dungeon/dungeon"; + +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[] = shuffle([ + HatWiz, + Purple, + Hyperspace, + Dungeon, +]); diff --git a/website/agb/src/app/showcase/page.tsx b/website/agb/src/app/showcase/page.tsx new file mode 100644 index 00000000..fcb2a42e --- /dev/null +++ b/website/agb/src/app/showcase/page.tsx @@ -0,0 +1,39 @@ +import { Metadata } from "next"; +import { ContentBlock } from "@/components/contentBlock"; +import { Games, ShowcaseGame } from "./games"; +import { slugify } from "@/sluggify"; +import { GameDisplay, GameGrid, GameImage } from "./styles"; + +export const metadata: Metadata = { + title: "Showcase - agb", +}; + +export default function ColourPickerPage() { + return ( + <> + +

Showcase

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

{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..6eac2dae --- /dev/null +++ b/website/agb/src/app/showcase/styles.tsx @@ -0,0 +1,34 @@ +"use client"; + +import Link from "next/link"; +import styled from "styled-components"; +import Image from "next/image"; + +export const GameGrid = styled.div` + display: grid; + grid-template-columns: repeat(auto-fit, min(100vw, 600px)); + justify-content: center; + gap: 48px; +`; + +export const GameImage = styled(Image)` + width: 100%; + width: max( + round(down, 100%, calc(240 * var(--device-pixel))), + min(calc(240 * var(--device-pixel)), 100vw) + ); + height: auto; + image-rendering: pixelated; +`; + +export const GameDisplay = styled(Link)` + width: 100%; + 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 91% rename from website/agb/src/app/contentBlock.tsx rename to website/agb/src/components/contentBlock.tsx index 8a05d749..20e7e3a1 100644 --- a/website/agb/src/app/contentBlock.tsx +++ b/website/agb/src/components/contentBlock.tsx @@ -14,11 +14,8 @@ const Section = styled.section<{ $color: string }>` const CENTERED_CSS = ` margin-left: auto; margin-right: auto; - max-width: 60%; - - @media (max-width: 40rem) { - max-width: 90%; - } + width: 60%; + min-width: min(95%, 1000px); `; export const CenteredBlock = styled.div` diff --git a/website/agb/src/components/externalLink.tsx b/website/agb/src/components/externalLink.tsx new file mode 100644 index 00000000..0bbdaa3a --- /dev/null +++ b/website/agb/src/components/externalLink.tsx @@ -0,0 +1,23 @@ +"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; + } +`; + +export const ExternalLinkBlock = styled.div` + display: flex; + flex-wrap: wrap; + gap: 16px; + justify-content: space-around; +`; 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("-"); +}