diff --git a/src/components/ReactView.tsx b/src/components/ReactView.tsx index 19c6e56..18185a8 100644 --- a/src/components/ReactView.tsx +++ b/src/components/ReactView.tsx @@ -1,7 +1,7 @@ import { App, MarkdownRenderChild } from "obsidian"; import * as React from "react"; import * as ReactDOM from "react-dom/client"; -import { ChessifyFileData } from "src/utils"; +import { ChessifyDataAdapter, ChessifyFileData } from "src/utils"; import { Chessify } from "../components/react/Chessify"; import { ChessifyPluginSettings } from "./obsidian/SettingsTab"; @@ -11,19 +11,22 @@ export class ReactView extends MarkdownRenderChild { app: App; settings: ChessifyPluginSettings; data: ChessifyFileData; + dataAdapter: ChessifyDataAdapter; constructor( containerEL: HTMLElement, source: string, app: App, settings: ChessifyPluginSettings, - data: ChessifyFileData + data: ChessifyFileData, + dataAdapter: ChessifyDataAdapter ) { super(containerEL); this.source = source; this.app = app; this.settings = settings; this.data = data; + this.dataAdapter = dataAdapter; } onload() { @@ -35,6 +38,7 @@ export class ReactView extends MarkdownRenderChild { app={this.app} pluginSettings={this.settings} chessifyData={this.data} + dataAdapter={this.dataAdapter} /> ); diff --git a/src/components/react/ChessgroundWrapper/index.tsx b/src/components/react/ChessgroundWrapper/index.tsx index b232660..1b3983b 100644 --- a/src/components/react/ChessgroundWrapper/index.tsx +++ b/src/components/react/ChessgroundWrapper/index.tsx @@ -5,6 +5,7 @@ import { useEffect, useRef } from "react"; import { Chess, Move } from "chess.js"; import { Api } from "chessground/api"; import { Config } from "chessground/config"; +import { DrawShape } from "chessground/draw"; import { playOtherSide, toColor, toDests } from "src/utils"; export interface ChessGroundSettings { @@ -15,8 +16,11 @@ export interface ChessGroundSettings { boardColor?: "brown" | "green"; chess: Chess; setHistory: React.Dispatch>; + setShapes: React.Dispatch>; setMoveNumber: React.Dispatch>; + currentMoveNumber: number; isViewOnly: boolean; + currentMoveShapes: DrawShape[]; } export function ChessgroundWrapper({ @@ -28,7 +32,10 @@ export function ChessgroundWrapper({ chess, setHistory, setMoveNumber, + currentMoveNumber, + setShapes, isViewOnly, + currentMoveShapes, }: ChessGroundSettings) { const ref = useRef(null); @@ -60,9 +67,6 @@ export function ChessgroundWrapper({ check: true, }, turnColor: toColor(chess), - drawable: { - onChange(shapes) {}, - }, ...config, }); @@ -81,13 +85,36 @@ export function ChessgroundWrapper({ setApi, setHistory, setMoveNumber, + setShapes, + currentMoveNumber, ]); - //Sync Is View Only + //Sync View Only useEffect(() => { api?.set({ viewOnly: isViewOnly }); }, [isViewOnly, api]); + //Sync Shapes To State + useEffect(() => { + api?.set({ + drawable: { + onChange(shapes) { + setShapes((currentShapes) => { + const shapesModified = currentShapes; + shapesModified[currentMoveNumber] = shapes; + + return shapesModified; + }); + }, + }, + }); + }, [api, currentMoveNumber, setShapes]); + + //Load Shapes + useEffect(() => { + if (currentMoveShapes) api?.setShapes(currentMoveShapes); + }, [api, currentMoveNumber, currentMoveShapes, setShapes]); + return (
{ // Parse Obsidian / Code Block Settings const { boardColor, boardOrientation, chessifyId } = parseUserConfig( @@ -28,6 +35,8 @@ export const Chessify = ({ source ); + const [chessifyDataModified] = useState(chessifyData); + // Setup Chessboard and Chess.js APIs const [chessView, setChessView] = useState(null); const chessLogic = useMemo(() => { @@ -47,6 +56,9 @@ export const Chessify = ({ const [history, setHistory] = useState([]); const [isViewOnly, setIsViewOnly] = useState(false); const [currentMove, setCurrentMove] = useState(0); + const [shapes, setShapes] = useState( + chessifyData.moves.map((data) => data.shapes) + ); //PgnViewer Functions const onBackButtonClick = useCallback(() => { @@ -101,6 +113,27 @@ export const Chessify = ({ [chessView, history] ); + const onSaveButtonClick = useCallback(async () => { + const chessifyData = { + header: chessifyDataModified.header, + moves: chessLogic.history({ verbose: true }).map((move, index) => ({ + ...move, + subMoves: [], + shapes: shapes[index], + })), + }; + + await dataAdapter.saveFile(chessifyData, chessifyId); + + new Notice("Save successfull!"); + }, [ + chessLogic, + chessifyDataModified.header, + chessifyId, + dataAdapter, + shapes, + ]); + return (
@@ -135,6 +171,7 @@ export const Chessify = ({ onBackButtonClick={onBackButtonClick} onForwardButtonClick={onForwardButtonClick} onMoveItemClick={onMoveItemClick} + onSaveButtonClick={onSaveButtonClick} />
diff --git a/src/components/react/PgnViewer/index.tsx b/src/components/react/PgnViewer/index.tsx index 9d25cce..d57ffd7 100644 --- a/src/components/react/PgnViewer/index.tsx +++ b/src/components/react/PgnViewer/index.tsx @@ -1,5 +1,5 @@ import { Move } from "chess.js"; -import { ArrowLeft, ArrowRight } from "lucide-react"; +import { ArrowLeft, ArrowRight, Save } from "lucide-react"; import * as React from "react"; import { useEffect, useMemo, useRef } from "react"; @@ -57,12 +57,14 @@ export const PgnViewer = ({ onBackButtonClick, onForwardButtonClick, onMoveItemClick, + onSaveButtonClick, }: { history: Move[]; currentMove: number; onBackButtonClick: () => void; onForwardButtonClick: () => void; onMoveItemClick: (moveIndex: number) => void; + onSaveButtonClick: () => void; }) => { const movePairs = useMemo(() => chunkArray(history, 2), [history]); @@ -123,6 +125,9 @@ export const PgnViewer = ({ + ); diff --git a/src/main.tsx b/src/main.tsx index fa7e2bc..20b8f7a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -103,7 +103,14 @@ export default class ChessifyPlugin extends Plugin { const data = await this.dataAdapter.loadFile(chessifyId); ctx.addChild( - new ReactView(el, source, this.app, this.settings, data) + new ReactView( + el, + source, + this.app, + this.settings, + data, + this.dataAdapter + ) ); } catch (e) { new Notice( diff --git a/src/utils/index.ts b/src/utils/index.ts index fb2f2e1..c8ccc12 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -94,15 +94,15 @@ export class ChessifyDataAdapter { this.storagePath = storagePath; } - async saveFile(data: ChessifyFileData) { - const id = nanoid(); + async saveFile(data: ChessifyFileData, id?: string) { + const chessifyId = id || nanoid(); await this.adapter.write( - `${this.storagePath}/${id}.json`, + `${this.storagePath}/${chessifyId}.json`, JSON.stringify(data, null, 2), {} ); - return id; + return chessifyId; } async loadFile(id: string): Promise {