popupManager 개발 중

This commit is contained in:
minsik 2024-10-18 13:36:32 +09:00
parent 07e11f3148
commit 15af4655a3
22 changed files with 784 additions and 107 deletions

View File

@ -15,6 +15,7 @@ import './globals.css'
import '../styles/style.scss'
import '../styles/contents.scss'
import Dimmed from '@/components/ui/Dimmed'
import PopupManager from '@/components/common/popupManager/PopupManager'
// const inter = Inter({ subsets: ['latin'] })
@ -81,6 +82,7 @@ export default async function RootLayout({ children }) {
)}
<ToastContainer />
<QModal />
<PopupManager />
</body>
</html>
</RecoilRootWrapper>

View File

@ -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'

View File

@ -1,11 +1,30 @@
import { HexColorPicker } from 'react-colorful'
import { useMessage } from '@/hooks/useMessage'
export default function ColorPicker(props) {
const { color, setColor } = props
const { getMessage } = useMessage()
const defaultColors = ['#EA575D', '#F29955', '#F2C957', '#32975D', '#3D7FED', '#828282', '#ffffff', '#000000']
return (
<>
<HexColorPicker color={color} onChange={setColor} />
<div>
<HexColorPicker color={color} onChange={setColor} />
</div>
<div className="hex-color-box">
<div className="color-box-tit">HEX</div>
<div className="color-hex-input">
<input type="text" className="input-origin" value={color} onChange={(e) => setColor(e.target.value)} />
</div>
<div className="color-box" style={{ backgroundColor: color }}></div>
</div>
<div className="default-color-wrap">
<div className="default-tit">{getMessage('modal.color.picker.default.color')}</div>
<div className="color-button-wrap">
{defaultColors.map((color, index) => (
<button key={index} className="default-color" style={{ backgroundColor: color }} onClick={() => setColor(color)}></button>
))}
</div>
</div>
</>
)
}

View File

