actually have a more usable way in mind
This commit is contained in:
parent
89ecd65999
commit
584eb559bd
32
archive/number-state-input.tsx
Normal file
32
archive/number-state-input.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
interface StateInputProps<T> {
|
||||||
|
state: PrimitiveAtom<T>;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NumberStateInput: FC<StateInputProps<number | null>> = (
|
||||||
|
props: StateInputProps<number | null>
|
||||||
|
) => {
|
||||||
|
const { state, className } = props;
|
||||||
|
const [number, setNumber] = useAtom(state);
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const re = /^\d*$/;
|
||||||
|
const v = e.target.value;
|
||||||
|
if (v === '') {
|
||||||
|
setNumber(null);
|
||||||
|
} else if (re.test(v)) {
|
||||||
|
setNumber(parseInt(v));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setNumber]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
className={className}
|
||||||
|
value={number ?? ''}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -16,6 +16,3 @@ type DrawMode = 'line' | 'trash' | 'grid';
|
|||||||
export const lineColorState = atom<string>(COLORS[0]!);
|
export const lineColorState = atom<string>(COLORS[0]!);
|
||||||
|
|
||||||
export const drawModeState = atom<DrawMode>('line');
|
export const drawModeState = atom<DrawMode>('line');
|
||||||
|
|
||||||
export const drawGridWidthState = atom<number | null>(4);
|
|
||||||
export const drawGridHeightState = atom<number | null>(4);
|
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
import { ChangeEvent, FC, useCallback } from 'react';
|
import { ChangeEvent, FC, useCallback } from 'react';
|
||||||
import { PrimitiveAtom, useAtom, WritableAtom } from 'jotai';
|
import { PrimitiveAtom, useAtom } from 'jotai';
|
||||||
import {
|
import { COLORS, drawModeState, lineColorState } from '../../atoms';
|
||||||
COLORS,
|
|
||||||
drawGridHeightState,
|
|
||||||
drawGridWidthState,
|
|
||||||
drawModeState,
|
|
||||||
lineColorState,
|
|
||||||
} from '../../atoms';
|
|
||||||
|
|
||||||
import './grid-config.scss';
|
import './grid-config.scss';
|
||||||
|
|
||||||
@ -46,16 +40,14 @@ const GridIcon = (
|
|||||||
<svg
|
<svg
|
||||||
className="icon"
|
className="icon"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="12"
|
viewBox="0 0 24 13"
|
||||||
height="12"
|
|
||||||
viewBox="0 0 12 12"
|
|
||||||
>
|
>
|
||||||
<line x1="0" y1="0" x2="12" y2="0" stroke="#ffffff" strokeWidth="2" />
|
<line x1="5" y1="0" x2="18" y2="0" stroke="#ffffff" strokeWidth="4" />
|
||||||
<line x1="0" y1="6" x2="12" y2="6" stroke="#ffffff" strokeWidth="2" />
|
<line x1="5" y1="7" x2="18" y2="7" stroke="#ffffff" strokeWidth="2" />
|
||||||
<line x1="0" y1="12" x2="12" y2="12" stroke="#ffffff" strokeWidth="2" />
|
<line x1="5" y1="13" x2="18" y2="13" stroke="#ffffff" strokeWidth="4" />
|
||||||
<line x1="0" y1="0" x2="0" y2="12" stroke="#ffffff" strokeWidth="2" />
|
<line x1="5" y1="0" x2="5" y2="13" stroke="#ffffff" strokeWidth="2" />
|
||||||
<line x1="6" y1="0" x2="6" y2="12" stroke="#ffffff" strokeWidth="2" />
|
<line x1="11" y1="0" x2="11" y2="13" stroke="#ffffff" strokeWidth="2" />
|
||||||
<line x1="12" y1="0" x2="12" y2="12" stroke="#ffffff" strokeWidth="2" />
|
<line x1="17" y1="0" x2="17" y2="13" stroke="#ffffff" strokeWidth="2" />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -84,39 +76,6 @@ const ColorOption: FC<ColorOptionProps> = (props: ColorOptionProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface StateInputProps<T> {
|
|
||||||
state: PrimitiveAtom<T>;
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NumberStateInput: FC<StateInputProps<number | null>> = (
|
|
||||||
props: StateInputProps<number | null>
|
|
||||||
) => {
|
|
||||||
const { state, className } = props;
|
|
||||||
const [number, setNumber] = useAtom(state);
|
|
||||||
|
|
||||||
const handleChange = useCallback(
|
|
||||||
(e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const re = /^\d*$/;
|
|
||||||
const v = e.target.value;
|
|
||||||
if (v === '') {
|
|
||||||
setNumber(null);
|
|
||||||
} else if (re.test(v)) {
|
|
||||||
setNumber(parseInt(v));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[setNumber]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
className={className}
|
|
||||||
value={number ?? ''}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ColorConfig: FC = () => (
|
const ColorConfig: FC = () => (
|
||||||
<div className="color-options">
|
<div className="color-options">
|
||||||
{COLORS.map((color) => (
|
{COLORS.map((color) => (
|
||||||
@ -130,8 +89,7 @@ const ModeConfig: FC = () => {
|
|||||||
|
|
||||||
const lineClassName = drawMode === 'line' ? 'option active' : 'option';
|
const lineClassName = drawMode === 'line' ? 'option active' : 'option';
|
||||||
const trashClassName = drawMode === 'trash' ? 'option active' : 'option';
|
const trashClassName = drawMode === 'trash' ? 'option active' : 'option';
|
||||||
const gridClassName =
|
const gridClassName = drawMode === 'grid' ? 'option active' : 'option';
|
||||||
drawMode === 'grid' ? 'option active grid' : 'option grid';
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="tool-options">
|
<div className="tool-options">
|
||||||
@ -147,22 +105,11 @@ const ModeConfig: FC = () => {
|
|||||||
>
|
>
|
||||||
{TrashIcon}
|
{TrashIcon}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className="grid-options">
|
|
||||||
<div
|
<div
|
||||||
className={gridClassName}
|
className={gridClassName}
|
||||||
onClick={() => setDrawMode('grid')}
|
onClick={() => setDrawMode('grid')}
|
||||||
>
|
>
|
||||||
{GridIcon}
|
{GridIcon}
|
||||||
<NumberStateInput
|
|
||||||
className="grid-size width"
|
|
||||||
state={drawGridWidthState}
|
|
||||||
/>
|
|
||||||
<span className="x">x</span>
|
|
||||||
<NumberStateInput
|
|
||||||
className="grid-size height"
|
|
||||||
state={drawGridHeightState}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -181,7 +181,14 @@ const Grid: FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const point = snapToGrid(mousePoint, GAP);
|
let point;
|
||||||
|
if (userDrawMode === 'grid') {
|
||||||
|
// snap to the thick grid
|
||||||
|
point = snapToGrid(mousePoint, GAP * 6);
|
||||||
|
} else {
|
||||||
|
// snap to the thin grid for line / trash
|
||||||
|
point = snapToGrid(mousePoint, GAP);
|
||||||
|
}
|
||||||
|
|
||||||
if (lodash.isEqual(userStartPoint, point)) {
|
if (lodash.isEqual(userStartPoint, point)) {
|
||||||
setUserStartPoint(null);
|
setUserStartPoint(null);
|
||||||
@ -249,6 +256,12 @@ const Grid: FC = () => {
|
|||||||
|
|
||||||
// ctrl+z/ctrl+y for undo/redo
|
// ctrl+z/ctrl+y for undo/redo
|
||||||
const onUndo = useCallback(() => {
|
const onUndo = useCallback(() => {
|
||||||
|
if (!lodash.isNull(userStartPoint)) {
|
||||||
|
// if the user has a start point, just cancel the pending line
|
||||||
|
setUserStartPoint(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const action = userActions[userActions.length - 1];
|
const action = userActions[userActions.length - 1];
|
||||||
if (!action) return;
|
if (!action) return;
|
||||||
|
|
||||||
@ -264,7 +277,7 @@ const Grid: FC = () => {
|
|||||||
}
|
}
|
||||||
setUserActions(userActions.slice(0, -1));
|
setUserActions(userActions.slice(0, -1));
|
||||||
setUserRedoActions([...userRedoActions, action]);
|
setUserRedoActions([...userRedoActions, action]);
|
||||||
}, [userLines, userActions, userRedoActions]);
|
}, [userLines, userActions, userRedoActions, userStartPoint]);
|
||||||
|
|
||||||
const onRedo = useCallback(() => {
|
const onRedo = useCallback(() => {
|
||||||
const action = userRedoActions[userRedoActions.length - 1];
|
const action = userRedoActions[userRedoActions.length - 1];
|
||||||
@ -341,6 +354,7 @@ const Grid: FC = () => {
|
|||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
// TODO: grid mode
|
||||||
} else {
|
} else {
|
||||||
console.assert(userDrawMode === 'trash');
|
console.assert(userDrawMode === 'trash');
|
||||||
return (
|
return (
|
||||||
|
Loading…
Reference in New Issue
Block a user