feat: style PGN Viewer

This commit is contained in:
chrislicodes 2023-05-25 12:53:10 +02:00
parent 71beedae89
commit 890dd2fbbb
7 changed files with 1267 additions and 62 deletions

View file

@ -245,7 +245,7 @@ export const ChessStudy = ({
}, [chessStudyId, dataAdapter, gameState.study]);
return (
<div className="chess-study border">
<div className="chess-study">
<div className="chessground-pgn-container">
<div className="chessground-container">
<ChessgroundWrapper
@ -286,7 +286,7 @@ export const ChessStudy = ({
/>
</div>
</div>
<div className="CommentSection border-top">
<div className="CommentSection">
<CommentSection
currentComment={gameState.currentMove?.comment}
setComments={(comment: JSONContent) =>

View file

@ -1,6 +1,6 @@
import { ArrowLeft, ArrowRight, Save } from 'lucide-react';
import * as React from 'react';
import { useEffect, useMemo, useRef } from 'react';
import { ReactNode, useEffect, useMemo, useRef } from 'react';
import { ChessStudyMove } from 'src/lib/storage';
const chunkArray = <T,>(array: T[], chunkSize: number) => {
@ -54,6 +54,56 @@ const MoveItem = ({
);
};
const VariantMoveItem = ({
isCurrentMove,
san,
onMoveItemClick,
moveIndicator = null,
}: {
isCurrentMove: boolean;
san: string;
onMoveItemClick: () => void;
moveIndicator?: string | null;
}) => {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (ref.current && isCurrentMove) {
ref.current?.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'end',
});
}
}, [isCurrentMove]);
return (
<div
className={`variant-move-item ${(isCurrentMove && 'active') || ''}`}
onClick={(e) => {
e.stopPropagation();
onMoveItemClick();
}}
ref={ref}
>
<span className={'variant-move-indicator'}>{moveIndicator}</span>
{san}
</div>
);
};
const VariantMoveItemContainer = ({ children }: { children: ReactNode }) => {
return <div className="variant-move-item-container">{children}</div>;
};
const VariantContainer = ({ children }: { children: ReactNode }) => {
return <div className="variant-container">{children}</div>;
};
const VariantsContainer = ({ children }: { children: ReactNode }) => {
return <div className="variants-container">{children}</div>;
};
export const PgnViewer = React.memo(
({
history,
@ -76,12 +126,14 @@ export const PgnViewer = React.memo(
<div className="height-width-100">
<div className="move-item-section">
<div className="move-item-container">
{movePairs.map((pair, i) => {
{movePairs.map((pair, currentMoveIndex) => {
const [wMove, bMove] = pair;
const variants = wMove.variants.concat(bMove?.variants || []);
return (
<React.Fragment key={wMove.san + bMove?.san}>
<p className="move-indicator center">{i + 1}</p>
<p className="move-indicator center">
{currentMoveIndex + 1}
</p>
<MoveItem
san={wMove.san}
isCurrentMove={wMove.moveId === currentMoveId}
@ -94,38 +146,102 @@ export const PgnViewer = React.memo(
onMoveItemClick={() => onMoveItemClick(bMove.moveId)}
/>
)}
{!!wMove.variants.concat(bMove?.variants || []).length && (
<VariantsContainer>
{!!wMove.variants.length && (
<VariantContainer>
{wMove.variants.map((variant, i) => {
return (
<VariantMoveItemContainer key="TODO">
{chunkArray(variant.moves, 2).map((pair, i) => {
const [bMove, wMove] = pair;
{/* Add Variants */}
{!!variants.length && (
<div
style={{
gridColumn: 'span 3',
display: 'flex',
flexDirection: 'column',
}}
>
{variants.map((variant, i) => {
return (
<div key={'sd'}>
{variant.moves.map((move) => (
<span
style={{
cursor: 'pointer',
color:
move.moveId === currentMoveId
? 'red'
: 'unset',
}}
onClick={() => onMoveItemClick(move.moveId)}
key={move.before}
>
{move.san}
</span>
))}
</div>
);
})}
</div>
return (
<>
<VariantMoveItem
key="TODO"
isCurrentMove={
bMove.moveId === currentMoveId
}
san={bMove.san}
onMoveItemClick={() =>
onMoveItemClick(bMove.moveId)
}
moveIndicator={
(i === 0 &&
`${
currentMoveIndex + 1 + i
}... `) ||
null
}
/>
{wMove && (
<VariantMoveItem
key="TODO"
isCurrentMove={
wMove.moveId === currentMoveId
}
san={wMove.san}
onMoveItemClick={() =>
onMoveItemClick(wMove.moveId)
}
moveIndicator={
(i % 2 === 0 && null) ||
`${currentMoveIndex + 2 + i}. `
}
/>
)}
</>
);
})}
</VariantMoveItemContainer>
);
})}
</VariantContainer>
)}
{!!bMove?.variants.length && (
<VariantContainer>
{bMove.variants.map((variant, i) => {
return (
<VariantMoveItemContainer key="TODO">
{chunkArray(variant.moves, 2).map((pair, i) => {
const [wMove, bMove] = pair;
return (
<>
<VariantMoveItem
key="TODO"
isCurrentMove={
wMove.moveId === currentMoveId
}
san={wMove.san}
onMoveItemClick={() =>
onMoveItemClick(wMove.moveId)
}
moveIndicator={`${
currentMoveIndex + 2 + i
}. `}
/>
{bMove && (
<VariantMoveItem
key="TODO"
isCurrentMove={
bMove.moveId === currentMoveId
}
san={bMove.san}
onMoveItemClick={() =>
onMoveItemClick(bMove.moveId)
}
/>
)}
</>
);
})}
</VariantMoveItemContainer>
);
})}
</VariantContainer>
)}
</VariantsContainer>
)}
</React.Fragment>
);

View file

@ -4,6 +4,8 @@ import { DrawShape } from 'chessground/draw';
import { nanoid } from 'nanoid';
import { DataAdapter, normalizePath } from 'obsidian';
export const CURRENT_STORAGE_VERSION = '0.0.1';
export interface VariantMove extends Move {
moveId: string;
shapes: DrawShape[];
@ -24,6 +26,7 @@ export interface ChessStudyMove extends Move {
}
export interface ChessStudyFileData {
version: string;
header: { title: string | null };
moves: ChessStudyMove[];
}

View file

@ -3,15 +3,6 @@
transform: translateY(1px);
}
.chess-study .border {
border: 1px var(--color-base-10) solid;
border-radius: 5px;
}
.chess-study .border-top {
border: 1px var(--color-base-10) solid;
}
.chess-study .vertical-align {
display: flex;
align-items: center;
@ -33,12 +24,13 @@
}
.chess-study {
height: 100%;
max-width: 750px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
.chess-study {
height: 100%;
background-color: var(--background-secondary);
border: 1px solid var(--background-secondary-alt);
border-radius: 5px;
}
.chess-study *,
@ -84,6 +76,7 @@
}
/* PGN Viewer */
.chess-study .move-item-section {
height: 415px;
}
@ -97,6 +90,8 @@
height: 35px;
}
/* Move Items */
.chess-study .move-item-container {
display: grid;
grid-template-columns: 0.15fr 0.425fr 0.425fr;
@ -131,6 +126,21 @@
font-weight: bold;
}
/* Variant Move Items */
.chess-study .variants-container {
grid-column: span 3 / auto;
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--color-base-50);
}
.chess-study .variant-container {
grid-column: span 3 / auto;
display: flex;
flex-direction: column;
}
.chess-study .move-indicator {
color: var(--color-base-60);
text-align: center;
@ -139,6 +149,28 @@
cursor: default;
}
.chess-study .variant-move-item {
padding-left: 6px;
user-select: none;
cursor: pointer;
}
.chess-study .variant-move-item-container {
display: flex;
flex-wrap: wrap;
padding: 4px 0;
border-top: 1px solid var(--color-base-50);
}
.chess-study .variant-move-item.active,
.chess-study .variant-move-item:hover {
color: hsl(var(--accent-h), var(--accent-s), calc(var(--accent-l) - 10%));
}
.chess-study .variant-move-indicator {
font-weight: bold;
}
/* Comment Section */
.chess-study .editor-input {
@ -157,6 +189,7 @@
height: 250px;
padding-top: 5px;
overflow: scroll;
border-top: 1px solid var(--background-secondary-alt);
}
.chess-study .ProseMirror,

View file

@ -1,6 +1,10 @@
import { Chess } from 'chess.js';
import { Editor, Notice, Plugin, normalizePath } from 'obsidian';
import { ChessStudyDataAdapter, ChessStudyFileData } from 'src/lib/storage';
import {
CURRENT_STORAGE_VERSION,
ChessStudyDataAdapter,
ChessStudyFileData,
} from 'src/lib/storage';
import { ReactView } from './components/ReactView';
import { PgnModal } from './components/obsidian/PgnModal';
import {
@ -59,6 +63,7 @@ export default class ChessStudyPlugin extends Plugin {
}
const chessStudyFileData: ChessStudyFileData = {
version: CURRENT_STORAGE_VERSION,
header: {
title: chess.header()['opening'] || null,
},

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long