@ -0,0 +1,44 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import ColorPicker from '@/components/common/color-picker/ColorPicker'
import { useMessage } from '@/hooks/useMessage'
import { useEffect, useState } from 'react'
export default function ColorPickerModal(props) {
const { isShow, setIsShow, pos = { x: 800, y: -950 }, color = '#ff0000', setColor } = props
const { getMessage } = useMessage()
const [originColor, setOriginColor] = useState(color)
useEffect(() => {
setOriginColor(color)
}, [isShow])
return (
<WithDraggable isShow={isShow} pos={pos}>
<div className={`modal-pop-wrap lr`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.color.picker.title')}</h1>
<button className="modal-close" onClick={() => setIsShow(false)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="color-setting-wrap">
<div className="color-tit">COLOR PICKER</div>
<div className="color-picker">
<ColorPicker color={originColor} setColor={setOriginColor} />
</div>
</div>
<div className="grid-btn-wrap">
<button
className="btn-frame modal act"
onClick={() => {
setColor(originColor)
setIsShow(false)
}}
>
{getMessage('common.message.save')}
</button>
</div>
</div>
</div>
</WithDraggable>
)
}

View File

@ -0,0 +1,69 @@
import WithDraggable from '@/components/common/draggable/withDraggable'
import QSelectBox from '@/components/common/select/QSelectBox'
const SelectOption = [{ name: '原寸' }, { name: '原寸' }, { name: '原寸' }, { name: '原寸' }]
export default function FontSetting(props) {
const { setShowFontSettingModal } = props
console.log(
Array.from({ length: 10 }).map((_, index) => {
return { name: 5 + index }
}),
)
return (
<WithDraggable isShow={true} pos={{ x: 800, y: -950 }}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head">
<h1 className="title">フォント </h1>
<button className="modal-close" onClick={() => setShowFontSettingModal(false)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="slope-wrap">
<div className="font-option-warp">
<div className="font-option-item">
<div className="option-item-tit">文字(F)</div>
<div className="grid-select">
<QSelectBox title={'MS PGothic'} option={SelectOption} />
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">フォントスタイル(Y)</div>
<div className="grid-select">
<QSelectBox title={'いつもの'} option={SelectOption} />
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">サイズ(S)</div>
<div className="grid-select">
<QSelectBox
title={'8'}
options={Array.from({ length: 9 }).map((_, index) => {
return { id: index, name: 8 * (index + 1) }
})}
/>
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">フォン</div>
<div className="grid-select">
<QSelectBox title={'黒'} option={SelectOption} />
</div>
</div>
</div>
<div className="font-ex-wrap">
<div className="font-ex-tit">見る</div>
<div className="font-ex-box">
<span style={{ fontSize: '12px', fontWeight: '400', color: '#101010' }}>Aaあぁアァ</span>
</div>
</div>
<div className="normal-font">ントですプリンタと画面 でも同じフォントを使用します.</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act">ストレージ</button>
</div>
</div>
</div>
</WithDraggable>
)
}

View File

@ -0,0 +1,8 @@
'use client'
import { useRecoilState } from 'recoil'
import { popupState } from '@/store/popupAtom'
export default function PopupManager() {
const [popup, setPopup] = useRecoilState(popupState)
return <>{popup.children?.map((child) => child.component)}</>
}

View File

@ -8,11 +8,18 @@ import QContextMenu from '@/components/common/context-menu/QContextMenu'
import { useContextMenu } from '@/hooks/useContextMenu'
import { useRecoilValue } from 'recoil'
import { currentObjectState } from '@/store/canvasAtom'
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
export default function CanvasFrame({ plan }) {
const canvasRef = useRef(null)
const { canvas } = useCanvas('canvas')
const { contextMenu, currentContextMenu, setCurrentContextMenu } = useContextMenu()
const { handleZoomClear } = useCanvasEvent()
const { contextMenu, currentContextMenu, setCurrentContextMenu } = useContextMenu({
externalFn: {
handleZoomClear,
},
})
const currentObject = useRecoilValue(currentObjectState)
useEffect(() => {
@ -44,7 +51,17 @@ export default function CanvasFrame({ plan }) {
{contextMenu.map((menus, index) => (
<ul key={index}>
{menus.map((menu) => (
<li onClick={(e) => setCurrentContextMenu(menu)}>{menu.name}</li>
<li
key={menu.id}
onClick={(e) => {
if (menu.fn) {
menu.fn()
}
setCurrentContextMenu(menu)
}}
>
{menu.name}
</li>
))}
</ul>
))}

View File

@ -19,6 +19,10 @@ import { MENU } from '@/common/common'
import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
import { popupState } from '@/store/popupAtom'
import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01'
import { usePopup } from '@/hooks/usePopup'
const canvasMenus = [
{ index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING },
@ -52,6 +56,7 @@ export default function CanvasMenu(props) {
setShowPropertiesSettingModal,
} = props
const { addPopup, closePopup } = usePopup()
const [menuNumber, setMenuNumber] = useState(null)
const [type, setType] = useState('')
@ -61,6 +66,7 @@ export default function CanvasMenu(props) {
const setPoints = useSetRecoilState(outerLinePointsState)
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const { handleZoomClear } = useCanvasEvent()
const globalLocale = useRecoilValue(globalLocaleStore)
const canvas = useRecoilValue(canvasState)
@ -69,7 +75,7 @@ export default function CanvasMenu(props) {
const { getMessage } = useMessage()
const { saveCanvas } = usePlan()
const { swalFire } = useSwal()
const [popup, setPopup] = useRecoilState(popupState)
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
const onClickNav = (menu) => {
setMenuNumber(menu.index)
@ -143,13 +149,13 @@ export default function CanvasMenu(props) {
setPoints([])
canvas?.clear()
}
const handleZoomClear = () => {
setCanvasZoom(100)
canvas.set({ zoom: 1 })
canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
canvas.renderAll()
}
//
// const handleZoomClear = () => {
// setCanvasZoom(100)
// canvas.set({ zoom: 1 })
// canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
// canvas.renderAll()
// }
useEffect(() => {
if (globalLocale === 'ko') {
@ -196,7 +202,8 @@ export default function CanvasMenu(props) {
<QSelectBox title={'瓦53A'} option={SelectOption} />
</div>
<div className="btn-from">
<button className="btn04" onClick={() => setShowCanvasSettingModal(true)}></button>
{/*<button className="btn04" onClick={() => setShowCanvasSettingModal(true)}></button>*/}
<button className="btn04" onClick={() => addPopup(<SettingModal01 />)}></button>
<button className="btn05"></button>
<button className="btn06"></button>
</div>

View File

@ -1,19 +1,17 @@
'use client'
import { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom'
import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom'
import { settingModalFirstOptionsState, settingModalGridOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom'
import '@/styles/contents.scss'
import CanvasMenu from '@/components/floor-plan/CanvasMenu'
import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01'
import CanvasLayout from '@/components/floor-plan/CanvasLayout'
import DotLineGrid from '@/components/floor-plan/modal/grid/DotLineGrid'
import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting'
import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting'
import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
import GridColorSetting from './modal/grid/GridColorSetting'
import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting'
import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing'
import Slope from '@/components/floor-plan/modal/Slope'
@ -28,6 +26,8 @@ import MovementSetting from '@/components/floor-plan/modal/movement/MovementSett
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting'
import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting'
import FontSetting from '@/components/common/font/FontSetting'
import { gridColorState } from '@/store/gridAtom'
export default function FloorPlan() {
const [showCanvasSettingModal, setShowCanvasSettingModal] = useState(false)
@ -58,10 +58,15 @@ export default function FloorPlan() {
const [showGridCopyModal, setShowGridCopyModal] = useState(false)
const [showGridMoveModal, setShowGridMoveModal] = useState(false)
const [showColorPickerModal, setShowColorPickerModal] = useState(false)
const [color, setColor] = useRecoilState(gridColorState)
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
const [showFontSettingModal, setShowFontSettingModal] = useState(false)
const canvasSettingProps = {
setShowCanvasSettingModal,
setShowDotLineGridModal,
setShowColorPickerModal,
setShowFontSettingModal,
}
const outlineProps = {
@ -127,6 +132,9 @@ export default function FloorPlan() {
const gridColorProps = {
setShowColorPickerModal,
color,
setColor,
setSettingModalGridOptions,
}
const propertiesSettingProps = {
@ -141,12 +149,13 @@ export default function FloorPlan() {
<CanvasMenu {...modalProps} />
<div className="canvas-content">
<CanvasLayout />
{showCanvasSettingModal && <SettingModal01 {...canvasSettingProps} />}
{/*{showCanvasSettingModal && <SettingModal01 {...canvasSettingProps} />}*/}
{showOutlineModal && <WallLineSetting {...outlineProps} />}
{showDotLineGridModal && <DotLineGrid {...dotLineProps} />}
{showColorPickerModal && <GridColorSetting {...gridColorProps} />}
{/*{showColorPickerModal && <GridColorSetting {...gridColorProps} />}*/}
{showFontSettingModal && <FontSetting setShowFontSettingModal={setShowFontSettingModal} />}
{showPropertiesSettingModal && <PropertiesSetting {...propertiesSettingProps} />}
{/*<DimensionLineSetting setShowFontSettingModal={setShowFontSettingModal} setShowColorPickerModal={setShowColorPickerModal} />*/}
{showPlaceShapeModal && <PlacementShapeSetting setShowPlaceShapeModal={setShowPlaceShapeModal} />}
{showRoofShapeSettingModal && <RoofShapeSetting setShowRoofShapeSettingModal={setShowRoofShapeSettingModal} />}
{showRoofShapePassivitySettingModal && (

View File

@ -1,4 +1,3 @@
import { useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable'
import RightAngle from '@/components/floor-plan/modal/lineTypes/RightAngle'
@ -6,7 +5,6 @@ import DoublePitch from '@/components/floor-plan/modal/lineTypes/DoublePitch'
import Angle from '@/components/floor-plan/modal/lineTypes/Angle'
import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal'
import { OUTER_LINE_TYPE } from '@/store/outerLineAtom'
import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall'
import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall'
import { useAuxiliaryDrawing } from '@/hooks/roofcover/useAuxiliaryDrawing'
@ -152,7 +150,7 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) {
{getMessage('modal.cover.outline.rollback')}
</button>
<button className="btn-frame modal act" onClick={() => handleFix(setShowAuxiliaryModal)}>
{getMessage('modal.cover.outline.fix')}
{getMessage('apply')}
</button>
</div>
</div>

View File

@ -1,39 +0,0 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import ColorPicker from '@/components/common/color-picker/ColorPicker'
import { useRecoilState, useSetRecoilState } from 'recoil'
import { gridColorState } from '@/store/gridAtom'
import { useMessage } from '@/hooks/useMessage'
import { useEffect } from 'react'
import { settingModalGridOptionsState } from '@/store/settingAtom'
export default function GridColorSetting(props) {
const { setShowColorPickerModal } = props
const [color, setColor] = useRecoilState(gridColorState)
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
const { getMessage } = useMessage()
useEffect(() => {
return () => {
setSettingModalGridOptions((prev) => {
const newSettingOptions = [...prev]
newSettingOptions[3].selected = false
return [...newSettingOptions]
})
}
}, [])
return (
<WithDraggable isShow={true} pos={{ x: 1300, y: -660 }}>
<div className={`modal-pop-wrap ssm mount`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.canvas.setting.grid.color.setting')}</h1>
<button className="modal-close" onClick={() => setShowColorPickerModal(false)}>
닫기
</button>
</div>
<div className="modal-body">
<ColorPicker color={color} setColor={setColor} />
</div>
</div>
</WithDraggable>
)
}

View File

@ -1,27 +1,45 @@
import React, { useEffect } from 'react'
import { useRecoilState } from 'recoil'
import React, { useEffect, useState } from 'react'
import { useRecoilState, useSetRecoilState } from 'recoil'
import { settingModalGridOptionsState } from '@/store/settingAtom'
import { useMessage } from '@/hooks/useMessage'
import { adsorptionPointAddModeState } from '@/store/canvasAtom'
import { useTempGrid } from '@/hooks/useTempGrid'
import { gridColorState } from '@/store/gridAtom'
import { useColor } from 'react-color-palette'
import ColorPickerModal from '@/components/common/color-picker/ColorPickerModal'
export default function GridOption(props) {
const { setShowDotLineGridModal, setShowColorPickerModal } = props
const { setShowDotLineGridModal } = props
const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState)
const [gridColor, setGridColor] = useRecoilState(gridColorState)
const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState)
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
const { getMessage } = useMessage()
const { tempGridMode, setTempGridMode } = useTempGrid()
const [gridColor, setGridColor] = useRecoilState(gridColorState)
const [color, setColor] = useColor(gridColor)
const [showColorPickerModal, setShowColorPickerModal] = useState(false)
useEffect(() => {
console.log('GridOption useEffect 실행')
console.log(color)
setGridColor(color.hex)
}, [color])
useEffect(() => {
gridOptions[3].selected = showColorPickerModal
setGridOptions([...gridOptions])
}, [showColorPickerModal])
useEffect(() => {
return () => {
setSettingModalGridOptions((prev) => {
const newSettingOptions = [...prev]
newSettingOptions[3].selected = false
return [...newSettingOptions]
})
}
}, [])
const onClickOption = (option) => {
const newGridOptions = [...gridOptions]
newGridOptions.map((item) => {
@ -54,6 +72,7 @@ export default function GridOption(props) {
if (option.id === 4) {
//
console.log(option)
if (option.selected) {
setShowColorPickerModal(true)
} else {
@ -64,6 +83,17 @@ export default function GridOption(props) {
setGridOptions(newGridOptions)
}
const colorPickerProps = {
color: gridColor,
setColor: setGridColor,
isShow: showColorPickerModal,
setIsShow: setShowColorPickerModal,
pos: {
x: -515,
y: -214,
},
}
return (
<>
<div className="modal-check-btn-wrap">
@ -77,6 +107,7 @@ export default function GridOption(props) {
))}
</div>
</div>
<ColorPickerModal {...colorPickerProps} />
</>
)
}

View File

@ -5,8 +5,9 @@ import React, { useEffect, useState } from 'react'
import { useAxios } from '@/hooks/useAxios'
import { useSwal } from '@/hooks/useSwal'
import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom'
import DimensionLineSetting from '@/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting'
export default function SecondOption() {
export default function SecondOption({ setShowFontSettingModal }) {
const [objectNo, setObjectNo] = useState('test123240912001') //
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
@ -18,6 +19,15 @@ export default function SecondOption() {
const { getMessage } = useMessage()
const { get, post } = useAxios()
const { swalFire } = useSwal()
const [showDimensionLineSettingModal, setShowDimensionLineSettingModal] = useState(false)
const dimensionLineSettingProps = {
isShow: showDimensionLineSettingModal,
setIsShow: setShowDimensionLineSettingModal,
pos: {
x: -515,
y: -214,
},
}
//
useEffect(() => {
@ -31,7 +41,10 @@ export default function SecondOption() {
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] }))
const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] }))
const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item, selected: res[item.column] }))
const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({
...item,
selected: res[item.column],
}))
const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item }))
const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] }))
@ -51,7 +64,14 @@ export default function SecondOption() {
const onClickOption = async (option) => {
// option4
const updatedOption4 = option4.map((item) => (item.id === option.id ? { ...item, selected: true } : { ...item, selected: false }))
const updatedOption4 = option4.map((item) =>
item.id === option.id
? { ...item, selected: true }
: {
...item,
selected: false,
},
)
setSettingModalFirstOptions({ option1, option2, dimensionDisplay })
setSettingModalSecondOptions({ option3, option4: updatedOption4 })
@ -117,6 +137,7 @@ export default function SecondOption() {
}
setAdsorptionRange(option.range)
}
return (
<>
<div className="modal-check-btn-wrap">
@ -124,7 +145,7 @@ export default function SecondOption() {
<div className="flex-check-box for2">
{settingModalSecondOptions &&
settingModalSecondOptions.option3.map((item) => (
<button key={item.id} className="arr-btn">
<button key={item.id} className="arr-btn" onClick={() => setShowFontSettingModal(true)}>
<span>{getMessage(item.name)}</span>
</button>
))}
@ -142,7 +163,7 @@ export default function SecondOption() {
))}
</div>
<div className="flex-check-box for-line">
<button className="arr-btn">
<button className="arr-btn" onClick={() => setShowDimensionLineSettingModal(true)}>
<span>{getMessage('modal.canvas.setting.font.plan.absorption.dimension.line')}</span>
</button>
<button className="arr-btn">
@ -159,6 +180,7 @@ export default function SecondOption() {
</button>
</div>
</div>
<DimensionLineSetting {...dimensionLineSettingProps} />
</>
)
}

View File

@ -10,7 +10,7 @@ import { canGridOptionSeletor } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil'
export default function SettingModal01(props) {
const { setShowCanvasSettingModal, setShowDotLineGridModal, setShowColorPickerModal } = props
const { setShowCanvasSettingModal, setShowDotLineGridModal, setShowFontSettingModal } = props
const [buttonAct, setButtonAct] = useState(1)
const { getMessage } = useMessage()
const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor)
@ -20,34 +20,36 @@ export default function SettingModal01(props) {
}
return (
<WithDraggable isShow={true} pos={{ x: 1300, y: -950 }}>
<div className={`modal-pop-wrap sm mount`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.canvas.setting')}</h1>
<button className="modal-close" onClick={() => setShowCanvasSettingModal(false)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="modal-btn-wrap">
<button className={`btn-frame modal ${buttonAct === 1 ? 'act' : ''}`} onClick={() => handleBtnClick(1)}>
{getMessage('modal.canvas.setting.display')}
<>
<WithDraggable isShow={true} pos={{ x: 1300, y: -950 }}>
<div className={`modal-pop-wrap sm mount`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.canvas.setting')}</h1>
<button className="modal-close" onClick={() => setShowCanvasSettingModal(false)}>
닫기
</button>
<button className={`btn-frame modal ${buttonAct === 2 ? 'act' : ''}`} onClick={() => handleBtnClick(2)}>
{getMessage('modal.canvas.setting.font.plan')}
</button>
{canGridOptionSeletorValue && (
<button className={`btn-frame modal ${buttonAct === 3 ? 'act' : ''}`} onClick={() => handleBtnClick(3)}>
{getMessage('modal.canvas.setting.grid')}
</button>
)}
</div>
{buttonAct === 1 && <FirstOption />}
{buttonAct === 2 && <SecondOption />}
{buttonAct === 3 && <GridOption setShowDotLineGridModal={setShowDotLineGridModal} setShowColorPickerModal={setShowColorPickerModal} />}
<div className="modal-body">
<div className="modal-btn-wrap">
<button className={`btn-frame modal ${buttonAct === 1 ? 'act' : ''}`} onClick={() => handleBtnClick(1)}>
{getMessage('modal.canvas.setting.display')}
</button>
<button className={`btn-frame modal ${buttonAct === 2 ? 'act' : ''}`} onClick={() => handleBtnClick(2)}>
{getMessage('modal.canvas.setting.font.plan')}
</button>
{canGridOptionSeletorValue && (
<button className={`btn-frame modal ${buttonAct === 3 ? 'act' : ''}`} onClick={() => handleBtnClick(3)}>
{getMessage('modal.canvas.setting.grid')}
</button>
)}
</div>
{buttonAct === 1 && <FirstOption />}
{buttonAct === 2 && <SecondOption setShowFontSettingModal={setShowFontSettingModal} />}
{buttonAct === 3 && <GridOption setShowDotLineGridModal={setShowDotLineGridModal} />}
</div>
</div>
</div>
</WithDraggable>
</WithDraggable>
</>
)
}

View File

@ -0,0 +1,51 @@
import WithDraggable from '@/components/common/draggable/withDraggable'
export default function DimensionLineSetting(props) {
const { isShow, setIsShow, pos = { x: 800, y: -950 }, setShowFontSettingModal, setShowColorPickerModal } = props
return (
<WithDraggable isShow={isShow} pos={pos}>
<div className={`modal-pop-wrap xxxm`}>
<div className="modal-head">
<h1 className="title">寸法線 設定 </h1>
<button className="modal-close">닫기</button>
</div>
<div className="modal-body">
<div className="font-btn-wrap">
<button className="btn-frame modal" onClick={() => setShowFontSettingModal(true)}>
フォント設定
</button>
</div>
<div className="line-color-wrap">
<div className="outline-form mb10">
<span style={{ width: 'auto' }}>寸法線の線太さ</span>
<div className="input-grid mr5" style={{ width: '66px' }}>
<input type="text" className="input-origin block" defaultValue={1} />
</div>
<span className="thin">pixel</span>
</div>
<div className="outline-form">
<span style={{ width: 'auto' }}>寸法線の線の色</span>
<button className="color-btn" style={{ backgroundColor: '#ff0000' }} onClick={() => setShowColorPickerModal(true)}></button>
</div>
</div>
<div className="font-ex-wrap">
<div className="font-ex-tit">見る</div>
<div className="form-box">
<div className="line-form">
<div className="line-font-box">
<span className="font" style={{ fontSize: '12px', fontWeight: '400' }}>
9,999
</span>
<span className="line" style={{ backgroundColor: '#ff0000', borderColor: '#ff0000', height: '1px' }}></span>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act">ストレージ</button>
</div>
</div>
</div>
</WithDraggable>
)
}

View File

@ -1,15 +1,17 @@
import { useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasSizeState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom'
import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom'
import { QPolygon } from '@/components/fabric/QPolygon'
// 캔버스에 필요한 이벤트
export function useCanvasEvent() {
const [canvas, setCanvasForEvent] = useState(null)
const canvas = useRecoilValue(canvasState)
const [canvasForEvent, setCanvasForEvent] = useState(null)
const [currentObject, setCurrentObject] = useRecoilState(currentObjectState)
const canvasSize = useRecoilValue(canvasSizeState)
const fontSize = useRecoilValue(fontSizeState)
const fontFamily = useRecoilValue(fontFamilyState)
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
// 기본적인 이벤트 필요시 추가
const attachDefaultEventOnCanvas = () => {
@ -167,7 +169,6 @@ export function useCanvasEvent() {
const whiteList = ['mouseLine', 'guideLine']
if (whiteList.includes(e.target.name)) {
return
}
},
}
@ -336,8 +337,16 @@ export function useCanvasEvent() {
})
}
const handleZoomClear = () => {
setCanvasZoom(100)
canvas.set({ zoom: 1 })
canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
canvas.renderAll()
}
return {
setCanvasForEvent,
attachDefaultEventOnCanvas,
handleZoomClear,
}
}

View File

@ -1,16 +1,18 @@
import { useRecoilValue } from 'recoil'
import { currentMenuState } from '@/store/canvasAtom'
import { currentMenuState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useState } from 'react'
import { MENU } from '@/common/common'
import AuxiliaryMove from '@/components/floor-plan/modal/auxiliary/AuxiliaryMove'
import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize'
export function useContextMenu() {
export function useContextMenu({ externalFn }) {
const currentMenu = useRecoilValue(currentMenuState)
const [contextMenu, setContextMenu] = useState([[]])
const [currentContextMenu, setCurrentContextMenu] = useState(null)
const currentObject = useRecoilValue(currentObjectState)
useEffect(() => {
const currentMenuSetting = () => {
console.log(currentMenu)
switch (currentMenu) {
case MENU.PLAN_DRAWING:
setContextMenu([
@ -50,6 +52,13 @@ export function useContextMenu() {
case MENU.ROOF_COVERING.DEFAULT:
setContextMenu([
[
{
id: 'refresh',
name: '새로고침',
fn: () => {
externalFn.handleZoomClear()
},
},
{
id: 'roofMaterialPlacement',
name: '지붕재 배치',
@ -150,8 +159,121 @@ export function useContextMenu() {
setContextMenu([])
break
}
}
useEffect(() => {
currentMenuSetting()
}, [currentMenu])
useEffect(() => {
console.log('currentObject', currentObject)
console.log('currentMenu', currentMenu)
if (currentObject?.name) {
console.log(currentObject)
switch (currentObject.name) {
case 'triangleDormer':
setContextMenu([
[
{
id: 'sizeEdit',
name: '사이즈 변경',
},
{
id: 'dormerRemove',
name: '삭제(D)',
},
{
id: 'dormerMove',
name: '이동(M)',
},
{
id: 'dormerCopy',
name: '복사(C)',
},
{
id: 'roofMaterialEdit',
name: '지붕재 변경',
},
{
id: 'dormerOffset',
name: '도머 오프셋',
},
],
])
break
case 'roof':
setContextMenu([
[
{
id: 'sizeEdit',
name: '사이즈 변경',
},
{
id: 'roofMaterialRemove',
name: '삭제(D)',
},
{
id: 'roofMaterialMove',
name: '이동(M)',
},
{
id: 'roofMaterialCopy',
name: '복사(C)',
},
],
[
{
id: 'roofMaterialEdit',
name: '지붕재 변경',
},
{
id: 'linePropertyEdit',
name: '각 변 속성 변경',
},
{
id: 'flowDirectionEdit',
name: '흐름 뱡향 변경',
},
],
])
break
case 'opening':
setContextMenu([
[
{
id: 'sizeEdit',
name: '사이즈 변경',
},
{
id: 'openingRemove',
name: '삭제(D)',
},
{
id: 'openingMove',
name: '이동(M)',
},
{
id: 'openingCopy',
name: '복사(C)',
},
{
id: 'openingOffset',
name: '개구 오프셋',
},
],
])
break
default:
currentMenuSetting()
}
} else {
currentMenuSetting()
}
}, [currentObject])
useEffect(() => {
console.log(currentContextMenu)
}, [currentContextMenu])
return {
contextMenu,
currentContextMenu,

26
src/hooks/usePopup.js Normal file
View File

@ -0,0 +1,26 @@
import { useRecoilState } from 'recoil'
import { popupState } from '@/store/popupAtom'
import { v4 as uuidv4 } from 'uuid'
import { useEffect } from 'react'
export function usePopup() {
const [popup, setPopup] = useRecoilState(popupState)
useEffect(() => {
console.log(popup)
}, [popup])
const addPopup = (component) => {
setPopup({ children: [...popup.children, { id: uuidv4(), component: component }] })
}
const closePopup = (id) => {
setPopup({ children: popup.children.filter((child) => child.id !== id) })
}
return {
popup,
setPopup,
addPopup,
closePopup,
}
}

View File

@ -247,6 +247,8 @@
"modal.object.setting.direction.select": "方向の選択",
"modal.placement.surface.setting.info": "ⓘ ①の長さ入力後に対角線の長さを入力すると、②の長さを自動計算します。",
"modal.placement.surface.setting.diagonal.length": "斜めの長さ",
"modal.color.picker.title": "色の設定",
"modal.color.picker.default.color": "基本色",
"setting": "設定",
"common.message.no.data": "No data",
"common.message.no.dataDown": "ダウンロードするデータがありません",

View File

@ -252,6 +252,8 @@
"modal.object.setting.direction.select": "방향 선택",
"modal.placement.surface.setting.info": "ⓘ ①의 길이 입력 후 대각선 길이를 입력하면 ②의 길이를 자동 계산합니다.",
"modal.placement.surface.setting.diagonal.length": "대각선 길이",
"modal.color.picker.title": "색 설정",
"modal.color.picker.default.color": "기본색상",
"setting": "설정",
"common.message.no.data": "No data",
"common.message.no.dataDown": "No data to download",

13
src/store/popupAtom.js Normal file
View File

@ -0,0 +1,13 @@
import { atom } from 'recoil'
/*
* id: uuid
* component: Popup Component
* */
export const popupState = atom({
key: 'popupState',
default: {
children: [],
},
dangerouslyAllowMutability: true,
})

View File

@ -34,6 +34,9 @@ $alert-color: #101010;
border-radius: 4px;
background-color: #272727;
z-index: 9999999;
&.xsm{
width: 200px;
}
&.xxxm{
width: 240px;
}
@ -1505,7 +1508,7 @@ $alert-color: #101010;
width: 16px;
height: 16px;
&.pink{
border: 2px solid #EA10AC;
border: 2px solid #ce1c9c;
background-color: #16417D;
}
&.white{
@ -1514,4 +1517,264 @@ $alert-color: #101010;
}
}
}
}
// 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%;
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 0 20px;
.line-form{
position: relative;
width: 102px;
height: 40px;
margin: 0 auto;
border-left: 1px dashed #101010;
border-right: 1px dashed #101010;
.line-font-box{
position: absolute;
bottom: -3px;
left: 0;
width: 100%;
text-align: center;
.font{
display: block;
padding-bottom: 6px;
color: #101010;
}
.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;
}
}
}