mirror of
https://github.com/chrislicodes/obsidian-chess-study.git
synced 2026-07-22 07:50:30 +00:00
feat: render board, wire up plugin and user config
This commit is contained in:
parent
4df70d9fee
commit
2f92f24b4b
11 changed files with 430 additions and 54 deletions
3
assets/board/green.css
Normal file
3
assets/board/green.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.green-board cg-board {
|
||||
background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4PSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogICAgIHZpZXdCb3g9IjAgMCA4IDgiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+CjxnIGlkPSJhIj4KICA8ZyBpZD0iYiI+CiAgICA8ZyBpZD0iYyI+CiAgICAgIDxnIGlkPSJkIj4KICAgICAgICA8cmVjdCB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSIjZmZmZmRkIiBpZD0iZSIvPgogICAgICAgIDx1c2UgeD0iMSIgeT0iMSIgaHJlZj0iI2UiIHg6aHJlZj0iI2UiLz4KICAgICAgICA8cmVjdCB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSIjODZhNjY2IiBpZD0iZiIvPgogICAgICAgIDx1c2UgeD0iMSIgeT0iLTEiIGhyZWY9IiNmIiB4OmhyZWY9IiNmIi8+CiAgICAgIDwvZz4KICAgICAgPHVzZSB4PSIyIiBocmVmPSIjZCIgeDpocmVmPSIjZCIvPgogICAgPC9nPgogICAgPHVzZSB4PSI0IiBocmVmPSIjYyIgeDpocmVmPSIjYyIvPgogIDwvZz4KICA8dXNlIHk9IjIiIGhyZWY9IiNiIiB4OmhyZWY9IiNiIi8+CjwvZz4KPHVzZSB5PSI0IiBocmVmPSIjYSIgeDpocmVmPSIjYSIvPgo8L3N2Zz4K");
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
import builtins from "builtin-modules";
|
||||
import { renameStyles } from "./rename-styles.mjs";
|
||||
|
||||
const banner = `/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
|
|
@ -38,6 +39,7 @@ const context = await esbuild.context({
|
|||
sourcemap: prod ? false : "inline",
|
||||
treeShaking: true,
|
||||
outfile: "main.js",
|
||||
plugins: [renameStyles],
|
||||
});
|
||||
|
||||
if (prod) {
|
||||
|
|
|
|||
16
rename-styles.mjs
Normal file
16
rename-styles.mjs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { existsSync, renameSync } from "fs";
|
||||
|
||||
export const renameStyles = {
|
||||
name: "rename-styles",
|
||||
setup(build) {
|
||||
build.onEnd(() => {
|
||||
const { outfile } = build.initialOptions;
|
||||
const outcss = outfile.replace(/\.js$/, ".css");
|
||||
const fixcss = outfile.replace(/main\.js$/, "styles.css");
|
||||
if (existsSync(outcss)) {
|
||||
console.log("Renaming", outcss, "to", fixcss);
|
||||
renameSync(outcss, fixcss);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
@ -2,11 +2,13 @@ import { PluginSettingTab, App, Setting } from "obsidian";
|
|||
import ChessifyPlugin from "src/main";
|
||||
|
||||
export interface ChessifyPluginSettings {
|
||||
defaultOrientation: "white" | "black";
|
||||
boardOrientation: "white" | "black";
|
||||
boardColor: "green" | "brown";
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: ChessifyPluginSettings = {
|
||||
defaultOrientation: "white",
|
||||
boardOrientation: "white",
|
||||
boardColor: "green",
|
||||
};
|
||||
|
||||
export class SettingsTab extends PluginSettingTab {
|
||||
|
|
@ -25,17 +27,35 @@ export class SettingsTab extends PluginSettingTab {
|
|||
containerEl.createEl("h2", { text: "Obsidian Chessify Settings" });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Orientation")
|
||||
.setName("Board Orientation")
|
||||
.setDesc("Sets the default orientation of the board")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown.addOption("white", "White");
|
||||
dropdown.addOption("black", "Black");
|
||||
|
||||
dropdown
|
||||
.setValue(this.plugin.settings.defaultOrientation)
|
||||
.setValue(this.plugin.settings.boardOrientation)
|
||||
.onChange((orientation) => {
|
||||
this.plugin.settings.defaultOrientation =
|
||||
orientation as "white" | "black";
|
||||
this.plugin.settings.boardOrientation = orientation as
|
||||
| "white"
|
||||
| "black";
|
||||
this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Board Color")
|
||||
.setDesc("Sets the default color of the board")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown.addOption("green", "Green");
|
||||
dropdown.addOption("brown", "Brown");
|
||||
|
||||
dropdown
|
||||
.setValue(this.plugin.settings.boardColor)
|
||||
.onChange((boardColor) => {
|
||||
this.plugin.settings.boardColor = boardColor as
|
||||
| "green"
|
||||
| "brown";
|
||||
this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
58
src/components/react/ChessgroundWrapper/index.tsx
Normal file
58
src/components/react/ChessgroundWrapper/index.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import * as React from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Chessground as ChessgroundApi } from "chessground";
|
||||
|
||||
import { Api } from "chessground/api";
|
||||
import { Config } from "chessground/config";
|
||||
|
||||
export interface ChessGroundSettings {
|
||||
config?: Config;
|
||||
boardColor?: "brown" | "green";
|
||||
}
|
||||
|
||||
export function ChessgroundWrapper({
|
||||
boardColor = "green",
|
||||
config = {},
|
||||
}: ChessGroundSettings) {
|
||||
const [api, setApi] = useState<Api | null>(null);
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (ref && ref.current && !api) {
|
||||
//Render the Chessboard
|
||||
const chessgroundApi = ChessgroundApi(ref.current, {
|
||||
animation: { enabled: true, duration: 100 },
|
||||
...config,
|
||||
});
|
||||
|
||||
setApi(chessgroundApi);
|
||||
} else if (ref && ref.current && api) {
|
||||
api.set(config);
|
||||
}
|
||||
}, [ref]);
|
||||
|
||||
useEffect(() => {
|
||||
api?.set(config);
|
||||
}, [api, config]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: "450px",
|
||||
width: "450px",
|
||||
}}
|
||||
className={`${boardColor}-board`}
|
||||
>
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
display:
|
||||
"table" /* hack: round to full pixel size in chrome */,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
27
src/components/react/Chessify.tsx
Normal file
27
src/components/react/Chessify.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { App } from "obsidian";
|
||||
import * as React from "react";
|
||||
import { ChessifyPluginSettings } from "src/components/obsidian/SettingsTab";
|
||||
import { ChessgroundWrapper, ChessGroundSettings } from "./ChessgroundWrapper";
|
||||
import { parseUserConfig } from "src/utils";
|
||||
|
||||
export type ChessifyConfig = ChessGroundSettings;
|
||||
|
||||
interface AppProps {
|
||||
source: string;
|
||||
app: App;
|
||||
pluginSettings: ChessifyPluginSettings;
|
||||
}
|
||||
|
||||
export const Chessify = ({ source, pluginSettings }: AppProps) => {
|
||||
const config = parseUserConfig(pluginSettings, source);
|
||||
|
||||
return (
|
||||
<ChessgroundWrapper
|
||||
boardColor={config.boardColor}
|
||||
config={{
|
||||
fen: config.fen,
|
||||
orientation: config.boardOrientation,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
17
src/main.tsx
17
src/main.tsx
|
|
@ -3,19 +3,28 @@ import {
|
|||
ChessifyPluginSettings,
|
||||
DEFAULT_SETTINGS,
|
||||
SettingsTab,
|
||||
} from "./obsidian-components/SettingsTab";
|
||||
} from "./components/obsidian/SettingsTab";
|
||||
import * as ReactDOM from "react-dom/client";
|
||||
import * as React from "react";
|
||||
import { Chessify } from "./react-components/Chessify";
|
||||
import { Chessify } from "./components/react/Chessify";
|
||||
|
||||
// these styles must be imported somewhere
|
||||
import "chessground/assets/chessground.base.css";
|
||||
import "chessground/assets/chessground.brown.css";
|
||||
import "chessground/assets/chessground.cburnett.css";
|
||||
import "assets/board/green.css";
|
||||
|
||||
export default class ChessifyPlugin extends Plugin {
|
||||
settings: ChessifyPluginSettings;
|
||||
|
||||
async onload() {
|
||||
// Load the Settings
|
||||
// Load the settings
|
||||
await this.loadSettings();
|
||||
|
||||
// Add settings tab
|
||||
this.addSettingTab(new SettingsTab(this.app, this));
|
||||
|
||||
// Add chessify code block processor
|
||||
this.registerMarkdownCodeBlockProcessor(
|
||||
"chessify",
|
||||
(source, el, ctx) => {
|
||||
|
|
@ -70,7 +79,7 @@ class ReactView extends MarkdownRenderChild {
|
|||
<Chessify
|
||||
source={this.source}
|
||||
app={this.app}
|
||||
settings={this.settings}
|
||||
pluginSettings={this.settings}
|
||||
/>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
import { App } from "obsidian";
|
||||
import * as React from "react";
|
||||
import { ChessifyPluginSettings } from "src/obsidian-components/SettingsTab";
|
||||
import { AppContext } from "./store/obsidian";
|
||||
|
||||
interface AppProps {
|
||||
source: string;
|
||||
app: App;
|
||||
settings: ChessifyPluginSettings;
|
||||
}
|
||||
|
||||
export const Chessify = ({ source, app, settings }: AppProps) => {
|
||||
return (
|
||||
<AppContext.Provider value={{ app, settings }}>
|
||||
<div>
|
||||
<p>Hello React: This is the passed source: {source}</p>
|
||||
<p>This is a reload test again</p>
|
||||
</div>
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import * as React from "react";
|
||||
import { App } from "obsidian";
|
||||
import { ChessifyPluginSettings } from "src/obsidian-components/SettingsTab";
|
||||
|
||||
interface AppContextProps {
|
||||
app: App;
|
||||
settings: ChessifyPluginSettings;
|
||||
}
|
||||
|
||||
export const AppContext = React.createContext<AppContextProps | null>(null);
|
||||
|
||||
export const useApp = (): AppContextProps | null => {
|
||||
if (AppContext) {
|
||||
return React.useContext(AppContext);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
25
src/utils/index.ts
Normal file
25
src/utils/index.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { parseYaml } from "obsidian";
|
||||
import { ChessifyPluginSettings } from "src/components/obsidian/SettingsTab";
|
||||
|
||||
type ChessifyAppConfig = ChessifyPluginSettings & {
|
||||
fen: string;
|
||||
};
|
||||
|
||||
export const parseUserConfig = (
|
||||
settings: ChessifyPluginSettings,
|
||||
content: string
|
||||
): ChessifyAppConfig => {
|
||||
const chessifyConfig: ChessifyAppConfig = {
|
||||
...settings,
|
||||
fen: "",
|
||||
};
|
||||
|
||||
try {
|
||||
return {
|
||||
...chessifyConfig,
|
||||
...parseYaml(content),
|
||||
};
|
||||
} catch (e) {
|
||||
throw Error("Something went wrong during parsing. :(");
|
||||
}
|
||||
};
|
||||
265
styles.css
265
styles.css
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue