diff --git a/README.md b/README.md
index ef8fdf4..c6d34f7 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
## chess wee woo
+---
+
attempt at making a chess game in React
technologies:
@@ -11,9 +13,9 @@ technologies:
todo:
-- fix board rendering from x,y to y,x
- add remaining pieces and some custom ones
- improve move system
-- allow rendering based on player color
-- server setup with firebase
+- server setup with supbase
+ - authentication
+ - networking
- page to allow matchmaking
diff --git a/chess/piece_info.tsx b/chess/piece_info.tsx
index 1698374..2f0daa9 100644
--- a/chess/piece_info.tsx
+++ b/chess/piece_info.tsx
@@ -1,6 +1,6 @@
import {piece_id, PieceInfoMap} from "./types";
-import {testpiece} from "./pieces/test";
+import {testpiece} from "./pieces/piece";
import {rook} from "./pieces/rook";
import {pawn} from "./pieces/pawn";
import {knight} from "./pieces/knight";
diff --git a/chess/pieces/bishop.tsx b/chess/pieces/bishop.tsx
index 6e10a1f..630b57d 100644
--- a/chess/pieces/bishop.tsx
+++ b/chess/pieces/bishop.tsx
@@ -1,31 +1,25 @@
import Image from "next/image";
-import { board, color_id, move, move_type, piece, PieceInfo, PieceRenderProps, point } from "../types";
-import { in_bounds } from "../utils";
+import {board, color_id, move, move_type, piece, PieceInfo, PieceRenderProps, point} from "../types";
+import {in_bounds} from "../utils";
+import {edge_mover} from "./piece";
export const bishop: PieceInfo = {
- render: (color) => ,
- moves: moves_bishop
+ render: (color) => ,
+ moves: moves_bishop
}
-function Bishop({ color }: PieceRenderProps) {
- return ;
+function Bishop({color}: PieceRenderProps) {
+ return ;
}
function moves_bishop(board: board, position: point): move[] {
- let moves: move[] = [];
+ const directions = [
+ {x: -1, y: -1},
+ {x: -1, y: +1},
+ {x: +1, y: -1},
+ {x: +1, y: +1}
+ ];
- const vecs: point[] = [{ x: -1, y: -1 }, { x: -1, y: 1}, { x: 1, y: - 1}, { x: 1, y: 1}];
- const my_color = board[position.x][position.y].color;
-
- vecs.forEach( vec => {
- for (let i = 1; i < 8; ++i) {
- const dest: point = {x: position.x + vec.x * i, y: position.y + vec.y * i};
- if (!in_bounds(dest.x) || !in_bounds(dest.y) || board[dest.x][dest.y].color === my_color) { break; }
- if (board[dest.x][dest.y].color !== color_id.none) { moves.push({ position: dest, type: move_type.capture }); break; }
- moves.push({ position: dest, type: move_type.move })
- }
- })
-
- return moves;
+ return edge_mover(board, position, directions);
}
diff --git a/chess/pieces/knight.tsx b/chess/pieces/knight.tsx
index 795232a..b1a1805 100644
--- a/chess/pieces/knight.tsx
+++ b/chess/pieces/knight.tsx
@@ -9,7 +9,7 @@ export const knight: PieceInfo = {
}
function Knight({color}: PieceRenderProps) {
- return ;
+ return ;
}
function moves_knight(board: board, position: point): move[] {
diff --git a/chess/pieces/pawn.tsx b/chess/pieces/pawn.tsx
index 9e88947..2d55f63 100644
--- a/chess/pieces/pawn.tsx
+++ b/chess/pieces/pawn.tsx
@@ -9,7 +9,7 @@ export const pawn: PieceInfo = {
}
function Pawn({color}: PieceRenderProps) {
- return ;
+ return ;
}
function moves_pawn(board: board, position: point): move[] {
diff --git a/chess/pieces/piece.tsx b/chess/pieces/piece.tsx
new file mode 100644
index 0000000..f19ed21
--- /dev/null
+++ b/chess/pieces/piece.tsx
@@ -0,0 +1,44 @@
+import Image from "next/image";
+
+import {board, color_id, move, move_type, PieceInfo, point} from "../types";
+import {in_bounds} from "../utils";
+
+export const testpiece: PieceInfo = {
+ render: () => ,
+ moves: moves_test
+}
+
+function TestPiece() {
+ return ;
+}
+
+function moves_test(board: board, position: point): move[] {
+ return [
+ {position: {x: position.x - 1, y: position.y}, type: move_type.move},
+ {position: {x: position.x + 1, y: position.y}, type: move_type.move},
+ {position: {x: position.x, y: position.y - 1}, type: move_type.move},
+ {position: {x: position.x, y: position.y + 1}, type: move_type.move},
+ ]
+}
+
+export function edge_mover(board: board, position: point, directions: point[]): move[] {
+ const piece = board[position.x][position.y];
+ let moves: move[] = [];
+
+ directions.forEach(direction => {
+ let current_pos = position;
+ while (true) {
+ if (!in_bounds(current_pos.x + direction.x) || !in_bounds(current_pos.y + direction.y) || board[current_pos.x + direction.x][current_pos.y + direction.y].color === piece.color) {
+ break;
+ }
+ if (board[current_pos.x + direction.x][current_pos.y + direction.y].color !== color_id.none) {
+ moves.push({ position: {x: current_pos.x + direction.x, y: current_pos.y + direction.y}, type: move_type.capture });
+ break;
+ }
+ moves.push({ position: {x: current_pos.x + direction.x, y: current_pos.y + direction.y}, type: move_type.move });
+ current_pos = {x: current_pos.x + direction.x, y: current_pos.y + direction.y};
+ }
+ })
+
+ return moves;
+}
diff --git a/chess/pieces/queen.tsx b/chess/pieces/queen.tsx
index 7eb1f4b..22839b4 100644
--- a/chess/pieces/queen.tsx
+++ b/chess/pieces/queen.tsx
@@ -2,6 +2,7 @@ import Image from "next/image";
import { board, color_id, move, move_type, piece, PieceInfo, PieceRenderProps, point } from "../types";
import { in_bounds } from "../utils";
+import {edge_mover} from "./piece";
export const queen: PieceInfo = {
render: (color) => ,
@@ -13,24 +14,16 @@ function Queen({ color }: PieceRenderProps) {
}
function moves_queen(board: board, position: point): move[] {
- let moves: move[] = [];
+ const directions = [
+ {x: -1, y: -1},
+ {x: 0, y: -1},
+ {x: +1, y: -1},
+ {x: +1, y: 0},
+ {x: +1, y: +1},
+ {x: 0, y: +1},
+ {x: -1, y: +1},
+ {x: -1, y: 0},
+ ];
- const my_color = board[position.x][position.y].color;
- let vecs: point[] = [];
- for (let i = -1; i <= 1; ++i) {
- for (let j = -1; j <= 1; ++j) {
- vecs.push({ x: i, y: j});
- }
- }
-
- vecs.forEach(vec => {
- for (let i = 1; i < 8; ++i) {
- const dest: point = { x: position.x + vec.x * i, y: position.y + vec.y * i };
- if (!in_bounds(dest.x) || !in_bounds(dest.y) || board[dest.x][dest.y].color === my_color) { break; }
- if (board[dest.x][dest.y].color !== color_id.none) { moves.push({ position: dest, type: move_type.capture }); break; }
- moves.push({ position: dest, type: move_type.move })
- }
- })
-
- return moves;
+ return edge_mover(board, position, directions);
}
diff --git a/chess/pieces/rook.tsx b/chess/pieces/rook.tsx
index f0d502a..f26e0f9 100644
--- a/chess/pieces/rook.tsx
+++ b/chess/pieces/rook.tsx
@@ -1,6 +1,7 @@
import Image from "next/image";
import {board, move, move_type, piece_id, PieceInfo, PieceRenderProps, point} from "../types";
+import {edge_mover} from "./piece";
export const rook: PieceInfo = {
render: (color) => ,
@@ -8,47 +9,16 @@ export const rook: PieceInfo = {
}
function Rook({color}: PieceRenderProps) {
- return ;
+ return ;
}
function moves_rook(board: board, position: point): move[] {
- let moves: move[] = [];
-
- let pos_x = position.x - 1;
- while (pos_x >= 0 && board[pos_x][position.y].piece === piece_id.none) {
- moves.push({position: {x: pos_x, y: position.y}, type: move_type.move});
- pos_x--;
- }
- if (pos_x >= 0 && board[pos_x][position.y].color !== board[position.x][position.y].color) {
- moves.push({position: {x: pos_x, y: position.y}, type: move_type.capture});
- }
-
- pos_x = position.x + 1;
- while (pos_x <= 7 && board[pos_x][position.y].piece === piece_id.none) {
- moves.push({position: {x: pos_x, y: position.y}, type: move_type.move});
- pos_x++;
- }
- if (pos_x <= 7 && board[pos_x][position.y].color !== board[position.x][position.y].color) {
- moves.push({position: {x: pos_x, y: position.y}, type: move_type.capture});
- }
-
- let pos_y = position.y - 1;
- while (pos_y >= 0 && board[position.x][pos_y].piece === piece_id.none) {
- moves.push({position: {x: position.x, y: pos_y}, type: move_type.move});
- pos_y--;
- }
- if (pos_y >= 0 && board[position.x][pos_y].color !== board[position.x][position.y].color) {
- moves.push({position: {x: position.x, y: pos_y}, type: move_type.capture});
- }
-
- pos_y = position.y + 1;
- while (pos_y <= 7 && board[position.x][pos_y].piece === piece_id.none) {
- moves.push({position: {x: position.x, y: pos_y}, type: move_type.move});
- pos_y++;
- }
- if (pos_y <= 7 && board[position.x][pos_y].color !== board[position.x][position.y].color) {
- moves.push({position: {x: position.x, y: pos_y}, type: move_type.capture});
- }
-
- return moves;
+ const directions = [
+ {x: +1, y: 0},
+ {x: -1, y: 0},
+ {x: 0, y: +1},
+ {x: 0, y: -1},
+ ];
+
+ return edge_mover(board, position, directions);
}
diff --git a/chess/pieces/test.tsx b/chess/pieces/test.tsx
deleted file mode 100644
index 9aa8c81..0000000
--- a/chess/pieces/test.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import Image from "next/image";
-
-import {board, move, move_type, PieceInfo, point} from "../types";
-
-export const testpiece: PieceInfo = {
- render: () => ,
- moves: moves_test
-}
-
-function TestPiece() {
- return ;
-}
-
-function moves_test(board: board, position: point): move[] {
- return [
- {position: {x: position.x - 1, y: position.y}, type: move_type.move},
- {position: {x: position.x + 1, y: position.y}, type: move_type.move},
- {position: {x: position.x, y: position.y - 1}, type: move_type.move},
- {position: {x: position.x, y: position.y + 1}, type: move_type.move},
- ]
-}
diff --git a/components/board.tsx b/components/board.tsx
index 61618d5..835ceed 100644
--- a/components/board.tsx
+++ b/components/board.tsx
@@ -1,8 +1,9 @@
-import {useMemo, useRef, useState} from "react";
+import {useEffect, useMemo, useRef, useState} from "react";
import {piece_info} from "../chess/piece_info";
import Square from "./square";
import {black_bishop, black_knight, black_pawn, black_queen, black_rook, board, board_state, BoardProps, color_id, move_type, p, piece, point, white_bishop, white_knight, white_pawn, white_queen, white_rook} from "../chess/types";
+import {supabase} from "../chess/supabase";
function get_initial_board(): piece[][] {
return [
@@ -18,11 +19,24 @@ function get_initial_board(): piece[][] {
}
export default function Board({side}: BoardProps) {
+ const room_id = "1234";
+
const [positions, set_positions] = useState(get_initial_board());
const [selected, set_selected] = useState(null);
const board_ref = useRef(null);
const positions_ref = useRef(positions);
+ // listen for changes to the current game
+ useEffect(() => {
+ const channel = supabase.channel("table-db-changes")
+ .on("postgres_changes",
+ {event: "UPDATE", schema: "public", table: "games", filter: "id = room_id"},
+ (payload => console.log(payload))).subscribe();
+ return () => {
+ channel.unsubscribe().then(r => console.log("unsubscribed:" + r));
+ };
+ })
+
const moves = useMemo(() => {
if (selected === null) {
return [];
diff --git a/components/game_list.tsx b/components/game_list.tsx
index c7c0b20..48fbbca 100644
--- a/components/game_list.tsx
+++ b/components/game_list.tsx
@@ -1,22 +1,36 @@
-import {supabase} from "../chess/supabase";
import {useEffect, useState} from "react";
+import {supabase} from "../chess/supabase";
+import {piece} from "../chess/types";
+
+type game = {
+ id: string;
+ created_at: string;
+ board: piece[][];
+ players: string[];
+}
+
export function GameList() {
- const [payloads, set_payloads] = useState([]);
+ const [games, set_games] = useState([]);
useEffect(() => {
- supabase.from("games").select().then(x => set_payloads(x.data!.map(x => JSON.stringify(x))));
+ supabase.from("games").select().then(x => set_games(x.data as game[]));
}, []);
useEffect(() => {
- console.log("subscribe")
- const channel = supabase.channel("table-db-changes").on("postgres_changes", {event: "UPDATE", schema: "public", table: "games"}, (payload => set_payloads(cur => [...cur, JSON.stringify(payload)]))).subscribe();
+ const channel = supabase.channel("table-db-changes").on("postgres_changes", {event: "*", schema: "public", table: "games"}, (payload => {
+ if (payload.eventType === "INSERT") {
+ set_games(games => [...games, payload.new as game]);
+ } else if (payload.eventType === "UPDATE") {
+ set_games(games => games.map(x => x.id === payload.new.id ? payload.new as game : x));
+ } else if (payload.eventType === "DELETE") {
+ set_games(games => games.filter(x => x.id !== payload.old.id));
+ }
+ })).subscribe();
return () => {
- channel.unsubscribe().then(r => console.log("unsubscribed:" + r))
+ channel.unsubscribe().then(r => console.log("unsubscribed:" + r));
};
}, []);
- return
- {payloads}
-
+ return {games?.map(x =>
{JSON.stringify(x)}
)}
;
}
diff --git a/components/piece.tsx b/components/piece.tsx
index 2b72d09..4463cd6 100644
--- a/components/piece.tsx
+++ b/components/piece.tsx
@@ -15,7 +15,6 @@ export default function Piece({x, y, piece, board, end_move, board_ref}: PiecePr
return (
= 16.3.0"
+ }
+ },
+ "node_modules/@supabase/auth-helpers-nextjs": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-nextjs/-/auth-helpers-nextjs-0.5.4.tgz",
+ "integrity": "sha512-Xm3BMDOYPbNyuh8UXDRgBDc3JkeM5S2PfuC1jFJ73CCay4YiH1YxTz06Cvtp+vLH432qdjnqH+49ehVvUehPnQ==",
+ "dependencies": {
+ "@supabase/auth-helpers-shared": "0.2.4"
+ },
+ "peerDependencies": {
+ "@supabase/supabase-js": "^2.0.4"
+ }
+ },
+ "node_modules/@supabase/auth-helpers-react": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-react/-/auth-helpers-react-0.3.1.tgz",
+ "integrity": "sha512-g3SFv08Dz9FapNif/ZY1b7qKGlMJDyTLSayHBz3kb3FuYxg7aLWgQtydDhm5AGbc0XtvpIBuhGTIOVevwpdosA==",
+ "peerDependencies": {
+ "@supabase/supabase-js": "^2.0.4"
+ }
+ },
+ "node_modules/@supabase/auth-helpers-shared": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-helpers-shared/-/auth-helpers-shared-0.2.4.tgz",
+ "integrity": "sha512-c+hi3N6DhjPTzjXGOokre4gmMZOqt0f1ORrwZwi2s07pk3cbkmn77DwwVtlYMNi3oZNYRQqAfxJu83UzpJrrmg==",
+ "peerDependencies": {
+ "@supabase/supabase-js": "^2.0.4"
+ }
+ },
+ "node_modules/@supabase/auth-ui-react": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-ui-react/-/auth-ui-react-0.2.6.tgz",
+ "integrity": "sha512-N2qxgsjxPQZPdDotVumzruj4RHaKNFb9ZRecttMeGOvrYFbMWRQVpWT/rYkTPsRW2phKiGXQlMwha6YxUE+t6Q==",
+ "dependencies": {
+ "@stitches/core": "^1.2.8",
+ "@stitches/react": "^1.2.8",
+ "prop-types": "^15.7.2"
+ },
+ "optionalDependencies": {
+ "fsevents": "^2.3.2"
+ },
+ "peerDependencies": {
+ "react": "^16.13.1 || ^17.0.1 || ^18.0.0",
+ "react-dom": "^16.13.1 || ^17.0.1 || ^18.0.0"
+ }
+ },
"node_modules/@supabase/functions-js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.0.0.tgz",
@@ -808,6 +871,21 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
+ "node_modules/bin-links": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.1.tgz",
+ "integrity": "sha512-bmFEM39CyX336ZGGRsGPlc6jZHriIoHacOQcTt72MktIjpPhZoP4te2jOyUXF3BLILmJ8aNLncoPVeIIFlrDeA==",
+ "dev": true,
+ "dependencies": {
+ "cmd-shim": "^6.0.0",
+ "npm-normalize-package-bin": "^3.0.0",
+ "read-cmd-shim": "^4.0.0",
+ "write-file-atomic": "^5.0.0"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -890,11 +968,29 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
},
+ "node_modules/cmd-shim": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.1.tgz",
+ "integrity": "sha512-S9iI9y0nKR4hwEQsVWpyxld/6kRfGepGfzff83FcaiEBpmvlbA2nnGe7Cylgrx2f/p1P5S5wpRm9oL8z1PbS3Q==",
+ "dev": true,
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -966,6 +1062,15 @@
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="
},
+ "node_modules/data-uri-to-buffer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -1648,6 +1753,29 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fetch-blob": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "dependencies": {
+ "node-domexception": "^1.0.0",
+ "web-streams-polyfill": "^3.0.3"
+ },
+ "engines": {
+ "node": "^12.20 || >= 14.13"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -1702,6 +1830,18 @@
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
},
+ "node_modules/formdata-polyfill": {
+ "version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
+ "dev": true,
+ "dependencies": {
+ "fetch-blob": "^3.1.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
"node_modules/framer-motion": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-8.0.2.tgz",
@@ -1724,11 +1864,48 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
+ "node_modules/fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/fs-minipass/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -2400,6 +2577,55 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/minipass": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz",
+ "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/minizlib/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true,
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -2477,6 +2703,25 @@
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -2506,6 +2751,15 @@
"node-gyp-build-test": "build-test.js"
}
},
+ "node_modules/npm-normalize-package-bin": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.0.tgz",
+ "integrity": "sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==",
+ "dev": true,
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -2832,6 +3086,15 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "node_modules/read-cmd-shim": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz",
+ "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==",
+ "dev": true,
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
@@ -3000,6 +3263,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true
+ },
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -3112,6 +3381,39 @@
}
}
},
+ "node_modules/supabase": {
+ "version": "1.34.5",
+ "resolved": "https://registry.npmjs.org/supabase/-/supabase-1.34.5.tgz",
+ "integrity": "sha512-RBIIZTwCB+Ap13p47XwM6eDq7kW+r8QiJyyVlL0NHPnwZv75Q51O12pQnvUCgmlQ0Xy3VDbJhxKkYLHMwLqxjw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "bin-links": "^4.0.1",
+ "node-fetch": "^3.2.10",
+ "tar": "6.1.13"
+ },
+ "bin": {
+ "supabase": "bin/supabase"
+ }
+ },
+ "node_modules/supabase/node_modules/node-fetch": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz",
+ "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==",
+ "dev": true,
+ "dependencies": {
+ "data-uri-to-buffer": "^4.0.0",
+ "fetch-blob": "^3.1.4",
+ "formdata-polyfill": "^4.0.10"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/node-fetch"
+ }
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -3157,6 +3459,23 @@
"node": ">=6"
}
},
+ "node_modules/tar": {
+ "version": "6.1.13",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz",
+ "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==",
+ "dev": true,
+ "dependencies": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^4.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -3303,6 +3622,15 @@
"node": ">=6.14.2"
}
},
+ "node_modules/web-streams-polyfill": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
+ "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
@@ -3388,6 +3716,19 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
+ "node_modules/write-file-atomic": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.0.tgz",
+ "integrity": "sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w==",
+ "dev": true,
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.7"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
"node_modules/yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
diff --git a/package.json b/package.json
index bc18535..a08965f 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,9 @@
},
"dependencies": {
"@next/font": "13.1.1",
+ "@supabase/auth-helpers-nextjs": "^0.5.4",
+ "@supabase/auth-helpers-react": "^0.3.1",
+ "@supabase/auth-ui-react": "^0.2.6",
"@supabase/supabase-js": "^2.4.1",
"@types/node": "18.11.18",
"@types/react": "18.0.26",
@@ -21,5 +24,8 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"typescript": "4.9.4"
+ },
+ "devDependencies": {
+ "supabase": "^1.34.5"
}
}
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 152f2b8..0b5162c 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -1,6 +1,13 @@
+import {Session, SessionContextProvider} from '@supabase/auth-helpers-react'
+import {AppProps} from 'next/app'
+
import '../styles/globals.css'
-import type {AppProps} from 'next/app'
+import {supabase} from "../chess/supabase";
-export default function App({ Component, pageProps }: AppProps) {
- return
+export default function App({Component, pageProps}: AppProps<{ initialSession: Session }>) {
+ return (
+
+
+
+ )
}
diff --git a/pages/game.tsx b/pages/game.tsx
index 8788561..1a83a04 100644
--- a/pages/game.tsx
+++ b/pages/game.tsx
@@ -1,4 +1,5 @@
import Head from 'next/head'
+import Link from "next/link";
import Board from "../components/board";
import {color_id} from "../chess/types";
@@ -12,6 +13,7 @@ export default function Game() {
+ back to home
diff --git a/pages/index.tsx b/pages/index.tsx
index ba6e182..bbd2e30 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,8 +1,23 @@
import Head from 'next/head'
import Link from "next/link";
-import {GameList} from "../components/game_list";
+import {Auth, ThemeSupa} from '@supabase/auth-ui-react'
+import {useSession} from '@supabase/auth-helpers-react'
+import {supabase} from "../chess/supabase";
export default function Home() {
+ const session = useSession();
+
+ // function that adds a row to the table "games" on supabase
+ async function create_game() {
+ let {error} = await supabase.from('games').insert({
+ board: [{hi: "hi"}, {lol: "hi2"}],
+ created_at: new Date().toISOString(),
+ });
+ if (error) {
+ throw error;
+ }
+ }
+
return (
<>
@@ -11,8 +26,25 @@ export default function Home() {
- view board
-
+ view test board
+ profile editor
+ play
+
+ {!session ? (
+
+ ) : (
+ <>
+
+
signed in
+
+ >
+ )}
+
source code
>
)
diff --git a/pages/play.tsx b/pages/play.tsx
new file mode 100644
index 0000000..41a93a3
--- /dev/null
+++ b/pages/play.tsx
@@ -0,0 +1,7 @@
+import {GameList} from "../components/game_list";
+import Link from "next/link";
+
+export default function Play() {
+ return <>
+ home>;
+}
diff --git a/pages/profile.tsx b/pages/profile.tsx
new file mode 100644
index 0000000..538691e
--- /dev/null
+++ b/pages/profile.tsx
@@ -0,0 +1,54 @@
+import {supabase} from "../chess/supabase";
+import {User, useUser} from "@supabase/auth-helpers-react";
+import {useEffect, useState} from "react";
+import Link from "next/link";
+import Image from "next/image";
+
+function Pro({user}: { user: User }) {
+ const [username, set_username] = useState("");
+ const [image_link, set_image_link] = useState("");
+ const [username_input, set_username_input] = useState("");
+ const id = user.id;
+
+ useEffect(() => {
+ supabase.from("users").select().eq('id', id).single().then(x => {
+ set_username(x.data.username);
+ set_image_link(x.data.avatar_url);
+ });
+ }, [id]);
+
+ useEffect(() => {
+
+ console.log("sub");
+ const channel = supabase.channel("table-db-changes").on("postgres_changes", {event: "UPDATE", schema: "public", table: "users"}, (payload => {
+ console.log(payload);
+ set_username(payload.new.username);
+ })).subscribe();
+ return () => {
+ supabase.removeChannel(channel).then(r => console.log("unsub:" + r));
+ };
+ }, []);
+
+ return (
+ <>
+ set_username_input(e.target.value)}/>
+
+ hello {username}
+
+ go to game
+ go to home
+ >
+ )
+}
+
+export default function Profile() {
+ const user = useUser();
+
+ return user ? : no user! wtf!
;
+}
diff --git a/styles/globals.css b/styles/globals.css
index d4f491e..5eac688 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -1,107 +1,480 @@
-:root {
- --max-width: 1100px;
- --border-radius: 12px;
- --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
- 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
- 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;
-
- --foreground-rgb: 0, 0, 0;
- --background-start-rgb: 214, 219, 220;
- --background-end-rgb: 255, 255, 255;
-
- --primary-glow: conic-gradient(
- from 180deg at 50% 50%,
- #16abff33 0deg,
- #0885ff33 55deg,
- #54d6ff33 120deg,
- #0071ff33 160deg,
- transparent 360deg
- );
- --secondary-glow: radial-gradient(
- rgba(255, 255, 255, 1),
- rgba(255, 255, 255, 0)
- );
-
- --tile-start-rgb: 239, 245, 249;
- --tile-end-rgb: 228, 232, 233;
- --tile-border: conic-gradient(
- #00000080,
- #00000040,
- #00000030,
- #00000020,
- #00000010,
- #00000010,
- #00000080
- );
-
- --callout-rgb: 238, 240, 241;
- --callout-border-rgb: 172, 175, 176;
- --card-rgb: 180, 185, 188;
- --card-border-rgb: 131, 134, 135;
-}
-
-@media (prefers-color-scheme: dark) {
- :root {
- --foreground-rgb: 255, 255, 255;
- --background-start-rgb: 0, 0, 0;
- --background-end-rgb: 0, 0, 0;
-
- --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
- --secondary-glow: linear-gradient(
- to bottom right,
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0),
- rgba(1, 65, 255, 0.3)
- );
-
- --tile-start-rgb: 2, 13, 46;
- --tile-end-rgb: 2, 5, 19;
- --tile-border: conic-gradient(
- #ffffff80,
- #ffffff40,
- #ffffff30,
- #ffffff20,
- #ffffff10,
- #ffffff10,
- #ffffff80
- );
-
- --callout-rgb: 20, 20, 20;
- --callout-border-rgb: 108, 108, 108;
- --card-rgb: 100, 100, 100;
- --card-border-rgb: 200, 200, 200;
- }
+html,
+body {
+ --custom-font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
+ Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
+ --custom-bg-color: #101010;
+ --custom-panel-color: #222;
+ --custom-box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.8);
+ --custom-color: #fff;
+ --custom-color-brand: #24b47e;
+ --custom-color-secondary: #666;
+ --custom-border: 1px solid #333;
+ --custom-border-radius: 5px;
+ --custom-spacing: 5px;
+
+ padding: 0;
+ margin: 0;
+ font-family: var(--custom-font-family);
+ background-color: var(--custom-bg-color);
}
* {
+ color: var(--custom-color);
+ font-family: var(--custom-font-family);
box-sizing: border-box;
- padding: 0;
- margin: 0;
}
html,
-body {
- max-width: 100vw;
+body,
+#__next {
+ height: 100vh;
+ width: 100vw;
overflow-x: hidden;
}
-body {
- color: rgb(var(--foreground-rgb));
- background: linear-gradient(
- to bottom,
- transparent,
- rgb(var(--background-end-rgb))
- )
- rgb(var(--background-start-rgb));
+/* Grid */
+
+.container {
+ width: 90%;
+ margin-left: auto;
+ margin-right: auto;
}
-a {
- color: inherit;
- text-decoration: none;
+.row {
+ position: relative;
+ width: 100%;
+}
+
+.row [class^='col'] {
+ float: left;
+ margin: 0.5rem 2%;
+ min-height: 0.125rem;
+}
+
+.col-1,
+.col-2,
+.col-3,
+.col-4,
+.col-5,
+.col-6,
+.col-7,
+.col-8,
+.col-9,
+.col-10,
+.col-11,
+.col-12 {
+ width: 96%;
+}
+
+.col-1-sm {
+ width: 4.33%;
+}
+
+.col-2-sm {
+ width: 12.66%;
+}
+
+.col-3-sm {
+ width: 21%;
+}
+
+.col-4-sm {
+ width: 29.33%;
+}
+
+.col-5-sm {
+ width: 37.66%;
+}
+
+.col-6-sm {
+ width: 46%;
+}
+
+.col-7-sm {
+ width: 54.33%;
+}
+
+.col-8-sm {
+ width: 62.66%;
+}
+
+.col-9-sm {
+ width: 71%;
+}
+
+.col-10-sm {
+ width: 79.33%;
+}
+
+.col-11-sm {
+ width: 87.66%;
+}
+
+.col-12-sm {
+ width: 96%;
+}
+
+.row::after {
+ content: '';
+ display: table;
+ clear: both;
+}
+
+.hidden-sm {
+ display: none;
+}
+
+@media only screen and (min-width: 33.75em) {
+ /* 540px */
+ .container {
+ width: 80%;
+ }
+}
+
+@media only screen and (min-width: 45em) {
+ /* 720px */
+ .col-1 {
+ width: 4.33%;
+ }
+
+ .col-2 {
+ width: 12.66%;
+ }
+
+ .col-3 {
+ width: 21%;
+ }
+
+ .col-4 {
+ width: 29.33%;
+ }
+
+ .col-5 {
+ width: 37.66%;
+ }
+
+ .col-6 {
+ width: 46%;
+ }
+
+ .col-7 {
+ width: 54.33%;
+ }
+
+ .col-8 {
+ width: 62.66%;
+ }
+
+ .col-9 {
+ width: 71%;
+ }
+
+ .col-10 {
+ width: 79.33%;
+ }
+
+ .col-11 {
+ width: 87.66%;
+ }
+
+ .col-12 {
+ width: 96%;
+ }
+
+ .hidden-sm {
+ display: block;
+ }
+}
+
+@media only screen and (min-width: 60em) {
+ /* 960px */
+ .container {
+ width: 75%;
+ max-width: 60rem;
+ }
+}
+
+/* Forms */
+
+label {
+ display: block;
+ margin: 5px 0;
+ color: var(--custom-color-secondary);
+ font-size: 0.8rem;
+ text-transform: uppercase;
+}
+
+input {
+ width: 100%;
+ border-radius: 5px;
+ border: var(--custom-border);
+ padding: 8px;
+ font-size: 0.9rem;
+ background-color: var(--custom-bg-color);
+ color: var(--custom-color);
+}
+
+input[disabled] {
+ color: var(--custom-color-secondary);
+}
+
+/* Utils */
+
+.block {
+ display: block;
+ width: 100%;
+}
+
+.inline-block {
+ display: inline-block;
+ width: 100%;
+}
+
+.flex {
+ display: flex;
+}
+
+.flex.column {
+ flex-direction: column;
+}
+
+.flex.row {
+ flex-direction: row;
+}
+
+.flex.flex-1 {
+ flex: 1 1 0;
+}
+
+.flex-end {
+ justify-content: flex-end;
+}
+
+.flex-center {
+ justify-content: center;
+}
+
+.items-center {
+ align-items: center;
+}
+
+.text-sm {
+ font-size: 0.8rem;
+ font-weight: 300;
+}
+
+.text-right {
+ text-align: right;
+}
+
+.font-light {
+ font-weight: 300;
+}
+
+.opacity-half {
+ opacity: 50%;
+}
+
+/* Button */
+
+button,
+.button {
+ color: var(--custom-color);
+ border: var(--custom-border);
+ background-color: var(--custom-bg-color);
+ display: inline-block;
+ text-align: center;
+ border-radius: var(--custom-border-radius);
+ padding: 0.5rem 1rem;
+ cursor: pointer;
+ font-size: 0.9rem;
+ text-transform: uppercase;
+}
+
+button.primary,
+.button.primary {
+ background-color: var(--custom-color-brand);
+ border: 1px solid var(--custom-color-brand);
+}
+
+/* Widgets */
+
+.card {
+ width: 100%;
+ display: block;
+ border: var(--custom-border);
+ border-radius: var(--custom-border-radius);
+ padding: var(--custom-spacing);
+}
+
+.avatar {
+ border-radius: var(--custom-border-radius);
+ overflow: hidden;
+ max-width: 100%;
+}
+
+.avatar.image {
+ object-fit: cover;
+}
+
+.avatar.no-image {
+ background-color: #333;
+ border: 1px solid rgb(200, 200, 200);
+ border-radius: 5px;
+}
+
+.footer {
+ position: absolute;
+ max-width: 100%;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ flex-flow: row;
+ border-top: var(--custom-border);
+ background-color: var(--custom-bg-color);
+}
+
+.footer div {
+ padding: var(--custom-spacing);
+ display: flex;
+ align-items: center;
+ width: 100%;
+}
+
+.footer div > img {
+ height: 20px;
+ margin-left: 10px;
+}
+
+.footer > div:first-child {
+ display: none;
+}
+
+.footer > div:nth-child(2) {
+ justify-content: left;
}
-@media (prefers-color-scheme: dark) {
- html {
- color-scheme: dark;
+@media only screen and (min-width: 60em) {
+ /* 960px */
+ .footer > div:first-child {
+ display: flex;
}
+
+ .footer > div:nth-child(2) {
+ justify-content: center;
+ }
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.mainHeader {
+ width: 100%;
+ font-size: 1.3rem;
+ margin-bottom: 20px;
+}
+
+.avatarPlaceholder {
+ border: var(--custom-border);
+ border-radius: var(--custom-border-radius);
+ width: 35px;
+ height: 35px;
+ background-color: rgba(255, 255, 255, 0.2);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+/* Auth */
+
+.auth-widget {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.auth-widget > .button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: none;
+ background-color: #444444;
+ text-transform: none !important;
+ transition: all 0.2s ease;
+}
+
+.auth-widget .button:hover {
+ background-color: #2a2a2a;
+}
+
+.auth-widget .button > .loader,
+.account .button > .loader {
+ width: 17px;
+ animation: spin 1s linear infinite;
+ filter: invert(1);
+}
+
+/* Account */
+
+.account {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.account > * > .avatarField {
+ display: flex;
+ align-items: center;
+ margin-bottom: 30px;
+}
+
+.account > * > .avatarField > .avatarContainer {
+ margin-right: 20px;
+}
+
+/* Profile Card */
+
+.profileCard {
+ border-radius: 5px;
+ display: flex;
+ border: var(--custom-border);
+ background-color: var(--custom-panel-color);
+ padding: 20px 20px;
+ margin-bottom: 20px;
+}
+
+.profileCard:last-child {
+ margin-bottom: 0;
+}
+
+.profileCard > .userInfo {
+ margin-left: 20px;
+ font-weight: 300;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.profileCard > .userInfo > p {
+ margin: 0;
+}
+
+.profileCard > .userInfo > .username {
+ font-size: 1.3rem;
+ font-weight: 500;
+ margin-bottom: 5px;
+}
+
+.profileCard > .userInfo > .website {
+ font-size: 0.9rem;
+ color: var(--custom-color-brand);
+ margin-bottom: 10px;
+ text-decoration: none;
}