Compare commits
2 Commits
1f3895a025
...
851e78bff3
Author | SHA1 | Date | |
---|---|---|---|
|
851e78bff3 | ||
|
0961ba41fd |
40
package-lock.json
generated
40
package-lock.json
generated
@ -12,7 +12,8 @@
|
|||||||
"@uidotdev/usehooks": "^2.4.1",
|
"@uidotdev/usehooks": "^2.4.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"recoil": "^0.7.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/lodash": "^4.14.202",
|
"@types/lodash": "^4.14.202",
|
||||||
@ -1776,6 +1777,11 @@
|
|||||||
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
|
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/hamt_plus": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA=="
|
||||||
|
},
|
||||||
"node_modules/handle-thing": {
|
"node_modules/handle-thing": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||||
@ -3118,6 +3124,25 @@
|
|||||||
"node": ">= 10.13.0"
|
"node": ">= 10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/recoil": {
|
||||||
|
"version": "0.7.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz",
|
||||||
|
"integrity": "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"hamt_plus": "1.0.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.13.1"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-native": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/relateurl": {
|
"node_modules/relateurl": {
|
||||||
"version": "0.2.7",
|
"version": "0.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||||
@ -5749,6 +5774,11 @@
|
|||||||
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
|
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"hamt_plus": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA=="
|
||||||
|
},
|
||||||
"handle-thing": {
|
"handle-thing": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||||
@ -6729,6 +6759,14 @@
|
|||||||
"resolve": "^1.20.0"
|
"resolve": "^1.20.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"recoil": {
|
||||||
|
"version": "0.7.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/recoil/-/recoil-0.7.7.tgz",
|
||||||
|
"integrity": "sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==",
|
||||||
|
"requires": {
|
||||||
|
"hamt_plus": "1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"relateurl": {
|
"relateurl": {
|
||||||
"version": "0.2.7",
|
"version": "0.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
"@uidotdev/usehooks": "^2.4.1",
|
"@uidotdev/usehooks": "^2.4.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"recoil": "^0.7.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
src/atoms.ts
Normal file
8
src/atoms.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
|
export const DEFAULT_COLOR = '#339ad6';
|
||||||
|
|
||||||
|
export const currentColorState = atom({
|
||||||
|
key: 'colorState',
|
||||||
|
default: DEFAULT_COLOR,
|
||||||
|
});
|
@ -1,8 +1,15 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
import { RecoilRoot } from 'recoil';
|
||||||
import Grid from '../grid/grid';
|
import Grid from '../grid/grid';
|
||||||
|
import GridConfig from '../grid/grid-config';
|
||||||
|
|
||||||
const App: FC = () => {
|
const App: FC = () => {
|
||||||
return <Grid />;
|
return (
|
||||||
|
<RecoilRoot>
|
||||||
|
<Grid />
|
||||||
|
<GridConfig />
|
||||||
|
</RecoilRoot>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
39
src/components/grid/grid-config.scss
Normal file
39
src/components/grid/grid-config.scss
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
.grid-config {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-config {
|
||||||
|
background-color: #000;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
.color-options {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
|
||||||
|
.color-option {
|
||||||
|
margin: 5px;
|
||||||
|
padding: 7px;
|
||||||
|
background-color: #283f56;
|
||||||
|
border: 2px solid #283f56;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #265584;
|
||||||
|
border-color: #458bd1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sample {
|
||||||
|
width: 24px;
|
||||||
|
height: 13px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
src/components/grid/grid-config.tsx
Normal file
52
src/components/grid/grid-config.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
import { currentColorState, DEFAULT_COLOR } from '../../atoms';
|
||||||
|
|
||||||
|
import './grid-config.scss';
|
||||||
|
|
||||||
|
interface ColorOptionProps {
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorOption: FC<ColorOptionProps> = (props: ColorOptionProps) => {
|
||||||
|
const { color } = props;
|
||||||
|
const [currentColor, setCurrentColor] = useRecoilState(currentColorState);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
color === currentColor ? 'color-option active' : 'color-option'
|
||||||
|
}
|
||||||
|
onClick={() => setCurrentColor(color)}
|
||||||
|
>
|
||||||
|
<div className="sample" style={{ backgroundColor: color }} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ColorConfig: FC = () => {
|
||||||
|
return (
|
||||||
|
<div className="color-config">
|
||||||
|
<div className="color-options">
|
||||||
|
<ColorOption color={DEFAULT_COLOR} />
|
||||||
|
<ColorOption color="#d33b3d" />
|
||||||
|
<ColorOption color="#3dd33b" />
|
||||||
|
<ColorOption color="#f1c40f" />
|
||||||
|
<ColorOption color="#d35400" />
|
||||||
|
<ColorOption color="#8e44ad" />
|
||||||
|
<ColorOption color="#eeeeee" />
|
||||||
|
<ColorOption color="#95a5a6" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const GridConfig: FC = () => {
|
||||||
|
return (
|
||||||
|
<div className="grid-config">
|
||||||
|
<ColorConfig />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GridConfig;
|
@ -12,6 +12,8 @@ import {
|
|||||||
import './grid.scss';
|
import './grid.scss';
|
||||||
|
|
||||||
import * as lodash from 'lodash';
|
import * as lodash from 'lodash';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { currentColorState } from '../../atoms';
|
||||||
|
|
||||||
interface Point {
|
interface Point {
|
||||||
x: number;
|
x: number;
|
||||||
@ -122,9 +124,10 @@ const Grid: FC = () => {
|
|||||||
return lines_thin.concat(lines_thick);
|
return lines_thin.concat(lines_thick);
|
||||||
}, [range, GAP]);
|
}, [range, GAP]);
|
||||||
|
|
||||||
const [userLines, setUserLines] = useState<Range[]>([]);
|
const [userLines, setUserLines] = useState<Line[]>([]);
|
||||||
const [userRedoLines, setUserRedoLines] = useState<Range[]>([]);
|
const [userRedoLines, setUserRedoLines] = useState<Line[]>([]);
|
||||||
const [userStartPoint, setUserStartPoint] = useState<Point | null>(null);
|
const [userStartPoint, setUserStartPoint] = useState<Point | null>(null);
|
||||||
|
const userLineColor = useRecoilValue(currentColorState);
|
||||||
|
|
||||||
// mouse clicks create lines
|
// mouse clicks create lines
|
||||||
const onGridClick = useCallback(
|
const onGridClick = useCallback(
|
||||||
@ -146,7 +149,7 @@ const Grid: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const line = pointsToRange(userStartPoint, point);
|
const line = pointsToRange(userStartPoint, point);
|
||||||
setUserLines([...userLines, line]);
|
setUserLines([...userLines, { ...line, stroke: userLineColor }]);
|
||||||
|
|
||||||
if (event.shiftKey == false) {
|
if (event.shiftKey == false) {
|
||||||
setUserStartPoint(null);
|
setUserStartPoint(null);
|
||||||
@ -154,7 +157,14 @@ const Grid: FC = () => {
|
|||||||
setUserStartPoint(point);
|
setUserStartPoint(point);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[userStartPoint, setUserStartPoint, setUserLines, GAP, mousePoint]
|
[
|
||||||
|
userLineColor,
|
||||||
|
userStartPoint,
|
||||||
|
setUserStartPoint,
|
||||||
|
setUserLines,
|
||||||
|
GAP,
|
||||||
|
mousePoint,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onGridContextMenu = useCallback(
|
const onGridContextMenu = useCallback(
|
||||||
@ -210,7 +220,7 @@ const Grid: FC = () => {
|
|||||||
y1={userStartPoint.y}
|
y1={userStartPoint.y}
|
||||||
x2={point.x}
|
x2={point.x}
|
||||||
y2={point.y}
|
y2={point.y}
|
||||||
stroke="#ff0000"
|
stroke={userLineColor}
|
||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -223,7 +233,7 @@ const Grid: FC = () => {
|
|||||||
cx={point.x}
|
cx={point.x}
|
||||||
cy={point.y}
|
cy={point.y}
|
||||||
r="3"
|
r="3"
|
||||||
fill="#ff0000"
|
fill={userLineColor}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, [userStartPoint, mousePoint]);
|
}, [userStartPoint, mousePoint]);
|
||||||
@ -237,7 +247,7 @@ const Grid: FC = () => {
|
|||||||
y1={line.y0}
|
y1={line.y0}
|
||||||
x2={line.x1}
|
x2={line.x1}
|
||||||
y2={line.y1}
|
y2={line.y1}
|
||||||
stroke="#ff0000"
|
stroke={line.stroke}
|
||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
Loading…
Reference in New Issue
Block a user