From b7d85f87e7c8b608b0d7d59b50029f42b7a33520 Mon Sep 17 00:00:00 2001 From: Suke-H Date: Tue, 21 Jan 2025 21:59:28 +0900 Subject: [PATCH 1/9] =?UTF-8?q?=E2=9C=85=20fix:=20#28=20CELL=5FTYPES?= =?UTF-8?q?=E5=91=A8=E3=82=8A=E3=81=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/editor/grid.tsx | 118 ++++++++++++++---------- frontend/src/components/types.ts | 20 ++-- frontend/src/constants/cell-types.ts | 60 +++++++++++- frontend/src/pages/editor-page.tsx | 36 ++++---- 4 files changed, 160 insertions(+), 74 deletions(-) diff --git a/frontend/src/components/editor/grid.tsx b/frontend/src/components/editor/grid.tsx index 37112c3..724664a 100644 --- a/frontend/src/components/editor/grid.tsx +++ b/frontend/src/components/editor/grid.tsx @@ -1,16 +1,16 @@ import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { PlusCircle, MinusCircle, Download, Upload, Link } from 'lucide-react'; -import { CellType, Panel, PanelPlacementModeType, PanelPlacementHistoryType } from '../types'; -import { CELL_TYPES } from '../../constants/cell-types'; -// import { exportStageToJson, importStageFromJson } from '../../utils/json'; -import { exportStageToYaml, importStageFromYaml } from '../../utils/yaml'; -import { shareStageUrl } from '../../utils/url'; +// import { PlusCircle, MinusCircle, Download, Upload, Link } from 'lucide-react'; +import { PlusCircle, MinusCircle, } from 'lucide-react'; +import { CellType, GridCell, Panel, PanelPlacementModeType, PanelPlacementHistoryType } from '../types'; +import { CELL_DEFINITIONS, CellSideInfo } from '../../constants/cell-types'; +// import { exportStageToYaml, importStageFromYaml } from '../../utils/yaml'; +// import { shareStageUrl } from '../../utils/url'; interface GridProps { - grid: CellType[][]; - setGrid: React.Dispatch>; - setGridHistory: React.Dispatch>; + grid: GridCell[][]; + setGrid: React.Dispatch>; + setGridHistory: React.Dispatch>; selectedCellType: CellType; panels: Panel[]; setPanels: React.Dispatch>; @@ -24,7 +24,9 @@ export const Grid: React.FC = ({ setGrid, setGridHistory, selectedCellType, + // eslint-disable-next-line @typescript-eslint/no-unused-vars panels, + // eslint-disable-next-line @typescript-eslint/no-unused-vars setPanels, panelPlacementMode, setPanelPlacementMode, @@ -60,10 +62,15 @@ export const Grid: React.FC = ({ // 通常のセル選択モード if (!panelPlacementMode.panel) { const newGrid = [...grid]; - newGrid[rowIndex][colIndex] = selectedCellType; + + // デフォルトでfrontかneutralを選択 + const cellDef = CELL_DEFINITIONS[selectedCellType]; + const side = 'neutral' in cellDef ? 'neutral' : 'front'; + newGrid[rowIndex][colIndex] = { type: selectedCellType, side }; setGrid(newGrid); setGridHistory((prev) => [...prev, newGrid]); + return; } @@ -78,23 +85,19 @@ export const Grid: React.FC = ({ for (let i = 0; i < panelRows; i++) { for (let j = 0; j < panelCols; j++) { - if (placingPanel.cells[i][j] === 'Black') { + if (placingPanel.cells[i][j] !== 'Empty') { const targetCell = updatedGrid[rowIndex + i][colIndex + j]; - - // 矢印セルの向きを反転 - if (targetCell.startsWith('Arrow')) { - if (targetCell === 'ArrowUp') updatedGrid[rowIndex + i][colIndex + j] = 'ArrowDown'; - else if (targetCell === 'ArrowDown') updatedGrid[rowIndex + i][colIndex + j] = 'ArrowUp'; - else if (targetCell === 'ArrowLeft') updatedGrid[rowIndex + i][colIndex + j] = 'ArrowRight'; - else if (targetCell === 'ArrowRight') updatedGrid[rowIndex + i][colIndex + j] = 'ArrowLeft'; - } - - // 白黒反転 - if (targetCell === 'White') { - updatedGrid[rowIndex + i][colIndex + j] = 'Black'; - } else if (targetCell === 'Black') { - updatedGrid[rowIndex + i][colIndex + j] = 'White'; + + // Emptyには置かない + if (targetCell.type === 'Empty') continue; + + // セルの状態を切り替える + if (targetCell.side === 'front') { + updatedGrid[rowIndex + i][colIndex + j] = { ...targetCell, side: 'back' }; + } else if (targetCell.side === 'back') { + updatedGrid[rowIndex + i][colIndex + j] = { ...targetCell, side: 'front' }; } + // neutralの場合は変更しない } } } @@ -110,19 +113,35 @@ export const Grid: React.FC = ({ }); }; - const renderGridCell = (cellType: CellType, rowIndex: number, colIndex: number) => { - const isEmpty = cellType === 'Empty'; - + const renderGridCell = (cell: GridCell, rowIndex: number, colIndex: number) => { + const cellDef = CELL_DEFINITIONS[cell.type]; + + // セルの状態に応じた情報を取得 + let sideInfo: CellSideInfo | undefined; + + if (cellDef.neutral) { + sideInfo = cellDef.neutral; + } else if (cellDef.front) { + sideInfo = cellDef.front; + } else if (cellDef.back) { + sideInfo = cellDef.back; + } + + if (!sideInfo) { + console.error(`No valid sideInfo found for cell type: ${cell.type}`); + return null; // またはデフォルトの要素を返す + } + return (
handleGridCellClick(rowIndex, colIndex)} > - {!isEmpty && ( + {cell.type !== 'Empty' && ( {CELL_TYPES[cellType].label} )} @@ -131,7 +150,7 @@ export const Grid: React.FC = ({ }; const canPlacePanelAtLocation = ( - grid: CellType[][], + grid: GridCell[][], rowIndex: number, colIndex: number, panel: Panel @@ -147,13 +166,18 @@ export const Grid: React.FC = ({ // パネルを配置するセルがすべて適切であるかチェック for (let i = 0; i < panelRows; i++) { for (let j = 0; j < panelCols; j++) { - if (panel.cells[i][j] === 'Black') { + const panelCell = panel.cells[i][j]; + if (panelCell !== 'Empty') { const targetCell = grid[rowIndex + i][colIndex + j]; - if ( - targetCell !== 'White' && - targetCell !== 'Black' && - !targetCell.startsWith('Arrow') - ) { + + // Emptyには置けない + if (targetCell.type === 'Empty') { + return false; + } + + // neutralなセルには置けない(開始、ゴール、ダミーゴールなど) + const cellDef = CELL_DEFINITIONS[targetCell.type]; + if ('neutral' in cellDef) { return false; } } @@ -163,12 +187,12 @@ export const Grid: React.FC = ({ return true; }; - const triggerFileInput = () => { - const input = document.getElementById('yamlImport') as HTMLInputElement; - if (input) { - input.click(); - } - }; + // const triggerFileInput = () => { + // const input = document.getElementById('yamlImport') as HTMLInputElement; + // if (input) { + // input.click(); + // } + // }; return ( @@ -206,7 +230,7 @@ export const Grid: React.FC = ({
-
+ {/*
@@ -225,7 +249,7 @@ export const Grid: React.FC = ({ -
+
*/} ); diff --git a/frontend/src/components/types.ts b/frontend/src/components/types.ts index b047d9a..f1151bc 100644 --- a/frontend/src/components/types.ts +++ b/frontend/src/components/types.ts @@ -1,18 +1,22 @@ -import { CELL_TYPES } from "../constants/cell-types"; +import { CELL_DEFINITIONS } from "../constants/cell-types"; -export type CellType = keyof typeof CELL_TYPES; +;export type CellType = keyof typeof CELL_DEFINITIONS; +// グリッド上のセルを表す型 +export type GridCell = { + type: CellType; + side: 'neutral' | 'front' | 'back'; +}; + +// パネルの型を更新 export interface Panel { id: string; cells: CellType[][]; } -export interface PanelPlacementModeType { +export type PanelPlacementModeType = { panel: Panel | null; highlightedCell: { row: number; col: number } | null; -} +}; -export interface PanelPlacementHistoryType { - panel: Panel | null; - highlightedCell: { row: number; col: number } | null; -} +export type PanelPlacementHistoryType = PanelPlacementModeType; diff --git a/frontend/src/constants/cell-types.ts b/frontend/src/constants/cell-types.ts index 827b76e..a318997 100644 --- a/frontend/src/constants/cell-types.ts +++ b/frontend/src/constants/cell-types.ts @@ -13,4 +13,62 @@ export const CELL_TYPES = { } as const; // キーから動的に型を生成 -export type CellType = keyof typeof CELL_TYPES; \ No newline at end of file +export type CellType = keyof typeof CELL_TYPES; +// export type CellType = 'Empty' | 'White' | 'Black' | 'Start' | 'Goal' | 'DummyGoal' | 'Crow' | 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight' | 'Normal'; + +// セルの状態を表す型 +export type CellSideInfo = { + code: string; + picture: string; +}; + +// セルの定義を表す型 +export type CellDefinition = { + label: string; + neutral?: CellSideInfo; + front?: CellSideInfo; + back?: CellSideInfo; +}; + +// セルの種類を定義 +export const CELL_DEFINITIONS: Record = { + Empty: { + label: '空', + neutral: { + code: 'e', + picture: 'empty.png' + } + }, + Normal: { + label: '通常床', + front: { + code: 'N', + picture: 'white.png' + }, + back: { + code: 'n', + picture: 'black.png' + } + }, + Start: { + label: 'スタート', + neutral: { + code: 's', + picture: 'start.png' + } + }, + Goal: { + label: 'ゴール', + neutral: { + code: 'g', + picture: 'goal.png' + } + }, + DummyGoal: { + label: 'ダミーゴール', + neutral: { + code: 'd', + picture: 'dummyGoal.png' + } + } +} as const; \ No newline at end of file diff --git a/frontend/src/pages/editor-page.tsx b/frontend/src/pages/editor-page.tsx index 641e396..3363070 100644 --- a/frontend/src/pages/editor-page.tsx +++ b/frontend/src/pages/editor-page.tsx @@ -3,15 +3,15 @@ import { CellTypeSelector } from '@/components/editor/cell-type-selector'; import { Grid } from '@/components/editor/grid'; import { PanelList } from '@/components/editor/panel-list'; import { NewPanelCreator } from '@/components/editor/new-panel-creator'; -import { CellType, Panel, PanelPlacementModeType, PanelPlacementHistoryType } from '@/components/types'; -import { decodeStageFromUrl } from '../utils/url'; +import { CellType, GridCell, Panel, PanelPlacementModeType, PanelPlacementHistoryType } from '@/components/types'; +// import { decodeStageFromUrl } from '../utils/url'; const EditorPage: React.FC = () => { - const [grid, setGrid] = useState([ - ['White', 'White', 'White'], - ['White', 'White', 'White'], - ['White', 'White', 'White'], + const [grid, setGrid] = useState([ + [{ type: 'Normal', side: 'front' }, { type: 'Normal', side: 'front' }, { type: 'Normal', side: 'front' }], + [{ type: 'Normal', side: 'front' }, { type: 'Normal', side: 'front' }, { type: 'Normal', side: 'front' }], + [{ type: 'Normal', side: 'front' }, { type: 'Normal', side: 'front' }, { type: 'Normal', side: 'front' }], ]); const [selectedCellType, setSelectedCellType] = useState('Black'); @@ -41,22 +41,22 @@ const EditorPage: React.FC = () => { highlightedCell: null, }); - const [gridHistory, setGridHistory] = useState([grid]); + const [gridHistory, setGridHistory] = useState([grid]); const [panelPlacementHistory, setPanelPlacementHistory] = useState([]); - useEffect(() => { + // useEffect(() => { - const params = new URLSearchParams(window.location.search); - const cells = params.get('cells'); - const panels = params.get('panels'); + // const params = new URLSearchParams(window.location.search); + // const cells = params.get('cells'); + // const panels = params.get('panels'); - if (cells && panels) { - const stageData = `cells=${cells}&panels=${panels}`; - const parsedData = decodeStageFromUrl(stageData); - setGrid(parsedData.cells); - setPanels(parsedData.panels); - } - }, []); + // if (cells && panels) { + // const stageData = `cells=${cells}&panels=${panels}`; + // const parsedData = decodeStageFromUrl(stageData); + // setGrid(parsedData.cells); + // setPanels(parsedData.panels); + // } + // }, []); // FastAPIの疎通確認 useEffect(() => { From 2377826e20bd19702cf9123b0a5086ce53228272 Mon Sep 17 00:00:00 2001 From: Suke-H Date: Wed, 22 Jan 2025 17:44:29 +0900 Subject: [PATCH 2/9] =?UTF-8?q?=E2=9C=85=20fix:=20=E4=BB=96=E3=81=AE?= =?UTF-8?q?=E5=BC=95=E6=95=B0=E3=81=AE=E5=9E=8B=E3=82=92CELL=5FDIEFINITION?= =?UTF-8?q?S=E3=81=B8=E9=81=A9=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/editor/cell-type-selector.tsx | 14 +++++++------- frontend/src/components/editor/grid.tsx | 4 ++-- frontend/src/components/types.ts | 7 ++++--- frontend/src/constants/cell-types.ts | 10 +++++++++- frontend/src/pages/editor-page.tsx | 3 ++- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/editor/cell-type-selector.tsx b/frontend/src/components/editor/cell-type-selector.tsx index 85b9f3e..ad9424c 100644 --- a/frontend/src/components/editor/cell-type-selector.tsx +++ b/frontend/src/components/editor/cell-type-selector.tsx @@ -1,11 +1,11 @@ import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { CellType } from '../types'; -import { CELL_TYPES } from '../../constants/cell-types'; +import { CellDefinitions } from '../types'; +import { CELL_DEFINITIONS } from '../../constants/cell-types'; interface CellTypeSelectorProps { - selectedCellType: CellType; - onCellTypeChange: (type: CellType) => void; + selectedCellType: CellDefinitions; + onCellTypeChange: (type: CellDefinitions) => void; } export const CellTypeSelector: React.FC = ({ @@ -18,14 +18,14 @@ export const CellTypeSelector: React.FC = ({ セル種類 - {(Object.keys(CELL_TYPES) as CellType[]).map((type) => ( + {(Object.keys(CELL_DEFINITIONS) as CellDefinitions[]).map((type) => ( ))} diff --git a/frontend/src/components/editor/grid.tsx b/frontend/src/components/editor/grid.tsx index 724664a..ec5f00e 100644 --- a/frontend/src/components/editor/grid.tsx +++ b/frontend/src/components/editor/grid.tsx @@ -2,7 +2,7 @@ import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; // import { PlusCircle, MinusCircle, Download, Upload, Link } from 'lucide-react'; import { PlusCircle, MinusCircle, } from 'lucide-react'; -import { CellType, GridCell, Panel, PanelPlacementModeType, PanelPlacementHistoryType } from '../types'; +import { GridCell, Panel, PanelPlacementModeType, PanelPlacementHistoryType , CellDefinitions} from '../types'; import { CELL_DEFINITIONS, CellSideInfo } from '../../constants/cell-types'; // import { exportStageToYaml, importStageFromYaml } from '../../utils/yaml'; // import { shareStageUrl } from '../../utils/url'; @@ -11,7 +11,7 @@ interface GridProps { grid: GridCell[][]; setGrid: React.Dispatch>; setGridHistory: React.Dispatch>; - selectedCellType: CellType; + selectedCellType: CellDefinitions; panels: Panel[]; setPanels: React.Dispatch>; panelPlacementMode: PanelPlacementModeType; diff --git a/frontend/src/components/types.ts b/frontend/src/components/types.ts index f1151bc..e6fe47e 100644 --- a/frontend/src/components/types.ts +++ b/frontend/src/components/types.ts @@ -1,10 +1,11 @@ -import { CELL_DEFINITIONS } from "../constants/cell-types"; +import { CELL_TYPES, CELL_DEFINITIONS } from "../constants/cell-types"; -;export type CellType = keyof typeof CELL_DEFINITIONS; +export type CellType = keyof typeof CELL_TYPES +export type CellDefinitions = keyof typeof CELL_DEFINITIONS; // グリッド上のセルを表す型 export type GridCell = { - type: CellType; + type: CellDefinitions; side: 'neutral' | 'front' | 'back'; }; diff --git a/frontend/src/constants/cell-types.ts b/frontend/src/constants/cell-types.ts index a318997..f63689a 100644 --- a/frontend/src/constants/cell-types.ts +++ b/frontend/src/constants/cell-types.ts @@ -25,6 +25,7 @@ export type CellSideInfo = { // セルの定義を表す型 export type CellDefinition = { label: string; + color: string; neutral?: CellSideInfo; front?: CellSideInfo; back?: CellSideInfo; @@ -34,6 +35,7 @@ export type CellDefinition = { export const CELL_DEFINITIONS: Record = { Empty: { label: '空', + color: 'bg-white', neutral: { code: 'e', picture: 'empty.png' @@ -41,6 +43,7 @@ export const CELL_DEFINITIONS: Record = { }, Normal: { label: '通常床', + color: 'bg-[#DAE0EA]', front: { code: 'N', picture: 'white.png' @@ -52,6 +55,7 @@ export const CELL_DEFINITIONS: Record = { }, Start: { label: 'スタート', + color: 'bg-green-500', neutral: { code: 's', picture: 'start.png' @@ -59,6 +63,7 @@ export const CELL_DEFINITIONS: Record = { }, Goal: { label: 'ゴール', + color: 'bg-blue-500', neutral: { code: 'g', picture: 'goal.png' @@ -66,9 +71,12 @@ export const CELL_DEFINITIONS: Record = { }, DummyGoal: { label: 'ダミーゴール', + color: 'bg-red-500', neutral: { code: 'd', picture: 'dummyGoal.png' } } -} as const; \ No newline at end of file +} as const; + +export type CellDefinitions = keyof typeof CELL_DEFINITIONS; diff --git a/frontend/src/pages/editor-page.tsx b/frontend/src/pages/editor-page.tsx index 3363070..8612021 100644 --- a/frontend/src/pages/editor-page.tsx +++ b/frontend/src/pages/editor-page.tsx @@ -4,6 +4,7 @@ import { Grid } from '@/components/editor/grid'; import { PanelList } from '@/components/editor/panel-list'; import { NewPanelCreator } from '@/components/editor/new-panel-creator'; import { CellType, GridCell, Panel, PanelPlacementModeType, PanelPlacementHistoryType } from '@/components/types'; +import { CellDefinitions } from 'constants/cell-types'; // import { decodeStageFromUrl } from '../utils/url'; const EditorPage: React.FC = () => { @@ -14,7 +15,7 @@ const EditorPage: React.FC = () => { [{ type: 'Normal', side: 'front' }, { type: 'Normal', side: 'front' }, { type: 'Normal', side: 'front' }], ]); - const [selectedCellType, setSelectedCellType] = useState('Black'); + const [selectedCellType, setSelectedCellType] = useState('Black'); const [panels, setPanels] = useState([ { id: 'panel1', From 5e2fe279c042bb26f994a5e35dc9656a19f28fd7 Mon Sep 17 00:00:00 2001 From: Suke-H Date: Wed, 22 Jan 2025 17:47:43 +0900 Subject: [PATCH 3/9] =?UTF-8?q?=E2=9C=85=20fix:=20PanelList=E3=81=B8?= =?UTF-8?q?=E3=81=AE=E5=9E=8B=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/editor/panel-list.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/editor/panel-list.tsx b/frontend/src/components/editor/panel-list.tsx index f5dcf67..35b5c63 100644 --- a/frontend/src/components/editor/panel-list.tsx +++ b/frontend/src/components/editor/panel-list.tsx @@ -1,7 +1,7 @@ import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Trash2, Move } from 'lucide-react'; -import { CellType, Panel, PanelPlacementModeType, PanelPlacementHistoryType } from '../types'; +import { Panel, PanelPlacementModeType, PanelPlacementHistoryType, GridCell } from '../types'; interface PanelListProps { panels: Panel[]; @@ -10,9 +10,9 @@ interface PanelListProps { setPanelPlacementMode: React.Dispatch>; panelPlacementHistory: PanelPlacementHistoryType[]; setPanelPlacementHistory: React.Dispatch>; - setGrid: React.Dispatch>; - gridHistory: CellType[][][]; - setGridHistory: React.Dispatch>; + setGrid: React.Dispatch>; + gridHistory: GridCell[][][]; + setGridHistory: React.Dispatch>; } export const PanelList: React.FC = ({ From c48f03db3a4e4b416ea4aff3c8c8dc5d9c9d7280 Mon Sep 17 00:00:00 2001 From: Suke-H Date: Wed, 22 Jan 2025 19:09:43 +0900 Subject: [PATCH 4/9] =?UTF-8?q?=E2=9C=85=20fix:=20#28=20=E3=83=AC=E3=83=B3?= =?UTF-8?q?=E3=83=80=E3=83=AA=E3=83=B3=E3=82=B0=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/editor/grid.tsx | 15 +++++---------- frontend/src/constants/cell-types.ts | 2 +- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/editor/grid.tsx b/frontend/src/components/editor/grid.tsx index ec5f00e..b5409cb 100644 --- a/frontend/src/components/editor/grid.tsx +++ b/frontend/src/components/editor/grid.tsx @@ -105,6 +105,8 @@ export const Grid: React.FC = ({ setGridHistory((prev) => [...prev, updatedGrid]); setPanelPlacementHistory((prev) => [...prev, panelPlacementMode]); setGrid(updatedGrid); + + console.log('updatedGrid', updatedGrid); } setPanelPlacementMode({ @@ -117,21 +119,14 @@ export const Grid: React.FC = ({ const cellDef = CELL_DEFINITIONS[cell.type]; // セルの状態に応じた情報を取得 - let sideInfo: CellSideInfo | undefined; - - if (cellDef.neutral) { - sideInfo = cellDef.neutral; - } else if (cellDef.front) { - sideInfo = cellDef.front; - } else if (cellDef.back) { - sideInfo = cellDef.back; - } + const sideInfo: CellSideInfo | undefined = cellDef[cell.side]; if (!sideInfo) { console.error(`No valid sideInfo found for cell type: ${cell.type}`); return null; // またはデフォルトの要素を返す } - + + console.log('レンダリング'); return (
= { color: 'bg-red-500', neutral: { code: 'd', - picture: 'dummyGoal.png' + picture: 'dummy-goal.png' } } } as const; From f2d6049e4c14c820fc028d12345431aaddf89757 Mon Sep 17 00:00:00 2001 From: Suke-H Date: Wed, 22 Jan 2025 19:14:31 +0900 Subject: [PATCH 5/9] =?UTF-8?q?=E2=9C=85=20fix:=20=E3=83=91=E3=83=8D?= =?UTF-8?q?=E3=83=AB=E3=81=AB=E3=82=88=E3=82=8B=E5=8F=8D=E8=BB=A2=E5=87=A6?= =?UTF-8?q?=E7=90=86=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/editor/grid.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/editor/grid.tsx b/frontend/src/components/editor/grid.tsx index b5409cb..8f3b66a 100644 --- a/frontend/src/components/editor/grid.tsx +++ b/frontend/src/components/editor/grid.tsx @@ -85,7 +85,7 @@ export const Grid: React.FC = ({ for (let i = 0; i < panelRows; i++) { for (let j = 0; j < panelCols; j++) { - if (placingPanel.cells[i][j] !== 'Empty') { + if (placingPanel.cells[i][j] === 'Black') { const targetCell = updatedGrid[rowIndex + i][colIndex + j]; // Emptyには置かない @@ -170,11 +170,11 @@ export const Grid: React.FC = ({ return false; } - // neutralなセルには置けない(開始、ゴール、ダミーゴールなど) - const cellDef = CELL_DEFINITIONS[targetCell.type]; - if ('neutral' in cellDef) { - return false; - } + // // neutralなセルには置けない(開始、ゴール、ダミーゴールなど) + // const cellDef = CELL_DEFINITIONS[targetCell.type]; + // if ('neutral' in cellDef) { + // return false; + // } } } } From 9a50fbff7fd29104fc52fc4bcbee8a0a4fa8ede9 Mon Sep 17 00:00:00 2001 From: Suke-H Date: Wed, 22 Jan 2025 19:28:05 +0900 Subject: [PATCH 6/9] =?UTF-8?q?=E2=9C=85=20fix:=20#28=20=E3=82=B0=E3=83=AA?= =?UTF-8?q?=E3=83=83=E3=83=89=E8=AA=BF=E6=95=B4=E5=87=A6=E7=90=86=E3=81=AE?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/editor/grid.tsx | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/editor/grid.tsx b/frontend/src/components/editor/grid.tsx index 8f3b66a..42d518e 100644 --- a/frontend/src/components/editor/grid.tsx +++ b/frontend/src/components/editor/grid.tsx @@ -37,18 +37,31 @@ export const Grid: React.FC = ({ setGrid((prevGrid) => { const newRows = prevGrid.length + rowDelta; const newCols = prevGrid[0].length + colDelta; - + if (newRows > 0 && newCols > 0) { + // 新しい空のセルを作成するヘルパー関数 + const createEmptyCell = (): GridCell => ({ + type: 'Normal', + side: 'front' + }); + if (rowDelta > 0) { - return [...prevGrid, ...Array(rowDelta).fill(Array(newCols).fill('White'))]; + // 行を追加 + const newRow = Array(newCols).fill(null).map(() => createEmptyCell()); + return [...prevGrid, ...Array(rowDelta).fill(null).map(() => newRow.map(cell => ({...cell})))]; } else if (rowDelta < 0) { - return prevGrid.slice(0, newRows).map((row) => row.slice(0, newCols)); + // 行を削除 + return prevGrid.slice(0, newRows).map(row => row.slice(0, newCols)); } - - return prevGrid.map((row) => { + + // 列の追加/削除 + return prevGrid.map(row => { if (colDelta > 0) { - return [...row, ...Array(colDelta).fill('White')]; + // 列を追加 + const newCells = Array(colDelta).fill(null).map(() => createEmptyCell()); + return [...row, ...newCells]; } else if (colDelta < 0) { + // 列を削除 return row.slice(0, newCols); } return row; From 35241b584c21b05294dd0b6c42f844392f9f2142 Mon Sep 17 00:00:00 2001 From: Suke-H Date: Fri, 24 Jan 2025 19:51:33 +0900 Subject: [PATCH 7/9] =?UTF-8?q?=E2=9C=85=20feat:=20#28=20=E3=82=BB?= =?UTF-8?q?=E3=83=AB=E9=81=B8=E6=8A=9E=E3=81=AB=E3=80=8C=E5=8F=8D=E8=BB=A2?= =?UTF-8?q?=E3=80=8D=E3=82=92=E7=94=A8=E6=84=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 仕様が大きく変わったので「反転」ボタンを用意した --- .../components/editor/cell-type-selector.tsx | 3 +- frontend/src/components/editor/grid.tsx | 30 +++++++++++++------ frontend/src/constants/cell-types.ts | 4 +++ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/editor/cell-type-selector.tsx b/frontend/src/components/editor/cell-type-selector.tsx index ad9424c..dbc303e 100644 --- a/frontend/src/components/editor/cell-type-selector.tsx +++ b/frontend/src/components/editor/cell-type-selector.tsx @@ -10,7 +10,7 @@ interface CellTypeSelectorProps { export const CellTypeSelector: React.FC = ({ selectedCellType, - onCellTypeChange + onCellTypeChange, }) => { return ( @@ -18,6 +18,7 @@ export const CellTypeSelector: React.FC = ({ セル種類 + {(Object.keys(CELL_DEFINITIONS) as CellDefinitions[]).map((type) => (
- {/*
- = ({ - + */} -
*/} + ); diff --git a/frontend/src/constants/cell-types.ts b/frontend/src/constants/cell-types.ts index 0709562..a78c1bf 100644 --- a/frontend/src/constants/cell-types.ts +++ b/frontend/src/constants/cell-types.ts @@ -49,11 +49,11 @@ export const CELL_DEFINITIONS: Record = { label: '通常床', color: 'bg-[#DAE0EA]', front: { - code: 'N', + code: 'w', picture: 'white.png' }, back: { - code: 'n', + code: 'b', picture: 'black.png' } }, @@ -80,7 +80,19 @@ export const CELL_DEFINITIONS: Record = { code: 'd', picture: 'dummy-goal.png' } - } + }, + Crow: { + label: 'カラス', + color: 'bg-yellow-500', + front: { + code: 'c', + picture: 'crow.png' + }, + back: { + code: 'C', + picture: 'black.png' + } + }, } as const; export type CellDefinitions = keyof typeof CELL_DEFINITIONS; diff --git a/frontend/src/pages/editor-page.tsx b/frontend/src/pages/editor-page.tsx index 8612021..f0f072b 100644 --- a/frontend/src/pages/editor-page.tsx +++ b/frontend/src/pages/editor-page.tsx @@ -5,7 +5,7 @@ import { PanelList } from '@/components/editor/panel-list'; import { NewPanelCreator } from '@/components/editor/new-panel-creator'; import { CellType, GridCell, Panel, PanelPlacementModeType, PanelPlacementHistoryType } from '@/components/types'; import { CellDefinitions } from 'constants/cell-types'; -// import { decodeStageFromUrl } from '../utils/url'; +import { decodeStageFromUrl } from '../utils/url'; const EditorPage: React.FC = () => { @@ -45,19 +45,19 @@ const EditorPage: React.FC = () => { const [gridHistory, setGridHistory] = useState([grid]); const [panelPlacementHistory, setPanelPlacementHistory] = useState([]); - // useEffect(() => { + useEffect(() => { - // const params = new URLSearchParams(window.location.search); - // const cells = params.get('cells'); - // const panels = params.get('panels'); + const params = new URLSearchParams(window.location.search); + const cells = params.get('cells'); + const panels = params.get('panels'); - // if (cells && panels) { - // const stageData = `cells=${cells}&panels=${panels}`; - // const parsedData = decodeStageFromUrl(stageData); - // setGrid(parsedData.cells); - // setPanels(parsedData.panels); - // } - // }, []); + if (cells && panels) { + const stageData = `cells=${cells}&panels=${panels}`; + const parsedData = decodeStageFromUrl(stageData); + setGrid(parsedData.cells); + setPanels(parsedData.panels); + } + }, []); // FastAPIの疎通確認 useEffect(() => { diff --git a/frontend/src/utils/url.ts b/frontend/src/utils/url.ts index 2653165..f5c9778 100644 --- a/frontend/src/utils/url.ts +++ b/frontend/src/utils/url.ts @@ -1,17 +1,20 @@ -import { CellType, Panel } from '@/components/types'; -import { CELL_TYPES } from '../constants/cell-types'; +import { CellDefinitions, CellType, Panel, GridCell } from '@/components/types'; +import { CELL_DEFINITIONS, CELL_TYPES } from '../constants/cell-types'; -const encodeStageToUrl = (grid: CellType[][], panels: Panel[]) => { +const encodeStageToUrl = (grid: GridCell[][], panels: Panel[]) => { // Cells のエンコード const cellsHeight = grid.length; const cellsWidth = grid[0].length; const cellsGrid = grid .flat() - .map((cell) => CELL_TYPES[cell].code) + .map((cell) => { + const cellDef = CELL_DEFINITIONS[cell.type]?.[cell.side]; + return cellDef ? cellDef.code : ''; + }) .join(''); const cellsEncoded = `h${cellsHeight}w${cellsWidth}g${cellsGrid}`; - // Panels のエンコード + // Panels のエンコード (unchanged) const panelsEncoded = panels .map((panel) => { const height = panel.cells.length; @@ -27,7 +30,7 @@ const encodeStageToUrl = (grid: CellType[][], panels: Panel[]) => { return `cells=${cellsEncoded}&panels=${panelsEncoded}`; }; -export const shareStageUrl = (grid: CellType[][], panels: Panel[]) => { +export const shareStageUrl = (grid: GridCell[][], panels: Panel[]) => { const stageData = encodeStageToUrl(grid, panels); const url = `${window.location.origin}/stage?${stageData}`; navigator.clipboard.writeText(url); @@ -47,8 +50,42 @@ export const decodeStageFromUrl = (stageData: string) => { const cellsWidth = parseInt(cellsWidthMatch?.[1] || '0', 10); const cellsGridString = cellsGridMatch?.[1] || ''; + // グリッドデータをデコード + const decodeCellGrid = (gridString: string): GridCell[] => { + const cells: GridCell[] = []; + let i = 0; + while (i < gridString.length) { + const currentChar = gridString[i]; + + const cellType = Object.keys(CELL_DEFINITIONS).find(type => + Object.values(CELL_DEFINITIONS[type]).some( + sideInfo => typeof sideInfo === 'object' && 'code' in sideInfo && sideInfo.code === currentChar + ) + ); + + if (cellType) { + let side: GridCell['side'] = 'neutral'; + + // Determine the side based on the code + Object.entries(CELL_DEFINITIONS[cellType]).forEach(([key, value]) => { + if (key !== 'label' && key !== 'color' && typeof value === 'object' && value && 'code' in value && value.code === currentChar) { + side = key as GridCell['side']; + } + }); + + cells.push({ type: cellType as CellDefinitions, side }); + } else { + // Fallback to Empty if no matching cell type + cells.push({ type: 'Empty', side: 'neutral' }); + } + + i += 1; + } + return cells; + }; + // グリッドデータをデコード(矢印の処理を改善) - const decodeCellGrid = (gridString: string): CellType[] => { + const decodePanelGrid = (gridString: string): CellType[] => { const cells: CellType[] = []; let i = 0; while (i < gridString.length) { @@ -109,7 +146,7 @@ export const decodeStageFromUrl = (stageData: string) => { const width = parseInt(widthMatch?.[1] || '0', 10); const gridData = gridMatch?.[1] || ''; - const decodedPanelCells = decodeCellGrid(gridData); + const decodedPanelCells = decodePanelGrid(gridData); const panelCells = Array.from({ length: height }, (_, i) => decodedPanelCells.slice(i * width, (i + 1) * width) ); @@ -118,4 +155,4 @@ export const decodeStageFromUrl = (stageData: string) => { }); return { cells, panels }; -}; +}; \ No newline at end of file From e554c249e0eae5bcf2ff816fe45a4e49c417c632 Mon Sep 17 00:00:00 2001 From: Suke-H Date: Fri, 24 Jan 2025 21:07:38 +0900 Subject: [PATCH 9/9] =?UTF-8?q?=E2=9C=85=20fix:=20#28=20Yaml=E5=85=A5?= =?UTF-8?q?=E5=87=BA=E5=8A=9B=E3=81=AE=E7=A2=BA=E8=AA=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/editor/grid.tsx | 24 +++++++--------- frontend/src/utils/string-operations.ts | 9 ++++++ frontend/src/utils/yaml.ts | 38 ++++++++++++------------- 3 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 frontend/src/utils/string-operations.ts diff --git a/frontend/src/components/editor/grid.tsx b/frontend/src/components/editor/grid.tsx index 5e46de2..f88d51d 100644 --- a/frontend/src/components/editor/grid.tsx +++ b/frontend/src/components/editor/grid.tsx @@ -1,10 +1,9 @@ import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle, } from '@/components/ui/card'; -// import { PlusCircle, MinusCircle, Download, Upload, Link } from 'lucide-react'; -import { PlusCircle, MinusCircle, Link } from 'lucide-react'; +import { PlusCircle, MinusCircle, Download, Upload, Link } from 'lucide-react'; import { GridCell, Panel, PanelPlacementModeType, PanelPlacementHistoryType , CellDefinitions} from '../types'; import { CELL_DEFINITIONS, CellSideInfo } from '../../constants/cell-types'; -// import { exportStageToYaml, importStageFromYaml } from '../../utils/yaml'; +import { exportStageToYaml, importStageFromYaml } from '../../utils/yaml'; import { shareStageUrl } from '../../utils/url'; interface GridProps { @@ -24,9 +23,7 @@ export const Grid: React.FC = ({ setGrid, setGridHistory, selectedCellType, - // eslint-disable-next-line @typescript-eslint/no-unused-vars panels, - // eslint-disable-next-line @typescript-eslint/no-unused-vars setPanels, panelPlacementMode, setPanelPlacementMode, @@ -207,13 +204,12 @@ export const Grid: React.FC = ({ return true; }; - // const triggerFileInput = () => { - // const input = document.getElementById('yamlImport') as HTMLInputElement; - // if (input) { - // input.click(); - // } - // }; - + const triggerFileInput = () => { + const input = document.getElementById('yamlImport') as HTMLInputElement; + if (input) { + input.click(); + } + }; return ( @@ -251,7 +247,7 @@ export const Grid: React.FC = ({
- {/* = ({ - */} + diff --git a/frontend/src/utils/string-operations.ts b/frontend/src/utils/string-operations.ts new file mode 100644 index 0000000..15c4bde --- /dev/null +++ b/frontend/src/utils/string-operations.ts @@ -0,0 +1,9 @@ +// 頭文字を大文字にする +export const capitalize = (str: string) => { + return str.charAt(0).toUpperCase() + str.slice(1); +}; + +// 頭文字を小文字にする +export const uncapitalize = (str: string) => { + return str.charAt(0).toLowerCase() + str.slice(1); +}; diff --git a/frontend/src/utils/yaml.ts b/frontend/src/utils/yaml.ts index 4ee5449..48e156a 100644 --- a/frontend/src/utils/yaml.ts +++ b/frontend/src/utils/yaml.ts @@ -1,30 +1,32 @@ -import { CellType, Panel } from '@/components/types'; import { parse, stringify } from 'yaml'; +import { CellDefinitions, CellType, Panel, GridCell } from '@/components/types'; +// import { CELL_DEFINITIONS, CELL_TYPES } from '../constants/cell-types'; +import { capitalize, uncapitalize } from './string-operations'; interface CellYamlData { Type: { Type: string; SkinId: number; }; - StartColor: string; // "Black", "White", "Empty" + CellSide: string; } interface PanelYamlData { Coordinates: { X: number; Y: number }[]; } -const transformCellToYamlFormat = (cell: CellType): CellYamlData => { - if (cell === 'Black' || cell === 'White') { - return { Type: { Type: 'Normal', SkinId: 0 }, StartColor: cell.charAt(0).toUpperCase() + cell.slice(1) }; - } - if (cell === 'Empty') { - return { Type: { Type: 'Normal', SkinId: 0 }, StartColor: 'Empty' }; - } - return { Type: { Type: cell || 'Normal', SkinId: 0 }, StartColor: 'White' }; +const transformCellToYamlFormat = (cell: GridCell): CellYamlData => { + return { + Type: { + Type: cell.type, + SkinId: 0 + }, + CellSide: capitalize(cell.side) + }; }; export const exportStageToYaml = ( - grid: CellType[][], + grid: GridCell[][], panels: Panel[] ) => { const cells = grid.map(row => row.map(cell => transformCellToYamlFormat(cell))); @@ -54,7 +56,7 @@ export const exportStageToYaml = ( export const importStageFromYaml = ( event: React.ChangeEvent, - setGrid: (grid: CellType[][]) => void, + setGrid: (grid: GridCell[][]) => void, setPanels: (panels: Panel[]) => void ) => { const file = event.target.files?.[0]; @@ -66,13 +68,11 @@ export const importStageFromYaml = ( const { Height, Width, Cells, Panels } = yamlData; // グリッド変換 - const grid: CellType[][] = Cells.map((row: CellYamlData[]) => - row.map((cell: CellYamlData) => { - if (cell.Type.Type === 'Normal') { - return cell.StartColor as CellType; - } - return cell.Type.Type; - }) + const grid: GridCell[][] = Cells.map((row: CellYamlData[]) => + row.map((cell: CellYamlData) => ({ + type: cell.Type.Type as CellDefinitions, + side: uncapitalize(cell.CellSide) as GridCell['side'] + })) ); // パネル変換とトリム