Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ Thumbs.db
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

# prisma
/generated/
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ yarn.lock
bun.lock
bun.lockb

# generated files
/generated

# Miscellaneous
/static/
91 changes: 91 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite dev",
"dev": "bun --env-file=.env vite dev",
"build": "vite build",
"preview": "vite preview",
"prepare": "svelte-kit sync; lefthook install; true",
"prepare": "svelte-kit sync; prisma generate; lefthook install; true",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"format": "prettier --write .",
Expand All @@ -29,11 +29,16 @@
"lefthook": "^1.13.6",
"prettier": "^3.6.2",
"prettier-plugin-svelte": "^3.4.0",
"prisma": "^6.19.0",
"svelte": "^5.39.5",
"svelte-check": "^4.3.2",
"tailwindcss": "^4.1.14",
"typescript": "^5.9.2",
"typescript-eslint": "^8.44.1",
"vite": "^7.1.7"
},
"dependencies": {
"@prisma/adapter-pg": "^6.19.0",
"@prisma/client": "^6.19.0"
}
}
3 changes: 3 additions & 0 deletions prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
22 changes: 22 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
provider = "prisma-client-js"
output = "../node_modules/@prisma/generated"
engineType = "client" // no Rust engine
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model BoardState {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
boardData Json
}
4 changes: 3 additions & 1 deletion src/iframe/life-game.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ <h1>
<button id="sizeChangeButton">サイズ変更</button>

<table id="game-board" style="border-collapse: collapse"></table>
<button id="randombutton">RANDOM</button>      
<button id="randombutton">RANDOM</button>
<button id="resetbutton">RESET</button>
<button id="saveButton">SAVE</button>
<button id="loadButton">LOAD</button>
<div id="pattern-button-container"></div>
<script src="./life-game.js"></script>
</body>
Expand Down
18 changes: 18 additions & 0 deletions src/iframe/life-game.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const generation = document.getElementById("generation"); //世代を表す文
const randomButton = document.getElementById("randombutton");
const resetButton = document.getElementById("resetbutton");
const sizeChangeButton = document.getElementById("sizeChangeButton");
const saveButton = document.getElementById("saveButton");
const loadButton = document.getElementById("loadButton");
//サイズ入力欄
const sizeInput = document.getElementById("sizeInput");
const sizeLabel = document.getElementById("sizeLabel");
Expand Down Expand Up @@ -187,3 +189,19 @@ sizeChangeButton.onclick = () => {
stop();
updatePatternButtons();
};

saveButton.onclick = async () => {
window.parent.postMessage({ type: "save_board", data: board }, "*");
};

loadButton.onclick = async () => {
window.parent.postMessage({ type: "request:load_board" }, "*");
};

on.load_board = (loadedBoard) => {
console.log("on.load_board");
board = loadedBoard;
renderBoard();
generationChange(0);
stop();
};
8 changes: 8 additions & 0 deletions src/lib/prisma.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "@prisma/generated/client";

export const prisma = new PrismaClient({
adapter: new PrismaPg({
connectionString: process.env.DATABASE_URL,
}),
});
28 changes: 28 additions & 0 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import * as icons from "$lib/icons/index.ts";
import patterns from "$lib/board-templates";
import { onMount } from "svelte";
import { loadBoard, saveBoard } from "./api.ts";

let code = $state(lifeGameJS);

Expand Down Expand Up @@ -40,6 +41,33 @@
function sendEvent(event: string, message?: unknown) {
preview_iframe?.contentWindow?.postMessage({ type: event, data: message }, "*");
}

onMount(() => {
const handler = async (event: MessageEvent<unknown>) => {
console.log("handler call");
const data = event.data as
| { type: "unknown event" }
| { type: "save_board"; data: boolean[][] }
| { type: "request:load_board" };
if (data.type === "save_board") {
console.log("board saved!");
await saveBoard(data.data);
return;
}

if (data.type === "request:load_board") {
console.log("loaded board");
const board = await loadBoard();
if (board) {
sendEvent("load_board", board);
}
return;
}
};

window.addEventListener("message", handler);
return () => window.removeEventListener("message", handler);
});
</script>

<div class="navbar bg-[#E0E0E0] shadow-sm">
Expand Down
42 changes: 42 additions & 0 deletions src/routes/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export async function saveBoard(board: boolean[][]) {
try {
const response = await fetch("/api/board", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(board),
});

if (!response.ok) {
throw new Error("サーバーとの通信に失敗しました。");
}

alert("盤面を保存しました!");
} catch (err) {
console.error("保存エラー:", err);
alert("保存に失敗しました。");
}
}

export async function loadBoard(): Promise<boolean[][] | undefined> {
try {
const response = await fetch("/api/board");

if (!response.ok) {
if (response.status === 404) {
throw new Error("保存されているデータがありません。");
} else {
throw new Error("サーバーとの通信に失敗しました。");
}
}

const loadedBoard = await response.json();

console.log("fetched board:", loadedBoard);
return loadedBoard as boolean[][]; // TODO: add proper types
} catch (err) {
console.error("読込エラー:", err);
alert("読み込みに失敗しました。");
}
}
29 changes: 29 additions & 0 deletions src/routes/api/board/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { json } from "@sveltejs/kit";
import { prisma } from "@/lib/prisma.server.ts";

export async function POST({ request }) {
const boardData = await request.json();

const newState = await prisma.boardState.create({
data: {
boardData: boardData,
},
});

return json(newState, { status: 201 });
}

export async function GET() {
// データベースから一番「最後」に保存されたデータを1件だけ探す
const latestState = await prisma.boardState.findFirst({
orderBy: {
createdAt: "desc", // 作成日時(createdAt)の降順(desc)で並び替え
},
});

if (!latestState) {
return json({ message: "No state found" }, { status: 404 });
}

return json(latestState.boardData);
}