From b2096daeca32e206e2ac7df8abf0890df44b7d60 Mon Sep 17 00:00:00 2001
From: Corwin <corwin@kuiper.dev>
Date: Tue, 23 Apr 2024 22:19:23 +0100
Subject: [PATCH] add colour converter

---
 website/agb/src/app/colour/colour.tsx | 133 ++++++++++++++++++++++++++
 website/agb/src/app/colour/page.tsx   |  10 ++
 2 files changed, 143 insertions(+)
 create mode 100644 website/agb/src/app/colour/colour.tsx
 create mode 100644 website/agb/src/app/colour/page.tsx

diff --git a/website/agb/src/app/colour/colour.tsx b/website/agb/src/app/colour/colour.tsx
new file mode 100644
index 00000000..77d11789
--- /dev/null
+++ b/website/agb/src/app/colour/colour.tsx
@@ -0,0 +1,133 @@
+"use client";
+
+import { ContentBlock } from "../contentBlock";
+import { useState } from "react";
+import { styled } from "styled-components";
+
+interface Colour {
+  r: number;
+  g: number;
+  b: number;
+}
+
+function fromHex(hex: string): Colour {
+  if (hex.startsWith("#")) {
+    hex = hex.slice(1);
+  }
+
+  const c = parseInt(hex, 16);
+
+  return {
+    r: c & 255,
+    g: (c >> 8) & 255,
+    b: (c >> 16) & 255,
+  };
+}
+
+function toHex(colour: Colour): string {
+  const hex = (colour.r | (colour.g << 8) | (colour.b << 16))
+    .toString(16)
+    .padStart(6, "0");
+
+  return `#${hex}`;
+}
+
+function fromRgb15(colour: number): Colour {
+  const r = colour & 31;
+  const g = (colour >> 5) & 31;
+  const b = (colour >> 10) & 31;
+
+  function upScale(a: number) {
+    return a << 3;
+  }
+  return {
+    r: upScale(r),
+    g: upScale(g),
+    b: upScale(b),
+  };
+}
+
+function toRgb15(colour: Colour): number {
+  const { r, g, b } = colour;
+  return ((r >> 3) & 31) | (((g >> 3) & 31) << 5) | (((b >> 3) & 31) << 10);
+}
+
+export default function ColourPicker() {
+  const [colour, setColour] = useState(fromHex("#FFFFFF"));
+  const gbaColour = fromRgb15(toRgb15(colour));
+
+  const hexColour = toHex(colour);
+  const gbaHexColour = toHex(gbaColour);
+  const gbaU16 = `0x${toRgb15(colour).toString(16)}`;
+
+  function setHexColour(colour: string) {
+    setColour(fromHex(colour));
+  }
+
+  function setGbaHexColour(colour: string) {
+    setColour(fromRgb15(toRgb15(fromHex(colour))));
+  }
+
+  return (
+    <ContentBlock>
+      <h1>agbrs colour converter</h1>
+      <PickerWrapper>
+        <PickerColumn>
+          <h2>Regular RGB8</h2>
+          <ColourInput
+            type="color"
+            value={hexColour}
+            onChange={(evt) => setHexColour(evt.target.value)}
+          />
+          <Input
+            type="text"
+            value={hexColour}
+            onChange={(evt) => setHexColour(evt.target.value)}
+          />
+        </PickerColumn>
+        <PickerColumn>
+          <h2>GBA RGB5</h2>
+          <ColourInput
+            type="color"
+            value={gbaHexColour}
+            onChange={(evt) => setGbaHexColour(evt.target.value)}
+          />
+          <Input
+            type="text"
+            value={gbaHexColour}
+            onChange={(evt) => setGbaHexColour(evt.target.value)}
+          />
+          <Input
+            type="text"
+            value={gbaU16}
+            onChange={(evt) =>
+              setColour(fromRgb15(parseInt(evt.target.value, 16)))
+            }
+          />
+        </PickerColumn>
+      </PickerWrapper>
+    </ContentBlock>
+  );
+}
+
+const PickerColumn = styled.div`
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 8px;
+  min-width: 40%;
+`;
+
+const PickerWrapper = styled.div`
+  display: flex;
+  justify-content: space-around;
+`;
+
+const Input = styled.input`
+  width: 100%;
+`;
+
+const ColourInput = styled(Input)`
+  height: 100px;
+  color: #33a012;
+`;
diff --git a/website/agb/src/app/colour/page.tsx b/website/agb/src/app/colour/page.tsx
new file mode 100644
index 00000000..6d760631
--- /dev/null
+++ b/website/agb/src/app/colour/page.tsx
@@ -0,0 +1,10 @@
+import { Metadata } from "next";
+import ColourPicker from "./colour";
+
+export const metadata: Metadata = {
+  title: "Colour Converter",
+};
+
+export default function ColourPickerPage() {
+  return <ColourPicker />;
+}