diff --git a/.gitignore b/.gitignore index 1f0de015..33c0f474 100644 --- a/.gitignore +++ b/.gitignore @@ -39,8 +39,7 @@ src/tracking/components/VesselListManager/ # 단, d.ts 타입 선언 파일은 필요시 포함 가능 # !**/*.d.ts -# Publish 폴더 (퍼블리시 원본 참조용, 빌드/커밋 제외) -src/publish/ +# Publish 폴더 (퍼블리시 원본 포함, 없어도 빌드 가능) nul 확인요청.txt diff --git a/src/App.jsx b/src/App.jsx index 11431e97..eb48247b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -8,7 +8,15 @@ import { ToastContainer } from './components/common/Toast'; // 퍼블리시 영역 (개발 환경에서만 동적 로드) // 프로덕션 빌드 시 tree-shaking으로 제외됨 const PublishRouter = import.meta.env.DEV - ? lazy(() => import('./publish')) + ? lazy(() => + import('./publish').catch(() => ({ + default: () => ( +
+ publish 폴더가 없습니다. 퍼블리시 파일을 추가하면 자동으로 활성화됩니다. +
+ ), + })) + ) : null; export default function App() { diff --git a/src/components/layout/Sidebar.jsx b/src/components/layout/Sidebar.jsx index 29105833..1702c55a 100644 --- a/src/components/layout/Sidebar.jsx +++ b/src/components/layout/Sidebar.jsx @@ -2,14 +2,18 @@ import { useState } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import SideNav, { keyToPath, pathToKey } from './SideNav'; -// 퍼블리시 패널 컴포넌트 재사용 -import Panel1Component from '../../publish/pages/Panel1Component'; -import Panel2Component from '../../publish/pages/Panel2Component'; -import Panel3Component from '../../publish/pages/Panel3Component'; -import Panel4Component from '../../publish/pages/Panel4Component'; -import Panel5Component from '../../publish/pages/Panel5Component'; -import Panel6Component from '../../publish/pages/Panel6Component'; -import Panel8Component from '../../publish/pages/Panel8Component'; +// 퍼블리시 패널 컴포넌트 (폴더 없어도 빌드 가능 — import.meta.glob은 매칭 파일 없으면 빈 객체 반환) +const publishPanels = import.meta.glob('../../publish/pages/Panel*Component.jsx', { eager: true }); +const getPanel = (name) => publishPanels[`../../publish/pages/${name}.jsx`]?.default || null; + +const Panel1Component = getPanel('Panel1Component'); +const Panel2Component = getPanel('Panel2Component'); +const Panel3Component = getPanel('Panel3Component'); +const Panel4Component = getPanel('Panel4Component'); +const Panel5Component = getPanel('Panel5Component'); +const Panel6Component = getPanel('Panel6Component'); +const Panel8Component = getPanel('Panel8Component'); + // DisplayComponent는 스토어 연결된 버전 사용 import DisplayComponent from '../../component/wrap/side/DisplayComponent'; // 구현된 페이지 @@ -55,32 +59,21 @@ export default function Sidebar() { onToggle: handleTogglePanel, }; - // 활성 키에 따른 패널 컴포넌트 렌더링 + // 활성 키에 따른 패널 컴포넌트 렌더링 (퍼블리시 패널이 없으면 null 반환) const renderPanel = () => { - switch (activeKey) { - case 'gnb1': - return ; - case 'gnb2': - return ; - case 'gnb3': - return ; - case 'gnb4': - return ; - case 'gnb5': - return ; - case 'gnb6': - return ; - case 'gnb7': - return ; - case 'gnb8': - return ; - case 'filter': - return ; - case 'layer': - return ; - default: - return null; // 선택된 메뉴 없으면 패널 없음 - } + const panelMap = { + gnb1: DisplayComponent ? : null, + gnb2: Panel2Component ? : null, + gnb3: Panel3Component ? : null, + gnb4: Panel4Component ? : null, + gnb5: Panel5Component ? : null, + gnb6: Panel6Component ? : null, + gnb7: , + gnb8: Panel8Component ? : null, + filter: DisplayComponent ? : null, + layer: DisplayComponent ? : null, + }; + return panelMap[activeKey] || null; }; return ( diff --git a/src/publish/PublishRoutes.jsx b/src/publish/PublishRoutes.jsx new file mode 100644 index 00000000..f65a738c --- /dev/null +++ b/src/publish/PublishRoutes.jsx @@ -0,0 +1,134 @@ +import { Route } from 'react-router-dom'; + +// 퍼블리시 레이아웃 컴포넌트 +import WrapComponent from './layouts/WrapComponent'; +import HeaderComponent from './layouts/HeaderComponent'; +import SideComponent from './layouts/SideComponent'; +import MainComponent from './layouts/MainComponent'; + +// 퍼블리시 페이지 컴포넌트 +import Panel1Component from './pages/Panel1Component'; +import Panel2Component from './pages/Panel2Component'; +import Panel3Component from './pages/Panel3Component'; +import Panel4Component from './pages/Panel4Component'; +import Panel5Component from './pages/Panel5Component'; +import Panel6Component from './pages/Panel6Component'; +import Panel7Component from './pages/Panel7Component'; +import Panel8Component from './pages/Panel8Component'; + +/** + * 퍼블리시 라우트 정의 + * - /publish/* 하위에서 퍼블리시 파일들을 미리볼 수 있음 + */ +const PublishRoutes = ( + <> + {/* 기본 페이지 - 전체 레이아웃 미리보기 */} + } /> + + {/* 개별 패널 미리보기 */} + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + {/* 전체 레이아웃 (원본 구조 그대로) */} + } /> + +); + +// 퍼블리시 홈 +function PublishHome() { + return ( +
+

퍼블리시 미리보기

+

좌측 메뉴에서 확인할 페이지를 선택하세요.

+
+

폴더 구조

+
+{`src/publish/
+├── _incoming/     # 새 퍼블리시 파일 (원본)
+├── layouts/       # 레이아웃 컴포넌트
+├── pages/         # 페이지 컴포넌트
+└── components/    # 공통 컴포넌트`}
+        
+

병합 방법

+
    +
  1. 새 퍼블리시 파일을 _incoming/ 폴더에 복사
  2. +
  3. Claude에게 병합 요청
  4. +
  5. 변경사항 확인 후 적용
  6. +
+
+
+ ); +} + +// 패널 래퍼 컴포넌트들 +function Panel1Wrapper() { + return ( +
+ {}} /> +
+ ); +} + +function Panel2Wrapper() { + return ( +
+ {}} /> +
+ ); +} + +function Panel3Wrapper() { + return ( +
+ {}} /> +
+ ); +} + +function Panel4Wrapper() { + return ( +
+ {}} /> +
+ ); +} + +function Panel5Wrapper() { + return ( +
+ {}} /> +
+ ); +} + +function Panel6Wrapper() { + return ( +
+ {}} /> +
+ ); +} + +function Panel7Wrapper() { + return ( +
+ {}} /> +
+ ); +} + +function Panel8Wrapper() { + return ( +
+ {}} /> +
+ ); +} + +export default PublishRoutes; diff --git a/src/publish/components/FileUpload.jsx b/src/publish/components/FileUpload.jsx new file mode 100644 index 00000000..f55348c6 --- /dev/null +++ b/src/publish/components/FileUpload.jsx @@ -0,0 +1,35 @@ +import React, { useState } from 'react'; + +export default function FileUpload({ label = "파일 선택", inputId, maxLength = 25, placeholder = "선택된 파일 없음" }) { + const [fileName, setFileName] = useState(''); + + // 중간 생략 함수 + const truncateMiddle = (str, maxLen) => { + if (!str) return ''; + if (str.length <= maxLen) return str; + const keep = Math.floor((maxLen - 3) / 2); + return str.slice(0, keep) + '...' + str.slice(str.length - keep); + }; + + const handleChange = (e) => { + const name = e.target.files[0]?.name || ''; + setFileName(name); + }; + + return ( +
+ + + + {fileName ? truncateMiddle(fileName, maxLength) : placeholder} + +
+ ); +} diff --git a/src/publish/components/Slider.jsx b/src/publish/components/Slider.jsx new file mode 100644 index 00000000..a8d7e9b2 --- /dev/null +++ b/src/publish/components/Slider.jsx @@ -0,0 +1,24 @@ +import { useState } from "react"; + +function Slider({ label = "", min = 0, max = 100, defaultValue = 50 }) { + const [value, setValue] = useState(defaultValue); + + const percent = ((value - min) / (max - min)) * 100; + + return ( + + ); +} + +export default Slider; diff --git a/src/publish/index.jsx b/src/publish/index.jsx new file mode 100644 index 00000000..0af72d8d --- /dev/null +++ b/src/publish/index.jsx @@ -0,0 +1,21 @@ +/** + * 퍼블리시 모듈 엔트리 포인트 + * 개발 환경에서만 사용되며, 프로덕션 빌드 시 제외됨 + */ +import { Routes, Route } from 'react-router-dom'; +import PublishLayout from './layouts/PublishLayout'; +import PublishRoutes from './PublishRoutes'; + +/** + * 퍼블리시 라우터 컴포넌트 + * App.jsx에서 lazy loading으로 로드됨 + */ +export default function PublishRouter() { + return ( + + }> + {PublishRoutes} + + + ); +} diff --git a/src/publish/layouts/HeaderComponent.jsx b/src/publish/layouts/HeaderComponent.jsx new file mode 100644 index 00000000..ad1626d0 --- /dev/null +++ b/src/publish/layouts/HeaderComponent.jsx @@ -0,0 +1,36 @@ + +import { Link } from "react-router-dom"; + +export default function HeaderComponent() { + return( + + ) +} \ No newline at end of file diff --git a/src/publish/layouts/MainComponent.jsx b/src/publish/layouts/MainComponent.jsx new file mode 100644 index 00000000..147476e0 --- /dev/null +++ b/src/publish/layouts/MainComponent.jsx @@ -0,0 +1,11 @@ +import { Outlet } from "react-router-dom"; +import TopComponent from "../pages/TopComponent"; + +export default function MainComponent() { + return ( +
+ + +
+ ); +} diff --git a/src/publish/layouts/PublishLayout.jsx b/src/publish/layouts/PublishLayout.jsx new file mode 100644 index 00000000..a7d5adca --- /dev/null +++ b/src/publish/layouts/PublishLayout.jsx @@ -0,0 +1,57 @@ +import { Outlet, Link, useLocation } from 'react-router-dom'; + +/** + * 퍼블리시 레이아웃 + * - 퍼블리시 파일들을 미리보기 위한 레이아웃 + * - 상단에 네비게이션 제공 + */ +export default function PublishLayout() { + const location = useLocation(); + const currentPath = location.pathname; + + const menuItems = [ + { path: '/publish', label: '메인', exact: true }, + { path: '/publish/panel1', label: 'Panel1 (선박)' }, + { path: '/publish/panel2', label: 'Panel2 (위성)' }, + { path: '/publish/panel3', label: 'Panel3 (기상)' }, + { path: '/publish/panel4', label: 'Panel4 (분석)' }, + { path: '/publish/panel5', label: 'Panel5 (타임라인)' }, + { path: '/publish/panel6', label: 'Panel6 (AI모드)' }, + { path: '/publish/panel7', label: 'Panel7 (리플레이)' }, + { path: '/publish/panel8', label: 'Panel8 (항적조회)' }, + ]; + + const isActive = (path, exact) => { + if (exact) return currentPath === path; + return currentPath.startsWith(path); + }; + + return ( +
+ {/* 퍼블리시 네비게이션 */} + + + {/* 퍼블리시 콘텐츠 */} +
+ +
+
+ ); +} diff --git a/src/publish/layouts/SideComponent.jsx b/src/publish/layouts/SideComponent.jsx new file mode 100644 index 00000000..40be2dba --- /dev/null +++ b/src/publish/layouts/SideComponent.jsx @@ -0,0 +1,94 @@ +import { useState } from "react"; +import { useNavigate, useLocation } from "react-router-dom"; + +import NavComponent from "../pages/NavComponent"; +import Panel1Component from "../pages/Panel1Component"; +import Panel2Component from "../pages/Panel2Component"; +import Panel3Component from "../pages/Panel3Component"; +import Panel4Component from "../pages/Panel4Component"; +import Panel5Component from "../pages/Panel5Component"; +import Panel6Component from "../pages/Panel6Component"; +import Panel7Component from "../pages/Panel7Component"; +import Panel8Component from "../pages/Panel8Component"; +import DisplayComponent from "../pages/DisplayComponent"; + +export default function SideComponent() { + const navigate = useNavigate(); + //const location = useLocation(); + + // 현재열린패널 + const [activePanel, setActivePanel] = useState("gnb1"); + + // 패널열린상태 + const [isPanelOpen, setIsPanelOpen] = useState(true); + const handleTogglePanel = () => setIsPanelOpen(prev => !prev); + + // Display 탭상태 + const [displayTab, setDisplayTab] = useState("filter"); + + /* ========================= + Nav 클릭 → 패널 + 라우팅 + ========================= */ + const handleChangePanel = (key) => { + setIsPanelOpen(true); + //setActivePanel(key); // navigate 없음 + + switch (key) { + case "gnb8": //항적조회 + setActivePanel("gnb8"); + navigate("/track"); + break; + + case "gnb7": // 리플레이 + setActivePanel("gnb7"); + navigate("/replay"); + break; + + case "filter": // 필터 + case "layer": // 레이어 + setActivePanel(key); + setDisplayTab(key); + + // 항적조회/리플레이에서 넘어올 경우 메인 초기화 + navigate("/main"); + break; + + default: + setActivePanel(key); + navigate("/main"); + break; + } + }; + + /* ========================= + 공통 props + ========================= */ + const panelProps = { + isOpen: isPanelOpen, + onToggle: handleTogglePanel, + }; + + return ( +
+ + +
+ {activePanel === "gnb1" && } + {activePanel === "gnb2" && } + {activePanel === "gnb3" && } + {activePanel === "gnb4" && } + {activePanel === "gnb5" && } + {activePanel === "gnb6" && } + {activePanel === "gnb7" && } + {activePanel === "gnb8" && } + {(activePanel === "filter" || activePanel === "layer") && ( + + )} +
+
+ ); +} diff --git a/src/publish/layouts/ToolComponent.jsx b/src/publish/layouts/ToolComponent.jsx new file mode 100644 index 00000000..99ac99cf --- /dev/null +++ b/src/publish/layouts/ToolComponent.jsx @@ -0,0 +1,131 @@ +import { useState } from "react" +export default function ToolComponent() { + const [isLegendOpen, setIsLegendOpen] = useState(false); + + return( +
+ {/* 툴바 */} +
+
    +
  • +
  • +
  • +
+
    +
  • +
  • +
  • +
+
    +
  • +
  • +
+
+ {/* 맵컨트롤 툴바 */} +
+
    +
  • +
  • 7
  • +
  • +
+
    +
  • +
  • +
  • +
+
+ {/* 범례 */} + {isLegendOpen && ( +
+
    +
  • + 통합통합 + 0 +
  • +
  • + 중국어선중국어선 + 0 +
  • +
  • + 중국어선허가중국어선허가 + 0 +
  • +
  • + 일본어선일본어선 + 0 +
  • +
  • + 위험물위험물 + 0 +
  • +
  • + 여객선여객선 + 0 +
  • +
  • + 함정함정 + 0 +
  • +
  • + 함정-RADAR함정-RADAR + 0 +
  • +
  • + 일반일반 + 0 +
  • +
  • + VTS-일반VTS-일반 + 0 +
  • +
  • + VTS-RADARVTS-RADAR + 0 +
  • +
  • + VPASS일반VPASS일반 + 0 +
  • +
  • + ENAV어선ENAV어선 + 0 +
  • +
  • + ENAV위험물ENAV위험물 + 0 +
  • +
  • + ENAV화물선ENAV화물선 + 0 +
  • +
  • + ENAV관공선ENAV관공선 + 0 +
  • +
  • + ENAV일반ENAV일반 + 0 +
  • +
  • + D-MF/HFD-MF/HF + 0 +
  • +
  • + 항공기항공기 + 0 +
  • +
  • + NLLNLL + 0 +
  • +
+
+ )} +
+ ) +} \ No newline at end of file diff --git a/src/publish/layouts/WrapComponent.jsx b/src/publish/layouts/WrapComponent.jsx new file mode 100644 index 00000000..f4030866 --- /dev/null +++ b/src/publish/layouts/WrapComponent.jsx @@ -0,0 +1,15 @@ +import { Outlet } from "react-router-dom"; +import HeaderComponent from "./HeaderComponent"; +import SideComponent from "./SideComponent"; +import ToolComponent from "./ToolComponent"; + +export default function WrapComponent() { + return ( +
+ + + {/* Main 영역 */} + +
+ ); +} diff --git a/src/publish/pages/Analysis1Component.jsx b/src/publish/pages/Analysis1Component.jsx new file mode 100644 index 00000000..9c09260b --- /dev/null +++ b/src/publish/pages/Analysis1Component.jsx @@ -0,0 +1,48 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Analysis1Component() { + const navigate = useNavigate(); + + return ( +
+ + {/* 위성 영상 등록 팝업 */} +
+
+
+ 관심 해역 설정 +
+ +
+
+ + + +
+
+ +
+
+ +
+ ); +} diff --git a/src/publish/pages/Analysis2Component.jsx b/src/publish/pages/Analysis2Component.jsx new file mode 100644 index 00000000..b0684528 --- /dev/null +++ b/src/publish/pages/Analysis2Component.jsx @@ -0,0 +1,129 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Analysis2Component() { + const navigate = useNavigate(); + + return ( +
+ + {/* 위성 영상 등록 팝업 */} +
+
+
+ 관심 해역 설정 +
+ +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
관심 해역 설정 - 해상영역명, 설정 옵션, 좌표,영역 옵션,해상영역명 크기, 해상영역명 색상,윤곽선 굵기,윤곽선 종류,윤곽선 색상,채우기 색상 에 대한 내용을 등록하는 표입니다.
해상영역명
설정 옵션 +
+ + + +
+
좌표[124,96891368166156, 36.37855817450263]
+ [125,25105622872591, 36.37855817450263]
+ [125,25105622872591, 36.37855817450263]
+ [125,25105622872591, 36.37855817450263]
+ [125,25105622872591, 36.37855817450263] +
영역 옵션 +
+ + +
+
해상영역명 크기 +
+ +
+ + +
+
+
해상영역명 색상
윤곽선 굵기 +
+ +
+ + +
+
+
윤곽선 종류 + +
윤곽선 색상 채우기 색상
+
+ +
+
+ + +
+
+
+
+
+ ); +} diff --git a/src/publish/pages/Analysis3Component.jsx b/src/publish/pages/Analysis3Component.jsx new file mode 100644 index 00000000..0ccc457a --- /dev/null +++ b/src/publish/pages/Analysis3Component.jsx @@ -0,0 +1,198 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Analysis3Component() { + const navigate = useNavigate(); + + return ( +
+ + {/* 위성 영상 등록 팝업 */} +
+
+
+ 관심 해역 분석 등록 +
+ +
+ +
+ {/* 지도캡쳐/테이블 영역 */} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
관심 해역 분석 등록 - 제목, 상세 내역, 공유 여부,공유 그룹 에 대한 내용을 등록하는 표입니다.
제목
상세 내역 + +
공유 여부 +
+ + +
+
공유 그룹 + +
+
+ {/* 관심영역 체크박스 목록 -스크롤됨 */} +
+
관심영역 목록
+
    +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
  • + + +
  • +
+
+
+
+ +
+
+ + +
+
+
+
+
+ ); +} diff --git a/src/publish/pages/Analysis4Component.jsx b/src/publish/pages/Analysis4Component.jsx new file mode 100644 index 00000000..efdc3c4d --- /dev/null +++ b/src/publish/pages/Analysis4Component.jsx @@ -0,0 +1,235 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Analysis4Component() { + const navigate = useNavigate(); + + return ( +
+ + {/* 위성 영상 등록 팝업 */} +
+
+
+
+ 350 대해구도 + 조회시간: 2026-07-00 17:15:13 +
+ +
+ +
+ +
+ {/* 지도캡쳐/테이블 영역 */} +
+
통항 선박
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
통항 선박 - 선박 종류, 승선원, 위험물 운반, 공유 여부 및 그룹 에 대한 표입니다
카고(척)0
카고 승성원(명)-
탱커수(척)
탱커 승선원(명)
위험물 운반석(척)
위험물 운반선 승선원(명)
위험물 양(톤)
어선(척)
어선 승선원(명)
기타 어선(척)
기타 어선 승선원(명)
여객선(척)
유도선(척)
유도선 승선원(명)
기타 선박(척)
기타 선박 승선원(명)
함정수(척)
+
+ {/* 관심영역 체크박스 목록 -스크롤됨 */} +
+
신호별
+ + + + + + + + + + + + + + + + + + + + + + + + +
신호별 - 제목, 상세 내역, 공유 여부,공유 그룹 에 대한 내용을 등록하는 표입니다.
AIS0
V-PASS-
VHF
MFHF
+ + +
E-NAV
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
E-NAV - 여객선, 어선, 카고, 관공선, 기타 선박과 공유 정보 에 대한 표입니다.
E-NAV 여객선(척)0
E-NAV 어선(척)-
E-NAV 카고(척)
E-NAV 관공선(척)
E-NAV 기타(척)
+ + +
기상정보
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
기상정보 - 유향, 유속, 유의 파고, 파향, 파주기, 풍속, 풍향 을 나타내는 표입니다
유향0
유속-
유의 파고0.5(m)
파향 +
+ 파향 + 350(°) +
+
파주기3.7(s)
풍속9.2(m/s)
풍향 +
+ 풍향 + 45(°) +
+
+
+
+
+ +
+
+
+
+
+ ); +} diff --git a/src/publish/pages/DisplayComponent.jsx b/src/publish/pages/DisplayComponent.jsx new file mode 100644 index 00000000..bf57d9e0 --- /dev/null +++ b/src/publish/pages/DisplayComponent.jsx @@ -0,0 +1,355 @@ +import { useEffect, useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import Slider from '../components/Slider'; + +export default function DisplayComponent({ isOpen, onToggle, activeTab: externalTab }) { + const navigate = useNavigate(); + + // 투명도 + const [opacity, setOpacity] = useState(70); + + // 아코디언 + const [isAccordionOpen1, setIsAccordionOpen1] = useState(true); // 기존 + const [isAccordionOpen2, setIsAccordionOpen2] = useState(true); // + const [isAccordionOpen3, setIsAccordionOpen3] = useState(true); // + const [isAccordionOpen4, setIsAccordionOpen4] = useState(false); // + + const toggleAccordion1 = () => setIsAccordionOpen1(prev => !prev); + const toggleAccordion2 = () => setIsAccordionOpen2(prev => !prev); + const toggleAccordion3 = () => setIsAccordionOpen3(prev => !prev); + const toggleAccordion4 = () => setIsAccordionOpen4(prev => !prev); + + // 탭이동 + const [activeTab, setActiveTab] = useState('filter'); + + useEffect(() => { + if (externalTab) { + setActiveTab(externalTab); + } + }, [externalTab]); + + const tabs = [ + { id: 'filter', label: '필터' }, + { id: 'layer', label: '레이어' }, + ]; + return ( + + ); +} diff --git a/src/publish/pages/EmptyMain.jsx b/src/publish/pages/EmptyMain.jsx new file mode 100644 index 00000000..2550b09a --- /dev/null +++ b/src/publish/pages/EmptyMain.jsx @@ -0,0 +1,4 @@ + +export default function EmptyMain() { + return null; // 또는 지도만 보여주는 영역 +} diff --git a/src/publish/pages/LayerComponent.jsx b/src/publish/pages/LayerComponent.jsx new file mode 100644 index 00000000..1117ff3f --- /dev/null +++ b/src/publish/pages/LayerComponent.jsx @@ -0,0 +1,91 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; +import FileUpload from '../components/FileUpload'; + +export default function LayerComponent() { + const navigate = useNavigate(); + + return ( +
+ + {/* 레이어등록 팝업 */} +
+
+
+ 레이어 등록 +
+ +
+ + + + + + + + + + + + + + + + + + + + +
레이어등록 - 레이어명, 첨부파일, 공유설정 에 대한 내용을 나타내는 표입니다.
레이어명 *
첨부파일 * +
+ + geojson 파일을 첨부해 주세요. +
+
공유설정 +
+ + + +
+
+
+ +
+
+ + +
+
+
+
+
+ ); +} diff --git a/src/publish/pages/MyPageComponent.jsx b/src/publish/pages/MyPageComponent.jsx new file mode 100644 index 00000000..c8824c42 --- /dev/null +++ b/src/publish/pages/MyPageComponent.jsx @@ -0,0 +1,208 @@ +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; + +export default function MyPageComponent() { + const navigate = useNavigate(); + + // 서브 팝업 상태 + // null | "password" | "cert" + const [subPopup, setSubPopup] = useState(null); + + return ( +
+ + {/* 내 정보 조회 */} +
+
+
+ 내 정보 조회 +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 내 정보 조회 - 아이디, 비밀번호, 이름, 이메일, 직급, 상세소속, 공인인증서 삭제 +
아이디admin222
비밀번호 + +
이름ADMIN
이메일123@korea.kr
직급경감
상세소속
공인인증서 삭제 + +
+
+ +
+
+ + +
+
+
+
+ + {/* 딤 + 서브 팝업 */} + {subPopup && ( +
+ + {/* 비밀번호 변경 */} + {subPopup === "password" && ( +
+
+ 비밀번호 수정 +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ 비밀번호 수정 - 현재 비밀번호, 새 비밀번호, 새 비밀번호 확인 +
현재 비밀번호 + +
새 비밀번호 + +
새 비밀번호 확인 + +
+
+ +
+
+ + +
+
+
+ )} + + {/* 공인인증서 삭제 */} + {subPopup === "cert" && ( +
+
+ 공인인증서 삭제 +
+ +
+
+ 공인인증서를 삭제 하시겠습니까? +
+
+ +
+
+ + +
+
+
+ )} + +
+ )} +
+ ); +} diff --git a/src/publish/pages/NavComponent.jsx b/src/publish/pages/NavComponent.jsx new file mode 100644 index 00000000..bf44b8d7 --- /dev/null +++ b/src/publish/pages/NavComponent.jsx @@ -0,0 +1,71 @@ +export default function NavComponent({ activeKey, onChange }) { + const gnbList = [ + { key: 'gnb1', class: 'gnb1', label: '선박' }, + { key: 'gnb2', class: 'gnb2', label: '위성' }, + { key: 'gnb3', class: 'gnb3', label: '기상' }, + { key: 'gnb4', class: 'gnb4', label: '분석' }, + { key: 'gnb5', class: 'gnb5', label: '타임라인' }, + { key: 'gnb6', class: 'gnb6', label: 'AI모드' }, + { key: 'gnb7', class: 'gnb7', label: '리플레이' }, + { key: 'gnb8', class: 'gnb8', label: '항적조회' }, + ]; + + const sideList = [ + { key: 'filter', class: 'filter', label: '필터' }, + { key: 'layer', class: 'layer', label: '레이어' }, + ]; + + return( + + ) +} diff --git a/src/publish/pages/Panel1Component.jsx b/src/publish/pages/Panel1Component.jsx new file mode 100644 index 00000000..8912f09c --- /dev/null +++ b/src/publish/pages/Panel1Component.jsx @@ -0,0 +1,727 @@ +import { useState, useEffect } from 'react'; +import { Link } from "react-router-dom"; +import Panel1DetailComponent from './Panel1DetailComponent'; + +export default function Panel1Component({ isOpen, onToggle }) { + // 내부 뷰 상태 + const [view, setView] = useState('list'); // list | detail + + // 아코디언 + const [isAccordionOpen1, setIsAccordionOpen1] = useState(false); // 기존 + const [isAccordionOpen2, setIsAccordionOpen2] = useState(false); // 새 아코디언 + + const toggleAccordion1 = () => setIsAccordionOpen1(prev => !prev); + const toggleAccordion2 = () => setIsAccordionOpen2(prev => !prev); + + // 탭이동 + const [activeTab, setActiveTab] = useState('ship01'); + + const tabs = [ + { id: 'ship01', label: '선박검색' }, + { id: 'ship02', label: '허가선박' }, + { id: 'ship03', label: '제재단속' }, + { id: 'ship04', label: '침몰선박' }, + { id: 'ship05', label: '선박입출항' }, + { id: 'ship06', label: '관심선박' } + ]; + return ( + + ); +} diff --git a/src/publish/pages/Panel1DetailComponent.jsx b/src/publish/pages/Panel1DetailComponent.jsx new file mode 100644 index 00000000..f1c74977 --- /dev/null +++ b/src/publish/pages/Panel1DetailComponent.jsx @@ -0,0 +1,112 @@ +import { useState, useEffect } from 'react'; +import { Link } from "react-router-dom"; + +export default function Panel1DetailComponent({ isOpen, onToggle, onBack }) { + + // 탭이동 + const [activeTab, setActiveTab] = useState('ship02'); + + const tabs = [ + { id: 'ship01', label: '선박검색' }, + { id: 'ship02', label: '허가선박' }, + { id: 'ship03', label: '제재단속' }, + { id: 'ship04', label: '침몰선박' }, + { id: 'ship05', label: '선박입출항' }, + { id: 'ship06', label: '관심선박' } + ]; + return ( + <> + {/* */} + + ); +} diff --git a/src/publish/pages/Panel2Component.jsx b/src/publish/pages/Panel2Component.jsx new file mode 100644 index 00000000..39ae3930 --- /dev/null +++ b/src/publish/pages/Panel2Component.jsx @@ -0,0 +1,420 @@ +import { useState } from 'react'; +import { Link, useNavigate } from "react-router-dom"; +import Slider from '../components/Slider'; + +export default function Panel2Component({ isOpen, onToggle }) { + const navigate = useNavigate(); + + // 아코디언 + const [isAccordionOpen1, setIsAccordionOpen1] = useState(false); // 기존 + const [isAccordionOpen2, setIsAccordionOpen2] = useState(false); // 새 아코디언 + + const toggleAccordion1 = () => setIsAccordionOpen1(prev => !prev); + const toggleAccordion2 = () => setIsAccordionOpen2(prev => !prev); + + // 탭이동 + const [activeTab, setActiveTab] = useState('ship01'); + + const tabs = [ + { id: 'ship01', label: '위성영상 관리' }, + { id: 'ship02', label: '위성사업자 관리' }, + { id: 'ship03', label: '위성 관리' }, + ]; + return ( + + ); +} diff --git a/src/publish/pages/Panel3Component.jsx b/src/publish/pages/Panel3Component.jsx new file mode 100644 index 00000000..55780771 --- /dev/null +++ b/src/publish/pages/Panel3Component.jsx @@ -0,0 +1,322 @@ +import { useState } from 'react'; +import { Link } from "react-router-dom"; +export default function Panel3Component({ isOpen, onToggle }) { + + // 탭이동 + const [activeTab, setActiveTab] = useState('weather01'); + + const tabs = [ + { id: 'weather01', label: '기상특보' }, + { id: 'weather02', label: '태풍정보' }, + { id: 'weather03', label: '조위관측' }, + { id: 'weather04', label: '조석정보' }, + { id: 'weather05', label: '항공기상' }, + ]; + return ( + + ); +} diff --git a/src/publish/pages/Panel4Component.jsx b/src/publish/pages/Panel4Component.jsx new file mode 100644 index 00000000..1d5bfec2 --- /dev/null +++ b/src/publish/pages/Panel4Component.jsx @@ -0,0 +1,521 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; +export default function Panel4Component({ isOpen, onToggle }) { + const navigate = useNavigate(); + + // 아코디언 + const [isAccordionOpen1, setIsAccordionOpen1] = useState(false); // 기존 + const toggleAccordion1 = () => setIsAccordionOpen1(prev => !prev); + + // 탭이동 + const [activeTab, setActiveTab] = useState('analysis01'); + + const tabs = [ + { id: 'analysis01', label: '관심 해역' }, + { id: 'analysis02', label: '해역 분석' }, + { id: 'analysis03', label: '해역 진입 선박' }, + { id: 'analysis04', label: '해구 분석' }, + ]; + return ( + + ); +} diff --git a/src/publish/pages/Panel5Component.jsx b/src/publish/pages/Panel5Component.jsx new file mode 100644 index 00000000..a469706d --- /dev/null +++ b/src/publish/pages/Panel5Component.jsx @@ -0,0 +1,7 @@ +import { useState } from "react"; +export default function Panel5Component() { + + return ( +
+ ); +} diff --git a/src/publish/pages/Panel6Component.jsx b/src/publish/pages/Panel6Component.jsx new file mode 100644 index 00000000..513549d1 --- /dev/null +++ b/src/publish/pages/Panel6Component.jsx @@ -0,0 +1,77 @@ +import { useState } from "react"; +import { Link } from "react-router-dom"; +export default function Panel6Component({ isOpen, onToggle }) { + + return ( + + ); +} diff --git a/src/publish/pages/Panel7Component.jsx b/src/publish/pages/Panel7Component.jsx new file mode 100644 index 00000000..3389c12a --- /dev/null +++ b/src/publish/pages/Panel7Component.jsx @@ -0,0 +1,7 @@ +import { useState } from "react"; +export default function Panel7Component() { + + return ( +
+ ); +} diff --git a/src/publish/pages/Panel8Component.jsx b/src/publish/pages/Panel8Component.jsx new file mode 100644 index 00000000..868a706e --- /dev/null +++ b/src/publish/pages/Panel8Component.jsx @@ -0,0 +1,7 @@ +import { useState } from "react"; +export default function Panel8Component() { + + return ( +
+ ); +} diff --git a/src/publish/pages/ReplayComponent.jsx b/src/publish/pages/ReplayComponent.jsx new file mode 100644 index 00000000..7f734dcd --- /dev/null +++ b/src/publish/pages/ReplayComponent.jsx @@ -0,0 +1,100 @@ + +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; + +export default function ReplayComponent() { + const navigate = useNavigate(); + + const max = 100; + const [value, setValue] = useState(30); + + const percent = (value / max) * 100; + + return( +
+ +
+ + +
+ {/* 재생상태 컨트롤 */} +
+
+ + +
+ +
+ setValue(Number(e.target.value))} + style={{ + background: `linear-gradient( + to right, + #FF0000 0%, + #FF0000 ${percent}%, + #D7DBEC ${percent}%, + #D7DBEC 100% + )` + }} + /> +
+ 2023-08-20  10:15:30 +
+
+ +
+ + +
+ +
+ {/* 재생옵션 영역 */} +
+ + +
+ +
+
+ +
+ ) +} \ No newline at end of file diff --git a/src/publish/pages/Satellite1Component.jsx b/src/publish/pages/Satellite1Component.jsx new file mode 100644 index 00000000..d9ad226a --- /dev/null +++ b/src/publish/pages/Satellite1Component.jsx @@ -0,0 +1,189 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; +import FileUpload from '../components/FileUpload'; + +export default function Satellite1Component() { + const navigate = useNavigate(); + + return ( +
+ + {/* 위성 영상 등록 팝업 */} +
+
+
+ 위성 영상 등록 +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
위성 영상 등록 - 사업자명/위성명, 영상 촬영일, 위성영상파일,CSV 파일,위성영상명, 영상전송 주기,영상 종류,위성 궤도,영상 출처,촬영 목적,촬영 모드,취득방법,구매가격, 에 대한 내용을 등록하는 표입니다.
사업자명/위성명 * +
+ + +
+
영상 촬영일 *
위성영상파일 * +
+ +
+
CSV 파일 * +
+ +
+
위성영상명 *
영상전송 주기 + +
영상 종류 +
+ + + + + +
+
위성 궤도 + + 영상 출처 + +
촬영 목적 + + 촬영 모드 + +
취득방법 + + 구매가격 +
+ +
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+ ); +} diff --git a/src/publish/pages/Satellite2Component.jsx b/src/publish/pages/Satellite2Component.jsx new file mode 100644 index 00000000..5d604e62 --- /dev/null +++ b/src/publish/pages/Satellite2Component.jsx @@ -0,0 +1,87 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Satellite2Component() { + const navigate = useNavigate(); + return ( +
+ + {/* 위성 사업자 등록 팝업 */} +
+
+
+ 위성 사업자 등록 +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
위성 사업자 등록 - 사업자 분류, 사업자명, 국가, 소재지, 상세내역 에 대한 내용을 등록하는 표입니다.
사업자 분류 * + +
사업자명
국가 * + +
소재지
상세내역
+
+ +
+
+ + +
+
+
+
+ +
+ ); +} diff --git a/src/publish/pages/Satellite3Component.jsx b/src/publish/pages/Satellite3Component.jsx new file mode 100644 index 00000000..f24eec73 --- /dev/null +++ b/src/publish/pages/Satellite3Component.jsx @@ -0,0 +1,94 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Satellite3Component() { + const navigate = useNavigate(); + + return ( +
+ + {/* 위성 관리 등록 팝업 */} +
+
+
+ 위성 관리 등록 +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
위성 관리 등록 - 사업자명, 위성명, 센서 타입, 촬영 해상도, 주파수, 상세내역 에 대한 내용을 등록하는 표입니다.
사업자명 * + +
위성명 *
센서 타입 + +
촬영 해상도
주파수
상세내역
+
+ +
+
+ + +
+
+
+
+ +
+ ); +} diff --git a/src/publish/pages/Satellite4Component.jsx b/src/publish/pages/Satellite4Component.jsx new file mode 100644 index 00000000..05c705a7 --- /dev/null +++ b/src/publish/pages/Satellite4Component.jsx @@ -0,0 +1,50 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Satellite4Component() { + const navigate = useNavigate(); + + return ( +
+ + {/* 삭제 팝업 */} +
+
+
+ 삭제 +
+ +
+
삭제 하시겠습니까?
+
+ +
+
+ + +
+
+
+
+ +
+ ); +} diff --git a/src/publish/pages/ShipComponent.jsx b/src/publish/pages/ShipComponent.jsx new file mode 100644 index 00000000..bc54d6fa --- /dev/null +++ b/src/publish/pages/ShipComponent.jsx @@ -0,0 +1,169 @@ +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; + +export default function ShipComponent() { + const navigate = useNavigate(); + + //progress bar value 선언 + const [value, setValue] = useState(60); + + // 갤러리 이미지 + const images = [ + { src: "/images/photo_ship_001.png", alt: "1511함A-05" }, + { src: "/images/photo_ship_002.png", alt: "1511함A-05" }, + ]; + + const [currentIndex, setCurrentIndex] = useState(0); + + const handlePrev = () => { + if (currentIndex === 0) return; + setCurrentIndex(prev => prev - 1); + }; + + const handleNext = () => { + if (currentIndex === images.length - 1) return; + setCurrentIndex(prev => prev + 1); + }; + + return( +
+ + {/* 배정보 팝업 */} +
+ {/* header */} +
+
+ + 대한민국 + 1511함A-05 + 13450135 +
+
+ +
+ + + + {/* 이미지 영역 */} +
+ {images[currentIndex].alt} +
+
+ {/* body */} +
+
+
+ +
    +
  • A
  • +
  • V
  • +
  • E
  • +
  • T
  • +
  • D
  • +
  • R
  • +
+
+ +
+ +
+
+ {value}% + +
+
+ +
    +
  • +
    + 출항지 + 서귀포해양경찰서 +
    +
    + 입항지 + 하태도 +
    +
  • +
  • +
    + 출항일시 + 2024-11-23 11:23:00 +
    +
    + 입항일시 + 2024-11-23 11:23:00 +
    +
  • +
  • +
    + 선박상태 + 정박 +
    +
    + 속도/항로 + 4.2 kn / 13.3˚ +
    +
    + 흘수 + 1.1m +
    +
  • +
+ + {/*
    +
  • + AIS + 정상 +
  • +
  • + RF + 정상 +
  • +
  • + EO + 정상 +
  • +
  • + SAR + 비활성 +
  • +
*/} +
+ + +
+
+ {/* footer */} +
데이터 수신시간 : 2024-11-23 11:23:00
+
+ +
+ ) +} \ No newline at end of file diff --git a/src/publish/pages/Signal1Component.jsx b/src/publish/pages/Signal1Component.jsx new file mode 100644 index 00000000..f64b90fa --- /dev/null +++ b/src/publish/pages/Signal1Component.jsx @@ -0,0 +1,58 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Signal1Component() { + const navigate = useNavigate(); + + return ( +
+ + {/* 신호설정 팝업 */} +
+
+
+ 신호설정 +
+ +
+ + + + + + + + + + + + + + + + +
신호설정 - 신호표출반경, 수신수기 설정 에 대한 내용을 나타내는 표입니다.
신호표출반경 + +
수신수기 설정
+
+ +
+
+ + +
+
+
+
+ +
+ ); +} diff --git a/src/publish/pages/Signal2Component.jsx b/src/publish/pages/Signal2Component.jsx new file mode 100644 index 00000000..99f4e694 --- /dev/null +++ b/src/publish/pages/Signal2Component.jsx @@ -0,0 +1,149 @@ +import { useState } from 'react'; +import { useNavigate } from "react-router-dom"; + +export default function Signal2Component() { + const navigate = useNavigate(); + + // 아코디언 상태 (3개, 초기 모두 열림) + const [accordionOpen, setAccordionOpen] = useState({ + signal1: true, + signal2: true, + signal3: true, + }); + + const toggleAccordion = (key) => { + setAccordionOpen((prev) => ({ ...prev, [key]: !prev[key] })); + }; + + return ( +
+ + {/* 신호설정 팝업 */} +
+
+
+ 맞춤 설정 +
+ +
+ {/* 아코디언그룹 01 */} +
+
+ NLL 고속 선박 탐지 + +
+ {/* 여기서부터 아코디언 */} +
+
    +
  • + + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ {/* 여기까지 */} +
+ + {/* 아코디언그룹 02 */} +
+
+ 특정 어업수역 탐지 + +
+ {/* 여기서부터 아코디언 */} +
+
    +
  • + + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ {/* 여기까지 */} +
+ + {/* 아코디언그룹 03 */} +
+
+ 위험화물 식별 + +
+ {/* 여기서부터 아코디언 */} +
+
    +
  • + + +
  • +
+
+ {/* 여기까지 */} +
+
+ +
+
+ + +
+
+
+
+ +
+ ); +} diff --git a/src/publish/pages/ToastComponent.jsx b/src/publish/pages/ToastComponent.jsx new file mode 100644 index 00000000..1748fe4b --- /dev/null +++ b/src/publish/pages/ToastComponent.jsx @@ -0,0 +1,59 @@ +import { Link } from "react-router-dom"; + +export default function ToastComponent() { + return( +
+ + {/* 지도상 배표식 */} +
+
+ + 1511함A-05 + 12.5 kts | 45° + +
+ +
+ + 1511함A-05 + 12.5 kts | 45° + +
+ +
+ + 1511함A-05 + 12.5 kts | 45° + +
+
+ + {/* 토스트팝업 */} +
+
+ 104 어업구역 비인가 선박 + + + + +
+ +
+ 104 어업구역 비인가 선박 + + + + +
+ +
+ 저속 이동 의심 선박 + + + + +
+
+
+ ) +} \ No newline at end of file diff --git a/src/publish/pages/TopComponent.jsx b/src/publish/pages/TopComponent.jsx new file mode 100644 index 00000000..f1ffa98a --- /dev/null +++ b/src/publish/pages/TopComponent.jsx @@ -0,0 +1,21 @@ +export default function TopComponent() { + return( +
+
+
    +
  • +
  • 경도129° 38’31.071”E
  • +
  • 위도35° 21’24.580”N
  • +
  • KST2024-07-01(화) 12:00:00
  • +
  • +
  • +
+
+ +
+ + +
+
+ ) +} \ No newline at end of file diff --git a/src/publish/pages/TrackComponent.jsx b/src/publish/pages/TrackComponent.jsx new file mode 100644 index 00000000..9216aa70 --- /dev/null +++ b/src/publish/pages/TrackComponent.jsx @@ -0,0 +1,41 @@ + +import { useNavigate } from "react-router-dom"; + +export default function TrackComponent() { + const navigate = useNavigate(); + + return( +
+ +
+ + + {/* 항적조회 검색바 */} +
+ + + +
+ +
+ +
+ ) +} \ No newline at end of file diff --git a/src/publish/pages/WeatherComponent.jsx b/src/publish/pages/WeatherComponent.jsx new file mode 100644 index 00000000..eb664225 --- /dev/null +++ b/src/publish/pages/WeatherComponent.jsx @@ -0,0 +1,71 @@ +import { useNavigate } from "react-router-dom"; + +export default function WeatherComponent() { + const navigate = useNavigate(); + + return( +
+ +
+ {/* header */} +
+
+ 해양관측소 +
+ +
+ {/* body */} +
+ +
    +
  • + 2023.10.16 20:54 +
  • +
  • + 조위 + 251(cm) +
  • +
  • + 수온 + 19.6(°C) +
  • +
  • + 염분 + 31.8(PSU) +
  • +
  • + 기온 + 16.9(°C) +
  • +
  • + 기압 + 1016.6(hPa) +
  • +
  • + 풍향 + 315(deg) +
  • +
  • + 풍속 + 7.1(m/s) +
  • +
  • + 유속방향 + -(deg) +
  • +
  • + 유속 + -(m/s) +
  • +
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/publish/scss/HeaderComponent.scss b/src/publish/scss/HeaderComponent.scss new file mode 100644 index 00000000..d033824c --- /dev/null +++ b/src/publish/scss/HeaderComponent.scss @@ -0,0 +1,109 @@ + +@charset "utf-8"; + +#wrap { + + /* header */ + #header { + width: 100%; + height: 4.4rem; + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + background: var(--secondary5); + + .logoArea { + display: flex; + align-items: center; + + .logo { + width: 4.3rem; + height: 4.4rem; + display: flex; + align-items: center; + justify-content: center; + background: url(../assets/images/logo.svg) no-repeat center / contain; + } + + .logoTxt { + color: var(--white); + font-weight: var(--fw-bold); + } + } + + aside { + ul { + display: flex; + + li { + position: relative; + width: 3rem; + height: 3rem; + margin-right: .9rem; + + &.setWrap:hover .setMenu { + display: block; + } + + a { + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-repeat: no-repeat; + background-position: center; + background-size: 3rem; + + &.alram { + background-image: url(../assets/images/ico_alarm.svg); + } + + &.set { + background-image: url(../assets/images/ico_set.svg); + } + + &.user { + background-image: url(../assets/images/ico_user.svg); + } + } + } + } + } + .setMenu { + display: none; + position: absolute; + top: 2.8rem; + right: -1rem; + min-width: 22rem; + background-color:var(--secondary2) ; + padding: .6rem 0; + z-index: 100; + pointer-events: auto; + + a { + display: block; + padding: .8rem 1.5rem; + font-size: var(--fs-m); + font-weight: var(--fw-bold); + + &:hover { + background-color:var(--primary1); + } + } + } + + .badge { + position: absolute; + top: .6rem; + right: .8rem; + display: block; + width: .5rem; + height: .6rem; + border-radius: 50%; + background-color: var(--alert); + } + } +} \ No newline at end of file diff --git a/src/publish/scss/Layout.scss b/src/publish/scss/Layout.scss new file mode 100644 index 00000000..81b9c753 --- /dev/null +++ b/src/publish/scss/Layout.scss @@ -0,0 +1,557 @@ + +@charset "utf-8"; + +#wrap { + width: 100%; + height: 100%; + + /* header */ + #header { + width: 100%; + height: 4.4rem; + position: relative; + display: flex; + justify-content: space-between; + align-items: center; + background: var(--secondary5); + + .logoArea { + display: flex; + align-items: center; + + .logo { + width: 4.3rem; + height: 4.4rem; + display: flex; + align-items: center; + justify-content: center; + background: url(../assets/images/logo.svg) no-repeat center / contain; + } + + .logoTxt { + color: var(--white); + font-weight: var(--fw-bold); + } + } + + aside { + ul { + display: flex; + + li { + width: 3rem; + height: 3rem; + margin-right: .9rem; + + a { + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-repeat: no-repeat; + background-position: center; + background-size: 3rem; + + &.alram { + background-image: url(../assets/images/ico_alarm.svg); + } + + &.set { + background-image: url(../assets/images/ico_set.svg); + } + + &.user { + background-image: url(../assets/images/ico_user.svg); + } + } + } + } + } + + .badge { + position: absolute; + top: .6rem; + right: .8rem; + display: block; + width: .5rem; + height: .6rem; + border-radius: 50%; + background-color: var(--alert); + } + } + + #sidePanel { + /* gnb */ + #nav { + position: fixed; + top: 4.4rem; + left: 0; + z-index: 100; + width: 4.3rem; + height: calc(100% - 4.4rem); + display: flex; + flex-direction: column; + justify-content: space-between; + background: var(--secondary1); + border-right: 1px solid var(--tertiary2); + + .gnb { + width: 4.2rem; + display: flex; + flex-direction: column; + + li { + width: 100%; + height: 4.4rem; + display: flex; + align-items: center; + justify-content: center; + + a { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-repeat: no-repeat; + background-position: center; + background-size: 3rem; + + /* 공통 상태 */ + &:hover, + &:active, + &.active { + background-color: var(--primary1); + } + + /* gnb icons */ + &.gnb1 { + background-image: url(../assets/images/ico_gnb01.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb01_on.svg); + } + } + + &.gnb2 { + background-image: url(../assets/images/ico_gnb02.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb02_on.svg); + } + } + + &.gnb3 { + background-image: url(../assets/images/ico_gnb03.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb03_on.svg); + } + } + + &.gnb4 { + background-image: url(../assets/images/ico_gnb04.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb04_on.svg); + } + } + + &.gnb5 { + background-image: url(../assets/images/ico_gnb05.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb05_on.svg); + } + } + + &.gnb6 { + background-image: url(../assets/images/ico_gnb06.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb06_on.svg); + } + } + } + } + } + } + + + /* side-pannel */ + .slidePanel { + position: fixed; + top: 4.4rem; + left: 4.3rem; + width: 54rem; + height: calc(100% - 4.4rem); + display: flex; + flex-direction: column; + background-color: var(--secondary2); + z-index: 99; + transform: translateX(0); + transition: transform .3s ease; + + /* 닫힘 상태 */ + &.is-closed { + transform: translateX(-100%); + + .toogle::after { + transform: translate(-50%, -50%) rotate(180deg); + } + } + + .tabBox { + flex-shrink: 0; + width: 100%; + height: 4.8rem; + padding: 0 1.9rem; + margin-top: 1.5rem; + } + + .tabWrap { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + + &.is-active { + display: flex; + } + + .tabTop { + flex-shrink: 0; + width: 100%; + padding: 0 2rem; + border-bottom: 1px solid var(--secondary1); + + .title { + height: 6.4rem; + font-size: var(--fs-ml); + color: var(--white); + padding: 2rem 0; + } + } + + .tabBtm { + flex: 1; + min-height: 0; + overflow-y: auto; + overflow-x: hidden; + padding: 3rem 1.9rem; + } + } + + .toogle { + position: absolute; + overflow: hidden; + z-index: 10; + top: 50%; + left: 100%; + width: 2.4rem; + height: 5rem; + border-radius: 0 1rem 1rem 0; + transform: translateY(-50%); + background-color: var(--secondary2); + border: solid 1px var(--secondary3); + + &::after { + content: ""; + position: absolute; + top: 50%; + left: 50%; + width: 2.4rem; + height: 2.4rem; + transform: translate(-50%, -50%); + background: url(../assets/images/ico_toggle.svg) no-repeat center / 2.4rem; + transition: transform .3s ease; + } + } + } + + } + /* main */ + #main { + width: 100%; + height: calc(100% - 4.4rem); + position: relative; + + /* top-bar */ + .topBar { + display: grid; + grid-template-columns: 1fr auto 1fr; + align-items: center; + padding: 1.5rem 5.4rem; + } + + /* top-location */ + .locationInfo { + grid-column: 2; + width: 71rem; + max-width: 100%; + height: 3.8rem; + background-color: rgba(var(--secondary6-rgb), .9); + + ul { + display: flex; + align-items: center; + width: 100%; + height: 100%; + + li { + display: flex; + align-items: center; + height: 100%; + padding: 0 1rem; + color: var(--white); + font-weight: var(--fw-bold); + font-size: 1.3rem; + + &:first-child, + &:last-child { + padding: 0; + } + + span + span { + padding-right: .5rem; + } + + &.divider { + position: relative; + + &::after { + content: ""; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + width: 1px; + height: 1.8rem; + background-color: rgba(255, 255, 255, .3); + } + } + + .wgs { + display: flex; + align-items: center; + padding-right: .5rem; + + &::before { + content: ""; + display: block; + width: 2rem; + height: 2rem; + margin-right: .5rem; + background: url(../assets/images/ico_globe.svg) no-repeat center / 2rem; + } + } + + .kst { + display: flex; + align-items: center; + justify-content: center; + width: 3.1rem; + height: 1.8rem; + margin-right: .5rem; + border-radius: .3rem; + background-color: var(--tertiary3); + color: var(--white); + font-size: var(--fs-s); + } + } + } + + button { + width: 4rem; + height: 3.8rem; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + box-sizing: border-box; + background-color: var(--secondary3); + background-repeat: no-repeat; + background-position: center; + background-size: 3rem; + + &:hover, + &.active { + background-color: rgba(var(--primary1-rgb), .8); + } + + &.map { + background-image: url(../assets/images/ico_map.svg); + } + + &.ship { + background-image: url(../assets/images/ico_ship.svg); + } + + &.set { + width: 2rem; + height: 2rem; + background-color: transparent; + background-image: url(../assets/images/ico_set_s.svg); + background-size: 2rem; + + &:hover, + &.active { + background-color: transparent; + } + } + } + } + + /* top-search */ + .schBox { + position: relative; + grid-column: 3; + justify-self: end; + width: 20rem; + height: 3.8rem; + + .sch { + width: 100%; + height: 100%; + padding-right: 4.4rem; + border-radius: 2rem; + background-color: rgba(var(--secondary6-rgb), .9); + + &::placeholder { + color: var(--white); + } + } + + .mainSchBtn { + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 4rem; + height: 3.8rem; + font-size: 0; + text-indent: -999999em; + border: none; + cursor: pointer; + background: url(../assets/images/ico_search_main.svg) no-repeat center left / 2.4rem; + } + } + } + + /* tool-bar */ + #tool { + .toolBar { + position: absolute; + top: 5.9rem; + right: .9rem; + width: 3rem; + height: 41rem; + } + + .control { + position: absolute; + bottom: 1.8rem; + right: .9rem; + width: 3rem; + height: 20rem; + } + + .toolItem { + width: 100%; + display: flex; + flex-direction: column; + + &.space { + li { + margin-bottom: .5rem; + } + } + + &.zoom { + li { + height: 3rem; + + &.num { + background-color: var(--white); + color: var(--gray-scale2); + border-left: 1px solid rgba(var(--secondary6-rgb), .8); + border-right: 1px solid rgba(var(--secondary6-rgb), .8); + font-size: var(--fs-m); + } + + button { + padding-bottom: 0; + } + } + } + + li { + display: flex; + align-items: center; + justify-content: center; + width: 3rem; + height: 4.2rem; + background-color: rgba(var(--secondary6-rgb), .8); + + &:hover, + &.active { + background-color: rgba(var(--primary1-rgb), .8); + } + + button { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + padding-bottom: .2rem; + cursor: pointer; + text-align: center; + font-size: var(--fs-xxs); + color: var(--white); + background-repeat: no-repeat; + background-position: top left; + background-size: 3rem; + + &::before { + content: ""; + flex-shrink: 0; + width: 3rem; + height: 3rem; + } + + &.tool01 { background-image: url(../assets/images/ico_tool01.svg); } + &.tool02 { background-image: url(../assets/images/ico_tool02.svg); } + &.tool03 { background-image: url(../assets/images/ico_tool03.svg); } + &.tool04 { background-image: url(../assets/images/ico_tool04.svg); } + &.tool05 { background-image: url(../assets/images/ico_tool05.svg); } + &.tool06 { background-image: url(../assets/images/ico_tool06.svg); } + &.tool07 { background-image: url(../assets/images/ico_tool07.svg); } + &.tool08 { background-image: url(../assets/images/ico_tool08.svg); } + + &.zoomin { background-image: url(../assets/images/ico_plus.svg); } + &.zoomout { background-image: url(../assets/images/ico_minus.svg); } + &.legend { background-image: url(../assets/images/ico_legend.svg); } + &.minimap { background-image: url(../assets/images/ico_minimap.svg); } + } + } + } + } + +} \ No newline at end of file diff --git a/src/publish/scss/MainComponent.scss b/src/publish/scss/MainComponent.scss new file mode 100644 index 00000000..f9a1e878 --- /dev/null +++ b/src/publish/scss/MainComponent.scss @@ -0,0 +1,188 @@ + +@charset "utf-8"; + +#wrap { + //* main */ + #main { + width: 100%; + min-height: calc(100vh - 4.4rem); + position: relative; + overscroll-behavior: none; + overflow: hidden; + + //* top-bar */ + .topBar { + position: absolute; + top: 1.5rem; + left: 0; + right: 0; + height: 4.4rem; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 5.4rem; + box-sizing: border-box; + z-index: 95; + } + + //* top-location */ + .locationInfo { + flex: 0 0 auto; + min-width: 71rem; + height: 3.8rem; + margin: 0 auto; + display: flex; + align-items: center; + background-color: rgba(var(--secondary6-rgb), .9); + overflow: hidden; + + ul { + display: flex; + align-items: center; + width: 100%; + height: 100%; + + li { + display: flex; + align-items: center; + height: 100%; + padding: 0 1rem; + color: var(--white); + font-weight: var(--fw-bold); + font-size: 1.3rem; + + &:first-child, + &:last-child { + padding: 0; + } + + span + span { + padding-right: .5rem; + } + + &.divider { + position: relative; + + &::after { + content: ""; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + width: 1px; + height: 1.8rem; + background-color: rgba(255, 255, 255, .3); + } + } + + .wgs { + display: flex; + align-items: center; + padding-right: .5rem; + + &::before { + content: ""; + display: block; + width: 2rem; + height: 2rem; + margin-right: .5rem; + background: url(../assets/images/ico_globe.svg) no-repeat center / 2rem; + } + } + + .kst { + display: flex; + align-items: center; + justify-content: center; + width: 3.1rem; + height: 1.8rem; + margin-right: .5rem; + border-radius: .3rem; + background-color: var(--tertiary3); + color: var(--white); + font-size: var(--fs-s); + } + } + } + + button { + width: 4rem; + height: 3.8rem; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + box-sizing: border-box; + background-color: var(--secondary3); + background-repeat: no-repeat; + background-position: center; + background-size: 3rem; + + &:hover, + &.active { + background-color: rgba(var(--primary1-rgb), .8); + } + + &.map { + background-image: url(../assets/images/ico_map.svg); + } + + &.ship { + background-image: url(../assets/images/ico_ship.svg); + } + + &.set { + width: 2rem; + height: 2rem; + background-color: transparent; + background-image: url(../assets/images/ico_set_s.svg); + background-size: 2rem; + + &:hover, + &.active { + background-color: transparent; + } + } + } + } + + //* top-search */ + .topSchBox { + flex: 0 0 auto; + width: 20rem; + height: 3.8rem; + display: flex; + justify-content: flex-end; + position: relative; + + .tschInput { + width: 100%; + height: 100%; + padding-right: 4.4rem; + border-radius: 2rem; + background-color: rgba(var(--secondary6-rgb), .9); + border: 0; + + &::placeholder { + color: var(--white); + } + } + + .mainSchBtn { + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 4rem; + height: 3.8rem; + font-size: 0; + text-indent: -999999em; + border: none; + cursor: pointer; + background: url(../assets/images/ico_search_main.svg) no-repeat center left / 2.4rem; + } + } + + } +} \ No newline at end of file diff --git a/src/publish/scss/SideComponent.scss b/src/publish/scss/SideComponent.scss new file mode 100644 index 00000000..7dc48fe2 --- /dev/null +++ b/src/publish/scss/SideComponent.scss @@ -0,0 +1,539 @@ + +@charset "utf-8"; + +#wrap { + + #sidePanel { + /* gnb */ + #nav { + position: fixed; + top: 4.4rem; + left: 0; + z-index: 100; + width: 4.3rem; + height: calc(100% - 4.4rem); + display: flex; + flex-direction: column; + justify-content: space-between; + background: var(--secondary1); + border-right: 1px solid var(--tertiary2); + + .gnb { + width: 4.2rem; + display: flex; + flex-direction: column; + + li { + width: 100%; + height: 4.4rem; + display: flex; + align-items: center; + justify-content: center; + + button { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-repeat: no-repeat; + background-position: center; + background-size: 3rem; + + /* 공통 상태 */ + &:hover, + &:active, + &.active { + background-color: var(--primary1); + } + + /* gnb icons */ + &.gnb1 { + background-image: url(../assets/images/ico_gnb01.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb01_on.svg); + } + } + + &.gnb2 { + background-image: url(../assets/images/ico_gnb02.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb02_on.svg); + } + } + + &.gnb3 { + background-image: url(../assets/images/ico_gnb03.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb03_on.svg); + } + } + + &.gnb4 { + background-image: url(../assets/images/ico_gnb04.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb04_on.svg); + } + } + + &.gnb5 { + background-image: url(../assets/images/ico_gnb05.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb05_on.svg); + } + } + + &.gnb6 { + background-image: url(../assets/images/ico_gnb06.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb06_on.svg); + } + } + + &.gnb7 { + background-image: url(../assets/images/ico_gnb07.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb07_on.svg); + } + } + + &.gnb8 { + background-image: url(../assets/images/ico_gnb08.svg); + + &:hover, + &:active, + &.active { + background-image: url(../assets/images/ico_gnb08_on.svg); + } + } + } + } + } + .side { + width: 4.2rem; + display: flex; + flex-direction: column; + + li { + width: 100%; + height: 4.4rem; + display: flex; + align-items: center; + justify-content: center; + + button { + width: 3rem; + height: 3rem; + display: flex; + align-items: center; + justify-content: center; + background-repeat: no-repeat; + background-position: center; + background-size: 3rem; + background-color: var(--primary3); + + &.filter { + background-image: url('../assets/images/ico_side01.svg'); + } + + &.layer { + background-image: url('../assets/images/ico_side02.svg'); + } + } + } + } + + } + + + /* side-pannel */ + .slidePanel { + position: fixed; + top: 4.4rem; + left: 4.3rem; + width: 54rem; + height: calc(100% - 4.4rem); + min-height: 0; + display: flex; + flex-direction: column; + background-color: var(--secondary2); + border-right: .1rem solid var(--secondary3); + z-index: 99; + transform: translateX(0); + transition: transform .3s ease; + + /* 닫힘 상태 */ + &.is-closed { + transform: translateX(-100%); + + .toogle::after { + transform: translate(-50%, -50%) rotate(180deg); + } + } + + .tabBox { + flex-shrink: 0; + width: 100%; + padding: 1.5rem 2rem 0 2rem; + } + + .tabWrap { + flex: 1; + min-height: 0; + display: none; + flex-direction: column; + + &.is-active { + display: flex; + } + + .tabWrapInner { + display: flex; + flex-direction: column; + flex: 1; + min-height: 100%; + + .tabWrapCnt { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + padding-bottom: 3rem; + + // 필터 스위치그룹 + .switchGroup { + display: flex; + flex-direction: column; + width: 100%; + + .sgHeader { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1.2rem 1rem; + background-color: var(--secondary1); + border-bottom: .1rem solid var(--secondary3); + + .colL { + display: flex; + align-items: center; + gap: 1rem; + font-weight: var(--fw-bold); + + .favship { + width: 2rem; + height: 2rem; + background: url(../assets/images/ico_favship.svg) no-repeat center / contain; + } + } + + .toggleBtn { + display: flex; + align-items: center; + width: 2.4rem; + height: 2.4rem; + background: url(../assets/images/ico_arrow_toggle_down.svg) no-repeat center / contain; + transition: transform 0.3s ease; + + &.is-open { + transform: rotate(180deg); + } + } + } + + .switchBox { + overflow: hidden; + max-height: 0; + transition: max-height 0.3s ease; + + &.is-open { + max-height: 500rem; + } + + .switchList { + display: flex; + flex-direction: column; + flex: 1 1 auto; + width: 100%; + background-color: var(--tertiary1); + padding: 1rem; + + li { + display: flex; + justify-content: space-between; + padding: .1rem 0; + + span { + flex: 1; + min-width: 0; + word-break: break-word; + overflow-wrap: break-word; + white-space: normal; + } + } + } + } + } + } + + .btnBox { + flex: 0 0 auto; + margin-top: auto; + display: flex; + justify-content: flex-end; + padding: 2rem; + } + } + + .tabTop { + flex-shrink: 0; + width: 100%; + padding: 0 2rem; + + .title { + font-size: var(--fs-ml); + color: var(--white); + font-weight: var(--fw-bold); + padding: 1.7rem 0; + + .prevBtn { + width: 2rem; + height: 2rem; + background: url(../assets/images/ico_tit_prev.svg) no-repeat center /contain; + margin-right: .5rem; + } + } + // 기상패널 범례 + .legend { + display: flex; + align-items: flex-start; + flex-direction: column; + gap: .4rem; + margin-bottom: 2.5rem; + + .legendTitle { + font-size: var(--fs-m); + } + + .legendList { + width: 100%; + border-radius: .6rem; + padding: 1.5rem; + background-color: rgba(var(--secondary4-rgb), .2); + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; + + li { + display: flex; + align-items: center; + justify-content: flex-start; + font-size: var(--fs-ml); + + img { + width: 2.6rem; + height: 2.6rem; + margin-right: .5rem; + } + } + } + } + } + + .tabBtm { + flex: 1; + min-height: 0; + overflow-y: auto; + overflow-x: hidden; + border-top: 1px solid var(--secondary1); + padding: 3rem 2rem; + + &.noLine { + overflow-y: visible; + border-top: 0; + padding: 0 2rem; + } + + &.noSc { + overflow-y: visible; + padding-bottom: 0; + } + .tabBtmInner { + display: flex; + flex-direction: column; + height: 100%; + min-height: 0; + + .tabBtmCnt { + flex: 1 1 auto; + min-height: 0 ; + overflow-y: auto; + padding-bottom: 2rem; + } + + .btnBox { + flex: 0 0 auto; + margin-top: auto; + display: flex; + justify-content: flex-end; + gap: 1rem; + padding: 2rem 0; + + &.rowSB { + justify-content: space-between; + } + + button { + flex: initial; + min-width: 12rem; + } + } + } + } + + } + + .toogle { + position: absolute; + overflow: hidden; + z-index: 10; + top: 50%; + left: 100%; + width: 2.4rem; + height: 5rem; + border-radius: 0 1rem 1rem 0; + transform: translateY(-50%); + background-color: var(--secondary2); + border: solid 1px var(--secondary3); + + &::after { + content: ""; + position: absolute; + top: 50%; + left: 50%; + width: 2.4rem; + height: 2.4rem; + transform: translate(-50%, -50%); + background: url(../assets/images/ico_toggle.svg) no-repeat center / 2.4rem; + transition: transform .3s ease; + } + } + // ai모드 + .panelHeader { + display: flex; + align-items: center; + padding: 0 2rem; + + .panelTitle { + padding: 1.7rem 0; + font-size: var(--fs-ml); + font-weight: var(--fw-bold); + } + } + + .panelBody { + display: flex; + flex: 1; + min-height: 0; + padding: 0 2rem; + + .ai { + display: grid; + grid-template-columns: repeat(2, 1fr); + align-items: start; + gap: 1rem; + row-gap: 1rem; + grid-auto-rows: min-content; + width: 100%; + + li { + display: flex; + align-items: center; + justify-content: flex-start; + + a { + position: relative; + display: flex; + flex-direction: column; + gap: .6rem; + width: 100%; + height: auto; + padding: 2rem 1.2rem; + background-color: var(--secondary1); + border: 2px solid transparent; + border-radius: .6rem; + + &.on { + background-color: var(--secondary5); + border-color: var(--primary1); + } + + &:not(.on) > * { + opacity: .5; + } + + .title { + display: flex; + align-items: center; + font-weight: var(--fw-bold); + + img { + width: 2.2rem; + height: 2.2rem; + margin-right: .5rem; + } + } + + .keyword { + font-weight: var(--fw-bold); + } + + .control { + position: absolute; + top: 2rem; + right: 1.5rem; + display: flex; + align-items: center; + + i { + width: .8rem; + height: .8rem; + border-radius: 50%; + background-color: var(--white); + margin-right: .5rem; + } + } + } + } + } + } + + .panelFooter { + border-top: 1px solid var(--secondary1); + padding: 1rem 2rem; + } + + } + + } +} \ No newline at end of file diff --git a/src/publish/scss/ToolComponent.scss b/src/publish/scss/ToolComponent.scss new file mode 100644 index 00000000..626898a9 --- /dev/null +++ b/src/publish/scss/ToolComponent.scss @@ -0,0 +1,153 @@ + +@charset "utf-8"; + +#wrap { + //* tool-bar */ + #tool { + .toolBar { + position: absolute; + top: 5.9rem; + right: .9rem; + width: 3rem; + height: 41rem; + z-index: 95; + } + + .control { + position: absolute; + bottom: 1.8rem; + right: .9rem; + width: 3rem; + height: 20rem; + } + + .toolItem { + width: 100%; + display: flex; + flex-direction: column; + + &.space { + li { + margin-bottom: .5rem; + } + } + + &.zoom { + li { + height: 3rem; + + &.num { + background-color: var(--white); + color: var(--gray-scale1); + border-left: 1px solid rgba(var(--secondary6-rgb), .8); + border-right: 1px solid rgba(var(--secondary6-rgb), .8); + font-size: var(--fs-m); + } + + button { + padding-bottom: 0; + } + } + } + + li { + display: flex; + align-items: center; + justify-content: center; + width: 3rem; + height: 4.2rem; + background-color: rgba(var(--secondary6-rgb), .8); + + button { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + padding-bottom: .2rem; + cursor: pointer; + text-align: center; + font-size: var(--fs-xxs); + color: var(--white); + background-repeat: no-repeat; + background-position: top left; + background-size: 3rem; + + &:hover, + &.active { + background-color: rgba(var(--primary1-rgb), .8); + } + + &::before { + content: ""; + flex-shrink: 0; + width: 3rem; + height: 3rem; + } + + &.tool01 { background-image: url(../assets/images/ico_tool01.svg); } + &.tool02 { background-image: url(../assets/images/ico_tool02.svg); } + &.tool03 { background-image: url(../assets/images/ico_tool03.svg); } + &.tool04 { background-image: url(../assets/images/ico_tool04.svg); } + &.tool05 { background-image: url(../assets/images/ico_tool05.svg); } + &.tool06 { background-image: url(../assets/images/ico_tool06.svg); } + &.tool07 { background-image: url(../assets/images/ico_tool07.svg); } + &.tool08 { background-image: url(../assets/images/ico_tool08.svg); } + + &.zoomin { background-image: url(../assets/images/ico_plus.svg); } + &.zoomout { background-image: url(../assets/images/ico_minus.svg); } + &.legend { background-image: url(../assets/images/ico_legend.svg); } + &.minimap { background-image: url(../assets/images/ico_minimap.svg); } + } + } + } + // 범례 + .legendWrap { + position: fixed; + right: 5rem; + bottom: 5rem; + + .legendList { + display: flex; + flex-direction: column; + width: 14rem; + height: auto; + border-radius: .5rem; + background-color: var(--gray-scale3); + padding: .7rem; + gap: .4rem; + + li { + display: flex; + justify-content: space-between; + align-items: center; + + &.legendItem { + padding: .5rem 0; + border-bottom: 1px solid var(--gray-scale7); + } + + .legendLabel { + display: flex; + align-items: center; + gap: .2rem; + font-size: var(--fs-s); + font-weight: var(--fw-bold); + + img { + width: 1.6rem; + height: 1.6rem; + } + } + + .legendValue { + font-size: var(--fs-s); + font-weight: var(--fw-heavy); + } + } + } + } + + } +} \ No newline at end of file diff --git a/src/publish/scss/WrapComponent.scss b/src/publish/scss/WrapComponent.scss new file mode 100644 index 00000000..fa86d43f --- /dev/null +++ b/src/publish/scss/WrapComponent.scss @@ -0,0 +1,7 @@ + +@charset "utf-8"; + +#wrap { + width: 100%; + min-height: 100vh; +} \ No newline at end of file