From f76c4551bf52f4e42cb9644dd147a12b0c2b3041 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Mon, 14 Oct 2024 16:13:43 +0900 Subject: [PATCH 01/63] =?UTF-8?q?=EC=A7=80=EB=B6=95=20=EB=AA=A8=EC=96=91?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EC=9E=91=EC=97=85=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dictionary.txt | 3 +- src/components/Roof2.jsx | 18 +- src/components/fabric/QPolygon.js | 9 +- src/hooks/useMode.js | 257 +++-- src/util/qpolygon-utils.js | 1504 ++++++++++++++--------------- 5 files changed, 843 insertions(+), 948 deletions(-) diff --git a/docs/dictionary.txt b/docs/dictionary.txt index cef0921e..7e07124d 100644 --- a/docs/dictionary.txt +++ b/docs/dictionary.txt @@ -23,4 +23,5 @@ 개구: openSpace 도머: dormer 그림자: shadow - +복도치수: planeSize +실제치수: actualSize diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index fbe61038..910fd365 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -39,7 +39,7 @@ import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMen import InitSettingsModal from './InitSettingsModal' import GridSettingsModal from './GridSettingsModal' import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' -import { changeAllHipAndGableRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils' +import { drawDirectionStringToArrow } from '@/util/qpolygon-utils' import ThumbnailList from '@/components/ui/ThumbnailLIst' import ObjectPlacement from '@/components/ui/ObjectPlacement' import { globalLocaleStore } from '@/store/localeAtom' @@ -409,6 +409,20 @@ export default function Roof2(props) { { x: 600, y: 100 }, ] + const rectangleType1 = [ + { x: 100, y: 100 }, + { x: 100, y: 600 }, + { x: 300, y: 600 }, + { x: 300, y: 100 }, + ] + + const rectangleType2 = [ + { x: 100, y: 100 }, + { x: 100, y: 300 }, + { x: 600, y: 300 }, + { x: 600, y: 100 }, + ] + const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint] const newP = [ { x: 450, y: 450 }, @@ -417,7 +431,7 @@ export default function Roof2(props) { { x: 450, y: 850 }, ] - const polygon = new QPolygon(twelvePoint, { + const polygon = new QPolygon(rectangleType2, { fill: 'transparent', stroke: 'green', strokeWidth: 1, diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 84e57974..9e034ac9 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -2,7 +2,7 @@ import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' import { QLine } from '@/components/fabric/QLine' import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util' -import { calculateAngle, drawDirectionArrow, drawHippedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils' +import { calculateAngle, drawDirectionArrow, drawRidgeRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils' import * as turf from '@turf/turf' export const QPolygon = fabric.util.createClass(fabric.Polygon, { @@ -174,9 +174,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }, // 보조선 그리기 - drawHelpLine(chon = 4) { - // drawHelpLineInHexagon(this, chon) - drawHippedRoof(this, chon) + drawHelpLine(pitch = 4) { + // drawHelpLineInHexagon(this, pitch) + console.log('drawHelpLine roofId : ', this.id) + drawRidgeRoof(this.id, pitch, this.canvas) }, addLengthText() { diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 6778bdba..e82c51f3 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -36,10 +36,7 @@ import { QPolygon } from '@/components/fabric/QPolygon' import offsetPolygon from '@/util/qpolygon-utils' import { isObjectNotEmpty } from '@/util/common-utils' import * as turf from '@turf/turf' -import { INPUT_TYPE, Mode } from '@/common/common' -import { m } from 'framer-motion' -import { set } from 'react-hook-form' -import { FaWineGlassEmpty } from 'react-icons/fa6' +import { INPUT_TYPE, LINE_TYPE, Mode } from '@/common/common' export function useMode() { const [mode, setMode] = useRecoilState(modeState) @@ -1509,6 +1506,25 @@ export function useMode() { *벽 지붕 외곽선 생성 polygon을 입력받아 만들기 */ const handleOuterlinesTest2 = (polygon, offset = 50) => { + console.log('polygon : ', polygon) + // TODO [ljyoung] : offset 입력 처리 후 제거 해야함. + polygon.lines.forEach((line, index) => { + if (index === 1 || index === 3) { + line.attributes = { + type: LINE_TYPE.WALLLINE.WALL, + offset: 50, + width: 100, + pitch: 4, + } + } else { + line.attributes = { + type: LINE_TYPE.WALLLINE.WALL, + offset: 50, + width: 100, + pitch: 4, + } + } + }) const roof = drawRoofPolygon(polygon) //지붕 그리기 roof.drawHelpLine() // roof.divideLine() @@ -1677,21 +1693,6 @@ export function useMode() { } const drawRoofPolygon = (wall) => { - // TODO [ljyoung] : offset 입력 처리 후 제거 해야함. - wall.lines.forEach((line, index) => { - if (index === wall.lines.length - 1 || index === 3) { - line.attributes = { - type: 'gable', - offset: 30, - } - } else { - line.attributes = { - type: 'hip', - offset: 50, - } - } - }) - const polygon = createRoofPolygon(wall.points) const originPolygon = new QPolygon(wall.points, { fontSize: 0 }) let offsetPolygon @@ -1710,13 +1711,33 @@ export function useMode() { return { x1: point.x, y1: point.y } }), ) - roof.name = 'roofBase' + roof.name = 'roof' roof.setWall(wall) roof.lines.forEach((line, index) => { - line.attributes = { type: wall.lines[index].attributes.type } + line.attributes = { + roofId: roof.id, + wallLine: wall.lines[index].id, + type: wall.lines[index].attributes.type, + offset: wall.lines[index].attributes.offset, + width: wall.lines[index].attributes.width, + pitch: wall.lines[index].attributes.pitch, + } }) + wall.attributes = { + roofId: roof.id, + } + + wall.lines.forEach((line, index) => { + line.attributes = { + roofId: roof.id, + } + }) + + console.log('roof : ', roof) + console.log('wall : ', wall) + setRoof(roof) setWall(wall) @@ -4852,12 +4873,6 @@ export function useMode() { ) } - const coordToTurfPolygon = (points) => { - const coordinates = points.map((point) => [point.x, point.y]) - coordinates.push(coordinates[0]) - return turf.polygon([coordinates]) - } - /** * trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 로 진입여부를 확인 * 확인 후 셀을 이동시킴 @@ -4866,125 +4881,58 @@ export function useMode() { const trestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'trestle') //가대를 가져옴 if (trestlePolygons.length !== 0) { + let lastPointPosition = { x: 0, y: 0 } let fabricPolygon = null let inside = false let turfPolygon - let manualDrawCells = drewRoofCells // 앞에서 자동으로 했을때 추가됨 - let direction + let manualDrawCells = drewRoofCells // + canvas.on('mouse:move', (e) => { //마우스 이벤트 삭제 후 재추가 const mousePoint = canvas.getPointer(e.e) + const turfPoint = turf.point([mousePoint.x, mousePoint.y]) + for (let i = 0; i < trestlePolygons.length; i++) { turfPolygon = polygonToTurfPolygon(trestlePolygons[i]) - direction = trestlePolygons[i].direction //도형의 방향 - let width = direction === 'south' || direction === 'north' ? 172 : 113 - let height = direction === 'south' || direction === 'north' ? 113 : 172 - - const points = [ - { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 }, - { x: mousePoint.x + width / 2, y: mousePoint.y - height / 2 }, - { x: mousePoint.x + width / 2, y: mousePoint.y + height / 2 }, - { x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 }, - ] - - const turfPoints = coordToTurfPolygon(points) - - if (turf.booleanWithin(turfPoints, turfPolygon)) { + if (turf.booleanPointInPolygon(turfPoint, turfPolygon)) { //turf에 보면 폴리곤안에 포인트가 있는지 함수가 있다 + const direction = trestlePolygons[i].direction //도형의 방향 + let width = direction === 'south' || direction === 'north' ? 172.2 : 113.4 + let height = direction === 'south' || direction === 'north' ? 113.4 : 172.2 + if (Math.abs(mousePoint.x - lastPointPosition.x) >= 5 || Math.abs(mousePoint.y - lastPointPosition.y) >= 5) { + let isDrawing = false - // if (Math.abs(mousePoint.x - lastPointPosition.x) >= 5 || Math.abs(mousePoint.y - lastPointPosition.y) >= 5) { - let isDrawing = false + if (isDrawing) return + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tmpCell')) //움직일때 일단 지워가면서 움직임 - if (isDrawing) return - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tmpCell')) //움직일때 일단 지워가면서 움직임 + const points = [ + { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 }, + { x: mousePoint.x + width / 2, y: mousePoint.y - height / 2 }, + { x: mousePoint.x + width / 2, y: mousePoint.y + height / 2 }, + { x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 }, + ] - fabricPolygon = new QPolygon(points, { - fill: '#BFFD9F', - // stroke: 'black', - // strokeWidth: 1, - selectable: false, // 선택 가능하게 설정 - lockMovementX: true, // X 축 이동 잠금 - lockMovementY: true, // Y 축 이동 잠금 - lockRotation: true, // 회전 잠금 - lockScalingX: true, // X 축 크기 조정 잠금 - lockScalingY: true, // Y 축 크기 조정 잠금 - opacity: 0.8, - parentId: trestlePolygons[i].parentId, - name: 'tmpCell', - }) + fabricPolygon = new QPolygon(points, { + fill: '#BFFD9F', + stroke: 'black', + selectable: false, // 선택 가능하게 설정 + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + lockScalingX: true, // X 축 크기 조정 잠금 + lockScalingY: true, // Y 축 크기 조정 잠금 + opacity: 0.8, + parentId: trestlePolygons[i].parentId, + name: 'tmpCell', + }) - canvas?.add(fabricPolygon) //움직여가면서 추가됨 - - /** - * 스냅기능 - */ - let snapDistance = 20 - - const bigLeft = trestlePolygons[i].left - const bigTop = trestlePolygons[i].top - const bigRight = bigLeft + trestlePolygons[i].width * trestlePolygons[i].scaleX - const bigBottom = bigTop + trestlePolygons[i].height * trestlePolygons[i].scaleY - const bigCenter = (bigTop + bigTop + trestlePolygons[i].height) / 2 - - // 작은 폴리곤의 경계 좌표 계산 - const smallLeft = fabricPolygon.left - const smallTop = fabricPolygon.top - const smallRight = smallLeft + fabricPolygon.width * fabricPolygon.scaleX - const smallBottom = smallTop + fabricPolygon.height * fabricPolygon.scaleY - const smallCenter = smallLeft + (fabricPolygon.width * fabricPolygon.scaleX) / 2 - - // 위쪽 변에 스냅 - if (Math.abs(smallTop - bigTop) < snapDistance) { - fabricPolygon.top = bigTop + canvas?.add(fabricPolygon) //움직여가면서 추가됨 + lastPointPosition = { x: mousePoint.x, y: mousePoint.y } } - // 아래쪽 변에 스냅 - if (Math.abs(smallTop + fabricPolygon.height * fabricPolygon.scaleY - (bigTop + trestlePolygons[i].height)) < snapDistance) { - fabricPolygon.top = bigTop + trestlePolygons[i].height - fabricPolygon.height * fabricPolygon.scaleY - } - - // 왼쪽변에 스냅 - if (Math.abs(smallLeft - bigLeft) < snapDistance) { - fabricPolygon.left = bigLeft - } - //오른쪽 변에 스냅 - if (Math.abs(smallRight - bigRight) < snapDistance) { - fabricPolygon.left = bigRight - fabricPolygon.width * fabricPolygon.scaleX - } - - if (direction === 'south' || direction === 'north') { - // 모듈왼쪽이 세로중앙선에 붙게 스냅 - if (Math.abs(smallLeft - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) { - fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2 - } - - // 모듈이 가운데가 세로중앙선에 붙게 스냅 - if (Math.abs(smallCenter - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) { - fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2 - (fabricPolygon.width * fabricPolygon.scaleX) / 2 - } - - // 모듈오른쪽이 세로중앙선에 붙게 스냅 - if (Math.abs(smallRight - (bigLeft + trestlePolygons[i].width / 2)) < snapDistance) { - fabricPolygon.left = bigLeft + trestlePolygons[i].width / 2 - fabricPolygon.width * fabricPolygon.scaleX - } - } else { - // 모듈이 가로중앙선에 스냅 - if (Math.abs(smallTop + fabricPolygon.height / 2 - bigCenter) < snapDistance) { - fabricPolygon.top = bigCenter - fabricPolygon.height / 2 - } - - if (Math.abs(smallTop - (bigTop + trestlePolygons[i].height / 2)) < snapDistance) { - fabricPolygon.top = bigTop + trestlePolygons[i].height / 2 - } - // 모듈 밑면이 가로중앙선에 스냅 - if (Math.abs(smallBottom - (bigTop + trestlePolygons[i].height / 2)) < snapDistance) { - fabricPolygon.top = bigTop + trestlePolygons[i].height / 2 - fabricPolygon.height * fabricPolygon.scaleY - } - } - - fabricPolygon.setCoords() canvas?.renderAll() inside = true + break } else { inside = false } @@ -5000,26 +4948,20 @@ export function useMode() { if (!inside) return if (fabricPolygon) { const turfCellPolygon = polygonToTurfPolygon(fabricPolygon) - fabricPolygon.setCoords() //좌표 재정렬 + if (turf.booleanWithin(turfCellPolygon, turfPolygon)) { //마우스 클릭시 set으로 해당 위치에 셀을 넣음 - - manualDrawCells.forEach((cell) => { - console.log('cells', cell.points) - }) - console.log('turfCellPolygon', turfCellPolygon.geometry.coordinates) - const isOverlap = manualDrawCells.some((cell) => turf.booleanOverlap(turfCellPolygon, polygonToTurfPolygon(cell))) if (!isOverlap) { //안겹치면 넣는다 - fabricPolygon.setCoords() fabricPolygon.set({ name: 'cell' }) + fabricPolygon.setCoords() manualDrawCells.push(fabricPolygon) } else { alert('셀끼리 겹치면 안되죠?') } - // } else { - // alert('나갔으요!!') + } else { + alert('나갔으요!!') } setDrewRoofCells(manualDrawCells) } @@ -5096,6 +5038,27 @@ export function useMode() { // console.log('bbox', bbox) + const boxes = [] + const installedCellsArray = [] + + for (let x = bbox[0]; x < bbox[2]; x += width) { + for (let y = bbox[1]; y < bbox[3]; y += height) { + const box = turf.polygon([ + [ + [x, y], + [x + width, y], + [x + width, y + height], + [x, y + height], + [x, y], + ], + ]) + + if (turf.booleanWithin(box, turfTrestlePolygon)) { + boxes.push(box) + } + } + } + for (let col = 0; col <= cols; col++) { for (let row = 0; row <= rows; row++) { let x = 0, @@ -5145,6 +5108,20 @@ export function useMode() { const squarePolygon = turf.polygon([square]) + // console.log('turfTrestlePolygon', turfTrestlePolygon) + // console.log('squarePolygon', squarePolygon) + + const areaSize = turf.area(turfTrestlePolygon) + + // console.log('areaSize', areaSize) + const objSize = turf.area(squarePolygon) + + // console.log('objSize', objSize) + + const maxObject = Math.floor(areaSize / objSize) + + // console.log('maxObjectSize', maxObject) + const disjointFromTrestle = turf.booleanContains(turfTrestlePolygon, squarePolygon) || turf.booleanWithin(squarePolygon, turfTrestlePolygon) if (disjointFromTrestle) { @@ -5185,8 +5162,6 @@ export function useMode() { lockScalingY: true, // Y 축 크기 조정 잠금 opacity: 0.8, parentId: trestle.parentId, - lineCol: col, - lineRow: row, }) canvas?.add(fabricPolygon) drawCellsArray.push(fabricPolygon) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index a7bcb0e2..c7ccfece 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -3,6 +3,7 @@ import { QLine } from '@/components/fabric/QLine' import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDirectionByPoint } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import * as turf from '@turf/turf' +import { LINE_TYPE } from '@/common/common' const TWO_PI = Math.PI * 2 @@ -12,7 +13,7 @@ export const defineQPloygon = () => { } } -export const drawHelpLineInHexagon = (polygon, chon) => { +export const drawHelpLineInHexagon = (polygon, pitch) => { const centerLines = drawCenterLines(polygon) let helpLines = [] @@ -1191,26 +1192,33 @@ function calculateAngleBetweenLines(line1, line2) { return (angleInRadians * 180) / Math.PI } -export const drawHippedRoof = (polygon, chon) => { - const hasNonParallelLines = polygon.lines.filter((line) => line.x1 !== line.x2 && line.y1 !== line.y2) +export const drawRidgeRoof = (roofId, pitch, canvas) => { + console.log('drawRidgeRoof : ', roofId) + const roof = canvas?.getObjects().find((object) => object.id === roofId) + const hasNonParallelLines = roof.lines.filter((line) => line.x1 !== line.x2 && line.y1 !== line.y2) if (hasNonParallelLines.length > 0) { alert('대각선이 존재합니다.') return } - drawRidgeRoof(polygon, chon) - drawHips(polygon) - connectLinePoint(polygon) + drawRidge(roof, canvas) + drawHips(roof, canvas) + connectLinePoint(roof, canvas) + modifyRidge(roof, canvas) } /** + * 마루가 존재하면 그린다. 마루는 지붕의 중간에 위치한다. * - * @param polygon - * @param chon + * @param roof + * @param canvas */ -const drawRidgeRoof = (polygon, chon) => { - const walls = polygon.wall.lines // 외벽의 라인 - const roofs = polygon.lines // 지붕의 라인 +const drawRidge = (roof, canvas) => { + const walls = canvas?.getObjects().find((object) => object.name === 'wall' && object.attributes.roofId === roof.id).lines // 외벽의 라인 + const roofs = roof.lines // 지붕의 라인 let ridgeRoof = [] + console.log('drawRidge : ', roof.ridges) + console.log('walls : ', walls) + console.log('roofs : ', roofs) roofs.forEach((currentRoof, index) => { let prevRoof, @@ -1228,8 +1236,11 @@ const drawRidgeRoof = (polygon, chon) => { // 지붕의 길이가 짧은 순으로 정렬 ridgeRoof.sort((a, b) => a.length - b.length) + console.log('ridgeRoof : ', ridgeRoof) + ridgeRoof.forEach((item) => { - if (getMaxRidge(roofs.length) > polygon.ridges.length) { + console.log(getMaxRidge(roofs.length), roof.ridges.length) + if (getMaxRidge(roofs.length) > roof.ridges.length) { let index = item.index, beforePrevRoof, prevRoof, @@ -1463,37 +1474,38 @@ const drawRidgeRoof = (polygon, chon) => { } } } - const currentWall = walls[index] - if (currentWall.attributes.type === 'gable') { - if (currentRoof.x1 === currentRoof.x2) { - startXPoint = currentRoof.x1 - } - if (currentRoof.y1 === currentRoof.y2) { - startYPoint = currentRoof.y1 - } - } + console.log('startXPoint', startXPoint, 'startYPoint', startYPoint, 'endXPoint', endXPoint, 'endYPoint', endYPoint) // 마루 그리기 if (startXPoint !== undefined && startYPoint !== undefined && endXPoint !== undefined && endYPoint !== undefined) { const ridge = new QLine( [Math.min(startXPoint, endXPoint), Math.min(startYPoint, endYPoint), Math.max(startXPoint, endXPoint), Math.max(startYPoint, endYPoint)], { - fontSize: polygon.fontSize, + fontSize: roof.fontSize, stroke: 'blue', strokeWidth: 1, name: 'ridgeLine', + attributes: { roofId: roof.id }, }, ) - polygon.canvas.add(ridge) - polygon.ridges.push(ridge) - polygon.innerLines.push(ridge) + canvas.add(ridge) + roof.ridges.push(ridge) + roof.innerLines.push(ridge) + console.log('currentRoof', currentRoof.x1, currentRoof.y1) + console.log('startXPoint', startXPoint, 'startYPoint', startYPoint, 'endXPoint', endXPoint, 'endYPoint', endYPoint) + + const distance = (x1, y1, x2, y2) => Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) + const dist1 = distance(startXPoint, startYPoint, currentRoof.x1, currentRoof.y1) + const dist2 = distance(endXPoint, endYPoint, currentRoof.x1, currentRoof.y1) + + currentRoof.attributes.ridgeCoordinate = { x1: dist1 < dist2 ? startXPoint : endXPoint, y1: dist1 < dist2 ? startYPoint : endYPoint } } } }) //겹쳐지는 마루는 하나로 합침 - polygon.ridges.forEach((ridge, index) => { - polygon.ridges + roof.ridges.forEach((ridge, index) => { + roof.ridges .filter((ridge2) => !(ridge.x1 === ridge2.x1 && ridge.y1 === ridge2.y1 && ridge.x2 === ridge2.x2 && ridge.y2 === ridge2.y2)) .forEach((ridge2) => { let overlap = segmentsOverlap(ridge, ridge2) @@ -1503,22 +1515,21 @@ const drawRidgeRoof = (polygon, chon) => { let y1 = Math.min(ridge.y1, ridge2.y1, ridge.y2, ridge2.y2) let y2 = Math.max(ridge.y1, ridge2.y1, ridge.y2, ridge2.y2) const newRidge = new QLine([x1, y1, x2, y2], { - fontSize: polygon.fontSize, + fontSize: roof.fontSize, stroke: 'blue', strokeWidth: 1, + name: 'ridgeLine', + attributes: { roofId: roof.id }, }) - polygon.canvas.remove(ridge) - polygon.canvas.remove(ridge2) - polygon.ridges = polygon.ridges.filter((r) => !(ridge.x1 === r.x1 && ridge.y1 === r.y1 && ridge.x2 === r.x2 && ridge.y2 === r.y2)) - polygon.ridges = polygon.ridges.filter((r) => !(ridge2.x1 === r.x1 && ridge2.y1 === r.y1 && ridge2.x2 === r.x2 && ridge2.y2 === r.y2)) - polygon.innerLines = polygon.innerLines.filter((r) => !(ridge.x1 === r.x1 && ridge.y1 === r.y1 && ridge.x2 === r.x2 && ridge.y2 === r.y2)) - polygon.innerLines = polygon.innerLines.filter( - (r) => !(ridge2.x1 === r.x1 && ridge2.y1 === r.y1 && ridge2.x2 === r.x2 && ridge2.y2 === r.y2), - ) - - polygon.canvas.add(newRidge) - polygon.ridges.push(newRidge) - polygon.innerLines.push(newRidge) + roof.canvas.remove(ridge) + roof.canvas.remove(ridge2) + roof.ridges = roof.ridges.filter((r) => !(ridge.x1 === r.x1 && ridge.y1 === r.y1 && ridge.x2 === r.x2 && ridge.y2 === r.y2)) + roof.ridges = roof.ridges.filter((r) => !(ridge2.x1 === r.x1 && ridge2.y1 === r.y1 && ridge2.x2 === r.x2 && ridge2.y2 === r.y2)) + roof.innerLines = roof.innerLines.filter((r) => !(ridge.x1 === r.x1 && ridge.y1 === r.y1 && ridge.x2 === r.x2 && ridge.y2 === r.y2)) + roof.innerLines = roof.innerLines.filter((r) => !(ridge2.x1 === r.x1 && ridge2.y1 === r.y1 && ridge2.x2 === r.x2 && ridge2.y2 === r.y2)) + canvas.add(newRidge) + roof.ridges.push(newRidge) + roof.innerLines.push(newRidge) } }) }) @@ -1565,720 +1576,151 @@ const segmentsOverlap = (line1, line2) => { return false } -const drawHips = (polygon) => { - /* - 마루에서 시작되는 hip을 먼저 그립니다. - */ - polygon.ridges.forEach((ridge) => { - let leftTop, rightTop, leftBottom, rightBottom - if (ridge.y1 === ridge.y2) { - //왼쪽 좌표 기준 225, 315도 방향 라인확인 - leftTop = polygon.lines - .filter((line) => line.x1 < ridge.x1 && line.y1 < ridge.y1 && Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(ridge.x1 - current.x1) < Math.min(ridge.x1 - prev.x1) ? current : prev - } - }, undefined) +/** + * 추녀마루를 그린다. + * @param roof + * @param canvas + */ +const drawHips = (roof, canvas) => { + console.log('drawHips roofs : ', roof) - leftBottom = polygon.lines - .filter((line) => line.x1 < ridge.x1 && line.y1 > ridge.y1 && Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(ridge.x1 - current.x1) < Math.min(ridge.x1 - prev.x1) ? current : prev - } - }, undefined) + const roofLines = roof.lines + const ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roof.id) - //오른쪽 좌표 기준 45, 135도 방향 라인확인 - rightTop = polygon.lines - .filter((line) => line.x1 > ridge.x2 && line.y1 < ridge.y2 && Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(current.x1 - ridge.x2) < Math.min(prev.x1 - ridge.x2) ? current : prev - } - }, undefined) - - rightBottom = polygon.lines - .filter((line) => line.x1 > ridge.x2 && line.y1 > ridge.y2 && Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(current.x1 - ridge.x2) < Math.min(prev.x1 - ridge.x2) ? current : prev - } - }, undefined) - if (leftTop !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 < ridge.x1 && - r.y1 < ridge.y1 && - (r.y1 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x1 - rightTop.x1) * (ridge.y1 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 < ridge.x1 && - r.y2 < ridge.y1 && - (r.y2 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x2 - rightTop.x1) * (ridge.y1 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([leftTop.x1, leftTop.y1, ridge.x1, ridge.y1], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (leftBottom !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 < ridge.x1 && - r.y1 > ridge.y1 && - (r.y1 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x1 - rightTop.x1) * (ridge.y1 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 < ridge.x1 && - r.y2 > ridge.y1 && - (r.y2 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x2 - rightTop.x1) * (ridge.y1 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([leftBottom.x1, leftBottom.y1, ridge.x1, ridge.y1], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (rightTop !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 > ridge.x2 && - r.y1 < ridge.y2 && - (r.y1 - rightTop.y1) * (ridge.x2 - rightTop.x1) === (r.x1 - rightTop.x1) * (ridge.y2 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 > ridge.x2 && - r.y2 < ridge.y2 && - (r.y2 - rightTop.y1) * (ridge.x2 - rightTop.x1) === (r.x2 - rightTop.x1) * (ridge.y2 - rightTop.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([rightTop.x1, rightTop.y1, ridge.x2, ridge.y2], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (rightBottom !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 > ridge.x2 && - r.y1 > ridge.y2 && - (r.y1 - rightBottom.y1) * (ridge.x2 - rightBottom.x1) === (r.x1 - rightBottom.x1) * (ridge.y2 - rightBottom.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 > ridge.x2 && - r.y2 > ridge.y2 && - (r.y2 - rightBottom.y1) * (ridge.x2 - rightBottom.x1) === (r.x2 - rightBottom.x1) * (ridge.y2 - rightBottom.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([rightBottom.x1, rightBottom.y1, ridge.x2, ridge.y2], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - } - if (ridge.x1 === ridge.x2) { - //위쪽 좌표 기준 45, 315도 방향 라인확인 - leftTop = polygon.lines - .filter((line) => line.x1 < ridge.x1 && line.y1 < ridge.y1 && Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(ridge.y1 - current.y1) < Math.min(ridge.y1 - prev.y1) ? current : prev - } - }, undefined) - - rightTop = polygon.lines - .filter((line) => line.x1 > ridge.x1 && line.y1 < ridge.y1 && Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(ridge.y1 - current.y1) < Math.min(ridge.y1 - prev.y1) ? current : prev - } - }, undefined) - - //아래쪽 좌표 기준 135, 225도 방향 라인확인 - leftBottom = polygon.lines - .filter((line) => line.x1 < ridge.x2 && line.y1 > ridge.y2 && Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(current.y1 - ridge.y2) < Math.min(prev.y1 - ridge.y2) ? current : prev - } - }, undefined) - - rightBottom = polygon.lines - .filter((line) => line.x1 > ridge.x2 && line.y1 > ridge.y2 && Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2)) - .reduce((prev, current) => { - if (prev === undefined) { - return current - } else { - return Math.min(current.y1 - ridge.y2) < Math.min(prev.y1 - ridge.y2) ? current : prev - } - }, undefined) - - if (leftTop !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if (r.x1 < ridge.x1 && r.y1 < ridge.y1) { - if ((r.y1 - leftTop.y1) * (ridge.x1 - leftTop.x1) === (r.x1 - leftTop.x1) * (ridge.y1 - leftTop.y1)) { - isRidgePointOnLine = true - } - } - if (r.x2 < ridge.x1 && r.y2 < ridge.y1) { - if ((r.y2 - leftTop.y1) * (ridge.x1 - leftTop.x1) === (r.x2 - leftTop.x1) * (ridge.y1 - leftTop.y1)) { - isRidgePointOnLine = true - } - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([leftTop.x1, leftTop.y1, ridge.x1, ridge.y1], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (rightTop !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if (r.x1 > ridge.x1 && r.y1 < ridge.y1) { - if ((r.y1 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x1 - rightTop.x1) * (ridge.y1 - rightTop.y1)) { - isRidgePointOnLine = true - } - } - if (r.x2 > ridge.x1 && r.y2 < ridge.y1) { - if ((r.y2 - rightTop.y1) * (ridge.x1 - rightTop.x1) === (r.x2 - rightTop.x1) * (ridge.y1 - rightTop.y1)) { - isRidgePointOnLine = true - } - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([rightTop.x1, rightTop.y1, ridge.x1, ridge.y1], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (leftBottom !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 < ridge.x2 && - r.y1 > ridge.y2 && - (r.y1 - leftBottom.y1) * (ridge.x2 - leftBottom.x1) === (r.x1 - leftBottom.x1) * (ridge.y2 - leftBottom.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 < ridge.x2 && - r.y2 > ridge.y2 && - (r.y2 - leftBottom.y1) * (ridge.x2 - leftBottom.x1) === (r.x2 - leftBottom.x1) * (ridge.y2 - leftBottom.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([leftBottom.x1, leftBottom.y1, ridge.x2, ridge.y2], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - if (rightBottom !== undefined) { - let isRidgePointOnLine = false - polygon.ridges.forEach((r) => { - if ( - r.x1 < ridge.x2 && - r.y1 > ridge.y2 && - (r.y1 - rightBottom.y1) * (ridge.x2 - rightBottom.x1) === (r.x1 - rightBottom.x1) * (ridge.y2 - rightBottom.y1) - ) { - isRidgePointOnLine = true - } - if ( - r.x2 < ridge.x2 && - r.y2 > ridge.y2 && - (r.y2 - rightBottom.y1) * (ridge.x2 - rightBottom.x1) === (r.x2 - rightBottom.x1) * (ridge.y2 - rightBottom.y1) - ) { - isRidgePointOnLine = true - } - }) - if (!isRidgePointOnLine) { - const hip = new QLine([rightBottom.x1, rightBottom.y1, ridge.x2, ridge.y2], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - } - }) - - // 가장 가까운 마루를 확인하여 그릴 수 있는 라인이 존재하면 먼저 그린다. - let prevLine, currentLine, nextLine - polygon.lines.forEach((value, index) => { - if (index === 0) { - prevLine = polygon.lines[polygon.lines.length - 1] - } else { - prevLine = polygon.lines[index - 1] - } - currentLine = polygon.lines[index] - - if (index === polygon.lines.length - 1) { - nextLine = polygon.lines[0] - } else if (index === polygon.lines.length) { - nextLine = polygon.lines[1] - } else { - nextLine = polygon.lines[index + 1] - } - - if (!isAlreadyHip(polygon, currentLine)) { - let dVector = getDirectionForDegree(prevLine, currentLine) - let nearRidge - - switch (dVector) { - case 45: - nearRidge = polygon.ridges - .filter( - (ridge) => - ((currentLine.x1 < ridge.x1 && currentLine.y1 > ridge.y1) || (currentLine.x1 < ridge.x2 && currentLine.y1 > ridge.y2)) && - (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1) || - Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)), - ) - .reduce((prev, current) => { - if (prev !== undefined) { - if ( - currentLine.x1 < current.x1 && - currentLine.y1 > current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x1, - y: current.y1, - } - : prev - } else if ( - currentLine.x1 < current.x2 && - currentLine.y1 > current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return Math.min(Math.abs(current.x2 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x2, - y: current.y2, - } - : prev - } else { - return prev - } - } else { - if ( - currentLine.x1 < current.x1 && - currentLine.y1 > current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return { x: current.x1, y: current.y1 } - } else if ( - currentLine.x1 < current.x2 && - currentLine.y1 > current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return { x: current.x2, y: current.y2 } - } else { - return undefined - } - } - }, undefined) - break - case 135: - nearRidge = polygon.ridges - .filter( - (ridge) => - ((currentLine.x1 < ridge.x1 && currentLine.y1 < ridge.y1) || (currentLine.x1 < ridge.x2 && currentLine.y1 < ridge.y2)) && - (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1) || - Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)), - ) - .reduce((prev, current) => { - if (prev !== undefined) { - if ( - currentLine.x1 < current.x1 && - currentLine.y1 < current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x1, - y: current.y1, - } - : prev - } else if ( - currentLine.x1 < current.x2 && - currentLine.y1 < current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x2, - y: current.y2, - } - : prev - } else { - return prev - } - } else { - if ( - currentLine.x1 < current.x1 && - currentLine.y1 < current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return { x: current.x1, y: current.y1 } - } else if ( - currentLine.x1 < current.x2 && - currentLine.y1 < current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return { x: current.x2, y: current.y2 } - } else { - return undefined - } - } - }, undefined) - break - case 225: - nearRidge = polygon.ridges - .filter( - (ridge) => - ((currentLine.x1 > ridge.x1 && currentLine.y1 < ridge.y1) || (currentLine.x1 > ridge.x2 && currentLine.y1 < ridge.y2)) && - (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1) || - Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)), - ) - .reduce((prev, current) => { - if (prev !== undefined) { - if ( - currentLine.x1 > current.x1 && - currentLine.y1 < current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x1, - y: current.y1, - } - : prev - } else if ( - currentLine.x1 > current.x2 && - currentLine.y1 < current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x2, - y: current.y2, - } - : prev - } else { - return prev - } - } else { - if ( - currentLine.x1 > current.x1 && - currentLine.y1 < current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return { x: current.x1, y: current.y1 } - } else if ( - currentLine.x1 > current.x2 && - currentLine.y1 < current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return { x: current.x2, y: current.y2 } - } else { - return undefined - } - } - }, undefined) - break - case 315: - nearRidge = polygon.ridges - .filter( - (ridge) => - ((currentLine.x1 > ridge.x1 && currentLine.y1 > ridge.y1) || (currentLine.x1 > ridge.x2 && currentLine.y1 > ridge.y2)) && - (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1) || - Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)), - ) - .reduce((prev, current) => { - if (prev !== undefined) { - if ( - currentLine.x1 > current.x1 && - currentLine.y1 > current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x1, - y: current.y1, - } - : prev - } else if ( - currentLine.x1 > current.x2 && - currentLine.y1 > current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x - currentLine.x1)) - ? { - x: current.x2, - y: current.y2, - } - : prev - } else { - return prev - } - } else { - if ( - currentLine.x1 > current.x1 && - currentLine.y1 > current.y1 && - Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1) - ) { - return { x: current.x1, y: current.y1 } - } else if ( - currentLine.x1 > current.x2 && - currentLine.y1 > current.y2 && - Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2) - ) { - return { x: current.x2, y: current.y2 } - } else { - return undefined - } - } - }, undefined) - break - } - - if (nearRidge !== undefined) { - let endXPoint, endYPoint - let minX, maxX, minY, maxY - - switch (dVector) { - case 45: - endXPoint = nearRidge.x - endYPoint = nearRidge.y - minX = Math.min(currentLine.x1, nearRidge.x) - minY = Math.min(currentLine.y1, nearRidge.y) - maxX = Math.max(currentLine.x1, nearRidge.x) - maxY = Math.max(currentLine.y1, nearRidge.y) - break - case 135: - endXPoint = nearRidge.x - endYPoint = nearRidge.y - minX = Math.min(currentLine.x1, nearRidge.x) - minY = Math.min(currentLine.y1, nearRidge.y) - maxX = Math.max(currentLine.x1, nearRidge.x) - maxY = Math.max(currentLine.y1, nearRidge.y) - break - case 225: - endXPoint = nearRidge.x - endYPoint = nearRidge.y - minX = Math.min(currentLine.x1, nearRidge.x) - minY = Math.min(currentLine.y1, nearRidge.y) - maxX = Math.max(currentLine.x1, nearRidge.x) - maxY = Math.max(currentLine.y1, nearRidge.y) - break - case 315: - endXPoint = nearRidge.x - endYPoint = nearRidge.y - minX = Math.min(currentLine.x1, nearRidge.x) - minY = Math.min(currentLine.y1, nearRidge.y) - maxX = Math.max(currentLine.x1, nearRidge.x) - maxY = Math.max(currentLine.y1, nearRidge.y) - break - } - - let lineCoordinate = [ - { x: minX, y: minY }, - { x: minX, y: maxY }, - { x: maxX, y: maxY }, - { x: maxX, y: minY }, - ] - - let innerPoint = polygon.lines.filter((line) => { - if (getPointInPolygon(lineCoordinate, { x: line.x1, y: line.y1 })) { - return line - } - }) - - if (innerPoint <= 0) { - const hip = new QLine([currentLine.x1, currentLine.y1, endXPoint, endYPoint], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - name: 'hipLine', - }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) - } - } - } - }) - - // 마루와 연결되지 않은 hip을 그린다. - /*polygon.lines.forEach((line, index) => { - if (!isAlreadyHip(polygon, line)) { - console.log(' 확인 : ', line) - let prevLine, currentLine, nextLine - if (index === 0) { - prevLine = polygon.lines[polygon.lines.length - 1] - } else { - prevLine = polygon.lines[index - 1] - } - currentLine = polygon.lines[index] - - if (index === polygon.lines.length - 1) { - nextLine = polygon.lines[0] - } else if (index === polygon.lines.length) { - nextLine = polygon.lines[1] - } else { - nextLine = polygon.lines[index + 1] - } - - let endXPoint, endYPoint - let dVector = getDirectionForDegree(prevLine, currentLine) - - let minX = Math.min(currentLine.x1, currentLine.x2, prevLine.x1, nextLine.x2) - let maxX = Math.max(currentLine.x1, currentLine.x2, prevLine.x1, nextLine.x2) - let minY = Math.min(currentLine.y1, currentLine.y2, prevLine.y1, nextLine.y2) - let maxY = Math.max(currentLine.y1, currentLine.y2, prevLine.y1, nextLine.y2) - - let lineCoordinate = [ - { x: minX, y: minY }, - { x: minX, y: maxY }, - { x: maxX, y: maxY }, - { x: maxX, y: minY }, - ] - - let acrossLine = getAcrossLine(polygon, currentLine, dVector) - let hypotenuse, adjacent - console.log(acrossLine) - - if (getLineDirection(prevLine) === getLineDirection(nextLine)) { - hypotenuse = Math.round(getRoofHypotenuse(Math.abs(currentLine.x1 - acrossLine.x1) / 2)) - } else { - hypotenuse = Math.min( - Math.round(getRoofHypotenuse(currentLine.length / 2)), - Math.round(getRoofHypotenuse(Math.abs(currentLine.x1 - acrossLine.x1) / 2)), - ) - } - adjacent = getAdjacent(hypotenuse) - - switch (dVector) { - case 45: - endXPoint = currentLine.x1 + adjacent - endYPoint = currentLine.y1 - adjacent - break - case 135: - endXPoint = currentLine.x1 + adjacent - endYPoint = currentLine.y1 + adjacent - break - case 225: - endXPoint = currentLine.x1 - adjacent - endYPoint = currentLine.y1 + adjacent - break - case 315: - endXPoint = currentLine.x1 - adjacent - endYPoint = currentLine.y1 - adjacent - break - } - - const hip = new QLine([currentLine.x1, currentLine.y1, endXPoint, endYPoint], { - fontSize: polygon.fontSize, + //마루에서 시작되는 hip을 먼저 그립니다. + roofLines + .filter((roof) => roof.attributes.type === LINE_TYPE.WALLLINE.EAVES && roof.attributes.ridgeCoordinate !== undefined) + .forEach((currentRoof, index) => { + const ridgeCoordinate = currentRoof.attributes.ridgeCoordinate + const hip1 = new QLine([currentRoof.x1, currentRoof.y1, ridgeCoordinate.x1, ridgeCoordinate.y1], { + fontSize: roof.fontSize, stroke: 'red', strokeWidth: 1, name: 'hipLine', + attributes: { roofId: roof.id, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, }) - polygon.canvas.add(hip) - polygon.hips.push(hip) - polygon.innerLines.push(hip) + canvas.add(hip1) + roof.hips.push(hip1) + roof.innerLines.push(hip1) + + const hip2 = new QLine([currentRoof.x2, currentRoof.y2, ridgeCoordinate.x1, ridgeCoordinate.y1], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roof.id, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas.add(hip2) + roof.hips.push(hip2) + roof.innerLines.push(hip2) + }) + + const hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roof.id) + + //마루에서 시작되지 않는 hip을 그립니다. + roofLines + .filter((roof) => { + let isHip = false + if (hipLines.some((hip) => hip.x1 === roof.x1 && hip.y1 === roof.y1)) { + isHip = true + } + return !isHip + }) + .forEach((currentRoof) => { + let prevRoof + roofLines.forEach((roof, index) => { + if (roof === currentRoof) { + prevRoof = index === 0 ? roofLines[roofLines.length - 1] : roofLines[index - 1] + } + }) + + // if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.EAVES && prevRoof.attributes.type === LINE_TYPE.WALLLINE.EAVES) { + let ridgePoints = [] + ridgeLines.forEach((ridge) => { + const deltaX1 = ridge.x1 - currentRoof.x1 + const deltaY1 = ridge.y1 - currentRoof.y1 + const deltaX2 = ridge.x2 - currentRoof.x1 + const deltaY2 = ridge.y2 - currentRoof.y1 + + if (Math.abs(deltaY1 / deltaX1) === 1) { + ridgePoints.push({ x: ridge.x1, y: ridge.y1 }) + } + if (Math.abs(deltaY2 / deltaX2) === 1) { + ridgePoints.push({ x: ridge.x2, y: ridge.y2 }) + } + }) + + ridgePoints = ridgePoints.reduce((prev, current) => { + if (prev !== undefined) { + const deltaPrevX = Math.abs(prev.x - currentRoof.x1) + const deltaPrevY = Math.abs(prev.y - currentRoof.y1) + const deltaCurrentX = Math.abs(current.x - currentRoof.x1) + const deltaCurrentY = Math.abs(current.y - currentRoof.y1) + if (deltaPrevX < deltaCurrentX && deltaPrevY < deltaCurrentY) { + return prev + } else { + return current + } + } else { + return current + } + }, undefined) + + if (ridgePoints !== undefined) { + const hip = new QLine([currentRoof.x1, currentRoof.y1, ridgePoints.x, ridgePoints.y], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roof.id, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas.add(hip) + roof.hips.push(hip) + roof.innerLines.push(hip) + } + }) +} + +/** + * 라인 사이가 지붕골 인지 확인. + * @param polygon + * @param line1 + * @param line2 + * @returns {boolean} + */ +const checkValley = (polygon, line1, line2) => { + let points = [ + { x: line1.x1, y: line1.y1 }, + { x: line1.x2, y: line1.y2 }, + { x: line2.x1, y: line2.y1 }, + { x: line2.x2, y: line2.y2 }, + ] + + const uniquePointsMap = new Map() + points.forEach((point) => { + const key = `${point.x},${point.y}` + if (!uniquePointsMap.has(key)) { + uniquePointsMap.set(key, point) } - })*/ + }) + points = Array.from(uniquePointsMap.values()) + + const centroidX = points.reduce((acc, point) => acc + point.x, 0) / points.length + const centroidY = points.reduce((acc, point) => acc + point.y, 0) / points.length + + let isValley = false + const pPoints = polygon.points + pPoints.forEach((point, index) => { + let j = (index + 1) % pPoints.length + let xi = pPoints[index].x + polygon.left, + yi = pPoints[index].y + polygon.top + let xj = pPoints[j].x + polygon.left, + yj = pPoints[j].y + polygon.top + + let intersect = yi > centroidY !== yj > centroidY && centroidX < ((xj - xi) * (centroidY - yi)) / (yj - yi) + xi + if (intersect) isValley = !isValley + }) + return isValley } const getPointInPolygon = (polygon, point, isInclude = false) => { @@ -2564,6 +2006,7 @@ const connectLinePoint = (polygon) => { stroke: 'blue', strokeWidth: 1, name: 'ridgeLine', + attributes: { roofId: polygon.id }, }) if (polygon.ridges.filter((r) => newRidge.x1 === r.x1 && newRidge.y1 === r.y1 && newRidge.x2 === r.x2 && newRidge.y2 === r.y2).length === 0) { polygon.canvas.remove(ridge) @@ -2586,6 +2029,99 @@ const connectLinePoint = (polygon) => { console.log('polygon : ', polygon) } +const modifyRidge = (roof, canvas) => { + const roofLines = roof.lines + const ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roof.id) + const hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roof.id) + + ridgeLines.forEach((ridge) => { + let ridgeHip1 = hipLines.filter((hip) => hip.x2 === ridge.x1 && hip.y2 === ridge.y1) + let ridgeHip2 = hipLines.filter((hip) => hip.x2 === ridge.x2 && hip.y2 === ridge.y2) + if (ridgeHip1.length >= 2) { + let currentRoof = roof.lines + .filter((roofLine) => roofLine.attributes !== undefined && roofLine.attributes.ridgeCoordinate !== undefined) + .find((roofLine) => roofLine.attributes.ridgeCoordinate.x1 === ridge.x1 && roofLine.attributes.ridgeCoordinate.y1 === ridge.y1) + console.log('1 currentRoof : ', currentRoof) + if (currentRoof === undefined) { + currentRoof = roof.lines.find( + (roofLine) => + (roofLine.x1 === ridgeHip1[0].x1 && + roofLine.y1 === ridgeHip1[0].y1 && + roofLine.x2 === ridgeHip1[1].x1 && + roofLine.y2 === ridgeHip1[1].y1) || + (roofLine.x1 === ridgeHip1[1].x1 && + roofLine.y1 === ridgeHip1[1].y1 && + roofLine.x2 === ridgeHip1[0].x1 && + roofLine.y2 === ridgeHip1[0].y1), + ) + if (currentRoof !== undefined) { + currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } + } + } + console.log('2 currentRoof : ', currentRoof) + if (currentRoof !== undefined) { + switch (currentRoof.attributes.type) { + case LINE_TYPE.WALLLINE.EAVES: + break + case LINE_TYPE.WALLLINE.GABLE: + changeGableRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.HIPANDGABLE: + changeHipAndGableRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.JERKINHEAD: + changeJerkInHeadRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.WALL: + changeWallRoof(roof.id, currentRoof, canvas) + break + } + } + } + if (ridgeHip2.length >= 2) { + let currentRoof = roof.lines + .filter((roofLine) => roofLine.attributes !== undefined && roofLine.attributes.ridgeCoordinate !== undefined) + .find((roofLine) => roofLine.attributes.ridgeCoordinate.x1 === ridge.x2 && roofLine.attributes.ridgeCoordinate.y1 === ridge.y2) + console.log('3 currentRoof : ', currentRoof) + if (currentRoof === undefined) { + currentRoof = roof.lines.find( + (roofLine) => + (roofLine.x1 === ridgeHip2[0].x1 && + roofLine.y1 === ridgeHip2[0].y1 && + roofLine.x2 === ridgeHip2[1].x1 && + roofLine.y2 === ridgeHip2[1].y1) || + (roofLine.x1 === ridgeHip2[1].x1 && + roofLine.y1 === ridgeHip2[1].y1 && + roofLine.x2 === ridgeHip2[0].x1 && + roofLine.y2 === ridgeHip2[0].y1), + ) + if (currentRoof !== undefined) { + currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } + } + } + console.log('4 currentRoof : ', currentRoof) + if (currentRoof !== undefined) { + switch (currentRoof.attributes.type) { + case LINE_TYPE.WALLLINE.EAVES: + break + case LINE_TYPE.WALLLINE.GABLE: + changeGableRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.HIPANDGABLE: + changeHipAndGableRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.JERKINHEAD: + changeJerkInHeadRoof(roof.id, currentRoof, canvas) + break + case LINE_TYPE.WALLLINE.WALL: + changeWallRoof(roof.id, currentRoof, canvas) + break + } + } + } + }) +} + /* 최대 생성 마루 갯수 */ @@ -2593,74 +2129,405 @@ const getMaxRidge = (length) => { return (length - 4) / 2 + 1 } -/* - 두 라인의 사잇각 계산 +/** + * 처마지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas */ -const getDirectionForDegree = (line1, line2) => { - let degree = getLineDirection(line1) + getLineDirection(line2) - let vector +export const changeEavesRoof = (roofId, currentRoof, canvas) => {} - switch (degree) { - case 'rb': - vector = 45 - break - case 'br': - vector = 45 - break - case 'lb': - vector = 135 - break - case 'bl': - vector = 135 - break - case 'lt': - vector = 225 - break - case 'tl': - vector = 225 - break - case 'rt': - vector = 315 - break - case 'tr': - vector = 315 - break +/** + * 박공지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas + */ +export const changeGableRoof = (roofId, currentRoof, canvas) => { + if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.GABLE) { + const roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) + let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) + let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) + + ridgeLines = ridgeLines.filter( + (ridge) => + (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || + (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), + ) + hipLines = hipLines.filter( + (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), + ) + let midX = (currentRoof.x1 + currentRoof.x2) / 2 + let midY = (currentRoof.y1 + currentRoof.y2) / 2 + if (ridgeLines !== undefined && ridgeLines.length > 0) { + const ridge = ridgeLines[0] + if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { + midX = ridge.x1 + (ridge.x1 - midX) + midY = ridge.y1 - (ridge.y1 - midY) + ridge.set({ + x1: midX, + y1: midY, + x2: ridge.x2, + y2: ridge.y2, + }) + } + if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { + midX = ridge.x2 + (ridge.x2 - midX) + midY = ridge.y2 - (ridge.y2 - midY) + ridge.set({ + x1: ridge.x1, + y1: ridge.y1, + x2: midX, + y2: midY, + }) + } + } + + if (hipLines !== undefined && hipLines.length > 0) { + hipLines.forEach((hip) => + hip.set({ + x1: hip.x1, + y1: hip.y1, + x2: midX, + y2: midY, + }), + ) + } else { + let hip1 = new QLine([currentRoof.x1, currentRoof.y1, midX, midY], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roofId, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas?.add(hip1) + roof.hips.push(hip1) + roof.innerLines.push(hip1) + + let hip2 = new QLine([currentRoof.x2, currentRoof.y2, midX, midY], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roofId, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas?.add(hip2) + roof.hips.push(hip2) + roof.innerLines.push(hip2) + } } - - return vector } -/* - 현재 라인의 방향을 계산 +/** + * 팔작지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas */ -const getLineDirection = (line) => { - let x1, x2, y1, y2, xp, yp - x1 = Math.round(line.x1) - x2 = Math.round(line.x2) - y1 = Math.round(line.y1) - y2 = Math.round(line.y2) +export const changeHipAndGableRoof = (roofId, currentRoof, canvas) => { + if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + const roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) + let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) + let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) - xp = x1 - x2 - yp = y1 - y2 + ridgeLines = ridgeLines.filter( + (ridge) => + (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || + (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), + ) + hipLines = hipLines.filter( + (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), + ) - if (xp === 0) { - if (yp < 0) { - return 'b' - } else { - return 't' + if (ridgeLines.length > 0) { + const ridge = ridgeLines[0] + let midX = (currentRoof.x1 + currentRoof.x2) / 2 + let midY = (currentRoof.y1 + currentRoof.y2) / 2 + let xWidth = currentRoof.attributes.width + let yWidth = currentRoof.attributes.width + let diffX = 0 + let diffY = 0 + + if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { + diffX = ridge.x1 - midX + diffY = ridge.y1 - midY + midX = ridge.x1 - diffX + midY = ridge.y1 - diffY + xWidth = diffX === 0 ? 0 : Math.sign(diffX) * xWidth + yWidth = diffY === 0 ? 0 : Math.sign(diffY) * yWidth + ridge.set({ + x1: midX + xWidth, + y1: midY + yWidth, + x2: ridge.x2, + y2: ridge.y2, + }) + + currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } + } + if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { + diffX = ridge.x2 - midX + diffY = ridge.y2 - midY + midX = ridge.x2 - diffX + midY = ridge.y2 - diffY + xWidth = diffX === 0 ? 0 : Math.sign(diffX) * xWidth + yWidth = diffY === 0 ? 0 : Math.sign(diffY) * yWidth + ridge.set({ + x1: ridge.x1, + y1: ridge.y1, + x2: midX + xWidth, + y2: midY + yWidth, + }) + + currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } + } + + if (hipLines.length > 0) { + hipLines.forEach((hip) => { + const singX = Math.sign(hip.x1 - currentRoof.attributes.ridgeCoordinate.x1) + const singY = Math.sign(hip.y1 - currentRoof.attributes.ridgeCoordinate.y1) + const alpha = diffX === 0 ? 0 : Math.abs(diffX) - currentRoof.attributes.width + const beta = diffY === 0 ? 0 : Math.abs(diffY) - currentRoof.attributes.width + const hypotenuse = Math.sqrt(Math.pow(alpha, 2) + Math.pow(beta, 2)) + + hip.set({ + x1: hip.x1, + y1: hip.y1, + x2: hip.x2 + singX * hypotenuse, + y2: hip.y2 + singY * hypotenuse, + }) + }) + } + + if (ridgeLines.length > 0 && hipLines.length > 0) { + hipLines.forEach((hip) => { + const hipLine = new QLine([hip.x2, hip.y2, currentRoof.attributes.ridgeCoordinate.x1, currentRoof.attributes.ridgeCoordinate.y1], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'gableLine', + }) + canvas?.add(hipLine) + roof.innerLines.push(hipLine) + }) + } } } - if (yp === 0) { - if (xp < 0) { - return 'r' - } else { - return 'l' +} + +/** + * 반절처 지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas + */ +export const changeJerkInHeadRoof = (roofId, currentRoof, canvas) => { + if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + console.log('roofId : ', roofId) + console.log('currentRoof : ', currentRoof) + const roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) + let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) + let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) + + ridgeLines = ridgeLines.filter( + (ridge) => + (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || + (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), + ) + hipLines = hipLines.filter( + (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), + ) + + console.log('ridgeLines : ', ridgeLines) + console.log('hipLines : ', hipLines) + + if (ridgeLines.length > 0) { + const ridge = ridgeLines[0] + let midX = (currentRoof.x1 + currentRoof.x2) / 2 + let midY = (currentRoof.y1 + currentRoof.y2) / 2 + let xWidth = currentRoof.attributes.width + let yWidth = currentRoof.attributes.width + if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { + const diffX = ridge.x1 - midX + const diffY = ridge.y1 - midY + midX = ridge.x1 - diffX + midY = ridge.y1 - diffY + xWidth = diffX === 0 ? 0 : (Math.sign(diffX) * xWidth) / 2 + yWidth = diffY === 0 ? 0 : (Math.sign(diffY) * yWidth) / 2 + ridge.set({ + x1: midX + xWidth, + y1: midY + yWidth, + x2: ridge.x2, + y2: ridge.y2, + }) + + currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } + } + if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { + const diffX = ridge.x2 - midX + const diffY = ridge.y2 - midY + midX = ridge.x2 - diffX + midY = ridge.y2 - diffY + xWidth = diffX === 0 ? 0 : (Math.sign(diffX) * xWidth) / 2 + yWidth = diffY === 0 ? 0 : (Math.sign(diffY) * yWidth) / 2 + ridge.set({ + x1: ridge.x1, + y1: ridge.y1, + x2: midX + xWidth, + y2: midY + yWidth, + }) + + currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } + } } + + if (hipLines.length > 0) { + const midX = (currentRoof.x1 + currentRoof.x2) / 2 + const midY = (currentRoof.y1 + currentRoof.y2) / 2 + + hipLines.forEach((hip) => { + const singX = Math.sign(hip.x1 - midX) + const singY = Math.sign(hip.y1 - midY) + const xWidth = singX === 0 ? 0 : (singX * currentRoof.attributes.width) / 2 + const yWidth = singY === 0 ? 0 : (singY * currentRoof.attributes.width) / 2 + + hip.set({ + x1: hip.x1, + y1: hip.y1, + x2: midX + xWidth, + y2: midY + yWidth, + }) + }) + } + + if (ridgeLines.length > 0 && hipLines.length > 0) { + console.log('currentRoof : ', currentRoof.attributes.ridgeCoordinate) + hipLines.forEach((hip) => { + const jerkinHeadLine = new QLine([hip.x2, hip.y2, currentRoof.attributes.ridgeCoordinate.x1, currentRoof.attributes.ridgeCoordinate.y1], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'jerkinHeadLine', + }) + canvas?.add(jerkinHeadLine) + roof.innerLines.push(jerkinHeadLine) + }) + + if (hipLines.length > 1) { + const jerkinHeadLine = new QLine([hipLines[0].x2, hipLines[0].y2, hipLines[1].x2, hipLines[1].y2], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'jerkinHeadLine', + }) + canvas?.add(jerkinHeadLine) + roof.innerLines.push(jerkinHeadLine) + } + } + } +} + +const changeWallRoof = (roofId, currentRoof, canvas) => { + console.log('roofId : ', roofId) + let roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) + const roofLines = roof.lines + let prevRoof, nextRoof + roofLines.forEach((r, index) => { + if (r.id === currentRoof.id) { + currentRoof = r + prevRoof = roofLines[index === 0 ? roofLines.length - 1 : index - 1] + nextRoof = roofLines[index === roofLines.length - 1 ? 0 : index + 1] + } + }) + + const wall = canvas?.getObjects().find((object) => object.name === 'wall' && object.attributes.roofId === roofId) + let wallLine = wall.lines.filter((w) => w.id === currentRoof.attributes.wallLine) + let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) + let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) + + ridgeLines = ridgeLines.filter( + (ridge) => + (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || + (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1), + ) + hipLines = hipLines.filter( + (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), + ) + + const wallMidX = (wallLine[0].x1 + wallLine[0].x2) / 2 + const wallMidY = (wallLine[0].y1 + wallLine[0].y2) / 2 + const roofMidX = (currentRoof.x1 + currentRoof.x2) / 2 + const roofMidY = (currentRoof.y1 + currentRoof.y2) / 2 + + const alpha = wallMidX - roofMidX === 0 ? 0 : wallMidX - roofMidX + const beta = wallMidY - roofMidY === 0 ? 0 : wallMidY - roofMidY + + currentRoof.set({ + x1: currentRoof.x1 + alpha, + y1: currentRoof.y1 + beta, + x2: currentRoof.x2 + alpha, + y2: currentRoof.y2 + beta, + }) + + prevRoof.set({ + x1: prevRoof.x1, + y1: prevRoof.y1, + x2: prevRoof.x2 + alpha, + y2: prevRoof.y2 + beta, + }) + + nextRoof.set({ + x1: nextRoof.x1 + alpha, + y1: nextRoof.y1 + beta, + x2: nextRoof.x2, + y2: nextRoof.y2, + }) + + reDrawPolygon(roof, canvas) + + if (ridgeLines.length > 0) { + const ridge = ridgeLines[0] + if (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) { + const diffX = ridge.x1 - wallMidX === 0 ? 0 : ridge.x1 - wallMidX + const diffY = ridge.y1 - wallMidY === 0 ? 0 : ridge.y1 - wallMidY + + ridge.set({ + x1: ridge.x1 - diffX, + y1: ridge.y1 - diffY, + x2: ridge.x2, + y2: ridge.y2, + }) + } + if (ridge.x2 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y2 === currentRoof.attributes.ridgeCoordinate.y1) { + const diffX = ridge.x2 - wallMidX === 0 ? 0 : ridge.x2 - wallMidX + const diffY = ridge.y2 - wallMidY === 0 ? 0 : ridge.y2 - wallMidY + + ridge.set({ + x1: ridge.x1, + y1: ridge.y1, + x2: ridge.x2 - diffX, + y2: ridge.y2 - diffY, + }) + } + } + + console.log('hipLines : ', hipLines) + if (hipLines.length > 0) { + hipLines.forEach((hip) => { + const diffX = hip.x1 - wallMidX + const diffY = hip.y1 - wallMidY + console.log('diffX : ', diffX, ' diffY : ', diffY) + hip.set({ + x1: hip.x1, + y1: hip.y1, + x2: wallMidX, + y2: wallMidY, + }) + }) } } export const changeAllHipAndGableRoof = (polygon, offset, canvas) => { - const roof = polygon.filter((p) => p.name === 'roofBase')[0] // 지붕 + const roof = polygon.filter((p) => p.name === 'roof')[0] // 지붕 const roofLines = roof.lines // 지붕의 라인 const ridges = roof.ridges // 마루의 라인 const hips = roof.hips // 추녀마루의 라인 @@ -2983,6 +2850,43 @@ const setHipAndGableRoof = (roof, ridge, hip1, hip2, offset, canvas) => { return gableLine } +/** + * 지붕을 변경한다. + * @param polygon + * @param canvas + */ +const reDrawPolygon = (polygon, canvas) => { + const lines = polygon.lines + let point = [] + lines.forEach((line) => point.push({ x: line.x1, y: line.y1 })) + + console.log('point : ', point) + + const newPolygon = new QPolygon(point, { + id: polygon.id, + name: polygon.name, + fill: polygon.fill, + stroke: polygon.stroke, + strokeWidth: polygon.strokeWidth, + selectable: polygon.selectable, + fontSize: polygon.fontSize, + wall: polygon.wall !== undefined ? polygon.wall : null, + }) + + const newLines = newPolygon.lines + + newLines.forEach((line, index) => { + lines.forEach((l, i) => { + if (index === i) { + line.id = l.id + line.attributes = l.attributes + } + }) + }) + canvas?.add(newPolygon) + canvas?.remove(polygon) +} + function arePointsEqual(point1, point2) { return point1.x === point2.x && point1.y === point2.y } From 5064ff627c3a80b4e63a68e7bf65b78a4bec0a44 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Mon, 14 Oct 2024 17:23:24 +0900 Subject: [PATCH 02/63] =?UTF-8?q?dev=20merge=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 316 ++++++++++++++++++++++++++++++------------- 1 file changed, 219 insertions(+), 97 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index e82c51f3..e7b457e5 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -36,7 +36,10 @@ import { QPolygon } from '@/components/fabric/QPolygon' import offsetPolygon from '@/util/qpolygon-utils' import { isObjectNotEmpty } from '@/util/common-utils' import * as turf from '@turf/turf' -import { INPUT_TYPE, LINE_TYPE, Mode } from '@/common/common' +import { INPUT_TYPE, Mode } from '@/common/common' +import { m } from 'framer-motion' +import { set } from 'react-hook-form' +import { FaWineGlassEmpty } from 'react-icons/fa6' export function useMode() { const [mode, setMode] = useRecoilState(modeState) @@ -1506,25 +1509,6 @@ export function useMode() { *벽 지붕 외곽선 생성 polygon을 입력받아 만들기 */ const handleOuterlinesTest2 = (polygon, offset = 50) => { - console.log('polygon : ', polygon) - // TODO [ljyoung] : offset 입력 처리 후 제거 해야함. - polygon.lines.forEach((line, index) => { - if (index === 1 || index === 3) { - line.attributes = { - type: LINE_TYPE.WALLLINE.WALL, - offset: 50, - width: 100, - pitch: 4, - } - } else { - line.attributes = { - type: LINE_TYPE.WALLLINE.WALL, - offset: 50, - width: 100, - pitch: 4, - } - } - }) const roof = drawRoofPolygon(polygon) //지붕 그리기 roof.drawHelpLine() // roof.divideLine() @@ -4873,6 +4857,12 @@ export function useMode() { ) } + const coordToTurfPolygon = (points) => { + const coordinates = points.map((point) => [point.x, point.y]) + coordinates.push(coordinates[0]) + return turf.polygon([coordinates]) + } + /** * trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 로 진입여부를 확인 * 확인 후 셀을 이동시킴 @@ -4880,56 +4870,190 @@ export function useMode() { const drawCellManualInTrestle = () => { const trestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'trestle') //가대를 가져옴 + const dormerTrestlePolygons = canvas?.getObjects().filter((obj) => obj.name === 'dormerTrestle') //도머 객체 + if (trestlePolygons.length !== 0) { - let lastPointPosition = { x: 0, y: 0 } let fabricPolygon = null let inside = false let turfPolygon - let manualDrawCells = drewRoofCells // - + let manualDrawCells = drewRoofCells // 앞에서 자동으로 했을때 추가됨 + let direction + let trestlePolygon canvas.on('mouse:move', (e) => { //마우스 이벤트 삭제 후 재추가 const mousePoint = canvas.getPointer(e.e) - const turfPoint = turf.point([mousePoint.x, mousePoint.y]) for (let i = 0; i < trestlePolygons.length; i++) { turfPolygon = polygonToTurfPolygon(trestlePolygons[i]) - if (turf.booleanPointInPolygon(turfPoint, turfPolygon)) { - //turf에 보면 폴리곤안에 포인트가 있는지 함수가 있다 - const direction = trestlePolygons[i].direction //도형의 방향 - let width = direction === 'south' || direction === 'north' ? 172.2 : 113.4 - let height = direction === 'south' || direction === 'north' ? 113.4 : 172.2 - if (Math.abs(mousePoint.x - lastPointPosition.x) >= 5 || Math.abs(mousePoint.y - lastPointPosition.y) >= 5) { - let isDrawing = false + trestlePolygon = trestlePolygons[i] + direction = trestlePolygons[i].direction //도형의 방향 + let width = direction === 'south' || direction === 'north' ? 172 : 113 + let height = direction === 'south' || direction === 'north' ? 113 : 172 - if (isDrawing) return - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tmpCell')) //움직일때 일단 지워가면서 움직임 + const points = [ + { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 }, + { x: mousePoint.x + width / 2, y: mousePoint.y - height / 2 }, + { x: mousePoint.x + width / 2, y: mousePoint.y + height / 2 }, + { x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 }, + ] - const points = [ - { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 }, - { x: mousePoint.x + width / 2, y: mousePoint.y - height / 2 }, - { x: mousePoint.x + width / 2, y: mousePoint.y + height / 2 }, - { x: mousePoint.x - width / 2, y: mousePoint.y + height / 2 }, - ] + const turfPoints = coordToTurfPolygon(points) - fabricPolygon = new QPolygon(points, { - fill: '#BFFD9F', - stroke: 'black', - selectable: false, // 선택 가능하게 설정 - lockMovementX: true, // X 축 이동 잠금 - lockMovementY: true, // Y 축 이동 잠금 - lockRotation: true, // 회전 잠금 - lockScalingX: true, // X 축 크기 조정 잠금 - lockScalingY: true, // Y 축 크기 조정 잠금 - opacity: 0.8, - parentId: trestlePolygons[i].parentId, - name: 'tmpCell', + if (turf.booleanWithin(turfPoints, turfPolygon)) { + let isDrawing = false + + if (isDrawing) return + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tmpCell')) //움직일때 일단 지워가면서 움직임 + + fabricPolygon = new fabric.Rect({ + fill: 'white', + stroke: 'black', + strokeWidth: 1, + width: width, + height: height, + left: mousePoint.x - width / 2, + top: mousePoint.y - height / 2, + selectable: false, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + opacity: 0.8, + name: 'tmpCell', + parentId: trestlePolygons[i].parentId, + }) + + canvas?.add(fabricPolygon) //움직여가면서 추가됨 + + /** + * 스냅기능 + */ + let snapDistance = 10 + let cellSnapDistance = 20 + + const trestleLeft = trestlePolygons[i].left + const trestleTop = trestlePolygons[i].top + const trestleRight = trestleLeft + trestlePolygons[i].width * trestlePolygons[i].scaleX + const trestleBottom = trestleTop + trestlePolygons[i].height * trestlePolygons[i].scaleY + const bigCenterY = (trestleTop + trestleTop + trestlePolygons[i].height) / 2 + + // 작은 폴리곤의 경계 좌표 계산 + const smallLeft = fabricPolygon.left + const smallTop = fabricPolygon.top + const smallRight = smallLeft + fabricPolygon.width * fabricPolygon.scaleX + const smallBottom = smallTop + fabricPolygon.height * fabricPolygon.scaleY + const smallCenterX = smallLeft + (fabricPolygon.width * fabricPolygon.scaleX) / 2 + const smallCenterY = smallTop + (fabricPolygon.height * fabricPolygon.scaleX) / 2 + + /** + * 미리 깔아놓은 셀이 있을때 셀에 흡착됨 + */ + if (manualDrawCells) { + manualDrawCells.forEach((cell) => { + const holdCellLeft = cell.left + const holdCellTop = cell.top + const holdCellRight = holdCellLeft + cell.width * cell.scaleX + const holdCellBottom = holdCellTop + cell.height * cell.scaleY + const holdCellCenterX = holdCellLeft + (cell.width * cell.scaleX) / 2 + const holdCellCenterY = holdCellTop + (cell.height * cell.scaleY) / 2 + + //설치된 셀에 좌측에 스냅 + if (Math.abs(smallRight - holdCellLeft) < snapDistance) { + fabricPolygon.left = holdCellLeft - width - 0.5 + } + + //설치된 셀에 우측에 스냅 + if (Math.abs(smallLeft - holdCellRight) < snapDistance) { + fabricPolygon.left = holdCellRight + 0.5 + } + + //설치된 셀에 위쪽에 스냅 + if (Math.abs(smallBottom - holdCellTop) < snapDistance) { + fabricPolygon.top = holdCellTop - height - 0.5 + } + + //설치된 셀에 밑쪽에 스냅 + if (Math.abs(smallTop - holdCellBottom) < snapDistance) { + fabricPolygon.top = holdCellBottom + 0.5 + } + //가운데 -> 가운데 + if (Math.abs(smallCenterX - holdCellCenterX) < cellSnapDistance) { + fabricPolygon.left = holdCellCenterX - width / 2 + } + //왼쪽 -> 가운데 + if (Math.abs(smallLeft - holdCellCenterX) < cellSnapDistance) { + fabricPolygon.left = holdCellCenterX + } + // 오른쪽 -> 가운데 + if (Math.abs(smallRight - holdCellCenterX) < cellSnapDistance) { + fabricPolygon.left = holdCellCenterX - width + } + //세로 가운데 -> 가운데 + if (Math.abs(smallCenterY - holdCellCenterY) < cellSnapDistance) { + fabricPolygon.top = holdCellCenterY - height / 2 + } + //위쪽 -> 가운데 + if (Math.abs(smallTop - holdCellCenterY) < cellSnapDistance) { + fabricPolygon.top = holdCellCenterY + } + //아랫쪽 -> 가운데 + if (Math.abs(smallBottom - holdCellCenterY) < cellSnapDistance) { + fabricPolygon.top = holdCellCenterY - height + } }) - - canvas?.add(fabricPolygon) //움직여가면서 추가됨 - lastPointPosition = { x: mousePoint.x, y: mousePoint.y } } + // 위쪽 변에 스냅 + if (Math.abs(smallTop - trestleTop) < snapDistance) { + fabricPolygon.top = trestleTop + } + + // 아래쪽 변에 스냅 + if (Math.abs(smallTop + fabricPolygon.height * fabricPolygon.scaleY - (trestleTop + trestlePolygons[i].height)) < snapDistance) { + fabricPolygon.top = trestleTop + trestlePolygons[i].height - fabricPolygon.height * fabricPolygon.scaleY + } + + // 왼쪽변에 스냅 + if (Math.abs(smallLeft - trestleLeft) < snapDistance) { + fabricPolygon.left = trestleLeft + } + //오른쪽 변에 스냅 + if (Math.abs(smallRight - trestleRight) < snapDistance) { + fabricPolygon.left = trestleRight - fabricPolygon.width * fabricPolygon.scaleX + } + + if (direction === 'south' || direction === 'north') { + // 모듈왼쪽이 세로중앙선에 붙게 스냅 + if (Math.abs(smallLeft - (trestleLeft + trestlePolygons[i].width / 2)) < snapDistance) { + fabricPolygon.left = trestleLeft + trestlePolygons[i].width / 2 + } + + // 모듈이 가운데가 세로중앙선에 붙게 스냅 + if (Math.abs(smallCenterX - (trestleLeft + trestlePolygons[i].width / 2)) < snapDistance) { + fabricPolygon.left = trestleLeft + trestlePolygons[i].width / 2 - (fabricPolygon.width * fabricPolygon.scaleX) / 2 + } + + // 모듈오른쪽이 세로중앙선에 붙게 스냅 + if (Math.abs(smallRight - (trestleLeft + trestlePolygons[i].width / 2)) < snapDistance) { + fabricPolygon.left = trestleLeft + trestlePolygons[i].width / 2 - fabricPolygon.width * fabricPolygon.scaleX + } + } else { + // 모듈이 가로중앙선에 스냅 + if (Math.abs(smallTop + fabricPolygon.height / 2 - bigCenterY) < snapDistance) { + fabricPolygon.top = bigCenterY - fabricPolygon.height / 2 + } + + if (Math.abs(smallTop - (trestleTop + trestlePolygons[i].height / 2)) < snapDistance) { + fabricPolygon.top = trestleTop + trestlePolygons[i].height / 2 + } + // 모듈 밑면이 가로중앙선에 스냅 + if (Math.abs(smallBottom - (trestleTop + trestlePolygons[i].height / 2)) < snapDistance) { + fabricPolygon.top = trestleTop + trestlePolygons[i].height / 2 - fabricPolygon.height * fabricPolygon.scaleY + } + } + + fabricPolygon.setCoords() canvas?.renderAll() inside = true break @@ -4945,23 +5069,56 @@ export function useMode() { }) canvas?.on('mouse:up', (e) => { + let isIntersection = true if (!inside) return if (fabricPolygon) { - const turfCellPolygon = polygonToTurfPolygon(fabricPolygon) + const rectPoints = [ + { x: fabricPolygon.left + 0.5, y: fabricPolygon.top + 0.5 }, + { x: fabricPolygon.left + 0.5 + fabricPolygon.width * fabricPolygon.scaleX, y: fabricPolygon.top + 0.5 }, + { + x: fabricPolygon.left + fabricPolygon.width * fabricPolygon.scaleX + 0.5, + y: fabricPolygon.top + fabricPolygon.height * fabricPolygon.scaleY + 0.5, + }, + { x: fabricPolygon.left + 0.5, y: fabricPolygon.top + fabricPolygon.height * fabricPolygon.scaleY + 0.5 }, + ] - if (turf.booleanWithin(turfCellPolygon, turfPolygon)) { + fabricPolygon.set({ points: rectPoints }) + const tempTurfModule = polygonToTurfPolygon(fabricPolygon) + + //도머 객체를 가져옴 + if (dormerTrestlePolygons) { + dormerTrestlePolygons.forEach((dormerTrestle) => { + const dormerTurfPolygon = polygonToTurfPolygon(dormerTrestle) //turf객체로 변환 + const intersection = turf.intersect(turf.featureCollection([dormerTurfPolygon, tempTurfModule])) //겹치는지 확인 + //겹치면 안됨 + if (intersection) { + alert('도머위에 모듈을 올릴 수 없습니다.') + isIntersection = false + } + }) + } + + if (!isIntersection) return + + fabricPolygon.setCoords() //좌표 재정렬 + + if (turf.booleanWithin(tempTurfModule, turfPolygon)) { //마우스 클릭시 set으로 해당 위치에 셀을 넣음 - const isOverlap = manualDrawCells.some((cell) => turf.booleanOverlap(turfCellPolygon, polygonToTurfPolygon(cell))) + const isOverlap = manualDrawCells.some((cell) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(cell))) //겹치는지 확인 if (!isOverlap) { //안겹치면 넣는다 - fabricPolygon.set({ name: 'cell' }) fabricPolygon.setCoords() - manualDrawCells.push(fabricPolygon) + fabricPolygon.set({ name: 'cell', fill: '#BFFD9F' }) + manualDrawCells.push(fabricPolygon) //모듈배열에 추가 + //해당 모듈에 프로퍼티로 넣는다 + trestlePolygon.set({ + modules: manualDrawCells, + }) } else { alert('셀끼리 겹치면 안되죠?') } } else { - alert('나갔으요!!') + alert('나갔죠?!!') } setDrewRoofCells(manualDrawCells) } @@ -5036,29 +5193,6 @@ export function useMode() { const cols = Math.floor((bbox[2] - bbox[0]) / width) const rows = Math.floor((bbox[3] - bbox[1]) / height) - // console.log('bbox', bbox) - - const boxes = [] - const installedCellsArray = [] - - for (let x = bbox[0]; x < bbox[2]; x += width) { - for (let y = bbox[1]; y < bbox[3]; y += height) { - const box = turf.polygon([ - [ - [x, y], - [x + width, y], - [x + width, y + height], - [x, y + height], - [x, y], - ], - ]) - - if (turf.booleanWithin(box, turfTrestlePolygon)) { - boxes.push(box) - } - } - } - for (let col = 0; col <= cols; col++) { for (let row = 0; row <= rows; row++) { let x = 0, @@ -5108,20 +5242,6 @@ export function useMode() { const squarePolygon = turf.polygon([square]) - // console.log('turfTrestlePolygon', turfTrestlePolygon) - // console.log('squarePolygon', squarePolygon) - - const areaSize = turf.area(turfTrestlePolygon) - - // console.log('areaSize', areaSize) - const objSize = turf.area(squarePolygon) - - // console.log('objSize', objSize) - - const maxObject = Math.floor(areaSize / objSize) - - // console.log('maxObjectSize', maxObject) - const disjointFromTrestle = turf.booleanContains(turfTrestlePolygon, squarePolygon) || turf.booleanWithin(squarePolygon, turfTrestlePolygon) if (disjointFromTrestle) { @@ -5162,6 +5282,8 @@ export function useMode() { lockScalingY: true, // Y 축 크기 조정 잠금 opacity: 0.8, parentId: trestle.parentId, + lineCol: col, + lineRow: row, }) canvas?.add(fabricPolygon) drawCellsArray.push(fabricPolygon) From 0bc0e73a103bd46113320c202b87eac4265eb0e8 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Fri, 18 Oct 2024 10:29:31 +0900 Subject: [PATCH 03/63] =?UTF-8?q?=EC=A7=80=EB=B6=95=20=EB=AA=A8=EC=96=91?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EC=9E=91=EC=97=85=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/common.js | 1 + src/components/Roof2.jsx | 45 +++++--- src/hooks/useMode.js | 43 +++++++- src/util/qpolygon-utils.js | 205 +++++++++++++++++++++++-------------- 4 files changed, 197 insertions(+), 97 deletions(-) diff --git a/src/common/common.js b/src/common/common.js index ae96db06..bc067077 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -63,6 +63,7 @@ export const LINE_TYPE = { HIPANDGABLE: 'hipAndGable', JERKINHEAD: 'jerkinhead', SHED: 'shed', + ETC: 'etc', }, SUBLINE: { /** diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 910fd365..2fe86ecc 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -4,7 +4,7 @@ import { useCanvas } from '@/hooks/useCanvas' import { useEffect, useRef, useState } from 'react' import { v4 as uuidv4 } from 'uuid' import { useMode } from '@/hooks/useMode' -import { Mode } from '@/common/common' +import { LINE_TYPE, Mode } from '@/common/common' import { Button, Input } from '@nextui-org/react' import RangeSlider from './ui/RangeSlider' import { useRecoilState, useRecoilValue } from 'recoil' @@ -39,7 +39,7 @@ import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMen import InitSettingsModal from './InitSettingsModal' import GridSettingsModal from './GridSettingsModal' import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' -import { drawDirectionStringToArrow } from '@/util/qpolygon-utils' +import { changeHipAndGableRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils' import ThumbnailList from '@/components/ui/ThumbnailLIst' import ObjectPlacement from '@/components/ui/ObjectPlacement' import { globalLocaleStore } from '@/store/localeAtom' @@ -431,7 +431,7 @@ export default function Roof2(props) { { x: 450, y: 850 }, ] - const polygon = new QPolygon(rectangleType2, { + const polygon = new QPolygon(rectangleType1, { fill: 'transparent', stroke: 'green', strokeWidth: 1, @@ -672,13 +672,14 @@ export default function Roof2(props) { canvas?.renderAll() } - const setAllGableRoof = () => { + const setGableRoof = () => { let offset = Number(prompt('gable roof offset', '50')) if (!isNaN(offset) && offset > 0) { - const polygon = canvas?.getObjects() - console.log('gable roof offset : ', offset) - console.log('polygon : ', polygon) - changeAllGableRoof(polygon, offset, canvas) + const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') + const currentRoof = polygon.lines[3] + currentRoof.attributes.type = LINE_TYPE.WALLLINE.HIPANDGABLE + currentRoof.attributes.width = offset + changeHipAndGableRoof(currentRoof, canvas) } else { alert('offset 은 0 보다 커야 함') } @@ -802,16 +803,28 @@ export default function Roof2(props) { - {templateType === 0 && ( - <> - - - )} - + {/* */} + {/*)}*/} + + + + + diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index e7b457e5..6a332d35 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -36,10 +36,7 @@ import { QPolygon } from '@/components/fabric/QPolygon' import offsetPolygon from '@/util/qpolygon-utils' import { isObjectNotEmpty } from '@/util/common-utils' import * as turf from '@turf/turf' -import { INPUT_TYPE, Mode } from '@/common/common' -import { m } from 'framer-motion' -import { set } from 'react-hook-form' -import { FaWineGlassEmpty } from 'react-icons/fa6' +import { INPUT_TYPE, LINE_TYPE, Mode } from '@/common/common' export function useMode() { const [mode, setMode] = useRecoilState(modeState) @@ -1509,6 +1506,43 @@ export function useMode() { *벽 지붕 외곽선 생성 polygon을 입력받아 만들기 */ const handleOuterlinesTest2 = (polygon, offset = 50) => { + console.log('polygon : ', polygon) + // TODO [ljyoung] : offset 입력 처리 후 제거 해야함. + polygon.lines.forEach((line, index) => { + line.attributes = { + type: LINE_TYPE.WALLLINE.EAVES, + offset: 40, + width: 50, + pitch: 4, + sleeve: true, + } + /*if (index === 1 || index === 3) { + line.attributes = { + type: LINE_TYPE.WALLLINE.WALL, + offset: 0, //출폭 + width: 30, //폭 + pitch: 4, //구배 + sleeve: true, //소매 + } + } else if (index === 0) { + line.attributes = { + type: LINE_TYPE.WALLLINE.EAVES, + offset: 0, + width: 50, + pitch: 4, + sleeve: true, + } + } else { + line.attributes = { + type: LINE_TYPE.WALLLINE.EAVES, + offset: 40, + width: 50, + pitch: 4, + sleeve: true, + } + }*/ + }) + const roof = drawRoofPolygon(polygon) //지붕 그리기 roof.drawHelpLine() // roof.divideLine() @@ -1706,6 +1740,7 @@ export function useMode() { offset: wall.lines[index].attributes.offset, width: wall.lines[index].attributes.width, pitch: wall.lines[index].attributes.pitch, + sleeve: wall.lines[index].attributes.sleeve || false, } }) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index c7ccfece..62597365 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -2030,7 +2030,6 @@ const connectLinePoint = (polygon) => { } const modifyRidge = (roof, canvas) => { - const roofLines = roof.lines const ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roof.id) const hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roof.id) @@ -2041,7 +2040,6 @@ const modifyRidge = (roof, canvas) => { let currentRoof = roof.lines .filter((roofLine) => roofLine.attributes !== undefined && roofLine.attributes.ridgeCoordinate !== undefined) .find((roofLine) => roofLine.attributes.ridgeCoordinate.x1 === ridge.x1 && roofLine.attributes.ridgeCoordinate.y1 === ridge.y1) - console.log('1 currentRoof : ', currentRoof) if (currentRoof === undefined) { currentRoof = roof.lines.find( (roofLine) => @@ -2058,7 +2056,6 @@ const modifyRidge = (roof, canvas) => { currentRoof.attributes.ridgeCoordinate = { x1: ridge.x1, y1: ridge.y1 } } } - console.log('2 currentRoof : ', currentRoof) if (currentRoof !== undefined) { switch (currentRoof.attributes.type) { case LINE_TYPE.WALLLINE.EAVES: @@ -2067,7 +2064,7 @@ const modifyRidge = (roof, canvas) => { changeGableRoof(roof.id, currentRoof, canvas) break case LINE_TYPE.WALLLINE.HIPANDGABLE: - changeHipAndGableRoof(roof.id, currentRoof, canvas) + changeHipAndGableRoof(currentRoof, canvas) break case LINE_TYPE.WALLLINE.JERKINHEAD: changeJerkInHeadRoof(roof.id, currentRoof, canvas) @@ -2082,7 +2079,6 @@ const modifyRidge = (roof, canvas) => { let currentRoof = roof.lines .filter((roofLine) => roofLine.attributes !== undefined && roofLine.attributes.ridgeCoordinate !== undefined) .find((roofLine) => roofLine.attributes.ridgeCoordinate.x1 === ridge.x2 && roofLine.attributes.ridgeCoordinate.y1 === ridge.y2) - console.log('3 currentRoof : ', currentRoof) if (currentRoof === undefined) { currentRoof = roof.lines.find( (roofLine) => @@ -2099,7 +2095,6 @@ const modifyRidge = (roof, canvas) => { currentRoof.attributes.ridgeCoordinate = { x1: ridge.x2, y1: ridge.y2 } } } - console.log('4 currentRoof : ', currentRoof) if (currentRoof !== undefined) { switch (currentRoof.attributes.type) { case LINE_TYPE.WALLLINE.EAVES: @@ -2108,7 +2103,7 @@ const modifyRidge = (roof, canvas) => { changeGableRoof(roof.id, currentRoof, canvas) break case LINE_TYPE.WALLLINE.HIPANDGABLE: - changeHipAndGableRoof(roof.id, currentRoof, canvas) + changeHipAndGableRoof(currentRoof, canvas) break case LINE_TYPE.WALLLINE.JERKINHEAD: changeJerkInHeadRoof(roof.id, currentRoof, canvas) @@ -2220,12 +2215,12 @@ export const changeGableRoof = (roofId, currentRoof, canvas) => { /** * 팔작지붕으로 변경 - * @param roofId * @param currentRoof * @param canvas */ -export const changeHipAndGableRoof = (roofId, currentRoof, canvas) => { +export const changeHipAndGableRoof = (currentRoof, canvas) => { if (currentRoof.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + const roofId = currentRoof.attributes.roofId const roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) @@ -2239,7 +2234,11 @@ export const changeHipAndGableRoof = (roofId, currentRoof, canvas) => { (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), ) - if (ridgeLines.length > 0) { + hipLines.forEach((hip) => canvas?.remove(hip)) + + console.log(canvas?.getObjects().find((object) => object.attributes !== undefined && object.attributes.roofId === roofId)) + + /*if (ridgeLines.length > 0) { const ridge = ridgeLines[0] let midX = (currentRoof.x1 + currentRoof.x2) / 2 let midY = (currentRoof.y1 + currentRoof.y2) / 2 @@ -2310,7 +2309,7 @@ export const changeHipAndGableRoof = (roofId, currentRoof, canvas) => { roof.innerLines.push(hipLine) }) } - } + }*/ } } @@ -2426,8 +2425,13 @@ export const changeJerkInHeadRoof = (roofId, currentRoof, canvas) => { } } +/** + * 벽지붕으로 변경 + * @param roofId + * @param currentRoof + * @param canvas + */ const changeWallRoof = (roofId, currentRoof, canvas) => { - console.log('roofId : ', roofId) let roof = canvas?.getObjects().find((object) => object.name === 'roof' && object.id === roofId) const roofLines = roof.lines let prevRoof, nextRoof @@ -2444,6 +2448,10 @@ const changeWallRoof = (roofId, currentRoof, canvas) => { let hipLines = canvas?.getObjects().filter((object) => object.name === 'hipLine' && object.attributes.roofId === roofId) let ridgeLines = canvas?.getObjects().filter((object) => object.name === 'ridgeLine' && object.attributes.roofId === roofId) + if (wallLine.length > 0) { + wallLine = wallLine[0] + } + ridgeLines = ridgeLines.filter( (ridge) => (ridge.x1 === currentRoof.attributes.ridgeCoordinate.x1 && ridge.y1 === currentRoof.attributes.ridgeCoordinate.y1) || @@ -2453,8 +2461,8 @@ const changeWallRoof = (roofId, currentRoof, canvas) => { (hip) => (hip.x1 === currentRoof.x1 && hip.y1 === currentRoof.y1) || (hip.x1 === currentRoof.x2 && hip.y1 === currentRoof.y2), ) - const wallMidX = (wallLine[0].x1 + wallLine[0].x2) / 2 - const wallMidY = (wallLine[0].y1 + wallLine[0].y2) / 2 + const wallMidX = (wallLine.x1 + wallLine.x2) / 2 + const wallMidY = (wallLine.y1 + wallLine.y2) / 2 const roofMidX = (currentRoof.x1 + currentRoof.x2) / 2 const roofMidY = (currentRoof.y1 + currentRoof.y2) / 2 @@ -2482,7 +2490,88 @@ const changeWallRoof = (roofId, currentRoof, canvas) => { y2: nextRoof.y2, }) - reDrawPolygon(roof, canvas) + if (currentRoof.attributes.sleeve && prevRoof.attributes.offset > 0 && nextRoof.attributes.offset > 0) { + const prevSignX = Math.sign(prevRoof.x1 - prevRoof.x2) + const prevSignY = Math.sign(prevRoof.y1 - prevRoof.y2) + const nextSignX = Math.sign(nextRoof.x1 - nextRoof.x2) + const nextSignY = Math.sign(nextRoof.y1 - nextRoof.y2) + + const prevWidthX = prevSignX === 0 ? 0 : prevSignX * currentRoof.attributes.width + const prevWidthY = prevSignY === 0 ? 0 : prevSignY * currentRoof.attributes.width + const nextWidthX = nextSignX === 0 ? 0 : nextSignX * currentRoof.attributes.width + const nextWidthY = nextSignY === 0 ? 0 : nextSignY * currentRoof.attributes.width + const prevX2 = prevRoof.x2 - prevWidthX + const prevY2 = prevRoof.y2 - prevWidthY + const nextX1 = nextRoof.x1 + nextWidthX + const nextY1 = nextRoof.y1 + nextWidthY + + currentRoof.set({ + x1: wallLine.x1, + y1: wallLine.y1, + x2: wallLine.x2, + y2: wallLine.y2, + }) + + prevRoof.set({ + x1: prevRoof.x1, + y1: prevRoof.y1, + x2: prevX2, + y2: prevY2, + }) + + nextRoof.set({ + x1: nextX1, + y1: nextY1, + x2: nextRoof.x2, + y2: nextRoof.y2, + }) + + const addPrevWallLine1 = new QLine([prevX2, prevY2, wallLine.x1 - prevWidthX, wallLine.y1 - prevWidthY], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'roofLine', + attributes: { roofId: roofId, type: LINE_TYPE.WALLLINE.ETC }, + }) + + const addPrevWallLine2 = new QLine( + [addPrevWallLine1.x2, addPrevWallLine1.y2, addPrevWallLine1.x2 + prevWidthX, addPrevWallLine1.y2 + prevWidthY], + { + fontSize: roof.fontSize, + stroke: 'cyan', + strokeWidth: 1, + name: 'roofLine', + attributes: { roofId: roofId, type: LINE_TYPE.WALLLINE.ETC }, + }, + ) + + const addNextWallLine1 = new QLine([wallLine.x2, wallLine.y2, wallLine.x2 + nextWidthX, wallLine.y2 + nextWidthY], { + fontSize: roof.fontSize, + stroke: 'green', + strokeWidth: 1, + name: 'roofLine', + attributes: { roofId: roofId, type: LINE_TYPE.WALLLINE.ETC }, + }) + + const addNextWallLine2 = new QLine([addNextWallLine1.x2, addNextWallLine1.y2, nextX1, nextY1], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'roofLine', + attributes: { roofId: roofId, type: LINE_TYPE.WALLLINE.ETC }, + }) + + canvas?.renderAll() + const prevIndex = roof.lines.indexOf(prevRoof) + 1 + roof.lines.splice(prevIndex, 0, addPrevWallLine1, addPrevWallLine2) + + const nextIndex = roof.lines.indexOf(currentRoof) + 1 + roof.lines.splice(nextIndex, 0, addNextWallLine1, addNextWallLine2) + } + + roof = reDrawPolygon(roof, canvas) + + console.log('roof : ', roof.lines) if (ridgeLines.length > 0) { const ridge = ridgeLines[0] @@ -2508,72 +2597,31 @@ const changeWallRoof = (roofId, currentRoof, canvas) => { y2: ridge.y2 - diffY, }) } - } - console.log('hipLines : ', hipLines) + let hip1 = new QLine([currentRoof.x1, currentRoof.y1, wallMidX, wallMidY], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roof.id, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + let hip2 = new QLine([currentRoof.x2, currentRoof.y2, wallMidX, wallMidY], { + fontSize: roof.fontSize, + stroke: 'red', + strokeWidth: 1, + name: 'hipLine', + attributes: { roofId: roof.id, currentRoofId: currentRoof.id, planeSize: currentRoof.length, actualSize: currentRoof.length }, + }) + canvas?.add(hip1) + canvas?.add(hip2) + } if (hipLines.length > 0) { hipLines.forEach((hip) => { - const diffX = hip.x1 - wallMidX - const diffY = hip.y1 - wallMidY - console.log('diffX : ', diffX, ' diffY : ', diffY) - hip.set({ - x1: hip.x1, - y1: hip.y1, - x2: wallMidX, - y2: wallMidY, - }) + canvas?.remove(hip) }) } } -export const changeAllHipAndGableRoof = (polygon, offset, canvas) => { - const roof = polygon.filter((p) => p.name === 'roof')[0] // 지붕 - const roofLines = roof.lines // 지붕의 라인 - const ridges = roof.ridges // 마루의 라인 - const hips = roof.hips // 추녀마루의 라인 - - console.log('roofLines : ', roofLines) - - ridges.forEach((ridge) => { - let ridgeHip1 = hips.filter((hip) => hip.x2 === ridge.x1 && hip.y2 === ridge.y1) - let ridgeHip2 = hips.filter((hip) => hip.x2 === ridge.x2 && hip.y2 === ridge.y2) - let gableLines = [] - if (ridgeHip1.length > 1) { - let x1 = ridgeHip1[0].x1, - y1 = ridgeHip1[0].y1, - x2 = ridgeHip1[1].x1, - y2 = ridgeHip1[1].y1 - roofLines.filter((roofLine) => { - if ( - (roofLine.x1 === x1 && roofLine.y1 === y1 && roofLine.x2 === x2 && roofLine.y2 === y2) || - (roofLine.x1 === x2 && roofLine.y1 === y2 && roofLine.x2 === x1 && roofLine.y2 === y1) - ) { - gableLines.push(setHipAndGableRoof(roof, ridge, ridgeHip1[0], ridgeHip1[1], offset, canvas)) - } - }) - } - if (ridgeHip2.length > 1) { - let x1 = ridgeHip2[0].x1, - y1 = ridgeHip2[0].y1, - x2 = ridgeHip2[1].x1, - y2 = ridgeHip2[1].y1 - roofLines.filter((roofLine) => { - if ( - (roofLine.x1 === x1 && roofLine.y1 === y1 && roofLine.x2 === x2 && roofLine.y2 === y2) || - (roofLine.x1 === x2 && roofLine.y1 === y2 && roofLine.x2 === x1 && roofLine.y2 === y1) - ) { - gableLines.push(setHipAndGableRoof(roof, ridge, ridgeHip2[0], ridgeHip2[1], offset, canvas)) - } - }) - } - gableLines.forEach((gableLine) => { - roof.innerLines.push(gableLine) - }) - }) - - // splitPolygonWithLines(roof) -} - /** * 모임지붕 -> 팔작지붕 변경 * @param roof @@ -2860,7 +2908,7 @@ const reDrawPolygon = (polygon, canvas) => { let point = [] lines.forEach((line) => point.push({ x: line.x1, y: line.y1 })) - console.log('point : ', point) + canvas?.remove(polygon) const newPolygon = new QPolygon(point, { id: polygon.id, @@ -2877,14 +2925,17 @@ const reDrawPolygon = (polygon, canvas) => { newLines.forEach((line, index) => { lines.forEach((l, i) => { - if (index === i) { + if (line.x1 === l.x1 && line.y1 === l.y1) { line.id = l.id line.attributes = l.attributes } }) }) + canvas?.add(newPolygon) - canvas?.remove(polygon) + canvas?.renderAll() + + return newPolygon } function arePointsEqual(point1, point2) { From fa0cad7707ef37c47ca9e7587a6f48c1dbfcdadf Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Fri, 18 Oct 2024 10:46:32 +0900 Subject: [PATCH 04/63] =?UTF-8?q?=EB=AA=85=EC=B9=AD=20=EC=B6=94=EA=B0=80.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/common.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/common/common.js b/src/common/common.js index 1ca3e8ca..2319279b 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -67,8 +67,13 @@ export const LINE_TYPE = { }, SUBLINE: { /** - * + * 추녀 / 마루 / 박공 / 지붕골 / 박공단 */ + HIP: 'hip', + RIDGE: 'ridge', + GABLE: 'gable', + VALLEY: 'valley', + VERGE: 'verge', }, } From 637c7a75d5c1a0627e248e116df391ffaf5268c4 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Fri, 25 Oct 2024 10:52:54 +0900 Subject: [PATCH 05/63] =?UTF-8?q?=EB=B3=80=EB=B3=84=EB=A1=9C=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dictionary.txt | 1 + src/common/common.js | 1 + src/components/Roof2.jsx | 56 +- src/components/fabric/QPolygon.js | 66 +- src/hooks/useMode.js | 53 +- src/util/canvas-util.js | 10 + src/util/qpolygon-utils.js | 1348 +++++++++++++++++------------ 7 files changed, 935 insertions(+), 600 deletions(-) diff --git a/docs/dictionary.txt b/docs/dictionary.txt index 7e07124d..f5f461b7 100644 --- a/docs/dictionary.txt +++ b/docs/dictionary.txt @@ -18,6 +18,7 @@ 출폭: offset 폭: width 경사(구배): pitch +각도: degree 이구배: doublePitch 소매: sleeve 개구: openSpace diff --git a/src/common/common.js b/src/common/common.js index 2319279b..5a14fa38 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -115,5 +115,6 @@ export const INPUT_TYPE = { export const POLYGON_TYPE = { ROOF: 'roof', + WALL: 'wall', TRESTLE: 'trestle', } diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 2fe86ecc..fad075bd 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -39,7 +39,7 @@ import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMen import InitSettingsModal from './InitSettingsModal' import GridSettingsModal from './GridSettingsModal' import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' -import { changeHipAndGableRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils' +import { changeCurrentRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils' import ThumbnailList from '@/components/ui/ThumbnailLIst' import ObjectPlacement from '@/components/ui/ObjectPlacement' import { globalLocaleStore } from '@/store/localeAtom' @@ -431,7 +431,7 @@ export default function Roof2(props) { { x: 450, y: 850 }, ] - const polygon = new QPolygon(rectangleType1, { + const polygon = new QPolygon(rectangleType2, { fill: 'transparent', stroke: 'green', strokeWidth: 1, @@ -672,18 +672,52 @@ export default function Roof2(props) { canvas?.renderAll() } + const setHipRoof = () => { + const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') + const currentRoof = polygon.lines[2] + currentRoof.attributes.type = LINE_TYPE.WALLLINE.EAVES + currentRoof.attributes.offset = 50 + changeCurrentRoof(currentRoof, canvas) + } const setGableRoof = () => { - let offset = Number(prompt('gable roof offset', '50')) + const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') + const currentRoof = polygon.lines[2] + currentRoof.attributes.type = LINE_TYPE.WALLLINE.GABLE + currentRoof.attributes.offset = 30 + changeCurrentRoof(currentRoof, canvas) + } + const setHipAndGableRoof = () => { + let offset = Number(prompt('팔작지붕 폭', '50')) if (!isNaN(offset) && offset > 0) { const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') - const currentRoof = polygon.lines[3] + const currentRoof = polygon.lines[2] currentRoof.attributes.type = LINE_TYPE.WALLLINE.HIPANDGABLE currentRoof.attributes.width = offset - changeHipAndGableRoof(currentRoof, canvas) + changeCurrentRoof(currentRoof, canvas) } else { - alert('offset 은 0 보다 커야 함') + alert('폭은 0 보다 커야 함') } } + const setJerkInHeadRoof = () => { + let offset = Number(prompt('팔작지붕 폭', '50')) + if (!isNaN(offset) && offset > 0) { + const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') + const currentRoof = polygon.lines[2] + currentRoof.attributes.type = LINE_TYPE.WALLLINE.JERKINHEAD + currentRoof.attributes.width = offset + changeCurrentRoof(currentRoof, canvas) + } else { + alert('폭은 0 보다 커야 함') + } + } + const setWallRoof = () => { + let offset = Number(prompt('소매 폭', '0')) + const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') + const currentRoof = polygon.lines[2] + currentRoof.attributes.type = LINE_TYPE.WALLLINE.WALL + currentRoof.attributes.width = offset + changeCurrentRoof(currentRoof, canvas) + } return ( <> {canvas && ( @@ -810,19 +844,19 @@ export default function Roof2(props) { {/* */} {/*)}*/} - - - - - + diff --git a/src/components/floor-plan/modal/object/type/TriangleDormer.jsx b/src/components/floor-plan/modal/object/type/TriangleDormer.jsx index f2a8a1f0..34a87e44 100644 --- a/src/components/floor-plan/modal/object/type/TriangleDormer.jsx +++ b/src/components/floor-plan/modal/object/type/TriangleDormer.jsx @@ -38,7 +38,7 @@ const TriangleDormer = forwardRef((props, refs) => {
- +
mm
diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index 0e187b1e..356c100e 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -547,7 +547,7 @@ export function useCommonUtils() { initEvent() obj.setCoords() updateGroupObjectCoords(obj, originLeft, originTop) - // canvas?.renderAll() + canvas?.renderAll() }) } } @@ -585,6 +585,10 @@ export function useCommonUtils() { editable: false, id: uuidv4(), //복사된 객체라 새로 따준다 }) + + //객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다 + if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() }) + initEvent() }) } @@ -748,7 +752,6 @@ export function useCommonUtils() { } else { // 다른 객체의 경우 left, top 절대 좌표 설정 obj.set({ - ...obj, left: obj.left, top: obj.top, }) diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index c9b4cd3b..c55841c6 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -43,8 +43,12 @@ export function useObjectBatch({ isHidden, setIsHidden }) { // 클릭한 위치에 있는 객체 찾기 const clickedObject = objects.find((obj) => { + console.log(obj) + if (obj.type === 'QPolygon') { - return obj.inPolygon({ x: pointer.x, y: pointer.y }) + const polygon = pointsToTurfPolygon(obj.getCurrentPoints()) + const turfPointer = turf.point([pointer.x, pointer.y]) + return turf.booleanPointInPolygon(turfPointer, polygon) } else { return obj.containsPoint(pointer) } @@ -403,7 +407,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { }) //오프셋이 있을땐 같이 도머로 만든다 const leftTriangle = new QPolygon(splitedTriangle[0], { - fill: 'transparent', + fill: 'white', stroke: 'black', strokeWidth: 1, selectable: true, @@ -422,7 +426,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { }) const rightTriangle = new QPolygon(splitedTriangle[1], { - fill: 'transparent', + fill: 'white', stroke: 'black', strokeWidth: 1, selectable: true, @@ -450,7 +454,33 @@ export function useObjectBatch({ isHidden, setIsHidden }) { drawDirectionArrow(leftTriangle) drawDirectionArrow(rightTriangle) - const objectGroup = new fabric.Group([leftTriangle, rightTriangle], { + let offsetPolygon + + if (offsetRef > 0) { + canvas?.remove(dormer) + + offsetPolygon = new QPolygon(triangleToPolygon(dormer), { + selectable: true, + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + viewLengthText: true, + name: 'triangleDormerOffset', + id: id, + fill: 'rgba(255, 255, 255, 0.6)', + stroke: 'black', + strokeWidth: 1, + originX: 'center', + originY: 'center', + fontSize: lengthTextFont.fontSize.value, + fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', + fontWeight: lengthTextFont.fontWeight.value, + }) + } + + const groupPolygon = offsetPolygon ? [leftTriangle, rightTriangle, offsetPolygon] : [leftTriangle, rightTriangle] + + const objectGroup = new fabric.Group(groupPolygon, { subTargetCheck: true, name: dormerName, id: id, @@ -796,10 +826,102 @@ export function useObjectBatch({ isHidden, setIsHidden }) { return [leftPoints, rightPoints] } + const reSizeObject = (side, target, width, height) => { + console.log('reSizeTarget', target) + + target.getObjects().forEach((obj) => { + console.log('obj', obj.type) + }) + + const objectWidth = target.width + const objectHeight = target.height + const changeWidth = (width / 10 / objectWidth).toFixed(2) + const changeHeight = (height / 10 / objectHeight).toFixed(2) + let sideX = 'left' + let sideY = 'top' + + //그룹 중심점 변경 + if (side === 2) { + sideX = 'right' + sideY = 'top' + } else if (side === 3) { + sideX = 'left' + sideY = 'bottom' + } else if (side === 4) { + sideX = 'right' + sideY = 'bottom' + } + + //변경 전 좌표 + const newCoords = target.getPointByOrigin(sideX, sideY) + + target.set({ + ...target, + originX: sideX, + originY: sideY, + left: newCoords.x, + top: newCoords.y, + }) + + target.setCoords() + canvas?.renderAll() //변경 좌표를 한번 적용 + + target.scaleX = changeWidth === 0 ? 1 : changeWidth + target.scaleY = changeHeight === 0 ? 1 : changeHeight + + //크기 변경후 좌표를 재 적용 + const changedCoords = target.getPointByOrigin('center', 'center') + + target.set({ + ...target, + originX: 'center', + originY: 'center', + left: changedCoords.x, + top: changedCoords.y, + }) + + if (target.name === 'roof') { + //얘는 일단 도머에 적용함 + target._objects.forEach((obj) => { + setSurfaceShapePattern(obj) + }) + } + // target.setCoords() + canvas.renderAll() + + // reGroupObject(target) + } + + const reGroupObject = (groupObj) => { + groupObj._restoreObjectsState() //이건 실행만 되도 그룹이 변경됨 + const reGroupObjects = [] + + groupObj._objects.forEach((obj) => { + const newObj = new QPolygon(obj.getCurrentPoints(), { + ...obj, + points: obj.getCurrentPoints(), + scaleX: 1, + scaleY: 1, + }) + reGroupObjects.push(newObj) + canvas.remove(obj) + }) + + const reGroup = new fabric.Group(reGroupObjects, { + subTargetCheck: true, + name: groupObj.name, + id: groupObj.id, + groupYn: true, + }) + canvas?.add(reGroup) + canvas?.remove(groupObj) + } + return { applyOpeningAndShadow, applyDormers, splitDormerTriangle, splitDormerPentagon, + reSizeObject, } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 3fd1bb0e..f8dc92b5 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -273,16 +273,19 @@ export function useContextMenu() { id: 'dormerRemove', shortcut: ['d', 'D'], name: `${getMessage('contextmenu.remove')}(D)`, + fn: () => deleteObject(), }, { id: 'dormerMove', shortcut: ['m', 'M'], name: `${getMessage('contextmenu.move')}(M)`, + fn: () => moveObject(), }, { id: 'dormerCopy', shortcut: ['c', 'C'], name: `${getMessage('contextmenu.copy')}(C)`, + fn: () => copyObject(), }, { id: 'roofMaterialEdit', @@ -451,7 +454,7 @@ export function useContextMenu() { ], ]) break - case 'dimensionLine': + case 'dimensionGroup': setContextMenu([ [ { diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 897c8a54..bddebc63 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -55,40 +55,40 @@ export function usePlan() { /** * 현재 캔버스에 그려진 데이터를 추출 */ - const currentCanvasData = () => { + const currentCanvasData = (mode = '') => { removeMouseLines() - const groups = canvas.getObjects().filter((obj) => obj.type === 'group') + if (mode === 'save') { + const groups = canvas.getObjects().filter((obj) => obj.type === 'group') - console.log('groups', groups) - - if (groups.length > 0) { - groups.forEach((group) => { - canvas?.remove(group) - canvas?.renderAll() - const restore = group._restoreObjectsState() //그룹 좌표 복구 - - //그룹시 좌표가 틀어지는 이슈 - restore._objects.forEach((obj) => { - obj.set({ - ...obj, - groupYn: true, - groupName: group.name, - groupId: group.id, - }) - - //디렉션이 있는 경우에만 - if (group.lineDirection) { - obj.set({ - lineDirection: group.lineDirection, - }) - } - - canvas?.add(obj) - obj.setCoords() + if (groups.length > 0) { + groups.forEach((group) => { + canvas?.remove(group) canvas?.renderAll() + const restore = group._restoreObjectsState() //그룹 좌표 복구 + + //그룹시 좌표가 틀어지는 이슈 + restore._objects.forEach((obj) => { + obj.set({ + ...obj, + groupYn: true, + groupName: group.name, + groupId: group.id, + }) + + //디렉션이 있는 경우에만 + if (group.lineDirection) { + obj.set({ + lineDirection: group.lineDirection, + }) + } + + canvas?.add(obj) + obj.setCoords() + canvas?.renderAll() + }) }) - }) + } } return addCanvas() @@ -172,7 +172,7 @@ export function usePlan() { * 페이지 내 캔버스를 저장 */ const saveCanvas = async (userId) => { - const canvasStatus = currentCanvasData() + const canvasStatus = currentCanvasData('save') initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id) ? await putCanvasStatus(canvasStatus) : await postCanvasStatus(userId, canvasStatus) From 223bf2dddf631c93ad9b43f1c9bd9172b728842d Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 1 Nov 2024 17:46:58 +0900 Subject: [PATCH 10/63] =?UTF-8?q?=EC=98=A4=EA=B0=81=ED=98=95=20=EB=8F=84?= =?UTF-8?q?=EB=A8=B8=20=ED=81=AC=EA=B8=B0=EB=B3=80=EA=B2=BD,=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/object/SizeSetting.jsx | 4 +- .../modal/object/type/PentagonDormer.jsx | 4 +- src/hooks/common/useCommonUtils.js | 5 +- src/hooks/object/useObjectBatch.js | 72 +++++++++++++++++-- src/hooks/useContextMenu.js | 5 +- src/hooks/usePolygon.js | 6 ++ 6 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/components/floor-plan/modal/object/SizeSetting.jsx b/src/components/floor-plan/modal/object/SizeSetting.jsx index af239258..1b20b853 100644 --- a/src/components/floor-plan/modal/object/SizeSetting.jsx +++ b/src/components/floor-plan/modal/object/SizeSetting.jsx @@ -15,7 +15,7 @@ export default function SizeSetting(props) { const { id, pos = contextPopupPosition, target } = props const { getMessage } = useMessage() const { closePopup } = usePopup() - const { reSizeObject } = useObjectBatch() + const { reSizeObjectBatch } = useObjectBatch({}) const widthRef = useRef(null) const heightRef = useRef(null) @@ -30,7 +30,7 @@ export default function SizeSetting(props) { const width = widthRef.current.value const height = heightRef.current.value - reSizeObject(settingTarget, target, width, height) + reSizeObjectBatch(settingTarget, target, width, height) } return ( diff --git a/src/components/floor-plan/modal/object/type/PentagonDormer.jsx b/src/components/floor-plan/modal/object/type/PentagonDormer.jsx index 73f9c5d8..c67a08fc 100644 --- a/src/components/floor-plan/modal/object/type/PentagonDormer.jsx +++ b/src/components/floor-plan/modal/object/type/PentagonDormer.jsx @@ -38,7 +38,7 @@ const PentagonDormer = forwardRef((props, refs) => {
- +
mm
@@ -60,7 +60,7 @@ const PentagonDormer = forwardRef((props, refs) => {
- +
mm
diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index 356c100e..2902e0c3 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -20,7 +20,6 @@ export function useCommonUtils() { const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText')) const commonTextFont = useRecoilValue(fontSelector('commonText')) const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState) - const { addPopup } = usePopup() useEffect(() => { @@ -749,12 +748,14 @@ export function useCommonUtils() { left: originObjLeft, top: originObjTop, }) + obj.fire('modified') } else { // 다른 객체의 경우 left, top 절대 좌표 설정 obj.set({ left: obj.left, top: obj.top, }) + obj.fire('modified') } obj.setCoords() // 좌표 반영 }) @@ -777,12 +778,14 @@ export function useCommonUtils() { left: originObjLeft, top: originObjTop, }) + obj.fire('modified') } else { targetObj.set({ ...targetObj, left: targetObj.left, top: targetObj.top, }) + obj.fire('modified') } targetObj.setCoords() } diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index c55841c6..df9c64ba 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -43,8 +43,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) { // 클릭한 위치에 있는 객체 찾기 const clickedObject = objects.find((obj) => { - console.log(obj) - if (obj.type === 'QPolygon') { const polygon = pointsToTurfPolygon(obj.getCurrentPoints()) const turfPointer = turf.point([pointer.x, pointer.y]) @@ -451,6 +449,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { setSurfaceShapePattern(leftTriangle) setSurfaceShapePattern(rightTriangle) //방향 + drawDirectionArrow(leftTriangle) drawDirectionArrow(rightTriangle) @@ -654,8 +653,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) { pitch: pitch, }) - canvas?.add(leftPentagon) - canvas?.add(rightPentagon) + // canvas?.add(leftPentagon) + // canvas?.add(rightPentagon) //패턴 setSurfaceShapePattern(leftPentagon) @@ -664,6 +663,39 @@ export function useObjectBatch({ isHidden, setIsHidden }) { drawDirectionArrow(leftPentagon) drawDirectionArrow(rightPentagon) + let offsetPolygon + + if (offsetRef > 0) { + canvas?.remove(dormer) + + offsetPolygon = new QPolygon(dormer.points, { + selectable: true, + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + viewLengthText: true, + name: 'pentagonDormerOffset', + id: id, + fill: 'rgba(255, 255, 255, 0.6)', + stroke: 'black', + strokeWidth: 1, + originX: 'center', + originY: 'center', + fontSize: lengthTextFont.fontSize.value, + fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', + fontWeight: lengthTextFont.fontWeight.value, + }) + } + + const groupPolygon = offsetPolygon ? [leftPentagon, rightPentagon, offsetPolygon] : [leftPentagon, rightPentagon] + + const objectGroup = new fabric.Group(groupPolygon, { + subTargetCheck: true, + name: dormerName, + id: id, + }) + canvas?.add(objectGroup) + isDown = false initEvent() @@ -826,7 +858,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { return [leftPoints, rightPoints] } - const reSizeObject = (side, target, width, height) => { + const reSizeObjectBatch = (side, target, width, height) => { console.log('reSizeTarget', target) target.getObjects().forEach((obj) => { @@ -889,7 +921,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { // target.setCoords() canvas.renderAll() - // reGroupObject(target) + reGroupObject(target) } const reGroupObject = (groupObj) => { @@ -905,6 +937,10 @@ export function useObjectBatch({ isHidden, setIsHidden }) { }) reGroupObjects.push(newObj) canvas.remove(obj) + + if (obj.direction) { + drawDirectionArrow(obj) + } }) const reGroup = new fabric.Group(reGroupObjects, { @@ -917,11 +953,33 @@ export function useObjectBatch({ isHidden, setIsHidden }) { canvas?.remove(groupObj) } + const moveObjectBatch = () => { + const obj = canvas.getActiveObject() + + if (obj) { + obj.set({ + lockMovementX: false, + lockMovementY: false, + }) + + addCanvasMouseEventListener('mouse:up', (e) => { + obj.set({ + lockMovementX: true, + lockMovementY: true, + }) + initEvent() + obj.setCoords() + reGroupObject(obj) + }) + } + } + return { applyOpeningAndShadow, applyDormers, splitDormerTriangle, splitDormerPentagon, - reSizeObject, + reSizeObjectBatch, + moveObjectBatch, } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index f8dc92b5..79eacd4c 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -21,7 +21,6 @@ import LinePropertySetting from '@/components/floor-plan/modal/lineProperty/Line import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/FlowDirectionSetting' import { useCommonUtils } from './common/useCommonUtils' -import { useObjectBatch } from './object/useObjectBatch' import { useMessage } from '@/hooks/useMessage' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { contextMenuListState, contextMenuState } from '@/store/contextMenu' @@ -33,6 +32,7 @@ import ColumnInsert from '@/components/floor-plan/modal/module/column/ColumnInse import RowRemove from '@/components/floor-plan/modal/module/row/RowRemove' import RowInsert from '@/components/floor-plan/modal/module/row/RowInsert' import CircuitNumberEdit from '@/components/floor-plan/modal/module/CircuitNumberEdit' +import { useObjectBatch } from '@/hooks/object/useObjectBatch' export function useContextMenu() { const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 @@ -49,6 +49,7 @@ export function useContextMenu() { const [cell, setCell] = useState(null) const [column, setColumn] = useState(null) const { handleZoomClear } = useCanvasEvent() + const { moveObjectBatch } = useObjectBatch({}) const currentMenuSetting = () => { switch (currentMenu) { @@ -279,7 +280,7 @@ export function useContextMenu() { id: 'dormerMove', shortcut: ['m', 'M'], name: `${getMessage('contextmenu.move')}(M)`, - fn: () => moveObject(), + fn: () => moveObjectBatch(), }, { id: 'dormerCopy', diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index c147e2fe..5a7d3062 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -113,6 +113,12 @@ export const usePolygon = () => { return } + //동일 아이디가 있으면 일단 지우고 다시 그린다 + const existArrow = polygon.canvas.getObjects().filter((obj) => obj.name === 'arrow' && obj.parentId === polygon.id) + if (existArrow.length > 0) { + polygon.canvas.remove(...existArrow) + } + polygon.canvas .getObjects() .filter((obj) => obj.name === 'flowText' && obj.parent === polygon.arrow) From 51c4fcfe1462e0c82b0ff1c33422d3e886e88e1c Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 1 Nov 2024 18:10:27 +0900 Subject: [PATCH 11/63] =?UTF-8?q?canvas=20menu=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20zoom=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasMenu.jsx | 12 ++++++++---- src/hooks/useCanvasEvent.js | 15 ++++++++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 63f1840d..c77e1870 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -49,7 +49,7 @@ export default function CanvasMenu(props) { const sessionState = useRecoilValue(sessionStore) const globalLocale = useRecoilValue(globalLocaleStore) const canvas = useRecoilValue(canvasState) - const { handleZoomClear } = useCanvasEvent() + const { handleZoomClear, handleZoom } = useCanvasEvent() const { handleMenu } = useMenu() const { getMessage } = useMessage() @@ -201,14 +201,18 @@ export default function CanvasMenu(props) { {canvasZoom}% - +
-
diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index ad3e8e75..4bab1fd6 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' import { v4 as uuidv4 } from 'uuid' import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' @@ -18,6 +18,10 @@ export function useCanvasEvent() { const lengthTextOption = useRecoilValue(fontSelector('lengthText')) const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan() + useEffect(() => { + canvas?.setZoom(canvasZoom / 100) + }, [canvasZoom]) + // 기본적인 이벤트 필요시 추가 const attachDefaultEventOnCanvas = () => { removeEventOnCanvas() @@ -365,6 +369,14 @@ export function useCanvasEvent() { }) } + const handleZoom = (isZoom) => { + if (isZoom) { + setCanvasZoom(canvasZoom + 10) + } else { + setCanvasZoom(canvasZoom - 10) + } + } + const handleZoomClear = () => { setCanvasZoom(100) canvas.set({ zoom: 1 }) @@ -376,5 +388,6 @@ export function useCanvasEvent() { setCanvasForEvent, attachDefaultEventOnCanvas, handleZoomClear, + handleZoom, } } From ea8b4a3e36570f2b26a4c0aaeafb73ec2c8a0aff Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 1 Nov 2024 18:10:42 +0900 Subject: [PATCH 12/63] =?UTF-8?q?contextmenu=20modal=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/context-menu/QContextMenu.jsx | 3 +++ src/hooks/useContextMenu.js | 13 +++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/common/context-menu/QContextMenu.jsx b/src/components/common/context-menu/QContextMenu.jsx index f710485f..9d3eb4f3 100644 --- a/src/components/common/context-menu/QContextMenu.jsx +++ b/src/components/common/context-menu/QContextMenu.jsx @@ -3,12 +3,14 @@ import { useEffect } from 'react' import '@/styles/contents.scss' import { useRecoilState } from 'recoil' import { contextMenuListState, contextMenuState } from '@/store/contextMenu' +import { useTempGrid } from '@/hooks/useTempGrid' export default function QContextMenu(props) { const { contextRef, canvasProps, handleKeyup } = props const [contextMenu, setContextMenu] = useRecoilState(contextMenuState) const [contextMenuList, setContextMenuList] = useRecoilState(contextMenuListState) const activeObject = canvasProps?.getActiveObject() //액티브된 객체를 가져옴 + const { tempGridMode, setTempGridMode } = useTempGrid() let contextType = '' @@ -32,6 +34,7 @@ export default function QContextMenu(props) { const handleContextMenu = (e) => { // e.preventDefault() //기존 contextmenu 막고 + if (tempGridMode) return const position = { x: window.innerWidth / 2 < e.pageX ? e.pageX - 240 : e.pageX, y: window.innerHeight / 2 < e.pageY ? getYPosition(e) : e.pageY, diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 8a6226a1..ccc8b8d8 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -43,12 +43,11 @@ export function useContextMenu() { const { addPopup } = usePopup() const [popupId, setPopupId] = useState(uuidv4()) const [gridColor, setGridColor] = useRecoilState(gridColorState) - const { deleteObject, moveObject, copyObject, editText, changeDimensionExtendLine } = useCommonUtils() + const { deleteObject, moveObject, copyObject, editText, changeDimensionExtendLine, deleteOuterLineObject } = useCommonUtils() const [qContextMenu, setQContextMenu] = useRecoilState(contextMenuState) const [cell, setCell] = useState(null) const [column, setColumn] = useState(null) const { handleZoomClear } = useCanvasEvent() - const currentMenuSetting = () => { switch (currentMenu) { case MENU.PLAN_DRAWING: @@ -172,6 +171,7 @@ export function useContextMenu() { { id: 'sizeEdit', name: getMessage('contextmenu.size.edit'), + component: , }, { id: 'remove', @@ -207,6 +207,7 @@ export function useContextMenu() { { id: 'flowDirectionEdit', name: getMessage('contextmenu.flow.direction.edit'), + component: , }, ], ]) @@ -241,7 +242,7 @@ export function useContextMenu() { if (temp.length > 0) menu = temp } - handleClick(null, menu) + if (menu) handleClick(null, menu) } useEffect(() => { @@ -342,6 +343,7 @@ export function useContextMenu() { { id: 'sizeEdit', name: getMessage('contextmenu.size.edit'), + component: , }, { id: 'openingRemove', @@ -419,19 +421,23 @@ export function useContextMenu() { ]) break case 'lineGrid': + case 'tempGrid': setContextMenu([ [ { id: 'gridMove', name: getMessage('modal.grid.move'), + component: , }, { id: 'gridCopy', name: getMessage('modal.grid.copy'), + component: , }, { id: 'gridColorEdit', name: getMessage('contextmenu.grid.color.edit'), + component: , }, { id: 'remove', @@ -561,7 +567,6 @@ export function useContextMenu() { ]) break case 'module': - case 'dimensionLineText': setContextMenu([ [ { From 88ffb2c4ee40720f87521e5e96f64f5e434183c2 Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 1 Nov 2024 18:11:05 +0900 Subject: [PATCH 13/63] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=20=EB=A7=81?= =?UTF-8?q?=ED=81=AC=20=EC=88=98=EC=A0=95,=20=20canvasMenu=EC=97=90=20?= =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=20=EC=9D=B8=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasMenu.jsx | 2 +- src/components/management/StuffSubHeader.jsx | 11 ++++++++--- src/locales/ja.json | 13 +++++++------ src/locales/ko.json | 13 +++++++------ 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 63f1840d..6ac20787 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -220,7 +220,7 @@ export default function CanvasMenu(props) {
- diff --git a/src/locales/ja.json b/src/locales/ja.json index c57582b2..e4605537 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -814,7 +814,10 @@ "estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG単価 (W)×PKG容量(W)", "estimate.detail.header.showPrice": "価格表示", "estimate.detail.showPrice.btn1": "Pricing", - "estimate.detail.showPrice.description": "クリックして製品の特異性を確認する", + "estimate.detail.showPrice.description1": "製品価格 OPEN", + "estimate.detail.showPrice.description2": "追加, 変更資材", + "estimate.detail.showPrice.description3": "添付必須", + "estimate.detail.showPrice.description4": "クリックして製品の特異性を確認する", "estimate.detail.showPrice.btn2": "製品を追加", "estimate.detail.showPrice.btn3": "製品削除" } diff --git a/src/locales/ko.json b/src/locales/ko.json index 1cb2c279..03443a0b 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -820,7 +820,10 @@ "estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG단가(W) * PKG용량(W)", "estimate.detail.header.showPrice": "가격표시", "estimate.detail.showPrice.btn1": "Pricing", - "estimate.detail.showPrice.description": "클릭하여 제품 특이사항 확인", + "estimate.detail.showPrice.description1": "제품 가격 OPEN", + "estimate.detail.showPrice.description2": "추가, 변경 자재", + "estimate.detail.showPrice.description3": "첨부필수", + "estimate.detail.showPrice.description4": "클릭하여 제품 특이사항 확인", "estimate.detail.showPrice.btn2": "제품추가", "estimate.detail.showPrice.btn3": "제품삭제" } From 0adfe0916c496e3503818cf4ed7eabbb848ccf26 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 4 Nov 2024 14:46:38 +0900 Subject: [PATCH 19/63] =?UTF-8?q?polygon=20name=20=EC=88=98=EC=A0=95,=20?= =?UTF-8?q?=EC=A7=80=EB=B6=95=20=EB=82=98=EB=88=84=EA=B8=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/option/useCanvasSetting.js | 8 +- src/hooks/option/useFirstOption.js | 8 +- src/hooks/roofcover/useAuxiliaryDrawing.js | 19 +- src/hooks/roofcover/useEavesGableEdit.js | 8 +- src/hooks/roofcover/useMovementSetting.js | 5 +- src/hooks/roofcover/usePropertiesSetting.js | 4 +- .../roofcover/useRoofAllocationSetting.js | 11 +- .../roofcover/useRoofShapePassivitySetting.js | 10 +- src/hooks/roofcover/useRoofShapeSetting.js | 10 +- src/store/settingAtom.js | 2 +- src/util/canvas-util.js | 6 +- src/util/qpolygon-utils.js | 257 +++++++++++++++++- 12 files changed, 299 insertions(+), 49 deletions(-) diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js index 0f87e156..2b2ea3c5 100644 --- a/src/hooks/option/useCanvasSetting.js +++ b/src/hooks/option/useCanvasSetting.js @@ -225,9 +225,9 @@ export function useCanvasSetting() { const option1 = settingModalFirstOptions.option1 // 'allocDisplay' 할당 표시 - // 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine' + // 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL // 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid' - // 'lineDisplay' 지붕선 표시 'roof', 'roofBase' + // 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF // 'wordDisplay' 문자 표시 // 'circuitNumDisplay' 회로번호 표시 // 'flowDisplay' 흐름방향 표시 'arrow' @@ -244,13 +244,13 @@ export function useCanvasSetting() { optionName = ['1'] break case 'outlineDisplay': //외벽선 표시 - optionName = ['outerLine', 'wallLine'] + optionName = ['outerLine', POLYGON_TYPE.WALL] break case 'gridDisplay': //그리드 표시 optionName = ['lindGrid', 'dotGrid'] break case 'lineDisplay': //지붕선 표시 - optionName = ['roof', 'roofBase'] + optionName = ['roof', POLYGON_TYPE.ROOF] break case 'wordDisplay': //문자 표시 optionName = ['6'] diff --git a/src/hooks/option/useFirstOption.js b/src/hooks/option/useFirstOption.js index c3778587..4b85b4c4 100644 --- a/src/hooks/option/useFirstOption.js +++ b/src/hooks/option/useFirstOption.js @@ -12,9 +12,9 @@ export function useFirstOption() { const option1 = settingModalFirstOptions.option1 // 'allocDisplay' 할당 표시 - // 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine' + // 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL // 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid' - // 'lineDisplay' 지붕선 표시 'roof', 'roofBase' + // 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF // 'wordDisplay' 문자 표시 // 'circuitNumDisplay' 회로번호 표시 // 'flowDisplay' 흐름방향 표시 'arrow' @@ -30,13 +30,13 @@ export function useFirstOption() { optionName = ['1'] break case 'outlineDisplay': //외벽선 표시 - optionName = ['outerLine', 'wallLine'] + optionName = ['outerLine', POLYGON_TYPE.WALL] break case 'gridDisplay': //그리드 표시 optionName = ['lineGrid', 'dotGrid', 'adsorptionPoint', 'tempGrid'] break case 'lineDisplay': //지붕선 표시 - optionName = ['roof', 'roofBase'] + optionName = ['roof', POLYGON_TYPE.ROOF] break case 'wordDisplay': //문자 표시 optionName = ['6'] diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index 956bcf8f..72b094c9 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -15,7 +15,7 @@ import { outerLineLength2State, outerLineTypeState, } from '@/store/outerLineAtom' -import { calculateIntersection, distanceBetweenPoints, findClosestPoint, polygonToTurfPolygon } from '@/util/canvas-util' +import { calculateIntersection, distanceBetweenPoints, findClosestPoint, isPointOnLine, polygonToTurfPolygon } from '@/util/canvas-util' import { fabric } from 'fabric' import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useSwal } from '@/hooks/useSwal' @@ -23,6 +23,7 @@ import { booleanPointInPolygon } from '@turf/turf' import { usePopup } from '@/hooks/usePopup' import { calculateAngle } from '@/util/qpolygon-utils' import { QPolygon } from '@/components/fabric/QPolygon' +import { POLYGON_TYPE } from '@/common/common' // 보조선 작성 export function useAuxiliaryDrawing(id) { @@ -80,7 +81,7 @@ export function useAuxiliaryDrawing(id) { useEffect(() => { // innerLines가 있을경우 삭제 - const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roofBase') + const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) if (roofs.length === 0) { swalFire({ text: '지붕형상이 없습니다.' }) closePopup(id) @@ -561,7 +562,7 @@ export function useAuxiliaryDrawing(id) { return } - const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') + const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) /*const allLines = [...auxiliaryLines] roofBases.forEach((roofBase) => { @@ -611,6 +612,7 @@ export function useAuxiliaryDrawing(id) { }, ) lineHistory.current.push(newLine) + lineHistory.current = lineHistory.current.filter((history) => history !== line1) removeLine(line1) intersectionPoints.current.push(...interSectionPointsWithRoofLines) return @@ -659,6 +661,7 @@ export function useAuxiliaryDrawing(id) { }) } lineHistory.current.push(newLine) + lineHistory.current = lineHistory.current.filter((history) => history !== line1) removeLine(line1) }) @@ -742,7 +745,7 @@ export function useAuxiliaryDrawing(id) { return } - const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') + const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) //lineHistory.current에 있는 선들 중 startPoint와 endPoint가 겹치는 line은 제거 // 겹치는 선 하나는 canvas에서 제거한다. @@ -772,9 +775,13 @@ export function useAuxiliaryDrawing(id) { }) const roofInnerLines = innerLines.filter((line) => { const inPolygon1 = - tempPolygonPoints.some((point) => point.x === line.x1 && point.y === line.y1) || roofBase.inPolygon({ x: line.x1, y: line.y1 }) + tempPolygonPoints.some((point) => point.x === line.x1 && point.y === line.y1) || + roofBase.inPolygon({ x: line.x1, y: line.y1 }) || + roofBase.lines.some((line) => isPointOnLine(line, { x: line.x1, y: line.y1 })) const inPolygon2 = - tempPolygonPoints.some((point) => point.x === line.x2 && point.y === line.y2) || roofBase.inPolygon({ x: line.x2, y: line.y2 }) + tempPolygonPoints.some((point) => point.x === line.x2 && point.y === line.y2) || + roofBase.inPolygon({ x: line.x2, y: line.y2 }) || + roofBase.lines.some((line) => isPointOnLine(line, { x: line.x2, y: line.y2 })) if (inPolygon1 && inPolygon2) { line.attributes = { ...line.attributes, roofId: roofBase.id } diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index 7696dc7a..5619abfb 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil' import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' -import { LINE_TYPE } from '@/common/common' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { useLine } from '@/hooks/useLine' import { useMode } from '@/hooks/useMode' import { outerLineFixState } from '@/store/outerLineAtom' @@ -54,7 +54,7 @@ export function useEavesGableEdit(id) { }, []) useEffect(() => { - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) wallLines.forEach((wallLine) => { convertPolygonToLines(wallLine) }) @@ -160,7 +160,7 @@ export function useEavesGableEdit(id) { attributes, }) - const roofBases = canvas?.getObjects().filter((obj) => obj.name === 'roofBase') + const roofBases = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) roofBases.forEach((roof) => { roof.innerLines.forEach((line) => { @@ -169,7 +169,7 @@ export function useEavesGableEdit(id) { canvas.remove(roof) }) - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'pitchText') removeTargets.forEach((obj) => { canvas.remove(obj) diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js index f0814a44..f09aee6b 100644 --- a/src/hooks/roofcover/useMovementSetting.js +++ b/src/hooks/roofcover/useMovementSetting.js @@ -4,6 +4,7 @@ import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' import { useEffect, useRef, useState } from 'react' import { useEvent } from '@/hooks/useEvent' +import { POLYGON_TYPE } from '@/common/common' //동선이동 형 올림 내림 export function useMovementSetting(id) { @@ -41,7 +42,7 @@ export function useMovementSetting(id) { }, [type]) useEffect(() => { - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 wallLine의 visible false + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) // 기존 wallLine의 visible false wallLines.forEach((line) => { line.set({ visible: false }) }) @@ -55,7 +56,7 @@ export function useMovementSetting(id) { addCanvasMouseEventListener('mouse:move', mouseMoveEvent) return () => { initEvent() - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) wallLines.forEach((line) => { line.set({ visible: true }) }) diff --git a/src/hooks/roofcover/usePropertiesSetting.js b/src/hooks/roofcover/usePropertiesSetting.js index b999c001..3a1535a3 100644 --- a/src/hooks/roofcover/usePropertiesSetting.js +++ b/src/hooks/roofcover/usePropertiesSetting.js @@ -1,5 +1,5 @@ import { useEffect, useRef } from 'react' -import { LINE_TYPE } from '@/common/common' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { canvasState, currentObjectState } from '@/store/canvasAtom' import { useMode } from '@/hooks/useMode' @@ -135,7 +135,7 @@ export function usePropertiesSetting(id) { hideLine(line) }) - const wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' }) + const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) wall.lines = [...lines] diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 3be745d6..c229549e 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -7,6 +7,7 @@ import { useSwal } from '@/hooks/useSwal' import { usePolygon } from '@/hooks/usePolygon' import { roofDisplaySelector } from '@/store/settingAtom' import { usePopup } from '@/hooks/usePopup' +import { POLYGON_TYPE } from '@/common/common' // 지붕면 할당 export function useRoofAllocationSetting(id) { @@ -81,12 +82,12 @@ export function useRoofAllocationSetting(id) { const [selectedRoofMaterial, setSelectedRoofMaterial] = useState(roofMaterials[0]) useEffect(() => { - const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') + const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) if (roofBases.length === 0) { swalFire({ text: '할당할 지붕이 없습니다.' }) closePopup(id) } - // if (type === 'roofBase') { + // if (type === POLYGON_TYPE.ROOF) { // // 지붕면 할당 // // } else if ('roof') { @@ -104,8 +105,8 @@ export function useRoofAllocationSetting(id) { // 선택한 지붕재로 할당 const handleSave = () => { - const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) roofBases.forEach((roofBase) => { try { splitPolygonWithLines(roofBase) @@ -117,7 +118,7 @@ export function useRoofAllocationSetting(id) { canvas.remove(line) }) - canvas.remove(roofBase) + // canvas.remove(roofBase) }) wallLines.forEach((wallLine) => { diff --git a/src/hooks/roofcover/useRoofShapePassivitySetting.js b/src/hooks/roofcover/useRoofShapePassivitySetting.js index ef7a4477..e0af3205 100644 --- a/src/hooks/roofcover/useRoofShapePassivitySetting.js +++ b/src/hooks/roofcover/useRoofShapePassivitySetting.js @@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from 'react' import { useLine } from '@/hooks/useLine' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' -import { LINE_TYPE } from '@/common/common' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { useMode } from '@/hooks/useMode' import { usePolygon } from '@/hooks/usePolygon' import { outerLineFixState } from '@/store/outerLineAtom' @@ -60,7 +60,7 @@ export function useRoofShapePassivitySetting(id) { useEffect(() => { if (!isLoading) return addCanvasMouseEventListener('mouse:down', mouseDown) - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) canvas?.remove(...wallLines) @@ -185,7 +185,7 @@ export function useRoofShapePassivitySetting(id) { } const handleLineToPolygon = () => { - const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') + const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine') const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') exceptObjs.forEach((obj) => { @@ -199,10 +199,10 @@ export function useRoofShapePassivitySetting(id) { let wall if (isFix.current) { - wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' }) + wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) } else { // 그냥 닫을 경우 처리 - wall = addPolygonByLines([...initLines.current], { name: 'wallLine', fill: 'transparent', stroke: 'black' }) + wall = addPolygonByLines([...initLines.current], { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) lines.forEach((line, idx) => { line.attributes = initLines.current[idx].attributes }) diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index ae886ce9..2823415d 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useRecoilValue, useSetRecoilState } from 'recoil' import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState, pitchTextSelector } from '@/store/canvasAtom' -import { LINE_TYPE } from '@/common/common' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { usePolygon } from '@/hooks/usePolygon' import { useMode } from '@/hooks/useMode' import { useLine } from '@/hooks/useLine' @@ -129,7 +129,7 @@ export function useRoofShapeSetting(id) { useEffect(() => { if (shapeNum === 4) { - canvas?.remove(canvas.getObjects().find((obj) => obj.name === 'wallLine')) + canvas?.remove(canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL)) const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') outerLines.forEach((line) => { showLine(line) @@ -376,20 +376,20 @@ export function useRoofShapeSetting(id) { // 기존 wallLine, roofBase 제거 canvas .getObjects() - .filter((obj) => obj.name === 'wallLine') + .filter((obj) => obj.name === POLYGON_TYPE.WALL) .forEach((line) => { canvas.remove(line) }) canvas .getObjects() - .filter((obj) => obj.name === 'roofBase') + .filter((obj) => obj.name === POLYGON_TYPE.ROOF) .forEach((obj) => { canvas.remove(...obj.innerLines) canvas.remove(obj) }) - const polygon = addPolygonByLines(outerLines, { name: 'wallLine' }) + const polygon = addPolygonByLines(outerLines, { name: POLYGON_TYPE.WALL }) polygon.lines = [...outerLines] addPitchTextsByOuterLines() diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index 9679d2d7..fede515e 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -5,7 +5,7 @@ export const settingModalFirstOptionsState = atom({ default: { option1: [ { id: 1, column: 'allocDisplay', name: 'modal.canvas.setting.first.option.alloc', selected: false }, - { id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: false }, + { id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: true }, { id: 3, column: 'gridDisplay', name: 'modal.canvas.setting.first.option.grid', selected: false }, { id: 4, column: 'lineDisplay', name: 'modal.canvas.setting.first.option.roof.line', selected: false }, { id: 5, column: 'wordDisplay', name: 'modal.canvas.setting.first.option.word', selected: false }, diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index be2249a6..1a78f991 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -521,9 +521,11 @@ export function isPointOnLine(line, point) { const a = line.y2 - line.y1 const b = line.x1 - line.x2 const c = line.x2 * line.y1 - line.x1 * line.y2 - return a * point.x + b * point.y + c === 0 -} + const result = Math.abs(a * point.x + b * point.y + c) / 100 + // 점이 선 위에 있는지 확인 + return result <= 10 +} /** * 점과 가까운 line 찾기 * @param point diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 8e9c3553..65cbc96d 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1,6 +1,14 @@ import { fabric } from 'fabric' import { QLine } from '@/components/fabric/QLine' -import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDegreeByChon, getDirectionByPoint } from '@/util/canvas-util' +import { + calculateIntersection, + distanceBetweenPoints, + findClosestPoint, + getDegreeByChon, + getDirectionByPoint, + isPointOnLine, +} from '@/util/canvas-util' + import { QPolygon } from '@/components/fabric/QPolygon' import * as turf from '@turf/turf' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' @@ -957,10 +965,13 @@ export default function offsetPolygon(vertices, offset) { } } -export const splitPolygonWithLines = (polygon) => { +/*export const splitPolygonWithLines = (polygon) => { const roofs = [] const allLines = [...polygon.innerLines] + const polygonLines = polygon.lines + const innerLines = polygon.innerLines + allLines.forEach((line) => { line.startPoint = { x: line.x1, y: line.y1 } line.endPoint = { x: line.x2, y: line.y2 } @@ -983,10 +994,10 @@ export const splitPolygonWithLines = (polygon) => { }) }) - /** + /!** * 좌표 테스트용 - */ - /*allLines.forEach((line) => { + *!/ + /!*allLines.forEach((line) => { const text = new fabric.Text(`(${line.startPoint.x},${line.startPoint.y})`, { left: line.startPoint.x, top: line.startPoint.y, @@ -1015,10 +1026,10 @@ export const splitPolygonWithLines = (polygon) => { polygon.canvas.add(text) polygon.canvas.renderAll() - })*/ - /** + })*!/ + /!** * 좌표 테스트용 끝 - */ + *!/ polygon.points.forEach((point, index) => { allLines.forEach((line) => { @@ -1164,6 +1175,233 @@ export const splitPolygonWithLines = (polygon) => { polygon.canvas.add(roof) polygon.canvas.renderAll() }) +}*/ +export const splitPolygonWithLines = (polygon) => { + const canvas = polygon.canvas + polygon.set({ visible: false }) + let innerLines = [...polygon.innerLines] + let polygonLines = [...polygon.lines] + const roofs = [] + + let delIndexs = [] + let newLines = [] + + polygonLines.forEach((line, index) => { + line.tempIndex = index + innerLines.forEach((innerLine) => { + let newLine1, newLine2 + if (isPointOnLine(line, innerLine.startPoint)) { + // 해당 line을 startPoint로 나눈 line2개를 canvas에 추가 하고 기존 line을 제거한다. + newLine1 = new QLine([line.x1, line.y1, innerLine.startPoint.x, innerLine.startPoint.y], { + fontSize: polygon.fontSize, + stroke: 'black', + strokeWidth: 3, + }) + + newLine2 = new QLine([innerLine.startPoint.x, innerLine.startPoint.y, line.x2, line.y2], { + fontSize: polygon.fontSize, + stroke: 'black', + strokeWidth: 3, + }) + delIndexs.push(polygonLines.indexOf(line)) + canvas.remove(polygonLines[polygonLines.indexOf(line)]) + if (newLine1.length / 10 > 10) { + newLines.push(newLine1) + } + if (newLine2.length / 10 > 10) { + newLines.push(newLine2) + } + } + if (isPointOnLine(line, innerLine.endPoint)) { + newLine1 = new QLine([line.x1, line.y1, innerLine.endPoint.x, innerLine.endPoint.y], { + fontSize: polygon.fontSize, + stroke: 'black', + strokeWidth: 3, + }) + + newLine2 = new QLine([innerLine.endPoint.x, innerLine.endPoint.y, line.x2, line.y2], { + fontSize: polygon.fontSize, + stroke: 'black', + strokeWidth: 3, + }) + delIndexs.push(polygonLines.indexOf(line)) + canvas.remove(polygonLines[polygonLines.indexOf(line)]) + if (newLine1.length / 10 > 10) { + newLines.push(newLine1) + } + if (newLine2.length / 10 > 10) { + newLines.push(newLine2) + } + } + }) + }) + polygonLines = polygonLines.filter((line) => !delIndexs.includes(line.tempIndex)) + polygonLines = [...polygonLines, ...newLines] + + const allLines = [...polygonLines, ...innerLines] + + /** + * 왼쪽 상단을 startPoint로 전부 변경 + */ + allLines.forEach((line) => { + let startPoint // 시작점 + let endPoint // 끝점 + if (line.x1 < line.x2) { + startPoint = { x: line.x1, y: line.y1 } + endPoint = { x: line.x2, y: line.y2 } + } else if (line.x1 > line.x2) { + startPoint = { x: line.x2, y: line.y2 } + endPoint = { x: line.x1, y: line.y1 } + } else { + if (line.y1 < line.y2) { + startPoint = { x: line.x1, y: line.y1 } + endPoint = { x: line.x2, y: line.y2 } + } else { + startPoint = { x: line.x2, y: line.y2 } + endPoint = { x: line.x1, y: line.y1 } + } + } + + line.startPoint = startPoint + line.endPoint = endPoint + }) + + polygonLines.forEach((line) => { + const startPoint = line.startPoint // 시작점 + let arrivalPoint = line.endPoint // 도착점 + + let currentPoint = startPoint + const roofPoints = [startPoint] + + const startLine = line + const visitPoints = [startPoint] + const visitLines = [startLine] + let cnt = 0 + + while (!isSamePoint(currentPoint, arrivalPoint)) { + line.set({ stroke: 'red' }) + canvas.renderAll() + let nextLines = allLines.filter( + (line2) => + (isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) && + line !== line2 && + innerLines.includes(line2) && + !visitLines.includes(line2), + ) + + if (nextLines.length === 0) { + nextLines = allLines.filter( + (line2) => + (isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) && + line !== line2 && + !visitLines.includes(line2), + ) + } + + if (!nextLines) { + break + } + + let comparisonPoints = [] + + nextLines.forEach((nextLine) => { + if (isSamePoint(nextLine.startPoint, currentPoint)) { + comparisonPoints.push(nextLine.endPoint) + } else { + comparisonPoints.push(nextLine.startPoint) + } + }) + + comparisonPoints = comparisonPoints.filter((point) => !visitPoints.some((visitPoint) => isSamePoint(visitPoint, point))) + comparisonPoints = comparisonPoints.filter((point) => !isSamePoint(point, currentPoint)) + + const minDistancePoint = comparisonPoints.reduce((prev, current) => { + const prevDistance = Math.sqrt(Math.pow(prev.x - arrivalPoint.x, 2) + Math.pow(prev.y - arrivalPoint.y, 2)) + const currentDistance = Math.sqrt(Math.pow(current.x - arrivalPoint.x, 2) + Math.pow(current.y - arrivalPoint.y, 2)) + + return prevDistance < currentDistance ? prev : current + }, comparisonPoints[0]) + + nextLines.forEach((nextLine) => { + if (isSamePoint(nextLine.startPoint, minDistancePoint) || isSamePoint(nextLine.endPoint, minDistancePoint)) { + visitLines.push(nextLine) + } + }) + + currentPoint = { ...minDistancePoint } + roofPoints.push(currentPoint) + cnt++ + if (cnt > 100) { + throw new Error('무한루프') + } + } + roofs.push(roofPoints) + }) + + const newRoofs = removeDuplicatePolygons(roofs) + console.log(newRoofs) + newRoofs.forEach((roofPoint, index) => { + let defense, pitch + const direction = getDirectionByPoint(roofPoint[0], roofPoint[roofPoint.length - 1]) + + switch (direction) { + case 'top': + defense = 'east' + break + case 'right': + defense = 'south' + break + case 'bottom': + defense = 'west' + break + case 'left': + defense = 'north' + break + } + pitch = polygon.lines[index].attributes?.pitch ?? 0 + + const roof = new QPolygon(roofPoint, { + fontSize: polygon.fontSize, + stroke: 'black', + fill: 'transparent', + strokeWidth: 3, + name: POLYGON_TYPE.ROOF, + originX: 'center', + originY: 'center', + selectable: true, + defense: defense, + direction: defense, + pitch: pitch, + }) + + polygon.canvas.add(roof) + canvas.remove(polygon) + polygon.canvas.renderAll() + }) +} + +const removeDuplicatePolygons = (polygons) => { + const uniquePolygons = [] + + polygons.forEach((polygon) => { + const sortedPolygon = polygon + .map((point) => `${Math.floor(point.x)},${Math.floor(point.y)}`) + .sort() + .join('|') + const isDuplicate = uniquePolygons.some((uniquePolygon) => { + const sortedUniquePolygon = uniquePolygon + .map((point) => `${Math.floor(point.x)},${Math.floor(point.y)}`) + .sort() + .join('|') + return sortedPolygon === sortedUniquePolygon + }) + + if (!isDuplicate) { + uniquePolygons.push(polygon) + } + }) + + return uniquePolygons } const isSamePoint = (a, b) => { @@ -1218,6 +1456,7 @@ export const drawRidgeRoof = (roofId, canvas) => { * @param canvas */ const drawRidge = (roof, canvas) => { + debugger const wallLines = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roof.id).lines // 외벽의 라인 const roofLines = roof.lines // 지붕의 라인 let ridgeRoof = [] @@ -3312,7 +3551,7 @@ function createRoofPaddingPolygon(polygon, lines, arcSegments = 0) { } function arePointsEqual(point1, point2) { - return point1.x === point2.x && point1.y === point2.y + return Math.abs(point1.x - point2.x) < 1 && Math.abs(point1.y - point2.y) - 1 } function arraysHaveSamePoints(array1, array2) { From c60db3cda56005746c34a3fc55f97cf1bde819c0 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 4 Nov 2024 15:07:27 +0900 Subject: [PATCH 20/63] =?UTF-8?q?=EA=B0=99=EC=9D=80=EC=A2=8C=ED=91=9C?= =?UTF-8?q?=ED=8C=90=EB=8B=A8=201=EC=98=A4=EC=B0=A8=20=ED=97=88=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/qpolygon-utils.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 65cbc96d..a574c393 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1380,22 +1380,27 @@ export const splitPolygonWithLines = (polygon) => { }) } -const removeDuplicatePolygons = (polygons) => { +function normalizePoint(point) { + return { + x: Math.round(point.x), + y: Math.round(point.y), + } +} + +function arePolygonsEqual(polygon1, polygon2) { + if (polygon1.length !== polygon2.length) return false + + const normalizedPolygon1 = polygon1.map(normalizePoint).sort((a, b) => a.x - b.x || a.y - b.y) + const normalizedPolygon2 = polygon2.map(normalizePoint).sort((a, b) => a.x - b.x || a.y - b.y) + + return normalizedPolygon1.every((point, index) => arePointsEqual(point, normalizedPolygon2[index])) +} + +function removeDuplicatePolygons(polygons) { const uniquePolygons = [] polygons.forEach((polygon) => { - const sortedPolygon = polygon - .map((point) => `${Math.floor(point.x)},${Math.floor(point.y)}`) - .sort() - .join('|') - const isDuplicate = uniquePolygons.some((uniquePolygon) => { - const sortedUniquePolygon = uniquePolygon - .map((point) => `${Math.floor(point.x)},${Math.floor(point.y)}`) - .sort() - .join('|') - return sortedPolygon === sortedUniquePolygon - }) - + const isDuplicate = uniquePolygons.some((uniquePolygon) => arePolygonsEqual(polygon, uniquePolygon)) if (!isDuplicate) { uniquePolygons.push(polygon) } @@ -3551,7 +3556,7 @@ function createRoofPaddingPolygon(polygon, lines, arcSegments = 0) { } function arePointsEqual(point1, point2) { - return Math.abs(point1.x - point2.x) < 1 && Math.abs(point1.y - point2.y) - 1 + return Math.abs(point1.x - point2.x) <= 1 && Math.abs(point1.y - point2.y) <= 1 } function arraysHaveSamePoints(array1, array2) { From 19e22ba9eaaa105e10ff728999b2ae394003ae82 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 4 Nov 2024 15:15:36 +0900 Subject: [PATCH 21/63] =?UTF-8?q?=EB=B3=B4=EC=A1=B0=EC=84=A0=20=EC=9E=90?= =?UTF-8?q?=EB=A5=B4=EA=B8=B0=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useAuxiliaryDrawing.js | 31 ++++++++++++++++++++++ src/util/qpolygon-utils.js | 1 - 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index 72b094c9..46311ad9 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -616,6 +616,37 @@ export function useAuxiliaryDrawing(id) { removeLine(line1) intersectionPoints.current.push(...interSectionPointsWithRoofLines) return + } else if (interSectionPointsWithRoofLines.length === 1) { + //지붕선과 만나는 점이 하나일 경우 + const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, interSectionPointsWithRoofLines[0]) + const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, interSectionPointsWithRoofLines[0]) + + if (!(distance1 === 0 || distance2 === 0)) { + if (distance1 >= distance2) { + const newLine = addLine([line1.x1, line1.y1, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], { + stroke: 'black', + strokeWidth: 1, + selectable: false, + name: 'auxiliaryLine', + isFixed: true, + }) + lineHistory.current.push(newLine) + lineHistory.current = lineHistory.current.filter((history) => history !== line1) + removeLine(line1) + } else { + const newLine = addLine([line1.x2, line1.y2, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], { + stroke: 'black', + strokeWidth: 1, + selectable: false, + name: 'auxiliaryLine', + isFixed: true, + }) + lineHistory.current.push(newLine) + lineHistory.current = lineHistory.current.filter((history) => history !== line1) + removeLine(line1) + } + intersectionPoints.current.push(interSectionPointsWithRoofLines[0]) + } } //보조선과 만나는 점을 찾는다. diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index a574c393..1e82aefb 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1461,7 +1461,6 @@ export const drawRidgeRoof = (roofId, canvas) => { * @param canvas */ const drawRidge = (roof, canvas) => { - debugger const wallLines = canvas?.getObjects().find((object) => object.name === POLYGON_TYPE.WALL && object.attributes.roofId === roof.id).lines // 외벽의 라인 const roofLines = roof.lines // 지붕의 라인 let ridgeRoof = [] From 4891eb50aa08c70d3fde895a7e4e7722241fb384 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 4 Nov 2024 16:02:02 +0900 Subject: [PATCH 22/63] =?UTF-8?q?=EC=A7=80=EB=B6=95=EB=A9=B4=20=ED=95=A0?= =?UTF-8?q?=EB=8B=B9=20=EC=8B=9C=20=EB=B0=A9=ED=96=A5=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20=EC=9E=91=EC=97=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/qpolygon-utils.js | 39 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 1e82aefb..0e0ac586 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1339,10 +1339,45 @@ export const splitPolygonWithLines = (polygon) => { }) const newRoofs = removeDuplicatePolygons(roofs) - console.log(newRoofs) newRoofs.forEach((roofPoint, index) => { let defense, pitch - const direction = getDirectionByPoint(roofPoint[0], roofPoint[roofPoint.length - 1]) + const polygonLines = [...polygon.lines] + + let representLines = [] + let representLine + + // 지붕을 그리면서 기존 polygon의 line중 연결된 line을 찾는다. + polygonLines.forEach((line) => { + let startFlag = false + let endFlag = false + const startPoint = line.startPoint + const endPoint = line.endPoint + roofPoint.forEach((point, index) => { + if (isSamePoint(point, startPoint)) { + startFlag = true + } + if (isSamePoint(point, endPoint)) { + endFlag = true + } + }) + + if (startFlag && endFlag) { + representLines.push(line) + } + }) + + // representLines중 가장 긴 line을 찾는다. + representLines.forEach((line) => { + if (!representLine) { + representLine = line + } else { + if (representLine.length < line.length) { + representLine = line + } + } + }) + + const direction = representLine.direction switch (direction) { case 'top': From 1838320606ed938b761744932738da60c56695b2 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 4 Nov 2024 16:11:58 +0900 Subject: [PATCH 23/63] =?UTF-8?q?modal=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/font/FontSetting.jsx | 4 +- .../common/popupManager/PopupManager.jsx | 6 +- src/components/floor-plan/CanvasMenu.jsx | 2 +- .../floor-plan/modal/setting01/GridOption.jsx | 4 +- .../modal/setting01/SecondOption.jsx | 21 ++++-- .../modal/setting01/SettingModal01.jsx | 4 +- .../dimensionLine/DimensionLineSetting.jsx | 7 +- .../setting01/planSize/PlanSizeSetting.jsx | 4 +- src/hooks/useContextMenu.js | 2 +- src/hooks/usePopup.js | 75 +++++++++++++++---- src/store/popupAtom.js | 3 +- 11 files changed, 94 insertions(+), 38 deletions(-) diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index 60181021..54b22b3b 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -47,7 +47,7 @@ const fontColors = [ ] export default function FontSetting(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) - const { id, setIsShow, pos = contextPopupPosition, type } = props + const { id, setIsShow, pos = contextPopupPosition, type, isConfig = false } = props const { getMessage } = useMessage() const { closePopup } = usePopup() const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom) @@ -83,7 +83,7 @@ export default function FontSetting(props) { className="modal-close" onClick={() => { if (setIsShow) setIsShow(false) - closePopup(id) + closePopup(id, isConfig) }} > 닫기 diff --git a/src/components/common/popupManager/PopupManager.jsx b/src/components/common/popupManager/PopupManager.jsx index aa4b6cae..f24a8526 100644 --- a/src/components/common/popupManager/PopupManager.jsx +++ b/src/components/common/popupManager/PopupManager.jsx @@ -5,5 +5,9 @@ import { Fragment } from 'react' export default function PopupManager() { const [popup, setPopup] = useRecoilState(popupState) - return popup.children?.map((child) => {child.component}) + + return [ + ...popup?.config.map((child) => {child.component}), + ...popup?.other.map((child) => {child.component}), + ] } diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index adcd34b3..22ac4131 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -129,7 +129,7 @@ export default function CanvasMenu(props) { const handlePopup = () => { const id = uuidv4() - addPopup(id, 0, ) + addPopup(id, 1, , true) } useEffect(() => { diff --git a/src/components/floor-plan/modal/setting01/GridOption.jsx b/src/components/floor-plan/modal/setting01/GridOption.jsx index 5edb2167..8ef1095f 100644 --- a/src/components/floor-plan/modal/setting01/GridOption.jsx +++ b/src/components/floor-plan/modal/setting01/GridOption.jsx @@ -78,14 +78,14 @@ export default function GridOption() { // 점 선 그리드 설정 모달 setShowDotLineGridModal(selectedOption.selected) - addPopup(dotLineId, 2, ) + addPopup(dotLineId, 2, , true) } else if (selectedOption.id === 3) { // 흡착점 모드 setAdsorptionPointAddMode(selectedOption.selected) } else if (selectedOption.id === 4) { // 그리드 색 설정 모달 setShowColorPickerModal(selectedOption.selected) - addPopup(colorId, 2, ) + addPopup(colorId, 2, , true) } setGridOptions(newGridOptions) diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index c09dfdc1..385c7bef 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -1,4 +1,4 @@ -import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { useRecoilValue } from 'recoil' import { useMessage } from '@/hooks/useMessage' import React, { useEffect, useState } from 'react' import DimensionLineSetting from '@/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting' @@ -67,6 +67,7 @@ export default function SecondOption() { id: fontId, pos: { x: 745, y: 180 }, setIsShow: setShowFontSettingModal, + isConfig: true, } const planSizeProps = { id: planSizeId, @@ -86,36 +87,41 @@ export default function SecondOption() { case 'font1': { //문자 글꼴변경 setShowFontSettingModal(true) + setShowDimensionLineSettingModal(false) fontProps.type = 'commonText' fontProps.id = fontId + 1 - addPopup(fontId + 1, 2, ) + addPopup(fontId + 1, 2, , true) break } case 'font2': { //흐름 방향 글꼴 변경 setShowFontSettingModal(true) + setShowDimensionLineSettingModal(false) fontProps.type = 'flowText' fontProps.id = fontId + 2 - addPopup(fontId + 2, 2, ) + addPopup(fontId + 2, 2, , true) break } case 'font3': { //치수 글꼴변경 setShowFontSettingModal(true) + + setShowDimensionLineSettingModal(false) fontProps.type = 'lengthText' fontProps.id = fontId + 3 - addPopup(fontId + 3, 2, ) + addPopup(fontId + 3, 2, , true) break } case 'font4': { //회로번호 글꼴변경 setShowFontSettingModal(true) + setShowDimensionLineSettingModal(false) fontProps.type = 'circuitNumberText' fontProps.id = fontId - addPopup(fontId, 2, ) + addPopup(fontId, 2, , true) break } @@ -123,7 +129,7 @@ export default function SecondOption() { //치수선 설정 if (!showDimensionLineSettingModal) { setShowDimensionLineSettingModal(true) - addPopup(dimensionId, 2, ) + addPopup(dimensionId, 2, , true) } else { setShowDimensionLineSettingModal(false) closePopup(dimensionId) @@ -134,7 +140,8 @@ export default function SecondOption() { case 'planSize': { //도면크기 설정 setShowPlanSizeSettingModal(true) - addPopup(planSizeId, 2, ) + setShowDimensionLineSettingModal(false) + addPopup(planSizeId, 2, , true) break } } diff --git a/src/components/floor-plan/modal/setting01/SettingModal01.jsx b/src/components/floor-plan/modal/setting01/SettingModal01.jsx index 8570555e..e1bef1f0 100644 --- a/src/components/floor-plan/modal/setting01/SettingModal01.jsx +++ b/src/components/floor-plan/modal/setting01/SettingModal01.jsx @@ -11,7 +11,7 @@ import { useRecoilValue } from 'recoil' import { usePopup } from '@/hooks/usePopup' export default function SettingModal01(props) { - const { setShowDotLineGridModal, setShowFontSettingModal, id } = props + const { setShowDotLineGridModal, setShowFontSettingModal, id, isConfig } = props console.log(props) const [buttonAct, setButtonAct] = useState(1) const { getMessage } = useMessage() @@ -27,7 +27,7 @@ export default function SettingModal01(props) {

{getMessage('modal.canvas.setting')}

-
diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx index 2afbd184..1aa39e74 100644 --- a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -87,6 +87,7 @@ export default function DimensionLineSetting(props) { setFontColor: setOriginFontColor, fontSize: originFontSize, setFontSize: setOriginFontSize, + isConfig: true, id: fontModalId, pos: { x: 455, @@ -97,17 +98,17 @@ export default function DimensionLineSetting(props) { const popupHandle = (type) => { switch (type) { case 'color': - addPopup(colorModalId, 3, ) + addPopup(colorModalId, 3, , true) break case 'font': - addPopup(fontModalId, 3, ) + addPopup(fontModalId, 3, , true) break } } return ( -
+

{getMessage('modal.canvas.setting.font.plan.absorption.dimension.line')}

)} - {tabNum === 3 && } + {tabNum === 3 && ( + + )}
diff --git a/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx b/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx index 9eadeb7f..927f973b 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx @@ -114,7 +114,7 @@ export default function PowerConditionalSelect({ setTabNum }) {
- +
@@ -132,12 +132,12 @@ export default function PowerConditionalSelect({ setTabNum }) {
- +
diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 6a11ed71..bfb8422c 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -18,8 +18,8 @@ export default function StepUp({}) { - - + + @@ -49,14 +49,14 @@ export default function StepUp({}) {
-
接続する
+
{getMessage('modal.circuit.trestle.setting.step.up.allocation.connected')}
シリアル枚数総回路数{getMessage('modal.circuit.trestle.setting.step.up.allocation.serial.amount')}{getMessage('modal.circuit.trestle.setting.step.up.allocation.total.amount')}
- - - + + + @@ -80,7 +80,7 @@ export default function StepUp({}) {
- +
@@ -90,13 +90,13 @@ export default function StepUp({}) {
-
昇圧オプション
+
{getMessage('modal.circuit.trestle.setting.step.up.allocation.option')}
名称回路数昇圧回路数{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}{getMessage('modal.circuit.trestle.setting.power.conditional.select.circuit.amount')}{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}
- - + + @@ -113,7 +113,7 @@ export default function StepUp({}) {
- +
@@ -124,7 +124,7 @@ export default function StepUp({}) {
- 綿調道区分 + {getMessage('modal.module.basic.setting.module.cotton.classification')}
@@ -395,7 +395,7 @@ export default function StepUp({}) {
- モニターの選択 + {getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')}
diff --git a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx index 5233d992..67bb2195 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -4,13 +4,13 @@ export default function PassivityCircuitAllocation() { const { getMessage } = useMessage() const moduleData = { header: [ - { name: getMessage('屋根面'), prop: 'roofShape' }, + { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' }, { name: getMessage('Q.TRON M-G2'), prop: 'moduleName', }, { - name: getMessage('発電量 (kW)'), + name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'powerGeneration', }, ], diff --git a/src/locales/ja.json b/src/locales/ja.json index e4605537..390b3fe7 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -123,6 +123,7 @@ "modal.module.basic.setting.auto.placement": "設定値に自動配置", "plan.menu.module.circuit.setting.circuit.trestle.setting": "回路と架台の設定", "modal.circuit.trestle.setting": "回路と架台設定", + "modal.circuit.trestle.setting.alloc.trestle": "仮割り当て", "modal.circuit.trestle.setting.power.conditional.select": "パワーコンディショナーを選択", "modal.circuit.trestle.setting.power.conditional.select.name": "名称", "modal.circuit.trestle.setting.power.conditional.select.rated.output": "定格出力", @@ -130,6 +131,8 @@ "modal.circuit.trestle.setting.power.conditional.select.max.connection": "最大接続枚数", "modal.circuit.trestle.setting.power.conditional.select.max.overload": "過積最大枚数", "modal.circuit.trestle.setting.power.conditional.select.output.current": "出力電流", + "modal.circuit.trestle.setting.power.conditional.select.check1": "同一傾斜同一方面の面積の場合、同じ面として回路を分ける。", + "modal.circuit.trestle.setting.power.conditional.select.check2": "MAX接続(過積)で回路を分ける。", "modal.circuit.trestle.setting.circuit.allocation": "回路割り当て", "modal.circuit.trestle.setting.circuit.allocation.auto": "自動回路割り当て", "modal.circuit.trestle.setting.circuit.allocation.passivity": "手動回路割当", @@ -140,6 +143,12 @@ "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "すべての回路番号の初期化", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "番号確定", "modal.circuit.trestle.setting.step.up.allocation": "昇圧設定", + "modal.circuit.trestle.setting.step.up.allocation.serial.amount": "シリアル枚数", + "modal.circuit.trestle.setting.step.up.allocation.total.amount": "総回路数", + "modal.circuit.trestle.setting.step.up.allocation.connected": "接続する", + "modal.circuit.trestle.setting.step.up.allocation.circuit.amount": "昇圧回路数", + "modal.circuit.trestle.setting.step.up.allocation.option": "昇圧オプション", + "modal.circuit.trestle.setting.step.up.allocation.select.monitor": "モニターの選択", "plan.menu.module.circuit.setting.plan.orientation": "図面方位の適用", "plan.menu.estimate": "見積", "plan.menu.estimate.roof.alloc": "屋根面の割り当て", diff --git a/src/locales/ko.json b/src/locales/ko.json index 03443a0b..5f3fd48d 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -127,6 +127,7 @@ "modal.module.basic.setting.auto.placement": "설정값으로 자동 배치", "plan.menu.module.circuit.setting.circuit.trestle.setting": "회로 및 가대 설정", "modal.circuit.trestle.setting": "회로 및 가대설정", + "modal.circuit.trestle.setting.alloc.trestle": "가대할당", "modal.circuit.trestle.setting.power.conditional.select": "파워컨디셔너 선택", "modal.circuit.trestle.setting.power.conditional.select.name": "명칭", "modal.circuit.trestle.setting.power.conditional.select.rated.output": "정격출력", @@ -134,6 +135,8 @@ "modal.circuit.trestle.setting.power.conditional.select.max.connection": "최대접속매수", "modal.circuit.trestle.setting.power.conditional.select.max.overload": "과적최대매수", "modal.circuit.trestle.setting.power.conditional.select.output.current": "출력전류", + "modal.circuit.trestle.setting.power.conditional.select.check1": "동일경사 동일 방면의 면적인 경우, 같은 면으로서 회로를 나눈다.", + "modal.circuit.trestle.setting.power.conditional.select.check2": "MAX 접속(과적)으로 회로를 나눈다.", "modal.circuit.trestle.setting.circuit.allocation": "회로 할당", "modal.circuit.trestle.setting.circuit.allocation.auto": "자동 회로 할당", "modal.circuit.trestle.setting.circuit.allocation.passivity": "수동 회로 할당", @@ -144,6 +147,12 @@ "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "모든 회로번호 초기화", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "번호 확정", "modal.circuit.trestle.setting.step.up.allocation": "승압 설정", + "modal.circuit.trestle.setting.step.up.allocation.serial.amount": "직렬매수", + "modal.circuit.trestle.setting.step.up.allocation.total.amount": "총 회로수", + "modal.circuit.trestle.setting.step.up.allocation.connected": "연결함", + "modal.circuit.trestle.setting.step.up.allocation.circuit.amount": "승압회로수", + "modal.circuit.trestle.setting.step.up.allocation.option": "승압옵션", + "modal.circuit.trestle.setting.step.up.allocation.select.monitor": "모니터 선택", "plan.menu.module.circuit.setting.plan.orientation": "도면 방위 적용", "plan.menu.estimate": "견적서", "plan.menu.estimate.roof.alloc": "지붕면 할당", From 204ab66f90b72f3b21fb7e0a12b5989ad40ba953 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 4 Nov 2024 17:37:01 +0900 Subject: [PATCH 26/63] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 1 + src/styles/_layout.scss | 1 + src/styles/_main.scss | 5 +++-- src/styles/_modal.scss | 27 ++++++++++++++++++++++++--- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 7c8f334a..50abad0d 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -1312,6 +1312,7 @@ font-weight: 400; color: #999999; padding: 0; + width: 100%; height: 100%; flex: 1 ; background-color: inherit; diff --git a/src/styles/_layout.scss b/src/styles/_layout.scss index fc8870a2..a549ad0e 100644 --- a/src/styles/_layout.scss +++ b/src/styles/_layout.scss @@ -239,6 +239,7 @@ footer{ nav{ .nav-list{ .nav-item{ + a, button{ font-size: 13px; } diff --git a/src/styles/_main.scss b/src/styles/_main.scss index 75632a27..0733f285 100644 --- a/src/styles/_main.scss +++ b/src/styles/_main.scss @@ -37,9 +37,10 @@ top: 50%; left: 0; transform: translateY(-50%); - width: 20px; - height: 20px; + width: 22px; + height: 22px; background: url(../../public/static/images/main/id_icon.svg)no-repeat center; + background-size: cover; } } .store-arr{ diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index 7c40ab1e..da421f16 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -391,19 +391,22 @@ $alert-color: #101010; table-layout: fixed; tr{ th{ - display: flex; - align-items: center; font-size: $pop-normal-size; color: $pop-color; font-weight: $pop-bold-weight; padding: 18px 0; border-bottom: 1px solid #424242; + vertical-align: middle; + .tip-wrap{ + display: flex; + align-items: center; + } } td{ font-size: $pop-normal-size; color: $pop-color; border-bottom: 1px solid #424242; - padding-left: 20px; + padding: 18px 0 18px 20px; vertical-align: middle; .flex-box{ display: flex; @@ -479,6 +482,7 @@ $alert-color: #101010; color: $pop-color; font-weight: $pop-normal-weight; } + } .img-edit-wrap{ @@ -528,6 +532,23 @@ $alert-color: #101010; } } +.for-address{ + input{ + flex: 1; + } + .check-address{ + flex: none; + width: 18px; + height: 18px; + margin-left: 5px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + &.fail{background-image: url(../../public/static/images/canvas/img_check_fail.svg);} + &.success{background-image: url(../../public/static/images/canvas/img_check_success.svg);} + } +} + // 외벽선 그리기 .outline-wrap{ padding: 24px 0; From c7549b243aa9c505760324898730fe6df0fd0348 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 4 Nov 2024 17:50:57 +0900 Subject: [PATCH 27/63] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/static/images/canvas/estiment_arr.svg | 3 ++ .../images/canvas/estiment_arr_color.svg | 3 ++ src/styles/_contents.scss | 45 +++++++++++++++---- 3 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 public/static/images/canvas/estiment_arr.svg create mode 100644 public/static/images/canvas/estiment_arr_color.svg diff --git a/public/static/images/canvas/estiment_arr.svg b/public/static/images/canvas/estiment_arr.svg new file mode 100644 index 00000000..bcdbb42b --- /dev/null +++ b/public/static/images/canvas/estiment_arr.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/static/images/canvas/estiment_arr_color.svg b/public/static/images/canvas/estiment_arr_color.svg new file mode 100644 index 00000000..45588c74 --- /dev/null +++ b/public/static/images/canvas/estiment_arr_color.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 50abad0d..6715d48b 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -828,22 +828,49 @@ } } +.estimate-arr-btn{ + display: block; + width: 20px; + height: 20px; + background-color: #94A0AD; + border: 1px solid #94A0AD; + background-position: center; + background-repeat: no-repeat; + background-image: url(../../public/static/images/canvas/estiment_arr.svg); + background-size: 11px 7px; + border-radius: 2px; + &.up{ + rotate: 180deg; + } + &.on{ + background-color: #fff; + border-color: #C2D0DD; + background-image: url(../../public/static/images/canvas/estiment_arr_color.svg) + } +} +.estimate-check-wrap{ + .estimate-check-inner{ + display: block; + } + &.hide{ + border-bottom: 1px solid #ECF0F4; + margin-bottom: 15px; + .estimate-check-inner{ + display: none; + } + } +} + .special-note-check-wrap{ display: grid; grid-template-columns: repeat(5, 1fr); - border: 1px solid #ECF0F4; border-radius: 3px; margin-bottom: 30px; .special-note-check-item{ padding: 14px 10px; - border-right: 1px solid #ECF0F4; - border-top: 1px solid #ECF0F4; - &:nth-child(5n){ - border-right: none; - } - &:nth-child(-n+5){ - border-top: none; - } + border: 1px solid #ECF0F4; + margin-top: -1px; + margin-right: -1px; &.act{ background-color: #F7F9FA; } From 187f11df199ba1293a9ed9dbea5dc570319e6cff Mon Sep 17 00:00:00 2001 From: basssy Date: Mon, 4 Nov 2024 17:54:34 +0900 Subject: [PATCH 28/63] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=99=94=EB=A9=B4=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/estimate/Estimate.jsx | 302 ++++++--- .../estimate/useEstimateController.js | 120 +++- src/store/floorPlanObjectAtom.js | 6 + yarn.lock | 595 +++++++++++++----- 4 files changed, 779 insertions(+), 244 deletions(-) diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 7cbf936a..47f99c3d 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -8,13 +8,41 @@ import { useMessage } from '@/hooks/useMessage' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import SingleDatePicker from '../common/datepicker/SingleDatePicker' import EstimateFileUploader from './EstimateFileUploader' +import { useAxios } from '@/hooks/useAxios' +import { globalLocaleStore } from '@/store/localeAtom' +import { isObjectNotEmpty } from '@/util/common-utils' +import dayjs from 'dayjs' +import { useCommonCode } from '@/hooks/common/useCommonCode' +import Select from 'react-select' +import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' export default function Estimate({ params }) { - const [objectNo, setObjectNo] = useState('') - const [files, setFiles] = useState([]) //첨부파일 + const [objectNo, setObjectNo] = useState('') //물건번호 + const [planNo, setPlanNo] = useState('') //플랜번호 + const [files, setFiles] = useState([]) // 보내는 첨부파일 + + //견적특이사항 접고 펼치기 + const [hidden, setHidden] = useState(false) + + //공통코드 + const { findCommonCode } = useCommonCode() + const [honorificCodeList, setHonorificCodeList] = useState([]) //경칭 공통코드 + + const [startDate, setStartDate] = useState(new Date()) + const singleDatePickerProps = { + startDate, + setStartDate, + } const sessionState = useRecoilValue(sessionStore) const objectRecoil = useRecoilValue(floorPlanObjectState) + + //견적서 상세데이터 + const { state, setState } = useEstimateController(params.pid) + + const globalLocaleState = useRecoilValue(globalLocaleStore) + const { get, post } = useAxios(globalLocaleState) + const { getMessage } = useMessage() const { setMenuNumber } = useCanvasMenu() @@ -27,46 +55,54 @@ export default function Estimate({ params }) { setUploadFiles: setFiles, } - useEffect(() => { - setObjectNo(objectRecoil.floorPlanObjectNo) - }, [objectRecoil]) - - useEffect(() => { - if (objectNo) { - //Q101X278191023001 - console.log('세션정보::::', sessionState) - //상세API호출 - } - }, [objectNo]) - useEffect(() => { setMenuNumber(5) + setObjectNo(objectRecoil.floorPlanObjectNo) + setPlanNo(params.pid) + + // 공통코드 + const code1 = findCommonCode(200800) + if (code1 != null) { + setHonorificCodeList(code1) + } + + //견적특이사항 API호출 + //http://localhost:8080/api/estimate/special-note-list }, []) + //견적일 set + useEffect(() => { + let estimateDatej = dayjs(startDate).format('YYYY-MM-DD') + setState({ estimateDate: estimateDatej }) + }, [startDate]) + return (
{/* 물건번호, 견적서번호, 등록일, 변경일시 시작 */} + {/*
*/}
{getMessage('estimate.detail.objectNo')}
- {objectNo} (Plan No: {params.pid}) + {objectNo} (Plan No: {planNo})
-
{getMessage('estimate.detail.estimateNo')}
-
5242310200065242
+
{getMessage('estimate.detail.docNo')}
+
{state.docNo}
-
{getMessage('estimate.detail.createDatetime')}
-
9999.09.28
+
{getMessage('estimate.detail.drawingEstimateCreateDate')}
+
+ {state?.drawingEstimateCreateDate ? `${dayjs(state.drawingEstimateCreateDate).format('YYYY.MM.DD')}` : ''} +
{getMessage('estimate.detail.lastEditDatetime')}
-
9999.09.28 06:36
+
{state?.lastEditDatetime ? `${dayjs(state.lastEditDatetime).format('YYYY.MM.DD HH:mm')}` : ''}
@@ -99,7 +135,7 @@ export default function Estimate({ params }) {
@@ -113,64 +149,152 @@ export default function Estimate({ params }) { {/* 안건명 */} - {/* 메모 */} - - + {/* 물건정보에서 입력한 메모 */} + + {/* 주문분류 */} {/* 지붕재・사양시공 최대4개*/} {/* 비고 */} - + @@ -200,25 +324,6 @@ export default function Estimate({ params }) { @@ -246,21 +351,40 @@ export default function Estimate({ params }) {

{getMessage('estimate.detail.header.specialEstimate')}

{getMessage('estimate.detail.header.specialEstimateProductInfo')}
+
+ + +
- {/* 공통코드영역시작 */} -
- {/* 공통코드영역끝 */} - {/* 견적특이사항 내용영역시작 */} -
- {/* 견적특이사항 내용영역끝 */} - {/* 견적특이사항 끝 */} + {/* 견적 특이사항 코드영역시작 */} +
+
+
+ {/* 견적특이사항 선택한 내용?영역시작 */} +
+
+
제목11??
+
제목1 비고
+
+
+
제목22??
+
제목2 비고
+
+
+ {/* 견적특이사항 선택한 내용?영역끝 */} +
+
+ + {/* 견적 특이사항 코드영역 끝 */} + + {/* 견적특이사항 영역끝 */} {/* 제품정보 시작 */}

{getMessage('estimate.detail.header.specialEstimateProductInfo')}

-
+
{getMessage('estimate.detail.sepcialEstimateProductInfo.totPcs')}
@@ -285,7 +409,7 @@ export default function Estimate({ params }) {
{/* YJOD면 아래영역 숨김 */} -
+
名称昇圧回路数{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}
- +
- + { + //담당자 charger + // console.log('담당자:::::', e.target.value) + setState({ charger: e.target.value }) + }} + />
- {getMessage('estimate.detail.title')} * + {getMessage('estimate.detail.objectName')} *
- + { + //안건명 objectName + // console.log('안건명::::', e.target.value) + setState({ objectName: e.target.value }) + }} + />
-
- +
+
{getMessage('estimate.detail.remarks')}물건정보에서 입력한 메모 표시{getMessage('estimate.detail.objectRemarks')}{state?.objectRemarks}
- {getMessage('estimate.detail.orderType')} * + {getMessage('estimate.detail.estimateType')} * -
+
+
+ { + setState({ estimateType: e.target.value }) + }} + /> + +
+
+ { + setState({ estimateType: e.target.value }) + }} + /> + +
+
{getMessage('estimate.detail.roofCns')} -
-
- -
-
- -
-
-
-
- {/* 마지막div엔 mb5 제외 */} -
+ {state?.roofMaterialIdMulti?.split('、').map((row, index) => { + //지붕재 + let roofList = row + let roofListLength = state?.roofMaterialIdMulti?.split('、').length + let style = 'mb5' + if (roofListLength == index + 1) { + style = '' + } + //사양시공 + let constructSpecificationMulti = state?.constructSpecificationMulti?.split('、') + + return ( + <> +
+
+ +
+
+ +
+
+ + ) + })}
{getMessage('estimate.detail.note')}{getMessage('estimate.detail.remarks')}
- + { + //비고 + // console.log('비고:::::', e.target.value) + setState({ remarks: e.target.value }) + }} + />
{getMessage('estimate.detail.header.fileList1')} - {/*
-
- - -
-
-

Drag file here

-
    -
    -
    */}
    @@ -319,18 +443,35 @@ export default function Estimate({ params }) {
    {getMessage('estimate.detail.header.showPrice')}
    -
    +
    + +
    -
    -
    +
      +
    • - {getMessage('estimate.detail.showPrice.description')} -
    -
    + {getMessage('estimate.detail.showPrice.description1')} + +
  • + + {getMessage('estimate.detail.showPrice.description2')} +
  • +
  • + + {getMessage('estimate.detail.showPrice.description3')} +
  • +
  • + + {getMessage('estimate.detail.showPrice.description4')} +
  • +
    - @@ -348,6 +489,7 @@ export default function Estimate({ params }) {
    {/* 기본정보끝 */} + {/* */}
    ) diff --git a/src/hooks/floorPlan/estimate/useEstimateController.js b/src/hooks/floorPlan/estimate/useEstimateController.js index 280c70da..3af6d048 100644 --- a/src/hooks/floorPlan/estimate/useEstimateController.js +++ b/src/hooks/floorPlan/estimate/useEstimateController.js @@ -1,6 +1,9 @@ import { useAxios } from '@/hooks/useAxios' -import { useReducer } from 'react' - +import { useEffect, useReducer, useState } from 'react' +import { useRecoilState, useRecoilValue } from 'recoil' +import { globalLocaleStore } from '@/store/localeAtom' +import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom' +import { isObjectNotEmpty } from '@/util/common-utils' const reducer = (prevState, nextState) => { return { ...prevState, ...nextState } } @@ -9,39 +12,127 @@ const reducer = (prevState, nextState) => { const ESTIMATE_API_ENDPOINT = '/api/estimates' // API 엔드포인트 정의 const defaultEstimateData = { - name: '', - objectName: '', - estimateDate: '', - itemList: [{ id: 1, name: '' }], + estimateDate: new Date(), //견적일 + charger: '', //담당자 + objectName: '', //안건명 + objectNameOmit: '', //경칭코드 + estimateType: 'YJOD', //주문분류 + remarks: '', //비고 + // itemList: [{ id: 1, name: '' }], + //아이템에 필요없는거 빼기 + itemList: [ + { + amount: '', + fileUploadFlg: '', + itemChangeFlg: '', + itemGroup: '', + itemId: '', //키값?? + itemName: '', + itemNo: '', + moduleFlg: '', + objectNo: '', + pkgMaterialFlg: '', + planNo: '', + pnowW: '', + salePrice: '', + saleTotPrice: '', + specification: '', + unit: '', + }, + ], } // Helper functions -const updateItemInList = (itemList, id, updates) => { - return itemList.map((item) => (item.id === id ? { ...item, ...updates } : item)) +// const updateItemInList = (itemList, id, updates) => { +const updateItemInList = (itemList, itemId, updates) => { + // return itemList.map((item) => (item.id === id ? { ...item, ...updates } : item)) + return itemList.map((item) => (item.itemId === itemId ? { ...item, ...updates } : item)) } -export const useEstimateController = () => { +export const useEstimateController = (planNo) => { + const globalLocaleState = useRecoilValue(globalLocaleStore) + const objectRecoil = useRecoilValue(floorPlanObjectState) + const [estimateData, setEstimateData] = useRecoilState(estimateState) + + const { get, post } = useAxios(globalLocaleState) + + const [isLoading, setIsLoading] = useState(false) const { promisePost } = useAxios() const [state, setState] = useReducer(reducer, defaultEstimateData) - const updateItem = (id, updates) => { + useEffect(() => { + if (!isLoading) { + if (objectRecoil.floorPlanObjectNo && planNo) { + fetchSetting() + } + } + }, []) + + // 상세 조회 + const fetchSetting = async () => { + try { + await get({ url: `/api/estimate/${objectRecoil.floorPlanObjectNo}/${planNo}/detail` }).then((res) => { + if (isObjectNotEmpty(res)) { + setState(res) + } + }) + setIsLoading(true) + } catch (error) { + console.error('견적서 상세조회 Error: ', error) + setIsLoading(true) + } + } + + // const updateItem = (id, updates) => { + const updateItem = (itemId, updates) => { setState({ - itemList: updateItemInList(state.itemList, id, updates), + // itemList: updateItemInList(state.itemList, id, updates), + itemList: updateItemInList(state.itemList, itemId, updates), }) } const addItem = () => { - const newId = Math.max(...state.itemList.map((item) => item.id)) + 1 + // const newId = Math.max(...state.itemList.map((item) => item.id)) + 1 + const newItemId = Math.max(...state.itemList.map((item) => item.itemId)) + 1 setState({ - itemList: [...state.itemList, { id: newId, name: '' }], + // itemList: [...state.itemList, { id: newId, name: '' }], + //셋팅할필요없는거 빼기 + itemList: [ + ...state.itemList, + { + itemId: newItemId, + amount: '', + fileUploadFlg: '', + itemChangeFlg: '', + itemGroup: '', + itemName: '', + itemNo: '', + moduleFlg: '', + objectNo: '', + pkgMaterialFlg: '', + planNo: '', + pnowW: '', + salePrice: '', + saleTotPrice: '', + specification: '', + unit: '', + }, + ], }) } + useEffect(() => { + setEstimateData({ ...state }) + }, [state]) + + //견적서 저장 const handleEstimateSubmit = async () => { + console.log('::담긴 estimateData:::', estimateData) + return try { const result = await promisePost({ url: ESTIMATE_API_ENDPOINT, - data: state, + data: estimateData, }) return result } catch (error) { @@ -56,5 +147,6 @@ export const useEstimateController = () => { updateItem, addItem, handleEstimateSubmit, + fetchSetting, } } diff --git a/src/store/floorPlanObjectAtom.js b/src/store/floorPlanObjectAtom.js index 3acd49a3..d514fe54 100644 --- a/src/store/floorPlanObjectAtom.js +++ b/src/store/floorPlanObjectAtom.js @@ -7,3 +7,9 @@ export const floorPlanObjectState = atom({ }, dangerouslyAllowMutability: true, }) + +export const estimateState = atom({ + key: `estimateState`, + default: {}, + dangerouslyAllowMutability: true, +}) diff --git a/yarn.lock b/yarn.lock index f2bcf8b4..a167fa9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -223,14 +223,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/runtime@^7.20.13": - version "7.25.0" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz" - integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.24.8": +"@babel/runtime@^7.20.13", "@babel/runtime@^7.24.8": version "7.25.0" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz" integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== @@ -534,6 +527,21 @@ resolved "https://registry.npmjs.org/@js-joda/core/-/core-5.6.3.tgz" integrity sha512-T1rRxzdqkEXcou0ZprN1q9yDRlvzCPLqmlNt5IIsGBzoEVgLCCYrKEwc84+TvsXuAc95VAZwtWD2zVsKPY4bcA== +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" + integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + "@next/env@14.2.3": version "14.2.3" resolved "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz" @@ -1238,7 +1246,7 @@ "@react-types/shared" "3.23.1" clsx "^1.2.1" -"@nextui-org/system@>=2.0.0", "@nextui-org/system@>=2.1.0", "@nextui-org/system@2.2.5": +"@nextui-org/system@2.2.5": version "2.2.5" resolved "https://registry.npmjs.org/@nextui-org/system/-/system-2.2.5.tgz" integrity sha512-nrX6768aiyWtpxX3OTFBIVWR+v9nlMsC3KaBinNfek97sNm7gAfTHi7q5kylE3L5yIMpNG+DclAKpuxgDQEmvw== @@ -1291,7 +1299,7 @@ "@react-types/tabs" "3.3.7" scroll-into-view-if-needed "3.0.10" -"@nextui-org/theme@>=2.1.0", "@nextui-org/theme@>=2.2.0", "@nextui-org/theme@2.2.9": +"@nextui-org/theme@2.2.9": version "2.2.9" resolved "https://registry.npmjs.org/@nextui-org/theme/-/theme-2.2.9.tgz" integrity sha512-TN2I9sMriLaj00pXsIMlg19+UHeOdjzS2JV0u4gjL14mSbQl5BYNxgbvU3gbMqkZZQ6OpwT4RnT8RS+ks6TXCw== @@ -1512,7 +1520,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1645,7 +1653,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/focus@^3.17.1", "@react-aria/focus@3.17.1": +"@react-aria/focus@3.17.1", "@react-aria/focus@^3.17.1": version "3.17.1" resolved "https://registry.npmjs.org/@react-aria/focus/-/focus-3.17.1.tgz" integrity sha512-FLTySoSNqX++u0nWZJPPN5etXY0WBxaIe/YuL/GTEeuqUIuC/2bJSaw5hlsM6T2yjy6Y/VAxBcKSdAFUlU6njQ== @@ -1667,7 +1675,7 @@ "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/form@^3.0.5", "@react-aria/form@3.0.5": +"@react-aria/form@3.0.5", "@react-aria/form@^3.0.5": version "3.0.5" resolved "https://registry.npmjs.org/@react-aria/form/-/form-3.0.5.tgz" integrity sha512-n290jRwrrRXO3fS82MyWR+OKN7yznVesy5Q10IclSTVYHHI3VI53xtAPr/WzNjJR1um8aLhOcDNFKwnNIUUCsQ== @@ -1697,7 +1705,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-aria/i18n@^3.11.1", "@react-aria/i18n@3.11.1": +"@react-aria/i18n@3.11.1", "@react-aria/i18n@^3.11.1": version "3.11.1" resolved "https://registry.npmjs.org/@react-aria/i18n/-/i18n-3.11.1.tgz" integrity sha512-vuiBHw1kZruNMYeKkTGGnmPyMnM5T+gT8bz97H1FqIq1hQ6OPzmtBZ6W6l6OIMjeHI5oJo4utTwfZl495GALFQ== @@ -1725,7 +1733,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-aria/interactions@^3.21.3", "@react-aria/interactions@3.21.3": +"@react-aria/interactions@3.21.3", "@react-aria/interactions@^3.21.3": version "3.21.3" resolved "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.21.3.tgz" integrity sha512-BWIuf4qCs5FreDJ9AguawLVS0lV9UU+sK4CCnbCNNmYqOWY+1+gRXCsnOM32K+oMESBxilAjdHW5n1hsMqYMpA== @@ -1745,7 +1753,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-aria/label@^3.7.8", "@react-aria/label@3.7.8": +"@react-aria/label@3.7.8", "@react-aria/label@^3.7.8": version "3.7.8" resolved "https://registry.npmjs.org/@react-aria/label/-/label-3.7.8.tgz" integrity sha512-MzgTm5+suPA3KX7Ug6ZBK2NX9cin/RFLsv1BdafJ6CZpmUSpWnGE/yQfYUB7csN7j31OsZrD3/P56eShYWAQfg== @@ -1754,7 +1762,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/link@^3.7.1", "@react-aria/link@3.7.1": +"@react-aria/link@3.7.1", "@react-aria/link@^3.7.1": version "3.7.1" resolved "https://registry.npmjs.org/@react-aria/link/-/link-3.7.1.tgz" integrity sha512-a4IaV50P3fXc7DQvEIPYkJJv26JknFbRzFT5MJOMgtzuhyJoQdILEUK6XHYjcSSNCA7uLgzpojArVk5Hz3lCpw== @@ -1766,7 +1774,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/listbox@^3.12.1", "@react-aria/listbox@3.12.1": +"@react-aria/listbox@3.12.1", "@react-aria/listbox@^3.12.1": version "3.12.1" resolved "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.12.1.tgz" integrity sha512-7JiUp0NGykbv/HgSpmTY1wqhuf/RmjFxs1HZcNaTv8A+DlzgJYc7yQqFjP3ZA/z5RvJFuuIxggIYmgIFjaRYdA== @@ -1788,7 +1796,7 @@ dependencies: "@swc/helpers" "^0.5.0" -"@react-aria/menu@^3.14.1", "@react-aria/menu@3.14.1": +"@react-aria/menu@3.14.1", "@react-aria/menu@^3.14.1": version "3.14.1" resolved "https://registry.npmjs.org/@react-aria/menu/-/menu-3.14.1.tgz" integrity sha512-BYliRb38uAzq05UOFcD5XkjA5foQoXRbcH3ZufBsc4kvh79BcP1PMW6KsXKGJ7dC/PJWUwCui6QL1kUg8PqMHA== @@ -1807,7 +1815,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/overlays@^3.22.1", "@react-aria/overlays@3.22.1": +"@react-aria/overlays@3.22.1", "@react-aria/overlays@^3.22.1": version "3.22.1" resolved "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.22.1.tgz" integrity sha512-GHiFMWO4EQ6+j6b5QCnNoOYiyx1Gk8ZiwLzzglCI4q1NY5AG2EAmfU4Z1+Gtrf2S5Y0zHbumC7rs9GnPoGLUYg== @@ -1852,7 +1860,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/selection@^3.18.1", "@react-aria/selection@3.18.1": +"@react-aria/selection@3.18.1", "@react-aria/selection@^3.18.1": version "3.18.1" resolved "https://registry.npmjs.org/@react-aria/selection/-/selection-3.18.1.tgz" integrity sha512-GSqN2jX6lh7v+ldqhVjAXDcrWS3N4IsKXxO6L6Ygsye86Q9q9Mq9twWDWWu5IjHD6LoVZLUBCMO+ENGbOkyqeQ== @@ -1905,7 +1913,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-aria/ssr@^3.9.4", "@react-aria/ssr@3.9.4": +"@react-aria/ssr@3.9.4", "@react-aria/ssr@^3.9.4": version "3.9.4" resolved "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.4.tgz" integrity sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ== @@ -1965,7 +1973,7 @@ "@react-types/tabs" "^3.3.7" "@swc/helpers" "^0.5.0" -"@react-aria/textfield@^3.14.5", "@react-aria/textfield@3.14.5": +"@react-aria/textfield@3.14.5", "@react-aria/textfield@^3.14.5": version "3.14.5" resolved "https://registry.npmjs.org/@react-aria/textfield/-/textfield-3.14.5.tgz" integrity sha512-hj7H+66BjB1iTKKaFXwSZBZg88YT+wZboEXZ0DNdQB2ytzoz/g045wBItUuNi4ZjXI3P+0AOZznVMYadWBAmiA== @@ -2006,7 +2014,7 @@ "@react-types/tooltip" "^3.4.9" "@swc/helpers" "^0.5.0" -"@react-aria/utils@^3.24.1", "@react-aria/utils@3.24.1": +"@react-aria/utils@3.24.1", "@react-aria/utils@^3.24.1": version "3.24.1" resolved "https://registry.npmjs.org/@react-aria/utils/-/utils-3.24.1.tgz" integrity sha512-O3s9qhPMd6n42x9sKeJ3lhu5V1Tlnzhu6Yk8QOvDuXf7UGuUjXf9mzfHJt1dYzID4l9Fwm8toczBzPM9t0jc8Q== @@ -2028,7 +2036,7 @@ "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/visually-hidden@^3.8.12", "@react-aria/visually-hidden@3.8.12": +"@react-aria/visually-hidden@3.8.12", "@react-aria/visually-hidden@^3.8.12": version "3.8.12" resolved "https://registry.npmjs.org/@react-aria/visually-hidden/-/visually-hidden-3.8.12.tgz" integrity sha512-Bawm+2Cmw3Xrlr7ARzl2RLtKh0lNUdJ0eNqzWcyx4c0VHUAWtThmH5l+HRqFUGzzutFZVo89SAy40BAbd0gjVw== @@ -2038,7 +2046,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/calendar@^3.5.1", "@react-stately/calendar@3.5.1": +"@react-stately/calendar@3.5.1", "@react-stately/calendar@^3.5.1": version "3.5.1" resolved "https://registry.npmjs.org/@react-stately/calendar/-/calendar-3.5.1.tgz" integrity sha512-7l7QhqGUJ5AzWHfvZzbTe3J4t72Ht5BmhW4hlVI7flQXtfrmYkVtl3ZdytEZkkHmWGYZRW9b4IQTQGZxhtlElA== @@ -2049,7 +2057,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/checkbox@^3.6.5", "@react-stately/checkbox@3.6.5": +"@react-stately/checkbox@3.6.5", "@react-stately/checkbox@^3.6.5": version "3.6.5" resolved "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.6.5.tgz" integrity sha512-IXV3f9k+LtmfQLE+DKIN41Q5QB/YBLDCB1YVx5PEdRp52S9+EACD5683rjVm8NVRDwjMi2SP6RnFRk7fVb5Azg== @@ -2060,7 +2068,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/collections@^3.10.7", "@react-stately/collections@3.10.7": +"@react-stately/collections@3.10.7", "@react-stately/collections@^3.10.7": version "3.10.7" resolved "https://registry.npmjs.org/@react-stately/collections/-/collections-3.10.7.tgz" integrity sha512-KRo5O2MWVL8n3aiqb+XR3vP6akmHLhLWYZEmPKjIv0ghQaEebBTrN3wiEjtd6dzllv0QqcWvDLM1LntNfJ2TsA== @@ -2076,7 +2084,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-stately/combobox@^3.8.4", "@react-stately/combobox@3.8.4": +"@react-stately/combobox@3.8.4", "@react-stately/combobox@^3.8.4": version "3.8.4" resolved "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.8.4.tgz" integrity sha512-iLVGvKRRz0TeJXZhZyK783hveHpYA6xovOSdzSD+WGYpiPXo1QrcrNoH3AE0Z2sHtorU+8nc0j58vh5PB+m2AA== @@ -2091,7 +2099,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/datepicker@^3.9.4", "@react-stately/datepicker@3.9.4": +"@react-stately/datepicker@3.9.4", "@react-stately/datepicker@^3.9.4": version "3.9.4" resolved "https://registry.npmjs.org/@react-stately/datepicker/-/datepicker-3.9.4.tgz" integrity sha512-yBdX01jn6gq4NIVvHIqdjBUPo+WN8Bujc4OnPw+ZnfA4jI0eIgq04pfZ84cp1LVXW0IB0VaCu1AlQ/kvtZjfGA== @@ -2112,7 +2120,7 @@ dependencies: "@swc/helpers" "^0.5.0" -"@react-stately/form@^3.0.3", "@react-stately/form@3.0.3": +"@react-stately/form@3.0.3", "@react-stately/form@^3.0.3": version "3.0.3" resolved "https://registry.npmjs.org/@react-stately/form/-/form-3.0.3.tgz" integrity sha512-92YYBvlHEWUGUpXgIaQ48J50jU9XrxfjYIN8BTvvhBHdD63oWgm8DzQnyT/NIAMzdLnhkg7vP+fjG8LjHeyIAg== @@ -2139,7 +2147,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-stately/list@^3.10.5", "@react-stately/list@3.10.5": +"@react-stately/list@3.10.5", "@react-stately/list@^3.10.5": version "3.10.5" resolved "https://registry.npmjs.org/@react-stately/list/-/list-3.10.5.tgz" integrity sha512-fV9plO+6QDHiewsYIhboxcDhF17GO95xepC5ki0bKXo44gr14g/LSo/BMmsaMnV+1BuGdBunB05bO4QOIaigXA== @@ -2161,7 +2169,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-stately/menu@^3.7.1", "@react-stately/menu@3.7.1": +"@react-stately/menu@3.7.1", "@react-stately/menu@^3.7.1": version "3.7.1" resolved "https://registry.npmjs.org/@react-stately/menu/-/menu-3.7.1.tgz" integrity sha512-mX1w9HHzt+xal1WIT2xGrTQsoLvDwuB2R1Er1MBABs//MsJzccycatcgV/J/28m6tO5M9iuFQQvLV+i1dCtodg== @@ -2171,7 +2179,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/overlays@^3.6.7", "@react-stately/overlays@3.6.7": +"@react-stately/overlays@3.6.7", "@react-stately/overlays@^3.6.7": version "3.6.7" resolved "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.6.7.tgz" integrity sha512-6zp8v/iNUm6YQap0loaFx6PlvN8C0DgWHNlrlzMtMmNuvjhjR0wYXVaTfNoUZBWj25tlDM81ukXOjpRXg9rLrw== @@ -2189,7 +2197,7 @@ "@react-types/overlays" "^3.8.9" "@swc/helpers" "^0.5.0" -"@react-stately/radio@^3.10.4", "@react-stately/radio@3.10.4": +"@react-stately/radio@3.10.4", "@react-stately/radio@^3.10.4": version "3.10.4" resolved "https://registry.npmjs.org/@react-stately/radio/-/radio-3.10.4.tgz" integrity sha512-kCIc7tAl4L7Hu4Wt9l2jaa+MzYmAJm0qmC8G8yPMbExpWbLRu6J8Un80GZu+JxvzgDlqDyrVvyv9zFifwH/NkQ== @@ -2222,7 +2230,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-stately/slider@^3.5.4", "@react-stately/slider@3.5.4": +"@react-stately/slider@3.5.4", "@react-stately/slider@^3.5.4": version "3.5.4" resolved "https://registry.npmjs.org/@react-stately/slider/-/slider-3.5.4.tgz" integrity sha512-Jsf7K17dr93lkNKL9ij8HUcoM1sPbq8TvmibD6DhrK9If2lje+OOL8y4n4qreUnfMT56HCAeS9wCO3fg3eMyrw== @@ -2232,7 +2240,7 @@ "@react-types/slider" "^3.7.3" "@swc/helpers" "^0.5.0" -"@react-stately/table@^3.11.8", "@react-stately/table@3.11.8": +"@react-stately/table@3.11.8", "@react-stately/table@^3.11.8": version "3.11.8" resolved "https://registry.npmjs.org/@react-stately/table/-/table-3.11.8.tgz" integrity sha512-EdyRW3lT1/kAVDp5FkEIi1BQ7tvmD2YgniGdLuW/l9LADo0T+oxZqruv60qpUS6sQap+59Riaxl91ClDxrJnpg== @@ -2247,7 +2255,7 @@ "@react-types/table" "^3.9.5" "@swc/helpers" "^0.5.0" -"@react-stately/tabs@^3.6.6", "@react-stately/tabs@3.6.6": +"@react-stately/tabs@3.6.6", "@react-stately/tabs@^3.6.6": version "3.6.6" resolved "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.6.6.tgz" integrity sha512-sOLxorH2uqjAA+v1ppkMCc2YyjgqvSGeBDgtR/lyPSDd4CVMoTExszROX2dqG0c8il9RQvzFuufUtQWMY6PgSA== @@ -2257,7 +2265,7 @@ "@react-types/tabs" "^3.3.7" "@swc/helpers" "^0.5.0" -"@react-stately/toggle@^3.7.4", "@react-stately/toggle@3.7.4": +"@react-stately/toggle@3.7.4", "@react-stately/toggle@^3.7.4": version "3.7.4" resolved "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.7.4.tgz" integrity sha512-CoYFe9WrhLkDP4HGDpJYQKwfiYCRBAeoBQHv+JWl5eyK61S8xSwoHsveYuEZ3bowx71zyCnNAqWRrmNOxJ4CKA== @@ -2275,7 +2283,7 @@ "@react-types/checkbox" "^3.8.3" "@swc/helpers" "^0.5.0" -"@react-stately/tooltip@^3.4.9", "@react-stately/tooltip@3.4.9": +"@react-stately/tooltip@3.4.9", "@react-stately/tooltip@^3.4.9": version "3.4.9" resolved "https://registry.npmjs.org/@react-stately/tooltip/-/tooltip-3.4.9.tgz" integrity sha512-P7CDJsdoKarz32qFwf3VNS01lyC+63gXpDZG31pUu+EO5BeQd4WKN/AH1Beuswpr4GWzxzFc1aXQgERFGVzraA== @@ -2284,7 +2292,7 @@ "@react-types/tooltip" "^3.4.9" "@swc/helpers" "^0.5.0" -"@react-stately/tree@^3.8.1", "@react-stately/tree@3.8.1": +"@react-stately/tree@3.8.1", "@react-stately/tree@^3.8.1": version "3.8.1" resolved "https://registry.npmjs.org/@react-stately/tree/-/tree-3.8.1.tgz" integrity sha512-LOdkkruJWch3W89h4B/bXhfr0t0t1aRfEp+IMrrwdRAl23NaPqwl5ILHs4Xu5XDHqqhg8co73pHrJwUyiTWEjw== @@ -2295,7 +2303,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/utils@^3.10.1", "@react-stately/utils@3.10.1": +"@react-stately/utils@3.10.1", "@react-stately/utils@^3.10.1": version "3.10.1" resolved "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.1.tgz" integrity sha512-VS/EHRyicef25zDZcM/ClpzYMC5i2YGN6uegOeQawmgfGjb02yaCX0F0zR69Pod9m2Hr3wunTbtpgVXvYbZItg== @@ -2309,7 +2317,7 @@ dependencies: "@swc/helpers" "^0.5.0" -"@react-stately/virtualizer@^3.7.1", "@react-stately/virtualizer@3.7.1": +"@react-stately/virtualizer@3.7.1", "@react-stately/virtualizer@^3.7.1": version "3.7.1" resolved "https://registry.npmjs.org/@react-stately/virtualizer/-/virtualizer-3.7.1.tgz" integrity sha512-voHgE6EQ+oZaLv6u2umKxakvIKNkCQuUihqKACTjdslp7SJh4Mvs3oLBI0hf0JOh+rCcFIKDvQtFwy1fXFRYBA== @@ -2325,7 +2333,7 @@ dependencies: "@react-types/shared" "^3.23.1" -"@react-types/breadcrumbs@^3.7.5", "@react-types/breadcrumbs@3.7.5": +"@react-types/breadcrumbs@3.7.5", "@react-types/breadcrumbs@^3.7.5": version "3.7.5" resolved "https://registry.npmjs.org/@react-types/breadcrumbs/-/breadcrumbs-3.7.5.tgz" integrity sha512-lV9IDYsMiu2TgdMIjEmsOE0YWwjb3jhUNK1DCZZfq6uWuiHLgyx2EncazJBUWSjHJ4ta32j7xTuXch+8Ai6u/A== @@ -2333,7 +2341,7 @@ "@react-types/link" "^3.5.5" "@react-types/shared" "^3.23.1" -"@react-types/button@^3.9.4", "@react-types/button@3.9.4": +"@react-types/button@3.9.4", "@react-types/button@^3.9.4": version "3.9.4" resolved "https://registry.npmjs.org/@react-types/button/-/button-3.9.4.tgz" integrity sha512-raeQBJUxBp0axNF74TXB8/H50GY8Q3eV6cEKMbZFP1+Dzr09Ngv0tJBeW0ewAxAguNH5DRoMUAUGIXtSXskVdA== @@ -2347,7 +2355,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/calendar@^3.4.6", "@react-types/calendar@3.4.6": +"@react-types/calendar@3.4.6", "@react-types/calendar@^3.4.6": version "3.4.6" resolved "https://registry.npmjs.org/@react-types/calendar/-/calendar-3.4.6.tgz" integrity sha512-WSntZPwtvsIYWvBQRAPvuCn55UTJBZroTvX0vQvWykJRQnPAI20G1hMQ3dNsnAL+gLZUYxBXn66vphmjUuSYew== @@ -2355,7 +2363,7 @@ "@internationalized/date" "^3.5.4" "@react-types/shared" "^3.23.1" -"@react-types/checkbox@^3.8.1", "@react-types/checkbox@3.8.1": +"@react-types/checkbox@3.8.1", "@react-types/checkbox@^3.8.1": version "3.8.1" resolved "https://registry.npmjs.org/@react-types/checkbox/-/checkbox-3.8.1.tgz" integrity sha512-5/oVByPw4MbR/8QSdHCaalmyWC71H/QGgd4aduTJSaNi825o+v/hsN2/CH7Fq9atkLKsC8fvKD00Bj2VGaKriQ== @@ -2369,14 +2377,14 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/combobox@^3.11.1", "@react-types/combobox@3.11.1": +"@react-types/combobox@3.11.1", "@react-types/combobox@^3.11.1": version "3.11.1" resolved "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.11.1.tgz" integrity sha512-UNc3OHt5cUt5gCTHqhQIqhaWwKCpaNciD8R7eQazmHiA9fq8ROlV+7l3gdNgdhJbTf5Bu/V5ISnN7Y1xwL3zqQ== dependencies: "@react-types/shared" "^3.23.1" -"@react-types/datepicker@^3.7.4", "@react-types/datepicker@3.7.4": +"@react-types/datepicker@3.7.4", "@react-types/datepicker@^3.7.4": version "3.7.4" resolved "https://registry.npmjs.org/@react-types/datepicker/-/datepicker-3.7.4.tgz" integrity sha512-ZfvgscvNzBJpYyVWg3nstJtA/VlWLwErwSkd1ivZYam859N30w8yH+4qoYLa6FzWLCFlrsRHyvtxlEM7lUAt5A== @@ -2394,7 +2402,7 @@ "@react-types/overlays" "^3.8.9" "@react-types/shared" "^3.24.1" -"@react-types/grid@^3.2.6", "@react-types/grid@3.2.6": +"@react-types/grid@3.2.6", "@react-types/grid@^3.2.6": version "3.2.6" resolved "https://registry.npmjs.org/@react-types/grid/-/grid-3.2.6.tgz" integrity sha512-XfHenL2jEBUYrhKiPdeM24mbLRXUn79wVzzMhrNYh24nBwhsPPpxF+gjFddT3Cy8dt6tRInfT6pMEu9nsXwaHw== @@ -2408,7 +2416,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/link@^3.5.5", "@react-types/link@3.5.5": +"@react-types/link@3.5.5", "@react-types/link@^3.5.5": version "3.5.5" resolved "https://registry.npmjs.org/@react-types/link/-/link-3.5.5.tgz" integrity sha512-G6P5WagHDR87npN7sEuC5IIgL1GsoY4WFWKO4734i2CXRYx24G9P0Su3AX4GA3qpspz8sK1AWkaCzBMmvnunfw== @@ -2422,7 +2430,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/menu@^3.9.9", "@react-types/menu@3.9.9": +"@react-types/menu@3.9.9", "@react-types/menu@^3.9.9": version "3.9.9" resolved "https://registry.npmjs.org/@react-types/menu/-/menu-3.9.9.tgz" integrity sha512-FamUaPVs1Fxr4KOMI0YcR2rYZHoN7ypGtgiEiJ11v/tEPjPPGgeKDxii0McCrdOkjheatLN1yd2jmMwYj6hTDg== @@ -2430,7 +2438,7 @@ "@react-types/overlays" "^3.8.7" "@react-types/shared" "^3.23.1" -"@react-types/overlays@^3.8.7", "@react-types/overlays@3.8.7": +"@react-types/overlays@3.8.7", "@react-types/overlays@^3.8.7": version "3.8.7" resolved "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.8.7.tgz" integrity sha512-zCOYvI4at2DkhVpviIClJ7bRrLXYhSg3Z3v9xymuPH3mkiuuP/dm8mUCtkyY4UhVeUTHmrQh1bzaOP00A+SSQA== @@ -2444,20 +2452,27 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/progress@^3.5.4", "@react-types/progress@3.5.4": +"@react-types/progress@3.5.4", "@react-types/progress@^3.5.4": version "3.5.4" resolved "https://registry.npmjs.org/@react-types/progress/-/progress-3.5.4.tgz" integrity sha512-JNc246sTjasPyx5Dp7/s0rp3Bz4qlu4LrZTulZlxWyb53WgBNL7axc26CCi+I20rWL9+c7JjhrRxnLl/1cLN5g== dependencies: "@react-types/shared" "^3.23.1" -"@react-types/radio@^3.8.1", "@react-types/radio@3.8.1": +"@react-types/radio@3.8.1", "@react-types/radio@^3.8.1": version "3.8.1" resolved "https://registry.npmjs.org/@react-types/radio/-/radio-3.8.1.tgz" integrity sha512-bK0gio/qj1+0Ldu/3k/s9BaOZvnnRgvFtL3u5ky479+aLG5qf1CmYed3SKz8ErZ70JkpuCSrSwSCFf0t1IHovw== dependencies: "@react-types/shared" "^3.23.1" +"@react-types/select@3.9.4": + version "3.9.4" + resolved "https://registry.npmjs.org/@react-types/select/-/select-3.9.4.tgz" + integrity sha512-xI7dnOW2st91fPPcv6hdtrTdcfetYiqZuuVPZ5TRobY7Q10/Zqqe/KqtOw1zFKUj9xqNJe4Ov3xP5GSdcO60Eg== + dependencies: + "@react-types/shared" "^3.23.1" + "@react-types/select@^3.9.6": version "3.9.6" resolved "https://registry.npmjs.org/@react-types/select/-/select-3.9.6.tgz" @@ -2465,14 +2480,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/select@3.9.4": - version "3.9.4" - resolved "https://registry.npmjs.org/@react-types/select/-/select-3.9.4.tgz" - integrity sha512-xI7dnOW2st91fPPcv6hdtrTdcfetYiqZuuVPZ5TRobY7Q10/Zqqe/KqtOw1zFKUj9xqNJe4Ov3xP5GSdcO60Eg== - dependencies: - "@react-types/shared" "^3.23.1" - -"@react-types/shared@^3.23.1", "@react-types/shared@3.23.1": +"@react-types/shared@3.23.1", "@react-types/shared@^3.23.1": version "3.23.1" resolved "https://registry.npmjs.org/@react-types/shared/-/shared-3.23.1.tgz" integrity sha512-5d+3HbFDxGZjhbMBeFHRQhexMFt4pUce3okyRtUVKbbedQFUrtXSBg9VszgF2RTeQDKDkMCIQDtz5ccP/Lk1gw== @@ -2496,7 +2504,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/table@^3.9.5", "@react-types/table@3.9.5": +"@react-types/table@3.9.5", "@react-types/table@^3.9.5": version "3.9.5" resolved "https://registry.npmjs.org/@react-types/table/-/table-3.9.5.tgz" integrity sha512-fgM2j9F/UR4Anmd28CueghCgBwOZoCVyN8fjaIFPd2MN4gCwUUfANwxLav65gZk4BpwUXGoQdsW+X50L3555mg== @@ -2504,21 +2512,21 @@ "@react-types/grid" "^3.2.6" "@react-types/shared" "^3.23.1" -"@react-types/tabs@^3.3.7", "@react-types/tabs@3.3.7": +"@react-types/tabs@3.3.7", "@react-types/tabs@^3.3.7": version "3.3.7" resolved "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.3.7.tgz" integrity sha512-ZdLe5xOcFX6+/ni45Dl2jO0jFATpTnoSqj6kLIS/BYv8oh0n817OjJkLf+DS3CLfNjApJWrHqAk34xNh6nRnEg== dependencies: "@react-types/shared" "^3.23.1" -"@react-types/textfield@^3.9.3", "@react-types/textfield@3.9.3": +"@react-types/textfield@3.9.3", "@react-types/textfield@^3.9.3": version "3.9.3" resolved "https://registry.npmjs.org/@react-types/textfield/-/textfield-3.9.3.tgz" integrity sha512-DoAY6cYOL0pJhgNGI1Rosni7g72GAt4OVr2ltEx2S9ARmFZ0DBvdhA9lL2nywcnKMf27PEJcKMXzXc10qaHsJw== dependencies: "@react-types/shared" "^3.23.1" -"@react-types/tooltip@^3.4.9", "@react-types/tooltip@3.4.9": +"@react-types/tooltip@3.4.9", "@react-types/tooltip@^3.4.9": version "3.4.9" resolved "https://registry.npmjs.org/@react-types/tooltip/-/tooltip-3.4.9.tgz" integrity sha512-wZ+uF1+Zc43qG+cOJzioBmLUNjRa7ApdcT0LI1VvaYvH5GdfjzUJOorLX9V/vAci0XMJ50UZ+qsh79aUlw2yqg== @@ -2531,7 +2539,7 @@ resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz" integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== -"@swc/helpers@^0.5.0", "@swc/helpers@0.5.5": +"@swc/helpers@0.5.5", "@swc/helpers@^0.5.0": version "0.5.5" resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz" integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A== @@ -4037,7 +4045,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0": +"@types/react@*": version "18.3.11" resolved "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz" integrity sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ== @@ -4058,6 +4066,11 @@ abab@^2.0.5, abab@^2.0.6: resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" @@ -4108,13 +4121,6 @@ ag-grid-react@^32.0.2: ag-grid-community "32.1.0" prop-types "^15.8.1" -agent-base@^7.0.2, agent-base@^7.1.0: - version "7.1.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" - integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== - dependencies: - debug "^4.3.4" - agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -4122,6 +4128,13 @@ agent-base@6: dependencies: debug "4" +agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" @@ -4164,6 +4177,19 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + arg@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" @@ -4231,6 +4257,14 @@ body-scroll-lock@^3.1.5: resolved "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz" integrity sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg== +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + brace-expansion@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" @@ -4285,6 +4319,15 @@ caniuse-lite@^1.0.30001579: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz" integrity sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA== +canvas@^2.8.0: + version "2.11.2" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860" + integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + nan "^2.17.0" + simple-get "^3.0.3" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -4294,7 +4337,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0": +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: version "3.6.0" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -4309,22 +4352,22 @@ chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0": optionalDependencies: fsevents "~2.3.2" +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + classnames@^2.3.1: version "2.5.1" resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== -client-only@^0.0.1, client-only@0.0.1: +client-only@0.0.1, client-only@^0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== -clsx@^1.1.1: - version "1.2.1" - resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" - integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== - -clsx@^1.2.1: +clsx@^1.1.1, clsx@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== @@ -4348,16 +4391,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + color-string@^1.9.0: version "1.9.1" resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" @@ -4366,6 +4409,16 @@ color-string@^1.9.0: color-name "^1.0.0" simple-swizzle "^0.2.2" +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +color2k@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz" + integrity sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog== + color@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/color/-/color-4.2.3.tgz" @@ -4374,11 +4427,6 @@ color@^4.2.3: color-convert "^2.0.1" color-string "^1.9.0" -color2k@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz" - integrity sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog== - combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -4386,6 +4434,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@2: + version "2.20.3" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@^11.0.0: version "11.1.0" resolved "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz" @@ -4396,11 +4449,6 @@ commander@^4.0.0: resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== -commander@2: - version "2.20.3" - resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - complex.js@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz" @@ -4411,6 +4459,11 @@ compute-scroll-into-view@^3.0.2: resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz" integrity sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg== +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + concaveman@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/concaveman/-/concaveman-1.2.1.tgz" @@ -4421,6 +4474,11 @@ concaveman@^1.2.1: robust-predicates "^2.0.4" tinyqueue "^2.0.3" +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + convert-source-map@^1.5.0: version "1.9.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" @@ -4521,6 +4579,13 @@ dayjs@^1.11.13: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== +debug@4, debug@^4.3.3, debug@^4.3.4: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + debug@^4.3.1: version "4.3.7" resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz" @@ -4528,18 +4593,18 @@ debug@^4.3.1: dependencies: ms "^2.1.3" -debug@^4.3.3, debug@^4.3.4, debug@4: - version "4.3.5" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - decimal.js@^10.3.1, decimal.js@^10.4.3: version "10.4.3" resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== +decompress-response@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" + integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== + dependencies: + mimic-response "^2.0.0" + deepmerge@4.3.1: version "4.3.1" resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" @@ -4555,6 +4620,16 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +detect-libc@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + detect-node-es@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz" @@ -4745,13 +4820,25 @@ fraction.js@^4.3.7: resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz" integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== -framer-motion@^11.2.13, framer-motion@>=10.17.0: +framer-motion@^11.2.13: version "11.3.21" resolved "https://registry.npmjs.org/framer-motion/-/framer-motion-11.3.21.tgz" integrity sha512-D+hfIsvzV8eL/iycld4K+tKlg2Q2LdwnrcBEohtGw3cG1AIuNYATbT5RUqIM1ndsAk+EfGhoSGf0UaiFodc5Tw== dependencies: tslib "^2.4.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + fs@^0.0.1-security: version "0.0.1-security" resolved "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz" @@ -4767,6 +4854,21 @@ function-bind@^1.1.2: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + geojson-equality-ts@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/geojson-equality-ts/-/geojson-equality-ts-1.0.2.tgz" @@ -4811,6 +4913,18 @@ glob@^10.3.10: minipass "^7.1.2" path-scurry "^1.11.1" +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" @@ -4831,6 +4945,11 @@ has-flag@^3.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + hasown@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" @@ -4885,7 +5004,7 @@ https-proxy-agent@^7.0.0: agent-base "^7.0.2" debug "4" -iconv-lite@^0.6.3, iconv-lite@0.6.3: +iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -4910,9 +5029,17 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" -inherits@^2.0.4: +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== international-types@^0.8.1: @@ -5243,6 +5370,13 @@ lru-cache@^10.2.0: resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz" integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + marchingsquares@^1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/marchingsquares/-/marchingsquares-1.3.3.tgz" @@ -5293,6 +5427,18 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" +mimic-response@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" + integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimatch@^9.0.4: version "9.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" @@ -5300,17 +5446,37 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== -minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" -ms@^2.1.1, ms@2.1.2: +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -5341,6 +5507,11 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" +nan@^2.17.0: + version "2.22.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3" + integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw== + nanoid@^3.3.6, nanoid@^3.3.7: version "3.3.7" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" @@ -5383,11 +5554,35 @@ next@14.2.3: "@next/swc-win32-ia32-msvc" "14.2.3" "@next/swc-win32-x64-msvc" "14.2.3" +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + nwsapi@^2.2.0: version "2.2.10" resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz" @@ -5403,6 +5598,13 @@ object-hash@^3.0.0: resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== +once@^1.3.0, once@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + open@^8.0.0: version "8.4.2" resolved "https://registry.npmjs.org/open/-/open-8.4.2.tgz" @@ -5434,6 +5636,11 @@ parse5@6.0.1: resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" @@ -5539,15 +5746,6 @@ postcss-value-parser@^4.0.0: resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8, postcss@^8.0.0, postcss@^8.2.14, postcss@^8.4.21, postcss@^8.4.23, postcss@>=8.0.9: - version "8.4.38" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz" - integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.2.0" - postcss@8.4.31: version "8.4.31" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" @@ -5557,6 +5755,15 @@ postcss@8.4.31: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^8, postcss@^8.4.23: + version "8.4.38" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz" + integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.2.0" + prettier@^3.3.3: version "3.3.3" resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz" @@ -5646,7 +5853,7 @@ react-datepicker@^7.3.0: prop-types "^15.7.2" react-onclickoutside "^6.13.0" -"react-dom@^15.5.x || ^16.x || ^17.x || ^18.x", "react-dom@^16.3.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17 || ^18", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", "react-dom@^16.9.0 || ^17 || ^18", react-dom@^18, react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 16.3.0", react-dom@>=16.6.0, react-dom@>=16.8.0, react-dom@>=18: +react-dom@^18: version "18.3.1" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -5758,7 +5965,7 @@ react-transition-group@^4.3.0: loose-envify "^1.4.0" prop-types "^15.6.2" -react@*, "react@^15.5.x || ^16.x || ^17.x || ^18.x", "react@^16.3.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17 || ^18", "react@^16.8.0 || ^17 || ^18", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", "react@^16.9.0 || ^17 || ^18", react@^18, react@^18.0.0, react@^18.2.0, react@^18.3.1, "react@>= 16.3.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16.13.1, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18: +react@^18: version "18.3.1" resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -5772,6 +5979,15 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@^4.2.0: version "4.5.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz" @@ -5831,6 +6047,13 @@ rfdc@^1.3.0: resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz" integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + robust-predicates@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz" @@ -5863,7 +6086,7 @@ safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass@^1.3.0, sass@^1.77.8: +sass@^1.77.8: version "1.77.8" resolved "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz" integrity sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ== @@ -5898,6 +6121,16 @@ seedrandom@^3.0.5: resolved "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz" integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== +semver@^6.0.0: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.5: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + semver@^7.5.4: version "7.6.2" resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" @@ -5908,6 +6141,11 @@ server-only@^0.0.1: resolved "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz" integrity sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA== +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -5920,11 +6158,30 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +signal-exit@^3.0.0: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55" + integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== + dependencies: + decompress-response "^4.2.0" + once "^1.3.1" + simple-concat "^1.0.0" + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" @@ -5937,7 +6194,7 @@ skmeans@0.9.7: resolved "https://registry.npmjs.org/skmeans/-/skmeans-0.9.7.tgz" integrity sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg== -source-map-js@^1.0.2, source-map-js@^1.2.0, "source-map-js@>=0.6.2 <2.0.0": +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== @@ -5972,13 +6229,6 @@ streamsearch@^1.1.0: resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string_decoder@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -5988,16 +6238,16 @@ string_decoder@^1.3.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.1.0: +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.1: +string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -6006,14 +6256,12 @@ string-width@^5.0.1: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== +string_decoder@^1.1.1, string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" + safe-buffer "~5.2.0" "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" @@ -6085,7 +6333,7 @@ sweetalert2-react-content@^5.0.7: resolved "https://registry.npmjs.org/sweetalert2-react-content/-/sweetalert2-react-content-5.0.7.tgz" integrity sha512-8Fk82Mpk45lFXpJWKIFF/lq8k/dJKDDQGFcuqVosaL/qRdViyAs5+u37LoTGfnOIvf+rfQB3PAXcp1XLLn+0ew== -sweetalert2@^11.0.0, sweetalert2@^11.14.1: +sweetalert2@^11.14.1: version "11.14.1" resolved "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.14.1.tgz" integrity sha512-xadhfcA4STGMh8nC5zHFFWURhRpWc4zyI3GdMDFH/m3hGWZeQQNWhX9xcG4lI9gZYsi/IlazKbwvvje3juL3Xg== @@ -6112,7 +6360,7 @@ tailwind-variants@^0.1.20: dependencies: tailwind-merge "^1.14.0" -tailwindcss@*, tailwindcss@^3.4.1, tailwindcss@>=3.4.0: +tailwindcss@^3.4.1: version "3.4.4" resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz" integrity sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A== @@ -6140,6 +6388,18 @@ tailwindcss@*, tailwindcss@^3.4.1, tailwindcss@>=3.4.0: resolve "^1.22.2" sucrase "^3.32.0" +tar@^6.1.11: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + tarn@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz" @@ -6228,6 +6488,11 @@ tr46@^3.0.0: dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + ts-interface-checker@^0.1.9: version "0.1.13" resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" @@ -6298,9 +6563,9 @@ use-sidecar@^1.1.2: detect-node-es "^1.1.0" tslib "^2.0.0" -util-deprecate@^1.0.2: +util-deprecate@^1.0.1, util-deprecate@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== uuid@^10.0.0: @@ -6327,6 +6592,11 @@ w3c-xmlserializer@^3.0.0: dependencies: xml-name-validator "^4.0.0" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" @@ -6360,6 +6630,14 @@ whatwg-url@^11.0.0: tr46 "^3.0.0" webidl-conversions "^7.0.0" +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" @@ -6367,6 +6645,13 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" @@ -6385,6 +6670,11 @@ wrap-ansi@^8.1.0: string-width "^5.0.1" strip-ansi "^7.0.1" +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + ws@^8.2.3: version "8.17.1" resolved "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz" @@ -6400,6 +6690,11 @@ xmlchars@^2.2.0: resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yaml@^1.10.0: version "1.10.2" resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" From a1f80b0752f65eadad0ef8c1b49e1550f7ac5786 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 4 Nov 2024 18:03:43 +0900 Subject: [PATCH 29/63] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 2777 +++++++++++++-------------- src/styles/_modal.scss | 3711 +++++++++++++++++++------------------ 2 files changed, 3369 insertions(+), 3119 deletions(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 6715d48b..7795cab8 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -17,1444 +17,1493 @@ // } // } // CanvasMenu -.canvas-menu-wrap{ - position: fixed; - top: 46px; - left: 0; - display: block; - width: 100%; - min-width: 1280px; - padding-bottom: 0; - background-color: #383838; - transition: padding .17s ease-in-out; - z-index: 999; - .canvas-menu-inner{ - position: relative; - display: flex; - align-items: center; - padding: 0 40px 0 20px; - background-color: #2C2C2C; - height: 46.8px; - z-index: 999; - .canvas-menu-list{ - display: flex; - align-items: center; - height: 100%; - .canvas-menu-item{ - display: flex; - align-items: center; - height: 100%; - button{ - display: flex; - align-items: center; - font-size: 12px; - height: 100%; - color: #fff; - font-weight: 600; - padding: 15px 20px; - opacity: 0.55; - transition: all .17s ease-in-out; - .menu-icon{ - display: block; - width: 14px; - height: 14px; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - margin-right: 10px; - &.con00{background-image: url(/static/images/canvas/menu_icon00.svg);} - &.con01{background-image: url(/static/images/canvas/menu_icon01.svg);} - &.con02{background-image: url(/static/images/canvas/menu_icon02.svg);} - &.con03{background-image: url(/static/images/canvas/menu_icon03.svg);} - &.con04{background-image: url(/static/images/canvas/menu_icon04.svg);} - &.con05{background-image: url(/static/images/canvas/menu_icon05.svg);} - &.con06{background-image: url(/static/images/canvas/menu_icon06.svg);} - } - } - &.active{ - background-color: #383838; - button{ - opacity: 1; - } - } - } - } - .canvas-side-btn-wrap{ - display: flex; - align-items: center; - margin-left: auto; - .select-box{ - width: 124px; - margin: 0 5px; - height: 30px; - > div{ - width: 100%; - } - } - .btn-from{ - display: flex; - align-items: center; - gap: 5px; - button{ - display: block; - width: 30px; - height: 30px; - border-radius: 2px; - background-color: #3D3D3D; - background-position: center; - background-repeat: no-repeat; - background-size: 15px 15px; - transition: all .17s ease-in-out; - &.btn01{background-image: url(../../public/static/images/canvas/side_icon03.svg);} - &.btn02{background-image: url(../../public/static/images/canvas/side_icon02.svg);} - &.btn03{background-image: url(../../public/static/images/canvas/side_icon01.svg);} - &.btn04{background-image: url(../../public/static/images/canvas/side_icon04.svg);} - &.btn05{background-image: url(../../public/static/images/canvas/side_icon05.svg);} - &.btn06{background-image: url(../../public/static/images/canvas/side_icon06.svg);} - &.btn07{background-image: url(../../public/static/images/canvas/side_icon07.svg);} - &.btn08{background-image: url(../../public/static/images/canvas/side_icon08.svg);} - &.btn09{background-image: url(../../public/static/images/canvas/side_icon09.svg);} - &:hover{ - background-color: #1083E3; - } - &.active{ - background-color: #1083E3; - } - } - } - .ico-btn-from{ - display: flex; - align-items: center; - gap: 5px; - button{ - .ico{ - display: block; - width: 15px; - height: 15px; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - &.ico01{background-image: url(../../public/static/images/canvas/ico-flx01.svg);} - &.ico02{background-image: url(../../public/static/images/canvas/ico-flx02.svg);} - &.ico03{background-image: url(../../public/static/images/canvas/ico-flx03.svg);} - &.ico04{background-image: url(../../public/static/images/canvas/ico-flx04.svg);} - } - .name{ - font-size: 12px; - color: #fff; - } - } - &.form06{ - .name{ - font-size: 13px; - } - } - } - .vertical-horizontal{ - display: flex; - min-width: 170px; - height: 28px; - margin-right: 5px; - border-radius: 2px; - background: #373737; - line-height: 28px; - overflow: hidden; - span{ - padding: 0 10px; - font-size: 13px; - color: #fff; - } - button{ - margin-left: auto; - height: 100%; - background-color: #4B4B4B; - font-size: 13px; - font-weight: 400; - color: #fff; - padding: 0 7.5px; - transition: all .17s ease-in-out; - } - &.on{ - button{ - background-color: #1083E3; - } - } - } - .size-control{ - display: flex; - align-items: center; - justify-content: center; - gap: 10px; - background-color: #3D3D3D; - border-radius: 2px; - width: 100px; - height: 30px; - margin: 0 5px; - span{ - font-size: 13px; - color: #fff; - } - .control-btn{ - display: block; - width: 12px; - height: 12px; - background-repeat: no-repeat; - background-size: cover; - background-position: center; - &.minus{ - background-image: url(../../public/static/images/canvas/minus.svg); - } - &.plus{ - background-image: url(../../public/static/images/canvas/plus.svg); - } - } - } - } - } - .canvas-depth2-wrap{ - position: absolute; - top: -100%; - left: 0; - background-color: #383838; - width: 100%; - height: 50px; - transition: all .17s ease-in-out; - .canvas-depth2-inner{ - display: flex; - align-items: center; - padding: 0 40px; - height: 100%; - .canvas-depth2-list{ - display: flex; - align-items: center ; - height: 100%; - .canvas-depth2-item{ - display: flex; - align-items: center; - margin-right: 26px; - height: 100%; - button{ - position: relative; - opacity: 0.55; - color: #fff; - font-size: 12px; - font-weight: normal; - height: 100%; - padding-right: 12px; - } - &.active{ - button{ - opacity: 1; - font-weight: 600; - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; - } - } - } - } - } - .canvas-depth2-btn-list{ - display: flex; - align-items: center; - margin-left: auto; - height: 100%; - .depth2-btn-box{ - display: flex; - align-items: center; - margin-right: 34px; - height: 100%; - transition: all .17s ease-in-out; - button{ - position: relative; - font-size: 12px; - font-weight: 400; - height: 100%; - color: #fff; - padding-right: 12px; - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; - } - } - &:last-child{ - margin-right: 0; - } - &.mouse{ - opacity: 0.55; - } - } - } - } - &.active{ - top: 47px; - } - } - &.active{ - padding-bottom: 50px; - } -} - -// canvas-layout -.canvas-content{ - padding-top: 46.8px; - transition: all .17s ease-in-out; - .canvas-frame{ - height: calc(100vh - 129.3px); - } - &.active{ - padding-top: calc(46.8px + 50px); - .canvas-frame{ - height: calc(100vh - 179.4px); - } - } -} -.canvas-layout{ - padding-top: 37px; - .canvas-page-list{ - position: fixed; - top: 92.8px; - left: 0; - display: flex; - background-color: #1C1C1C; - border-top: 1px solid #000; - width: 100%; - min-width: 1280px; - transition: all .17s ease-in-out; - z-index: 99; - &.active{ - top: calc(92.8px + 50px); - } - .canvas-plane-wrap{ - display: flex; - align-items: center; - max-width: calc(100% - 45px); - .canvas-page-box{ - display: flex; - align-items: center; - background-color: #1c1c1c; - padding: 9.6px 20px; - border-right:1px solid #000; - min-width: 0; - transition: all .17s ease-in-out; - span{ - display: flex; - align-items: center; - width: 100%; - font-size: 12px; - font-family: 'Pretendard', sans-serif; - color: #AAA; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - .close{ - flex: none; - display: block; - width: 7px; - height: 8px; - margin-left: 15px; - background: url(../../public/static/images/canvas/plan_close_gray.svg)no-repeat center; - background-size: cover; - } - &.on{ - background-color: #fff; - span{ - font-weight: 600; - color: #101010; - } - .close{ - background: url(../../public/static/images/canvas/plan_close_black.svg)no-repeat center; - } - &:hover{ - background-color: #fff; - } - } - &:hover{ - background-color: #000; - } - } - } - .plane-add{ - display: flex; - align-items: center; - justify-content: center; - width: 45px; - padding: 13.5px 0; - background-color: #1C1C1C; - border-right: 1px solid #000; - transition: all .17s ease-in-out; - span{ - display: block; - width: 9px; - height: 9px; - background: url(../../public/static/images/canvas/plane_add.svg)no-repeat center; - background-size: cover; - } - &:hover{ - background-color: #000; - } - } - } -} - -.canvas-frame{ +.canvas-menu-wrap { + position: fixed; + top: 46px; + left: 0; + display: block; + width: 100%; + min-width: 1280px; + padding-bottom: 0; + background-color: #383838; + transition: padding 0.17s ease-in-out; + z-index: 999; + .canvas-menu-inner { position: relative; - // height: calc(100% - 36.5px); - background-color: #F4F4F7; - overflow: auto; - transition: all .17s ease-in-out; - // &::-webkit-scrollbar { - // width: 10px; - // height: 10px; - // background-color: #fff; - // } - // &::-webkit-scrollbar-thumb { - // background-color: #C1CCD7; - // border-radius: 30px; - // } - // &::-webkit-scrollbar-track { - // background-color: #fff; - // } - .canvas-container{ - margin: 0 auto; - background-color: #fff; - } - canvas{ - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - } -} - -// sub-page -.sub-header{ - position: fixed; - top: 46px; - left: 0; - width: 100%; - min-width: 1280px; - height: 46px; - border-bottom: 1px solid #000; - background: #2C2C2C; + display: flex; + align-items: center; + padding: 0 40px 0 20px; + background-color: #2c2c2c; + height: 46.8px; z-index: 999; - .sub-header-inner{ + .canvas-menu-list { + display: flex; + align-items: center; + height: 100%; + .canvas-menu-item { display: flex; align-items: center; height: 100%; - padding: 0 100px; - .sub-header-title-wrap{ - display: flex; - align-items: center; - .title-item{ - position: relative; - padding: 0 24px; - a{ - display: flex; - align-items: center; - .icon{ - width: 22px; - height: 22px; - margin-right: 8px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - &.drawing{background-image: url(../../public/static/images/main/drawing_icon.svg);} - } - } - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 16px; - background-color: #D9D9D9; - } - &:first-child{ - padding-left: 0; - } - &:last-child{ - padding-right: 0; - &:after{ - display: none; - } - } + button { + display: flex; + align-items: center; + font-size: 12px; + height: 100%; + color: #fff; + font-weight: 600; + padding: 15px 20px; + opacity: 0.55; + transition: all 0.17s ease-in-out; + .menu-icon { + display: block; + width: 14px; + height: 14px; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + margin-right: 10px; + &.con00 { + background-image: url(/static/images/canvas/menu_icon00.svg); } + &.con01 { + background-image: url(/static/images/canvas/menu_icon01.svg); + } + &.con02 { + background-image: url(/static/images/canvas/menu_icon02.svg); + } + &.con03 { + background-image: url(/static/images/canvas/menu_icon03.svg); + } + &.con04 { + background-image: url(/static/images/canvas/menu_icon04.svg); + } + &.con05 { + background-image: url(/static/images/canvas/menu_icon05.svg); + } + &.con06 { + background-image: url(/static/images/canvas/menu_icon06.svg); + } + } } - .sub-header-title{ - font-size: 16px; + &.active { + background-color: #383838; + button { + opacity: 1; + } + } + } + } + .canvas-side-btn-wrap { + display: flex; + align-items: center; + margin-left: auto; + .select-box { + width: 124px; + margin: 0 5px; + height: 30px; + > div { + width: 100%; + } + } + .btn-from { + display: flex; + align-items: center; + gap: 5px; + button { + display: block; + width: 30px; + height: 30px; + border-radius: 2px; + background-color: #3d3d3d; + background-position: center; + background-repeat: no-repeat; + background-size: 15px 15px; + transition: all 0.17s ease-in-out; + &.btn01 { + background-image: url(../../public/static/images/canvas/side_icon03.svg); + } + &.btn02 { + background-image: url(../../public/static/images/canvas/side_icon02.svg); + } + &.btn03 { + background-image: url(../../public/static/images/canvas/side_icon01.svg); + } + &.btn04 { + background-image: url(../../public/static/images/canvas/side_icon04.svg); + } + &.btn05 { + background-image: url(../../public/static/images/canvas/side_icon05.svg); + } + &.btn06 { + background-image: url(../../public/static/images/canvas/side_icon06.svg); + } + &.btn07 { + background-image: url(../../public/static/images/canvas/side_icon07.svg); + } + &.btn08 { + background-image: url(../../public/static/images/canvas/side_icon08.svg); + } + &.btn09 { + background-image: url(../../public/static/images/canvas/side_icon09.svg); + } + &:hover { + background-color: #1083e3; + } + &.active { + background-color: #1083e3; + } + } + } + .ico-btn-from { + display: flex; + align-items: center; + gap: 5px; + button { + .ico { + display: block; + width: 15px; + height: 15px; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + &.ico01 { + background-image: url(../../public/static/images/canvas/ico-flx01.svg); + } + &.ico02 { + background-image: url(../../public/static/images/canvas/ico-flx02.svg); + } + &.ico03 { + background-image: url(../../public/static/images/canvas/ico-flx03.svg); + } + &.ico04 { + background-image: url(../../public/static/images/canvas/ico-flx04.svg); + } + } + .name { + font-size: 12px; color: #fff; - font-weight: 600; + } } - .sub-header-location{ - margin-left: auto; - display: flex; - align-items: center; - .location-item{ - position: relative; - display: flex; - align-items: center; - padding: 0 10px; - span{ - display: flex; - font-size: 12px; - color: #AAA; - font-weight: normal; - cursor: default; - } - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 4px; - height: 6px; - background: url(../../public/static/images/main/loaction_arr.svg)no-repeat center; - } - &:first-child{ - padding-left: 0; - } - &:last-child{ - padding-right: 0; - span{ - color: #fff; - } - &:after{ - display: none; - } - } - } + &.form06 { + .name { + font-size: 13px; + } } - } -} - -// sub content -.sub-content{ - padding-top: 46px; - .sub-content-inner{ - max-width: 1760px; - margin: 0 auto; - padding: 20px 20px 0; - .sub-content-box{ - margin-bottom: 20px; - &:last-child{ - margin-bottom: 0; - } - } - } - &.estimate{ + } + .vertical-horizontal { display: flex; - flex-direction: column; - padding-top: 0; - .sub-content-inner{ - flex: 1; - width: 100%; + min-width: 170px; + height: 28px; + margin-right: 5px; + border-radius: 2px; + background: #373737; + line-height: 28px; + overflow: hidden; + span { + padding: 0 10px; + font-size: 13px; + color: #fff; } - } -} -.sub-table-box{ - padding: 20px; - border-radius: 6px; - border: 1px solid #E9EAED; - background: #FFF; - box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); - .table-box-title-wrap{ - display: flex; - align-items: center; - margin-bottom: 15px; - .title-wrap{ - display: flex; - align-items: center; - h3{ - display: block; - font-size: 15px; - color: #101010; - font-weight: 600; - margin-right: 14px; - &.product{ - margin-right: 10px; - } - } - .product_tit{ - position: relative; - font-size: 15px; - font-weight: 600; - color: #1083E3; - padding-left: 10px; - &::before{ - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 1px; - height: 11px; - background-color: #D9D9D9; - } - } - .option{ - padding-left: 5px; - font-size: 13px; - color: #101010; - font-weight: 400; - } - .info-wrap{ - display: flex; - align-items: center; - li{ - position: relative; - padding: 0 6px; - font-size: 12px; - color: #101010; - font-weight: normal; - span{ - font-weight: 600; - &.red{ - color: #E23D70; - } - } - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 11px; - background-color: #D9D9D9; - } - &:first-child{padding-left: 0;} - &:last-child{padding-right: 0;&::after{display: none;}} - } - } + button { + margin-left: auto; + height: 100%; + background-color: #4b4b4b; + font-size: 13px; + font-weight: 400; + color: #fff; + padding: 0 7.5px; + transition: all 0.17s ease-in-out; } - } - .left-unit-box{ - margin-left: auto; - display: flex; - align-items: center; - } - .promise-gudie{ - display: block; - font-size: 13px; - font-weight: 700; - color: #101010; - margin-bottom: 20px; - } - .important{ - color: #f00; - } - .sub-center-footer{ + &.on { + button { + background-color: #1083e3; + } + } + } + .size-control { display: flex; align-items: center; justify-content: center; - margin-top: 20px; - } - .sub-right-footer{ - display: flex; - align-items: center; - justify-content: flex-end; - margin-top: 20px; - } -} -.pagination-wrap{ - margin-top: 24px; -} - -.infomation-wrap{ - margin-bottom: 30px; -} - -.infomation-box-wrap{ - display: flex; - gap: 10px; - .sub-table-box{ - flex: 1 ; - } - .info-title{ - font-size: 14px; - font-weight: 500; - color: #344356; - margin-bottom: 10px; - } - .info-inner{ - position: relative; - font-size: 13px; - color: #344356; - .copy-ico{ - position: absolute; - bottom: 0; - right: 0; - width: 16px; - height: 16px; - background: url(../../public/static/images/sub/copy_ico.svg)no-repeat center; - background-size: cover; + gap: 10px; + background-color: #3d3d3d; + border-radius: 2px; + width: 100px; + height: 30px; + margin: 0 5px; + span { + font-size: 13px; + color: #fff; } - } -} - -// 견적서 -.estimate-list-wrap{ - display: flex; - align-items: center; - margin-bottom: 10px; - &.one{ - .estimate-box{ - &:last-child{ - min-width: unset; - } + .control-btn { + display: block; + width: 12px; + height: 12px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + &.minus { + background-image: url(../../public/static/images/canvas/minus.svg); + } + &.plus { + background-image: url(../../public/static/images/canvas/plus.svg); + } } + } } - .estimate-box{ - flex: 1 ; - display: flex; - align-items: center; - &:last-child{ - flex: none; - min-width: 220px; - } - .estimate-tit{ - width: 105px; - height: 30px; - line-height: 30px; - background-color: #F4F4F7; - border-radius: 100px; - text-align: center; - font-size: 13px; - font-weight: 500; - color: #344356; - } - .estimate-name{ - font-size: 13px; - color: #344356; - margin-left: 14px; - font-weight: 400; - &.blue{ - font-size: 16px; - font-weight: 700; - color: #1083E3; - } - &.red{ - font-size: 16px; - font-weight: 700; - color: #D72A2A; - } - } - } - &:last-child{ - margin-bottom: 0; - } -} - -// file drag box -.drag-file-box{ - padding: 10px; - .btn-area{ - padding-bottom: 15px; - border-bottom: 1px solid #ECF0F4; - .file-upload{ - display: inline-block; - height: 30px; - background-color: #94A0AD; - padding: 0 10px; - border-radius: 2px; - font-size: 13px; - line-height: 30px; - color: #fff; - font-weight: 500; - cursor: pointer; - transition: background .15s ease-in-out; - &:hover{ - background-color: #607F9A; - } - } - } - .drag-file-area{ - position: relative; - margin-top: 15px; - p{ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 13px; - color: #ccc; - font-weight: 400; - cursor: default; - } - } - .file-list{ - .file-item{ - margin-bottom: 15px; - span{ - position: relative; - font-size: 13px; - color: #45576F; - font-weight: 400; - white-space: nowrap; - padding-right: 55px; - button{ - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 15px; - height: 15px; - background: url(../../public/static/images/sub/file_delete.svg)no-repeat center; - background-size: cover; - } - } - &:last-child{ - margin-bottom: 0; - } - } - } -} - -.estimate-arr-btn{ - display: block; - width: 20px; - height: 20px; - background-color: #94A0AD; - border: 1px solid #94A0AD; - background-position: center; - background-repeat: no-repeat; - background-image: url(../../public/static/images/canvas/estiment_arr.svg); - background-size: 11px 7px; - border-radius: 2px; - &.up{ - rotate: 180deg; - } - &.on{ - background-color: #fff; - border-color: #C2D0DD; - background-image: url(../../public/static/images/canvas/estiment_arr_color.svg) - } -} -.estimate-check-wrap{ - .estimate-check-inner{ - display: block; - } - &.hide{ - border-bottom: 1px solid #ECF0F4; - margin-bottom: 15px; - .estimate-check-inner{ - display: none; - } - } -} - -.special-note-check-wrap{ - display: grid; - grid-template-columns: repeat(5, 1fr); - border-radius: 3px; - margin-bottom: 30px; - .special-note-check-item{ - padding: 14px 10px; - border: 1px solid #ECF0F4; - margin-top: -1px; - margin-right: -1px; - &.act{ - background-color: #F7F9FA; - } - } -} - -.calculation-estimate{ - border: 1px solid #ECF0F4; - border-radius: 3px; - padding: 24px; - max-height: 350px; - overflow-y: auto; - margin-bottom: 30px; - dl{ - margin-bottom: 35px; - &:last-child{ - margin-bottom: 0; - } - dt{ - font-size: 13px; - font-weight: 600; - color: #1083E3; - margin-bottom: 15px; - } - dd{ - font-size: 12px; - font-weight: 400; - color: #45576F; - margin-bottom: 8px; - &:last-child{ - margin-bottom: 0; - } - } - } - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9dee2; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } -} -.esimate-wrap{ - margin-bottom: 20px; -} - -.estimate-product-option{ - display: flex; - align-items: center; - margin-bottom: 15px; - .product-price-wrap{ - display: flex; - align-items: center; - .product-price-tit{ - font-size: 13px; - font-weight: 400; - color: #45576F; - margin-right: 10px; - } - .select-wrap{ - width: 110px; - } - } - .product-edit-wrap{ - display: flex; - align-items: center; - margin-left: auto; - .product-edit-explane{ - display: flex; - align-items: center; - margin-right: 15px; - .explane-item{ - position: relative; - display: flex; - align-items: center; - padding: 0 10px; - font-size: 12px; - font-weight: 400; - span{ - width: 20px; - height: 20px; - margin-right: 5px; - background-size: cover; - background-repeat: no-repeat; - background-position: center; - } - &:before{ - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 1px; - height: 12px; - background-color: #D9D9D9; - } - &:first-child{ - padding-left: 0; - &::before{ - display: none; - } - } - &:last-child{ - padding-right: 0; - } - &.item01{ - color: #3BBB48; - span{ - background-image: url(../../public/static/images/sub/open_ico.svg); - } - } - &.item02{ - color: #909000; - span{ - background-image: url(../../public/static/images/sub/change_ico.svg); - } - } - &.item03{ - color: #0191C9; - span{ - background-image: url(../../public/static/images/sub/attachment_ico.svg); - } - } - &.item04{ - color: #F16A6A; - span{ - background-image: url(../../public/static/images/sub/click_check_ico.svg); - } - } - } - } - .product-edit-btn{ - display: flex; - align-items: center; - button{ - display: flex; - align-items: center; - span{ - width: 13px; - height: 13px; - margin-right: 5px; - background-size: cover; - &.plus{ - background: url(../../public/static/images/sub/plus_btn.svg)no-repeat center; - } - &.minus{ - background: url(../../public/static/images/sub/minus_btn.svg)no-repeat center; - } - } - } - } - } -} - -// 발전시물레이션 -.chart-wrap{ - display: flex; - gap: 20px; + } + .canvas-depth2-wrap { + position: absolute; + top: -100%; + left: 0; + background-color: #383838; width: 100%; - .sub-table-box{ - height: 100%; - } - .chart-inner{ - flex: 1; - .chart-box{ - margin-bottom: 30px; - } - } - .chart-table-wrap{ + height: 50px; + transition: all 0.17s ease-in-out; + .canvas-depth2-inner { + display: flex; + align-items: center; + padding: 0 40px; + height: 100%; + .canvas-depth2-list { display: flex; - flex-direction: column; - flex: none; - width: 650px; - .sub-table-box{ - flex: 1; - &:first-child{ - margin-bottom: 20px; - } - } - } -} - -.chart-month-table{ - table{ - table-layout: fixed; - border-collapse:collapse; - border: 1px solid #ECF0F4; - border-radius: 4px; - thead{ - th{ - padding: 4.5px 0; - border-bottom: 1px solid #ECF0F4; - text-align: center; - font-size: 13px; - color: #45576F; - font-weight: 500; - background-color: #F8F9FA; - } - } - tbody{ - td{ - font-size: 13px; - color: #45576F; - text-align: center; - padding: 4.5px 0; - } - } - } -} - -.simulation-guide-wrap{ - display: flex; - padding: 20px; - .simulation-tit-wrap{ - flex: none; - padding-right: 40px; - border-right: 1px solid #EEEEEE; - span{ - display: block; + align-items: center; + height: 100%; + .canvas-depth2-item { + display: flex; + align-items: center; + margin-right: 26px; + height: 100%; + button { position: relative; - padding-left: 60px; - font-size: 15px; - color: #14324F; - font-weight: 600; - &::before{ + opacity: 0.55; + color: #fff; + font-size: 12px; + font-weight: normal; + height: 100%; + padding-right: 12px; + } + &.active { + button { + opacity: 1; + font-weight: 600; + &:after { content: ''; position: absolute; top: 50%; - left: 0; + right: 0; transform: translateY(-50%); - width: 40px; - height: 40px; - background: url(../../public/static/images/sub/simulation_guide.svg)no-repeat center; - background-size: cover; + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; + } } + } } - } - .simulation-guide-box{ - flex: 1; - padding-left: 40px; - dl{ - margin-bottom: 25px; - dt{ - font-size: 13px; - color: #101010; - font-weight: 600; - margin-bottom: 5px; - } - dd{ - font-size: 12px; - color: #45576F; - font-weight: 400; - line-height: 24px; - } - &:last-child{ - margin-bottom: 0; - } - } - ul, ol{ - list-style: unset; - } - } -} - -.module-total{ - display: flex; - align-items: center; - background-color: #F8F9FA; - padding: 9px 0; - margin-right: 4px; - border: 1px solid #ECF0F4; - border-top: none; - .total-title{ - flex: 1; - text-align: center; - font-size: 13px; - color: #344356; - font-weight: 500; - } - .total-num{ - flex: none; - width: 121px; - text-align: center; - font-size: 15px; - color: #344356; - font-weight: 500; - } -} - -// 물건상세 -.information-help-wrap{ - display: flex; - padding: 24px; - background-color: #F4F4F4; - border-radius: 4px; - margin-bottom: 15px; - .information-help-tit-wrap{ - position: relative; + } + .canvas-depth2-btn-list { display: flex; align-items: center; - padding-right: 40px; - border-right: 1px solid #E0E0E3; - .help-tit-icon{ - width: 40px; - height: 40px; - border-radius: 50%; - margin-right: 10px; - background: #fff url(../../public/static/images/sub/information_help.svg)no-repeat center; - background-size: 20px 20px; - } - .help-tit{ - font-size: 13px; - font-weight: 600; - color: #45576F; - } - } - .information-help-guide{ - padding-left: 40px; - span{ - display: block; + margin-left: auto; + height: 100%; + .depth2-btn-box { + display: flex; + align-items: center; + margin-right: 34px; + height: 100%; + transition: all 0.17s ease-in-out; + button { + position: relative; font-size: 12px; font-weight: 400; - color: #45576F; - margin-bottom: 7px; - &:last-child{ - margin-bottom: 0; + height: 100%; + color: #fff; + padding-right: 12px; + &:after { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; } + } + &:last-child { + margin-right: 0; + } + &.mouse { + opacity: 0.55; + } } + } } + &.active { + top: 47px; + } + } + &.active { + padding-bottom: 50px; + } } -.community-search-warp{ +// canvas-layout +.canvas-content { + padding-top: 46.8px; + transition: all 0.17s ease-in-out; + .canvas-frame { + height: calc(100vh - 129.3px); + } + &.active { + padding-top: calc(46.8px + 50px); + .canvas-frame { + height: calc(100vh - 179.4px); + } + } +} +.canvas-layout { + padding-top: 37px; + .canvas-page-list { + position: fixed; + top: 92.8px; + left: 0; + display: flex; + background-color: #1c1c1c; + border-top: 1px solid #000; + width: 100%; + min-width: 1280px; + transition: all 0.17s ease-in-out; + z-index: 99; + &.active { + top: calc(92.8px + 50px); + } + .canvas-plane-wrap { + display: flex; + align-items: center; + max-width: calc(100% - 45px); + .canvas-page-box { + display: flex; + align-items: center; + background-color: #1c1c1c; + padding: 9.6px 20px; + border-right: 1px solid #000; + min-width: 0; + transition: all 0.17s ease-in-out; + span { + display: flex; + align-items: center; + width: 100%; + font-size: 12px; + font-family: 'Pretendard', sans-serif; + color: #aaa; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + .close { + flex: none; + display: block; + width: 7px; + height: 8px; + margin-left: 15px; + background: url(../../public/static/images/canvas/plan_close_gray.svg) no-repeat center; + background-size: cover; + } + &.on { + background-color: #fff; + span { + font-weight: 600; + color: #101010; + } + .close { + background: url(../../public/static/images/canvas/plan_close_black.svg) no-repeat center; + } + &:hover { + background-color: #fff; + } + } + &:hover { + background-color: #000; + } + } + } + .plane-add { + display: flex; + align-items: center; + justify-content: center; + width: 45px; + padding: 13.5px 0; + background-color: #1c1c1c; + border-right: 1px solid #000; + transition: all 0.17s ease-in-out; + span { + display: block; + width: 9px; + height: 9px; + background: url(../../public/static/images/canvas/plane_add.svg) no-repeat center; + background-size: cover; + } + &:hover { + background-color: #000; + } + } + } +} + +.canvas-frame { + position: relative; + // height: calc(100% - 36.5px); + background-color: #f4f4f7; + overflow: auto; + transition: all 0.17s ease-in-out; + // &::-webkit-scrollbar { + // width: 10px; + // height: 10px; + // background-color: #fff; + // } + // &::-webkit-scrollbar-thumb { + // background-color: #C1CCD7; + // border-radius: 30px; + // } + // &::-webkit-scrollbar-track { + // background-color: #fff; + // } + .canvas-container { + margin: 0 auto; + background-color: #fff; + } + canvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +} + +// sub-page +.sub-header { + position: fixed; + top: 46px; + left: 0; + width: 100%; + min-width: 1280px; + height: 46px; + border-bottom: 1px solid #000; + background: #2c2c2c; + z-index: 999; + .sub-header-inner { display: flex; - flex-direction: column; align-items: center; - padding: 10px 0 30px 0; - border-bottom: 1px solid #E5E5E5; - margin-bottom: 24px; - .community-search-box{ + height: 100%; + padding: 0 100px; + .sub-header-title-wrap { + display: flex; + align-items: center; + .title-item { + position: relative; + padding: 0 24px; + a { + display: flex; + align-items: center; + .icon { + width: 22px; + height: 22px; + margin-right: 8px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + &.drawing { + background-image: url(../../public/static/images/main/drawing_icon.svg); + } + } + } + &:after { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 16px; + background-color: #d9d9d9; + } + &:first-child { + padding-left: 0; + } + &:last-child { + padding-right: 0; + &:after { + display: none; + } + } + } + } + .sub-header-title { + font-size: 16px; + color: #fff; + font-weight: 600; + } + .sub-header-location { + margin-left: auto; + display: flex; + align-items: center; + .location-item { position: relative; display: flex; align-items: center; - width: 580px; - height: 45px; - padding: 0 45px 0 20px; - margin-bottom: 20px; - border-radius: 2px; - border: 1px solid #101010; - .community-input{ - width: 100%; - height: 100%; - font-size: 13px; - font-weight: 400; - color: #101010; - &::placeholder{ - color: #C8C8C8; - } + padding: 0 10px; + span { + display: flex; + font-size: 12px; + color: #aaa; + font-weight: normal; + cursor: default; } - .community-search-ico{ - position: absolute; - top: 50%; - right: 20px; - transform: translateY(-50%); - flex: none; - width: 21px; - height: 100%; - background: url(../../public/static/images/sub/community_search.svg)no-repeat center; - background-size: 21px 21px; - z-index: 3; - } - } - .community-search-keyword{ - font-size: 13px; - font-weight: 400; - color: #45576F; - span{ - font-weight: 600; - color: #F16A6A; + &:after { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 4px; + height: 6px; + background: url(../../public/static/images/main/loaction_arr.svg) no-repeat center; } + &:first-child { + padding-left: 0; + } + &:last-child { + padding-right: 0; + span { + color: #fff; + } + &:after { + display: none; + } + } + } } + } } -// 자료 다운로드 -.file-down-list{ - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 14px; - .file-down-item{ +// sub content +.sub-content { + padding-top: 46px; + .sub-content-inner { + max-width: 1760px; + margin: 0 auto; + padding: 20px 20px 0; + .sub-content-box { + margin-bottom: 20px; + &:last-child { + margin-bottom: 0; + } + } + } + &.estimate { + display: flex; + flex-direction: column; + padding-top: 0; + .sub-content-inner { + flex: 1; + width: 100%; + } + } +} +.sub-table-box { + padding: 20px; + border-radius: 6px; + border: 1px solid #e9eaed; + background: #fff; + box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); + .table-box-title-wrap { + display: flex; + align-items: center; + margin-bottom: 15px; + .title-wrap { + display: flex; + align-items: center; + h3 { + display: block; + font-size: 15px; + color: #101010; + font-weight: 600; + margin-right: 14px; + &.product { + margin-right: 10px; + } + } + .product_tit { + position: relative; + font-size: 15px; + font-weight: 600; + color: #1083e3; + padding-left: 10px; + &::before { + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 1px; + height: 11px; + background-color: #d9d9d9; + } + } + .option { + padding-left: 5px; + font-size: 13px; + color: #101010; + font-weight: 400; + } + .info-wrap { display: flex; align-items: center; - padding: 24px; - border-radius: 4px; - border: 1px solid #E5E5E5; - background: #FFF; - transition: all .15s ease-in-out; - .file-item-info{ - .item-num{ - display: inline-block; - padding: 6px 17.5px; - border-radius: 60px; - background-color: #F4F4F7; - font-size: 13px; - font-weight: 600; - color: #101010; - margin-bottom: 15px; + li { + position: relative; + padding: 0 6px; + font-size: 12px; + color: #101010; + font-weight: normal; + span { + font-weight: 600; + &.red { + color: #e23d70; } - .item-name{ - font-size: 16px; - color: #101010; - font-weight: 500; - margin-bottom: 13px; - } - .item-date{ - font-size: 13px; - font-weight: 400; - color: #344356; + } + &:after { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 11px; + background-color: #d9d9d9; + } + &:first-child { + padding-left: 0; + } + &:last-child { + padding-right: 0; + &::after { + display: none; } + } } - .file-down-box{ - display: flex; - align-items: center; - flex: none; - margin-left: auto; - height: 100%; - .file-down-btn{ - width: 36px; - height: 36px; - background: url(../../public/static/images/sub/file_down_btn.svg)no-repeat center; - background-size: cover; - } - } - &:hover{ - background-color: #F4F4F7; - } + } } -} - -.file-down-nodata{ + } + .left-unit-box { + margin-left: auto; + display: flex; + align-items: center; + } + .promise-gudie { + display: block; + font-size: 13px; + font-weight: 700; + color: #101010; + margin-bottom: 20px; + } + .important { + color: #f00; + } + .sub-center-footer { display: flex; align-items: center; justify-content: center; - width: 100%; - height: 148px; - padding: 24px; - border-radius: 4px; - border: 1px solid #E5E5E5; - font-size: 16px; + margin-top: 20px; + } + .sub-right-footer { + display: flex; + align-items: center; + justify-content: flex-end; + margin-top: 20px; + } +} +.pagination-wrap { + margin-top: 24px; +} + +.infomation-wrap { + margin-bottom: 30px; +} + +.infomation-box-wrap { + display: flex; + gap: 10px; + .sub-table-box { + flex: 1; + } + .info-title { + font-size: 14px; font-weight: 500; color: #344356; + margin-bottom: 10px; + } + .info-inner { + position: relative; + font-size: 13px; + color: #344356; + .copy-ico { + position: absolute; + bottom: 0; + right: 0; + width: 16px; + height: 16px; + background: url(../../public/static/images/sub/copy_ico.svg) no-repeat center; + background-size: cover; + } + } +} + +// 견적서 +.estimate-list-wrap { + display: flex; + align-items: center; + margin-bottom: 10px; + &.one { + .estimate-box { + &:last-child { + min-width: unset; + } + } + } + .estimate-box { + flex: 1; + display: flex; + align-items: center; + &:last-child { + flex: none; + min-width: 220px; + } + .estimate-tit { + width: 105px; + height: 30px; + line-height: 30px; + background-color: #f4f4f7; + border-radius: 100px; + text-align: center; + font-size: 13px; + font-weight: 500; + color: #344356; + } + .estimate-name { + font-size: 13px; + color: #344356; + margin-left: 14px; + font-weight: 400; + &.blue { + font-size: 16px; + font-weight: 700; + color: #1083e3; + } + &.red { + font-size: 16px; + font-weight: 700; + color: #d72a2a; + } + } + } + &:last-child { + margin-bottom: 0; + } +} + +// file drag box +.drag-file-box { + padding: 10px; + .btn-area { + padding-bottom: 15px; + border-bottom: 1px solid #ecf0f4; + .file-upload { + display: inline-block; + height: 30px; + background-color: #94a0ad; + padding: 0 10px; + border-radius: 2px; + font-size: 13px; + line-height: 30px; + color: #fff; + font-weight: 500; + cursor: pointer; + transition: background 0.15s ease-in-out; + &:hover { + background-color: #607f9a; + } + } + } + .drag-file-area { + position: relative; + margin-top: 15px; + p { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 13px; + color: #ccc; + font-weight: 400; + cursor: default; + } + } + .file-list { + .file-item { + margin-bottom: 15px; + span { + position: relative; + font-size: 13px; + color: #45576f; + font-weight: 400; + white-space: nowrap; + padding-right: 55px; + button { + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 15px; + height: 15px; + background: url(../../public/static/images/sub/file_delete.svg) no-repeat center; + background-size: cover; + } + } + &:last-child { + margin-bottom: 0; + } + } + } +} + +.estimate-arr-btn { + display: block; + width: 20px; + height: 20px; + background-color: #94a0ad; + border: 1px solid #94a0ad; + background-position: center; + background-repeat: no-repeat; + background-image: url(../../public/static/images/canvas/estiment_arr.svg); + background-size: 11px 7px; + border-radius: 2px; + &.up { + rotate: 180deg; + } + &.on { + background-color: #fff; + border-color: #c2d0dd; + background-image: url(../../public/static/images/canvas/estiment_arr_color.svg); + } +} +.estimate-check-wrap { + .estimate-check-inner { + display: block; + } + &.hide { + border-bottom: 1px solid #ecf0f4; + margin-bottom: 15px; + .estimate-check-inner { + display: none; + } + } +} + +.special-note-check-wrap { + display: grid; + grid-template-columns: repeat(5, 1fr); + border-radius: 3px; + margin-bottom: 30px; + .special-note-check-item { + padding: 14px 10px; + border: 1px solid #ecf0f4; + margin-top: -1px; + margin-right: -1px; + &.act { + background-color: #f7f9fa; + } + } +} + +.calculation-estimate { + border: 1px solid #ecf0f4; + border-radius: 3px; + padding: 24px; + max-height: 350px; + overflow-y: auto; + margin-bottom: 30px; + dl { + margin-bottom: 35px; + &:last-child { + margin-bottom: 0; + } + dt { + font-size: 13px; + font-weight: 600; + color: #1083e3; + margin-bottom: 15px; + } + dd { + font-size: 12px; + font-weight: 400; + color: #45576f; + margin-bottom: 8px; + &:last-child { + margin-bottom: 0; + } + } + } + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #d9dee2; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } +} +.esimate-wrap { + margin-bottom: 20px; +} + +.estimate-product-option { + display: flex; + align-items: center; + margin-bottom: 15px; + .product-price-wrap { + display: flex; + align-items: center; + .product-price-tit { + font-size: 13px; + font-weight: 400; + color: #45576f; + margin-right: 10px; + } + .select-wrap { + width: 110px; + } + } + .product-edit-wrap { + display: flex; + align-items: center; + margin-left: auto; + .product-edit-explane { + display: flex; + align-items: center; + margin-right: 15px; + .explane-item { + position: relative; + display: flex; + align-items: center; + padding: 0 10px; + font-size: 12px; + font-weight: 400; + span { + width: 20px; + height: 20px; + margin-right: 5px; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + } + &:before { + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 1px; + height: 12px; + background-color: #d9d9d9; + } + &:first-child { + padding-left: 0; + &::before { + display: none; + } + } + &:last-child { + padding-right: 0; + } + &.item01 { + color: #3bbb48; + span { + background-image: url(../../public/static/images/sub/open_ico.svg); + } + } + &.item02 { + color: #909000; + span { + background-image: url(../../public/static/images/sub/change_ico.svg); + } + } + &.item03 { + color: #0191c9; + span { + background-image: url(../../public/static/images/sub/attachment_ico.svg); + } + } + &.item04 { + color: #f16a6a; + span { + background-image: url(../../public/static/images/sub/click_check_ico.svg); + } + } + } + } + .product-edit-btn { + display: flex; + align-items: center; + button { + display: flex; + align-items: center; + span { + width: 13px; + height: 13px; + margin-right: 5px; + background-size: cover; + &.plus { + background: url(../../public/static/images/sub/plus_btn.svg) no-repeat center; + } + &.minus { + background: url(../../public/static/images/sub/minus_btn.svg) no-repeat center; + } + } + } + } + } +} + +// 발전시물레이션 +.chart-wrap { + display: flex; + gap: 20px; + width: 100%; + .sub-table-box { + height: 100%; + } + .chart-inner { + flex: 1; + .chart-box { + margin-bottom: 30px; + } + } + .chart-table-wrap { + display: flex; + flex-direction: column; + flex: none; + width: 650px; + .sub-table-box { + flex: 1; + &:first-child { + margin-bottom: 20px; + } + } + } +} + +.chart-month-table { + table { + table-layout: fixed; + border-collapse: collapse; + border: 1px solid #ecf0f4; + border-radius: 4px; + thead { + th { + padding: 4.5px 0; + border-bottom: 1px solid #ecf0f4; + text-align: center; + font-size: 13px; + color: #45576f; + font-weight: 500; + background-color: #f8f9fa; + } + } + tbody { + td { + font-size: 13px; + color: #45576f; + text-align: center; + padding: 4.5px 0; + } + } + } +} + +.simulation-guide-wrap { + display: flex; + padding: 20px; + .simulation-tit-wrap { + flex: none; + padding-right: 40px; + border-right: 1px solid #eeeeee; + span { + display: block; + position: relative; + padding-left: 60px; + font-size: 15px; + color: #14324f; + font-weight: 600; + &::before { + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 40px; + height: 40px; + background: url(../../public/static/images/sub/simulation_guide.svg) no-repeat center; + background-size: cover; + } + } + } + .simulation-guide-box { + flex: 1; + padding-left: 40px; + dl { + margin-bottom: 25px; + dt { + font-size: 13px; + color: #101010; + font-weight: 600; + margin-bottom: 5px; + } + dd { + font-size: 12px; + color: #45576f; + font-weight: 400; + line-height: 24px; + } + &:last-child { + margin-bottom: 0; + } + } + ul, + ol { + list-style: unset; + } + } +} + +.module-total { + display: flex; + align-items: center; + background-color: #f8f9fa; + padding: 9px 0; + margin-right: 4px; + border: 1px solid #ecf0f4; + border-top: none; + .total-title { + flex: 1; + text-align: center; + font-size: 13px; + color: #344356; + font-weight: 500; + } + .total-num { + flex: none; + width: 121px; + text-align: center; + font-size: 15px; + color: #344356; + font-weight: 500; + } +} + +// 물건상세 +.information-help-wrap { + display: flex; + padding: 24px; + background-color: #f4f4f4; + border-radius: 4px; + margin-bottom: 15px; + .information-help-tit-wrap { + position: relative; + display: flex; + align-items: center; + padding-right: 40px; + border-right: 1px solid #e0e0e3; + .help-tit-icon { + width: 40px; + height: 40px; + border-radius: 50%; + margin-right: 10px; + background: #fff url(../../public/static/images/sub/information_help.svg) no-repeat center; + background-size: 20px 20px; + } + .help-tit { + font-size: 13px; + font-weight: 600; + color: #45576f; + } + } + .information-help-guide { + padding-left: 40px; + span { + display: block; + font-size: 12px; + font-weight: 400; + color: #45576f; + margin-bottom: 7px; + &:last-child { + margin-bottom: 0; + } + } + } +} + +.community-search-warp { + display: flex; + flex-direction: column; + align-items: center; + padding: 10px 0 30px 0; + border-bottom: 1px solid #e5e5e5; + margin-bottom: 24px; + .community-search-box { + position: relative; + display: flex; + align-items: center; + width: 580px; + height: 45px; + padding: 0 45px 0 20px; + margin-bottom: 20px; + border-radius: 2px; + border: 1px solid #101010; + .community-input { + width: 100%; + height: 100%; + font-size: 13px; + font-weight: 400; + color: #101010; + &::placeholder { + color: #c8c8c8; + } + } + .community-search-ico { + position: absolute; + top: 50%; + right: 20px; + transform: translateY(-50%); + flex: none; + width: 21px; + height: 100%; + background: url(../../public/static/images/sub/community_search.svg) no-repeat center; + background-size: 21px 21px; + z-index: 3; + } + } + .community-search-keyword { + font-size: 13px; + font-weight: 400; + color: #45576f; + span { + font-weight: 600; + color: #f16a6a; + } + } +} + +// 자료 다운로드 +.file-down-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + .file-down-item { + display: flex; + align-items: center; + padding: 24px; + border-radius: 4px; + border: 1px solid #e5e5e5; + background: #fff; + transition: all 0.15s ease-in-out; + .file-item-info { + .item-num { + display: inline-block; + padding: 6px 17.5px; + border-radius: 60px; + background-color: #f4f4f7; + font-size: 13px; + font-weight: 600; + color: #101010; + margin-bottom: 15px; + } + .item-name { + font-size: 16px; + color: #101010; + font-weight: 500; + margin-bottom: 13px; + } + .item-date { + font-size: 13px; + font-weight: 400; + color: #344356; + } + } + .file-down-box { + display: flex; + align-items: center; + flex: none; + margin-left: auto; + height: 100%; + .file-down-btn { + width: 36px; + height: 36px; + background: url(../../public/static/images/sub/file_down_btn.svg) no-repeat center; + background-size: cover; + } + } + &:hover { + background-color: #f4f4f7; + } + } +} + +.file-down-nodata { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 148px; + padding: 24px; + border-radius: 4px; + border: 1px solid #e5e5e5; + font-size: 16px; + font-weight: 500; + color: #344356; } //신규물건 등록 -.product-input-wrap{ - display: flex; - align-items: center; - width: 200px; - height: 30px; - background-color: #FAFAFA; - border: 1px solid #EEE; - padding: 0 10px; - input{ - font-size: 13px; - font-weight: 400; - color: #999999; - padding: 0; - width: 100%; - height: 100%; - flex: 1 ; - background-color: inherit; - } - .product-delete{ - flex: none; - display: block; - width: 15px; - height: 100%; - background: url(../../public/static/images/sub/product-del.svg)no-repeat center; - background-size: 15px 15px; - } +.product-input-wrap { + display: flex; + align-items: center; + width: 200px; + height: 30px; + background-color: #fafafa; + border: 1px solid #eee; + padding: 0 10px; + input { + font-size: 13px; + font-weight: 400; + color: #999999; + padding: 0; + width: 100%; + height: 100%; + flex: 1; + background-color: inherit; + } + .product-delete { + flex: none; + display: block; + width: 15px; + height: 100%; + background: url(../../public/static/images/sub/product-del.svg) no-repeat center; + background-size: 15px 15px; + } } @media screen and (max-width: 1800px) { - .canvas-menu-wrap{ - .canvas-menu-inner{ - .canvas-menu-list{ - .canvas-menu-item button{ - .menu-icon{ - margin-right: 5px; - } - } - .canvas-menu-item{ - button{ - padding: 15px 15px; - font-size: 11px; - } - } - } + .canvas-menu-wrap { + .canvas-menu-inner { + .canvas-menu-list { + .canvas-menu-item button { + .menu-icon { + margin-right: 5px; + } } - .canvas-depth2-wrap{ - .canvas-depth2-inner{ - .canvas-depth2-list{ - .canvas-depth2-item{ - button{ - font-size: 11px; - } - } - } - } + .canvas-menu-item { + button { + padding: 15px 15px; + font-size: 11px; + } } - } + } + } + .canvas-depth2-wrap { + .canvas-depth2-inner { + .canvas-depth2-list { + .canvas-depth2-item { + button { + font-size: 11px; + } + } + } + } + } + } } @media screen and (max-width: 1600px) { - .canvas-menu-wrap{ - .canvas-menu-inner{ - .canvas-menu-list{ - .canvas-menu-item button{ - .menu-icon{ - display: none; - } - } - } + .canvas-menu-wrap { + .canvas-menu-inner { + .canvas-menu-list { + .canvas-menu-item button { + .menu-icon { + display: none; + } } - } - .canvas-content{ - .canvas-frame{ - height: calc(100vh - 129.5px); - } - &.active{ - .canvas-frame{ - height: calc(100vh - 179.5px); - } - } - } + } + } + } + .canvas-content { + .canvas-frame { + height: calc(100vh - 129.5px); + } + &.active { + .canvas-frame { + height: calc(100vh - 179.5px); + } + } + } } @media screen and (max-width: 1500px) { - .canvas-menu-wrap{ - .canvas-menu-inner{ - .canvas-menu-list{ - .canvas-menu-item{ - button{ - padding: 15px 10px; - font-size: 10px; - } - } - } - .canvas-side-btn-wrap{ - .btn-from{ - gap: 3px; - } - .vertical-horizontal{ - margin-right: 3px; - min-width: 150px; - } - .select-box{ - width: 100px; - margin: 0 3px; - } - .size-control{ - width: 90px; - margin: 0 3px; - } - } + .canvas-menu-wrap { + .canvas-menu-inner { + .canvas-menu-list { + .canvas-menu-item { + button { + padding: 15px 10px; + font-size: 10px; + } } + } + .canvas-side-btn-wrap { + .btn-from { + gap: 3px; + } + .vertical-horizontal { + margin-right: 3px; + min-width: 150px; + } + .select-box { + width: 100px; + margin: 0 3px; + } + .size-control { + width: 90px; + margin: 0 3px; + } + } } - .sub-header{ - .sub-header-inner{ - .sub-header-title{ - font-size: 15px; + } + .sub-header { + .sub-header-inner { + .sub-header-title { + font-size: 15px; + } + .sub-header-title-wrap { + .title-item { + a { + .icon { + width: 20px; + height: 20px; } - .sub-header-title-wrap{ - .title-item{ - a{ - .icon{ - width: 20px; - height: 20px; - } - } - } - } - } - } - + } + } + } + } + } } diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index da421f16..4ddb3bad 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -4,1902 +4,2103 @@ $pop-bold-weight: 500; $pop-normal-size: 12px; $alert-color: #101010; -@keyframes mountpop{ - from{opacity: 0; scale: 0.95;} - to{opacity: 1; scale: 1;} +@keyframes mountpop { + from { + opacity: 0; + scale: 0.95; + } + to { + opacity: 1; + scale: 1; + } } -@keyframes unmountpop{ - from{opacity: 1; scale: 1;} - to{opacity: 0; scale: 0.95;} +@keyframes unmountpop { + from { + opacity: 1; + scale: 1; + } + to { + opacity: 0; + scale: 0.95; + } } -.normal-font{ - font-size: 12px; - font-weight: 400; - color: #fff; +.normal-font { + font-size: 12px; + font-weight: 400; + color: #fff; } -.bold-font{ - font-size: 12px; - font-weight: 500; - color: #fff; +.bold-font { + font-size: 12px; + font-weight: 500; + color: #fff; } -.modal-pop-wrap{ - position: fixed; - top: 0; - left: 0; - width: 100%; - height: -webkit-fit-content; - height: -moz-fit-content; - height: fit-content; - border: 1px solid #000; - border-radius: 4px; - background-color: #272727; - z-index: 9999999; - &.xsm{ - width: 200px; +.modal-pop-wrap { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: -webkit-fit-content; + height: -moz-fit-content; + height: fit-content; + border: 1px solid #000; + border-radius: 4px; + background-color: #272727; + z-index: 9999999; + &.xsm { + width: 200px; + } + &.xxxm { + width: 240px; + } + &.xxm { + width: 270px; + } + &.xm { + width: 300px; + } + &.ssm { + width: 380px; + } + &.sm { + width: 580px; + } + &.r { + width: 400px; + } + &.lr { + width: 440px; + } + &.lr-2 { + width: 450px; + } + &.lrr { + width: 480px; + } + &.ml { + width: 530px; + } + &.l-2 { + width: 640px; + } + &.lx-2 { + width: 740px; + } + &.lx { + width: 770px; + } + &.l { + width: 800px; + } + &.mount { + animation: mountpop 0.17s ease-in-out forwards; + } + &.unmount { + animation: unmountpop 0.17s ease-in-out forwards; + } + &.alert { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: transparent; + border: none; + .modal-head { + background-color: transparent; + padding: 0 0 8px; + .modal-close { + width: 20px; + height: 20px; + background: url(../../public/static/images/canvas/alert_close.svg) no-repeat center; + } } - &.xxxm{ - width: 240px; - } - &.xxm{ - width: 270px; - } - &.xm{ - width: 300px; - } - &.ssm{ - width: 380px; - } - &.sm{ - width: 580px; - } - &.r{ - width: 400px; - } - &.lr{ - width: 440px; - } - &.lr-2{ - width: 450px; - } - &.lrr{ - width: 480px; - } - &.ml{ - width: 530px; - } - &.l-2{ - width: 640px; - } - &.lx-2{ - width: 740px; - } - &.lx{ - width: 770px; - } - &.l{ - width: 800px; - } - &.mount{ - animation: mountpop .17s ease-in-out forwards; - } - &.unmount{ - animation: unmountpop .17s ease-in-out forwards; - } - &.alert{ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: transparent; - border: none; - .modal-head{ - background-color: transparent; - padding: 0 0 8px; - .modal-close{ - width: 20px; - height: 20px; - background: url(../../public/static/images/canvas/alert_close.svg)no-repeat center; - } - } - .modal-body{ - background-color: #fff; - padding: 22px; - border-radius: 4px; - border: 1px solid #101010; - color: $alert-color; - .alert-title{ - font-size: 13px; - font-weight: 700; - color: $alert-color; - margin-bottom: 15px; - } - } - } -} -.modal-head{ - display: flex; - align-items: center; - padding: 10px 24px; - background-color: #000; - // overflow: hidden; - h1.title{ + .modal-body { + background-color: #fff; + padding: 22px; + border-radius: 4px; + border: 1px solid #101010; + color: $alert-color; + .alert-title { font-size: 13px; - color: $pop-color; font-weight: 700; - } - .modal-close{ - margin-left: auto; - color: transparent; - font-size: 0; - width: 10px; - height: 10px; - background: url(../../public/static/images/canvas/modal_close.svg)no-repeat center; - } -} -.modal-body{ - padding: 24px; - .modal-btn-wrap{ - display: flex; - align-items: center; - gap: 5px; - button{ - flex: 1; - } - &.sub{ - button{ - flex: 1 1 auto; - padding: 0; - } - margin-bottom: 14px; - } - } - .modal-check-btn-wrap{ - margin-top: 15px; - .check-wrap-title{ - font-size: $pop-normal-size; - color: $pop-color; - font-weight: 600; - &.light{ - font-weight: $pop-normal-weight; - } - } - .flex-check-box{ - display: flex; - flex-wrap: wrap; - gap: 10px; - margin-top: 15px; - &.for2{ - justify-content: flex-end; - button{ - width: calc(50% - 5px); - } - &.btn{ - gap: 5px; - button{ - width: calc(50% - 2.5px); - } - } - } - &.for-line{ - button{ - flex: 1; - } - } - } - } - .outer-line-wrap{ - border-top: 1px solid #3C3C3C; - margin-top: 10px; - padding-top: 15px; - margin-bottom: 15px; - > div{ - margin-bottom: 15px; - &:last-child{ - margin-bottom: 0; - } - } - } - .modal-guide{ - display: block; - font-size: $pop-normal-size; color: $alert-color; - font-weight: $pop-normal-weight; + margin-bottom: 15px; + } } + } } - -.adsorption-point{ +.modal-head { + display: flex; + align-items: center; + padding: 10px 24px; + background-color: #000; + // overflow: hidden; + h1.title { + font-size: 13px; + color: $pop-color; + font-weight: 700; + } + .modal-close { + margin-left: auto; + color: transparent; + font-size: 0; + width: 10px; + height: 10px; + background: url(../../public/static/images/canvas/modal_close.svg) no-repeat center; + } +} +.modal-body { + padding: 24px; + .modal-btn-wrap { display: flex; align-items: center; - background-color: #3A3A3A; - border-radius: 3px; - padding-left: 11px; - overflow: hidden; - transition: all 0.17s ease-in-out; - span{ - font-size: $pop-normal-size; - color: #898989; + gap: 5px; + button { + flex: 1; } - i{ - display: flex; - align-items: center; - padding: 0 7px; - margin-left: auto; - height: 100%; - font-size: 13px; - color: #898989; + &.sub { + button { + flex: 1 1 auto; + padding: 0; + } + margin-bottom: 14px; } - &.act{ - i{ - color: $pop-color; - background-color: #1083E3; + } + .modal-check-btn-wrap { + margin-top: 15px; + .check-wrap-title { + font-size: $pop-normal-size; + color: $pop-color; + font-weight: 600; + &.light { + font-weight: $pop-normal-weight; + } + } + .flex-check-box { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 15px; + &.for2 { + justify-content: flex-end; + button { + width: calc(50% - 5px); } + &.btn { + gap: 5px; + button { + width: calc(50% - 2.5px); + } + } + } + &.for-line { + button { + flex: 1; + } + } } + } + .outer-line-wrap { + border-top: 1px solid #3c3c3c; + margin-top: 10px; + padding-top: 15px; + margin-bottom: 15px; + > div { + margin-bottom: 15px; + &:last-child { + margin-bottom: 0; + } + } + } + .modal-guide { + display: block; + font-size: $pop-normal-size; + color: $alert-color; + font-weight: $pop-normal-weight; + } +} + +.adsorption-point { + display: flex; + align-items: center; + background-color: #3a3a3a; + border-radius: 3px; + padding-left: 11px; + overflow: hidden; + transition: all 0.17s ease-in-out; + span { + font-size: $pop-normal-size; + color: #898989; + } + i { + display: flex; + align-items: center; + padding: 0 7px; + margin-left: auto; + height: 100%; + font-size: 13px; + color: #898989; + } + &.act { + i { + color: $pop-color; + background-color: #1083e3; + } + } } // grid-option -.grid-check-form{ +.grid-check-form { + display: flex; + align-items: center; + gap: 15px; + padding-bottom: 15px; + &.border { + border-bottom: 1px solid #424242; + } +} +.grid-option-wrap { + .grid-option-box { display: flex; align-items: center; - gap: 15px; - padding-bottom: 15px; - &.border{ - border-bottom: 1px solid #424242; + background-color: transparent; + border: 1px solid #3d3d3d; + border-radius: 2px; + padding: 15px 10px; + gap: 20px; + margin-bottom: 10px; + .grid-input-form { + display: flex; + align-items: center; + span { + flex: none; + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + } + .input-grid { + width: 54px; + input { + width: 100%; + } + } } + &:last-child { + margin-bottom: 0; + } + } } -.grid-option-wrap{ - .grid-option-box{ - display: flex; - align-items: center; - background-color: transparent; - border: 1px solid #3D3D3D; - border-radius: 2px; - padding: 15px 10px; - gap: 20px; - margin-bottom: 10px; - .grid-input-form{ - display: flex; - align-items: center; - span{ - flex: none; - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - } - .input-grid{ - width: 54px; - input{ - width: 100%; - } - } - } - &:last-child{ - margin-bottom: 0; - } - } +.select-form { + .sort-select { + width: 100%; + } } -.select-form{ - .sort-select{width: 100%;} +.grid-select { + flex: 1; + &.no-flx { + flex: unset; + } + .sort-select { + width: 100%; + background-color: #313131; + min-width: auto; + font-size: 12px; + border: none; + p { + font-size: 12px; + } + > ul { + border: none; + } + } + &.right { + p { + text-align: right; + } + ul { + li { + justify-content: flex-end; + } + } + } } -.grid-select{ - flex: 1; - &.no-flx{ - flex: unset; - } - .sort-select{ - width: 100%; - background-color: #313131; - min-width: auto; - font-size: 12px; - border: none; - p{ - font-size: 12px; - } - > ul{ - border: none; - } - } - &.right{ - p{ - text-align: right; - } - ul{ - li{ - justify-content: flex-end; - } - } - } -} -.grid-btn-wrap{ - padding-top: 15px; - text-align: right; - button{ - padding: 0 10px; - } +.grid-btn-wrap { + padding-top: 15px; + text-align: right; + button { + padding: 0 10px; + } } // grid copy -.grid-option-tit{ - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - padding-bottom: 15px; - +.grid-option-tit { + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + padding-bottom: 15px; } -.grid-direction{ - display: flex; - align-items: center; - gap: 5px; - flex: 1; +.grid-direction { + display: flex; + align-items: center; + gap: 5px; + flex: 1; } -.direction{ - width: 22px; - height: 22px; - background-color: #757575; - background-image: url(../../public/static/images/canvas/grid_option_arr.svg); - background-repeat: no-repeat; - background-position: center; - background-size: 16px 15px; - border-radius: 50%; - transition: all .15s ease-in-out; - opacity: 0.6; - &.down{transform: rotate(180deg);} - &.left{transform: rotate(-90deg);} - &.right{transform: rotate(90deg);} - &:hover, - &.act{ - opacity: 1; - } +.direction { + width: 22px; + height: 22px; + background-color: #757575; + background-image: url(../../public/static/images/canvas/grid_option_arr.svg); + background-repeat: no-repeat; + background-position: center; + background-size: 16px 15px; + border-radius: 50%; + transition: all 0.15s ease-in-out; + opacity: 0.6; + &.down { + transform: rotate(180deg); + } + &.left { + transform: rotate(-90deg); + } + &.right { + transform: rotate(90deg); + } + &:hover, + &.act { + opacity: 1; + } } // grid-move -.move-form{ - width: 100%; - p{ - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - } +.move-form { + width: 100%; + p { + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + } } -.input-move-wrap{ - display: flex; - align-items: center; - gap: 5px; - span{ - color: $pop-color; - font-size: $pop-normal-size; - } - .input-move{ - width: 130px; - input{ - width: 100%; - } +.input-move-wrap { + display: flex; + align-items: center; + gap: 5px; + span { + color: $pop-color; + font-size: $pop-normal-size; + } + .input-move { + width: 130px; + input { + width: 100%; } + } } -.direction-move-wrap{ - flex: none; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 5px; - margin-left: auto; +.direction-move-wrap { + flex: none; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 5px; + margin-left: auto; } // 배치면 초기 설정 -.placement-table{ - table{ - table-layout: fixed; - tr{ - th{ - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - padding: 18px 0; - border-bottom: 1px solid #424242; - vertical-align: middle; - .tip-wrap{ - display: flex; - align-items: center; - } - } - td{ - font-size: $pop-normal-size; - color: $pop-color; - border-bottom: 1px solid #424242; - padding: 18px 0 18px 20px; - vertical-align: middle; - .flex-box{ - display: flex; - align-items: center; - height: 100%; - } - } - &:first-child{ - td, - th{ - padding-top: 0; - } - } - } - } - .tooltip{ - position: relative; - display: block; - width: 15px; - height: 15px; - margin-left: 5px; - background: url(../../public/static/images/canvas/pop_tip.svg)no-repeat center; - background-size: cover; - } - &.light{ - padding: 0; - th,td{ - color: $alert-color; - border-bottom: none; - border-top: 1px solid #EFEFEF; - } - th{ - padding: 14px 0; - } - tr{ - &:first-child{ - td, - th{ - padding-top: 14px; - } - } - &:last-child{ - td, - th{ - padding-bottom: 0px; - } - } - } - } -} - -.pop-form-radio{ - display: flex; - align-items: center; - gap: 10px; -} -.placement-option{ - display: flex; - align-items: center; - gap: 20px; -} -.select-wrap{ - .sort-select{ - width: 100%; - } -} -.flex-ment{ - display: flex; - align-items: center; - gap: 5px; - span{ +.placement-table { + table { + table-layout: fixed; + tr { + th { font-size: $pop-normal-size; color: $pop-color; - font-weight: $pop-normal-weight; + font-weight: $pop-bold-weight; + padding: 18px 0; + border-bottom: 1px solid #424242; + vertical-align: middle; + .tip-wrap { + display: flex; + align-items: center; + } + } + td { + font-size: $pop-normal-size; + color: $pop-color; + border-bottom: 1px solid #424242; + padding: 18px 0 18px 20px; + vertical-align: middle; + .flex-box { + display: flex; + align-items: center; + height: 100%; + } + } + &:first-child { + td, + th { + padding-top: 0; + } + } } - + } + .tooltip { + position: relative; + display: block; + width: 15px; + height: 15px; + margin-left: 5px; + background: url(../../public/static/images/canvas/pop_tip.svg) no-repeat center; + background-size: cover; + } + &.light { + padding: 0; + th, + td { + color: $alert-color; + border-bottom: none; + border-top: 1px solid #efefef; + } + th { + padding: 14px 0; + } + tr { + &:first-child { + td, + th { + padding-top: 14px; + } + } + &:last-child { + td, + th { + padding-bottom: 0px; + } + } + } + } } -.img-edit-wrap{ - flex: none; - .img-edit-btn{ - display: flex; - align-items: center; - height: 30px; - padding: 0 10px; - font-size: 12px; - font-weight: 400; - color: #101010; - background-color: #fff; - border-radius: 2px; - cursor: pointer; - transition: all .15s ease-in-out; - .img-edit{ - width: 16px; - height: 16px; - background: url(../../public/static/images/canvas/img_edit_ico.svg)no-repeat center; - background-size: cover; - margin-right: 5px; - } - &:hover{ - background-color: #ebebeb; - } - } +.pop-form-radio { + display: flex; + align-items: center; + gap: 10px; } -.img-name-wrap{ +.placement-option { + display: flex; + align-items: center; + gap: 20px; +} +.select-wrap { + .sort-select { + width: 100%; + } +} +.flex-ment { + display: flex; + align-items: center; + gap: 5px; + span { + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + } +} + +.img-edit-wrap { + flex: none; + .img-edit-btn { display: flex; align-items: center; - width: 100%; - margin-left: 10px; - input{ - flex: 1; - + height: 30px; + padding: 0 10px; + font-size: 12px; + font-weight: 400; + color: #101010; + background-color: #fff; + border-radius: 2px; + cursor: pointer; + transition: all 0.15s ease-in-out; + .img-edit { + width: 16px; + height: 16px; + background: url(../../public/static/images/canvas/img_edit_ico.svg) no-repeat center; + background-size: cover; + margin-right: 5px; } - .img-check{ - flex: none; - width: 18px; - height: 18px; - margin-left: 5px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - background-image: url(../../public/static/images/canvas/img_check_fail.svg); + &:hover { + background-color: #ebebeb; } + } +} +.img-name-wrap { + display: flex; + align-items: center; + width: 100%; + margin-left: 10px; + input { + flex: 1; + } + .img-check { + flex: none; + width: 18px; + height: 18px; + margin-left: 5px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + background-image: url(../../public/static/images/canvas/img_check_fail.svg); + } } -.for-address{ - input{ - flex: 1; +.for-address { + input { + flex: 1; + } + .check-address { + flex: none; + width: 18px; + height: 18px; + margin-left: 5px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + &.fail { + background-image: url(../../public/static/images/canvas/img_check_fail.svg); } - .check-address{ - flex: none; - width: 18px; - height: 18px; - margin-left: 5px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - &.fail{background-image: url(../../public/static/images/canvas/img_check_fail.svg);} - &.success{background-image: url(../../public/static/images/canvas/img_check_success.svg);} + &.success { + background-image: url(../../public/static/images/canvas/img_check_success.svg); } + } } // 외벽선 그리기 -.outline-wrap{ - padding: 24px 0; - border-top: 1px solid #424242; - - .outline-inner{ - display: flex; - align-items: center; - margin-bottom: 14px; - &:last-child{ - margin-bottom: 0; - } - .outline-form{ - // width: 50%; - margin-right: 15px; - } - } - &:last-child{ - border-bottom: 1px solid #424242; - } -} -.outline-form{ +.outline-wrap { + padding: 24px 0; + border-top: 1px solid #424242; + + .outline-inner { display: flex; align-items: center; - - span{ - width: 60px; - flex: none; - font-size: $pop-normal-size; - font-weight: $pop-bold-weight; - color: $pop-color; - margin-right: 10px; - &.thin{ - width: auto; - font-weight: $pop-normal-weight; - margin-right: 0; - } + margin-bottom: 14px; + &:last-child { + margin-bottom: 0; } + .outline-form { + // width: 50%; + margin-right: 15px; + } + } + &:last-child { + border-bottom: 1px solid #424242; + } +} +.outline-form { + display: flex; + align-items: center; - .reset-btn{ - flex: none; - width: 30px; - height: 30px; - background: transparent; - border: 1px solid #484848; - border-radius: 2px; - margin-left: 5px; - background-image: url(../../public/static/images/canvas/reset_ico.svg); - background-repeat: no-repeat; - background-size: 12px 12px; - background-position: center; - } - &:last-child{ - margin-right: 0; + span { + width: 60px; + flex: none; + font-size: $pop-normal-size; + font-weight: $pop-bold-weight; + color: $pop-color; + margin-right: 10px; + &.thin { + width: auto; + font-weight: $pop-normal-weight; + margin-right: 0; } + } + + .reset-btn { + flex: none; + width: 30px; + height: 30px; + background: transparent; + border: 1px solid #484848; + border-radius: 2px; + margin-left: 5px; + background-image: url(../../public/static/images/canvas/reset_ico.svg); + background-repeat: no-repeat; + background-size: 12px 12px; + background-position: center; + } + &:last-child { + margin-right: 0; + } } -.cul-wrap{ +.cul-wrap { + display: flex; + .outline-box { + width: 50%; + margin-right: 15px; + .outline-form { + width: 100%; + margin-bottom: 14px; + margin-right: 0; + &:last-child { + margin-bottom: 0; + } + } + } + .cul-box { display: flex; - .outline-box{ - width: 50%; - margin-right: 15px; - .outline-form{ - width: 100%; - margin-bottom: 14px; - margin-right: 0; - &:last-child{ - margin-bottom: 0; - } - } - } - .cul-box{ - display: flex; - align-items: center; - justify-content: center; - width: 50%; - background-color: #3D3D3D; - border-radius: 2px ; - } + align-items: center; + justify-content: center; + width: 50%; + background-color: #3d3d3d; + border-radius: 2px; + } } // 외벽선 속성 설정 -.properties-guide{ - font-size: $pop-normal-size; - color: #AAA; - font-weight: $pop-normal-weight; - margin-bottom: 14px; +.properties-guide { + font-size: $pop-normal-size; + color: #aaa; + font-weight: $pop-normal-weight; + margin-bottom: 14px; } -.setting-tit{ - font-size: 13px; - color: $pop-color; - font-weight: $pop-bold-weight; - margin-bottom: 10px; +.setting-tit { + font-size: 13px; + color: $pop-color; + font-weight: $pop-bold-weight; + margin-bottom: 10px; } -.properties-setting-wrap{ - &.outer{ - margin-top: 24px; - } - .setting-btn-wrap{ - display: flex; - align-items: center; - padding: 14px 0; - border-top: 1px solid #424242; - border-bottom: 1px solid #424242; - .setting-btn{ - display: block; - width: 100%; - height: 40px; - font-size: 13px; - color: #fff; - font-weight: 700; - border-radius: 2px; - transition: all .15s ease-in-out; - &.green{ - background-color: #305941; - border: 1px solid #45CD7D; - &:hover{ - background-color: #3a6b4e; - } - } - &.blue{ - background-color: #2E5360; - border: 1px solid #3FBAE6; - &:hover{ - background-color: #365f6e; - } - } - } - } -} - -// 지붕형상 설정 -.roof-shape-menu{ - display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr; - grid-template-rows: 1fr 1fr; - gap: 24px 10px; - margin-bottom: 24px; - .shape-box{ - display: flex; - align-items: center; - justify-content: center; - width: 100%; - padding: 13px; - background-color: #3D3D3D; - transition: background .15s ease-in-out; - img{ - max-width: 100%; - } - } - .shape-title{ - font-size: $pop-normal-size; - font-weight: $pop-bold-weight; - color: $pop-color; - margin-top: 10px; - text-align: center; - transition: color .15s ease-in-out; - } - .shape-menu-box{ - &.act, - &:hover{ - .shape-box{background-color: #008BFF;} - .shape-title{color: #008BFF;} - } - } -} - -.setting-box{ +.properties-setting-wrap { + &.outer { + margin-top: 24px; + } + .setting-btn-wrap { + display: flex; + align-items: center; padding: 14px 0; border-top: 1px solid #424242; border-bottom: 1px solid #424242; -} -.padding-form{ - padding-left: 23px; -} -.discrimination-box{ - padding: 16px 12px; - border: 1px solid #3D3D3D; - border-radius: 2px; + .setting-btn { + display: block; + width: 100%; + height: 40px; + font-size: 13px; + color: #fff; + font-weight: 700; + border-radius: 2px; + transition: all 0.15s ease-in-out; + &.green { + background-color: #305941; + border: 1px solid #45cd7d; + &:hover { + background-color: #3a6b4e; + } + } + &.blue { + background-color: #2e5360; + border: 1px solid #3fbae6; + &:hover { + background-color: #365f6e; + } + } + } + } } -.modal-bottom-border-bx{ - margin-top: 24px; - padding-bottom: 14px; - border-bottom: 1px solid #424242; +// 지붕형상 설정 +.roof-shape-menu { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-rows: 1fr 1fr; + gap: 24px 10px; + margin-bottom: 24px; + .shape-box { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + padding: 13px; + background-color: #3d3d3d; + transition: background 0.15s ease-in-out; + img { + max-width: 100%; + } + } + .shape-title { + font-size: $pop-normal-size; + font-weight: $pop-bold-weight; + color: $pop-color; + margin-top: 10px; + text-align: center; + transition: color 0.15s ease-in-out; + } + .shape-menu-box { + &.act, + &:hover { + .shape-box { + background-color: #008bff; + } + .shape-title { + color: #008bff; + } + } + } +} + +.setting-box { + padding: 14px 0; + border-top: 1px solid #424242; + border-bottom: 1px solid #424242; +} +.padding-form { + padding-left: 23px; +} +.discrimination-box { + padding: 16px 12px; + border: 1px solid #3d3d3d; + border-radius: 2px; +} + +.modal-bottom-border-bx { + margin-top: 24px; + padding-bottom: 14px; + border-bottom: 1px solid #424242; } // 처마∙케라바 변경 -.eaves-keraba-table{ - display: table; - border-collapse: collapse; - .eaves-keraba-item{ - display: table-row; - .eaves-keraba-th, - .eaves-keraba-td{ - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - display: table-cell; - vertical-align: middle; - padding-bottom: 14px; - } - .eaves-keraba-td{ - padding-left: 10px; - } - .eaves-keraba-ico{ - display: flex; - align-items: center; - justify-content: center; - padding: 5px; - background-color: #3D3D3D; - border: 1px solid #3D3D3D; - border-radius: 2px; - cursor: pointer; - &.act{ - border: 1px solid #ED0004; - } - } - &:last-child{ - .eaves-keraba-th, - .eaves-keraba-td{ - padding-bottom: 0; - } - } +.eaves-keraba-table { + display: table; + border-collapse: collapse; + .eaves-keraba-item { + display: table-row; + .eaves-keraba-th, + .eaves-keraba-td { + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + display: table-cell; + vertical-align: middle; + padding-bottom: 14px; } + .eaves-keraba-td { + padding-left: 10px; + } + .eaves-keraba-ico { + display: flex; + align-items: center; + justify-content: center; + padding: 5px; + background-color: #3d3d3d; + border: 1px solid #3d3d3d; + border-radius: 2px; + cursor: pointer; + &.act { + border: 1px solid #ed0004; + } + } + &:last-child { + .eaves-keraba-th, + .eaves-keraba-td { + padding-bottom: 0; + } + } + } } -.guide{ - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: $pop-color; - margin-bottom: 24px; - &.sm{ - margin-bottom: 15px; - } - span{ - display: block; - } +.guide { + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: $pop-color; + margin-bottom: 24px; + &.sm { + margin-bottom: 15px; + } + span { + display: block; + } } // 지붕면 할당 -.allocation-select-wrap{ +.allocation-select-wrap { + display: flex; + align-items: center; + padding-bottom: 14px; + border-bottom: 1px solid #424242; + margin-bottom: 14px; + span { + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + margin-right: 10px; + } + .allocation-edit { display: flex; align-items: center; - padding-bottom: 14px; - border-bottom: 1px solid #424242; - margin-bottom: 14px; - span{ - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - margin-right: 10px; - } - .allocation-edit{ - display: flex; - align-items: center; - height: 30px; - padding: 0 10px; - margin-left: 5px; - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - border: 1px solid #484848; - background-color: #323234; - i{ - display: block; - width: 12px; - height: 12px; - margin-right: 5px; - background: url(../../public/static/images/canvas/allocation_edit.svg)no-repeat center; - background-size: cover; - } + height: 30px; + padding: 0 10px; + margin-left: 5px; + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + border: 1px solid #484848; + background-color: #323234; + i { + display: block; + width: 12px; + height: 12px; + margin-right: 5px; + background: url(../../public/static/images/canvas/allocation_edit.svg) no-repeat center; + background-size: cover; } + } } -.block-box{ - display: flex; - align-items: center; +.block-box { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 10px; + .flex-ment { gap: 10px; - margin-bottom: 10px; - .flex-ment{ - gap: 10px; - .dec{ - text-decoration: underline; - } - .delete{ - display: block; - width: 15px; - height: 15px; - background: url(../../public/static/images/canvas/allocation_delete.svg)no-repeat center; - background-size: cover; - } + .dec { + text-decoration: underline; } - &:last-child{ - margin-bottom: 0; + .delete { + display: block; + width: 15px; + height: 15px; + background: url(../../public/static/images/canvas/allocation_delete.svg) no-repeat center; + background-size: cover; } + } + &:last-child { + margin-bottom: 0; + } } -.icon-btn-wrap{ - flex: 1; +.icon-btn-wrap { + flex: 1; + display: flex; + align-items: center; + gap: 5px; + button { display: flex; align-items: center; - gap: 5px; - button{ - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 30px; - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: $pop-color; - border: 1px solid #646464; - border-radius: 2px; - padding: 0 10px; - transition: all .15s ease-in-out; - i{ - height: 15px; - display: block; - margin-left: 10px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - transition: all .15s ease-in-out; - &.allocation01{ - background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg); - width: 15px; - } - &.allocation02{ - background-image: url(../../public/static/images/canvas/allocation_icon02_white.svg); - width: 18px; - } - } - &.act, - &:hover{ - color: #101010; - border: 1px solid #101010; - background-color: #fff; - i{ - &.allocation01{ - background-image: url(../../public/static/images/canvas/allocation_icon01_black.svg); - } - &.allocation02{ - background-image: url(../../public/static/images/canvas/allocation_icon02_black.svg); - } - } - } - } -} - -// 경사설정 -.slope-wrap{ - padding-bottom: 24px; - border-bottom: 1px solid #424242; -} - -// 면형상 배치 -.plane-frame-wrap{ - display: flex; - gap: 10px; - .plane-shape-wrap{ - flex: none; - width: 73px; - } -} - -.plane-shape-menu{ - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 5px; - .shape-menu-box{ - border-radius: 2px; - width: 34px; - height: 34px; - background-color: #373737; - border: 1px solid #676767; - transition: background .15s ease-in-out, border .15s ease-in-out; - .shape-box{ - display: flex; - justify-content: center; - align-items: center; - position: relative; - width: 100%; - height: 100%; - border-radius: 2px; - } - &.act, - &:hover{ - border-color: #008BFF; - background-color: #008BFF; - } - } -} - -.shape-library{ - display: flex; - flex-direction: column; - align-items: center; justify-content: center; - gap: 5px; - padding-top: 5px; - .library-btn{ - width: 100%; - height: 34px; - border: 1px solid #6C6C6C; - border-radius: 2px; - background-color: #373737; - background-repeat: no-repeat; - background-position: center; - transition: all .15s ease-in-out; - &.ico01{background-image: url(../../public/static/images/canvas/shape_labrary01.svg); background-size: 19px 18px;} - &.ico02{background-image: url(../../public/static/images/canvas/shape_labrary02.svg); background-size: 15px 20px;} - &.ico03{background-image: url(../../public/static/images/canvas/shape_labrary03.svg); background-size: 19px 16px;} - &:hover{ - border-color: #1083E3; - background-color: #1083E3; - } - } -} - -.plane-detail-wrap{ - display: flex; - flex-direction: column; - flex: 1; -} -.plane-shape-wrapper{ - flex: 1; - display: flex; - flex-direction: column; - gap: 10px; - .plane-box{ - width: 100%; - padding: 10px 18px; - border-radius: 2px; - background-color: #313131; - border: 1px solid #484848; - .plane-box-tit{ - font-size: $pop-normal-size; - font-weight: 600; - color: $pop-color; - margin-bottom: 10px; - } - &.shape-box{ - .shape-box-inner{ - display: flex; - gap:15px; - min-height: 140px; - .shape-img{ - position: relative; - flex: none; - width: 150px; - background-color: #fff; - border-radius: 2px; - img{ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } - } - .shape-data{ - flex: 1; - .eaves-keraba-table{ - .eaves-keraba-item{ - .eaves-keraba-th, - .eaves-keraba-td{ - padding-bottom: 10px; - } - &:last-child{ - .eaves-keraba-th, - .eaves-keraba-td{ - padding-bottom: 0px; - } - } - } - } - } - } - } - &.direction-box{ - flex: 1; - display: flex; - flex-direction: column; - .plane-direction-box{ - flex: 1; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - } - } - } -} -.plane-direction{ - width: 150px; - position: relative; - height: 120px; - span{ - position: absolute; - font-size: 12px; - font-weight: 500; - color: #B1B1B1; - &.top{top: 0; left: 50%; transform: translateX(-50%);} - &.right{top: 50%; right: 0; transform: translateY(-50%);} - &.bottom{bottom: 0; left: 50%; transform: translateX(-50%);} - &.left{top: 50%; left: 0; transform: translateY(-50%);} - } - .plane-btn{ - position: absolute; - width: 28px; - height: 28px; - background-color: #777777; - background-image: url(../../public/static/images/canvas/plane_arr.svg); - background-size: 12px 13px; - background-repeat: no-repeat; - background-position: center; - border-radius: 50%; - transition: all .15s ease-in-out; - &.up{top: 22px; left: 50%; transform: translateX(-50%);} - &.right{top: 50%; right: 32px; transform: translateY(-50%) rotate(90deg);} - &.down{bottom: 22px; left: 50%; transform: translateX(-50%) rotate(180deg);} - &.left{top: 50%; left: 32px; transform: translateY(-50%) rotate(270deg);} - &:hover, - &.act{ - background-color: #fff; - background-image: url(../../public/static/images/canvas/plane_arr_act.svg); - } - } -} - -.plane-tab-guide{ + width: 100%; + height: 30px; font-size: $pop-normal-size; font-weight: $pop-normal-weight; color: $pop-color; - margin-top: 10px; -} -.plane-shape-btn{ - padding-top: 10px; - margin-top: auto; - button{ - display: block; - width: 100%; + border: 1px solid #646464; + border-radius: 2px; + padding: 0 10px; + transition: all 0.15s ease-in-out; + i { + height: 15px; + display: block; + margin-left: 10px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + transition: all 0.15s ease-in-out; + &.allocation01 { + background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg); + width: 15px; + } + &.allocation02 { + background-image: url(../../public/static/images/canvas/allocation_icon02_white.svg); + width: 18px; + } } + &.act, + &:hover { + color: #101010; + border: 1px solid #101010; + background-color: #fff; + i { + &.allocation01 { + background-image: url(../../public/static/images/canvas/allocation_icon01_black.svg); + } + &.allocation02 { + background-image: url(../../public/static/images/canvas/allocation_icon02_black.svg); + } + } + } + } } -// 오브젝트 배치 -.mb-box{ - margin-bottom: 24px; +// 경사설정 +.slope-wrap { + padding-bottom: 24px; + border-bottom: 1px solid #424242; } -.object-direction-wrap{ - display: flex; - align-items: center; - justify-content: center; -} -.discrimination-tit{ - font-size: 13px; - color: #fff; - font-weight: 500; +// 면형상 배치 +.plane-frame-wrap { + display: flex; + gap: 10px; + .plane-shape-wrap { + flex: none; + width: 73px; + } } -.object-size-wrap{ - display: flex; - min-height: 206px; - gap: 24px; - margin-top: 14px; - .object-size-img{ - position: relative; - flex: none; - width: 200px; - background-color: #fff; - img{ +.plane-shape-menu { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 5px; + .shape-menu-box { + border-radius: 2px; + width: 34px; + height: 34px; + background-color: #373737; + border: 1px solid #676767; + transition: + background 0.15s ease-in-out, + border 0.15s ease-in-out; + .shape-box { + display: flex; + justify-content: center; + align-items: center; + position: relative; + width: 100%; + height: 100%; + border-radius: 2px; + } + &.act, + &:hover { + border-color: #008bff; + background-color: #008bff; + } + } +} + +.shape-library { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 5px; + padding-top: 5px; + .library-btn { + width: 100%; + height: 34px; + border: 1px solid #6c6c6c; + border-radius: 2px; + background-color: #373737; + background-repeat: no-repeat; + background-position: center; + transition: all 0.15s ease-in-out; + &.ico01 { + background-image: url(../../public/static/images/canvas/shape_labrary01.svg); + background-size: 19px 18px; + } + &.ico02 { + background-image: url(../../public/static/images/canvas/shape_labrary02.svg); + background-size: 15px 20px; + } + &.ico03 { + background-image: url(../../public/static/images/canvas/shape_labrary03.svg); + background-size: 19px 16px; + } + &:hover { + border-color: #1083e3; + background-color: #1083e3; + } + } +} + +.plane-detail-wrap { + display: flex; + flex-direction: column; + flex: 1; +} +.plane-shape-wrapper { + flex: 1; + display: flex; + flex-direction: column; + gap: 10px; + .plane-box { + width: 100%; + padding: 10px 18px; + border-radius: 2px; + background-color: #313131; + border: 1px solid #484848; + .plane-box-tit { + font-size: $pop-normal-size; + font-weight: 600; + color: $pop-color; + margin-bottom: 10px; + } + &.shape-box { + .shape-box-inner { + display: flex; + gap: 15px; + min-height: 140px; + .shape-img { + position: relative; + flex: none; + width: 150px; + background-color: #fff; + border-radius: 2px; + img { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); + } } - } -} - -// 표시변경 -.display-change-wrap{ - margin: 24px 0; -} -.warning{ - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: #FFAFAF; -} - -// 각 변 속성 변경 -.radio-grid-wrap{ - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 24px 15px; -} - -// 면 흐름 설정 -.drawing-flow-wrap{ - display: flex; - gap: 10px; - .discrimination-box{ - flex: 1; - display: flex; - flex-direction: column; - .object-direction-wrap{ - flex: 1; - } - } -} - -.compas-box{ - display: flex; - align-items: center; - justify-content: center; -} -.compas-box-inner { - position: relative; - width: 200px; - height: 200px; - border-radius: 50%; - - .circle { - position: absolute; - width: 12px; - height: 12px; - border: 1px solid #fff; - border-radius: 50%; - top: 95%; - left: 50%; - transform-origin: 0 -90px; /* 중심에서 반지름 거리만큼 떨어져 위치 */ - cursor:pointer; - z-index: 3; - /* 0번을 180도 위치(아래)에, 13번을 0도 위치(위)에 배치 */ - i{ - position: absolute; - top: 12.5px; - left: 50%; - font-size: 11px; - color: #8B8B8B; - font-weight: 500; - -webkit-user-select: none; - -moz-user-select: none; - -ms-use-select: none; - user-select: none; - } - &:nth-child(1) { transform: rotate(180deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(180deg);}} - &:nth-child(2) { transform: rotate(195deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(165deg);}} - &:nth-child(3) { transform: rotate(210deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(150deg);}} - &:nth-child(4) { transform: rotate(225deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(135deg);}} - &:nth-child(5) { transform: rotate(240deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(120deg);}} - &:nth-child(6) { transform: rotate(255deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(105deg);}} - &:nth-child(7) { transform: rotate(270deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(90deg);}} - &:nth-child(8) { transform: rotate(285deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(75deg);}} - &:nth-child(9) { transform: rotate(300deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(60deg);}} - &:nth-child(10) { transform: rotate(315deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(45deg);}} - &:nth-child(11) { transform: rotate(330deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(30deg);}} - &:nth-child(12) { transform: rotate(345deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(15deg);}} - &:nth-child(13) { transform: rotate(0deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(0deg);}} - &:nth-child(14) { transform: rotate(15deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-15deg);}} - &:nth-child(15) { transform: rotate(30deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-30deg);}} - &:nth-child(16) { transform: rotate(45deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-45deg);}} - &:nth-child(17) { transform: rotate(60deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-60deg);}} - &:nth-child(18) { transform: rotate(75deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-75deg);}} - &:nth-child(19) { transform: rotate(90deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-90deg);}} - &:nth-child(20) { transform: rotate(105deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-105deg);}} - &:nth-child(21) { transform: rotate(120deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-120deg);}} - &:nth-child(22) { transform: rotate(135deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-135deg);}} - &:nth-child(23) { transform: rotate(150deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-150deg);}} - &:nth-child(24) { transform: rotate(165deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-165deg);}} - &.act{ - &::after{ - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 5px; - height: 5px; - background-color: #fff; - } - i{ - color: #fff; - } - } - } - .compas{ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 148px; - height: 148px; - border: 4px solid #fff; - border-radius: 50%; - .compas-arr{ - width: 100%; - height: 100%; - background: url(../../public/static/images/canvas/compas.svg)no-repeat center; - background-size: 122px 122px; - } - } -} - - -// 지붕모듈선택 -.roof-module-tab{ - display: flex; - align-items: center; - gap: 10px; - margin-bottom: 14px; - .module-tab-bx{ - flex: 1; - height: 34px; - line-height: 31px; - border: 1px solid #484848; - border-radius: 2px; - background-color: transparent; - font-size: 12px; - color: #AAA; - text-align: center; - cursor: default; - transition: all .15s ease-in-out; - &.act{ - background-color: #1083E3; - border: 1px solid #1083E3; - color: #fff; - font-weight: 500; - } - } - .tab-arr{ - display: block; - width: 9px; - height: 14px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - background-image: url(../../public/static/images/canvas/module_tab_arr.svg); - transition: all .15s ease-in-out; - &.act{ - background-image: url(../../public/static/images/canvas/module_tab_arr_white.svg); - } - } -} - -.roof-module-compas{ - margin-bottom: 24px; - .compas-box-inner{ - width: 280px; - height: 253px; - .circle{ - top: 86%; - &:nth-child(1), - &:nth-child(7), - &:nth-child(13), - &:nth-child(19){ - &::before{ - content: ''; - position: absolute; - top: 20px; - left: 50%; - transform: translateX(-50%); - width: 1px; - height: 6px; - background-color: #8B8B8B; + .shape-data { + flex: 1; + .eaves-keraba-table { + .eaves-keraba-item { + .eaves-keraba-th, + .eaves-keraba-td { + padding-bottom: 10px; + } + &:last-child { + .eaves-keraba-th, + .eaves-keraba-td { + padding-bottom: 0px; } + } } - i{ - top: 32px; - } - &.act{ - i{color: #8B8B8B;} - } + } } + } } -} -.center-wrap{ - display: flex; - flex-direction: column; - align-items: center; - gap: 20px; -} - -.module-table-flex-wrap{ - display: flex; - gap: 10px; - .outline-form{ + &.direction-box { + flex: 1; + display: flex; + flex-direction: column; + .plane-direction-box { flex: 1; - } -} - -.module-box-tab{ - display: flex; - .module-btn{ - flex: 1; - border-top: 1px solid #505050; - border-bottom: 1px solid #505050; - border-right: 1px solid #505050; - background-color: #454545; - color: #fff; - height: 30px; - font-size: 12px; - font-weight: 400; - transition: all .15s ease-in-out; - &:first-child{ - border-left: 1px solid #505050; - } - &.act{ - border-color: #fff; - background-color: #fff; - color: #101010; - } - } -} - -.module-table-box{ - flex: 1; - background-color: #3D3D3D; - border-radius: 2px; - .module-table-inner{ - padding: 10px; - .outline-form{ - span{ - width: auto; - } - } - .module-table-tit{ - padding: 10px 0; - font-size: 12px; - color: #fff; - border-bottom: 1px solid #4D4D4D; - } - .eaves-keraba-table{ - width: 100%; - margin-top: 15px; - .eaves-keraba-th{ - width: 72px; - } - .eaves-keraba-th, - .eaves-keraba-td{ - padding-bottom: 5px; - } - } - .self-table-tit{ - font-size: 12px; - font-weight: 500; - color: #fff; - padding-bottom: 15px; - } - } - .warning-guide{ - padding: 20px; - .warning{ - color: #FFCACA; - max-height: 55px; - overflow-y: auto; - padding-right: 30px; - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #D9D9D9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } - } - } -} - -.module-self-table{ - display: table; - border-top: 1px solid #4D4D4D; - border-collapse: collapse; - width: 100%; - .self-table-item{ - display: table-row; - .self-item-td, - .self-item-th{ - display: table-cell; - vertical-align: middle; - border-bottom: 1px solid #4D4D4D; - } - .self-item-th{ - width: 60px; - font-size: 12px; - font-weight: 500; - color: #fff; - } - .self-item-td{ - font-size: 12px; - font-weight: 400; - color: #fff; - padding: 15px 20px; - } - } -} - -.self-table-flx{ - display: flex; - align-items: center; - margin-top: 15px; - button{ - margin-left: auto; - } -} -.hexagonal-wrap{ - .hexagonal-item{ - padding: 15px 0; - border-bottom: 1px solid #4D4D4D; - &:first-child{ - padding-top: 0; - } - &:last-child{ - padding-bottom: 0; - border: none; - } - .hexagonal-flx-auto{ - display: flex; - justify-content: space-between; - } - .hexagonal-flx{ - display: flex; - align-items: center; - button{ - margin-left: auto; - } - } - } -} - -// 회로 및 가대설정 -.circuit-check-inner{ - padding: 5px 0; -} - -.x-scroll-table{ - overflow-x: auto; - padding-bottom: 5px; - .roof-module-table{ - min-width: 1200px; - } - &::-webkit-scrollbar { - height: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #D9D9D9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } -} - -.circuit-right-wrap{ - display: flex; - justify-content: flex-end; -} - -.circuit-data-form{ - display: flex; - flex-direction: column; - gap: 5px; - min-height: 60px; - padding: 12px; - border: 1px solid rgba(255, 255, 255, 0.20); - span{ - display: inline-flex; - align-items: center; - .del{ - display: block; - margin-left: 10px; - width: 15px; - height: 15px; - background: url(../../public/static/images/canvas/circuit_del.svg)no-repeat center; - background-size: cover; - } - } -} -.circuit-table-tit{ - color: #fff; - font-size: 12px; - font-weight: 600; - padding: 11px 10px; - background-color: #474747; - border: 1px solid #505050; - border-bottom: none; -} - -.circuit-overflow{ - max-height: 400px; - overflow-y: auto; - margin-bottom: 15px; - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #D9D9D9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } -} - -.circuit-table-flx-wrap{ - display: flex; - gap: 10px; - margin-bottom: 10px; - .circuit-table-flx-box{ - flex: 1; - display: flex; - flex-direction: column; - .bottom-wrap{ - margin-top: auto; - } - .roof-module-table{ - table{ - table-layout: fixed; - } - } - } -} - -.circuit-count-input{ - display: flex; - align-items: center; - gap: 10px; -} - -// 모듈부가기능 -.additional-radio-wrap{ - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 15px 0; - margin-bottom: 24px; -} -.additional-wrap{ - padding: 24px 0; - border-top: 1px solid #424242; -} - -.additional-color-wrap{ - display: flex; - align-items: center; - padding: 5px 0; - gap: 15px; - .additional-color-box{ - display: flex; - align-items: center; - gap: 8px; - .additional-color{ - display: block; - width: 16px; - height: 16px; - &.pink{ - border: 2px solid #ce1c9c; - background-color: #16417D; - } - &.white{ - border: 2px solid #FFF; - background-color: #001027; - } - } - } -} - -// color setting -.color-setting-wrap{ - padding-bottom: 15px; - border-bottom: 1px solid #424242; - .color-tit{ - font-size: 13px; - font-weight: 500; - color: #ffffff; - margin-bottom: 10px; - } - .color-picker{ - .react-colorful{ - width: 100%; - height: auto; - gap: 20px; - .react-colorful__pointer{ - width: 15px; - height: 15px; - border: 4px solid #Fff; - } - .react-colorful__saturation{ - border-radius: 2px; - height: 200px; - border-bottom: 5px solid #000; - } - .react-colorful__last-control{ - border-radius: 2px; - height: 10px; - } - } - .hex-color-box{ - display: flex; - align-items: center; - margin-top: 15px; - .color-box-tit{ - font-size: 12px; - color: #fff; - font-weight: 500; - margin-right: 10px; - } - .color-hex-input{ - width: 150px; - margin-right: 5px; - input{ - width: 100%; - } - } - .color-box{ - display: block; - width: 30px; - height: 30px; - border-radius: 4px; - } - } - .default-color-wrap{ - margin-top: 25px; - .default-tit{ - font-size: 12px; - font-weight: 500; - color: #fff; - margin-bottom: 10px; - } - .color-button-wrap{ - display: grid; - grid-template-columns: repeat(8, 1fr); - gap: 21px; - .default-color{ - display: block; - width: 100%; - height: 30px; - border-radius: 4px; - } - } - } - } -} - -// 글꼴 설정 팝업 -.font-option-warp{ - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 15px 5px; - margin-bottom: 15px; - .font-option-item{ - .option-item-tit{ - font-size: 12px; - font-weight: 500; - color: #fff; - margin-bottom: 10px; - } - } -} -.font-ex-wrap{ - margin-bottom: 15px; - .font-ex-tit{ - font-size: 12px; - font-weight: 500; - color: #fff; - margin-bottom: 10px; - } - .font-ex-box{ display: flex; align-items: center; justify-content: center; width: 100%; - min-height: 80px; - background-color: #fff; + } } - + } } - -// 치수선 설정 -.font-btn-wrap{ - margin-bottom: 15px; - button{ - width: 100%; - height: 30px; - line-height: 28px; +.plane-direction { + width: 150px; + position: relative; + height: 120px; + span { + position: absolute; + font-size: 12px; + font-weight: 500; + color: #b1b1b1; + &.top { + top: 0; + left: 50%; + transform: translateX(-50%); } -} - -.line-color-wrap{ - margin-bottom: 15px; - .color-btn{ - display: block; - width: 100%; - height: 30px; - border-radius: 2px; + &.right { + top: 50%; + right: 0; + transform: translateY(-50%); } -} - -.form-box{ - width: 100%; - background-color: #fff; - padding: 10px 15px 20px; - .line-form{ - position: relative; - display: flex; - flex-direction: column; - justify-content: flex-end; - min-width: 102px; - min-height: 40px; - margin: 0 auto; - - &::before{ - content: ''; - position: absolute; - bottom: 0px; - left: 0; - width: 100%; - height: 40px; - border-left: 1px dashed #101010; - border-right: 1px dashed #101010; - } - .line-font-box{ - .font{ - display: block; - padding-bottom: 15px; - color: #101010; - text-align: center; - line-height: 1; - } - .line{ - position: relative; - display: block; - width: 100%; - height: 1px; - border-radius: 30px; - &::before{ - content: ''; - position: absolute; - top: 50%; - transform: translateY(-50%) rotate(45deg); - left: 1px; - width: 9px; - height:+ 9px; - border: 1px solid; - border-color: inherit; - border-top: none; - border-right: none; - } - &::after{ - content: ''; - position: absolute; - top: 50%; - transform: translateY(-50%) rotate(45deg); - right: 1px; - width: 9px; - height: 9px; - border: 1px solid; - border-color: inherit; - border-bottom: none; - border-left: none; - } - } - } + &.bottom { + bottom: 0; + left: 50%; + transform: translateX(-50%); } + &.left { + top: 50%; + left: 0; + transform: translateY(-50%); + } + } + .plane-btn { + position: absolute; + width: 28px; + height: 28px; + background-color: #777777; + background-image: url(../../public/static/images/canvas/plane_arr.svg); + background-size: 12px 13px; + background-repeat: no-repeat; + background-position: center; + border-radius: 50%; + transition: all 0.15s ease-in-out; + &.up { + top: 22px; + left: 50%; + transform: translateX(-50%); + } + &.right { + top: 50%; + right: 32px; + transform: translateY(-50%) rotate(90deg); + } + &.down { + bottom: 22px; + left: 50%; + transform: translateX(-50%) rotate(180deg); + } + &.left { + top: 50%; + left: 32px; + transform: translateY(-50%) rotate(270deg); + } + &:hover, + &.act { + background-color: #fff; + background-image: url(../../public/static/images/canvas/plane_arr_act.svg); + } + } } -// 사이즈 변경 -.size-inner-warp{ - position: relative; +.plane-tab-guide { + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: $pop-color; + margin-top: 10px; } -.size-check-wrap{ - position: relative; +.plane-shape-btn { + padding-top: 10px; + margin-top: auto; + button { display: block; - width: 132px; - height: 132px; - margin: 0 auto; - .size-btn{ - position: absolute; - width: 16px; - height: 16px; - border: 1px solid #fff; - border-radius: 50%; - &.act{ - &::after{ - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 8px; - height: 8px; - background-color: #fff; - border-radius: 50%; - } - } - &:nth-child(1){ top: 0; left: 0; } - &:nth-child(2){ top: 0; right: 0; } - &:nth-child(3){ bottom: 0; left: 0; } - &:nth-child(4){ bottom: 0; right: 0; } + width: 100%; + } +} + +// 오브젝트 배치 +.mb-box { + margin-bottom: 24px; +} + +.object-direction-wrap { + display: flex; + align-items: center; + justify-content: center; +} +.discrimination-tit { + font-size: 13px; + color: #fff; + font-weight: 500; +} + +.object-size-wrap { + display: flex; + min-height: 206px; + gap: 24px; + margin-top: 14px; + .object-size-img { + position: relative; + flex: none; + width: 200px; + background-color: #fff; + img { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); } - .size-box{ + } +} + +// 표시변경 +.display-change-wrap { + margin: 24px 0; +} +.warning { + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: #ffafaf; +} + +// 각 변 속성 변경 +.radio-grid-wrap { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24px 15px; +} + +// 면 흐름 설정 +.drawing-flow-wrap { + display: flex; + gap: 10px; + .discrimination-box { + flex: 1; + display: flex; + flex-direction: column; + .object-direction-wrap { + flex: 1; + } + } +} + +.compas-box { + display: flex; + align-items: center; + justify-content: center; +} +.compas-box-inner { + position: relative; + width: 200px; + height: 200px; + border-radius: 50%; + + .circle { + position: absolute; + width: 12px; + height: 12px; + border: 1px solid #fff; + border-radius: 50%; + top: 95%; + left: 50%; + transform-origin: 0 -90px; /* 중심에서 반지름 거리만큼 떨어져 위치 */ + cursor: pointer; + z-index: 3; + /* 0번을 180도 위치(아래)에, 13번을 0도 위치(위)에 배치 */ + i { + position: absolute; + top: 12.5px; + left: 50%; + font-size: 11px; + color: #8b8b8b; + font-weight: 500; + -webkit-user-select: none; + -moz-user-select: none; + -ms-use-select: none; + user-select: none; + } + &:nth-child(1) { + transform: rotate(180deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(180deg); + } + } + &:nth-child(2) { + transform: rotate(195deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(165deg); + } + } + &:nth-child(3) { + transform: rotate(210deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(150deg); + } + } + &:nth-child(4) { + transform: rotate(225deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(135deg); + } + } + &:nth-child(5) { + transform: rotate(240deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(120deg); + } + } + &:nth-child(6) { + transform: rotate(255deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(105deg); + } + } + &:nth-child(7) { + transform: rotate(270deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(90deg); + } + } + &:nth-child(8) { + transform: rotate(285deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(75deg); + } + } + &:nth-child(9) { + transform: rotate(300deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(60deg); + } + } + &:nth-child(10) { + transform: rotate(315deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(45deg); + } + } + &:nth-child(11) { + transform: rotate(330deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(30deg); + } + } + &:nth-child(12) { + transform: rotate(345deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(15deg); + } + } + &:nth-child(13) { + transform: rotate(0deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(0deg); + } + } + &:nth-child(14) { + transform: rotate(15deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-15deg); + } + } + &:nth-child(15) { + transform: rotate(30deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-30deg); + } + } + &:nth-child(16) { + transform: rotate(45deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-45deg); + } + } + &:nth-child(17) { + transform: rotate(60deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-60deg); + } + } + &:nth-child(18) { + transform: rotate(75deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-75deg); + } + } + &:nth-child(19) { + transform: rotate(90deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-90deg); + } + } + &:nth-child(20) { + transform: rotate(105deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-105deg); + } + } + &:nth-child(21) { + transform: rotate(120deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-120deg); + } + } + &:nth-child(22) { + transform: rotate(135deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-135deg); + } + } + &:nth-child(23) { + transform: rotate(150deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-150deg); + } + } + &:nth-child(24) { + transform: rotate(165deg) translate(-50%, -50%); + i { + transform: translateX(-50%) rotate(-165deg); + } + } + &.act { + &::after { + content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - width: 100px; - height: 100px; + width: 5px; + height: 5px; background-color: #fff; + } + i { + color: #fff; + } } -} - -.size-option-top{ - margin-bottom: 15px; -} -.size-option-side{ + } + .compas { position: absolute; top: 50%; - left: 0; - transform: translateY(-50%); -} -.size-option-wrap{ - width: 88px; - margin: 0 auto; - .size-option{ - display: flex; - align-items: center; - input{ - width: 100%; - flex: 1; - } - span{ - flex: none; - } + left: 50%; + transform: translate(-50%, -50%); + width: 148px; + height: 148px; + border: 4px solid #fff; + border-radius: 50%; + .compas-arr { + width: 100%; + height: 100%; + background: url(../../public/static/images/canvas/compas.svg) no-repeat center; + background-size: 122px 122px; } + } +} + +// 지붕모듈선택 +.roof-module-tab { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 14px; + .module-tab-bx { + flex: 1; + height: 34px; + line-height: 31px; + border: 1px solid #484848; + border-radius: 2px; + background-color: transparent; + font-size: 12px; + color: #aaa; + text-align: center; + cursor: default; + transition: all 0.15s ease-in-out; + &.act { + background-color: #1083e3; + border: 1px solid #1083e3; + color: #fff; + font-weight: 500; + } + } + .tab-arr { + display: block; + width: 9px; + height: 14px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + background-image: url(../../public/static/images/canvas/module_tab_arr.svg); + transition: all 0.15s ease-in-out; + &.act { + background-image: url(../../public/static/images/canvas/module_tab_arr_white.svg); + } + } +} + +.roof-module-compas { + margin-bottom: 24px; + .compas-box-inner { + width: 280px; + height: 253px; + .circle { + top: 86%; + &:nth-child(1), + &:nth-child(7), + &:nth-child(13), + &:nth-child(19) { + &::before { + content: ''; + position: absolute; + top: 20px; + left: 50%; + transform: translateX(-50%); + width: 1px; + height: 6px; + background-color: #8b8b8b; + } + } + i { + top: 32px; + } + &.act { + i { + color: #8b8b8b; + } + } + } + } +} +.center-wrap { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; +} + +.module-table-flex-wrap { + display: flex; + gap: 10px; + .outline-form { + flex: 1; + } +} + +.module-box-tab { + display: flex; + .module-btn { + flex: 1; + border-top: 1px solid #505050; + border-bottom: 1px solid #505050; + border-right: 1px solid #505050; + background-color: #454545; + color: #fff; + height: 30px; + font-size: 12px; + font-weight: 400; + transition: all 0.15s ease-in-out; + &:first-child { + border-left: 1px solid #505050; + } + &.act { + border-color: #fff; + background-color: #fff; + color: #101010; + } + } +} + +.module-table-box { + flex: 1; + background-color: #3d3d3d; + border-radius: 2px; + .module-table-inner { + padding: 10px; + .outline-form { + span { + width: auto; + } + } + .module-table-tit { + padding: 10px 0; + font-size: 12px; + color: #fff; + border-bottom: 1px solid #4d4d4d; + } + .eaves-keraba-table { + width: 100%; + margin-top: 15px; + .eaves-keraba-th { + width: 72px; + } + .eaves-keraba-th, + .eaves-keraba-td { + padding-bottom: 5px; + } + } + .self-table-tit { + font-size: 12px; + font-weight: 500; + color: #fff; + padding-bottom: 15px; + } + } + .warning-guide { + padding: 20px; + .warning { + color: #ffcaca; + max-height: 55px; + overflow-y: auto; + padding-right: 30px; + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #d9d9d9; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } + } + } +} + +.module-self-table { + display: table; + border-top: 1px solid #4d4d4d; + border-collapse: collapse; + width: 100%; + .self-table-item { + display: table-row; + .self-item-td, + .self-item-th { + display: table-cell; + vertical-align: middle; + border-bottom: 1px solid #4d4d4d; + } + .self-item-th { + width: 60px; + font-size: 12px; + font-weight: 500; + color: #fff; + } + .self-item-td { + font-size: 12px; + font-weight: 400; + color: #fff; + padding: 15px 20px; + } + } +} + +.self-table-flx { + display: flex; + align-items: center; + margin-top: 15px; + button { + margin-left: auto; + } +} +.hexagonal-wrap { + .hexagonal-item { + padding: 15px 0; + border-bottom: 1px solid #4d4d4d; + &:first-child { + padding-top: 0; + } + &:last-child { + padding-bottom: 0; + border: none; + } + .hexagonal-flx-auto { + display: flex; + justify-content: space-between; + } + .hexagonal-flx { + display: flex; + align-items: center; + button { + margin-left: auto; + } + } + } +} + +// 회로 및 가대설정 +.circuit-check-inner { + padding: 5px 0; +} + +.x-scroll-table { + overflow-x: auto; + padding-bottom: 5px; + .roof-module-table { + min-width: 1200px; + } + &::-webkit-scrollbar { + height: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #d9d9d9; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } +} + +.circuit-right-wrap { + display: flex; + justify-content: flex-end; +} + +.circuit-data-form { + display: flex; + flex-direction: column; + gap: 5px; + min-height: 60px; + padding: 12px; + border: 1px solid rgba(255, 255, 255, 0.2); + span { + display: inline-flex; + align-items: center; + .del { + display: block; + margin-left: 10px; + width: 15px; + height: 15px; + background: url(../../public/static/images/canvas/circuit_del.svg) no-repeat center; + background-size: cover; + } + } +} +.circuit-table-tit { + color: #fff; + font-size: 12px; + font-weight: 600; + padding: 11px 10px; + background-color: #474747; + border: 1px solid #505050; + border-bottom: none; +} + +.circuit-overflow { + max-height: 400px; + overflow-y: auto; + margin-bottom: 15px; + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #d9d9d9; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } +} + +.circuit-table-flx-wrap { + display: flex; + gap: 10px; + margin-bottom: 10px; + .circuit-table-flx-box { + flex: 1; + display: flex; + flex-direction: column; + .bottom-wrap { + margin-top: auto; + } + .roof-module-table { + table { + table-layout: fixed; + } + } + } +} + +.circuit-count-input { + display: flex; + align-items: center; + gap: 10px; +} + +// 모듈부가기능 +.additional-radio-wrap { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px 0; + margin-bottom: 24px; +} +.additional-wrap { + padding: 24px 0; + border-top: 1px solid #424242; +} + +.additional-color-wrap { + display: flex; + align-items: center; + padding: 5px 0; + gap: 15px; + .additional-color-box { + display: flex; + align-items: center; + gap: 8px; + .additional-color { + display: block; + width: 16px; + height: 16px; + &.pink { + border: 2px solid #ce1c9c; + background-color: #16417d; + } + &.white { + border: 2px solid #fff; + background-color: #001027; + } + } + } +} + +// color setting +.color-setting-wrap { + padding-bottom: 15px; + border-bottom: 1px solid #424242; + .color-tit { + font-size: 13px; + font-weight: 500; + color: #ffffff; + margin-bottom: 10px; + } + .color-picker { + .react-colorful { + width: 100%; + height: auto; + gap: 20px; + .react-colorful__pointer { + width: 15px; + height: 15px; + border: 4px solid #fff; + } + .react-colorful__saturation { + border-radius: 2px; + height: 200px; + border-bottom: 5px solid #000; + } + .react-colorful__last-control { + border-radius: 2px; + height: 10px; + } + } + .hex-color-box { + display: flex; + align-items: center; + margin-top: 15px; + .color-box-tit { + font-size: 12px; + color: #fff; + font-weight: 500; + margin-right: 10px; + } + .color-hex-input { + width: 150px; + margin-right: 5px; + input { + width: 100%; + } + } + .color-box { + display: block; + width: 30px; + height: 30px; + border-radius: 4px; + } + } + .default-color-wrap { + margin-top: 25px; + .default-tit { + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + .color-button-wrap { + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 21px; + .default-color { + display: block; + width: 100%; + height: 30px; + border-radius: 4px; + } + } + } + } +} + +// 글꼴 설정 팝업 +.font-option-warp { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px 5px; + margin-bottom: 15px; + .font-option-item { + .option-item-tit { + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + } +} +.font-ex-wrap { + margin-bottom: 15px; + .font-ex-tit { + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + .font-ex-box { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + min-height: 80px; + background-color: #fff; + } +} + +// 치수선 설정 +.font-btn-wrap { + margin-bottom: 15px; + button { + width: 100%; + height: 30px; + line-height: 28px; + } +} + +.line-color-wrap { + margin-bottom: 15px; + .color-btn { + display: block; + width: 100%; + height: 30px; + border-radius: 2px; + } +} + +.form-box { + width: 100%; + background-color: #fff; + padding: 10px 15px 20px; + .line-form { + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-end; + min-width: 102px; + min-height: 40px; + margin: 0 auto; + + &::before { + content: ''; + position: absolute; + bottom: 0px; + left: 0; + width: 100%; + height: 40px; + border-left: 1px dashed #101010; + border-right: 1px dashed #101010; + } + .line-font-box { + .font { + display: block; + padding-bottom: 15px; + color: #101010; + text-align: center; + line-height: 1; + } + .line { + position: relative; + display: block; + width: 100%; + height: 1px; + border-radius: 30px; + &::before { + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + left: 1px; + width: 9px; + height: +9px; + border: 1px solid; + border-color: inherit; + border-top: none; + border-right: none; + } + &::after { + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + right: 1px; + width: 9px; + height: 9px; + border: 1px solid; + border-color: inherit; + border-bottom: none; + border-left: none; + } + } + } + } +} + +// 사이즈 변경 +.size-inner-warp { + position: relative; +} +.size-check-wrap { + position: relative; + display: block; + width: 132px; + height: 132px; + margin: 0 auto; + .size-btn { + position: absolute; + width: 16px; + height: 16px; + border: 1px solid #fff; + border-radius: 50%; + &.act { + &::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 8px; + height: 8px; + background-color: #fff; + border-radius: 50%; + } + } + &:nth-child(1) { + top: 0; + left: 0; + } + &:nth-child(2) { + top: 0; + right: 0; + } + &:nth-child(3) { + bottom: 0; + left: 0; + } + &:nth-child(4) { + bottom: 0; + right: 0; + } + } + .size-box { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 100px; + height: 100px; + background-color: #fff; + } +} + +.size-option-top { + margin-bottom: 15px; +} +.size-option-side { + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); +} +.size-option-wrap { + width: 88px; + margin: 0 auto; + .size-option { + display: flex; + align-items: center; + input { + width: 100%; + flex: 1; + } + span { + flex: none; + } + } } //이미지 크기 설정 -.range-wrap{ - display: flex; - align-items: center; - input{ - flex: 1; - margin-right: 10px; - } - label{ - flex: none; - text-align: right; - width: 38px; - font-size: 13px; - color: #fff; - font-weight: 500; - } -} \ No newline at end of file +.range-wrap { + display: flex; + align-items: center; + input { + flex: 1; + margin-right: 10px; + } + label { + flex: none; + text-align: right; + width: 38px; + font-size: 13px; + color: #fff; + font-weight: 500; + } +} From 70ebb63fa78346f06ed3769715afd837f1d84b97 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 5 Nov 2024 10:17:40 +0900 Subject: [PATCH 30/63] =?UTF-8?q?api=20=ED=98=B8=EC=B6=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/roof2/RoofSelect.jsx | 128 --------------------------- src/app/roof2/page.jsx | 6 -- src/components/InitSettingsModal.jsx | 7 -- 3 files changed, 141 deletions(-) delete mode 100644 src/app/roof2/RoofSelect.jsx diff --git a/src/app/roof2/RoofSelect.jsx b/src/app/roof2/RoofSelect.jsx deleted file mode 100644 index d759398b..00000000 --- a/src/app/roof2/RoofSelect.jsx +++ /dev/null @@ -1,128 +0,0 @@ -'use client' - -import { Select, SelectItem } from '@nextui-org/react' -import { useEffect, useState } from 'react' -import { useAxios } from '@/hooks/useAxios' - -export default function RoofSelect() { - const [roofMaterials, setRoofMaterials] = useState([]) - const [manufacturers, setManufacturers] = useState([]) - const [trestles, setTrestles] = useState([]) - const [modules, setModules] = useState([]) - const [originTrestles, setOriginTrestles] = useState([]) - - const [roofMaterialId, setRoofMaterialId] = useState(null) - const [manufacturerId, setManufacturerId] = useState(null) - const [trestleId, setTrestleId] = useState(null) - - const { get } = useAxios() - - useEffect(() => { - get({ url: '/api/roof-material/roof-material-infos' }).then((res) => { - //TODO: error handling - if (!res) return - - setRoofMaterials(res) - }) - }, []) - - useEffect(() => { - if (!roofMaterialId) { - return - } - - get({ url: `/api/roof-material/roof-material-infos/${roofMaterialId}/trestles` }).then((res) => { - if (res.length === 0) { - return - } - setOriginTrestles(res) - const manufactural = res.map((trestle) => { - return { id: trestle.manufacturerId, name: trestle.manufacturerName } - }) - // Remove duplicates - const uniqueManufactural = Array.from(new Set(manufactural.map((a) => a.id))).map((id) => { - return manufactural.find((a) => a.id === id) - }) - - setManufacturers(uniqueManufactural) - }) - }, [roofMaterialId]) - - useEffect(() => { - if (!manufacturerId) { - return - } - - const trestles = originTrestles.filter((trestle) => trestle.manufacturerId === manufacturerId) - setTrestles(trestles) - }, [manufacturerId]) - - useEffect(() => { - if (!trestleId) { - return - } - get({ url: `/api/module/module-infos?roofMaterialId=${roofMaterialId}&trestleId=${trestleId}` }).then((res) => { - if (res.length === 0) { - return - } - setModules(res) - }) - }, [trestleId]) - - const handleRoofMaterialOnChange = (e) => { - const roofMaterialId = e.target.value - setRoofMaterialId(roofMaterialId) - setManufacturers([]) - setManufacturerId(null) - setTrestleId(null) - setTrestles([]) - setModules([]) - } - - const handleManufacturersOnChange = (e) => { - const manufacturerId = Number(e.target.value) - setTrestles([]) - setManufacturerId(manufacturerId) - setTrestleId(null) - setModules([]) - } - - const handleTrestlesOnChange = (e) => { - const trestleId = Number(e.target.value) - setTrestleId(trestleId) - setModules([]) - } - - return ( -
    - {roofMaterials.length > 0 && ( - - )} - {manufacturers.length > 0 && ( - - )} - {trestles.length > 0 && ( - - )} - {modules.length > 0 && ( - - )} -
    - ) -} diff --git a/src/app/roof2/page.jsx b/src/app/roof2/page.jsx index dce69910..94e86fbe 100644 --- a/src/app/roof2/page.jsx +++ b/src/app/roof2/page.jsx @@ -1,14 +1,8 @@ import Roof2 from '@/components/Roof2' -import RoofSelect from '@/app/roof2/RoofSelect' export default async function Roof2Page() { return ( <> -
    -
    - -
    -
    diff --git a/src/components/InitSettingsModal.jsx b/src/components/InitSettingsModal.jsx index 5f0837a8..52c82e86 100644 --- a/src/components/InitSettingsModal.jsx +++ b/src/components/InitSettingsModal.jsx @@ -29,13 +29,6 @@ export default function InitSettingsModal(props) { //const { get, post } = useAxios() useEffect(() => { - get({ url: '/api/roof-material/roof-material-infos' }).then((res) => { - //TODO: error handling - if (!res) return - - setRoofMaterials(res) - }) - get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => { if (res.length == 0) return From 34e3872123da165564787954cfbde94b765e7509 Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 5 Nov 2024 13:13:22 +0900 Subject: [PATCH 31/63] =?UTF-8?q?=EB=8B=A4=EA=B5=AD=EC=96=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/font/FontSetting.jsx | 43 +++++++++++----------- src/locales/ja.json | 13 +++++++ src/locales/ko.json | 13 +++++++ 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index 54b22b3b..a658871d 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -14,15 +14,7 @@ const fonts = [ { name: '@Yu Gothic UI', value: '@Yu Gothic UI' }, { name: 'Yu Gothic UI', value: 'Yu Gothic UI' }, ] -const fontOptions = [ - { name: '보통', value: 'normal' }, - { name: '기울임꼴', value: 'italic' }, - { - name: '굵게', - value: 'bold', - }, - { name: '굵은 기울임꼴', value: 'boldAndItalic' }, -] + const fontSizes = [ ...Array.from({ length: 4 }).map((_, index) => { return { name: index + 8, value: index + 8 } @@ -34,17 +26,7 @@ const fontSizes = [ { name: 48, value: 48 }, { name: 72, value: 72 }, ] -const fontColors = [ - { name: '검정색', value: 'black' }, - { name: '빨강색', value: 'red' }, - { name: '파랑색', value: 'blue' }, - { name: '회색', value: 'gray' }, - { name: '황색', value: 'yellow' }, - { name: '녹색', value: 'green' }, - { name: '분홍색', value: 'pink' }, - { name: '황금색', value: 'gold' }, - { name: '남색', value: 'darkblue' }, -] + export default function FontSetting(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, setIsShow, pos = contextPopupPosition, type, isConfig = false } = props @@ -57,7 +39,26 @@ export default function FontSetting(props) { const [selectedFontWeight, setSelectedFontWeight] = useState(currentFont.fontWeight) const [selectedFontSize, setSelectedFontSize] = useState(currentFont.fontSize) const [selectedFontColor, setSelectedFontColor] = useState(currentFont.fontColor) - + const fontOptions = [ + { name: getMessage('font.style.normal'), value: 'normal' }, + { name: getMessage('font.style.italic'), value: 'italic' }, + { + name: getMessage('font.style.bold'), + value: 'bold', + }, + { name: getMessage('font.style.bold.italic'), value: 'boldAndItalic' }, + ] + const fontColors = [ + { name: getMessage('color.black'), value: 'black' }, + { name: getMessage('color.red'), value: 'red' }, + { name: getMessage('color.blue'), value: 'blue' }, + { name: getMessage('color.gray'), value: 'gray' }, + { name: getMessage('color.yellow'), value: 'yellow' }, + { name: getMessage('color.green'), value: 'green' }, + { name: getMessage('color.pink'), value: 'pink' }, + { name: getMessage('color.gold'), value: 'gold' }, + { name: getMessage('color.darkblue'), value: 'darkblue' }, + ] const handleSaveBtn = () => { setGlobalFont((prev) => { return { diff --git a/src/locales/ja.json b/src/locales/ja.json index 390b3fe7..05ab09cf 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -483,6 +483,19 @@ "commons.east": "ドン", "commons.south": "南", "commons.north": "北", + "font.style.normal": "보통(JA)", + "font.style.italic": "기울임꼴(JA)", + "font.style.bold": "굵게(JA)", + "font.style.bold.italic": "굵은 기울임꼴(JA)", + "color.black": "검정색(JA)", + "color.red": "빨강색(JA)", + "color.blue": "파랑색(JA)", + "color.gray": "회색(JA)", + "color.yellow": "황색(JA)", + "color.green": "녹색(JA)", + "color.pink": "분홍색(JA)", + "color.gold": "황금색(JA)", + "color.darkblue": "남색(JA)", "site.name": "Q.CAST III", "site.sub_name": "太陽光発電システム図面管理サイト", "board.notice.title": "お知らせ", diff --git a/src/locales/ko.json b/src/locales/ko.json index 5f3fd48d..d8cef240 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -489,6 +489,19 @@ "commons.east": "동", "commons.south": "남", "commons.north": "북", + "font.style.normal": "보통", + "font.style.italic": "기울임꼴", + "font.style.bold": "굵게", + "font.style.bold.italic": "굵은 기울임꼴", + "color.black": "검정색", + "color.red": "빨강색", + "color.blue": "파랑색", + "color.gray": "회색", + "color.yellow": "황색", + "color.green": "녹색", + "color.pink": "분홍색", + "color.gold": "황금색", + "color.darkblue": "남색", "site.name": "Q.CAST III", "site.sub_name": "태양광 발전 시스템 도면관리 사이트", "board.notice.title": "공지사항", From 30dc9a12155ad876d4ad20d9826c0fb9e9a27d34 Mon Sep 17 00:00:00 2001 From: basssy Date: Tue, 5 Nov 2024 13:14:53 +0900 Subject: [PATCH 32/63] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/floorPlan/estimate/useEstimateController.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/floorPlan/estimate/useEstimateController.js b/src/hooks/floorPlan/estimate/useEstimateController.js index 3af6d048..87fa15ca 100644 --- a/src/hooks/floorPlan/estimate/useEstimateController.js +++ b/src/hooks/floorPlan/estimate/useEstimateController.js @@ -18,6 +18,7 @@ const defaultEstimateData = { objectNameOmit: '', //경칭코드 estimateType: 'YJOD', //주문분류 remarks: '', //비고 + estimateOption: '', //견적특이사항 // itemList: [{ id: 1, name: '' }], //아이템에 필요없는거 빼기 itemList: [ From 3a94703a8f5fd1fa096df1a92fd64f26bc6c38ec Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Tue, 5 Nov 2024 14:45:08 +0900 Subject: [PATCH 33/63] git clear cache --- src/components/fabric/QLine.js | 5 +- src/hooks/option/useCanvasSetting.js | 6 +- src/hooks/option/useFirstOption.js | 3 +- src/hooks/roofcover/useEavesGableEdit.js | 6 +- src/hooks/roofcover/useMovementSetting.js | 5 +- src/hooks/roofcover/usePropertiesSetting.js | 6 +- .../roofcover/useRoofAllocationSetting.js | 3 +- .../roofcover/useRoofShapePassivitySetting.js | 8 +- src/hooks/roofcover/useRoofShapeSetting.js | 8 +- src/util/qpolygon-utils.js | 72 ++- yarn.lock | 595 +++++++++++++----- 11 files changed, 525 insertions(+), 192 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 781d8395..6fb4237a 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -13,6 +13,9 @@ export const QLine = fabric.util.createClass(fabric.Line, { area: 0, children: [], initialize: function (points, options, length = 0) { + // 소수점 전부 제거 + points = points.map((point) => Number(point.toFixed(1))) + this.callSuper('initialize', points, { ...options, selectable: options.selectable ?? true }) if (options.id) { this.id = options.id @@ -20,8 +23,6 @@ export const QLine = fabric.util.createClass(fabric.Line, { this.id = uuidv4() } this.line = this - // 소수점 전부 제거 - points = points.map((point) => Math.round(point)) this.idx = options.idx ?? 0 this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }) diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js index 0f87e156..7aa77043 100644 --- a/src/hooks/option/useCanvasSetting.js +++ b/src/hooks/option/useCanvasSetting.js @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' -import { canvasState } from '@/store/canvasAtom' +import { adsorptionPointModeState, adsorptionRangeState, canvasState } from '@/store/canvasAtom' import { globalLocaleStore } from '@/store/localeAtom' import { useMessage } from '@/hooks/useMessage' import { useAxios } from '@/hooks/useAxios' @@ -9,8 +9,6 @@ import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@ import { setSurfaceShapePattern } from '@/util/canvas-util' import { POLYGON_TYPE } from '@/common/common' -import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom' - export function useCanvasSetting() { const canvas = useRecoilValue(canvasState) @@ -244,7 +242,7 @@ export function useCanvasSetting() { optionName = ['1'] break case 'outlineDisplay': //외벽선 표시 - optionName = ['outerLine', 'wallLine'] + optionName = ['outerLine', POLYGON_TYPE.WALL] break case 'gridDisplay': //그리드 표시 optionName = ['lindGrid', 'dotGrid'] diff --git a/src/hooks/option/useFirstOption.js b/src/hooks/option/useFirstOption.js index c3778587..f4459df4 100644 --- a/src/hooks/option/useFirstOption.js +++ b/src/hooks/option/useFirstOption.js @@ -2,6 +2,7 @@ import { useRecoilState, useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' import { useEffect } from 'react' import { settingModalFirstOptionsState } from '@/store/settingAtom' +import { POLYGON_TYPE } from '@/common/common' export function useFirstOption() { const canvas = useRecoilValue(canvasState) @@ -30,7 +31,7 @@ export function useFirstOption() { optionName = ['1'] break case 'outlineDisplay': //외벽선 표시 - optionName = ['outerLine', 'wallLine'] + optionName = ['outerLine', POLYGON_TYPE.WALL] break case 'gridDisplay': //그리드 표시 optionName = ['lineGrid', 'dotGrid', 'adsorptionPoint', 'tempGrid'] diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index 7696dc7a..5f5f07eb 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil' import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' -import { LINE_TYPE } from '@/common/common' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { useLine } from '@/hooks/useLine' import { useMode } from '@/hooks/useMode' import { outerLineFixState } from '@/store/outerLineAtom' @@ -54,7 +54,7 @@ export function useEavesGableEdit(id) { }, []) useEffect(() => { - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) wallLines.forEach((wallLine) => { convertPolygonToLines(wallLine) }) @@ -169,7 +169,7 @@ export function useEavesGableEdit(id) { canvas.remove(roof) }) - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'pitchText') removeTargets.forEach((obj) => { canvas.remove(obj) diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js index f0814a44..f09aee6b 100644 --- a/src/hooks/roofcover/useMovementSetting.js +++ b/src/hooks/roofcover/useMovementSetting.js @@ -4,6 +4,7 @@ import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' import { useEffect, useRef, useState } from 'react' import { useEvent } from '@/hooks/useEvent' +import { POLYGON_TYPE } from '@/common/common' //동선이동 형 올림 내림 export function useMovementSetting(id) { @@ -41,7 +42,7 @@ export function useMovementSetting(id) { }, [type]) useEffect(() => { - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 wallLine의 visible false + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) // 기존 wallLine의 visible false wallLines.forEach((line) => { line.set({ visible: false }) }) @@ -55,7 +56,7 @@ export function useMovementSetting(id) { addCanvasMouseEventListener('mouse:move', mouseMoveEvent) return () => { initEvent() - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) wallLines.forEach((line) => { line.set({ visible: true }) }) diff --git a/src/hooks/roofcover/usePropertiesSetting.js b/src/hooks/roofcover/usePropertiesSetting.js index b999c001..5a6164a2 100644 --- a/src/hooks/roofcover/usePropertiesSetting.js +++ b/src/hooks/roofcover/usePropertiesSetting.js @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react' -import { LINE_TYPE } from '@/common/common' -import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' +import { useRecoilValue, useResetRecoilState } from 'recoil' import { canvasState, currentObjectState } from '@/store/canvasAtom' import { useMode } from '@/hooks/useMode' import { usePolygon } from '@/hooks/usePolygon' @@ -135,7 +135,7 @@ export function usePropertiesSetting(id) { hideLine(line) }) - const wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' }) + const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) wall.lines = [...lines] diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 3be745d6..af29f95d 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -7,6 +7,7 @@ import { useSwal } from '@/hooks/useSwal' import { usePolygon } from '@/hooks/usePolygon' import { roofDisplaySelector } from '@/store/settingAtom' import { usePopup } from '@/hooks/usePopup' +import { POLYGON_TYPE } from '@/common/common' // 지붕면 할당 export function useRoofAllocationSetting(id) { @@ -105,7 +106,7 @@ export function useRoofAllocationSetting(id) { // 선택한 지붕재로 할당 const handleSave = () => { const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) roofBases.forEach((roofBase) => { try { splitPolygonWithLines(roofBase) diff --git a/src/hooks/roofcover/useRoofShapePassivitySetting.js b/src/hooks/roofcover/useRoofShapePassivitySetting.js index ef7a4477..290d0bae 100644 --- a/src/hooks/roofcover/useRoofShapePassivitySetting.js +++ b/src/hooks/roofcover/useRoofShapePassivitySetting.js @@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from 'react' import { useLine } from '@/hooks/useLine' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' -import { LINE_TYPE } from '@/common/common' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { useMode } from '@/hooks/useMode' import { usePolygon } from '@/hooks/usePolygon' import { outerLineFixState } from '@/store/outerLineAtom' @@ -60,7 +60,7 @@ export function useRoofShapePassivitySetting(id) { useEffect(() => { if (!isLoading) return addCanvasMouseEventListener('mouse:down', mouseDown) - const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) canvas?.remove(...wallLines) @@ -199,10 +199,10 @@ export function useRoofShapePassivitySetting(id) { let wall if (isFix.current) { - wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' }) + wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) } else { // 그냥 닫을 경우 처리 - wall = addPolygonByLines([...initLines.current], { name: 'wallLine', fill: 'transparent', stroke: 'black' }) + wall = addPolygonByLines([...initLines.current], { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) lines.forEach((line, idx) => { line.attributes = initLines.current[idx].attributes }) diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index ae886ce9..bc203221 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useRecoilValue, useSetRecoilState } from 'recoil' import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState, pitchTextSelector } from '@/store/canvasAtom' -import { LINE_TYPE } from '@/common/common' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { usePolygon } from '@/hooks/usePolygon' import { useMode } from '@/hooks/useMode' import { useLine } from '@/hooks/useLine' @@ -129,7 +129,7 @@ export function useRoofShapeSetting(id) { useEffect(() => { if (shapeNum === 4) { - canvas?.remove(canvas.getObjects().find((obj) => obj.name === 'wallLine')) + canvas?.remove(canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL)) const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') outerLines.forEach((line) => { showLine(line) @@ -376,7 +376,7 @@ export function useRoofShapeSetting(id) { // 기존 wallLine, roofBase 제거 canvas .getObjects() - .filter((obj) => obj.name === 'wallLine') + .filter((obj) => obj.name === POLYGON_TYPE.WALL) .forEach((line) => { canvas.remove(line) }) @@ -389,7 +389,7 @@ export function useRoofShapeSetting(id) { canvas.remove(obj) }) - const polygon = addPolygonByLines(outerLines, { name: 'wallLine' }) + const polygon = addPolygonByLines(outerLines, { name: POLYGON_TYPE.WALL }) polygon.lines = [...outerLines] addPitchTextsByOuterLines() diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 8e9c3553..4c5571fb 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -4,6 +4,7 @@ import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDegr import { QPolygon } from '@/components/fabric/QPolygon' import * as turf from '@turf/turf' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' +import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' const TWO_PI = Math.PI * 2 @@ -1259,9 +1260,9 @@ const drawRidge = (roof, canvas) => { let xEqualInnerLines = anotherRoof.filter((roof) => roof.x1 === roof.x2 && isInnerLine(prevRoof, currentRoof, nextRoof, roof)), //x가 같은 내부선 yEqualInnerLines = anotherRoof.filter((roof) => roof.y1 === roof.y2 && isInnerLine(prevRoof, currentRoof, nextRoof, roof)) //y가 같은 내부선 - let ridgeBaseLength = currentRoof.length / 2, // 지붕의 기반 길이 + let ridgeBaseLength = Math.round((currentRoof.length / 2) * 10) / 10, // 지붕의 기반 길이 ridgeMaxLength = Math.min(prevRoof.length, nextRoof.length), // 지붕의 최대 길이. 이전, 다음 벽 중 짧은 길이 - ridgeAcrossLength = Math.max(prevRoof.length, nextRoof.length) - currentRoof.length // 맞은편 벽까지의 길이 - 지붕의 기반 길이 + ridgeAcrossLength = Math.round((ridgeMaxLength - currentRoof.length) * 10) / 10 // 맞은편 벽까지의 길이 - 지붕의 기반 길이 let acrossRoof = anotherRoof .filter((roof) => { @@ -1339,12 +1340,12 @@ const drawRidge = (roof, canvas) => { if (acrossRoof !== undefined) { if (currentRoof.x1 === currentRoof.x2) { if (ridgeAcrossLength < Math.abs(currentRoof.x1 - acrossRoof.x1)) { - ridgeAcrossLength = Math.abs(currentRoof.x1 - acrossRoof.x1) - currentRoof.length + ridgeAcrossLength = Math.round((Math.round(Math.abs(currentRoof.x1 - acrossRoof.x1) * 10) / 10 - currentRoof.length) * 10) / 10 } } if (currentRoof.y1 === currentRoof.y2) { if (ridgeAcrossLength < Math.abs(currentRoof.y1 - acrossRoof.y1)) { - ridgeAcrossLength = Math.abs(currentRoof.y1 - acrossRoof.y1) - currentRoof.length + ridgeAcrossLength = Math.round((Math.round(Math.abs(currentRoof.y1 - acrossRoof.y1) * 10) / 10 - currentRoof.length) * 10) / 10 } } } @@ -1404,7 +1405,7 @@ const drawRidge = (roof, canvas) => { Math.abs(currentRoof.y1 - yEqualInnerLines[0].y1) <= Math.abs(currentRoof.y1 - nextRoof.y1) && Math.abs(currentRoof.x1 - yEqualInnerLines[0].x2) >= Math.abs(currentRoof.x1 - nextRoof.x2) ) { - ridgeMaxLength = Math.abs(currentRoof.x1 - yEqualInnerLines[0].x2) + ridgeMaxLength = Math.round(Math.abs(currentRoof.x1 - yEqualInnerLines[0].x2) * 10) / 10 } ridgeLength = Math.min(ridgeMaxLength, ridgeAcrossLength) startXPoint = currentRoof.x1 + (nextRoof.direction === 'right' ? 1 : -1) * Math.abs(currentRoof.y1 - startYPoint) @@ -1465,7 +1466,7 @@ const drawRidge = (roof, canvas) => { Math.abs(currentRoof.x1 - xEqualInnerLines[0].x1) <= Math.abs(currentRoof.x1 - nextRoof.x1) && Math.abs(currentRoof.y1 - xEqualInnerLines[0].y2) >= Math.abs(currentRoof.y1 - nextRoof.y2) ) { - ridgeMaxLength = Math.abs(currentRoof.y1 - xEqualInnerLines[0].y2) + ridgeMaxLength = Math.round(Math.abs(currentRoof.y1 - xEqualInnerLines[0].y2) * 10) / 10 } ridgeLength = Math.min(ridgeMaxLength, ridgeAcrossLength) startYPoint = currentRoof.y1 + (nextRoof.direction === 'bottom' ? 1 : -1) * Math.abs(currentRoof.x1 - startXPoint) @@ -1476,6 +1477,10 @@ const drawRidge = (roof, canvas) => { // 마루 그리기 if (startXPoint !== undefined && startYPoint !== undefined && endXPoint !== undefined && endYPoint !== undefined) { + startXPoint = Math.round(startXPoint * 10) / 10 + startYPoint = Math.round(startYPoint * 10) / 10 + endXPoint = Math.round(endXPoint * 10) / 10 + endYPoint = Math.round(endYPoint * 10) / 10 const ridge = new QLine( [Math.min(startXPoint, endXPoint), Math.min(startYPoint, endYPoint), Math.max(startXPoint, endXPoint), Math.max(startYPoint, endYPoint)], { @@ -1659,15 +1664,15 @@ const drawHips = (roof, canvas) => { let ridgePoints = [] ridgeLines.forEach((ridge) => { - const deltaX1 = ridge.x1 - currentRoof.x1 - const deltaY1 = ridge.y1 - currentRoof.y1 - const deltaX2 = ridge.x2 - currentRoof.x1 - const deltaY2 = ridge.y2 - currentRoof.y1 + const deltaX1 = Math.round((ridge.x1 - currentRoof.x1) * 10) / 10 + const deltaY1 = Math.round((ridge.y1 - currentRoof.y1) * 10) / 10 + const deltaX2 = Math.round((ridge.x2 - currentRoof.x1) * 10) / 10 + const deltaY2 = Math.round((ridge.y2 - currentRoof.y1) * 10) / 10 - if (Math.abs(deltaY1 / deltaX1) === 1) { + if (Math.round(Math.abs(deltaY1 / deltaX1) * 10) / 10 === 1) { ridgePoints.push({ x: ridge.x1, y: ridge.y1 }) } - if (Math.abs(deltaY2 / deltaX2) === 1) { + if (Math.round(Math.abs(deltaY2 / deltaX2) * 10) / 10 === 1) { ridgePoints.push({ x: ridge.x2, y: ridge.y2 }) } }) @@ -2207,8 +2212,15 @@ const changeEavesRoof = (currentRoof, canvas) => { object.x1 !== undefined && object.x2 !== undefined, ) + innerLines - .filter((line) => line.name !== LINE_TYPE.SUBLINE.RIDGE && line.name !== LINE_TYPE.SUBLINE.HIP && line.name !== LINE_TYPE.SUBLINE.VALLEY) + .filter( + (line) => + line.name !== LINE_TYPE.SUBLINE.RIDGE && + line.name !== LINE_TYPE.SUBLINE.HIP && + line.name !== LINE_TYPE.SUBLINE.VALLEY && + line.name !== OUTER_LINE_TYPE.OUTER_LINE, + ) .forEach((line) => { roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) canvas?.remove(line) @@ -2375,7 +2387,13 @@ const changeGableRoof = (currentRoof, canvas) => { }) innerLines - .filter((line) => line.name !== LINE_TYPE.SUBLINE.RIDGE && line.name !== LINE_TYPE.SUBLINE.HIP && line.name !== LINE_TYPE.SUBLINE.VALLEY) + .filter( + (line) => + line.name !== LINE_TYPE.SUBLINE.RIDGE && + line.name !== LINE_TYPE.SUBLINE.HIP && + line.name !== LINE_TYPE.SUBLINE.VALLEY && + line.name !== OUTER_LINE_TYPE.OUTER_LINE, + ) .forEach((line) => { roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) canvas?.remove(line) @@ -2544,7 +2562,13 @@ const changeHipAndGableRoof = (currentRoof, canvas) => { ) innerLines - .filter((line) => line.name !== LINE_TYPE.SUBLINE.RIDGE && line.name !== LINE_TYPE.SUBLINE.HIP && line.name !== LINE_TYPE.SUBLINE.VALLEY) + .filter( + (line) => + line.name !== LINE_TYPE.SUBLINE.RIDGE && + line.name !== LINE_TYPE.SUBLINE.HIP && + line.name !== LINE_TYPE.SUBLINE.VALLEY && + line.name !== OUTER_LINE_TYPE.OUTER_LINE, + ) .forEach((line) => { roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) canvas?.remove(line) @@ -2743,7 +2767,13 @@ const changeJerkInHeadRoof = (currentRoof, canvas) => { ) innerLines - .filter((line) => line.name !== LINE_TYPE.SUBLINE.RIDGE && line.name !== LINE_TYPE.SUBLINE.HIP && line.name !== LINE_TYPE.SUBLINE.VALLEY) + .filter( + (line) => + line.name !== LINE_TYPE.SUBLINE.RIDGE && + line.name !== LINE_TYPE.SUBLINE.HIP && + line.name !== LINE_TYPE.SUBLINE.VALLEY && + line.name !== OUTER_LINE_TYPE.OUTER_LINE, + ) .forEach((line) => { roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) canvas?.remove(line) @@ -2992,7 +3022,13 @@ const changeWallRoof = (currentRoof, canvas) => { ) innerLines - .filter((line) => line.name !== LINE_TYPE.SUBLINE.RIDGE && line.name !== LINE_TYPE.SUBLINE.HIP && line.name !== LINE_TYPE.SUBLINE.VALLEY) + .filter( + (line) => + line.name !== LINE_TYPE.SUBLINE.RIDGE && + line.name !== LINE_TYPE.SUBLINE.HIP && + line.name !== LINE_TYPE.SUBLINE.VALLEY && + line.name !== OUTER_LINE_TYPE.OUTER_LINE, + ) .forEach((line) => { roof.innerLines = roof.innerLines.filter((l) => l.id !== line.id) canvas?.remove(line) @@ -3163,7 +3199,7 @@ export const changeCurrentRoof = (currentRoof, canvas) => { canvas?.remove(originRoof) - innerLines.forEach((line) => canvas?.remove(line)) + innerLines.filter((line) => line.name !== OUTER_LINE_TYPE.OUTER_LINE).forEach((line) => canvas?.remove(line)) const polygon = createPolygon(wall.points) const originPolygon = new QPolygon(wall.points, { fontSize: 0 }) diff --git a/yarn.lock b/yarn.lock index f2bcf8b4..a167fa9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -223,14 +223,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/runtime@^7.20.13": - version "7.25.0" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz" - integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.24.8": +"@babel/runtime@^7.20.13", "@babel/runtime@^7.24.8": version "7.25.0" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz" integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== @@ -534,6 +527,21 @@ resolved "https://registry.npmjs.org/@js-joda/core/-/core-5.6.3.tgz" integrity sha512-T1rRxzdqkEXcou0ZprN1q9yDRlvzCPLqmlNt5IIsGBzoEVgLCCYrKEwc84+TvsXuAc95VAZwtWD2zVsKPY4bcA== +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" + integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + "@next/env@14.2.3": version "14.2.3" resolved "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz" @@ -1238,7 +1246,7 @@ "@react-types/shared" "3.23.1" clsx "^1.2.1" -"@nextui-org/system@>=2.0.0", "@nextui-org/system@>=2.1.0", "@nextui-org/system@2.2.5": +"@nextui-org/system@2.2.5": version "2.2.5" resolved "https://registry.npmjs.org/@nextui-org/system/-/system-2.2.5.tgz" integrity sha512-nrX6768aiyWtpxX3OTFBIVWR+v9nlMsC3KaBinNfek97sNm7gAfTHi7q5kylE3L5yIMpNG+DclAKpuxgDQEmvw== @@ -1291,7 +1299,7 @@ "@react-types/tabs" "3.3.7" scroll-into-view-if-needed "3.0.10" -"@nextui-org/theme@>=2.1.0", "@nextui-org/theme@>=2.2.0", "@nextui-org/theme@2.2.9": +"@nextui-org/theme@2.2.9": version "2.2.9" resolved "https://registry.npmjs.org/@nextui-org/theme/-/theme-2.2.9.tgz" integrity sha512-TN2I9sMriLaj00pXsIMlg19+UHeOdjzS2JV0u4gjL14mSbQl5BYNxgbvU3gbMqkZZQ6OpwT4RnT8RS+ks6TXCw== @@ -1512,7 +1520,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1645,7 +1653,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/focus@^3.17.1", "@react-aria/focus@3.17.1": +"@react-aria/focus@3.17.1", "@react-aria/focus@^3.17.1": version "3.17.1" resolved "https://registry.npmjs.org/@react-aria/focus/-/focus-3.17.1.tgz" integrity sha512-FLTySoSNqX++u0nWZJPPN5etXY0WBxaIe/YuL/GTEeuqUIuC/2bJSaw5hlsM6T2yjy6Y/VAxBcKSdAFUlU6njQ== @@ -1667,7 +1675,7 @@ "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/form@^3.0.5", "@react-aria/form@3.0.5": +"@react-aria/form@3.0.5", "@react-aria/form@^3.0.5": version "3.0.5" resolved "https://registry.npmjs.org/@react-aria/form/-/form-3.0.5.tgz" integrity sha512-n290jRwrrRXO3fS82MyWR+OKN7yznVesy5Q10IclSTVYHHI3VI53xtAPr/WzNjJR1um8aLhOcDNFKwnNIUUCsQ== @@ -1697,7 +1705,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-aria/i18n@^3.11.1", "@react-aria/i18n@3.11.1": +"@react-aria/i18n@3.11.1", "@react-aria/i18n@^3.11.1": version "3.11.1" resolved "https://registry.npmjs.org/@react-aria/i18n/-/i18n-3.11.1.tgz" integrity sha512-vuiBHw1kZruNMYeKkTGGnmPyMnM5T+gT8bz97H1FqIq1hQ6OPzmtBZ6W6l6OIMjeHI5oJo4utTwfZl495GALFQ== @@ -1725,7 +1733,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-aria/interactions@^3.21.3", "@react-aria/interactions@3.21.3": +"@react-aria/interactions@3.21.3", "@react-aria/interactions@^3.21.3": version "3.21.3" resolved "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.21.3.tgz" integrity sha512-BWIuf4qCs5FreDJ9AguawLVS0lV9UU+sK4CCnbCNNmYqOWY+1+gRXCsnOM32K+oMESBxilAjdHW5n1hsMqYMpA== @@ -1745,7 +1753,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-aria/label@^3.7.8", "@react-aria/label@3.7.8": +"@react-aria/label@3.7.8", "@react-aria/label@^3.7.8": version "3.7.8" resolved "https://registry.npmjs.org/@react-aria/label/-/label-3.7.8.tgz" integrity sha512-MzgTm5+suPA3KX7Ug6ZBK2NX9cin/RFLsv1BdafJ6CZpmUSpWnGE/yQfYUB7csN7j31OsZrD3/P56eShYWAQfg== @@ -1754,7 +1762,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/link@^3.7.1", "@react-aria/link@3.7.1": +"@react-aria/link@3.7.1", "@react-aria/link@^3.7.1": version "3.7.1" resolved "https://registry.npmjs.org/@react-aria/link/-/link-3.7.1.tgz" integrity sha512-a4IaV50P3fXc7DQvEIPYkJJv26JknFbRzFT5MJOMgtzuhyJoQdILEUK6XHYjcSSNCA7uLgzpojArVk5Hz3lCpw== @@ -1766,7 +1774,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/listbox@^3.12.1", "@react-aria/listbox@3.12.1": +"@react-aria/listbox@3.12.1", "@react-aria/listbox@^3.12.1": version "3.12.1" resolved "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.12.1.tgz" integrity sha512-7JiUp0NGykbv/HgSpmTY1wqhuf/RmjFxs1HZcNaTv8A+DlzgJYc7yQqFjP3ZA/z5RvJFuuIxggIYmgIFjaRYdA== @@ -1788,7 +1796,7 @@ dependencies: "@swc/helpers" "^0.5.0" -"@react-aria/menu@^3.14.1", "@react-aria/menu@3.14.1": +"@react-aria/menu@3.14.1", "@react-aria/menu@^3.14.1": version "3.14.1" resolved "https://registry.npmjs.org/@react-aria/menu/-/menu-3.14.1.tgz" integrity sha512-BYliRb38uAzq05UOFcD5XkjA5foQoXRbcH3ZufBsc4kvh79BcP1PMW6KsXKGJ7dC/PJWUwCui6QL1kUg8PqMHA== @@ -1807,7 +1815,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/overlays@^3.22.1", "@react-aria/overlays@3.22.1": +"@react-aria/overlays@3.22.1", "@react-aria/overlays@^3.22.1": version "3.22.1" resolved "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.22.1.tgz" integrity sha512-GHiFMWO4EQ6+j6b5QCnNoOYiyx1Gk8ZiwLzzglCI4q1NY5AG2EAmfU4Z1+Gtrf2S5Y0zHbumC7rs9GnPoGLUYg== @@ -1852,7 +1860,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-aria/selection@^3.18.1", "@react-aria/selection@3.18.1": +"@react-aria/selection@3.18.1", "@react-aria/selection@^3.18.1": version "3.18.1" resolved "https://registry.npmjs.org/@react-aria/selection/-/selection-3.18.1.tgz" integrity sha512-GSqN2jX6lh7v+ldqhVjAXDcrWS3N4IsKXxO6L6Ygsye86Q9q9Mq9twWDWWu5IjHD6LoVZLUBCMO+ENGbOkyqeQ== @@ -1905,7 +1913,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-aria/ssr@^3.9.4", "@react-aria/ssr@3.9.4": +"@react-aria/ssr@3.9.4", "@react-aria/ssr@^3.9.4": version "3.9.4" resolved "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.4.tgz" integrity sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ== @@ -1965,7 +1973,7 @@ "@react-types/tabs" "^3.3.7" "@swc/helpers" "^0.5.0" -"@react-aria/textfield@^3.14.5", "@react-aria/textfield@3.14.5": +"@react-aria/textfield@3.14.5", "@react-aria/textfield@^3.14.5": version "3.14.5" resolved "https://registry.npmjs.org/@react-aria/textfield/-/textfield-3.14.5.tgz" integrity sha512-hj7H+66BjB1iTKKaFXwSZBZg88YT+wZboEXZ0DNdQB2ytzoz/g045wBItUuNi4ZjXI3P+0AOZznVMYadWBAmiA== @@ -2006,7 +2014,7 @@ "@react-types/tooltip" "^3.4.9" "@swc/helpers" "^0.5.0" -"@react-aria/utils@^3.24.1", "@react-aria/utils@3.24.1": +"@react-aria/utils@3.24.1", "@react-aria/utils@^3.24.1": version "3.24.1" resolved "https://registry.npmjs.org/@react-aria/utils/-/utils-3.24.1.tgz" integrity sha512-O3s9qhPMd6n42x9sKeJ3lhu5V1Tlnzhu6Yk8QOvDuXf7UGuUjXf9mzfHJt1dYzID4l9Fwm8toczBzPM9t0jc8Q== @@ -2028,7 +2036,7 @@ "@swc/helpers" "^0.5.0" clsx "^2.0.0" -"@react-aria/visually-hidden@^3.8.12", "@react-aria/visually-hidden@3.8.12": +"@react-aria/visually-hidden@3.8.12", "@react-aria/visually-hidden@^3.8.12": version "3.8.12" resolved "https://registry.npmjs.org/@react-aria/visually-hidden/-/visually-hidden-3.8.12.tgz" integrity sha512-Bawm+2Cmw3Xrlr7ARzl2RLtKh0lNUdJ0eNqzWcyx4c0VHUAWtThmH5l+HRqFUGzzutFZVo89SAy40BAbd0gjVw== @@ -2038,7 +2046,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/calendar@^3.5.1", "@react-stately/calendar@3.5.1": +"@react-stately/calendar@3.5.1", "@react-stately/calendar@^3.5.1": version "3.5.1" resolved "https://registry.npmjs.org/@react-stately/calendar/-/calendar-3.5.1.tgz" integrity sha512-7l7QhqGUJ5AzWHfvZzbTe3J4t72Ht5BmhW4hlVI7flQXtfrmYkVtl3ZdytEZkkHmWGYZRW9b4IQTQGZxhtlElA== @@ -2049,7 +2057,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/checkbox@^3.6.5", "@react-stately/checkbox@3.6.5": +"@react-stately/checkbox@3.6.5", "@react-stately/checkbox@^3.6.5": version "3.6.5" resolved "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.6.5.tgz" integrity sha512-IXV3f9k+LtmfQLE+DKIN41Q5QB/YBLDCB1YVx5PEdRp52S9+EACD5683rjVm8NVRDwjMi2SP6RnFRk7fVb5Azg== @@ -2060,7 +2068,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/collections@^3.10.7", "@react-stately/collections@3.10.7": +"@react-stately/collections@3.10.7", "@react-stately/collections@^3.10.7": version "3.10.7" resolved "https://registry.npmjs.org/@react-stately/collections/-/collections-3.10.7.tgz" integrity sha512-KRo5O2MWVL8n3aiqb+XR3vP6akmHLhLWYZEmPKjIv0ghQaEebBTrN3wiEjtd6dzllv0QqcWvDLM1LntNfJ2TsA== @@ -2076,7 +2084,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-stately/combobox@^3.8.4", "@react-stately/combobox@3.8.4": +"@react-stately/combobox@3.8.4", "@react-stately/combobox@^3.8.4": version "3.8.4" resolved "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.8.4.tgz" integrity sha512-iLVGvKRRz0TeJXZhZyK783hveHpYA6xovOSdzSD+WGYpiPXo1QrcrNoH3AE0Z2sHtorU+8nc0j58vh5PB+m2AA== @@ -2091,7 +2099,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/datepicker@^3.9.4", "@react-stately/datepicker@3.9.4": +"@react-stately/datepicker@3.9.4", "@react-stately/datepicker@^3.9.4": version "3.9.4" resolved "https://registry.npmjs.org/@react-stately/datepicker/-/datepicker-3.9.4.tgz" integrity sha512-yBdX01jn6gq4NIVvHIqdjBUPo+WN8Bujc4OnPw+ZnfA4jI0eIgq04pfZ84cp1LVXW0IB0VaCu1AlQ/kvtZjfGA== @@ -2112,7 +2120,7 @@ dependencies: "@swc/helpers" "^0.5.0" -"@react-stately/form@^3.0.3", "@react-stately/form@3.0.3": +"@react-stately/form@3.0.3", "@react-stately/form@^3.0.3": version "3.0.3" resolved "https://registry.npmjs.org/@react-stately/form/-/form-3.0.3.tgz" integrity sha512-92YYBvlHEWUGUpXgIaQ48J50jU9XrxfjYIN8BTvvhBHdD63oWgm8DzQnyT/NIAMzdLnhkg7vP+fjG8LjHeyIAg== @@ -2139,7 +2147,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-stately/list@^3.10.5", "@react-stately/list@3.10.5": +"@react-stately/list@3.10.5", "@react-stately/list@^3.10.5": version "3.10.5" resolved "https://registry.npmjs.org/@react-stately/list/-/list-3.10.5.tgz" integrity sha512-fV9plO+6QDHiewsYIhboxcDhF17GO95xepC5ki0bKXo44gr14g/LSo/BMmsaMnV+1BuGdBunB05bO4QOIaigXA== @@ -2161,7 +2169,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-stately/menu@^3.7.1", "@react-stately/menu@3.7.1": +"@react-stately/menu@3.7.1", "@react-stately/menu@^3.7.1": version "3.7.1" resolved "https://registry.npmjs.org/@react-stately/menu/-/menu-3.7.1.tgz" integrity sha512-mX1w9HHzt+xal1WIT2xGrTQsoLvDwuB2R1Er1MBABs//MsJzccycatcgV/J/28m6tO5M9iuFQQvLV+i1dCtodg== @@ -2171,7 +2179,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/overlays@^3.6.7", "@react-stately/overlays@3.6.7": +"@react-stately/overlays@3.6.7", "@react-stately/overlays@^3.6.7": version "3.6.7" resolved "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.6.7.tgz" integrity sha512-6zp8v/iNUm6YQap0loaFx6PlvN8C0DgWHNlrlzMtMmNuvjhjR0wYXVaTfNoUZBWj25tlDM81ukXOjpRXg9rLrw== @@ -2189,7 +2197,7 @@ "@react-types/overlays" "^3.8.9" "@swc/helpers" "^0.5.0" -"@react-stately/radio@^3.10.4", "@react-stately/radio@3.10.4": +"@react-stately/radio@3.10.4", "@react-stately/radio@^3.10.4": version "3.10.4" resolved "https://registry.npmjs.org/@react-stately/radio/-/radio-3.10.4.tgz" integrity sha512-kCIc7tAl4L7Hu4Wt9l2jaa+MzYmAJm0qmC8G8yPMbExpWbLRu6J8Un80GZu+JxvzgDlqDyrVvyv9zFifwH/NkQ== @@ -2222,7 +2230,7 @@ "@react-types/shared" "^3.24.1" "@swc/helpers" "^0.5.0" -"@react-stately/slider@^3.5.4", "@react-stately/slider@3.5.4": +"@react-stately/slider@3.5.4", "@react-stately/slider@^3.5.4": version "3.5.4" resolved "https://registry.npmjs.org/@react-stately/slider/-/slider-3.5.4.tgz" integrity sha512-Jsf7K17dr93lkNKL9ij8HUcoM1sPbq8TvmibD6DhrK9If2lje+OOL8y4n4qreUnfMT56HCAeS9wCO3fg3eMyrw== @@ -2232,7 +2240,7 @@ "@react-types/slider" "^3.7.3" "@swc/helpers" "^0.5.0" -"@react-stately/table@^3.11.8", "@react-stately/table@3.11.8": +"@react-stately/table@3.11.8", "@react-stately/table@^3.11.8": version "3.11.8" resolved "https://registry.npmjs.org/@react-stately/table/-/table-3.11.8.tgz" integrity sha512-EdyRW3lT1/kAVDp5FkEIi1BQ7tvmD2YgniGdLuW/l9LADo0T+oxZqruv60qpUS6sQap+59Riaxl91ClDxrJnpg== @@ -2247,7 +2255,7 @@ "@react-types/table" "^3.9.5" "@swc/helpers" "^0.5.0" -"@react-stately/tabs@^3.6.6", "@react-stately/tabs@3.6.6": +"@react-stately/tabs@3.6.6", "@react-stately/tabs@^3.6.6": version "3.6.6" resolved "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.6.6.tgz" integrity sha512-sOLxorH2uqjAA+v1ppkMCc2YyjgqvSGeBDgtR/lyPSDd4CVMoTExszROX2dqG0c8il9RQvzFuufUtQWMY6PgSA== @@ -2257,7 +2265,7 @@ "@react-types/tabs" "^3.3.7" "@swc/helpers" "^0.5.0" -"@react-stately/toggle@^3.7.4", "@react-stately/toggle@3.7.4": +"@react-stately/toggle@3.7.4", "@react-stately/toggle@^3.7.4": version "3.7.4" resolved "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.7.4.tgz" integrity sha512-CoYFe9WrhLkDP4HGDpJYQKwfiYCRBAeoBQHv+JWl5eyK61S8xSwoHsveYuEZ3bowx71zyCnNAqWRrmNOxJ4CKA== @@ -2275,7 +2283,7 @@ "@react-types/checkbox" "^3.8.3" "@swc/helpers" "^0.5.0" -"@react-stately/tooltip@^3.4.9", "@react-stately/tooltip@3.4.9": +"@react-stately/tooltip@3.4.9", "@react-stately/tooltip@^3.4.9": version "3.4.9" resolved "https://registry.npmjs.org/@react-stately/tooltip/-/tooltip-3.4.9.tgz" integrity sha512-P7CDJsdoKarz32qFwf3VNS01lyC+63gXpDZG31pUu+EO5BeQd4WKN/AH1Beuswpr4GWzxzFc1aXQgERFGVzraA== @@ -2284,7 +2292,7 @@ "@react-types/tooltip" "^3.4.9" "@swc/helpers" "^0.5.0" -"@react-stately/tree@^3.8.1", "@react-stately/tree@3.8.1": +"@react-stately/tree@3.8.1", "@react-stately/tree@^3.8.1": version "3.8.1" resolved "https://registry.npmjs.org/@react-stately/tree/-/tree-3.8.1.tgz" integrity sha512-LOdkkruJWch3W89h4B/bXhfr0t0t1aRfEp+IMrrwdRAl23NaPqwl5ILHs4Xu5XDHqqhg8co73pHrJwUyiTWEjw== @@ -2295,7 +2303,7 @@ "@react-types/shared" "^3.23.1" "@swc/helpers" "^0.5.0" -"@react-stately/utils@^3.10.1", "@react-stately/utils@3.10.1": +"@react-stately/utils@3.10.1", "@react-stately/utils@^3.10.1": version "3.10.1" resolved "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.1.tgz" integrity sha512-VS/EHRyicef25zDZcM/ClpzYMC5i2YGN6uegOeQawmgfGjb02yaCX0F0zR69Pod9m2Hr3wunTbtpgVXvYbZItg== @@ -2309,7 +2317,7 @@ dependencies: "@swc/helpers" "^0.5.0" -"@react-stately/virtualizer@^3.7.1", "@react-stately/virtualizer@3.7.1": +"@react-stately/virtualizer@3.7.1", "@react-stately/virtualizer@^3.7.1": version "3.7.1" resolved "https://registry.npmjs.org/@react-stately/virtualizer/-/virtualizer-3.7.1.tgz" integrity sha512-voHgE6EQ+oZaLv6u2umKxakvIKNkCQuUihqKACTjdslp7SJh4Mvs3oLBI0hf0JOh+rCcFIKDvQtFwy1fXFRYBA== @@ -2325,7 +2333,7 @@ dependencies: "@react-types/shared" "^3.23.1" -"@react-types/breadcrumbs@^3.7.5", "@react-types/breadcrumbs@3.7.5": +"@react-types/breadcrumbs@3.7.5", "@react-types/breadcrumbs@^3.7.5": version "3.7.5" resolved "https://registry.npmjs.org/@react-types/breadcrumbs/-/breadcrumbs-3.7.5.tgz" integrity sha512-lV9IDYsMiu2TgdMIjEmsOE0YWwjb3jhUNK1DCZZfq6uWuiHLgyx2EncazJBUWSjHJ4ta32j7xTuXch+8Ai6u/A== @@ -2333,7 +2341,7 @@ "@react-types/link" "^3.5.5" "@react-types/shared" "^3.23.1" -"@react-types/button@^3.9.4", "@react-types/button@3.9.4": +"@react-types/button@3.9.4", "@react-types/button@^3.9.4": version "3.9.4" resolved "https://registry.npmjs.org/@react-types/button/-/button-3.9.4.tgz" integrity sha512-raeQBJUxBp0axNF74TXB8/H50GY8Q3eV6cEKMbZFP1+Dzr09Ngv0tJBeW0ewAxAguNH5DRoMUAUGIXtSXskVdA== @@ -2347,7 +2355,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/calendar@^3.4.6", "@react-types/calendar@3.4.6": +"@react-types/calendar@3.4.6", "@react-types/calendar@^3.4.6": version "3.4.6" resolved "https://registry.npmjs.org/@react-types/calendar/-/calendar-3.4.6.tgz" integrity sha512-WSntZPwtvsIYWvBQRAPvuCn55UTJBZroTvX0vQvWykJRQnPAI20G1hMQ3dNsnAL+gLZUYxBXn66vphmjUuSYew== @@ -2355,7 +2363,7 @@ "@internationalized/date" "^3.5.4" "@react-types/shared" "^3.23.1" -"@react-types/checkbox@^3.8.1", "@react-types/checkbox@3.8.1": +"@react-types/checkbox@3.8.1", "@react-types/checkbox@^3.8.1": version "3.8.1" resolved "https://registry.npmjs.org/@react-types/checkbox/-/checkbox-3.8.1.tgz" integrity sha512-5/oVByPw4MbR/8QSdHCaalmyWC71H/QGgd4aduTJSaNi825o+v/hsN2/CH7Fq9atkLKsC8fvKD00Bj2VGaKriQ== @@ -2369,14 +2377,14 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/combobox@^3.11.1", "@react-types/combobox@3.11.1": +"@react-types/combobox@3.11.1", "@react-types/combobox@^3.11.1": version "3.11.1" resolved "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.11.1.tgz" integrity sha512-UNc3OHt5cUt5gCTHqhQIqhaWwKCpaNciD8R7eQazmHiA9fq8ROlV+7l3gdNgdhJbTf5Bu/V5ISnN7Y1xwL3zqQ== dependencies: "@react-types/shared" "^3.23.1" -"@react-types/datepicker@^3.7.4", "@react-types/datepicker@3.7.4": +"@react-types/datepicker@3.7.4", "@react-types/datepicker@^3.7.4": version "3.7.4" resolved "https://registry.npmjs.org/@react-types/datepicker/-/datepicker-3.7.4.tgz" integrity sha512-ZfvgscvNzBJpYyVWg3nstJtA/VlWLwErwSkd1ivZYam859N30w8yH+4qoYLa6FzWLCFlrsRHyvtxlEM7lUAt5A== @@ -2394,7 +2402,7 @@ "@react-types/overlays" "^3.8.9" "@react-types/shared" "^3.24.1" -"@react-types/grid@^3.2.6", "@react-types/grid@3.2.6": +"@react-types/grid@3.2.6", "@react-types/grid@^3.2.6": version "3.2.6" resolved "https://registry.npmjs.org/@react-types/grid/-/grid-3.2.6.tgz" integrity sha512-XfHenL2jEBUYrhKiPdeM24mbLRXUn79wVzzMhrNYh24nBwhsPPpxF+gjFddT3Cy8dt6tRInfT6pMEu9nsXwaHw== @@ -2408,7 +2416,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/link@^3.5.5", "@react-types/link@3.5.5": +"@react-types/link@3.5.5", "@react-types/link@^3.5.5": version "3.5.5" resolved "https://registry.npmjs.org/@react-types/link/-/link-3.5.5.tgz" integrity sha512-G6P5WagHDR87npN7sEuC5IIgL1GsoY4WFWKO4734i2CXRYx24G9P0Su3AX4GA3qpspz8sK1AWkaCzBMmvnunfw== @@ -2422,7 +2430,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/menu@^3.9.9", "@react-types/menu@3.9.9": +"@react-types/menu@3.9.9", "@react-types/menu@^3.9.9": version "3.9.9" resolved "https://registry.npmjs.org/@react-types/menu/-/menu-3.9.9.tgz" integrity sha512-FamUaPVs1Fxr4KOMI0YcR2rYZHoN7ypGtgiEiJ11v/tEPjPPGgeKDxii0McCrdOkjheatLN1yd2jmMwYj6hTDg== @@ -2430,7 +2438,7 @@ "@react-types/overlays" "^3.8.7" "@react-types/shared" "^3.23.1" -"@react-types/overlays@^3.8.7", "@react-types/overlays@3.8.7": +"@react-types/overlays@3.8.7", "@react-types/overlays@^3.8.7": version "3.8.7" resolved "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.8.7.tgz" integrity sha512-zCOYvI4at2DkhVpviIClJ7bRrLXYhSg3Z3v9xymuPH3mkiuuP/dm8mUCtkyY4UhVeUTHmrQh1bzaOP00A+SSQA== @@ -2444,20 +2452,27 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/progress@^3.5.4", "@react-types/progress@3.5.4": +"@react-types/progress@3.5.4", "@react-types/progress@^3.5.4": version "3.5.4" resolved "https://registry.npmjs.org/@react-types/progress/-/progress-3.5.4.tgz" integrity sha512-JNc246sTjasPyx5Dp7/s0rp3Bz4qlu4LrZTulZlxWyb53WgBNL7axc26CCi+I20rWL9+c7JjhrRxnLl/1cLN5g== dependencies: "@react-types/shared" "^3.23.1" -"@react-types/radio@^3.8.1", "@react-types/radio@3.8.1": +"@react-types/radio@3.8.1", "@react-types/radio@^3.8.1": version "3.8.1" resolved "https://registry.npmjs.org/@react-types/radio/-/radio-3.8.1.tgz" integrity sha512-bK0gio/qj1+0Ldu/3k/s9BaOZvnnRgvFtL3u5ky479+aLG5qf1CmYed3SKz8ErZ70JkpuCSrSwSCFf0t1IHovw== dependencies: "@react-types/shared" "^3.23.1" +"@react-types/select@3.9.4": + version "3.9.4" + resolved "https://registry.npmjs.org/@react-types/select/-/select-3.9.4.tgz" + integrity sha512-xI7dnOW2st91fPPcv6hdtrTdcfetYiqZuuVPZ5TRobY7Q10/Zqqe/KqtOw1zFKUj9xqNJe4Ov3xP5GSdcO60Eg== + dependencies: + "@react-types/shared" "^3.23.1" + "@react-types/select@^3.9.6": version "3.9.6" resolved "https://registry.npmjs.org/@react-types/select/-/select-3.9.6.tgz" @@ -2465,14 +2480,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/select@3.9.4": - version "3.9.4" - resolved "https://registry.npmjs.org/@react-types/select/-/select-3.9.4.tgz" - integrity sha512-xI7dnOW2st91fPPcv6hdtrTdcfetYiqZuuVPZ5TRobY7Q10/Zqqe/KqtOw1zFKUj9xqNJe4Ov3xP5GSdcO60Eg== - dependencies: - "@react-types/shared" "^3.23.1" - -"@react-types/shared@^3.23.1", "@react-types/shared@3.23.1": +"@react-types/shared@3.23.1", "@react-types/shared@^3.23.1": version "3.23.1" resolved "https://registry.npmjs.org/@react-types/shared/-/shared-3.23.1.tgz" integrity sha512-5d+3HbFDxGZjhbMBeFHRQhexMFt4pUce3okyRtUVKbbedQFUrtXSBg9VszgF2RTeQDKDkMCIQDtz5ccP/Lk1gw== @@ -2496,7 +2504,7 @@ dependencies: "@react-types/shared" "^3.24.1" -"@react-types/table@^3.9.5", "@react-types/table@3.9.5": +"@react-types/table@3.9.5", "@react-types/table@^3.9.5": version "3.9.5" resolved "https://registry.npmjs.org/@react-types/table/-/table-3.9.5.tgz" integrity sha512-fgM2j9F/UR4Anmd28CueghCgBwOZoCVyN8fjaIFPd2MN4gCwUUfANwxLav65gZk4BpwUXGoQdsW+X50L3555mg== @@ -2504,21 +2512,21 @@ "@react-types/grid" "^3.2.6" "@react-types/shared" "^3.23.1" -"@react-types/tabs@^3.3.7", "@react-types/tabs@3.3.7": +"@react-types/tabs@3.3.7", "@react-types/tabs@^3.3.7": version "3.3.7" resolved "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.3.7.tgz" integrity sha512-ZdLe5xOcFX6+/ni45Dl2jO0jFATpTnoSqj6kLIS/BYv8oh0n817OjJkLf+DS3CLfNjApJWrHqAk34xNh6nRnEg== dependencies: "@react-types/shared" "^3.23.1" -"@react-types/textfield@^3.9.3", "@react-types/textfield@3.9.3": +"@react-types/textfield@3.9.3", "@react-types/textfield@^3.9.3": version "3.9.3" resolved "https://registry.npmjs.org/@react-types/textfield/-/textfield-3.9.3.tgz" integrity sha512-DoAY6cYOL0pJhgNGI1Rosni7g72GAt4OVr2ltEx2S9ARmFZ0DBvdhA9lL2nywcnKMf27PEJcKMXzXc10qaHsJw== dependencies: "@react-types/shared" "^3.23.1" -"@react-types/tooltip@^3.4.9", "@react-types/tooltip@3.4.9": +"@react-types/tooltip@3.4.9", "@react-types/tooltip@^3.4.9": version "3.4.9" resolved "https://registry.npmjs.org/@react-types/tooltip/-/tooltip-3.4.9.tgz" integrity sha512-wZ+uF1+Zc43qG+cOJzioBmLUNjRa7ApdcT0LI1VvaYvH5GdfjzUJOorLX9V/vAci0XMJ50UZ+qsh79aUlw2yqg== @@ -2531,7 +2539,7 @@ resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz" integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== -"@swc/helpers@^0.5.0", "@swc/helpers@0.5.5": +"@swc/helpers@0.5.5", "@swc/helpers@^0.5.0": version "0.5.5" resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz" integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A== @@ -4037,7 +4045,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0": +"@types/react@*": version "18.3.11" resolved "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz" integrity sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ== @@ -4058,6 +4066,11 @@ abab@^2.0.5, abab@^2.0.6: resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" @@ -4108,13 +4121,6 @@ ag-grid-react@^32.0.2: ag-grid-community "32.1.0" prop-types "^15.8.1" -agent-base@^7.0.2, agent-base@^7.1.0: - version "7.1.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" - integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== - dependencies: - debug "^4.3.4" - agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -4122,6 +4128,13 @@ agent-base@6: dependencies: debug "4" +agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" @@ -4164,6 +4177,19 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + arg@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" @@ -4231,6 +4257,14 @@ body-scroll-lock@^3.1.5: resolved "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz" integrity sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg== +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + brace-expansion@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" @@ -4285,6 +4319,15 @@ caniuse-lite@^1.0.30001579: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz" integrity sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA== +canvas@^2.8.0: + version "2.11.2" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860" + integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + nan "^2.17.0" + simple-get "^3.0.3" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -4294,7 +4337,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0": +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: version "3.6.0" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -4309,22 +4352,22 @@ chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0": optionalDependencies: fsevents "~2.3.2" +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + classnames@^2.3.1: version "2.5.1" resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== -client-only@^0.0.1, client-only@0.0.1: +client-only@0.0.1, client-only@^0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== -clsx@^1.1.1: - version "1.2.1" - resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" - integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== - -clsx@^1.2.1: +clsx@^1.1.1, clsx@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== @@ -4348,16 +4391,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + color-string@^1.9.0: version "1.9.1" resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" @@ -4366,6 +4409,16 @@ color-string@^1.9.0: color-name "^1.0.0" simple-swizzle "^0.2.2" +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +color2k@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz" + integrity sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog== + color@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/color/-/color-4.2.3.tgz" @@ -4374,11 +4427,6 @@ color@^4.2.3: color-convert "^2.0.1" color-string "^1.9.0" -color2k@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz" - integrity sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog== - combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -4386,6 +4434,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@2: + version "2.20.3" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@^11.0.0: version "11.1.0" resolved "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz" @@ -4396,11 +4449,6 @@ commander@^4.0.0: resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== -commander@2: - version "2.20.3" - resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - complex.js@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz" @@ -4411,6 +4459,11 @@ compute-scroll-into-view@^3.0.2: resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz" integrity sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg== +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + concaveman@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/concaveman/-/concaveman-1.2.1.tgz" @@ -4421,6 +4474,11 @@ concaveman@^1.2.1: robust-predicates "^2.0.4" tinyqueue "^2.0.3" +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + convert-source-map@^1.5.0: version "1.9.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" @@ -4521,6 +4579,13 @@ dayjs@^1.11.13: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== +debug@4, debug@^4.3.3, debug@^4.3.4: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + debug@^4.3.1: version "4.3.7" resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz" @@ -4528,18 +4593,18 @@ debug@^4.3.1: dependencies: ms "^2.1.3" -debug@^4.3.3, debug@^4.3.4, debug@4: - version "4.3.5" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - decimal.js@^10.3.1, decimal.js@^10.4.3: version "10.4.3" resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== +decompress-response@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" + integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== + dependencies: + mimic-response "^2.0.0" + deepmerge@4.3.1: version "4.3.1" resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" @@ -4555,6 +4620,16 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +detect-libc@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + detect-node-es@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz" @@ -4745,13 +4820,25 @@ fraction.js@^4.3.7: resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz" integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== -framer-motion@^11.2.13, framer-motion@>=10.17.0: +framer-motion@^11.2.13: version "11.3.21" resolved "https://registry.npmjs.org/framer-motion/-/framer-motion-11.3.21.tgz" integrity sha512-D+hfIsvzV8eL/iycld4K+tKlg2Q2LdwnrcBEohtGw3cG1AIuNYATbT5RUqIM1ndsAk+EfGhoSGf0UaiFodc5Tw== dependencies: tslib "^2.4.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + fs@^0.0.1-security: version "0.0.1-security" resolved "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz" @@ -4767,6 +4854,21 @@ function-bind@^1.1.2: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + geojson-equality-ts@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/geojson-equality-ts/-/geojson-equality-ts-1.0.2.tgz" @@ -4811,6 +4913,18 @@ glob@^10.3.10: minipass "^7.1.2" path-scurry "^1.11.1" +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" @@ -4831,6 +4945,11 @@ has-flag@^3.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + hasown@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" @@ -4885,7 +5004,7 @@ https-proxy-agent@^7.0.0: agent-base "^7.0.2" debug "4" -iconv-lite@^0.6.3, iconv-lite@0.6.3: +iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -4910,9 +5029,17 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" -inherits@^2.0.4: +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== international-types@^0.8.1: @@ -5243,6 +5370,13 @@ lru-cache@^10.2.0: resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz" integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + marchingsquares@^1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/marchingsquares/-/marchingsquares-1.3.3.tgz" @@ -5293,6 +5427,18 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" +mimic-response@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" + integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimatch@^9.0.4: version "9.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" @@ -5300,17 +5446,37 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== -minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" -ms@^2.1.1, ms@2.1.2: +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -5341,6 +5507,11 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" +nan@^2.17.0: + version "2.22.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3" + integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw== + nanoid@^3.3.6, nanoid@^3.3.7: version "3.3.7" resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" @@ -5383,11 +5554,35 @@ next@14.2.3: "@next/swc-win32-ia32-msvc" "14.2.3" "@next/swc-win32-x64-msvc" "14.2.3" +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + nwsapi@^2.2.0: version "2.2.10" resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz" @@ -5403,6 +5598,13 @@ object-hash@^3.0.0: resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== +once@^1.3.0, once@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + open@^8.0.0: version "8.4.2" resolved "https://registry.npmjs.org/open/-/open-8.4.2.tgz" @@ -5434,6 +5636,11 @@ parse5@6.0.1: resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" @@ -5539,15 +5746,6 @@ postcss-value-parser@^4.0.0: resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8, postcss@^8.0.0, postcss@^8.2.14, postcss@^8.4.21, postcss@^8.4.23, postcss@>=8.0.9: - version "8.4.38" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz" - integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.2.0" - postcss@8.4.31: version "8.4.31" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" @@ -5557,6 +5755,15 @@ postcss@8.4.31: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^8, postcss@^8.4.23: + version "8.4.38" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz" + integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.2.0" + prettier@^3.3.3: version "3.3.3" resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz" @@ -5646,7 +5853,7 @@ react-datepicker@^7.3.0: prop-types "^15.7.2" react-onclickoutside "^6.13.0" -"react-dom@^15.5.x || ^16.x || ^17.x || ^18.x", "react-dom@^16.3.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17 || ^18", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", "react-dom@^16.9.0 || ^17 || ^18", react-dom@^18, react-dom@^18.0.0, react-dom@^18.2.0, "react-dom@>= 16.3.0", react-dom@>=16.6.0, react-dom@>=16.8.0, react-dom@>=18: +react-dom@^18: version "18.3.1" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== @@ -5758,7 +5965,7 @@ react-transition-group@^4.3.0: loose-envify "^1.4.0" prop-types "^15.6.2" -react@*, "react@^15.5.x || ^16.x || ^17.x || ^18.x", "react@^16.3.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17 || ^18", "react@^16.8.0 || ^17 || ^18", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0", "react@^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", "react@^16.9.0 || ^17 || ^18", react@^18, react@^18.0.0, react@^18.2.0, react@^18.3.1, "react@>= 16.3.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=16.13.1, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18: +react@^18: version "18.3.1" resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== @@ -5772,6 +5979,15 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@^4.2.0: version "4.5.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz" @@ -5831,6 +6047,13 @@ rfdc@^1.3.0: resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz" integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + robust-predicates@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz" @@ -5863,7 +6086,7 @@ safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass@^1.3.0, sass@^1.77.8: +sass@^1.77.8: version "1.77.8" resolved "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz" integrity sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ== @@ -5898,6 +6121,16 @@ seedrandom@^3.0.5: resolved "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz" integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== +semver@^6.0.0: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.5: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + semver@^7.5.4: version "7.6.2" resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" @@ -5908,6 +6141,11 @@ server-only@^0.0.1: resolved "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz" integrity sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA== +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -5920,11 +6158,30 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +signal-exit@^3.0.0: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55" + integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA== + dependencies: + decompress-response "^4.2.0" + once "^1.3.1" + simple-concat "^1.0.0" + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" @@ -5937,7 +6194,7 @@ skmeans@0.9.7: resolved "https://registry.npmjs.org/skmeans/-/skmeans-0.9.7.tgz" integrity sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg== -source-map-js@^1.0.2, source-map-js@^1.2.0, "source-map-js@>=0.6.2 <2.0.0": +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== @@ -5972,13 +6229,6 @@ streamsearch@^1.1.0: resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string_decoder@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -5988,16 +6238,16 @@ string_decoder@^1.3.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.1.0: +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.1: +string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -6006,14 +6256,12 @@ string-width@^5.0.1: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== +string_decoder@^1.1.1, string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" + safe-buffer "~5.2.0" "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" @@ -6085,7 +6333,7 @@ sweetalert2-react-content@^5.0.7: resolved "https://registry.npmjs.org/sweetalert2-react-content/-/sweetalert2-react-content-5.0.7.tgz" integrity sha512-8Fk82Mpk45lFXpJWKIFF/lq8k/dJKDDQGFcuqVosaL/qRdViyAs5+u37LoTGfnOIvf+rfQB3PAXcp1XLLn+0ew== -sweetalert2@^11.0.0, sweetalert2@^11.14.1: +sweetalert2@^11.14.1: version "11.14.1" resolved "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.14.1.tgz" integrity sha512-xadhfcA4STGMh8nC5zHFFWURhRpWc4zyI3GdMDFH/m3hGWZeQQNWhX9xcG4lI9gZYsi/IlazKbwvvje3juL3Xg== @@ -6112,7 +6360,7 @@ tailwind-variants@^0.1.20: dependencies: tailwind-merge "^1.14.0" -tailwindcss@*, tailwindcss@^3.4.1, tailwindcss@>=3.4.0: +tailwindcss@^3.4.1: version "3.4.4" resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz" integrity sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A== @@ -6140,6 +6388,18 @@ tailwindcss@*, tailwindcss@^3.4.1, tailwindcss@>=3.4.0: resolve "^1.22.2" sucrase "^3.32.0" +tar@^6.1.11: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + tarn@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz" @@ -6228,6 +6488,11 @@ tr46@^3.0.0: dependencies: punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + ts-interface-checker@^0.1.9: version "0.1.13" resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" @@ -6298,9 +6563,9 @@ use-sidecar@^1.1.2: detect-node-es "^1.1.0" tslib "^2.0.0" -util-deprecate@^1.0.2: +util-deprecate@^1.0.1, util-deprecate@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== uuid@^10.0.0: @@ -6327,6 +6592,11 @@ w3c-xmlserializer@^3.0.0: dependencies: xml-name-validator "^4.0.0" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" @@ -6360,6 +6630,14 @@ whatwg-url@^11.0.0: tr46 "^3.0.0" webidl-conversions "^7.0.0" +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" @@ -6367,6 +6645,13 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" @@ -6385,6 +6670,11 @@ wrap-ansi@^8.1.0: string-width "^5.0.1" strip-ansi "^7.0.1" +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + ws@^8.2.3: version "8.17.1" resolved "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz" @@ -6400,6 +6690,11 @@ xmlchars@^2.2.0: resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yaml@^1.10.0: version "1.10.2" resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" From 1fb9e26efc4850d6d3e9f285318a760936f6a929 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Tue, 5 Nov 2024 15:12:58 +0900 Subject: [PATCH 34/63] lock file add ignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 10fae790..52b4f8d4 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,7 @@ next-env.d.ts .idea .vscode + +#lock files +yarn.lock +package-lock.json \ No newline at end of file From 6ccadf80af7226fc039da65bdea58197a10375ed Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 5 Nov 2024 15:15:52 +0900 Subject: [PATCH 35/63] =?UTF-8?q?=EB=B3=B4=EC=A1=B0=EC=84=A0=20intersect?= =?UTF-8?q?=20=EA=B2=80=EC=82=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useAuxiliaryDrawing.js | 4 ++-- src/util/qpolygon-utils.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index 46311ad9..e9aa7d93 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -21,7 +21,7 @@ import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useSwal } from '@/hooks/useSwal' import { booleanPointInPolygon } from '@turf/turf' import { usePopup } from '@/hooks/usePopup' -import { calculateAngle } from '@/util/qpolygon-utils' +import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils' import { QPolygon } from '@/components/fabric/QPolygon' import { POLYGON_TYPE } from '@/common/common' @@ -587,7 +587,7 @@ export function useAuxiliaryDrawing(id) { return } // 기존 점과 겹치는지 확인 - if (interSectionPointsWithRoofLines.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) { + if (interSectionPointsWithRoofLines.some((point) => isSamePoint(point, intersectionPoint))) { return } diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 118e67dc..e373df8d 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1445,7 +1445,7 @@ function removeDuplicatePolygons(polygons) { return uniquePolygons } -const isSamePoint = (a, b) => { +export const isSamePoint = (a, b) => { return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 1 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 1 } From a49968240b62105517cea304a324008fff602db5 Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 5 Nov 2024 15:25:41 +0900 Subject: [PATCH 36/63] =?UTF-8?q?Canvas=20=ED=98=84=ED=99=A9=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/Canvas Status.md | 151 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 docs/Canvas Status.md diff --git a/docs/Canvas Status.md b/docs/Canvas Status.md new file mode 100644 index 00000000..97be9074 --- /dev/null +++ b/docs/Canvas Status.md @@ -0,0 +1,151 @@ +# Canvas 배포 현황 + +## 1. 배치면 초기 설정 + +## 2. 지붕덥개 + +### 2.1. 외벽선 그리기 + +### 2.2. 지붕형상 설정 + +### 2.3. 지붕형상 수동 설정 + +### 2.4. 보조선 작성 + +### 2.5. 처마 ·케라바 변경 + +### 2.6. 동선이동 ·형올림내림 + +### 2.7. 외벽선 편집 및 오프셋 + +### 2.8. 지붕면 할당 + +## 3. 배치면 + +### 3.0. Context Menu + +### 3.1. 경사 설정 + +### 3.2. 배치면 그리기 + +### 3.3. 면형상 그리기 + +### 3.4. 오브젝트 배치 + +### 3.5. 배치면 전체 삭제 + +## 4. 모듈, 회로 구성 + +### 4.1. 기본 설정 + +### 4.2. 회로 및 가대 설정 + +### 4.3. 도면 방위 적용 + +## 0. Context menu + +### (지붕덮개) 지붕재 & 보조선 우클릭 + +* 새로고침 +* 지붕재 배치 +* 지붕재 삭제 +* 지붕재 전체 삭제 +* 선택 · 이동 +* 외벽선 삭제 +* 이미지 크기 조절 +* 사이즈 변경 +* 보조선 이동 +* 보조선 복사 +* 보조선 삭제 +* 보조선 수직 이등분선 +* 보조선 절삭 +* 보조선 전체 삭제 + +### 개구 우클릭 + +* 사이즈 변경 +* 삭제 +* 이동 +* 복사 +* 개구 오프셋 + +### 그림자 표시 우클릭 + +* 사이즈 변경 +* 삭제 +* 이동 +* 복사 + +### 치수선 우클릭 + +* 삭제 +* 이동 +* 치수 보조선 변경 +* 표시 변경 + +### 문자 우클릭 + +* 삭제 +* 이동 +* 복사 +* 폰트 설정 +* 편집 + +### (배치면) 지붕재 우클릭 + +* 사이즈 변경 +* 삭제 +* 이동 +* 복사 +* 이미지 크기 조절 +* 지붕재 변경 +* 각 변 속성 변경 +* 흐름 방향 변경 + +### (배치면) 도머 우클릭 + +* 사이즈 변경 +* 삭제 +* 이동 +* 복사 +* 지붕재 변경 +* 도머 오프셋 + +### (패널 배치된 상태) 지붕면 1면 선택 후 마우스 우클릭 + +* 모듈 세로 가운데 정렬 +* 모듈 가로 가운데 정렬 +* 모듈 왼쪽 정렬 +* 모듈 오른쪽 정렬 +* 모듈 위쪽 정렬 +* 모듈 아래쪽 정렬 +* 모듈 일괄 삭제 +* 모듈 일괄 이동 +* 모듈 일괄 복사 +* 모듈 일괄 회로 번호 변경 +* + +### (패널 배치된 상태) 지붕면 2면 이상 선택 후 마우스 우클릭 + +* 모듈 세로 가운데 정렬 +* 모듈 가로 가운데 정렬 +* 모듈 왼쪽 정렬 +* 모듈 오른쪽 정렬 +* 모듈 위쪽 정렬 +* 모듈 아래쪽 정렬 +* 모듈 일괄 삭제 +* 모듈 일괄 회로 번호 변경 + +### 패널 선택 후 마우스 우클릭 + +* 삭제 +* 이동 +* 복사 +* 열 이동 +* 열 복사 +* 열 삭제 +* 열 삽입 +* 단 이동 +* 단 복사 +* 단 삭제 +* 단 삽입 \ No newline at end of file From c51c510ded669be83e49e95356da48b9190102f5 Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 5 Nov 2024 15:40:54 +0900 Subject: [PATCH 37/63] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 2677 ++++++++++++++------------- src/styles/_modal.scss | 3635 ++++++++++++++++++------------------- 2 files changed, 3035 insertions(+), 3277 deletions(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 7795cab8..6715d48b 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -17,1493 +17,1444 @@ // } // } // CanvasMenu -.canvas-menu-wrap { - position: fixed; - top: 46px; - left: 0; - display: block; - width: 100%; - min-width: 1280px; - padding-bottom: 0; - background-color: #383838; - transition: padding 0.17s ease-in-out; - z-index: 999; - .canvas-menu-inner { - position: relative; - display: flex; - align-items: center; - padding: 0 40px 0 20px; - background-color: #2c2c2c; - height: 46.8px; - z-index: 999; - .canvas-menu-list { - display: flex; - align-items: center; - height: 100%; - .canvas-menu-item { - display: flex; - align-items: center; - height: 100%; - button { - display: flex; - align-items: center; - font-size: 12px; - height: 100%; - color: #fff; - font-weight: 600; - padding: 15px 20px; - opacity: 0.55; - transition: all 0.17s ease-in-out; - .menu-icon { - display: block; - width: 14px; - height: 14px; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - margin-right: 10px; - &.con00 { - background-image: url(/static/images/canvas/menu_icon00.svg); - } - &.con01 { - background-image: url(/static/images/canvas/menu_icon01.svg); - } - &.con02 { - background-image: url(/static/images/canvas/menu_icon02.svg); - } - &.con03 { - background-image: url(/static/images/canvas/menu_icon03.svg); - } - &.con04 { - background-image: url(/static/images/canvas/menu_icon04.svg); - } - &.con05 { - background-image: url(/static/images/canvas/menu_icon05.svg); - } - &.con06 { - background-image: url(/static/images/canvas/menu_icon06.svg); - } - } - } - &.active { - background-color: #383838; - button { - opacity: 1; - } - } - } - } - .canvas-side-btn-wrap { - display: flex; - align-items: center; - margin-left: auto; - .select-box { - width: 124px; - margin: 0 5px; - height: 30px; - > div { - width: 100%; - } - } - .btn-from { - display: flex; - align-items: center; - gap: 5px; - button { - display: block; - width: 30px; - height: 30px; - border-radius: 2px; - background-color: #3d3d3d; - background-position: center; - background-repeat: no-repeat; - background-size: 15px 15px; - transition: all 0.17s ease-in-out; - &.btn01 { - background-image: url(../../public/static/images/canvas/side_icon03.svg); - } - &.btn02 { - background-image: url(../../public/static/images/canvas/side_icon02.svg); - } - &.btn03 { - background-image: url(../../public/static/images/canvas/side_icon01.svg); - } - &.btn04 { - background-image: url(../../public/static/images/canvas/side_icon04.svg); - } - &.btn05 { - background-image: url(../../public/static/images/canvas/side_icon05.svg); - } - &.btn06 { - background-image: url(../../public/static/images/canvas/side_icon06.svg); - } - &.btn07 { - background-image: url(../../public/static/images/canvas/side_icon07.svg); - } - &.btn08 { - background-image: url(../../public/static/images/canvas/side_icon08.svg); - } - &.btn09 { - background-image: url(../../public/static/images/canvas/side_icon09.svg); - } - &:hover { - background-color: #1083e3; - } - &.active { - background-color: #1083e3; - } - } - } - .ico-btn-from { - display: flex; - align-items: center; - gap: 5px; - button { - .ico { - display: block; - width: 15px; - height: 15px; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - &.ico01 { - background-image: url(../../public/static/images/canvas/ico-flx01.svg); - } - &.ico02 { - background-image: url(../../public/static/images/canvas/ico-flx02.svg); - } - &.ico03 { - background-image: url(../../public/static/images/canvas/ico-flx03.svg); - } - &.ico04 { - background-image: url(../../public/static/images/canvas/ico-flx04.svg); - } - } - .name { - font-size: 12px; - color: #fff; - } - } - &.form06 { - .name { - font-size: 13px; - } - } - } - .vertical-horizontal { - display: flex; - min-width: 170px; - height: 28px; - margin-right: 5px; - border-radius: 2px; - background: #373737; - line-height: 28px; - overflow: hidden; - span { - padding: 0 10px; - font-size: 13px; - color: #fff; - } - button { - margin-left: auto; - height: 100%; - background-color: #4b4b4b; - font-size: 13px; - font-weight: 400; - color: #fff; - padding: 0 7.5px; - transition: all 0.17s ease-in-out; - } - &.on { - button { - background-color: #1083e3; - } - } - } - .size-control { - display: flex; - align-items: center; - justify-content: center; - gap: 10px; - background-color: #3d3d3d; - border-radius: 2px; - width: 100px; - height: 30px; - margin: 0 5px; - span { - font-size: 13px; - color: #fff; - } - .control-btn { - display: block; - width: 12px; - height: 12px; - background-repeat: no-repeat; - background-size: cover; - background-position: center; - &.minus { - background-image: url(../../public/static/images/canvas/minus.svg); - } - &.plus { - background-image: url(../../public/static/images/canvas/plus.svg); - } - } - } - } - } - .canvas-depth2-wrap { - position: absolute; - top: -100%; +.canvas-menu-wrap{ + position: fixed; + top: 46px; left: 0; - background-color: #383838; + display: block; width: 100%; - height: 50px; - transition: all 0.17s ease-in-out; - .canvas-depth2-inner { - display: flex; - align-items: center; - padding: 0 40px; - height: 100%; - .canvas-depth2-list { + min-width: 1280px; + padding-bottom: 0; + background-color: #383838; + transition: padding .17s ease-in-out; + z-index: 999; + .canvas-menu-inner{ + position: relative; display: flex; align-items: center; - height: 100%; - .canvas-depth2-item { - display: flex; - align-items: center; - margin-right: 26px; - height: 100%; - button { - position: relative; - opacity: 0.55; - color: #fff; - font-size: 12px; - font-weight: normal; + padding: 0 40px 0 20px; + background-color: #2C2C2C; + height: 46.8px; + z-index: 999; + .canvas-menu-list{ + display: flex; + align-items: center; height: 100%; - padding-right: 12px; - } - &.active { - button { - opacity: 1; - font-weight: 600; - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; - } + .canvas-menu-item{ + display: flex; + align-items: center; + height: 100%; + button{ + display: flex; + align-items: center; + font-size: 12px; + height: 100%; + color: #fff; + font-weight: 600; + padding: 15px 20px; + opacity: 0.55; + transition: all .17s ease-in-out; + .menu-icon{ + display: block; + width: 14px; + height: 14px; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + margin-right: 10px; + &.con00{background-image: url(/static/images/canvas/menu_icon00.svg);} + &.con01{background-image: url(/static/images/canvas/menu_icon01.svg);} + &.con02{background-image: url(/static/images/canvas/menu_icon02.svg);} + &.con03{background-image: url(/static/images/canvas/menu_icon03.svg);} + &.con04{background-image: url(/static/images/canvas/menu_icon04.svg);} + &.con05{background-image: url(/static/images/canvas/menu_icon05.svg);} + &.con06{background-image: url(/static/images/canvas/menu_icon06.svg);} + } + } + &.active{ + background-color: #383838; + button{ + opacity: 1; + } + } } - } } - } - .canvas-depth2-btn-list { - display: flex; - align-items: center; - margin-left: auto; - height: 100%; - .depth2-btn-box { - display: flex; - align-items: center; - margin-right: 34px; - height: 100%; - transition: all 0.17s ease-in-out; - button { - position: relative; - font-size: 12px; - font-weight: 400; + .canvas-side-btn-wrap{ + display: flex; + align-items: center; + margin-left: auto; + .select-box{ + width: 124px; + margin: 0 5px; + height: 30px; + > div{ + width: 100%; + } + } + .btn-from{ + display: flex; + align-items: center; + gap: 5px; + button{ + display: block; + width: 30px; + height: 30px; + border-radius: 2px; + background-color: #3D3D3D; + background-position: center; + background-repeat: no-repeat; + background-size: 15px 15px; + transition: all .17s ease-in-out; + &.btn01{background-image: url(../../public/static/images/canvas/side_icon03.svg);} + &.btn02{background-image: url(../../public/static/images/canvas/side_icon02.svg);} + &.btn03{background-image: url(../../public/static/images/canvas/side_icon01.svg);} + &.btn04{background-image: url(../../public/static/images/canvas/side_icon04.svg);} + &.btn05{background-image: url(../../public/static/images/canvas/side_icon05.svg);} + &.btn06{background-image: url(../../public/static/images/canvas/side_icon06.svg);} + &.btn07{background-image: url(../../public/static/images/canvas/side_icon07.svg);} + &.btn08{background-image: url(../../public/static/images/canvas/side_icon08.svg);} + &.btn09{background-image: url(../../public/static/images/canvas/side_icon09.svg);} + &:hover{ + background-color: #1083E3; + } + &.active{ + background-color: #1083E3; + } + } + } + .ico-btn-from{ + display: flex; + align-items: center; + gap: 5px; + button{ + .ico{ + display: block; + width: 15px; + height: 15px; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + &.ico01{background-image: url(../../public/static/images/canvas/ico-flx01.svg);} + &.ico02{background-image: url(../../public/static/images/canvas/ico-flx02.svg);} + &.ico03{background-image: url(../../public/static/images/canvas/ico-flx03.svg);} + &.ico04{background-image: url(../../public/static/images/canvas/ico-flx04.svg);} + } + .name{ + font-size: 12px; + color: #fff; + } + } + &.form06{ + .name{ + font-size: 13px; + } + } + } + .vertical-horizontal{ + display: flex; + min-width: 170px; + height: 28px; + margin-right: 5px; + border-radius: 2px; + background: #373737; + line-height: 28px; + overflow: hidden; + span{ + padding: 0 10px; + font-size: 13px; + color: #fff; + } + button{ + margin-left: auto; + height: 100%; + background-color: #4B4B4B; + font-size: 13px; + font-weight: 400; + color: #fff; + padding: 0 7.5px; + transition: all .17s ease-in-out; + } + &.on{ + button{ + background-color: #1083E3; + } + } + } + .size-control{ + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + background-color: #3D3D3D; + border-radius: 2px; + width: 100px; + height: 30px; + margin: 0 5px; + span{ + font-size: 13px; + color: #fff; + } + .control-btn{ + display: block; + width: 12px; + height: 12px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + &.minus{ + background-image: url(../../public/static/images/canvas/minus.svg); + } + &.plus{ + background-image: url(../../public/static/images/canvas/plus.svg); + } + } + } + } + } + .canvas-depth2-wrap{ + position: absolute; + top: -100%; + left: 0; + background-color: #383838; + width: 100%; + height: 50px; + transition: all .17s ease-in-out; + .canvas-depth2-inner{ + display: flex; + align-items: center; + padding: 0 40px; height: 100%; - color: #fff; - padding-right: 12px; - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; + .canvas-depth2-list{ + display: flex; + align-items: center ; + height: 100%; + .canvas-depth2-item{ + display: flex; + align-items: center; + margin-right: 26px; + height: 100%; + button{ + position: relative; + opacity: 0.55; + color: #fff; + font-size: 12px; + font-weight: normal; + height: 100%; + padding-right: 12px; + } + &.active{ + button{ + opacity: 1; + font-weight: 600; + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; + } + } + } + } + } + .canvas-depth2-btn-list{ + display: flex; + align-items: center; + margin-left: auto; + height: 100%; + .depth2-btn-box{ + display: flex; + align-items: center; + margin-right: 34px; + height: 100%; + transition: all .17s ease-in-out; + button{ + position: relative; + font-size: 12px; + font-weight: 400; + height: 100%; + color: #fff; + padding-right: 12px; + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; + } + } + &:last-child{ + margin-right: 0; + } + &.mouse{ + opacity: 0.55; + } + } } - } - &:last-child { - margin-right: 0; - } - &.mouse { - opacity: 0.55; - } } - } + &.active{ + top: 47px; + } } - &.active { - top: 47px; + &.active{ + padding-bottom: 50px; } - } - &.active { - padding-bottom: 50px; - } } // canvas-layout -.canvas-content { - padding-top: 46.8px; - transition: all 0.17s ease-in-out; - .canvas-frame { - height: calc(100vh - 129.3px); - } - &.active { - padding-top: calc(46.8px + 50px); - .canvas-frame { - height: calc(100vh - 179.4px); +.canvas-content{ + padding-top: 46.8px; + transition: all .17s ease-in-out; + .canvas-frame{ + height: calc(100vh - 129.3px); + } + &.active{ + padding-top: calc(46.8px + 50px); + .canvas-frame{ + height: calc(100vh - 179.4px); + } } - } } -.canvas-layout { - padding-top: 37px; - .canvas-page-list { - position: fixed; - top: 92.8px; - left: 0; - display: flex; - background-color: #1c1c1c; - border-top: 1px solid #000; - width: 100%; - min-width: 1280px; - transition: all 0.17s ease-in-out; - z-index: 99; - &.active { - top: calc(92.8px + 50px); - } - .canvas-plane-wrap { - display: flex; - align-items: center; - max-width: calc(100% - 45px); - .canvas-page-box { +.canvas-layout{ + padding-top: 37px; + .canvas-page-list{ + position: fixed; + top: 92.8px; + left: 0; display: flex; - align-items: center; - background-color: #1c1c1c; - padding: 9.6px 20px; - border-right: 1px solid #000; - min-width: 0; - transition: all 0.17s ease-in-out; - span { - display: flex; - align-items: center; - width: 100%; - font-size: 12px; - font-family: 'Pretendard', sans-serif; - color: #aaa; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; + background-color: #1C1C1C; + border-top: 1px solid #000; + width: 100%; + min-width: 1280px; + transition: all .17s ease-in-out; + z-index: 99; + &.active{ + top: calc(92.8px + 50px); } - .close { - flex: none; - display: block; - width: 7px; - height: 8px; - margin-left: 15px; - background: url(../../public/static/images/canvas/plan_close_gray.svg) no-repeat center; - background-size: cover; + .canvas-plane-wrap{ + display: flex; + align-items: center; + max-width: calc(100% - 45px); + .canvas-page-box{ + display: flex; + align-items: center; + background-color: #1c1c1c; + padding: 9.6px 20px; + border-right:1px solid #000; + min-width: 0; + transition: all .17s ease-in-out; + span{ + display: flex; + align-items: center; + width: 100%; + font-size: 12px; + font-family: 'Pretendard', sans-serif; + color: #AAA; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + .close{ + flex: none; + display: block; + width: 7px; + height: 8px; + margin-left: 15px; + background: url(../../public/static/images/canvas/plan_close_gray.svg)no-repeat center; + background-size: cover; + } + &.on{ + background-color: #fff; + span{ + font-weight: 600; + color: #101010; + } + .close{ + background: url(../../public/static/images/canvas/plan_close_black.svg)no-repeat center; + } + &:hover{ + background-color: #fff; + } + } + &:hover{ + background-color: #000; + } + } } - &.on { - background-color: #fff; - span { - font-weight: 600; - color: #101010; - } - .close { - background: url(../../public/static/images/canvas/plan_close_black.svg) no-repeat center; - } - &:hover { - background-color: #fff; - } + .plane-add{ + display: flex; + align-items: center; + justify-content: center; + width: 45px; + padding: 13.5px 0; + background-color: #1C1C1C; + border-right: 1px solid #000; + transition: all .17s ease-in-out; + span{ + display: block; + width: 9px; + height: 9px; + background: url(../../public/static/images/canvas/plane_add.svg)no-repeat center; + background-size: cover; + } + &:hover{ + background-color: #000; + } } - &:hover { - background-color: #000; - } - } } - .plane-add { - display: flex; - align-items: center; - justify-content: center; - width: 45px; - padding: 13.5px 0; - background-color: #1c1c1c; - border-right: 1px solid #000; - transition: all 0.17s ease-in-out; - span { - display: block; - width: 9px; - height: 9px; - background: url(../../public/static/images/canvas/plane_add.svg) no-repeat center; - background-size: cover; - } - &:hover { - background-color: #000; - } - } - } } -.canvas-frame { - position: relative; - // height: calc(100% - 36.5px); - background-color: #f4f4f7; - overflow: auto; - transition: all 0.17s ease-in-out; - // &::-webkit-scrollbar { - // width: 10px; - // height: 10px; - // background-color: #fff; - // } - // &::-webkit-scrollbar-thumb { - // background-color: #C1CCD7; - // border-radius: 30px; - // } - // &::-webkit-scrollbar-track { - // background-color: #fff; - // } - .canvas-container { - margin: 0 auto; - background-color: #fff; - } - canvas { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - } +.canvas-frame{ + position: relative; + // height: calc(100% - 36.5px); + background-color: #F4F4F7; + overflow: auto; + transition: all .17s ease-in-out; + // &::-webkit-scrollbar { + // width: 10px; + // height: 10px; + // background-color: #fff; + // } + // &::-webkit-scrollbar-thumb { + // background-color: #C1CCD7; + // border-radius: 30px; + // } + // &::-webkit-scrollbar-track { + // background-color: #fff; + // } + .canvas-container{ + margin: 0 auto; + background-color: #fff; + } + canvas{ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } } // sub-page -.sub-header { - position: fixed; - top: 46px; - left: 0; - width: 100%; - min-width: 1280px; - height: 46px; - border-bottom: 1px solid #000; - background: #2c2c2c; - z-index: 999; - .sub-header-inner { - display: flex; - align-items: center; - height: 100%; - padding: 0 100px; - .sub-header-title-wrap { - display: flex; - align-items: center; - .title-item { - position: relative; - padding: 0 24px; - a { - display: flex; - align-items: center; - .icon { - width: 22px; - height: 22px; - margin-right: 8px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - &.drawing { - background-image: url(../../public/static/images/main/drawing_icon.svg); - } - } - } - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 16px; - background-color: #d9d9d9; - } - &:first-child { - padding-left: 0; - } - &:last-child { - padding-right: 0; - &:after { - display: none; - } - } - } - } - .sub-header-title { - font-size: 16px; - color: #fff; - font-weight: 600; - } - .sub-header-location { - margin-left: auto; - display: flex; - align-items: center; - .location-item { - position: relative; +.sub-header{ + position: fixed; + top: 46px; + left: 0; + width: 100%; + min-width: 1280px; + height: 46px; + border-bottom: 1px solid #000; + background: #2C2C2C; + z-index: 999; + .sub-header-inner{ display: flex; align-items: center; - padding: 0 10px; - span { - display: flex; - font-size: 12px; - color: #aaa; - font-weight: normal; - cursor: default; + height: 100%; + padding: 0 100px; + .sub-header-title-wrap{ + display: flex; + align-items: center; + .title-item{ + position: relative; + padding: 0 24px; + a{ + display: flex; + align-items: center; + .icon{ + width: 22px; + height: 22px; + margin-right: 8px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + &.drawing{background-image: url(../../public/static/images/main/drawing_icon.svg);} + } + } + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 16px; + background-color: #D9D9D9; + } + &:first-child{ + padding-left: 0; + } + &:last-child{ + padding-right: 0; + &:after{ + display: none; + } + } + } } - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 4px; - height: 6px; - background: url(../../public/static/images/main/loaction_arr.svg) no-repeat center; - } - &:first-child { - padding-left: 0; - } - &:last-child { - padding-right: 0; - span { + .sub-header-title{ + font-size: 16px; color: #fff; - } - &:after { - display: none; - } + font-weight: 600; + } + .sub-header-location{ + margin-left: auto; + display: flex; + align-items: center; + .location-item{ + position: relative; + display: flex; + align-items: center; + padding: 0 10px; + span{ + display: flex; + font-size: 12px; + color: #AAA; + font-weight: normal; + cursor: default; + } + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 4px; + height: 6px; + background: url(../../public/static/images/main/loaction_arr.svg)no-repeat center; + } + &:first-child{ + padding-left: 0; + } + &:last-child{ + padding-right: 0; + span{ + color: #fff; + } + &:after{ + display: none; + } + } + } } - } } - } } // sub content -.sub-content { - padding-top: 46px; - .sub-content-inner { - max-width: 1760px; - margin: 0 auto; - padding: 20px 20px 0; - .sub-content-box { - margin-bottom: 20px; - &:last-child { - margin-bottom: 0; - } +.sub-content{ + padding-top: 46px; + .sub-content-inner{ + max-width: 1760px; + margin: 0 auto; + padding: 20px 20px 0; + .sub-content-box{ + margin-bottom: 20px; + &:last-child{ + margin-bottom: 0; + } + } } - } - &.estimate { - display: flex; - flex-direction: column; - padding-top: 0; - .sub-content-inner { - flex: 1; - width: 100%; + &.estimate{ + display: flex; + flex-direction: column; + padding-top: 0; + .sub-content-inner{ + flex: 1; + width: 100%; + } } - } } -.sub-table-box { - padding: 20px; - border-radius: 6px; - border: 1px solid #e9eaed; - background: #fff; - box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); - .table-box-title-wrap { - display: flex; - align-items: center; - margin-bottom: 15px; - .title-wrap { - display: flex; - align-items: center; - h3 { - display: block; - font-size: 15px; - color: #101010; - font-weight: 600; - margin-right: 14px; - &.product { - margin-right: 10px; - } - } - .product_tit { - position: relative; - font-size: 15px; - font-weight: 600; - color: #1083e3; - padding-left: 10px; - &::before { - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 1px; - height: 11px; - background-color: #d9d9d9; - } - } - .option { - padding-left: 5px; - font-size: 13px; - color: #101010; - font-weight: 400; - } - .info-wrap { +.sub-table-box{ + padding: 20px; + border-radius: 6px; + border: 1px solid #E9EAED; + background: #FFF; + box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); + .table-box-title-wrap{ display: flex; align-items: center; - li { - position: relative; - padding: 0 6px; - font-size: 12px; - color: #101010; - font-weight: normal; - span { - font-weight: 600; - &.red { - color: #e23d70; + margin-bottom: 15px; + .title-wrap{ + display: flex; + align-items: center; + h3{ + display: block; + font-size: 15px; + color: #101010; + font-weight: 600; + margin-right: 14px; + &.product{ + margin-right: 10px; + } } - } - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 11px; - background-color: #d9d9d9; - } - &:first-child { - padding-left: 0; - } - &:last-child { - padding-right: 0; - &::after { - display: none; + .product_tit{ + position: relative; + font-size: 15px; + font-weight: 600; + color: #1083E3; + padding-left: 10px; + &::before{ + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 1px; + height: 11px; + background-color: #D9D9D9; + } + } + .option{ + padding-left: 5px; + font-size: 13px; + color: #101010; + font-weight: 400; + } + .info-wrap{ + display: flex; + align-items: center; + li{ + position: relative; + padding: 0 6px; + font-size: 12px; + color: #101010; + font-weight: normal; + span{ + font-weight: 600; + &.red{ + color: #E23D70; + } + } + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 11px; + background-color: #D9D9D9; + } + &:first-child{padding-left: 0;} + &:last-child{padding-right: 0;&::after{display: none;}} + } } - } } - } } - } - .left-unit-box { - margin-left: auto; - display: flex; - align-items: center; - } - .promise-gudie { - display: block; - font-size: 13px; - font-weight: 700; - color: #101010; - margin-bottom: 20px; - } - .important { - color: #f00; - } - .sub-center-footer { - display: flex; - align-items: center; - justify-content: center; - margin-top: 20px; - } - .sub-right-footer { - display: flex; - align-items: center; - justify-content: flex-end; - margin-top: 20px; - } + .left-unit-box{ + margin-left: auto; + display: flex; + align-items: center; + } + .promise-gudie{ + display: block; + font-size: 13px; + font-weight: 700; + color: #101010; + margin-bottom: 20px; + } + .important{ + color: #f00; + } + .sub-center-footer{ + display: flex; + align-items: center; + justify-content: center; + margin-top: 20px; + } + .sub-right-footer{ + display: flex; + align-items: center; + justify-content: flex-end; + margin-top: 20px; + } } -.pagination-wrap { - margin-top: 24px; +.pagination-wrap{ + margin-top: 24px; } -.infomation-wrap { - margin-bottom: 30px; +.infomation-wrap{ + margin-bottom: 30px; } -.infomation-box-wrap { - display: flex; - gap: 10px; - .sub-table-box { - flex: 1; - } - .info-title { - font-size: 14px; - font-weight: 500; - color: #344356; - margin-bottom: 10px; - } - .info-inner { - position: relative; - font-size: 13px; - color: #344356; - .copy-ico { - position: absolute; - bottom: 0; - right: 0; - width: 16px; - height: 16px; - background: url(../../public/static/images/sub/copy_ico.svg) no-repeat center; - background-size: cover; +.infomation-box-wrap{ + display: flex; + gap: 10px; + .sub-table-box{ + flex: 1 ; + } + .info-title{ + font-size: 14px; + font-weight: 500; + color: #344356; + margin-bottom: 10px; + } + .info-inner{ + position: relative; + font-size: 13px; + color: #344356; + .copy-ico{ + position: absolute; + bottom: 0; + right: 0; + width: 16px; + height: 16px; + background: url(../../public/static/images/sub/copy_ico.svg)no-repeat center; + background-size: cover; + } } - } } // 견적서 -.estimate-list-wrap { - display: flex; - align-items: center; - margin-bottom: 10px; - &.one { - .estimate-box { - &:last-child { - min-width: unset; - } - } - } - .estimate-box { - flex: 1; +.estimate-list-wrap{ display: flex; align-items: center; - &:last-child { - flex: none; - min-width: 220px; + margin-bottom: 10px; + &.one{ + .estimate-box{ + &:last-child{ + min-width: unset; + } + } } - .estimate-tit { - width: 105px; - height: 30px; - line-height: 30px; - background-color: #f4f4f7; - border-radius: 100px; - text-align: center; - font-size: 13px; - font-weight: 500; - color: #344356; + .estimate-box{ + flex: 1 ; + display: flex; + align-items: center; + &:last-child{ + flex: none; + min-width: 220px; + } + .estimate-tit{ + width: 105px; + height: 30px; + line-height: 30px; + background-color: #F4F4F7; + border-radius: 100px; + text-align: center; + font-size: 13px; + font-weight: 500; + color: #344356; + } + .estimate-name{ + font-size: 13px; + color: #344356; + margin-left: 14px; + font-weight: 400; + &.blue{ + font-size: 16px; + font-weight: 700; + color: #1083E3; + } + &.red{ + font-size: 16px; + font-weight: 700; + color: #D72A2A; + } + } } - .estimate-name { - font-size: 13px; - color: #344356; - margin-left: 14px; - font-weight: 400; - &.blue { - font-size: 16px; - font-weight: 700; - color: #1083e3; - } - &.red { - font-size: 16px; - font-weight: 700; - color: #d72a2a; - } + &:last-child{ + margin-bottom: 0; } - } - &:last-child { - margin-bottom: 0; - } } // file drag box -.drag-file-box { - padding: 10px; - .btn-area { - padding-bottom: 15px; - border-bottom: 1px solid #ecf0f4; - .file-upload { - display: inline-block; - height: 30px; - background-color: #94a0ad; - padding: 0 10px; - border-radius: 2px; - font-size: 13px; - line-height: 30px; - color: #fff; - font-weight: 500; - cursor: pointer; - transition: background 0.15s ease-in-out; - &:hover { - background-color: #607f9a; - } - } - } - .drag-file-area { - position: relative; - margin-top: 15px; - p { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 13px; - color: #ccc; - font-weight: 400; - cursor: default; - } - } - .file-list { - .file-item { - margin-bottom: 15px; - span { - position: relative; - font-size: 13px; - color: #45576f; - font-weight: 400; - white-space: nowrap; - padding-right: 55px; - button { - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 15px; - height: 15px; - background: url(../../public/static/images/sub/file_delete.svg) no-repeat center; - background-size: cover; +.drag-file-box{ + padding: 10px; + .btn-area{ + padding-bottom: 15px; + border-bottom: 1px solid #ECF0F4; + .file-upload{ + display: inline-block; + height: 30px; + background-color: #94A0AD; + padding: 0 10px; + border-radius: 2px; + font-size: 13px; + line-height: 30px; + color: #fff; + font-weight: 500; + cursor: pointer; + transition: background .15s ease-in-out; + &:hover{ + background-color: #607F9A; + } + } + } + .drag-file-area{ + position: relative; + margin-top: 15px; + p{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 13px; + color: #ccc; + font-weight: 400; + cursor: default; + } + } + .file-list{ + .file-item{ + margin-bottom: 15px; + span{ + position: relative; + font-size: 13px; + color: #45576F; + font-weight: 400; + white-space: nowrap; + padding-right: 55px; + button{ + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 15px; + height: 15px; + background: url(../../public/static/images/sub/file_delete.svg)no-repeat center; + background-size: cover; + } + } + &:last-child{ + margin-bottom: 0; + } } - } - &:last-child { - margin-bottom: 0; - } } - } } -.estimate-arr-btn { - display: block; - width: 20px; - height: 20px; - background-color: #94a0ad; - border: 1px solid #94a0ad; - background-position: center; - background-repeat: no-repeat; - background-image: url(../../public/static/images/canvas/estiment_arr.svg); - background-size: 11px 7px; - border-radius: 2px; - &.up { - rotate: 180deg; - } - &.on { - background-color: #fff; - border-color: #c2d0dd; - background-image: url(../../public/static/images/canvas/estiment_arr_color.svg); - } -} -.estimate-check-wrap { - .estimate-check-inner { +.estimate-arr-btn{ display: block; - } - &.hide { - border-bottom: 1px solid #ecf0f4; - margin-bottom: 15px; - .estimate-check-inner { - display: none; + width: 20px; + height: 20px; + background-color: #94A0AD; + border: 1px solid #94A0AD; + background-position: center; + background-repeat: no-repeat; + background-image: url(../../public/static/images/canvas/estiment_arr.svg); + background-size: 11px 7px; + border-radius: 2px; + &.up{ + rotate: 180deg; + } + &.on{ + background-color: #fff; + border-color: #C2D0DD; + background-image: url(../../public/static/images/canvas/estiment_arr_color.svg) } - } } - -.special-note-check-wrap { - display: grid; - grid-template-columns: repeat(5, 1fr); - border-radius: 3px; - margin-bottom: 30px; - .special-note-check-item { - padding: 14px 10px; - border: 1px solid #ecf0f4; - margin-top: -1px; - margin-right: -1px; - &.act { - background-color: #f7f9fa; +.estimate-check-wrap{ + .estimate-check-inner{ + display: block; } - } -} - -.calculation-estimate { - border: 1px solid #ecf0f4; - border-radius: 3px; - padding: 24px; - max-height: 350px; - overflow-y: auto; - margin-bottom: 30px; - dl { - margin-bottom: 35px; - &:last-child { - margin-bottom: 0; - } - dt { - font-size: 13px; - font-weight: 600; - color: #1083e3; - margin-bottom: 15px; - } - dd { - font-size: 12px; - font-weight: 400; - color: #45576f; - margin-bottom: 8px; - &:last-child { - margin-bottom: 0; - } - } - } - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9dee2; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } -} -.esimate-wrap { - margin-bottom: 20px; -} - -.estimate-product-option { - display: flex; - align-items: center; - margin-bottom: 15px; - .product-price-wrap { - display: flex; - align-items: center; - .product-price-tit { - font-size: 13px; - font-weight: 400; - color: #45576f; - margin-right: 10px; - } - .select-wrap { - width: 110px; - } - } - .product-edit-wrap { - display: flex; - align-items: center; - margin-left: auto; - .product-edit-explane { - display: flex; - align-items: center; - margin-right: 15px; - .explane-item { - position: relative; - display: flex; - align-items: center; - padding: 0 10px; - font-size: 12px; - font-weight: 400; - span { - width: 20px; - height: 20px; - margin-right: 5px; - background-size: cover; - background-repeat: no-repeat; - background-position: center; - } - &:before { - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 1px; - height: 12px; - background-color: #d9d9d9; - } - &:first-child { - padding-left: 0; - &::before { + &.hide{ + border-bottom: 1px solid #ECF0F4; + margin-bottom: 15px; + .estimate-check-inner{ display: none; - } } - &:last-child { - padding-right: 0; - } - &.item01 { - color: #3bbb48; - span { - background-image: url(../../public/static/images/sub/open_ico.svg); - } - } - &.item02 { - color: #909000; - span { - background-image: url(../../public/static/images/sub/change_ico.svg); - } - } - &.item03 { - color: #0191c9; - span { - background-image: url(../../public/static/images/sub/attachment_ico.svg); - } - } - &.item04 { - color: #f16a6a; - span { - background-image: url(../../public/static/images/sub/click_check_ico.svg); - } - } - } } - .product-edit-btn { - display: flex; - align-items: center; - button { +} + +.special-note-check-wrap{ + display: grid; + grid-template-columns: repeat(5, 1fr); + border-radius: 3px; + margin-bottom: 30px; + .special-note-check-item{ + padding: 14px 10px; + border: 1px solid #ECF0F4; + margin-top: -1px; + margin-right: -1px; + &.act{ + background-color: #F7F9FA; + } + } +} + +.calculation-estimate{ + border: 1px solid #ECF0F4; + border-radius: 3px; + padding: 24px; + max-height: 350px; + overflow-y: auto; + margin-bottom: 30px; + dl{ + margin-bottom: 35px; + &:last-child{ + margin-bottom: 0; + } + dt{ + font-size: 13px; + font-weight: 600; + color: #1083E3; + margin-bottom: 15px; + } + dd{ + font-size: 12px; + font-weight: 400; + color: #45576F; + margin-bottom: 8px; + &:last-child{ + margin-bottom: 0; + } + } + } + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #d9dee2; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } +} +.esimate-wrap{ + margin-bottom: 20px; +} + +.estimate-product-option{ + display: flex; + align-items: center; + margin-bottom: 15px; + .product-price-wrap{ display: flex; align-items: center; - span { - width: 13px; - height: 13px; - margin-right: 5px; - background-size: cover; - &.plus { - background: url(../../public/static/images/sub/plus_btn.svg) no-repeat center; - } - &.minus { - background: url(../../public/static/images/sub/minus_btn.svg) no-repeat center; - } + .product-price-tit{ + font-size: 13px; + font-weight: 400; + color: #45576F; + margin-right: 10px; + } + .select-wrap{ + width: 110px; + } + } + .product-edit-wrap{ + display: flex; + align-items: center; + margin-left: auto; + .product-edit-explane{ + display: flex; + align-items: center; + margin-right: 15px; + .explane-item{ + position: relative; + display: flex; + align-items: center; + padding: 0 10px; + font-size: 12px; + font-weight: 400; + span{ + width: 20px; + height: 20px; + margin-right: 5px; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + } + &:before{ + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 1px; + height: 12px; + background-color: #D9D9D9; + } + &:first-child{ + padding-left: 0; + &::before{ + display: none; + } + } + &:last-child{ + padding-right: 0; + } + &.item01{ + color: #3BBB48; + span{ + background-image: url(../../public/static/images/sub/open_ico.svg); + } + } + &.item02{ + color: #909000; + span{ + background-image: url(../../public/static/images/sub/change_ico.svg); + } + } + &.item03{ + color: #0191C9; + span{ + background-image: url(../../public/static/images/sub/attachment_ico.svg); + } + } + &.item04{ + color: #F16A6A; + span{ + background-image: url(../../public/static/images/sub/click_check_ico.svg); + } + } + } + } + .product-edit-btn{ + display: flex; + align-items: center; + button{ + display: flex; + align-items: center; + span{ + width: 13px; + height: 13px; + margin-right: 5px; + background-size: cover; + &.plus{ + background: url(../../public/static/images/sub/plus_btn.svg)no-repeat center; + } + &.minus{ + background: url(../../public/static/images/sub/minus_btn.svg)no-repeat center; + } + } + } } - } } - } } // 발전시물레이션 -.chart-wrap { - display: flex; - gap: 20px; - width: 100%; - .sub-table-box { - height: 100%; - } - .chart-inner { - flex: 1; - .chart-box { - margin-bottom: 30px; - } - } - .chart-table-wrap { +.chart-wrap{ display: flex; - flex-direction: column; - flex: none; - width: 650px; - .sub-table-box { - flex: 1; - &:first-child { - margin-bottom: 20px; - } + gap: 20px; + width: 100%; + .sub-table-box{ + height: 100%; + } + .chart-inner{ + flex: 1; + .chart-box{ + margin-bottom: 30px; + } + } + .chart-table-wrap{ + display: flex; + flex-direction: column; + flex: none; + width: 650px; + .sub-table-box{ + flex: 1; + &:first-child{ + margin-bottom: 20px; + } + } } - } } -.chart-month-table { - table { - table-layout: fixed; - border-collapse: collapse; - border: 1px solid #ecf0f4; - border-radius: 4px; - thead { - th { - padding: 4.5px 0; - border-bottom: 1px solid #ecf0f4; +.chart-month-table{ + table{ + table-layout: fixed; + border-collapse:collapse; + border: 1px solid #ECF0F4; + border-radius: 4px; + thead{ + th{ + padding: 4.5px 0; + border-bottom: 1px solid #ECF0F4; + text-align: center; + font-size: 13px; + color: #45576F; + font-weight: 500; + background-color: #F8F9FA; + } + } + tbody{ + td{ + font-size: 13px; + color: #45576F; + text-align: center; + padding: 4.5px 0; + } + } + } +} + +.simulation-guide-wrap{ + display: flex; + padding: 20px; + .simulation-tit-wrap{ + flex: none; + padding-right: 40px; + border-right: 1px solid #EEEEEE; + span{ + display: block; + position: relative; + padding-left: 60px; + font-size: 15px; + color: #14324F; + font-weight: 600; + &::before{ + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 40px; + height: 40px; + background: url(../../public/static/images/sub/simulation_guide.svg)no-repeat center; + background-size: cover; + } + } + } + .simulation-guide-box{ + flex: 1; + padding-left: 40px; + dl{ + margin-bottom: 25px; + dt{ + font-size: 13px; + color: #101010; + font-weight: 600; + margin-bottom: 5px; + } + dd{ + font-size: 12px; + color: #45576F; + font-weight: 400; + line-height: 24px; + } + &:last-child{ + margin-bottom: 0; + } + } + ul, ol{ + list-style: unset; + } + } +} + +.module-total{ + display: flex; + align-items: center; + background-color: #F8F9FA; + padding: 9px 0; + margin-right: 4px; + border: 1px solid #ECF0F4; + border-top: none; + .total-title{ + flex: 1; text-align: center; font-size: 13px; - color: #45576f; + color: #344356; font-weight: 500; - background-color: #f8f9fa; - } } - tbody { - td { - font-size: 13px; - color: #45576f; + .total-num{ + flex: none; + width: 121px; text-align: center; - padding: 4.5px 0; - } + font-size: 15px; + color: #344356; + font-weight: 500; } - } -} - -.simulation-guide-wrap { - display: flex; - padding: 20px; - .simulation-tit-wrap { - flex: none; - padding-right: 40px; - border-right: 1px solid #eeeeee; - span { - display: block; - position: relative; - padding-left: 60px; - font-size: 15px; - color: #14324f; - font-weight: 600; - &::before { - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 40px; - height: 40px; - background: url(../../public/static/images/sub/simulation_guide.svg) no-repeat center; - background-size: cover; - } - } - } - .simulation-guide-box { - flex: 1; - padding-left: 40px; - dl { - margin-bottom: 25px; - dt { - font-size: 13px; - color: #101010; - font-weight: 600; - margin-bottom: 5px; - } - dd { - font-size: 12px; - color: #45576f; - font-weight: 400; - line-height: 24px; - } - &:last-child { - margin-bottom: 0; - } - } - ul, - ol { - list-style: unset; - } - } -} - -.module-total { - display: flex; - align-items: center; - background-color: #f8f9fa; - padding: 9px 0; - margin-right: 4px; - border: 1px solid #ecf0f4; - border-top: none; - .total-title { - flex: 1; - text-align: center; - font-size: 13px; - color: #344356; - font-weight: 500; - } - .total-num { - flex: none; - width: 121px; - text-align: center; - font-size: 15px; - color: #344356; - font-weight: 500; - } } // 물건상세 -.information-help-wrap { - display: flex; - padding: 24px; - background-color: #f4f4f4; - border-radius: 4px; - margin-bottom: 15px; - .information-help-tit-wrap { - position: relative; +.information-help-wrap{ display: flex; - align-items: center; - padding-right: 40px; - border-right: 1px solid #e0e0e3; - .help-tit-icon { - width: 40px; - height: 40px; - border-radius: 50%; - margin-right: 10px; - background: #fff url(../../public/static/images/sub/information_help.svg) no-repeat center; - background-size: 20px 20px; + padding: 24px; + background-color: #F4F4F4; + border-radius: 4px; + margin-bottom: 15px; + .information-help-tit-wrap{ + position: relative; + display: flex; + align-items: center; + padding-right: 40px; + border-right: 1px solid #E0E0E3; + .help-tit-icon{ + width: 40px; + height: 40px; + border-radius: 50%; + margin-right: 10px; + background: #fff url(../../public/static/images/sub/information_help.svg)no-repeat center; + background-size: 20px 20px; + } + .help-tit{ + font-size: 13px; + font-weight: 600; + color: #45576F; + } } - .help-tit { - font-size: 13px; - font-weight: 600; - color: #45576f; + .information-help-guide{ + padding-left: 40px; + span{ + display: block; + font-size: 12px; + font-weight: 400; + color: #45576F; + margin-bottom: 7px; + &:last-child{ + margin-bottom: 0; + } + } } - } - .information-help-guide { - padding-left: 40px; - span { - display: block; - font-size: 12px; - font-weight: 400; - color: #45576f; - margin-bottom: 7px; - &:last-child { - margin-bottom: 0; - } - } - } } -.community-search-warp { - display: flex; - flex-direction: column; - align-items: center; - padding: 10px 0 30px 0; - border-bottom: 1px solid #e5e5e5; - margin-bottom: 24px; - .community-search-box { - position: relative; +.community-search-warp{ display: flex; + flex-direction: column; align-items: center; - width: 580px; - height: 45px; - padding: 0 45px 0 20px; - margin-bottom: 20px; - border-radius: 2px; - border: 1px solid #101010; - .community-input { - width: 100%; - height: 100%; - font-size: 13px; - font-weight: 400; - color: #101010; - &::placeholder { - color: #c8c8c8; - } + padding: 10px 0 30px 0; + border-bottom: 1px solid #E5E5E5; + margin-bottom: 24px; + .community-search-box{ + position: relative; + display: flex; + align-items: center; + width: 580px; + height: 45px; + padding: 0 45px 0 20px; + margin-bottom: 20px; + border-radius: 2px; + border: 1px solid #101010; + .community-input{ + width: 100%; + height: 100%; + font-size: 13px; + font-weight: 400; + color: #101010; + &::placeholder{ + color: #C8C8C8; + } + } + .community-search-ico{ + position: absolute; + top: 50%; + right: 20px; + transform: translateY(-50%); + flex: none; + width: 21px; + height: 100%; + background: url(../../public/static/images/sub/community_search.svg)no-repeat center; + background-size: 21px 21px; + z-index: 3; + } } - .community-search-ico { - position: absolute; - top: 50%; - right: 20px; - transform: translateY(-50%); - flex: none; - width: 21px; - height: 100%; - background: url(../../public/static/images/sub/community_search.svg) no-repeat center; - background-size: 21px 21px; - z-index: 3; + .community-search-keyword{ + font-size: 13px; + font-weight: 400; + color: #45576F; + span{ + font-weight: 600; + color: #F16A6A; + } } - } - .community-search-keyword { - font-size: 13px; - font-weight: 400; - color: #45576f; - span { - font-weight: 600; - color: #f16a6a; - } - } } // 자료 다운로드 -.file-down-list { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 14px; - .file-down-item { - display: flex; - align-items: center; - padding: 24px; - border-radius: 4px; - border: 1px solid #e5e5e5; - background: #fff; - transition: all 0.15s ease-in-out; - .file-item-info { - .item-num { - display: inline-block; - padding: 6px 17.5px; - border-radius: 60px; - background-color: #f4f4f7; - font-size: 13px; - font-weight: 600; - color: #101010; - margin-bottom: 15px; - } - .item-name { - font-size: 16px; - color: #101010; - font-weight: 500; - margin-bottom: 13px; - } - .item-date { - font-size: 13px; - font-weight: 400; - color: #344356; - } +.file-down-list{ + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + .file-down-item{ + display: flex; + align-items: center; + padding: 24px; + border-radius: 4px; + border: 1px solid #E5E5E5; + background: #FFF; + transition: all .15s ease-in-out; + .file-item-info{ + .item-num{ + display: inline-block; + padding: 6px 17.5px; + border-radius: 60px; + background-color: #F4F4F7; + font-size: 13px; + font-weight: 600; + color: #101010; + margin-bottom: 15px; + } + .item-name{ + font-size: 16px; + color: #101010; + font-weight: 500; + margin-bottom: 13px; + } + .item-date{ + font-size: 13px; + font-weight: 400; + color: #344356; + } + } + .file-down-box{ + display: flex; + align-items: center; + flex: none; + margin-left: auto; + height: 100%; + .file-down-btn{ + width: 36px; + height: 36px; + background: url(../../public/static/images/sub/file_down_btn.svg)no-repeat center; + background-size: cover; + } + } + &:hover{ + background-color: #F4F4F7; + } } - .file-down-box { - display: flex; - align-items: center; - flex: none; - margin-left: auto; - height: 100%; - .file-down-btn { - width: 36px; - height: 36px; - background: url(../../public/static/images/sub/file_down_btn.svg) no-repeat center; - background-size: cover; - } - } - &:hover { - background-color: #f4f4f7; - } - } } -.file-down-nodata { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 148px; - padding: 24px; - border-radius: 4px; - border: 1px solid #e5e5e5; - font-size: 16px; - font-weight: 500; - color: #344356; +.file-down-nodata{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 148px; + padding: 24px; + border-radius: 4px; + border: 1px solid #E5E5E5; + font-size: 16px; + font-weight: 500; + color: #344356; } //신규물건 등록 -.product-input-wrap { - display: flex; - align-items: center; - width: 200px; - height: 30px; - background-color: #fafafa; - border: 1px solid #eee; - padding: 0 10px; - input { - font-size: 13px; - font-weight: 400; - color: #999999; - padding: 0; - width: 100%; - height: 100%; - flex: 1; - background-color: inherit; - } - .product-delete { - flex: none; - display: block; - width: 15px; - height: 100%; - background: url(../../public/static/images/sub/product-del.svg) no-repeat center; - background-size: 15px 15px; - } +.product-input-wrap{ + display: flex; + align-items: center; + width: 200px; + height: 30px; + background-color: #FAFAFA; + border: 1px solid #EEE; + padding: 0 10px; + input{ + font-size: 13px; + font-weight: 400; + color: #999999; + padding: 0; + width: 100%; + height: 100%; + flex: 1 ; + background-color: inherit; + } + .product-delete{ + flex: none; + display: block; + width: 15px; + height: 100%; + background: url(../../public/static/images/sub/product-del.svg)no-repeat center; + background-size: 15px 15px; + } } @media screen and (max-width: 1800px) { - .canvas-menu-wrap { - .canvas-menu-inner { - .canvas-menu-list { - .canvas-menu-item button { - .menu-icon { - margin-right: 5px; - } - } - .canvas-menu-item { - button { - padding: 15px 15px; - font-size: 11px; - } - } - } - } - .canvas-depth2-wrap { - .canvas-depth2-inner { - .canvas-depth2-list { - .canvas-depth2-item { - button { - font-size: 11px; + .canvas-menu-wrap{ + .canvas-menu-inner{ + .canvas-menu-list{ + .canvas-menu-item button{ + .menu-icon{ + margin-right: 5px; + } + } + .canvas-menu-item{ + button{ + padding: 15px 15px; + font-size: 11px; + } + } } - } } - } - } - } + .canvas-depth2-wrap{ + .canvas-depth2-inner{ + .canvas-depth2-list{ + .canvas-depth2-item{ + button{ + font-size: 11px; + } + } + } + } + } + } } @media screen and (max-width: 1600px) { - .canvas-menu-wrap { - .canvas-menu-inner { - .canvas-menu-list { - .canvas-menu-item button { - .menu-icon { - display: none; - } + .canvas-menu-wrap{ + .canvas-menu-inner{ + .canvas-menu-list{ + .canvas-menu-item button{ + .menu-icon{ + display: none; + } + } + } } - } - } - } - .canvas-content { - .canvas-frame { - height: calc(100vh - 129.5px); - } - &.active { - .canvas-frame { - height: calc(100vh - 179.5px); - } - } - } + } + .canvas-content{ + .canvas-frame{ + height: calc(100vh - 129.5px); + } + &.active{ + .canvas-frame{ + height: calc(100vh - 179.5px); + } + } + } } @media screen and (max-width: 1500px) { - .canvas-menu-wrap { - .canvas-menu-inner { - .canvas-menu-list { - .canvas-menu-item { - button { - padding: 15px 10px; - font-size: 10px; - } - } - } - .canvas-side-btn-wrap { - .btn-from { - gap: 3px; - } - .vertical-horizontal { - margin-right: 3px; - min-width: 150px; - } - .select-box { - width: 100px; - margin: 0 3px; - } - .size-control { - width: 90px; - margin: 0 3px; - } - } - } - } - .sub-header { - .sub-header-inner { - .sub-header-title { - font-size: 15px; - } - .sub-header-title-wrap { - .title-item { - a { - .icon { - width: 20px; - height: 20px; + .canvas-menu-wrap{ + .canvas-menu-inner{ + .canvas-menu-list{ + .canvas-menu-item{ + button{ + padding: 15px 10px; + font-size: 10px; + } + } } - } + .canvas-side-btn-wrap{ + .btn-from{ + gap: 3px; + } + .vertical-horizontal{ + margin-right: 3px; + min-width: 150px; + } + .select-box{ + width: 100px; + margin: 0 3px; + } + .size-control{ + width: 90px; + margin: 0 3px; + } + } } - } } - } + .sub-header{ + .sub-header-inner{ + .sub-header-title{ + font-size: 15px; + } + .sub-header-title-wrap{ + .title-item{ + a{ + .icon{ + width: 20px; + height: 20px; + } + } + } + } + } + } + } diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index 4ddb3bad..01b47c47 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -4,2103 +4,1910 @@ $pop-bold-weight: 500; $pop-normal-size: 12px; $alert-color: #101010; -@keyframes mountpop { - from { - opacity: 0; - scale: 0.95; - } - to { - opacity: 1; - scale: 1; - } +@keyframes mountpop{ + from{opacity: 0; scale: 0.95;} + to{opacity: 1; scale: 1;} } -@keyframes unmountpop { - from { - opacity: 1; - scale: 1; - } - to { - opacity: 0; - scale: 0.95; - } +@keyframes unmountpop{ + from{opacity: 1; scale: 1;} + to{opacity: 0; scale: 0.95;} } -.normal-font { - font-size: 12px; - font-weight: 400; - color: #fff; +.normal-font{ + font-size: 12px; + font-weight: 400; + color: #fff; } -.bold-font { - font-size: 12px; - font-weight: 500; - color: #fff; +.bold-font{ + font-size: 12px; + font-weight: 500; + color: #fff; } -.modal-pop-wrap { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: -webkit-fit-content; - height: -moz-fit-content; - height: fit-content; - border: 1px solid #000; - border-radius: 4px; - background-color: #272727; - z-index: 9999999; - &.xsm { - width: 200px; - } - &.xxxm { - width: 240px; - } - &.xxm { - width: 270px; - } - &.xm { - width: 300px; - } - &.ssm { - width: 380px; - } - &.sm { - width: 580px; - } - &.r { - width: 400px; - } - &.lr { - width: 440px; - } - &.lr-2 { - width: 450px; - } - &.lrr { - width: 480px; - } - &.ml { - width: 530px; - } - &.l-2 { - width: 640px; - } - &.lx-2 { - width: 740px; - } - &.lx { - width: 770px; - } - &.l { - width: 800px; - } - &.mount { - animation: mountpop 0.17s ease-in-out forwards; - } - &.unmount { - animation: unmountpop 0.17s ease-in-out forwards; - } - &.alert { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: transparent; - border: none; - .modal-head { - background-color: transparent; - padding: 0 0 8px; - .modal-close { - width: 20px; - height: 20px; - background: url(../../public/static/images/canvas/alert_close.svg) no-repeat center; - } +.modal-pop-wrap{ + position: fixed; + top: 0; + left: 0; + width: 100%; + height: -webkit-fit-content; + height: -moz-fit-content; + height: fit-content; + border: 1px solid #000; + border-radius: 4px; + background-color: #272727; + z-index: 9999999; + &.xsm{ + width: 200px; } - .modal-body { - background-color: #fff; - padding: 22px; - border-radius: 4px; - border: 1px solid #101010; - color: $alert-color; - .alert-title { + &.xxxm{ + width: 240px; + } + &.xxm{ + width: 270px; + } + &.xm{ + width: 300px; + } + &.ssm{ + width: 380px; + } + &.sm{ + width: 580px; + } + &.r{ + width: 400px; + } + &.lr{ + width: 440px; + } + &.lr-2{ + width: 450px; + } + &.lrr{ + width: 480px; + } + &.ml{ + width: 530px; + } + &.l-2{ + width: 640px; + } + &.lx-2{ + width: 740px; + } + &.lx{ + width: 770px; + } + &.l{ + width: 800px; + } + &.mount{ + animation: mountpop .17s ease-in-out forwards; + } + &.unmount{ + animation: unmountpop .17s ease-in-out forwards; + } + &.alert{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: transparent; + border: none; + .modal-head{ + background-color: transparent; + padding: 0 0 8px; + .modal-close{ + width: 20px; + height: 20px; + background: url(../../public/static/images/canvas/alert_close.svg)no-repeat center; + } + } + .modal-body{ + background-color: #fff; + padding: 22px; + border-radius: 4px; + border: 1px solid #101010; + color: $alert-color; + .alert-title{ + font-size: 13px; + font-weight: 700; + color: $alert-color; + margin-bottom: 15px; + } + } + } +} +.modal-head{ + display: flex; + align-items: center; + padding: 10px 24px; + background-color: #000; + // overflow: hidden; + h1.title{ font-size: 13px; + color: $pop-color; font-weight: 700; - color: $alert-color; + } + .modal-close{ + margin-left: auto; + color: transparent; + font-size: 0; + width: 10px; + height: 10px; + background: url(../../public/static/images/canvas/modal_close.svg)no-repeat center; + } +} +.modal-body{ + padding: 24px; + .modal-btn-wrap{ + display: flex; + align-items: center; + gap: 5px; + button{ + flex: 1; + } + &.sub{ + button{ + flex: 1 1 auto; + padding: 0; + } + margin-bottom: 14px; + } + } + .modal-check-btn-wrap{ + margin-top: 15px; + .check-wrap-title{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: 600; + &.light{ + font-weight: $pop-normal-weight; + } + } + .flex-check-box{ + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 15px; + &.for2{ + justify-content: flex-end; + button{ + width: calc(50% - 5px); + } + &.btn{ + gap: 5px; + button{ + width: calc(50% - 2.5px); + } + } + } + &.for-line{ + button{ + flex: 1; + } + } + } + } + .outer-line-wrap{ + border-top: 1px solid #3C3C3C; + margin-top: 10px; + padding-top: 15px; margin-bottom: 15px; - } + > div{ + margin-bottom: 15px; + &:last-child{ + margin-bottom: 0; + } + } } - } -} -.modal-head { - display: flex; - align-items: center; - padding: 10px 24px; - background-color: #000; - // overflow: hidden; - h1.title { - font-size: 13px; - color: $pop-color; - font-weight: 700; - } - .modal-close { - margin-left: auto; - color: transparent; - font-size: 0; - width: 10px; - height: 10px; - background: url(../../public/static/images/canvas/modal_close.svg) no-repeat center; - } -} -.modal-body { - padding: 24px; - .modal-btn-wrap { - display: flex; - align-items: center; - gap: 5px; - button { - flex: 1; - } - &.sub { - button { - flex: 1 1 auto; - padding: 0; - } - margin-bottom: 14px; - } - } - .modal-check-btn-wrap { - margin-top: 15px; - .check-wrap-title { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: 600; - &.light { + .modal-guide{ + display: block; + font-size: $pop-normal-size; + color: $alert-color; font-weight: $pop-normal-weight; - } } - .flex-check-box { - display: flex; - flex-wrap: wrap; - gap: 10px; - margin-top: 15px; - &.for2 { - justify-content: flex-end; - button { - width: calc(50% - 5px); - } - &.btn { - gap: 5px; - button { - width: calc(50% - 2.5px); - } - } - } - &.for-line { - button { - flex: 1; - } - } - } - } - .outer-line-wrap { - border-top: 1px solid #3c3c3c; - margin-top: 10px; - padding-top: 15px; - margin-bottom: 15px; - > div { - margin-bottom: 15px; - &:last-child { - margin-bottom: 0; - } - } - } - .modal-guide { - display: block; - font-size: $pop-normal-size; - color: $alert-color; - font-weight: $pop-normal-weight; - } } -.adsorption-point { - display: flex; - align-items: center; - background-color: #3a3a3a; - border-radius: 3px; - padding-left: 11px; - overflow: hidden; - transition: all 0.17s ease-in-out; - span { - font-size: $pop-normal-size; - color: #898989; - } - i { +.adsorption-point{ display: flex; align-items: center; - padding: 0 7px; - margin-left: auto; - height: 100%; - font-size: 13px; - color: #898989; - } - &.act { - i { - color: $pop-color; - background-color: #1083e3; + background-color: #3A3A3A; + border-radius: 3px; + padding-left: 11px; + overflow: hidden; + transition: all 0.17s ease-in-out; + span{ + font-size: $pop-normal-size; + color: #898989; + } + i{ + display: flex; + align-items: center; + padding: 0 7px; + margin-left: auto; + height: 100%; + font-size: 13px; + color: #898989; + } + &.act{ + i{ + color: $pop-color; + background-color: #1083E3; + } } - } } // grid-option -.grid-check-form { - display: flex; - align-items: center; - gap: 15px; - padding-bottom: 15px; - &.border { - border-bottom: 1px solid #424242; - } -} -.grid-option-wrap { - .grid-option-box { +.grid-check-form{ display: flex; align-items: center; - background-color: transparent; - border: 1px solid #3d3d3d; - border-radius: 2px; - padding: 15px 10px; - gap: 20px; - margin-bottom: 10px; - .grid-input-form { - display: flex; - align-items: center; - span { - flex: none; - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - } - .input-grid { - width: 54px; - input { - width: 100%; + gap: 15px; + padding-bottom: 15px; + &.border{ + border-bottom: 1px solid #424242; + } +} +.grid-option-wrap{ + .grid-option-box{ + display: flex; + align-items: center; + background-color: transparent; + border: 1px solid #3D3D3D; + border-radius: 2px; + padding: 15px 10px; + gap: 20px; + margin-bottom: 10px; + .grid-input-form{ + display: flex; + align-items: center; + span{ + flex: none; + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + } + .input-grid{ + width: 54px; + input{ + width: 100%; + } + } + } + &:last-child{ + margin-bottom: 0; } - } } - &:last-child { - margin-bottom: 0; - } - } } -.select-form { - .sort-select { - width: 100%; - } +.select-form{ + .sort-select{width: 100%;} } -.grid-select { - flex: 1; - &.no-flx { - flex: unset; - } - .sort-select { - width: 100%; - background-color: #313131; - min-width: auto; - font-size: 12px; - border: none; - p { - font-size: 12px; +.grid-select{ + flex: 1; + &.no-flx{ + flex: unset; } - > ul { - border: none; + .sort-select{ + width: 100%; + background-color: #313131; + min-width: auto; + font-size: 12px; + border: none; + p{ + font-size: 12px; + } + > ul{ + border: none; + } } - } - &.right { - p { - text-align: right; + &.right{ + p{ + text-align: right; + } + ul{ + li{ + justify-content: flex-end; + } + } } - ul { - li { - justify-content: flex-end; - } - } - } } -.grid-btn-wrap { - padding-top: 15px; - text-align: right; - button { - padding: 0 10px; - } +.grid-btn-wrap{ + padding-top: 15px; + text-align: right; + button{ + padding: 0 10px; + } } // grid copy -.grid-option-tit { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - padding-bottom: 15px; +.grid-option-tit{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + padding-bottom: 15px; + } -.grid-direction { - display: flex; - align-items: center; - gap: 5px; - flex: 1; +.grid-direction{ + display: flex; + align-items: center; + gap: 5px; + flex: 1; } -.direction { - width: 22px; - height: 22px; - background-color: #757575; - background-image: url(../../public/static/images/canvas/grid_option_arr.svg); - background-repeat: no-repeat; - background-position: center; - background-size: 16px 15px; - border-radius: 50%; - transition: all 0.15s ease-in-out; - opacity: 0.6; - &.down { - transform: rotate(180deg); - } - &.left { - transform: rotate(-90deg); - } - &.right { - transform: rotate(90deg); - } - &:hover, - &.act { - opacity: 1; - } +.direction{ + width: 22px; + height: 22px; + background-color: #757575; + background-image: url(../../public/static/images/canvas/grid_option_arr.svg); + background-repeat: no-repeat; + background-position: center; + background-size: 16px 15px; + border-radius: 50%; + transition: all .15s ease-in-out; + opacity: 0.6; + &.down{transform: rotate(180deg);} + &.left{transform: rotate(-90deg);} + &.right{transform: rotate(90deg);} + &:hover, + &.act{ + opacity: 1; + } } // grid-move -.move-form { - width: 100%; - p { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - } -} -.input-move-wrap { - display: flex; - align-items: center; - gap: 5px; - span { - color: $pop-color; - font-size: $pop-normal-size; - } - .input-move { - width: 130px; - input { - width: 100%; - } - } -} -.direction-move-wrap { - flex: none; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 5px; - margin-left: auto; -} - -// 배치면 초기 설정 -.placement-table { - table { - table-layout: fixed; - tr { - th { +.move-form{ + width: 100%; + p{ font-size: $pop-normal-size; color: $pop-color; font-weight: $pop-bold-weight; - padding: 18px 0; - border-bottom: 1px solid #424242; - vertical-align: middle; - .tip-wrap { - display: flex; - align-items: center; - } - } - td { - font-size: $pop-normal-size; - color: $pop-color; - border-bottom: 1px solid #424242; - padding: 18px 0 18px 20px; - vertical-align: middle; - .flex-box { - display: flex; - align-items: center; - height: 100%; - } - } - &:first-child { - td, - th { - padding-top: 0; - } - } } - } - .tooltip { - position: relative; - display: block; - width: 15px; - height: 15px; - margin-left: 5px; - background: url(../../public/static/images/canvas/pop_tip.svg) no-repeat center; - background-size: cover; - } - &.light { - padding: 0; - th, - td { - color: $alert-color; - border-bottom: none; - border-top: 1px solid #efefef; - } - th { - padding: 14px 0; - } - tr { - &:first-child { - td, - th { - padding-top: 14px; - } - } - &:last-child { - td, - th { - padding-bottom: 0px; - } - } - } - } } - -.pop-form-radio { - display: flex; - align-items: center; - gap: 10px; -} -.placement-option { - display: flex; - align-items: center; - gap: 20px; -} -.select-wrap { - .sort-select { - width: 100%; - } -} -.flex-ment { - display: flex; - align-items: center; - gap: 5px; - span { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - } -} - -.img-edit-wrap { - flex: none; - .img-edit-btn { +.input-move-wrap{ display: flex; align-items: center; - height: 30px; - padding: 0 10px; - font-size: 12px; - font-weight: 400; - color: #101010; - background-color: #fff; - border-radius: 2px; - cursor: pointer; - transition: all 0.15s ease-in-out; - .img-edit { - width: 16px; - height: 16px; - background: url(../../public/static/images/canvas/img_edit_ico.svg) no-repeat center; - background-size: cover; - margin-right: 5px; + gap: 5px; + span{ + color: $pop-color; + font-size: $pop-normal-size; } - &:hover { - background-color: #ebebeb; + .input-move{ + width: 130px; + input{ + width: 100%; + } } - } } -.img-name-wrap { - display: flex; - align-items: center; - width: 100%; - margin-left: 10px; - input { - flex: 1; - } - .img-check { +.direction-move-wrap{ flex: none; - width: 18px; - height: 18px; - margin-left: 5px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - background-image: url(../../public/static/images/canvas/img_check_fail.svg); - } + display: grid; + grid-template-columns: 1fr 1fr; + gap: 5px; + margin-left: auto; } -.for-address { - input { - flex: 1; - } - .check-address { +// 배치면 초기 설정 +.placement-table{ + table{ + table-layout: fixed; + tr{ + th{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + padding: 18px 0; + border-bottom: 1px solid #424242; + vertical-align: middle; + .tip-wrap{ + display: flex; + align-items: center; + } + } + td{ + font-size: $pop-normal-size; + color: $pop-color; + border-bottom: 1px solid #424242; + padding: 18px 0 18px 20px; + vertical-align: middle; + .flex-box{ + display: flex; + align-items: center; + height: 100%; + } + } + &:first-child{ + td, + th{ + padding-top: 0; + } + } + } + } + .tooltip{ + position: relative; + display: block; + width: 15px; + height: 15px; + margin-left: 5px; + background: url(../../public/static/images/canvas/pop_tip.svg)no-repeat center; + background-size: cover; + } + &.light{ + padding: 0; + th,td{ + color: $alert-color; + border-bottom: none; + border-top: 1px solid #EFEFEF; + } + th{ + padding: 14px 0; + } + tr{ + &:first-child{ + td, + th{ + padding-top: 14px; + } + } + &:last-child{ + td, + th{ + padding-bottom: 0px; + } + } + } + } +} + +.pop-form-radio{ + display: flex; + align-items: center; + gap: 10px; +} +.placement-option{ + display: flex; + align-items: center; + gap: 20px; +} +.select-wrap{ + .sort-select{ + width: 100%; + } +} +.flex-ment{ + display: flex; + align-items: center; + gap: 5px; + span{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + } + +} + +.img-edit-wrap{ flex: none; - width: 18px; - height: 18px; - margin-left: 5px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - &.fail { - background-image: url(../../public/static/images/canvas/img_check_fail.svg); + .img-edit-btn{ + display: flex; + align-items: center; + height: 30px; + padding: 0 10px; + font-size: 12px; + font-weight: 400; + color: #101010; + background-color: #fff; + border-radius: 2px; + cursor: pointer; + transition: all .15s ease-in-out; + .img-edit{ + width: 16px; + height: 16px; + background: url(../../public/static/images/canvas/img_edit_ico.svg)no-repeat center; + background-size: cover; + margin-right: 5px; + } + &:hover{ + background-color: #ebebeb; + } } - &.success { - background-image: url(../../public/static/images/canvas/img_check_success.svg); +} +.img-name-wrap{ + display: flex; + align-items: center; + width: 100%; + margin-left: 10px; + input{ + flex: 1; + + } + .img-check{ + flex: none; + width: 18px; + height: 18px; + margin-left: 5px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + background-image: url(../../public/static/images/canvas/img_check_fail.svg); + } +} + +.for-address{ + input{ + flex: 1; + } + .check-address{ + flex: none; + width: 18px; + height: 18px; + margin-left: 5px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + &.fail{background-image: url(../../public/static/images/canvas/img_check_fail.svg);} + &.success{background-image: url(../../public/static/images/canvas/img_check_success.svg);} } - } } // 외벽선 그리기 -.outline-wrap { - padding: 24px 0; - border-top: 1px solid #424242; - - .outline-inner { +.outline-wrap{ + padding: 24px 0; + border-top: 1px solid #424242; + + .outline-inner{ + display: flex; + align-items: center; + margin-bottom: 14px; + &:last-child{ + margin-bottom: 0; + } + .outline-form{ + // width: 50%; + margin-right: 15px; + } + } + &:last-child{ + border-bottom: 1px solid #424242; + } +} +.outline-form{ display: flex; align-items: center; - margin-bottom: 14px; - &:last-child { - margin-bottom: 0; + + span{ + width: 60px; + flex: none; + font-size: $pop-normal-size; + font-weight: $pop-bold-weight; + color: $pop-color; + margin-right: 10px; + &.thin{ + width: auto; + font-weight: $pop-normal-weight; + margin-right: 0; + } } - .outline-form { - // width: 50%; - margin-right: 15px; - } - } - &:last-child { - border-bottom: 1px solid #424242; - } -} -.outline-form { - display: flex; - align-items: center; - span { - width: 60px; - flex: none; - font-size: $pop-normal-size; - font-weight: $pop-bold-weight; - color: $pop-color; - margin-right: 10px; - &.thin { - width: auto; - font-weight: $pop-normal-weight; - margin-right: 0; + .reset-btn{ + flex: none; + width: 30px; + height: 30px; + background: transparent; + border: 1px solid #484848; + border-radius: 2px; + margin-left: 5px; + background-image: url(../../public/static/images/canvas/reset_ico.svg); + background-repeat: no-repeat; + background-size: 12px 12px; + background-position: center; + } + &:last-child{ + margin-right: 0; } - } - - .reset-btn { - flex: none; - width: 30px; - height: 30px; - background: transparent; - border: 1px solid #484848; - border-radius: 2px; - margin-left: 5px; - background-image: url(../../public/static/images/canvas/reset_ico.svg); - background-repeat: no-repeat; - background-size: 12px 12px; - background-position: center; - } - &:last-child { - margin-right: 0; - } } -.cul-wrap { - display: flex; - .outline-box { - width: 50%; - margin-right: 15px; - .outline-form { - width: 100%; - margin-bottom: 14px; - margin-right: 0; - &:last-child { - margin-bottom: 0; - } - } - } - .cul-box { +.cul-wrap{ display: flex; - align-items: center; - justify-content: center; - width: 50%; - background-color: #3d3d3d; - border-radius: 2px; - } + .outline-box{ + width: 50%; + margin-right: 15px; + .outline-form{ + width: 100%; + margin-bottom: 14px; + margin-right: 0; + &:last-child{ + margin-bottom: 0; + } + } + } + .cul-box{ + display: flex; + align-items: center; + justify-content: center; + width: 50%; + background-color: #3D3D3D; + border-radius: 2px ; + } } // 외벽선 속성 설정 -.properties-guide { - font-size: $pop-normal-size; - color: #aaa; - font-weight: $pop-normal-weight; - margin-bottom: 14px; +.properties-guide{ + font-size: $pop-normal-size; + color: #AAA; + font-weight: $pop-normal-weight; + margin-bottom: 14px; } -.setting-tit { - font-size: 13px; - color: $pop-color; - font-weight: $pop-bold-weight; - margin-bottom: 10px; +.setting-tit{ + font-size: 13px; + color: $pop-color; + font-weight: $pop-bold-weight; + margin-bottom: 10px; } -.properties-setting-wrap { - &.outer { - margin-top: 24px; - } - .setting-btn-wrap { - display: flex; - align-items: center; - padding: 14px 0; - border-top: 1px solid #424242; - border-bottom: 1px solid #424242; - .setting-btn { - display: block; - width: 100%; - height: 40px; - font-size: 13px; - color: #fff; - font-weight: 700; - border-radius: 2px; - transition: all 0.15s ease-in-out; - &.green { - background-color: #305941; - border: 1px solid #45cd7d; - &:hover { - background-color: #3a6b4e; - } - } - &.blue { - background-color: #2e5360; - border: 1px solid #3fbae6; - &:hover { - background-color: #365f6e; - } - } +.properties-setting-wrap{ + &.outer{ + margin-top: 24px; + } + .setting-btn-wrap{ + display: flex; + align-items: center; + padding: 14px 0; + border-top: 1px solid #424242; + border-bottom: 1px solid #424242; + .setting-btn{ + display: block; + width: 100%; + height: 40px; + font-size: 13px; + color: #fff; + font-weight: 700; + border-radius: 2px; + transition: all .15s ease-in-out; + &.green{ + background-color: #305941; + border: 1px solid #45CD7D; + &:hover{ + background-color: #3a6b4e; + } + } + &.blue{ + background-color: #2E5360; + border: 1px solid #3FBAE6; + &:hover{ + background-color: #365f6e; + } + } + } } - } } // 지붕형상 설정 -.roof-shape-menu { - display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr; - grid-template-rows: 1fr 1fr; - gap: 24px 10px; - margin-bottom: 24px; - .shape-box { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - padding: 13px; - background-color: #3d3d3d; - transition: background 0.15s ease-in-out; - img { - max-width: 100%; - } - } - .shape-title { - font-size: $pop-normal-size; - font-weight: $pop-bold-weight; - color: $pop-color; - margin-top: 10px; - text-align: center; - transition: color 0.15s ease-in-out; - } - .shape-menu-box { - &.act, - &:hover { - .shape-box { - background-color: #008bff; - } - .shape-title { - color: #008bff; - } - } - } -} - -.setting-box { - padding: 14px 0; - border-top: 1px solid #424242; - border-bottom: 1px solid #424242; -} -.padding-form { - padding-left: 23px; -} -.discrimination-box { - padding: 16px 12px; - border: 1px solid #3d3d3d; - border-radius: 2px; -} - -.modal-bottom-border-bx { - margin-top: 24px; - padding-bottom: 14px; - border-bottom: 1px solid #424242; -} - -// 처마∙케라바 변경 -.eaves-keraba-table { - display: table; - border-collapse: collapse; - .eaves-keraba-item { - display: table-row; - .eaves-keraba-th, - .eaves-keraba-td { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - display: table-cell; - vertical-align: middle; - padding-bottom: 14px; - } - .eaves-keraba-td { - padding-left: 10px; - } - .eaves-keraba-ico { - display: flex; - align-items: center; - justify-content: center; - padding: 5px; - background-color: #3d3d3d; - border: 1px solid #3d3d3d; - border-radius: 2px; - cursor: pointer; - &.act { - border: 1px solid #ed0004; - } - } - &:last-child { - .eaves-keraba-th, - .eaves-keraba-td { - padding-bottom: 0; - } - } - } -} -.guide { - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: $pop-color; - margin-bottom: 24px; - &.sm { - margin-bottom: 15px; - } - span { - display: block; - } -} - -// 지붕면 할당 -.allocation-select-wrap { - display: flex; - align-items: center; - padding-bottom: 14px; - border-bottom: 1px solid #424242; - margin-bottom: 14px; - span { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - margin-right: 10px; - } - .allocation-edit { - display: flex; - align-items: center; - height: 30px; - padding: 0 10px; - margin-left: 5px; - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - border: 1px solid #484848; - background-color: #323234; - i { - display: block; - width: 12px; - height: 12px; - margin-right: 5px; - background: url(../../public/static/images/canvas/allocation_edit.svg) no-repeat center; - background-size: cover; - } - } -} - -.block-box { - display: flex; - align-items: center; - gap: 10px; - margin-bottom: 10px; - .flex-ment { - gap: 10px; - .dec { - text-decoration: underline; - } - .delete { - display: block; - width: 15px; - height: 15px; - background: url(../../public/static/images/canvas/allocation_delete.svg) no-repeat center; - background-size: cover; - } - } - &:last-child { - margin-bottom: 0; - } -} - -.icon-btn-wrap { - flex: 1; - display: flex; - align-items: center; - gap: 5px; - button { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 30px; - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: $pop-color; - border: 1px solid #646464; - border-radius: 2px; - padding: 0 10px; - transition: all 0.15s ease-in-out; - i { - height: 15px; - display: block; - margin-left: 10px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - transition: all 0.15s ease-in-out; - &.allocation01 { - background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg); - width: 15px; - } - &.allocation02 { - background-image: url(../../public/static/images/canvas/allocation_icon02_white.svg); - width: 18px; - } - } - &.act, - &:hover { - color: #101010; - border: 1px solid #101010; - background-color: #fff; - i { - &.allocation01 { - background-image: url(../../public/static/images/canvas/allocation_icon01_black.svg); - } - &.allocation02 { - background-image: url(../../public/static/images/canvas/allocation_icon02_black.svg); - } - } - } - } -} - -// 경사설정 -.slope-wrap { - padding-bottom: 24px; - border-bottom: 1px solid #424242; -} - -// 면형상 배치 -.plane-frame-wrap { - display: flex; - gap: 10px; - .plane-shape-wrap { - flex: none; - width: 73px; - } -} - -.plane-shape-menu { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 5px; - .shape-menu-box { - border-radius: 2px; - width: 34px; - height: 34px; - background-color: #373737; - border: 1px solid #676767; - transition: - background 0.15s ease-in-out, - border 0.15s ease-in-out; - .shape-box { - display: flex; - justify-content: center; - align-items: center; - position: relative; - width: 100%; - height: 100%; - border-radius: 2px; - } - &.act, - &:hover { - border-color: #008bff; - background-color: #008bff; - } - } -} - -.shape-library { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 5px; - padding-top: 5px; - .library-btn { - width: 100%; - height: 34px; - border: 1px solid #6c6c6c; - border-radius: 2px; - background-color: #373737; - background-repeat: no-repeat; - background-position: center; - transition: all 0.15s ease-in-out; - &.ico01 { - background-image: url(../../public/static/images/canvas/shape_labrary01.svg); - background-size: 19px 18px; - } - &.ico02 { - background-image: url(../../public/static/images/canvas/shape_labrary02.svg); - background-size: 15px 20px; - } - &.ico03 { - background-image: url(../../public/static/images/canvas/shape_labrary03.svg); - background-size: 19px 16px; - } - &:hover { - border-color: #1083e3; - background-color: #1083e3; - } - } -} - -.plane-detail-wrap { - display: flex; - flex-direction: column; - flex: 1; -} -.plane-shape-wrapper { - flex: 1; - display: flex; - flex-direction: column; - gap: 10px; - .plane-box { - width: 100%; - padding: 10px 18px; - border-radius: 2px; - background-color: #313131; - border: 1px solid #484848; - .plane-box-tit { - font-size: $pop-normal-size; - font-weight: 600; - color: $pop-color; - margin-bottom: 10px; - } - &.shape-box { - .shape-box-inner { - display: flex; - gap: 15px; - min-height: 140px; - .shape-img { - position: relative; - flex: none; - width: 150px; - background-color: #fff; - border-radius: 2px; - img { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } - } - .shape-data { - flex: 1; - .eaves-keraba-table { - .eaves-keraba-item { - .eaves-keraba-th, - .eaves-keraba-td { - padding-bottom: 10px; - } - &:last-child { - .eaves-keraba-th, - .eaves-keraba-td { - padding-bottom: 0px; - } - } - } - } - } - } - } - &.direction-box { - flex: 1; - display: flex; - flex-direction: column; - .plane-direction-box { - flex: 1; +.roof-shape-menu{ + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-rows: 1fr 1fr; + gap: 24px 10px; + margin-bottom: 24px; + .shape-box{ display: flex; align-items: center; justify-content: center; width: 100%; - } + padding: 13px; + background-color: #3D3D3D; + transition: background .15s ease-in-out; + img{ + max-width: 100%; + } } - } -} -.plane-direction { - width: 150px; - position: relative; - height: 120px; - span { - position: absolute; - font-size: 12px; - font-weight: 500; - color: #b1b1b1; - &.top { - top: 0; - left: 50%; - transform: translateX(-50%); + .shape-title{ + font-size: $pop-normal-size; + font-weight: $pop-bold-weight; + color: $pop-color; + margin-top: 10px; + text-align: center; + transition: color .15s ease-in-out; } - &.right { - top: 50%; - right: 0; - transform: translateY(-50%); + .shape-menu-box{ + &.act, + &:hover{ + .shape-box{background-color: #008BFF;} + .shape-title{color: #008BFF;} + } } - &.bottom { - bottom: 0; - left: 50%; - transform: translateX(-50%); - } - &.left { - top: 50%; - left: 0; - transform: translateY(-50%); - } - } - .plane-btn { - position: absolute; - width: 28px; - height: 28px; - background-color: #777777; - background-image: url(../../public/static/images/canvas/plane_arr.svg); - background-size: 12px 13px; - background-repeat: no-repeat; - background-position: center; - border-radius: 50%; - transition: all 0.15s ease-in-out; - &.up { - top: 22px; - left: 50%; - transform: translateX(-50%); - } - &.right { - top: 50%; - right: 32px; - transform: translateY(-50%) rotate(90deg); - } - &.down { - bottom: 22px; - left: 50%; - transform: translateX(-50%) rotate(180deg); - } - &.left { - top: 50%; - left: 32px; - transform: translateY(-50%) rotate(270deg); - } - &:hover, - &.act { - background-color: #fff; - background-image: url(../../public/static/images/canvas/plane_arr_act.svg); - } - } } -.plane-tab-guide { - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: $pop-color; - margin-top: 10px; +.setting-box{ + padding: 14px 0; + border-top: 1px solid #424242; + border-bottom: 1px solid #424242; } -.plane-shape-btn { - padding-top: 10px; - margin-top: auto; - button { - display: block; - width: 100%; - } +.padding-form{ + padding-left: 23px; +} +.discrimination-box{ + padding: 16px 12px; + border: 1px solid #3D3D3D; + border-radius: 2px; } -// 오브젝트 배치 -.mb-box { - margin-bottom: 24px; +.modal-bottom-border-bx{ + margin-top: 24px; + padding-bottom: 14px; + border-bottom: 1px solid #424242; } -.object-direction-wrap { - display: flex; - align-items: center; - justify-content: center; -} -.discrimination-tit { - font-size: 13px; - color: #fff; - font-weight: 500; -} - -.object-size-wrap { - display: flex; - min-height: 206px; - gap: 24px; - margin-top: 14px; - .object-size-img { - position: relative; - flex: none; - width: 200px; - background-color: #fff; - img { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); +// 처마∙케라바 변경 +.eaves-keraba-table{ + display: table; + border-collapse: collapse; + .eaves-keraba-item{ + display: table-row; + .eaves-keraba-th, + .eaves-keraba-td{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + display: table-cell; + vertical-align: middle; + padding-bottom: 14px; + } + .eaves-keraba-td{ + padding-left: 10px; + } + .eaves-keraba-ico{ + display: flex; + align-items: center; + justify-content: center; + padding: 5px; + background-color: #3D3D3D; + border: 1px solid #3D3D3D; + border-radius: 2px; + cursor: pointer; + &.act{ + border: 1px solid #ED0004; + } + } + &:last-child{ + .eaves-keraba-th, + .eaves-keraba-td{ + padding-bottom: 0; + } + } + } +} +.guide{ + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: $pop-color; + margin-bottom: 24px; + &.sm{ + margin-bottom: 15px; + } + span{ + display: block; } - } } -// 표시변경 -.display-change-wrap { - margin: 24px 0; -} -.warning { - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: #ffafaf; +// 지붕면 할당 +.allocation-select-wrap{ + display: flex; + align-items: center; + padding-bottom: 14px; + border-bottom: 1px solid #424242; + margin-bottom: 14px; + span{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + margin-right: 10px; + } + .allocation-edit{ + display: flex; + align-items: center; + height: 30px; + padding: 0 10px; + margin-left: 5px; + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + border: 1px solid #484848; + background-color: #323234; + i{ + display: block; + width: 12px; + height: 12px; + margin-right: 5px; + background: url(../../public/static/images/canvas/allocation_edit.svg)no-repeat center; + background-size: cover; + } + } } -// 각 변 속성 변경 -.radio-grid-wrap { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 24px 15px; +.block-box{ + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 10px; + .flex-ment{ + gap: 10px; + .dec{ + text-decoration: underline; + } + .delete{ + display: block; + width: 15px; + height: 15px; + background: url(../../public/static/images/canvas/allocation_delete.svg)no-repeat center; + background-size: cover; + } + } + &:last-child{ + margin-bottom: 0; + } } -// 면 흐름 설정 -.drawing-flow-wrap { - display: flex; - gap: 10px; - .discrimination-box { +.icon-btn-wrap{ + flex: 1; + display: flex; + align-items: center; + gap: 5px; + button{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 30px; + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: $pop-color; + border: 1px solid #646464; + border-radius: 2px; + padding: 0 10px; + transition: all .15s ease-in-out; + i{ + height: 15px; + display: block; + margin-left: 10px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + transition: all .15s ease-in-out; + &.allocation01{ + background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg); + width: 15px; + } + &.allocation02{ + background-image: url(../../public/static/images/canvas/allocation_icon02_white.svg); + width: 18px; + } + } + &.act, + &:hover{ + color: #101010; + border: 1px solid #101010; + background-color: #fff; + i{ + &.allocation01{ + background-image: url(../../public/static/images/canvas/allocation_icon01_black.svg); + } + &.allocation02{ + background-image: url(../../public/static/images/canvas/allocation_icon02_black.svg); + } + } + } + } +} + +// 경사설정 +.slope-wrap{ + padding-bottom: 24px; + border-bottom: 1px solid #424242; +} + +// 면형상 배치 +.plane-frame-wrap{ + display: flex; + gap: 10px; + .plane-shape-wrap{ + flex: none; + width: 73px; + } +} + +.plane-shape-menu{ + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 5px; + .shape-menu-box{ + border-radius: 2px; + width: 34px; + height: 34px; + background-color: #373737; + border: 1px solid #676767; + transition: background .15s ease-in-out, border .15s ease-in-out; + .shape-box{ + display: flex; + justify-content: center; + align-items: center; + position: relative; + width: 100%; + height: 100%; + border-radius: 2px; + } + &.act, + &:hover{ + border-color: #008BFF; + background-color: #008BFF; + } + } +} + +.shape-library{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 5px; + padding-top: 5px; + .library-btn{ + width: 100%; + height: 34px; + border: 1px solid #6C6C6C; + border-radius: 2px; + background-color: #373737; + background-repeat: no-repeat; + background-position: center; + transition: all .15s ease-in-out; + &.ico01{background-image: url(../../public/static/images/canvas/shape_labrary01.svg); background-size: 19px 18px;} + &.ico02{background-image: url(../../public/static/images/canvas/shape_labrary02.svg); background-size: 15px 20px;} + &.ico03{background-image: url(../../public/static/images/canvas/shape_labrary03.svg); background-size: 19px 16px;} + &:hover{ + border-color: #1083E3; + background-color: #1083E3; + } + } +} + +.plane-detail-wrap{ + display: flex; + flex-direction: column; + flex: 1; +} +.plane-shape-wrapper{ flex: 1; display: flex; flex-direction: column; - .object-direction-wrap { - flex: 1; + gap: 10px; + .plane-box{ + width: 100%; + padding: 10px 18px; + border-radius: 2px; + background-color: #313131; + border: 1px solid #484848; + .plane-box-tit{ + font-size: $pop-normal-size; + font-weight: 600; + color: $pop-color; + margin-bottom: 10px; + } + &.shape-box{ + .shape-box-inner{ + display: flex; + gap:15px; + min-height: 140px; + .shape-img{ + position: relative; + flex: none; + width: 150px; + background-color: #fff; + border-radius: 2px; + img{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + } + .shape-data{ + flex: 1; + .eaves-keraba-table{ + .eaves-keraba-item{ + .eaves-keraba-th, + .eaves-keraba-td{ + padding-bottom: 10px; + } + &:last-child{ + .eaves-keraba-th, + .eaves-keraba-td{ + padding-bottom: 0px; + } + } + } + } + } + } + } + &.direction-box{ + flex: 1; + display: flex; + flex-direction: column; + .plane-direction-box{ + flex: 1; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + } + } + } +} +.plane-direction{ + width: 150px; + position: relative; + height: 120px; + span{ + position: absolute; + font-size: 12px; + font-weight: 500; + color: #B1B1B1; + &.top{top: 0; left: 50%; transform: translateX(-50%);} + &.right{top: 50%; right: 0; transform: translateY(-50%);} + &.bottom{bottom: 0; left: 50%; transform: translateX(-50%);} + &.left{top: 50%; left: 0; transform: translateY(-50%);} + } + .plane-btn{ + position: absolute; + width: 28px; + height: 28px; + background-color: #777777; + background-image: url(../../public/static/images/canvas/plane_arr.svg); + background-size: 12px 13px; + background-repeat: no-repeat; + background-position: center; + border-radius: 50%; + transition: all .15s ease-in-out; + &.up{top: 22px; left: 50%; transform: translateX(-50%);} + &.right{top: 50%; right: 32px; transform: translateY(-50%) rotate(90deg);} + &.down{bottom: 22px; left: 50%; transform: translateX(-50%) rotate(180deg);} + &.left{top: 50%; left: 32px; transform: translateY(-50%) rotate(270deg);} + &:hover, + &.act{ + background-color: #fff; + background-image: url(../../public/static/images/canvas/plane_arr_act.svg); + } } - } } -.compas-box { - display: flex; - align-items: center; - justify-content: center; +.plane-tab-guide{ + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: $pop-color; + margin-top: 10px; +} +.plane-shape-btn{ + padding-top: 10px; + margin-top: auto; + button{ + display: block; + width: 100%; + } +} + +// 오브젝트 배치 +.mb-box{ + margin-bottom: 24px; +} + +.object-direction-wrap{ + display: flex; + align-items: center; + justify-content: center; +} +.discrimination-tit{ + font-size: 13px; + color: #fff; + font-weight: 500; +} + +.object-size-wrap{ + display: flex; + min-height: 206px; + gap: 24px; + margin-top: 14px; + .object-size-img{ + position: relative; + flex: none; + width: 200px; + background-color: #fff; + img{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + } +} + +// 표시변경 +.display-change-wrap{ + margin: 24px 0; +} +.warning{ + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: #FFAFAF; +} + +// 각 변 속성 변경 +.radio-grid-wrap{ + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24px 15px; +} + +// 면 흐름 설정 +.drawing-flow-wrap{ + display: flex; + gap: 10px; + .discrimination-box{ + flex: 1; + display: flex; + flex-direction: column; + .object-direction-wrap{ + flex: 1; + } + &:first-child{ + flex: none; + width: 195px; + } + } +} + +.compas-box{ + display: flex; + align-items: center; + justify-content: center; } .compas-box-inner { - position: relative; - width: 200px; - height: 200px; - border-radius: 50%; - - .circle { - position: absolute; - width: 12px; - height: 12px; - border: 1px solid #fff; + position: relative; + width: 200px; + height: 200px; border-radius: 50%; - top: 95%; - left: 50%; - transform-origin: 0 -90px; /* 중심에서 반지름 거리만큼 떨어져 위치 */ - cursor: pointer; - z-index: 3; - /* 0번을 180도 위치(아래)에, 13번을 0도 위치(위)에 배치 */ - i { - position: absolute; - top: 12.5px; - left: 50%; - font-size: 11px; - color: #8b8b8b; - font-weight: 500; - -webkit-user-select: none; - -moz-user-select: none; - -ms-use-select: none; - user-select: none; + + .circle { + position: absolute; + width: 12px; + height: 12px; + border: 1px solid #fff; + border-radius: 50%; + top: 95%; + left: 50%; + transform-origin: 0 -90px; /* 중심에서 반지름 거리만큼 떨어져 위치 */ + cursor:pointer; + z-index: 3; + /* 0번을 180도 위치(아래)에, 13번을 0도 위치(위)에 배치 */ + i{ + position: absolute; + top: 12.5px; + left: 50%; + font-size: 11px; + color: #8B8B8B; + font-weight: 500; + -webkit-user-select: none; + -moz-user-select: none; + -ms-use-select: none; + user-select: none; + } + &:nth-child(1) { transform: rotate(180deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(180deg);}} + &:nth-child(2) { transform: rotate(195deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(165deg);}} + &:nth-child(3) { transform: rotate(210deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(150deg);}} + &:nth-child(4) { transform: rotate(225deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(135deg);}} + &:nth-child(5) { transform: rotate(240deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(120deg);}} + &:nth-child(6) { transform: rotate(255deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(105deg);}} + &:nth-child(7) { transform: rotate(270deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(90deg);}} + &:nth-child(8) { transform: rotate(285deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(75deg);}} + &:nth-child(9) { transform: rotate(300deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(60deg);}} + &:nth-child(10) { transform: rotate(315deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(45deg);}} + &:nth-child(11) { transform: rotate(330deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(30deg);}} + &:nth-child(12) { transform: rotate(345deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(15deg);}} + &:nth-child(13) { transform: rotate(0deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(0deg);}} + &:nth-child(14) { transform: rotate(15deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-15deg);}} + &:nth-child(15) { transform: rotate(30deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-30deg);}} + &:nth-child(16) { transform: rotate(45deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-45deg);}} + &:nth-child(17) { transform: rotate(60deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-60deg);}} + &:nth-child(18) { transform: rotate(75deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-75deg);}} + &:nth-child(19) { transform: rotate(90deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-90deg);}} + &:nth-child(20) { transform: rotate(105deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-105deg);}} + &:nth-child(21) { transform: rotate(120deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-120deg);}} + &:nth-child(22) { transform: rotate(135deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-135deg);}} + &:nth-child(23) { transform: rotate(150deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-150deg);}} + &:nth-child(24) { transform: rotate(165deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-165deg);}} + &.act{ + &::after{ + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 5px; + height: 5px; + background-color: #fff; + border-radius: 50%; + } + i{ + color: #fff; + } + } } - &:nth-child(1) { - transform: rotate(180deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(180deg); - } - } - &:nth-child(2) { - transform: rotate(195deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(165deg); - } - } - &:nth-child(3) { - transform: rotate(210deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(150deg); - } - } - &:nth-child(4) { - transform: rotate(225deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(135deg); - } - } - &:nth-child(5) { - transform: rotate(240deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(120deg); - } - } - &:nth-child(6) { - transform: rotate(255deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(105deg); - } - } - &:nth-child(7) { - transform: rotate(270deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(90deg); - } - } - &:nth-child(8) { - transform: rotate(285deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(75deg); - } - } - &:nth-child(9) { - transform: rotate(300deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(60deg); - } - } - &:nth-child(10) { - transform: rotate(315deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(45deg); - } - } - &:nth-child(11) { - transform: rotate(330deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(30deg); - } - } - &:nth-child(12) { - transform: rotate(345deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(15deg); - } - } - &:nth-child(13) { - transform: rotate(0deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(0deg); - } - } - &:nth-child(14) { - transform: rotate(15deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-15deg); - } - } - &:nth-child(15) { - transform: rotate(30deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-30deg); - } - } - &:nth-child(16) { - transform: rotate(45deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-45deg); - } - } - &:nth-child(17) { - transform: rotate(60deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-60deg); - } - } - &:nth-child(18) { - transform: rotate(75deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-75deg); - } - } - &:nth-child(19) { - transform: rotate(90deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-90deg); - } - } - &:nth-child(20) { - transform: rotate(105deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-105deg); - } - } - &:nth-child(21) { - transform: rotate(120deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-120deg); - } - } - &:nth-child(22) { - transform: rotate(135deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-135deg); - } - } - &:nth-child(23) { - transform: rotate(150deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-150deg); - } - } - &:nth-child(24) { - transform: rotate(165deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-165deg); - } - } - &.act { - &::after { - content: ''; + .compas{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - width: 5px; - height: 5px; - background-color: #fff; - } - i { - color: #fff; - } + width: 148px; + height: 148px; + border: 4px solid #fff; + border-radius: 50%; + .compas-arr{ + width: 100%; + height: 100%; + background: url(../../public/static/images/canvas/compas.svg)no-repeat center; + background-size: 122px 122px; + } } - } - .compas { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 148px; - height: 148px; - border: 4px solid #fff; - border-radius: 50%; - .compas-arr { - width: 100%; - height: 100%; - background: url(../../public/static/images/canvas/compas.svg) no-repeat center; - background-size: 122px 122px; - } - } +} + +.draw-flow-wrap{ + margin: 10px 0; } // 지붕모듈선택 -.roof-module-tab { - display: flex; - align-items: center; - gap: 10px; - margin-bottom: 14px; - .module-tab-bx { +.roof-module-tab{ + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 14px; + .module-tab-bx{ + flex: 1; + height: 34px; + line-height: 31px; + border: 1px solid #484848; + border-radius: 2px; + background-color: transparent; + font-size: 12px; + color: #AAA; + text-align: center; + cursor: default; + transition: all .15s ease-in-out; + &.act{ + background-color: #1083E3; + border: 1px solid #1083E3; + color: #fff; + font-weight: 500; + } + } + .tab-arr{ + display: block; + width: 9px; + height: 14px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + background-image: url(../../public/static/images/canvas/module_tab_arr.svg); + transition: all .15s ease-in-out; + &.act{ + background-image: url(../../public/static/images/canvas/module_tab_arr_white.svg); + } + } +} + +.roof-module-compas{ + margin-bottom: 24px; + .compas-box-inner{ + width: 280px; + height: 253px; + .circle{ + top: 86%; + &:nth-child(1), + &:nth-child(7), + &:nth-child(13), + &:nth-child(19){ + &::before{ + content: ''; + position: absolute; + top: 20px; + left: 50%; + transform: translateX(-50%); + width: 1px; + height: 6px; + background-color: #8B8B8B; + } + } + i{ + top: 32px; + } + &.act{ + i{color: #8B8B8B;} + } + } + } +} +.center-wrap{ + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; +} + +.module-table-flex-wrap{ + display: flex; + gap: 10px; + .outline-form{ + flex: 1; + } +} + +.module-box-tab{ + display: flex; + .module-btn{ + flex: 1; + border-top: 1px solid #505050; + border-bottom: 1px solid #505050; + border-right: 1px solid #505050; + background-color: #454545; + color: #fff; + height: 30px; + font-size: 12px; + font-weight: 400; + transition: all .15s ease-in-out; + &:first-child{ + border-left: 1px solid #505050; + } + &.act{ + border-color: #fff; + background-color: #fff; + color: #101010; + } + } +} + +.module-table-box{ flex: 1; - height: 34px; - line-height: 31px; - border: 1px solid #484848; + background-color: #3D3D3D; border-radius: 2px; - background-color: transparent; - font-size: 12px; - color: #aaa; - text-align: center; - cursor: default; - transition: all 0.15s ease-in-out; - &.act { - background-color: #1083e3; - border: 1px solid #1083e3; - color: #fff; - font-weight: 500; - } - } - .tab-arr { - display: block; - width: 9px; - height: 14px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - background-image: url(../../public/static/images/canvas/module_tab_arr.svg); - transition: all 0.15s ease-in-out; - &.act { - background-image: url(../../public/static/images/canvas/module_tab_arr_white.svg); - } - } -} - -.roof-module-compas { - margin-bottom: 24px; - .compas-box-inner { - width: 280px; - height: 253px; - .circle { - top: 86%; - &:nth-child(1), - &:nth-child(7), - &:nth-child(13), - &:nth-child(19) { - &::before { - content: ''; - position: absolute; - top: 20px; - left: 50%; - transform: translateX(-50%); - width: 1px; - height: 6px; - background-color: #8b8b8b; + .module-table-inner{ + padding: 10px; + .outline-form{ + span{ + width: auto; + } } - } - i { - top: 32px; - } - &.act { - i { - color: #8b8b8b; + .module-table-tit{ + padding: 10px 0; + font-size: 12px; + color: #fff; + border-bottom: 1px solid #4D4D4D; + } + .eaves-keraba-table{ + width: 100%; + margin-top: 15px; + .eaves-keraba-th{ + width: 72px; + } + .eaves-keraba-th, + .eaves-keraba-td{ + padding-bottom: 5px; + } + } + .self-table-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + padding-bottom: 15px; + } + } + .warning-guide{ + padding: 20px; + .warning{ + color: #FFCACA; + max-height: 55px; + overflow-y: auto; + padding-right: 30px; + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #D9D9D9; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } } - } } - } -} -.center-wrap { - display: flex; - flex-direction: column; - align-items: center; - gap: 20px; } -.module-table-flex-wrap { - display: flex; - gap: 10px; - .outline-form { - flex: 1; - } +.module-self-table{ + display: table; + border-top: 1px solid #4D4D4D; + border-collapse: collapse; + width: 100%; + .self-table-item{ + display: table-row; + .self-item-td, + .self-item-th{ + display: table-cell; + vertical-align: middle; + border-bottom: 1px solid #4D4D4D; + } + .self-item-th{ + width: 60px; + font-size: 12px; + font-weight: 500; + color: #fff; + } + .self-item-td{ + font-size: 12px; + font-weight: 400; + color: #fff; + padding: 15px 20px; + } + } } -.module-box-tab { - display: flex; - .module-btn { - flex: 1; - border-top: 1px solid #505050; - border-bottom: 1px solid #505050; - border-right: 1px solid #505050; - background-color: #454545; - color: #fff; - height: 30px; - font-size: 12px; - font-weight: 400; - transition: all 0.15s ease-in-out; - &:first-child { - border-left: 1px solid #505050; - } - &.act { - border-color: #fff; - background-color: #fff; - color: #101010; - } - } -} - -.module-table-box { - flex: 1; - background-color: #3d3d3d; - border-radius: 2px; - .module-table-inner { - padding: 10px; - .outline-form { - span { - width: auto; - } - } - .module-table-tit { - padding: 10px 0; - font-size: 12px; - color: #fff; - border-bottom: 1px solid #4d4d4d; - } - .eaves-keraba-table { - width: 100%; - margin-top: 15px; - .eaves-keraba-th { - width: 72px; - } - .eaves-keraba-th, - .eaves-keraba-td { - padding-bottom: 5px; - } - } - .self-table-tit { - font-size: 12px; - font-weight: 500; - color: #fff; - padding-bottom: 15px; - } - } - .warning-guide { - padding: 20px; - .warning { - color: #ffcaca; - max-height: 55px; - overflow-y: auto; - padding-right: 30px; - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9d9d9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } - } - } -} - -.module-self-table { - display: table; - border-top: 1px solid #4d4d4d; - border-collapse: collapse; - width: 100%; - .self-table-item { - display: table-row; - .self-item-td, - .self-item-th { - display: table-cell; - vertical-align: middle; - border-bottom: 1px solid #4d4d4d; - } - .self-item-th { - width: 60px; - font-size: 12px; - font-weight: 500; - color: #fff; - } - .self-item-td { - font-size: 12px; - font-weight: 400; - color: #fff; - padding: 15px 20px; - } - } -} - -.self-table-flx { - display: flex; - align-items: center; - margin-top: 15px; - button { - margin-left: auto; - } -} -.hexagonal-wrap { - .hexagonal-item { - padding: 15px 0; - border-bottom: 1px solid #4d4d4d; - &:first-child { - padding-top: 0; - } - &:last-child { - padding-bottom: 0; - border: none; - } - .hexagonal-flx-auto { - display: flex; - justify-content: space-between; - } - .hexagonal-flx { - display: flex; - align-items: center; - button { +.self-table-flx{ + display: flex; + align-items: center; + margin-top: 15px; + button{ margin-left: auto; - } } - } +} +.hexagonal-wrap{ + .hexagonal-item{ + padding: 15px 0; + border-bottom: 1px solid #4D4D4D; + &:first-child{ + padding-top: 0; + } + &:last-child{ + padding-bottom: 0; + border: none; + } + .hexagonal-flx-auto{ + display: flex; + justify-content: space-between; + } + .hexagonal-flx{ + display: flex; + align-items: center; + button{ + margin-left: auto; + } + } + } } // 회로 및 가대설정 -.circuit-check-inner { - padding: 5px 0; +.circuit-check-inner{ + padding: 5px 0; } -.x-scroll-table { - overflow-x: auto; - padding-bottom: 5px; - .roof-module-table { - min-width: 1200px; - } - &::-webkit-scrollbar { - height: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9d9d9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } -} - -.circuit-right-wrap { - display: flex; - justify-content: flex-end; -} - -.circuit-data-form { - display: flex; - flex-direction: column; - gap: 5px; - min-height: 60px; - padding: 12px; - border: 1px solid rgba(255, 255, 255, 0.2); - span { - display: inline-flex; - align-items: center; - .del { - display: block; - margin-left: 10px; - width: 15px; - height: 15px; - background: url(../../public/static/images/canvas/circuit_del.svg) no-repeat center; - background-size: cover; +.x-scroll-table{ + overflow-x: auto; + padding-bottom: 5px; + .roof-module-table{ + min-width: 1200px; + } + &::-webkit-scrollbar { + height: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #D9D9D9; + } + &::-webkit-scrollbar-track { + background-color: transparent; } - } -} -.circuit-table-tit { - color: #fff; - font-size: 12px; - font-weight: 600; - padding: 11px 10px; - background-color: #474747; - border: 1px solid #505050; - border-bottom: none; } -.circuit-overflow { - max-height: 400px; - overflow-y: auto; - margin-bottom: 15px; - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9d9d9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } +.circuit-right-wrap{ + display: flex; + justify-content: flex-end; } -.circuit-table-flx-wrap { - display: flex; - gap: 10px; - margin-bottom: 10px; - .circuit-table-flx-box { - flex: 1; +.circuit-data-form{ display: flex; flex-direction: column; - .bottom-wrap { - margin-top: auto; + gap: 5px; + min-height: 60px; + padding: 12px; + border: 1px solid rgba(255, 255, 255, 0.20); + span{ + display: inline-flex; + align-items: center; + .del{ + display: block; + margin-left: 10px; + width: 15px; + height: 15px; + background: url(../../public/static/images/canvas/circuit_del.svg)no-repeat center; + background-size: cover; + } } - .roof-module-table { - table { - table-layout: fixed; - } - } - } +} +.circuit-table-tit{ + color: #fff; + font-size: 12px; + font-weight: 600; + padding: 11px 10px; + background-color: #474747; + border: 1px solid #505050; + border-bottom: none; } -.circuit-count-input { - display: flex; - align-items: center; - gap: 10px; +.circuit-overflow{ + max-height: 400px; + overflow-y: auto; + margin-bottom: 15px; + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #D9D9D9; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } +} + +.circuit-table-flx-wrap{ + display: flex; + gap: 10px; + margin-bottom: 10px; + .circuit-table-flx-box{ + flex: 1; + display: flex; + flex-direction: column; + .bottom-wrap{ + margin-top: auto; + } + .roof-module-table{ + table{ + table-layout: fixed; + } + } + } +} + +.circuit-count-input{ + display: flex; + align-items: center; + gap: 10px; } // 모듈부가기능 -.additional-radio-wrap { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 15px 0; - margin-bottom: 24px; +.additional-radio-wrap{ + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px 0; + margin-bottom: 24px; } -.additional-wrap { - padding: 24px 0; - border-top: 1px solid #424242; +.additional-wrap{ + padding: 24px 0; + border-top: 1px solid #424242; } -.additional-color-wrap { - display: flex; - align-items: center; - padding: 5px 0; - gap: 15px; - .additional-color-box { +.additional-color-wrap{ display: flex; align-items: center; - gap: 8px; - .additional-color { - display: block; - width: 16px; - height: 16px; - &.pink { - border: 2px solid #ce1c9c; - background-color: #16417d; - } - &.white { - border: 2px solid #fff; - background-color: #001027; - } + padding: 5px 0; + gap: 15px; + .additional-color-box{ + display: flex; + align-items: center; + gap: 8px; + .additional-color{ + display: block; + width: 16px; + height: 16px; + &.pink{ + border: 2px solid #ce1c9c; + background-color: #16417D; + } + &.white{ + border: 2px solid #FFF; + background-color: #001027; + } + } } - } } // color setting -.color-setting-wrap { - padding-bottom: 15px; - border-bottom: 1px solid #424242; - .color-tit { - font-size: 13px; - font-weight: 500; - color: #ffffff; - margin-bottom: 10px; - } - .color-picker { - .react-colorful { - width: 100%; - height: auto; - gap: 20px; - .react-colorful__pointer { - width: 15px; - height: 15px; - border: 4px solid #fff; - } - .react-colorful__saturation { - border-radius: 2px; - height: 200px; - border-bottom: 5px solid #000; - } - .react-colorful__last-control { - border-radius: 2px; - height: 10px; - } - } - .hex-color-box { - display: flex; - align-items: center; - margin-top: 15px; - .color-box-tit { - font-size: 12px; - color: #fff; +.color-setting-wrap{ + padding-bottom: 15px; + border-bottom: 1px solid #424242; + .color-tit{ + font-size: 13px; font-weight: 500; - margin-right: 10px; - } - .color-hex-input { - width: 150px; - margin-right: 5px; - input { - width: 100%; - } - } - .color-box { - display: block; - width: 30px; - height: 30px; - border-radius: 4px; - } + color: #ffffff; + margin-bottom: 10px; } - .default-color-wrap { - margin-top: 25px; - .default-tit { + .color-picker{ + .react-colorful{ + width: 100%; + height: auto; + gap: 20px; + .react-colorful__pointer{ + width: 15px; + height: 15px; + border: 4px solid #Fff; + } + .react-colorful__saturation{ + border-radius: 2px; + height: 200px; + border-bottom: 5px solid #000; + } + .react-colorful__last-control{ + border-radius: 2px; + height: 10px; + } + } + .hex-color-box{ + display: flex; + align-items: center; + margin-top: 15px; + .color-box-tit{ + font-size: 12px; + color: #fff; + font-weight: 500; + margin-right: 10px; + } + .color-hex-input{ + width: 150px; + margin-right: 5px; + input{ + width: 100%; + } + } + .color-box{ + display: block; + width: 30px; + height: 30px; + border-radius: 4px; + } + } + .default-color-wrap{ + margin-top: 25px; + .default-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + .color-button-wrap{ + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 21px; + .default-color{ + display: block; + width: 100%; + height: 30px; + border-radius: 4px; + } + } + } + } +} + +// 글꼴 설정 팝업 +.font-option-warp{ + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px 5px; + margin-bottom: 15px; + .font-option-item{ + .option-item-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + } +} +.font-ex-wrap{ + margin-bottom: 15px; + .font-ex-tit{ font-size: 12px; font-weight: 500; color: #fff; margin-bottom: 10px; - } - .color-button-wrap { - display: grid; - grid-template-columns: repeat(8, 1fr); - gap: 21px; - .default-color { - display: block; - width: 100%; - height: 30px; - border-radius: 4px; - } - } } - } -} - -// 글꼴 설정 팝업 -.font-option-warp { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 15px 5px; - margin-bottom: 15px; - .font-option-item { - .option-item-tit { - font-size: 12px; - font-weight: 500; - color: #fff; - margin-bottom: 10px; + .font-ex-box{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + min-height: 80px; + background-color: #fff; } - } -} -.font-ex-wrap { - margin-bottom: 15px; - .font-ex-tit { - font-size: 12px; - font-weight: 500; - color: #fff; - margin-bottom: 10px; - } - .font-ex-box { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - min-height: 80px; - background-color: #fff; - } + } // 치수선 설정 -.font-btn-wrap { - margin-bottom: 15px; - button { - width: 100%; - height: 30px; - line-height: 28px; - } -} - -.line-color-wrap { - margin-bottom: 15px; - .color-btn { - display: block; - width: 100%; - height: 30px; - border-radius: 2px; - } -} - -.form-box { - width: 100%; - background-color: #fff; - padding: 10px 15px 20px; - .line-form { - position: relative; - display: flex; - flex-direction: column; - justify-content: flex-end; - min-width: 102px; - min-height: 40px; - margin: 0 auto; - - &::before { - content: ''; - position: absolute; - bottom: 0px; - left: 0; - width: 100%; - height: 40px; - border-left: 1px dashed #101010; - border-right: 1px dashed #101010; +.font-btn-wrap{ + margin-bottom: 15px; + button{ + width: 100%; + height: 30px; + line-height: 28px; } - .line-font-box { - .font { - display: block; - padding-bottom: 15px; - color: #101010; - text-align: center; - line-height: 1; - } - .line { - position: relative; +} + +.line-color-wrap{ + margin-bottom: 15px; + .color-btn{ display: block; width: 100%; - height: 1px; - border-radius: 30px; - &::before { - content: ''; - position: absolute; - top: 50%; - transform: translateY(-50%) rotate(45deg); - left: 1px; - width: 9px; - height: +9px; - border: 1px solid; - border-color: inherit; - border-top: none; - border-right: none; - } - &::after { - content: ''; - position: absolute; - top: 50%; - transform: translateY(-50%) rotate(45deg); - right: 1px; - width: 9px; - height: 9px; - border: 1px solid; - border-color: inherit; - border-bottom: none; - border-left: none; - } - } + height: 30px; + border-radius: 2px; + } +} + +.form-box{ + width: 100%; + background-color: #fff; + padding: 10px 15px 20px; + .line-form{ + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-end; + min-width: 102px; + min-height: 40px; + margin: 0 auto; + + &::before{ + content: ''; + position: absolute; + bottom: 0px; + left: 0; + width: 100%; + height: 40px; + border-left: 1px dashed #101010; + border-right: 1px dashed #101010; + } + .line-font-box{ + .font{ + display: block; + padding-bottom: 15px; + color: #101010; + text-align: center; + line-height: 1; + } + .line{ + position: relative; + display: block; + width: 100%; + height: 1px; + border-radius: 30px; + &::before{ + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + left: 1px; + width: 9px; + height:+ 9px; + border: 1px solid; + border-color: inherit; + border-top: none; + border-right: none; + } + &::after{ + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + right: 1px; + width: 9px; + height: 9px; + border: 1px solid; + border-color: inherit; + border-bottom: none; + border-left: none; + } + } + } } - } } // 사이즈 변경 -.size-inner-warp { - position: relative; +.size-inner-warp{ + position: relative; } -.size-check-wrap { - position: relative; - display: block; - width: 132px; - height: 132px; - margin: 0 auto; - .size-btn { - position: absolute; - width: 16px; - height: 16px; - border: 1px solid #fff; - border-radius: 50%; - &.act { - &::after { - content: ''; +.size-check-wrap{ + position: relative; + display: block; + width: 132px; + height: 132px; + margin: 0 auto; + .size-btn{ + position: absolute; + width: 16px; + height: 16px; + border: 1px solid #fff; + border-radius: 50%; + &.act{ + &::after{ + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 8px; + height: 8px; + background-color: #fff; + border-radius: 50%; + } + } + &:nth-child(1){ top: 0; left: 0; } + &:nth-child(2){ top: 0; right: 0; } + &:nth-child(3){ bottom: 0; left: 0; } + &:nth-child(4){ bottom: 0; right: 0; } + } + .size-box{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - width: 8px; - height: 8px; + width: 100px; + height: 100px; background-color: #fff; - border-radius: 50%; - } } - &:nth-child(1) { - top: 0; - left: 0; - } - &:nth-child(2) { - top: 0; - right: 0; - } - &:nth-child(3) { - bottom: 0; - left: 0; - } - &:nth-child(4) { - bottom: 0; - right: 0; - } - } - .size-box { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 100px; - height: 100px; - background-color: #fff; - } } -.size-option-top { - margin-bottom: 15px; +.size-option-top{ + margin-bottom: 15px; } -.size-option-side { - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); +.size-option-side{ + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); } -.size-option-wrap { - width: 88px; - margin: 0 auto; - .size-option { - display: flex; - align-items: center; - input { - width: 100%; - flex: 1; +.size-option-wrap{ + width: 88px; + margin: 0 auto; + .size-option{ + display: flex; + align-items: center; + input{ + width: 100%; + flex: 1; + } + span{ + flex: none; + } } - span { - flex: none; - } - } } //이미지 크기 설정 -.range-wrap { - display: flex; - align-items: center; - input { - flex: 1; - margin-right: 10px; - } - label { - flex: none; - text-align: right; - width: 38px; - font-size: 13px; - color: #fff; - font-weight: 500; - } -} +.range-wrap{ + display: flex; + align-items: center; + input{ + flex: 1; + margin-right: 10px; + } + label{ + flex: none; + text-align: right; + width: 38px; + font-size: 13px; + color: #fff; + font-weight: 500; + } +} \ No newline at end of file From 5d5fae75b58d433ff32942ff9e514aeb4a4cc951 Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 5 Nov 2024 15:41:02 +0900 Subject: [PATCH 38/63] =?UTF-8?q?=ED=8D=BC=EB=B8=94=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowDirection/FlowDirectionSetting.jsx | 46 ++++++++++--------- .../placementShape/PlacementShapeSetting.jsx | 12 +++-- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx index 8d0ce8c2..b550b424 100644 --- a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx +++ b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx @@ -60,7 +60,7 @@ export default function FlowDirectionSetting(props) { }, [compasDeg]) return ( -
    +

    {getMessage('modal.shape.flow.direction.setting')}

    -
    -
    - {Array.from({ length: 180 / 15 + 1 }).map((dot, index) => ( -
    setCompasDeg(15 * (12 + index))} - > - {13 - index} +
    +
    +
    + {Array.from({ length: 180 / 15 + 1 }).map((dot, index) => ( +
    setCompasDeg(15 * (12 + index))} + > + {13 - index} +
    + ))} + {Array.from({ length: 180 / 15 - 1 }).map((dot, index) => ( +
    setCompasDeg(15 * (index + 1))} + > + {24 - index} +
    + ))} +
    +
    - ))} - {Array.from({ length: 180 / 15 - 1 }).map((dot, index) => ( -
    setCompasDeg(15 * (index + 1))} - > - {24 - index} -
    - ))} -
    -
    diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 99b72eb4..decb7fa3 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -180,8 +180,10 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
    - {getMessage('modal.placement.initial.setting.size')} - +
    + {getMessage('modal.placement.initial.setting.size')} + +
    @@ -252,8 +254,10 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
    - {getMessage('modal.placement.initial.setting.roof.material')} - +
    + {getMessage('modal.placement.initial.setting.roof.material')} + +
    From 8c6aef853440630ae89300cdeedba009317b2247 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 5 Nov 2024 15:42:36 +0900 Subject: [PATCH 39/63] =?UTF-8?q?=EB=8F=99=EC=84=A0=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=ED=98=95=20=EC=98=AC=EB=A6=BC=EB=82=B4=EB=A6=BC=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=EB=90=9C=20object=EC=97=90=20=EB=94=B0=EB=9D=BC=20?= =?UTF-8?q?=EC=83=89=EA=B9=94=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useMovementSetting.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js index f09aee6b..2141eb43 100644 --- a/src/hooks/roofcover/useMovementSetting.js +++ b/src/hooks/roofcover/useMovementSetting.js @@ -1,10 +1,11 @@ import { useRecoilValue } from 'recoil' -import { canvasState } from '@/store/canvasAtom' +import { canvasState, currentObjectState } from '@/store/canvasAtom' import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' import { useEffect, useRef, useState } from 'react' import { useEvent } from '@/hooks/useEvent' import { POLYGON_TYPE } from '@/common/common' +import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' //동선이동 형 올림 내림 export function useMovementSetting(id) { @@ -16,6 +17,7 @@ export function useMovementSetting(id) { const { initEvent, addCanvasMouseEventListener } = useEvent() const { closePopup } = usePopup() const { getMessage } = useMessage() + const currentObject = useRecoilValue(currentObjectState) const buttonType = [ { id: 1, name: getMessage('modal.movement.flow.line.move'), type: TYPE.FLOW_LINE }, { id: 2, name: getMessage('modal.movement.flow.line.updown'), type: TYPE.UP_DOWN }, @@ -46,8 +48,11 @@ export function useMovementSetting(id) { wallLines.forEach((line) => { line.set({ visible: false }) }) + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 기존 outerLine의 selectable true outerLines.forEach((line) => { + line.set({ stroke: 'black' }) + line.set({ visible: true }) line.bringToFront() line.set({ selectable: true }) }) @@ -64,6 +69,22 @@ export function useMovementSetting(id) { } }, []) + useEffect(() => { + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 기존 outerLine의 selectable true + outerLines.forEach((line) => { + line.set({ stroke: 'black' }) + }) + if (!currentObject) { + return + } + + if (currentObject.name === OUTER_LINE_TYPE.OUTER_LINE) { + currentObject.set({ stroke: 'red' }) + currentObject.bringToFront() + } + canvas.renderAll() + }, [currentObject]) + const mouseMoveEvent = (e) => { if (typeRef.current === TYPE.FLOW_LINE) { flowLineEvent(e) From c05989f6ae10a84e65d7dff7595f43ea39b3e821 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 5 Nov 2024 15:42:56 +0900 Subject: [PATCH 40/63] =?UTF-8?q?=EC=83=89=20=EC=BD=94=EB=93=9C=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useMovementSetting.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js index 2141eb43..1c128133 100644 --- a/src/hooks/roofcover/useMovementSetting.js +++ b/src/hooks/roofcover/useMovementSetting.js @@ -79,7 +79,7 @@ export function useMovementSetting(id) { } if (currentObject.name === OUTER_LINE_TYPE.OUTER_LINE) { - currentObject.set({ stroke: 'red' }) + currentObject.set({ stroke: '#EA10AC' }) currentObject.bringToFront() } canvas.renderAll() From 708f6c8ea11f33c641e55c6cf4f08820872d0334 Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Tue, 5 Nov 2024 15:46:30 +0900 Subject: [PATCH 41/63] =?UTF-8?q?feat:=20QInput=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20number=20type=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Playground.jsx | 21 ++++- src/components/common/input/QInput.jsx | 103 +++++++++++++++++-------- 2 files changed, 90 insertions(+), 34 deletions(-) diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index d1061306..5cd4588c 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -39,6 +39,7 @@ export default function Playground() { const [color, setColor] = useState('#ff0000') const [textInput, setTextInput] = useState('') + const [numberInput, setNumberInput] = useState(null) const [radioInput, setRadioInput] = useState('') const [checkboxInput, setCheckboxInput] = useState([]) const [selectedValue, setSelectedValue] = useState('') @@ -48,6 +49,9 @@ export default function Playground() { useEffect(() => { console.log('textInput:', textInput) }, [textInput]) + useEffect(() => { + console.log('numberInput:', numberInput) + }, [numberInput]) useEffect(() => { console.log('radioInput:', radioInput) }, [radioInput]) @@ -161,8 +165,19 @@ export default function Playground() { > QInput TextInput DATA RESET - - + + +
    + + +
    - {/* {sessionState?.storeId === 'T01' && ( */} {session?.storeId === 'T01' && ( <>
    @@ -1947,10 +1943,8 @@ export default function StuffDetail() { onChange={onSelectionChange} getOptionLabel={(x) => x.saleStoreName} getOptionValue={(x) => x.saleStoreId} - // isClearable={sessionState?.storeLvl === '1' ? true : false} - isClearable={session?.storeLvl === '1' ? true : false} - // isDisabled={sessionState?.storeLvl !== '1' ? true : false} - isDisabled={session?.storeLvl !== '1' ? true : false} + isClearable={detailData.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false} + isDisabled={detailData.tempFlg === '0' ? true : session?.storeLvl !== '1' ? true : false} value={saleStoreList.filter(function (option) { return option.saleStoreId === selOptions })} @@ -1967,7 +1961,6 @@ export default function StuffDetail() {
    )} - {/* {sessionState?.storeId !== 'T01' && sessionState?.storeLvl === '1' && ( */} {session?.storeId !== 'T01' && session?.storeLvl === '1' && ( <>
    @@ -1983,8 +1976,9 @@ export default function StuffDetail() { getOptionLabel={(x) => x.saleStoreName} getOptionValue={(x) => x.saleStoreId} isClearable={false} - // isDisabled={sessionState?.storeLvl !== '1' ? true : sessionState?.storeId !== 'T01' ? true : false} - isDisabled={session?.storeLvl !== '1' ? true : session?.storeId !== 'T01' ? true : false} + isDisabled={ + detailData.tempFlg === '0' ? true : session?.storeLvl !== '1' ? true : session?.storeId !== 'T01' ? true : false + } value={showSaleStoreList.filter(function (option) { return option.saleStoreId === selOptions })} @@ -2001,7 +1995,6 @@ export default function StuffDetail() {
    )} - {/* {sessionState?.storeId !== 'T01' && sessionState?.storeLvl !== '1' && ( */} {session?.storeId !== 'T01' && session?.storeLvl !== '1' && ( <>
    @@ -2062,10 +2055,10 @@ export default function StuffDetail() { onChange={onSelectionChange2} getOptionLabel={(x) => x.saleStoreName} getOptionValue={(x) => x.saleStoreId} - // isDisabled={sessionState?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true} - isDisabled={session?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true} - // isClearable={sessionState?.storeLvl === '1' ? true : false} - isClearable={session?.storeLvl === '1' ? true : false} + isDisabled={ + detailData.tempFlg === '0' ? true : session?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true + } + isClearable={detailData.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false} value={otherSaleStoreList.filter(function (option) { return option.saleStoreId === otherSelOptions })} From 524eab2130541ba19a28a3219037d2814a365059 Mon Sep 17 00:00:00 2001 From: basssy Date: Wed, 6 Nov 2024 08:58:10 +0900 Subject: [PATCH 49/63] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 62 ----------------------------- 1 file changed, 62 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index b369defe..2603cc04 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -167,62 +167,6 @@ export default function Stuff() { } } - //그리드 체크박스 선택시 미사용 - // const getSelectedRowdata = (data) => { - // setSelectedRowData(data) - // setSelectedRowDataCount(data.length) - // } - - //물건삭제 - // const fnDeleteRowData = (data) => { - // if (data.length === 0) { - // return alert('삭제할 데이터를 선택하세요') - // } - // let errCount = 0 - // data.forEach((cell) => { - // if (!cell.objectNo) { - // if (errCount === 0) { - // alert('물건정보가 있는 행만 삭제 됩니다') - // } - // errCount++ - // } - // }) - // } - - //행추가 - // let newCount = 0 - // const addRowItems = () => { - // // console.log('girdRef::::::', gridRef.current.api) - // const newItems = [ - // { - // mission: newCount + 1, - // successful: true, - // }, - // ] - // gridRef.current.api.applyTransaction({ - // add: newItems, - // addIndex: newCount, - // }) - // newCount++ - // } - - //행삭제 - // const removeRowItems = () => { - // // console.log('selectedRowData::', selectedRowData) - // let errCount = 0 - // selectedRowData.forEach((cell) => { - // if (!cell.company) { - // let newSelectedRowData = selectedRowData.filter((item) => item.company == null) - // gridRef.current.api.applyTransaction({ remove: newSelectedRowData }) - // } else { - // if (errCount === 0) { - // alert('행추가로 추가 한 행만 삭제됩니다.') - // } - // errCount++ - // } - // }) - // } - // 진입시 그리드 데이터 조회 useEffect(() => { if (isObjectNotEmpty(session)) { @@ -297,8 +241,6 @@ export default function Stuff() { //조회를 눌렀을때 async function fetchData() { - let saleStoreId - saleStoreId = stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : session?.storeId const apiUrl = `/api/object/list?saleStoreId=${session?.storeId}&${queryStringFormatter(stuffSearchParams)}` await get({ url: apiUrl }).then((res) => { if (!isEmptyArray(res)) { @@ -330,8 +272,6 @@ export default function Stuff() { }) setPageNo(1) - let saleStoreId - saleStoreId = stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : session?.storeId const apiUrl = `/api/object/list?saleStoreId=${session?.storeId}&${queryStringFormatter(stuffSearchParams)}` get({ url: apiUrl }).then((res) => { if (!isEmptyArray(res)) { @@ -364,8 +304,6 @@ export default function Stuff() { }) setPageNo(1) - let saleStoreId - saleStoreId = stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : session?.storeId const apiUrl = `/api/object/list?saleStoreId=${session?.storeId}&${queryStringFormatter(stuffSearchParams)}` get({ url: apiUrl }).then((res) => { if (!isEmptyArray(res)) { From 9577105d23d6abe1c256aeba46da98e7853d0888 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 6 Nov 2024 10:44:59 +0900 Subject: [PATCH 50/63] =?UTF-8?q?=EB=8F=99=EC=84=A0=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useMovementSetting.js | 119 ++++++++++++++++++++-- 1 file changed, 108 insertions(+), 11 deletions(-) diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js index f872fc17..34961ea0 100644 --- a/src/hooks/roofcover/useMovementSetting.js +++ b/src/hooks/roofcover/useMovementSetting.js @@ -6,6 +6,7 @@ import { useEffect, useRef, useState } from 'react' import { useEvent } from '@/hooks/useEvent' import { POLYGON_TYPE } from '@/common/common' import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' +import { QLine } from '@/components/fabric/QLine' //동선이동 형 올림 내림 export function useMovementSetting(id) { @@ -18,6 +19,7 @@ export function useMovementSetting(id) { const { closePopup } = usePopup() const { getMessage } = useMessage() const currentObject = useRecoilValue(currentObjectState) + const selectedObject = useRef(null) const buttonType = [ { id: 1, name: getMessage('modal.movement.flow.line.move'), type: TYPE.FLOW_LINE }, { id: 2, name: getMessage('modal.movement.flow.line.updown'), type: TYPE.UP_DOWN }, @@ -40,6 +42,7 @@ export function useMovementSetting(id) { } useEffect(() => { + removeFlowLine() typeRef.current = type const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 기존 outerLine의 selectable true outerLines.forEach((line) => { @@ -85,8 +88,10 @@ export function useMovementSetting(id) { canvas.renderAll() addCanvasMouseEventListener('mouse:move', mouseMoveEvent) + addCanvasMouseEventListener('mouse:down', mouseDownEvent) return () => { initEvent() + removeFlowLine() const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) wallLines.forEach((line) => { line.set({ visible: true }) @@ -107,11 +112,14 @@ export function useMovementSetting(id) { outerLines.forEach((line) => { line.set({ stroke: 'black' }) }) - clearRef() + selectedObject.current = null + if (!currentObject) { return } + clearRef() + selectedObject.current = currentObject if (currentObject.name === OUTER_LINE_TYPE.OUTER_LINE) { currentObject.set({ stroke: '#EA10AC' }) currentObject.bringToFront() @@ -134,14 +142,91 @@ export function useMovementSetting(id) { } } - const mouseMoveEvent = (e) => { + const mouseDownEvent = (e) => { if (typeRef.current === TYPE.FLOW_LINE) { - flowLineEvent(e) + flowLineDownEvent(e) } else { - updownEvent(e) + updownDownEvent(e) } } - const flowLineEvent = (e) => { + + const removeFlowLine = () => { + const flowLine = canvas.getObjects().filter((obj) => obj.name === 'flowLine') + flowLine.forEach((line) => { + canvas.remove(line) + }) + } + + const mouseMoveEvent = (e) => { + if (typeRef.current === TYPE.FLOW_LINE) { + flowLineMoveEvent(e) + } else { + updownMoveEvent(e) + } + } + //동선 이동 마우스 클릭 이벤트 + const flowLineDownEvent = (e) => { + const target = selectedObject.current + if (!target) { + return + } + + const direction = target.direction + + removeFlowLine() + + let newPoint = [] + if (direction === 'left' || direction === 'right') { + if (FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked) { + newPoint = [ + target.x1, + target.y1 + Number(FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value / 10), + target.x2, + target.y2 + Number(FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value / 10), + ] + } else { + newPoint = [ + target.x1, + target.y1 - Number(FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value / 10), + target.x2, + target.y2 - Number(FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value / 10), + ] + } + } else { + if (FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked) { + newPoint = [ + target.x1 - Number(FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value / 10), + target.y1, + target.x2 - Number(FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value / 10), + target.y2, + ] + } else { + newPoint = [ + target.x1 + Number(FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value / 10), + target.y1, + target.x2 + Number(FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value / 10), + target.y2, + ] + } + } + + const cloned = new fabric.Line(newPoint, { + stroke: 'red', + strokeWidth: 4, + name: 'flowLine', + currentLine: target, + }) + + canvas.add(cloned) + canvas.renderAll() + canvas.discardActiveObject() + } + + //형 올림내림 마우스 클릭 이벤트 + const updownDownEvent = (e) => { + console.log('updownDownEvent') + } + const flowLineMoveEvent = (e) => { const target = canvas.getActiveObject() if (!target) { return @@ -181,7 +266,7 @@ export function useMovementSetting(id) { canvas?.renderAll() } - const updownEvent = (e) => { + const updownMoveEvent = (e) => { const target = canvas.getActiveObject() if (!target) { return @@ -222,12 +307,24 @@ export function useMovementSetting(id) { const handleSave = () => { if (type === TYPE.FLOW_LINE) { - // 동선이동 - if (FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked) { - // 높이 변경: 아래, 왼쪽 체크 - } else { - // 높이 변경: 위, 오른쪽 체크 + const flowLine = canvas.getObjects().find((obj) => obj.name === 'flowLine') + + const currentLine = flowLine.currentLine + if (!flowLine || !currentLine) { + return } + + currentLine.set({ + x1: flowLine.x1, + y1: flowLine.y1, + x2: flowLine.x2, + y2: flowLine.y2, + }) + currentLine.startPoint = { x: flowLine.x1, y: flowLine.y1 } + currentLine.endPoint = { x: flowLine.x2, y: flowLine.y2 } + + canvas.remove(flowLine) + canvas.renderAll() } else { // 형 올림내림 if (UP_DOWN_REF.UP_RADIO_REF.current.checked) { From daf6bd4e009582ea81138b410df3f73a26ab48c1 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 6 Nov 2024 12:44:35 +0900 Subject: [PATCH 51/63] =?UTF-8?q?=EB=B0=B0=EC=B9=98=EB=A9=B4=20=EC=98=A4?= =?UTF-8?q?=EB=B8=8C=EC=A0=9D=ED=8A=B8=20=EC=9D=B4=EB=8F=99=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 17 ++ .../floor-plan/modal/object/SizeSetting.jsx | 16 +- src/hooks/common/useCanvasConfigInitialize.js | 9 +- src/hooks/object/useObjectBatch.js | 50 +++-- src/hooks/surface/useSurfaceShapeBatch.js | 208 ++++++++++++++++++ src/hooks/useContextMenu.js | 9 +- src/hooks/usePlan.js | 8 +- 7 files changed, 288 insertions(+), 29 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 5d1bad29..44cbfb37 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -137,6 +137,22 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }) }) + this.on('polygonMoved', () => { + //폴리곤일때만 사용 + let matrix = this.calcTransformMatrix() + + let transformedPoints = this.get('points') + .map((p) => { + return new fabric.Point(p.x - this.pathOffset.x, p.y - this.pathOffset.y) + }) + .map((p) => { + return fabric.util.transformPoint(p, matrix) + }) + this.set('points', transformedPoints) + this.set('pathOffset', { x: this.left, y: this.top }) + this.setCoords() + }) + // polygon.fillCell({ width: 50, height: 30, padding: 10 }) }, @@ -211,6 +227,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { let points = this.getCurrentPoints() + this.texts = [] points.forEach((start, i) => { const end = points[(i + 1) % points.length] const dx = end.x - start.x diff --git a/src/components/floor-plan/modal/object/SizeSetting.jsx b/src/components/floor-plan/modal/object/SizeSetting.jsx index 1b20b853..333150ea 100644 --- a/src/components/floor-plan/modal/object/SizeSetting.jsx +++ b/src/components/floor-plan/modal/object/SizeSetting.jsx @@ -8,6 +8,8 @@ import { contextPopupPositionState } from '@/store/popupAtom' import { useRef, useState, useEffect } from 'react' import { useObjectBatch } from '@/hooks/object/useObjectBatch' import { useEvent } from '@/hooks/useEvent' +import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common' +import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' export default function SizeSetting(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) @@ -15,8 +17,8 @@ export default function SizeSetting(props) { const { id, pos = contextPopupPosition, target } = props const { getMessage } = useMessage() const { closePopup } = usePopup() - const { reSizeObjectBatch } = useObjectBatch({}) - + const { resizeObjectBatch } = useObjectBatch({}) + const { reSizePolygon } = useSurfaceShapeBatch() const widthRef = useRef(null) const heightRef = useRef(null) @@ -30,7 +32,15 @@ export default function SizeSetting(props) { const width = widthRef.current.value const height = heightRef.current.value - reSizeObjectBatch(settingTarget, target, width, height) + if ( + target.name === BATCH_TYPE.OPENING || + target.name === BATCH_TYPE.SHADOW || + target.name === BATCH_TYPE.TRIANGLE_DORMER || + target.name === BATCH_TYPE.PENTAGON_DORMER || + target.name === POLYGON_TYPE.ROOF + ) { + resizeObjectBatch(settingTarget, target, width, height) + } } return ( diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js index 8d8eb38b..c4f137b0 100644 --- a/src/hooks/common/useCanvasConfigInitialize.js +++ b/src/hooks/common/useCanvasConfigInitialize.js @@ -100,8 +100,6 @@ export function useCanvasConfigInitialize() { const groups = canvas.getObjects().filter((obj) => obj.groupYn && obj.name === 'dimensionGroup') const groupIds = [] - console.log('groupDimensionInit', groups) - groups.forEach((group) => { if (!groupIds.includes(group.id)) { groupIds.push(group.id) @@ -157,6 +155,7 @@ export function useCanvasConfigInitialize() { //그룹아이디로 캔버스의 객체를 조회함 const groupObjects = canvas.getObjects().filter((obj) => obj.groupId === id || obj.id === id) const objectsName = canvas.getObjects().filter((obj) => obj.groupId === id || obj.id === id)[0].groupName + const objectsParentId = canvas.getObjects().filter((obj) => obj.groupId === id || obj.id === id)[0].parentId let objectArray = [] @@ -181,8 +180,14 @@ export function useCanvasConfigInitialize() { lockMovementY: true, originX: 'center', originY: 'center', + parentId: objectsParentId, }) canvas.add(group) + + //그룹 객체 재그룹 완료 + group.getObjects().forEach((obj) => { + obj.fire('modified') + }) }) } diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index 19cbadec..3fb47cee 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -33,10 +33,16 @@ export function useObjectBatch({ isHidden, setIsHidden }) { }, []) const dbClickEvent = () => { + console.log('dbClickEvent 실행') const dormerObject = canvas.getObjects().filter((obj) => obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) + console.log('dormerObject', dormerObject) + if (dormerObject) { + canvas.off('mouse:dblclick') canvas.on('mouse:dblclick', (e) => { + console.log('event', e) + if (e.target && e.target instanceof fabric.Group) { const pointer = canvas.getPointer(e.e) const objects = e.target._objects @@ -71,7 +77,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { let rect, isDown, origX, origY let selectedSurface //프리입력 - console.log('useObjectBatch', isHidden) + if (selectedType === INPUT_TYPE.FREE) { addCanvasMouseEventListener('mouse:down', (e) => { isDown = true @@ -160,7 +166,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { } isDown = false - rect.set({ name: objName }) + rect.set({ name: objName, parentId: selectedSurface.id }) rect.setCoords() initEvent() @@ -204,6 +210,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { lockRotation: true, lockScalingX: true, lockScalingY: true, + parentId: selectedSurface.id, }) //개구냐 그림자냐에 따라 변경 @@ -241,7 +248,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { } isDown = false - rect.set({ name: objName }) + rect.set({ name: objName, parentId: selectedSurface.id }) rect.setCoords() initEvent() if (setIsHidden) setIsHidden(false) @@ -483,6 +490,9 @@ export function useObjectBatch({ isHidden, setIsHidden }) { subTargetCheck: true, name: dormerName, id: id, + parentId: selectedSurface.id, + originX: 'center', + originY: 'center', }) canvas?.add(objectGroup) @@ -693,6 +703,10 @@ export function useObjectBatch({ isHidden, setIsHidden }) { subTargetCheck: true, name: dormerName, id: id, + parentId: selectedSurface.id, + groupYn: true, + originX: 'center', + originY: 'center', }) canvas?.add(objectGroup) @@ -858,9 +872,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { return [leftPoints, rightPoints] } - const reSizeObjectBatch = (side, target, width, height) => { - const targetObj = canvas.getActiveObject() - + const resizeObjectBatch = (side, target, width, height) => { const objectWidth = target.width const objectHeight = target.height const changeWidth = (width / 10 / objectWidth).toFixed(2) @@ -884,7 +896,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) { const newCoords = target.getPointByOrigin(sideX, sideY) target.set({ - ...target, originX: sideX, originY: sideY, left: newCoords.x, @@ -894,8 +905,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) { target.setCoords() canvas?.renderAll() //변경 좌표를 한번 적용 - target.scaleX = changeWidth === 0 ? 1 : changeWidth - target.scaleY = changeHeight === 0 ? 1 : changeHeight + target.scaleX = changeWidth || 1 + target.scaleY = changeHeight || 1 //크기 변경후 좌표를 재 적용 const changedCoords = target.getPointByOrigin('center', 'center') @@ -910,9 +921,12 @@ export function useObjectBatch({ isHidden, setIsHidden }) { if (target.name === 'roof') { //얘는 일단 도머에 적용함 - target._objects.forEach((obj) => { - setSurfaceShapePattern(obj) - }) + if (target.type === 'group') { + target._objects.forEach((obj) => setSurfaceShapePattern(obj)) + } else { + setSurfaceShapePattern(target) + target.fire('modified') + } } // target.setCoords() canvas.renderAll() @@ -923,27 +937,29 @@ export function useObjectBatch({ isHidden, setIsHidden }) { const reGroupObject = (groupObj) => { groupObj._restoreObjectsState() //이건 실행만 되도 그룹이 변경됨 const reGroupObjects = [] - groupObj._objects.forEach((obj) => { const newObj = new QPolygon(obj.getCurrentPoints(), { ...obj, points: obj.getCurrentPoints(), scaleX: 1, scaleY: 1, + texts: [], }) reGroupObjects.push(newObj) canvas.remove(obj) - if (obj.direction) { drawDirectionArrow(obj) } + newObj.fire('modified') }) - const reGroup = new fabric.Group(reGroupObjects, { subTargetCheck: true, name: groupObj.name, id: groupObj.id, groupYn: true, + parentId: groupObj.parentId, + originX: 'center', + originY: 'center', }) canvas?.add(reGroup) canvas?.remove(groupObj) @@ -965,7 +981,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { }) initEvent() obj.setCoords() - reGroupObject(obj) + if (obj.type === 'group') reGroupObject(obj) }) } } @@ -975,7 +991,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { applyDormers, splitDormerTriangle, splitDormerPentagon, - reSizeObjectBatch, + resizeObjectBatch, moveObjectBatch, } } diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index 2bfefb98..9457169c 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -12,10 +12,12 @@ import { useEvent } from '@/hooks/useEvent' import { usePopup } from '@/hooks/usePopup' import { roofDisplaySelector } from '@/store/settingAtom' import { usePolygon } from '@/hooks/usePolygon' +import { fontSelector } from '@/store/fontAtom' export function useSurfaceShapeBatch() { const { getMessage } = useMessage() const { drawDirectionArrow } = usePolygon() + const lengthTextFont = useRecoilValue(fontSelector('lengthText')) const canvas = useRecoilValue(canvasState) const globalPitch = useRecoilValue(globalPitchState) @@ -598,8 +600,214 @@ export function useSurfaceShapeBatch() { }) } + const findAllChildren = (parentId) => { + let allChildren = [] + + // 직계 자식 객체들 찾기 + const directChildren = canvas.getObjects().filter((obj) => obj.parentId === parentId) + + directChildren.forEach((child) => { + allChildren.push(child) // 현재 자식 추가 + + // 자식이 그룹인 경우 + if (child.type === 'group') { + // 그룹 내부의 객체들 추가 + child.getObjects().forEach((groupItem) => { + allChildren.push(groupItem) + // 그룹 내부 객체의 자식들도 찾기 + const nestedChildren = findAllChildren(groupItem.id) + allChildren.push(...nestedChildren) + }) + } + + // 현재 자식의 하위 자식들 찾기 + const childrenOfChild = findAllChildren(child.id) + allChildren.push(...childrenOfChild) + }) + + // 중복 제거하여 반환 + return [...new Set(allChildren)] + } + + const findGroupObjects = (parentId) => { + let groupObjectsArray = [] + + // 직계 자식 객체들 찾기 + const directChildren = canvas.getObjects().filter((obj) => obj.parentId === parentId) + + // 각 자식 객체에 대해 처리 + directChildren.forEach((child) => { + groupObjectsArray.push(child) // 현재 자식 추가 + + // 자식이 그룹인 경우 그룹 내부 객체들도 처리 + if (child.type === 'group') { + child.getObjects().forEach((groupItem) => { + // 그룹 내부 각 아이템의 하위 객체들 찾기 + const nestedObjects = findGroupObjects(groupItem.id) + groupObjectsArray.push(...nestedObjects) + }) + } + + // 일반 자식의 하위 객체들 찾기 + const childObjects = findGroupObjects(child.id) + groupObjectsArray.push(...childObjects) + }) + + return groupObjectsArray + } + + function getAllRelatedObjects(id) { + const result = [] + const map = new Map() + + // Create a map of objects by their id + canvas.getObjects().forEach((obj) => { + map.set(obj.id, obj) + }) + + // Helper function to recursively find all related objects + function findRelatedObjects(id) { + const obj = map.get(id) + if (obj) { + result.push(obj) + canvas.getObjects().forEach((o) => { + if (o.parentId === id) { + findRelatedObjects(o.id) + } + }) + } + } + + // Start the search with the given parentId + findRelatedObjects(id) + + return result + } + + const moveSurfaceShapeBatch = () => { + const roof = canvas.getActiveObject() + + if (roof) { + let isDragging = false + + const childrenObjects = canvas.getObjects().filter((obj) => obj.parentId === roof.id) + + console.log('childrenObjects', childrenObjects) + + // const groupObjects = canvas.getObjects().filter((obj) => obj.parentId === roof.id && obj.type === 'group') + + // const ungroupObjects = [] // 그룹 해제된 객체들 + // const groupChildObjects = [] + + // groupObjects.forEach((obj) => { + // obj._restoreObjectsState() + // obj.getObjects().forEach((o) => { + // o.set({ + // ungroupYn: true, + // }) + // canvas.add(o) + // ungroupObjects.push(o) + // }) + // canvas.remove(obj) + // }) + + // const childObjects = findAllChildren(roof.id) + // groupObjects.forEach((obj) => { + // groupChildObjects.push(...obj.getObjects()) + // }) + + // console.log('ungroupObjects', ungroupObjects) + // console.log('childObjects', childObjects) + // console.log('groupChildObjects', groupChildObjects) + + // const children = canvas.getObjects().filter((obj) => obj.parentId === roof.id) + // let grandChildren = [] + + // children.forEach((child) => { + // if (child.type === 'group') { + // child.getObjects().forEach((grandChild) => { + // const groupObjects = canvas.getObjects().filter((obj) => obj.parentId === grandChild.id) + // grandChildren.push(...groupObjects) + // }) + // } else { + // grandChildren.push(...canvas.getObjects().filter((obj) => obj.parentId === child.id)) + // } + // }) + + const selectionArray = [roof, ...childrenObjects] + + const selection = new fabric.ActiveSelection(selectionArray, { + canvas: canvas, + draggable: true, + lockMovementX: false, // X축 이동 허용 + lockMovementY: false, // Y축 이동 허용 + originX: 'center', + originY: 'center', + }) + + canvas.setActiveObject(selection) + + addCanvasMouseEventListener('mouse:up', (e) => { + isDragging = false + canvas.selection = true + + canvas.discardActiveObject() // 모든 선택 해제 + canvas.requestRenderAll() // 화면 업데이트 + + selection.getObjects().forEach((obj) => { + obj.set({ + lockMovementX: true, + lockMovementY: true, + }) + obj.setCoords() + + if (obj.type === 'group') { + reGroupObject(obj) + } + }) + + canvas.renderAll() + roof.fire('polygonMoved') + if (roof.type === 'group') reGroupObject(obj) + drawDirectionArrow(roof) + initEvent() + }) + } + } + + const reGroupObject = (groupObj) => { + groupObj._restoreObjectsState() //이건 실행만 되도 그룹이 변경됨 + const reGroupObjects = [] + + groupObj._objects.forEach((obj) => { + const newObj = new QPolygon(obj.getCurrentPoints(), { + ...obj, + points: obj.getCurrentPoints(), + scaleX: 1, + scaleY: 1, + }) + reGroupObjects.push(newObj) + canvas.remove(obj) + + if (obj.direction) { + drawDirectionArrow(obj) + } + }) + + const reGroup = new fabric.Group(reGroupObjects, { + subTargetCheck: true, + name: groupObj.name, + id: groupObj.id, + groupYn: true, + parentId: groupObj.parentId, + }) + canvas?.add(reGroup) + canvas?.remove(groupObj) + } + return { applySurfaceShape, deleteAllSurfacesAndObjects, + moveSurfaceShapeBatch, } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 979675be..7f8b9db5 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -33,6 +33,7 @@ import RowRemove from '@/components/floor-plan/modal/module/row/RowRemove' import RowInsert from '@/components/floor-plan/modal/module/row/RowInsert' import CircuitNumberEdit from '@/components/floor-plan/modal/module/CircuitNumberEdit' import { useObjectBatch } from '@/hooks/object/useObjectBatch' +import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' export function useContextMenu() { const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 @@ -50,7 +51,7 @@ export function useContextMenu() { const [column, setColumn] = useState(null) const { handleZoomClear } = useCanvasEvent() const { moveObjectBatch } = useObjectBatch({}) - + const { moveSurfaceShapeBatch } = useSurfaceShapeBatch() const currentMenuSetting = () => { switch (currentMenu) { case MENU.PLAN_DRAWING: @@ -256,6 +257,7 @@ export function useContextMenu() { }, [currentContextMenu]) useEffect(() => { + console.log('currentObject', currentObject) if (currentObject?.name) { console.log(currentObject?.name) switch (currentObject.name) { @@ -305,22 +307,25 @@ export function useContextMenu() { { id: 'sizeEdit', name: '사이즈 변경', - component: , + component: , }, { id: 'roofMaterialRemove', shortcut: ['d', 'D'], name: `${getMessage('contextmenu.remove')}(D)`, + fn: () => deleteObject(), }, { id: 'roofMaterialMove', shortcut: ['m', 'M'], name: `${getMessage('contextmenu.move')}(M)`, + fn: () => moveSurfaceShapeBatch(), }, { id: 'roofMaterialCopy', shortcut: ['c', 'C'], name: `${getMessage('contextmenu.copy')}(C)`, + fn: () => copyObject(), }, ], [ diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index bddebc63..d1887f6f 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -77,11 +77,9 @@ export function usePlan() { }) //디렉션이 있는 경우에만 - if (group.lineDirection) { - obj.set({ - lineDirection: group.lineDirection, - }) - } + if (group.lineDirection) obj.set({ lineDirection: group.lineDirection }) + //부모객체가 있으면 (면형상 위에 도머등..) + if (group.parentId) obj.set({ parentId: group.parentId }) canvas?.add(obj) obj.setCoords() From 2a108eb1afaf75d4419833c773ded4fbd4e34bab Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 6 Nov 2024 13:57:04 +0900 Subject: [PATCH 52/63] =?UTF-8?q?dormeroffset=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/object/DormerOffset.jsx | 57 +++++++++++++------ src/hooks/object/useObjectBatch.js | 30 +++++++++- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/src/components/floor-plan/modal/object/DormerOffset.jsx b/src/components/floor-plan/modal/object/DormerOffset.jsx index bc56e4b7..a90b61ee 100644 --- a/src/components/floor-plan/modal/object/DormerOffset.jsx +++ b/src/components/floor-plan/modal/object/DormerOffset.jsx @@ -1,9 +1,11 @@ +import { useState, useEffect, useRef } from 'react' import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' import { useRecoilValue } from 'recoil' import { contextPopupPositionState } from '@/store/popupAtom' import { usePopup } from '@/hooks/usePopup' -import { useState } from 'react' +import { useObjectBatch } from '@/hooks/object/useObjectBatch' +import { canvasState } from '@/store/canvasAtom' export default function DormerOffset(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) @@ -12,6 +14,31 @@ export default function DormerOffset(props) { const { closePopup } = usePopup() const [arrow1, setArrow1] = useState(null) const [arrow2, setArrow2] = useState(null) + const arrow1LengthRef = useRef() + const arrow2LengthRef = useRef() + + const canvas = useRecoilValue(canvasState) + const { dormerOffsetKeyEvent, dormerOffset } = useObjectBatch({}) + + useEffect(() => { + if (canvas) { + dormerOffsetKeyEvent(setArrow1, setArrow2) + } + }, []) + + const handleOffsetDormer = () => { + const length1 = arrow1LengthRef.current.value + const length2 = arrow2LengthRef.current.value + + dormerOffset(arrow1, arrow2, length1, length2) + + setArrow1(null) + setArrow2(null) + arrow1LengthRef.current.value = '' + arrow2LengthRef.current.value = '' + + // closePopup(id) + } return (
    @@ -29,44 +56,40 @@ export default function DormerOffset(props) {

    {getMessage('length')}

    - +
    mm
    - +
    mm
    @@ -75,7 +98,9 @@ export default function DormerOffset(props) {
    - +
    diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index 3fb47cee..41583a81 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -16,7 +16,7 @@ import { fontSelector } from '@/store/fontAtom' export function useObjectBatch({ isHidden, setIsHidden }) { const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) - const { addCanvasMouseEventListener, initEvent } = useEvent() + const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent() const { swalFire } = useSwal() const { drawDirectionArrow } = usePolygon() const lengthTextFont = useRecoilValue(fontSelector('lengthText')) @@ -963,6 +963,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) { }) canvas?.add(reGroup) canvas?.remove(groupObj) + + return reGroup } const moveObjectBatch = () => { @@ -986,6 +988,30 @@ export function useObjectBatch({ isHidden, setIsHidden }) { } } + const dormerOffsetKeyEvent = (setArrow1, setArrow2) => { + addDocumentEventListener('keydown', document, (e) => { + if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { + const keyEvent = e.key === 'ArrowDown' ? 'down' : 'up' + setArrow1(keyEvent) + } else if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') { + const keyEvent = e.key === 'ArrowLeft' ? 'left' : 'right' + setArrow2(keyEvent) + } + }) + } + + const dormerOffset = (arrow1, arrow2, length1, length2) => { + length1 = parseInt(length1) / 10 + length2 = parseInt(length2) / 10 + + const dormer = canvas.getActiveObject() + if (length1) dormer.top = arrow1 === 'down' ? dormer.top + length1 : dormer.top - length1 + if (length2) dormer.left = arrow2 === 'left' ? dormer.left - length2 : dormer.left + length2 + + const newDormer = reGroupObject(dormer) + canvas?.setActiveObject(newDormer) + } + return { applyOpeningAndShadow, applyDormers, @@ -993,5 +1019,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) { splitDormerPentagon, resizeObjectBatch, moveObjectBatch, + dormerOffsetKeyEvent, + dormerOffset, } } From 2d07bceb5dcd098c417ede2a2e164e6101a44f69 Mon Sep 17 00:00:00 2001 From: basssy Date: Wed, 6 Nov 2024 14:28:50 +0900 Subject: [PATCH 53/63] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=ED=99=94=EB=A9=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/estimate/Estimate.jsx | 111 +++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 15 deletions(-) diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 47f99c3d..813962b3 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -10,7 +10,7 @@ import SingleDatePicker from '../common/datepicker/SingleDatePicker' import EstimateFileUploader from './EstimateFileUploader' import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' -import { isObjectNotEmpty } from '@/util/common-utils' +import { isNotEmptyArray, isObjectNotEmpty } from '@/util/common-utils' import dayjs from 'dayjs' import { useCommonCode } from '@/hooks/common/useCommonCode' import Select from 'react-select' @@ -21,6 +21,12 @@ export default function Estimate({ params }) { const [planNo, setPlanNo] = useState('') //플랜번호 const [files, setFiles] = useState([]) // 보내는 첨부파일 + //체크박스 + const [checkItems, setCheckItems] = useState(new Set()) + const [checkedList, setCheckedList] = useState([]) + + const [showContentCode, setShowContentCode] = useState('ATTR001') + //견적특이사항 접고 펼치기 const [hidden, setHidden] = useState(false) @@ -40,6 +46,11 @@ export default function Estimate({ params }) { //견적서 상세데이터 const { state, setState } = useEstimateController(params.pid) + //견적특이사항 상세 데이터 LIST + + //견적특이사항 List + const [specialNoteList, setSpecialNoteList] = useState([]) + const globalLocaleState = useRecoilValue(globalLocaleStore) const { get, post } = useAxios(globalLocaleState) @@ -65,17 +76,57 @@ export default function Estimate({ params }) { if (code1 != null) { setHonorificCodeList(code1) } - - //견적특이사항 API호출 - //http://localhost:8080/api/estimate/special-note-list }, []) + useEffect(() => { + //견적특이사항 API호출 + //여러개 선택하면 구분자로 (、) + let url = `/api/estimate/special-note-list` + get({ url: url }).then((res) => { + if (isNotEmptyArray(res)) { + if (state?.estimateOption) { + res.map((row) => { + let estimateOption = state?.estimateOption?.split('、') + row.text = false + estimateOption.map((row2) => { + if (row2 === row.code) { + row.text = true + } + }) + }) + setSpecialNoteList(res) + } + } + }) + }, [state?.estimateOption]) + //견적일 set useEffect(() => { - let estimateDatej = dayjs(startDate).format('YYYY-MM-DD') - setState({ estimateDate: estimateDatej }) + let estimateDate = dayjs(startDate).format('YYYY-MM-DD') + setState({ estimateDate: estimateDate }) }, [startDate]) + useEffect(() => { + //선택된 견적특이사항 setState + if (isNotEmptyArray(specialNoteList)) { + const liveCheckedData = specialNoteList.filter((row) => row.text === true) + + const data = [] + for (let ele of liveCheckedData) { + data.push(ele.code) + } + + const newData = data.join('、') + setState({ estimateOption: newData }) + } + }, [specialNoteList]) + + // 견적특이사항 remark 보여주기 + const settingShowContent = (code, event) => { + setShowContentCode(code) + event.stopPropagation() + } + return (
    @@ -359,17 +410,47 @@ export default function Estimate({ params }) { {/* 견적 특이사항 코드영역시작 */}
    -
    +
    + {/* SpecialNoteList반복문 */} + {specialNoteList.map((row) => { + return ( +
    { + settingShowContent(row.code, event) + }} + > +
    + { + setSpecialNoteList((specialNote) => + specialNote.map((temp) => (temp.code === row.code ? { ...temp, text: !temp.text } : temp)), + ) + settingShowContent(row.code, event) + }} + /> + +
    +
    + ) + })} +
    {/* 견적특이사항 선택한 내용?영역시작 */}
    -
    -
    제목11??
    -
    제목1 비고
    -
    -
    -
    제목22??
    -
    제목2 비고
    -
    + {specialNoteList.map((row) => { + if (row.code === showContentCode) { + return ( +
    +
    {row.codeNm}
    +
    {row.remarks}
    +
    + ) + } + })}
    {/* 견적특이사항 선택한 내용?영역끝 */}
    From 7954c45c7efe76ae79256220f950825962739846 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 6 Nov 2024 15:04:42 +0900 Subject: [PATCH 54/63] =?UTF-8?q?=EA=B0=9C=EA=B5=AC=20=EC=98=A4=ED=94=84?= =?UTF-8?q?=EC=85=8B=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/modal/object/DormerOffset.jsx | 4 ++-- src/hooks/object/useObjectBatch.js | 7 +++++-- src/hooks/useContextMenu.js | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/floor-plan/modal/object/DormerOffset.jsx b/src/components/floor-plan/modal/object/DormerOffset.jsx index a90b61ee..191a94ea 100644 --- a/src/components/floor-plan/modal/object/DormerOffset.jsx +++ b/src/components/floor-plan/modal/object/DormerOffset.jsx @@ -9,7 +9,7 @@ import { canvasState } from '@/store/canvasAtom' export default function DormerOffset(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) - const { id, pos = contextPopupPosition } = props + const { id, pos = contextPopupPosition, title } = props const { getMessage } = useMessage() const { closePopup } = usePopup() const [arrow1, setArrow1] = useState(null) @@ -43,7 +43,7 @@ export default function DormerOffset(props) {
    -

    {getMessage('contextmenu.dormer.offset')}

    +

    {title}

    diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index 41583a81..a16ce0f9 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -1008,8 +1008,11 @@ export function useObjectBatch({ isHidden, setIsHidden }) { if (length1) dormer.top = arrow1 === 'down' ? dormer.top + length1 : dormer.top - length1 if (length2) dormer.left = arrow2 === 'left' ? dormer.left - length2 : dormer.left + length2 - const newDormer = reGroupObject(dormer) - canvas?.setActiveObject(newDormer) + if (dormer.type === 'group') { + const newDormer = reGroupObject(dormer) + canvas?.setActiveObject(newDormer) + } + canvas.renderAll() } return { diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 7f8b9db5..34f5a952 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -296,7 +296,7 @@ export function useContextMenu() { { id: 'dormerOffset', name: getMessage('contextmenu.dormer.offset'), - component: , + component: , }, ], ]) @@ -376,6 +376,7 @@ export function useContextMenu() { { id: 'openingOffset', name: getMessage('contextmenu.opening.offset'), + component: , }, ], ]) From 4cad5cfd50de0eb995d1c2cf639f19c3033a0567 Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Wed, 6 Nov 2024 15:19:44 +0900 Subject: [PATCH 55/63] =?UTF-8?q?refactor:=20QInput=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20type=20text=EB=A1=9C=20=ED=86=B5=EC=9D=BC,?= =?UTF-8?q?=20=EC=88=AB=EC=9E=90=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80?= =?UTF-8?q?=EC=82=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Playground.jsx | 4 +- src/components/common/input/QInput.jsx | 65 +++++++++++++++----------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index 5cd4588c..a908ba0f 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -39,7 +39,7 @@ export default function Playground() { const [color, setColor] = useState('#ff0000') const [textInput, setTextInput] = useState('') - const [numberInput, setNumberInput] = useState(null) + const [numberInput, setNumberInput] = useState('') const [radioInput, setRadioInput] = useState('') const [checkboxInput, setCheckboxInput] = useState([]) const [selectedValue, setSelectedValue] = useState('') @@ -171,7 +171,7 @@ export default function Playground() {
    From b0a9e91d077e161208a329a66442ec2fcb97990f Mon Sep 17 00:00:00 2001 From: minsik Date: Wed, 6 Nov 2024 15:47:04 +0900 Subject: [PATCH 59/63] =?UTF-8?q?=EC=B4=88=EA=B8=B0=20position=20=EC=84=B8?= =?UTF-8?q?=ED=8C=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/draggable/WithDraggable.jsx | 12 ++++++------ .../placementSurface/PlacementSurfaceSetting.jsx | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/common/draggable/WithDraggable.jsx b/src/components/common/draggable/WithDraggable.jsx index 29952981..76656837 100644 --- a/src/components/common/draggable/WithDraggable.jsx +++ b/src/components/common/draggable/WithDraggable.jsx @@ -1,18 +1,18 @@ 'use client' -import { useEffect, useState } from 'react' +import { useState } from 'react' import Draggable from 'react-draggable' -export default function WithDraggable({ isShow, children, pos, handle = '' }) { - const [position, setPosition] = useState({ x: 0, y: 0 }) +export default function WithDraggable({ isShow, children, pos = { x: 0, y: 0 }, handle = '' }) { + const [position, setPosition] = useState(pos) const handleOnDrag = (e, data) => { e.stopPropagation() setPosition({ x: data.x, y: data.y }) } - useEffect(() => { - setPosition({ ...pos }) - }, []) + // useEffect(() => { + // setPosition({ ...pos }) + // }, []) return ( <> diff --git a/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx b/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx index c22d2248..431e0f85 100644 --- a/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx +++ b/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx @@ -240,7 +240,7 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } }) }, []) return ( - +

    {getMessage('plan.menu.placement.surface.arrangement')}

    From c53653d0819915325297fd6bab8f7b60f71e5e42 Mon Sep 17 00:00:00 2001 From: minsik Date: Wed, 6 Nov 2024 15:47:54 +0900 Subject: [PATCH 60/63] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/setting01/SettingModal01.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/floor-plan/modal/setting01/SettingModal01.jsx b/src/components/floor-plan/modal/setting01/SettingModal01.jsx index e1bef1f0..222226c1 100644 --- a/src/components/floor-plan/modal/setting01/SettingModal01.jsx +++ b/src/components/floor-plan/modal/setting01/SettingModal01.jsx @@ -11,12 +11,12 @@ import { useRecoilValue } from 'recoil' import { usePopup } from '@/hooks/usePopup' export default function SettingModal01(props) { - const { setShowDotLineGridModal, setShowFontSettingModal, id, isConfig } = props - console.log(props) + const { id } = props const [buttonAct, setButtonAct] = useState(1) const { getMessage } = useMessage() const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor) - const { addPopup, closePopup } = usePopup() + const { closePopup } = usePopup() + const handleBtnClick = (num) => { setButtonAct(num) } From 4e1cbd08d8f7c9089f51daf2b800924624044360 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 6 Nov 2024 16:03:55 +0900 Subject: [PATCH 61/63] =?UTF-8?q?Polygon=20=EC=84=A0=ED=83=9D=20=EC=8B=9C?= =?UTF-8?q?=20stroke=20red?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useCanvasEvent.js | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index 4bab1fd6..9b25eedd 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -209,13 +209,52 @@ export function useCanvasEvent() { created: (e) => { const target = e.selected[0] setCurrentObject(target) + const { selected } = e + + if (selected.length > 0) { + selected.forEach((obj) => { + if (obj.type === 'QPolygon') { + obj.set({ stroke: 'red' }) + } + }) + canvas.renderAll() + } }, cleared: (e) => { setCurrentObject(null) + const { deselected } = e + + if (deselected.length > 0) { + deselected.forEach((obj) => { + if (obj.type === 'QPolygon') { + obj.set({ stroke: 'black' }) + } + }) + } + canvas.renderAll() }, updated: (e) => { const target = e.selected[0] setCurrentObject(target) + const { selected, deselected } = e + + if (deselected.length > 0) { + deselected.forEach((obj) => { + if (obj.type === 'QPolygon') { + obj.set({ stroke: 'black' }) + } + }) + } + + if (selected.length > 0) { + selected.forEach((obj) => { + if (obj.type === 'QPolygon') { + obj.set({ stroke: 'red' }) + } + }) + } + + canvas.renderAll() }, } From d8a69306f3aeb51be38a5dd0b961ca3083111ccd Mon Sep 17 00:00:00 2001 From: basssy Date: Wed, 6 Nov 2024 16:16:25 +0900 Subject: [PATCH 62/63] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=86=8C=EC=8A=A4=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 130 ++++++++---------- .../management/StuffSearchCondition.jsx | 30 +--- 2 files changed, 64 insertions(+), 96 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 2603cc04..8c97347d 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -5,7 +5,7 @@ import { useRouter, usePathname } from 'next/navigation' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import StuffQGrid from './StuffQGrid' -import { useRecoilValue, useRecoilState, useSetRecoilState } from 'recoil' +import { useRecoilValue, useRecoilState, useSetRecoilState, useResetRecoilState } from 'recoil' import { stuffSearchState } from '@/store/stuffAtom' import { queryStringFormatter, isEmptyArray } from '@/util/common-utils' import dayjs from 'dayjs' @@ -19,7 +19,7 @@ import { sessionStore } from '@/store/commonAtom' import { SessionContext } from '@/app/SessionProvider' export default function Stuff() { - const sessionState = useRecoilValue(sessionStore) + const resetStuffRecoil = useResetRecoilState(stuffSearchState) const { session } = useContext(SessionContext) const setAppMessageState = useSetRecoilState(appMessageStore) const stuffSearchParams = useRecoilValue(stuffSearchState) @@ -34,9 +34,6 @@ export default function Stuff() { const { get } = useAxios(globalLocaleState) const gridRef = useRef() - // const [selectedRowData, setSelectedRowData] = useState([]) - // const [selectedRowDataCount, setSelectedRowDataCount] = useState(0) - const router = useRouter() const pathname = usePathname() @@ -67,10 +64,6 @@ export default function Stuff() { field: 'lastEditDatetime', minWidth: 200, headerName: getMessage('stuff.gridHeader.lastEditDatetime'), - // headerCheckboxSelection: true, - // headerCheckboxSelectionCurrentPageOnly: true, //페이징시 현재 페이지만 체크되도록 - // checkboxSelection: true, - // showDisabledCheckboxes: true, cellStyle: { justifyContent: 'center' }, valueFormatter: function (params) { if (params.value) { @@ -169,77 +162,67 @@ export default function Stuff() { // 진입시 그리드 데이터 조회 useEffect(() => { - if (isObjectNotEmpty(session)) { - if (stuffSearchParams?.code === 'S') { - const params = { - // saleStoreId: stuffSearchParams.schSelSaleStoreId, - saleStoreId: session.storeId, - schObjectNo: stuffSearchParams?.schObjectNo, - schAddress: stuffSearchParams?.schAddress, - schObjectName: stuffSearchParams?.schObjectName, - schSaleStoreName: stuffSearchParams?.schSaleStoreName, - schReceiveUser: stuffSearchParams?.schReceiveUser, - schDispCompanyName: stuffSearchParams?.schDispCompanyName, - schDateType: stuffSearchParams.schDateType, - schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), - schToDt: dayjs(new Date()).format('YYYY-MM-DD'), - startRow: (pageNo - 1) * pageSize + 1, - endRow: pageNo * pageSize, - schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId - ? stuffSearchParams.schOtherSelSaleStoreId - : stuffSearchParams.schSelSaleStoreId, - schSortType: stuffSearchParams.schSortType, - } - async function fetchData() { - const apiUrl = `/api/object/list?${queryStringFormatter(params)}` - await get({ - url: apiUrl, - }).then((res) => { - if (!isEmptyArray(res)) { - setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt }) - setTotalCount(res[0].totCnt) - } - }) - } - if (stuffSearchParams?.schSelSaleStoreId !== '') { - fetchData() - } - } else if (stuffSearchParams?.code === 'M') { - //메인화면에서 진입 - const params = { - saleStoreId: session?.storeId, - schObjectNo: stuffSearchParams.schObjectNo, - schAddress: '', - schObjectName: '', - schSaleStoreName: '', - schReceiveUser: '', - schDispCompanyName: '', - schDateType: 'U', - schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), - schToDt: dayjs(new Date()).format('YYYY-MM-DD'), - startRow: (pageNo - 1) * pageSize + 1, - endRow: pageNo * pageSize, - schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId - ? stuffSearchParams.schOtherSelSaleStoreId - : stuffSearchParams.schSelSaleStoreId, - schSortType: 'R', - } - setStuffSearch({ - ...params, + if (stuffSearchParams?.code === 'S') { + const params = { + saleStoreId: session.storeId, + schObjectNo: stuffSearchParams?.schObjectNo, + schAddress: stuffSearchParams?.schAddress, + schObjectName: stuffSearchParams?.schObjectName, + schSaleStoreName: stuffSearchParams?.schSaleStoreName, + schReceiveUser: stuffSearchParams?.schReceiveUser, + schDispCompanyName: stuffSearchParams?.schDispCompanyName, + schDateType: stuffSearchParams.schDateType, + schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), + schToDt: dayjs(new Date()).format('YYYY-MM-DD'), + startRow: (pageNo - 1) * pageSize + 1, + endRow: pageNo * pageSize, + schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : stuffSearchParams.schSelSaleStoreId, + schSortType: stuffSearchParams.schSortType, + } + + async function fetchData() { + const apiUrl = `/api/object/list?${queryStringFormatter(params)}` + await get({ + url: apiUrl, + }).then((res) => { + if (!isEmptyArray(res)) { + setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt }) + setTotalCount(res[0].totCnt) + } }) } - } - }, [pageNo, session, stuffSearchParams]) - useEffect(() => { - if (stuffSearchParams?.code === 'E') { + fetchData() + } else if (stuffSearchParams?.code === 'M') { + const params = { + saleStoreId: session?.storeId, + schObjectNo: stuffSearchParams.schObjectNo, + schAddress: '', + schObjectName: '', + schSaleStoreName: '', + schReceiveUser: '', + schDispCompanyName: '', + schDateType: 'U', + schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), + schToDt: dayjs(new Date()).format('YYYY-MM-DD'), + startRow: (pageNo - 1) * pageSize + 1, + endRow: pageNo * pageSize, + schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : stuffSearchParams.schSelSaleStoreId, + schSortType: 'R', + } + setStuffSearch({ + ...params, + }) + } else if (stuffSearchParams?.code === 'E') { stuffSearchParams.startRow = 1 stuffSearchParams.endRow = 1 * pageSize stuffSearchParams.schSortType = defaultSortType - setPageNo(1) + setStuffSearch({ + ...stuffSearch, + code: 'FINISH', + }) - //조회를 눌렀을때 async function fetchData() { const apiUrl = `/api/object/list?saleStoreId=${session?.storeId}&${queryStringFormatter(stuffSearchParams)}` await get({ url: apiUrl }).then((res) => { @@ -252,7 +235,10 @@ export default function Stuff() { } }) } + fetchData() + } else if (stuffSearchParams?.code === 'C') { + resetStuffRecoil() } }, [stuffSearchParams]) diff --git a/src/components/management/StuffSearchCondition.jsx b/src/components/management/StuffSearchCondition.jsx index 659ab696..1d40b61a 100644 --- a/src/components/management/StuffSearchCondition.jsx +++ b/src/components/management/StuffSearchCondition.jsx @@ -94,13 +94,13 @@ export default function StuffSearchCondition() { }) } else { setStuffSearch({ - schObjectNo: objectNo ? objectNo : '', - schSaleStoreName: saleStoreName ? saleStoreName : '', - schAddress: address ? address : '', - schObjectName: objectName ? objectName : '', - schDispCompanyName: dispCompanyName ? dispCompanyName : '', + schObjectNo: objectNo, + schSaleStoreName: saleStoreName, + schAddress: address, + schObjectName: objectName, + schDispCompanyName: dispCompanyName, schSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : stuffSearch.schSelSaleStoreId, - schReceiveUser: receiveUser ? receiveUser : '', + schReceiveUser: receiveUser, schDateType: dateType, schFromDt: dayjs(startDate).format('YYYY-MM-DD'), schToDt: dayjs(endDate).format('YYYY-MM-DD'), @@ -131,14 +131,12 @@ export default function StuffSearchCondition() { setDateType('U') setStartDate(dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')) setEndDate(dayjs(new Date()).format('YYYY-MM-DD')) - // if (sessionState?.storeId === 'T01') { if (session?.storeId === 'T01') { setSchSelSaleStoreId('') handleClear1() //판매대리점선택 자동완성 클리어 resetStuffRecoil() setStuffSearch({ ...stuffSearch, - code: 'C', schSelSaleStoreId: '', schOtherSelSaleStoreId: '', }) @@ -156,23 +154,17 @@ export default function StuffSearchCondition() { } useEffect(() => { - // if (isObjectNotEmpty(sessionState)) { if (isObjectNotEmpty(session)) { // storeId가 T01 이거나 storeLvl이 1차점일때만 판매대리점 선택 활성화 let url - // if (sessionState?.storeId === 'T01') { if (session?.storeId === 'T01') { //T01일떄 - // url = `/api/object/saleStore/${sessionState?.storeId}/firstList?userId=${sessionState?.userId}` url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}` } else { - // if (sessionState.storeLvl === '1') { if (session.storeLvl === '1') { //T01아닌 1차점일때 - // url = `/api/object/saleStore/${sessionState?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}` url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}` } else { - // url = `/api/object/saleStore/${sessionState?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}` url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}` } } @@ -187,7 +179,6 @@ export default function StuffSearchCondition() { let allList let favList let otherList - // if (sessionState?.storeId === 'T01') { if (session?.storeId === 'T01') { allList = res allList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId) @@ -195,17 +186,14 @@ export default function StuffSearchCondition() { setSchSelSaleStoreList(allList) setFavoriteStoreList(favList) setShowSaleStoreList(favList) - // setSchSelSaleStoreId(sessionState?.storeId) setSchSelSaleStoreId(session?.storeId) setStuffSearch({ ...stuffSearch, code: 'S', - // schSelSaleStoreId: sessionState?.storeId, schSelSaleStoreId: session?.storeId, }) //T01일때 2차 판매점 호출하기 디폴트로 1차점을 본인으로 셋팅해서 세션storeId사용 - // url = `/api/object/saleStore/${sessionState?.storeId}/list?firstFlg=0&userId=${sessionState?.userId}` url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=0&userId=${session?.userId}` get({ url: url }).then((res) => { @@ -222,7 +210,6 @@ export default function StuffSearchCondition() { } }) } else { - // if (sessionState?.storeLvl === '1') { if (session?.storeLvl === '1') { allList = res favList = res.filter((row) => row.priority !== 'B') @@ -250,7 +237,6 @@ export default function StuffSearchCondition() { setOtherSaleStoreList(otherList) //선택한 2차점 세션으로 자동셋팅 - // setOtherSaleStoreId(sessionState?.storeId) setOtherSaleStoreId(session?.storeId) setStuffSearch({ ...stuffSearch, @@ -262,7 +248,6 @@ export default function StuffSearchCondition() { } }) } - // }, [sessionState]) }, [session]) //초기화 눌렀을 때 1차판매점 자동완성도.. @@ -296,7 +281,6 @@ export default function StuffSearchCondition() { stuffSearch.schSelSaleStoreId = key.saleStoreId //T01아닌 1차점은 본인으로 디폴트셋팅이고 수정할수없어서 여기안옴 //고른 1차점의 saleStoreId로 2차점 API호출하기 - // let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${sessionState?.userId}` let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${session?.userId}` let otherList get({ url: url }).then((res) => { @@ -620,7 +604,6 @@ export default function StuffSearchCondition() { value={'U'} onChange={(e) => { setDateType(e.target.value) - //setStuffSearch({ ...stuffSearch, code: 'S', schDateType: e.target.value }) }} /> @@ -634,7 +617,6 @@ export default function StuffSearchCondition() { value={'R'} onChange={(e) => { setDateType(e.target.value) - //setStuffSearch({ ...stuffSearch, code: 'S', schDateType: e.target.value }) }} /> From 23a5e2d2a73c9b8ad5934de48642fd17a51a7343 Mon Sep 17 00:00:00 2001 From: basssy Date: Thu, 7 Nov 2024 08:33:23 +0900 Subject: [PATCH 63/63] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=ED=99=94=EB=A9=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/estimate/Estimate.jsx | 27 +++++++++------- src/components/management/StuffDetail.jsx | 11 +------ .../estimate/useEstimateController.js | 31 ++++++++++++++++--- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 813962b3..f12d7c69 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -1,9 +1,9 @@ 'use client' -import { useEffect, useState, useRef } from 'react' +import { useEffect, useState, useContext } from 'react' import { useRecoilValue } from 'recoil' import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' -import { sessionStore } from '@/store/commonAtom' +import { SessionContext } from '@/app/SessionProvider' import { useMessage } from '@/hooks/useMessage' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import SingleDatePicker from '../common/datepicker/SingleDatePicker' @@ -21,10 +21,6 @@ export default function Estimate({ params }) { const [planNo, setPlanNo] = useState('') //플랜번호 const [files, setFiles] = useState([]) // 보내는 첨부파일 - //체크박스 - const [checkItems, setCheckItems] = useState(new Set()) - const [checkedList, setCheckedList] = useState([]) - const [showContentCode, setShowContentCode] = useState('ATTR001') //견적특이사항 접고 펼치기 @@ -40,7 +36,7 @@ export default function Estimate({ params }) { setStartDate, } - const sessionState = useRecoilValue(sessionStore) + const { session } = useContext(SessionContext) const objectRecoil = useRecoilValue(floorPlanObjectState) //견적서 상세데이터 @@ -127,6 +123,19 @@ export default function Estimate({ params }) { event.stopPropagation() } + // 첨부파일 state에 넣기 + useEffect(() => { + // console.log(files) + if (files.length > 0) { + files.map((row) => { + setState({ fileList: row.data }) + }) + } else { + console.log('첨부파일 없음') + setState({ fileList: [] }) + } + }, [files]) + return (
    @@ -206,7 +215,6 @@ export default function Estimate({ params }) { defaultValue={state?.charger} onChange={(e) => { //담당자 charger - // console.log('담당자:::::', e.target.value) setState({ charger: e.target.value }) }} /> @@ -227,7 +235,6 @@ export default function Estimate({ params }) { defaultValue={state?.objectName} onChange={(e) => { //안건명 objectName - // console.log('안건명::::', e.target.value) setState({ objectName: e.target.value }) }} /> @@ -244,7 +251,6 @@ export default function Estimate({ params }) { if (isObjectNotEmpty(e)) { setState({ objectNameOmit: e.clCodeNm }) } else { - // console.log('XXX') setState({ objectNameOmit: '' }) } }} @@ -342,7 +348,6 @@ export default function Estimate({ params }) { defaultValue={state?.remarks} onChange={(e) => { //비고 - // console.log('비고:::::', e.target.value) setState({ remarks: e.target.value }) }} /> diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 9a455216..61cdc1df 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -11,7 +11,6 @@ import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty } from '@/util/common-u import { useMessage } from '@/hooks/useMessage' import { useForm } from 'react-hook-form' import { useRecoilValue, useSetRecoilState } from 'recoil' -import { sessionStore } from '@/store/commonAtom' import { SessionContext } from '@/app/SessionProvider' import FindAddressPop from './popup/FindAddressPop' import PlanRequestPop from './popup/PlanRequestPop' @@ -28,7 +27,6 @@ export default function StuffDetail() { const [selOptions, setSelOptions] = useState('') //선택한 1차점 const [otherSelOptions, setOtherSelOptions] = useState('') //선택한 1차점외 - const sessionState = useRecoilValue(sessionStore) const { session } = useContext(SessionContext) const router = useRouter() @@ -320,12 +318,11 @@ export default function StuffDetail() { let firstList let otherList let favList - // if (sessionState?.storeId === 'T01') { if (session?.storeId === 'T01') { url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}` } else { if (session.storeLvl === '1') { - url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}` + url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}` } else { url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}` } @@ -400,7 +397,6 @@ export default function StuffDetail() { } }) } - // }, [objectNo, sessionState]) }, [objectNo, session]) useEffect(() => { @@ -1279,9 +1275,7 @@ export default function StuffDetail() { //1차점 or 2차점 안고르고 임시저장하면 if (params.saleStoreId == '') { - // params.saleStoreId = sessionState.storeId params.saleStoreId = session.storeId - // params.saleStoreLevel = sessionState.storeLvl params.saleStoreLevel = session.storeLvl } @@ -1445,7 +1439,6 @@ export default function StuffDetail() {
    - {/* {sessionState?.storeId === 'T01' && ( */} {session?.storeId === 'T01' && ( <>
    @@ -1479,7 +1472,6 @@ export default function StuffDetail() { )} - {/* {sessionState?.storeId !== 'T01' && sessionState?.storeLvl === '1' && ( */} {session?.storeId !== 'T01' && session?.storeLvl === '1' && ( <>
    @@ -1511,7 +1503,6 @@ export default function StuffDetail() {
    )} - {/* {sessionState?.storeId !== 'T01' && sessionState?.storeLvl !== '1' && ( */} {session?.storeId !== 'T01' && session?.storeLvl !== '1' && ( <>
    diff --git a/src/hooks/floorPlan/estimate/useEstimateController.js b/src/hooks/floorPlan/estimate/useEstimateController.js index 87fa15ca..2b92a14a 100644 --- a/src/hooks/floorPlan/estimate/useEstimateController.js +++ b/src/hooks/floorPlan/estimate/useEstimateController.js @@ -1,9 +1,11 @@ import { useAxios } from '@/hooks/useAxios' -import { useEffect, useReducer, useState } from 'react' +import { useContext, useEffect, useReducer, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' import { globalLocaleStore } from '@/store/localeAtom' import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom' import { isObjectNotEmpty } from '@/util/common-utils' +import { SessionContext } from '@/app/SessionProvider' + const reducer = (prevState, nextState) => { return { ...prevState, ...nextState } } @@ -41,6 +43,7 @@ const defaultEstimateData = { unit: '', }, ], + fileList: [], } // Helper functions @@ -51,14 +54,14 @@ const updateItemInList = (itemList, itemId, updates) => { } export const useEstimateController = (planNo) => { + const { session } = useContext(SessionContext) const globalLocaleState = useRecoilValue(globalLocaleStore) const objectRecoil = useRecoilValue(floorPlanObjectState) const [estimateData, setEstimateData] = useRecoilState(estimateState) - const { get, post } = useAxios(globalLocaleState) + const { get, post, promisePost } = useAxios(globalLocaleState) const [isLoading, setIsLoading] = useState(false) - const { promisePost } = useAxios() const [state, setState] = useReducer(reducer, defaultEstimateData) useEffect(() => { @@ -123,12 +126,32 @@ export const useEstimateController = (planNo) => { } useEffect(() => { - setEstimateData({ ...state }) + setEstimateData({ ...state, userId: session.userId }) + //sapSalesStoreCd 추가예정 필수값 + // setEstimateData({ ...state, userId: session.userId, sapSalesStoreCd : session.sapSalesStoreCd }) }, [state]) //견적서 저장 const handleEstimateSubmit = async () => { console.log('::담긴 estimateData:::', estimateData) + //1. 첨부파일 저장 + const formData = new FormData() + formData.append('file', estimateData.fileList) + formData.append('objectNo', estimateData.objectNo) + formData.append('planNo', estimateData.planNo) + formData.append('category', '10') + formData.append('userId', estimateData.userId) + for (const value of formData.values()) { + console.log('formData::', value) + } + + await promisePost({ url: '/api/file/fileUpload', data: formData }).then((res) => { + console.log('파일저장::::::::::', res) + }) + + //2. 상세데이터 저장 + + console.log('상세저장시작!!') return try { const result = await promisePost({