mirror of
https://github.com/TheRealOwenRees/chess-scribe-website.git
synced 2026-07-23 09:56:57 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
2d56700dd8
|
|||
|
4cd7b0199e
|
|||
|
5ed83a20d8
|
|||
|
00267b05ba
|
|||
|
7e205df26d
|
|||
|
551b07fc42
|
@@ -0,0 +1,4 @@
|
||||
DISCORD_CONTACT_WEBHOOK=
|
||||
DISCORD_ERROR_LOG_WEBHOOK=
|
||||
LICHESS_CLIENT_ID=
|
||||
VITE_API_BASE_URL=
|
||||
@@ -3,6 +3,7 @@ FEN string
|
||||
Env Vars
|
||||
API base URL
|
||||
|
||||
- favicon and page titles
|
||||
- rearrange buttons / header space - collapse on smaller screens
|
||||
|
||||
- add / edit headers
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import type { ChangeEvent } from "react";
|
||||
import FormField from "#/components/FormField.tsx";
|
||||
import type { IHeader } from "#/interfaces.ts";
|
||||
|
||||
interface IProps {
|
||||
headers: IHeader;
|
||||
updateHeaders: (e: ChangeEvent<HTMLInputElement>, fieldName: string) => void;
|
||||
}
|
||||
|
||||
const CustomHeaders = ({ headers, updateHeaders }: IProps) => {
|
||||
return (
|
||||
<div className="mt-4 w-full">
|
||||
<details className="bg-(--neutral-content)/20 p-4 rounded-lg">
|
||||
<summary>
|
||||
Custom Headers (PDF)
|
||||
<p className="text-sm font-normal">
|
||||
Text in these fields will overwrite the PGN headers in the generated
|
||||
PDF
|
||||
</p>
|
||||
</summary>
|
||||
<div>
|
||||
<form className="grid place-items-center gap-4 sm:grid-cols-2 mt-2">
|
||||
<FormField
|
||||
fieldName="title"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="subtitle"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="date"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="author"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomHeaders;
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { ChangeEvent } from "react";
|
||||
import type { IHeader } from "#/interfaces.ts";
|
||||
|
||||
export interface IFormField {
|
||||
fieldName: string;
|
||||
type: string;
|
||||
headers: IHeader;
|
||||
updateHeaders: (e: ChangeEvent<HTMLInputElement>, fieldName: string) => void;
|
||||
}
|
||||
|
||||
const FormField = ({ fieldName, type, headers, updateHeaders }: IFormField) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label htmlFor={fieldName} className="text-sm capitalize">
|
||||
{fieldName}
|
||||
</label>
|
||||
<input
|
||||
className="headers__input"
|
||||
type={type}
|
||||
id={fieldName}
|
||||
name={fieldName}
|
||||
value={headers[fieldName]}
|
||||
onChange={(e) => updateHeaders(e, fieldName)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormField;
|
||||
@@ -0,0 +1,105 @@
|
||||
import type { ChangeEvent } from "react";
|
||||
import FormField from "#/components/FormField.tsx";
|
||||
import type { IHeader } from "#/interfaces.ts";
|
||||
|
||||
interface IProps {
|
||||
headers: IHeader;
|
||||
updateHeaders: (e: ChangeEvent<HTMLInputElement>, fieldName: string) => void;
|
||||
}
|
||||
|
||||
const HeaderFields = ({ headers, updateHeaders }: IProps) => {
|
||||
return (
|
||||
<div className="mt-4 w-full">
|
||||
<details className="bg-(--neutral-content)/15 p-4 rounded-lg">
|
||||
<summary>
|
||||
Headers
|
||||
<p className="text-sm font-normal">Edit the game PGN headers</p>
|
||||
</summary>
|
||||
<div>
|
||||
<form className="grid place-items-center gap-4 sm:grid-cols-2 mt-2">
|
||||
<FormField
|
||||
fieldName="event"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="site"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="date"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="round"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="white"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="black"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="result"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="eco"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="whiteElo"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="blackElo"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="plyCount"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="eventDate"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<FormField
|
||||
fieldName="source"
|
||||
type="text"
|
||||
headers={headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HeaderFields;
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import type { IPosition } from "#/interfaces.ts";
|
||||
import type { IHeader, IPosition } from "#/interfaces.ts";
|
||||
import { gameReducer, initialGameState } from "#/reducers/gameReducer.ts";
|
||||
import { downloadPDF } from "#/utils/pdfUtils.ts";
|
||||
import { buildPgnString, getHeaders } from "#/utils/pgnUtils.ts";
|
||||
@@ -118,6 +118,7 @@ export const useChessGame = () => {
|
||||
...getHeaders(pgnString),
|
||||
title: "",
|
||||
subtitle: "",
|
||||
author: "",
|
||||
};
|
||||
gameDispatch({
|
||||
type: "SET_GAME",
|
||||
@@ -153,6 +154,18 @@ export const useChessGame = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const updateHeaders = (
|
||||
e: ChangeEvent<HTMLInputElement>,
|
||||
fieldName: string,
|
||||
) => {
|
||||
e.preventDefault();
|
||||
const updatedHeaders = {
|
||||
...gameState.headers,
|
||||
[fieldName]: e.target.value,
|
||||
} as IHeader;
|
||||
gameDispatch({ type: "SET_HEADERS", payload: updatedHeaders });
|
||||
};
|
||||
|
||||
return {
|
||||
gameState,
|
||||
fileInputRef,
|
||||
@@ -165,5 +178,6 @@ export const useChessGame = () => {
|
||||
handleToggleDiagram,
|
||||
currentPosition,
|
||||
generatingPdf,
|
||||
updateHeaders,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -17,6 +17,9 @@ export interface IHeader {
|
||||
plyCount: string;
|
||||
eventDate: string;
|
||||
source: string;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
author: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
|
||||
+16
-10
@@ -1,3 +1,5 @@
|
||||
import CustomHeaders from "#/components/CustomHeaders.tsx";
|
||||
import HeaderFields from "#/components/HeaderFields.tsx";
|
||||
import LichessButton from "#/components/LichessButton.tsx";
|
||||
import PgnViewer from "#/components/PgnViewer.tsx";
|
||||
import Section from "#/components/Section.tsx";
|
||||
@@ -16,12 +18,13 @@ const Chessboard = () => {
|
||||
handleToggleClock,
|
||||
handleToggleDiagram,
|
||||
handlePlyChange,
|
||||
updateHeaders,
|
||||
} = useChessGame();
|
||||
|
||||
return (
|
||||
<main className="px-4 pb-8 place-self-center min-h-[calc(100vh-226px)]">
|
||||
<Section title="Convert PGN to PDF">
|
||||
<LichessButton /> or{" "}
|
||||
<LichessButton onClickHandler={() => console.log("Lichess Login")} /> or{" "}
|
||||
<input
|
||||
type="file"
|
||||
id="file-input"
|
||||
@@ -78,15 +81,8 @@ const Chessboard = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
{/*<button*/}
|
||||
{/* className="btn btn-primary"*/}
|
||||
{/* type="button"*/}
|
||||
{/* onClick={handleClearGame}*/}
|
||||
{/*>*/}
|
||||
{/* Clear Game*/}
|
||||
{/*</button>*/}
|
||||
|
||||
<div className="flex flex-col gap-4 items-center">
|
||||
<div className="flex justify-center gap-4">
|
||||
<button
|
||||
className="btn btn-secondary"
|
||||
type="button"
|
||||
@@ -105,6 +101,16 @@ const Chessboard = () => {
|
||||
Save PDF
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<HeaderFields
|
||||
headers={gameState.headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
<CustomHeaders
|
||||
headers={gameState.headers}
|
||||
updateHeaders={updateHeaders}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/* Headers */
|
||||
.headers__input {
|
||||
height: 3rem;
|
||||
padding: 0 1rem;
|
||||
line-height: 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--neutral-content);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
background-color: var(--header-bg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Checkbox */
|
||||
.checkbox-accent {
|
||||
accent-color: var(--accent);
|
||||
|
||||
Reference in New Issue
Block a user