diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 98c0e5d..7be2c22 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -5,7 +5,7 @@
import lifeGameJS from "@/iframe/life-game.js?raw";
import patterns from "$lib/board-templates";
import * as icons from "$lib/icons/index.ts";
- import { loadBoard, saveBoard } from "./api.ts";
+ import { saveBoard, fetchBoardList, loadBoardById, type BoardListItem } from "./api.ts";
let editingCode = $state(lifeGameJS);
let appliedCode = $state(lifeGameJS);
@@ -23,9 +23,14 @@
let generationFigure = $state(0);
let sizeValue = $state(20);
- type SaveState = { saving: false } | { saving: true; boardData: boolean[][] };
+ type SaveState = { saving: false } | { saving: true; boardData: boolean[][]; boardName: string };
let saveState: SaveState = $state({ saving: false });
- let boardNameInput = $state("");
+
+ type LoadState =
+ | { state: "closed" }
+ | { state: "loading" }
+ | { state: "list"; list: BoardListItem[] };
+ let loadState: LoadState = $state({ state: "closed" });
type OngoingEvent =
| "play"
@@ -56,8 +61,7 @@
break;
}
case "save_board": {
- saveState = { saving: true, boardData: event.data.data as boolean[][] };
- boardNameInput = "";
+ saveState = { saving: true, boardData: event.data.data as boolean[][], boardName: "" };
break;
}
default: {
@@ -81,20 +85,32 @@
async function handleSave() {
if (!saveState.saving) return;
- const name = boardNameInput.trim() === "" ? "Unnamed Board" : boardNameInput.trim();
+ const name = saveState.boardName.trim() === "" ? "Unnamed Board" : saveState.boardName.trim();
await saveBoard({ board: saveState.boardData, name: name }, isJapanese);
saveState = { saving: false };
- boardNameInput = "";
}
async function handleLoad() {
- const board = await loadBoard(isJapanese);
+ loadState = { state: "loading" };
+
+ const list = await fetchBoardList(isJapanese);
+
+ if (list) {
+ loadState = { state: "list", list };
+ } else {
+ loadState = { state: "closed" };
+ }
+ }
+
+ async function selectBoard(id: number) {
+ loadState = { state: "closed" };
+
+ const board = await loadBoardById(id, isJapanese);
if (board) {
sendEvent("apply_board", board);
}
- return;
}
@@ -196,34 +212,87 @@
-
-
-
+
+
+
+
-
-
+
-
+
{
isProgress = false;
+ sendEvent("pause");
sendEvent("save_board");
}}
>
diff --git a/src/routes/api.ts b/src/routes/api.ts
index 711c995..0c126da 100644
--- a/src/routes/api.ts
+++ b/src/routes/api.ts
@@ -32,7 +32,13 @@ export async function saveBoard(data: { board: boolean[][]; name: string }, isJa
}
}
-export async function loadBoard(isJapanese: boolean): Promise {
+export type BoardListItem = {
+ id: number;
+ boardName: string;
+ createdAt: string;
+};
+
+export async function fetchBoardList(isJapanese: boolean): Promise {
try {
const response = await fetch("/api/board");
@@ -52,9 +58,46 @@ export async function loadBoard(isJapanese: boolean): Promise {
+ try {
+ const response = await fetch(`/api/board?id=${id}`);
+
+ if (!response.ok) {
+ if (response.status === 404) {
+ if (isJapanese) {
+ throw new Error("指定されたIDのデータが見つかりません。");
+ } else {
+ throw new Error("The specified ID data was not found.");
+ }
+ } else {
+ if (isJapanese) {
+ throw new Error("サーバーとの通信に失敗しました。");
+ } else {
+ throw new Error("Failed to communicate with the server.");
+ }
+ }
+ }
+
const loadedBoard = await response.json();
- return loadedBoard as boolean[][]; // TODO: add proper types
+ return loadedBoard as boolean[][];
} catch (err) {
if (isJapanese) {
console.error("読込エラー:", err);
diff --git a/src/routes/api/board/+server.ts b/src/routes/api/board/+server.ts
index 9270476..d79eeed 100644
--- a/src/routes/api/board/+server.ts
+++ b/src/routes/api/board/+server.ts
@@ -28,17 +28,43 @@ export async function POST({ request }) {
return json(newState, { status: 201 });
}
-export async function GET() {
- // データベースから一番「最後」に保存されたデータを1件だけ探す
- const latestState = await prisma.boardState.findFirst({
- orderBy: {
- createdAt: "desc", // 作成日時(createdAt)の降順(desc)で並び替え
- },
- });
+export async function GET({ url }) {
+ const boardId = url.searchParams.get("id");
- if (!latestState) {
- return json({ message: "No state found" }, { status: 404 });
- }
+ if (boardId) {
+ //IDが指定された場合、そのIDの盤面を返す
+ const id = parseInt(boardId, 10);
+ if (isNaN(id)) {
+ return json({ message: "無効なIDです。" }, { status: 400 });
+ }
+
+ const state = await prisma.boardState.findUnique({
+ where: { id: id },
+ select: { boardData: true },
+ });
- return json(latestState.boardData);
+ if (!state) {
+ return json({ message: `ID: ${id} の盤面は見つかりません。` }, { status: 404 });
+ }
+
+ return json(state.boardData);
+ } else {
+ //IDが指定されなかった場合、全ての盤面のリストを返す
+ const allStates = await prisma.boardState.findMany({
+ orderBy: {
+ createdAt: "desc",
+ },
+ select: {
+ id: true,
+ boardName: true,
+ createdAt: true,
+ },
+ });
+
+ if (!allStates || allStates.length === 0) {
+ return json({ message: "No state found" }, { status: 404 });
+ }
+
+ return json(allStates);
+ }
}