BLOCK8 기준 보기와 분석·작업 로그 화면 추가
This commit is contained in:
1 parent
62c7395dc1
commit
1986680183
4 files changed
+251
-15
No files matched your search
+95
-9
@@ -1,14 +1,100 @@
|
||||
export default function App() {
|
||||
import { useState } from 'react'
|
||||
|
||||
const views = {
|
||||
전체: { transform: 'rotate(-8 450 180) skewY(-2deg)' },
|
||||
평면: { transform: 'rotate(0 450 180)' },
|
||||
정면: { transform: 'rotate(-90 450 180)' },
|
||||
측면: { transform: 'rotate(90 450 180)' },
|
||||
}
|
||||
|
||||
function StationModel({ view }) {
|
||||
return (
|
||||
<main className="welcome">
|
||||
<section className="welcome-card" aria-labelledby="welcome-title">
|
||||
<span className="welcome-mark" aria-hidden="true">3D</span>
|
||||
<p className="welcome-kicker">새 프로젝트</p>
|
||||
<h1 id="welcome-title">작업을 시작할 준비가 되었습니다</h1>
|
||||
<p className="welcome-description">
|
||||
이 공간은 비어 있습니다. 도면과 작업 내용을 추가해 새 모델을 만들어 보세요.
|
||||
</p>
|
||||
<svg className="model-svg" viewBox="0 0 900 360" role="img" aria-labelledby="model-title model-desc">
|
||||
<title id="model-title">BLOCK8 확인된 종단 기준선</title>
|
||||
<desc id="model-desc">측점 319.010에서 338.990까지 19.980미터의 기준 구간입니다. 단면 형상은 미확정입니다.</desc>
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto-start-reverse">
|
||||
<path d="M 0 0 L 8 4 L 0 8 z" fill="#718b78" />
|
||||
</marker>
|
||||
</defs>
|
||||
<g className="model-grid">
|
||||
<path d="M90 250 L810 250 M130 280 L850 280 M110 220 L830 220" />
|
||||
<path d="M180 200 L180 290 M360 200 L360 290 M540 200 L540 290 M720 200 L720 290" />
|
||||
</g>
|
||||
<g style={views[view]} className="station-line">
|
||||
<path className="station-shadow" d="M180 185 L720 185" />
|
||||
<path className="station-main" d="M180 185 L720 185" />
|
||||
<path className="station-cap" d="M180 164 L180 207 M720 164 L720 207" />
|
||||
<circle cx="180" cy="185" r="9" />
|
||||
<circle cx="720" cy="185" r="9" />
|
||||
<path className="dimension" d="M190 137 L710 137" markerStart="url(#arrow)" markerEnd="url(#arrow)" />
|
||||
<path className="dimension-tick" d="M180 145 L180 164 M720 145 L720 164" />
|
||||
<text x="450" y="122" textAnchor="middle" className="length-label">19.980 m · 측점 차이</text>
|
||||
<text x="180" y="228" textAnchor="middle" className="endpoint-label">STA. 0K+319.010</text>
|
||||
<text x="720" y="228" textAnchor="middle" className="endpoint-label">STA. 0K+338.990</text>
|
||||
</g>
|
||||
<g className="axis-labels">
|
||||
<path d="M82 303 L150 303" /><path d="M82 303 L82 263" />
|
||||
<text x="157" y="307">종단 기준</text><text x="76" y="255">EL 기준 미연결</text>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [view, setView] = useState('전체')
|
||||
return (
|
||||
<main className="page-shell">
|
||||
<header className="topbar">
|
||||
<a className="brand" href="#top"><span className="brand-mark">B8</span><span>도면 모델 작업실</span></a>
|
||||
<span className="project-chip">광터지하차도 · BLOCK8</span>
|
||||
<nav className="file-links" aria-label="작업 자료">
|
||||
<a href="/analysis/도면분석.md" target="_blank" rel="noreferrer">분석 파일 ↗</a>
|
||||
<a href="/작업기록.txt" target="_blank" rel="noreferrer">작업 로그 ↗</a>
|
||||
<a href="/drawings/광터지하차도_BLOCK8.dxf" download>원본 DXF ↓</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<section className="intro" id="top">
|
||||
<div>
|
||||
<span className="kicker">도면 근거가 확인된 범위부터 표시합니다</span>
|
||||
<h1>BLOCK8 <em>모델 보기</em></h1>
|
||||
<p>현재 도면에서 확인된 종단 구간 기준선입니다. 구조물 단면은 추가 확인이 필요합니다.</p>
|
||||
</div>
|
||||
<span className="status-pill"><i /> 단면 윤곽 확인 필요</span>
|
||||
</section>
|
||||
|
||||
<section className="summary-grid" aria-label="확인된 기준값">
|
||||
<article><span>시점</span><strong>0K+319.010</strong><small>도면 명시값</small></article>
|
||||
<article><span>종점</span><strong>0K+338.990</strong><small>도면 명시값</small></article>
|
||||
<article><span>구간 길이</span><strong>19.980 <i>m</i></strong><small>측점 차이로 계산</small></article>
|
||||
<article className="unknown"><span>단면 폭 · 높이</span><strong>확인 필요</strong><small>구조선과 EL 연결 전</small></article>
|
||||
</section>
|
||||
|
||||
<section className="model-card" aria-labelledby="model-heading">
|
||||
<div className="card-heading">
|
||||
<div><span className="eyebrow">3D 기준 보기 · 형상 검토 중</span><h2 id="model-heading">확인된 종단 구간</h2></div>
|
||||
<div className="view-controls" aria-label="보기 방향">
|
||||
{Object.keys(views).map(name => <button key={name} className={view === name ? 'active' : ''} onClick={() => setView(name)}>{name}</button>)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="model-stage"><StationModel view={view} /><span className="stage-note">선은 측점 범위를 나타냅니다 · 구조물 단면/폭/높이를 표현한 형상이 아닙니다</span></div>
|
||||
<div className="model-caption"><span><i className="legend-line" /> 도면 명시 측점으로 계산한 기준선</span><span>단면 윤곽 · 배치 · EL 연결: 확인 필요</span></div>
|
||||
</section>
|
||||
|
||||
<section className="bottom-grid">
|
||||
<article className="info-card">
|
||||
<span className="eyebrow">진행 상태</span><h2>분석은 완료, 구조 형상은 미확정</h2>
|
||||
<p>도면에서 측점과 구간 길이를 읽었습니다. DXF 단위가 지정되지 않았고 BLOCK8의 전체 구조물 윤곽을 확인하지 못해, 임의의 폭·높이를 넣은 구조물 모델은 표시하지 않습니다.</p>
|
||||
<a className="text-link" href="/analysis/도면분석.md" target="_blank" rel="noreferrer">도면 분석 내용 보기 <span>↗</span></a>
|
||||
</article>
|
||||
<article className="info-card log-card">
|
||||
<span className="eyebrow">작업 기록</span><h2>분석 자료와 변경 이력</h2>
|
||||
<p>초기화 이후 도면 등록과 분석 기록을 날짜·커밋 단위로 정리했습니다.</p>
|
||||
<a className="text-link" href="/작업기록.txt" target="_blank" rel="noreferrer">작업 로그 파일 열기 <span>↗</span></a>
|
||||
</article>
|
||||
</section>
|
||||
<footer>단위 m · 도면 명시값과 계산값을 구분해 표시합니다.</footer>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
+84
-6
@@ -8,9 +8,87 @@
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
body { min-width: 320px; min-height: 100vh; margin: 0; }
|
||||
.welcome { display: grid; min-height: 100vh; place-items: center; padding: 24px; }
|
||||
.welcome-card { width: min(100%, 560px); padding: 48px 32px; text-align: center; background: #fafcf8; border: 1px solid #dbe4d7; border-radius: 16px; }
|
||||
.welcome-mark { display: grid; width: 52px; height: 52px; margin: 0 auto 24px; place-items: center; border-radius: 15px; background: #446b58; color: white; font-size: 17px; font-weight: 700; }
|
||||
.welcome-kicker { margin: 0 0 10px; color: #71877a; font-size: 12px; font-weight: 700; letter-spacing: .08em; }
|
||||
h1 { margin: 0; font-size: clamp(22px, 5vw, 30px); letter-spacing: -.05em; }
|
||||
.welcome-description { margin: 16px 0 0; color: #77857b; font-size: 14px; line-height: 1.8; }
|
||||
a { color: inherit; text-decoration: none; }
|
||||
button { font: inherit; cursor: pointer; }
|
||||
.page-shell { width: min(100% - 64px, 1380px); margin: 0 auto; padding-bottom: 25px; }
|
||||
.topbar { min-height: 72px; display: flex; align-items: center; gap: 20px; border-bottom: 1px solid #d8e0d6; }
|
||||
.brand { display: inline-flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 700; white-space: nowrap; }
|
||||
.brand-mark { display: grid; width: 34px; height: 34px; place-items: center; border-radius: 10px; background: #446b58; color: #fff; font-size: 12px; }
|
||||
.project-chip { color: #819087; font-size: 11px; }
|
||||
.file-links { display: flex; gap: 8px; margin-left: auto; }
|
||||
.file-links a { padding: 9px 11px; border: 1px solid #d7dfd4; border-radius: 7px; background: #fafcf8; color: #536d5b; font-size: 11px; white-space: nowrap; }
|
||||
.file-links a:hover,.text-link:hover { border-color: #89a28d; color: #2d6045; }
|
||||
.intro { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 36px 0 25px; }
|
||||
.kicker,.eyebrow { display: block; color: #788a7d; font-size: 10px; font-weight: 700; letter-spacing: .08em; }
|
||||
h1 { margin: 8px 0; font-size: clamp(27px, 4vw, 34px); letter-spacing: -.06em; }
|
||||
h1 em { margin-left: 7px; color: #778b7d; font-size: .8em; font-style: normal; font-weight: 400; }
|
||||
.intro p,.info-card p { margin: 0; color: #79877c; font-size: 12px; line-height: 1.8; }
|
||||
.status-pill { display: inline-flex; align-items: center; gap: 8px; padding: 10px 14px; border: 1px solid #e5dbc2; border-radius: 30px; background: #faf5e9; color: #967641; font-size: 11px; white-space: nowrap; }
|
||||
.status-pill i { width: 7px; height: 7px; border-radius: 50%; background: #b98f48; }
|
||||
.summary-grid { display: grid; grid-template-columns: repeat(4, 1fr); margin-bottom: 18px; overflow: hidden; border: 1px solid #dce4d9; border-radius: 11px; background: #fafcf8; }
|
||||
.summary-grid article { min-height: 112px; padding: 18px 22px; border-right: 1px solid #e3e9e1; }
|
||||
.summary-grid article:last-child { border: 0; }
|
||||
.summary-grid span,.summary-grid small { display: block; color: #839084; font-size: 10px; }
|
||||
.summary-grid strong { display: block; margin: 10px 0 6px; font-family: Georgia,serif; font-size: clamp(19px, 2.5vw, 26px); font-weight: 400; white-space: nowrap; }
|
||||
.summary-grid strong i { color: #78877c; font-family: sans-serif; font-size: 12px; font-style: normal; }
|
||||
.summary-grid .unknown strong { color: #a38048; font-family: inherit; font-size: 18px; }
|
||||
.model-card,.info-card { overflow: hidden; border: 1px solid #dbe4d7; border-radius: 12px; background: #fafcf8; }
|
||||
.card-heading { display: flex; align-items: center; justify-content: space-between; gap: 15px; padding: 19px 22px 12px; }
|
||||
h2 { margin: 5px 0 0; font-size: 17px; letter-spacing: -.04em; }
|
||||
.view-controls { display: flex; gap: 4px; padding: 3px; border-radius: 7px; background: #edf1ea; }
|
||||
.view-controls button { padding: 7px 11px; border: 0; border-radius: 5px; background: transparent; color: #768579; font-size: 10px; }
|
||||
.view-controls button.active { background: white; color: #426a50; box-shadow: 0 1px 4px #233c2912; }
|
||||
.model-stage { position: relative; display: grid; min-height: 330px; place-items: center; overflow: hidden; border-top: 1px solid #e0e7dd; border-bottom: 1px solid #e0e7dd; background: linear-gradient(180deg,#f6f9f5,#edf2ec); }
|
||||
.model-svg { width: min(100%, 940px); height: auto; min-height: 270px; overflow: visible; }
|
||||
.model-grid path { fill: none; stroke: #dbe4dc; stroke-width: 1; }
|
||||
.station-line { transform-box: view-box; transform-origin: center; transition: transform .35s ease; }
|
||||
.station-shadow { fill: none; stroke: #d2ddd2; stroke-width: 15; stroke-linecap: round; }
|
||||
.station-main { fill: none; stroke: #547d62; stroke-width: 5; stroke-linecap: round; }
|
||||
.station-cap { fill: none; stroke: #819782; stroke-width: 2; }
|
||||
.station-line circle { fill: #fafcf8; stroke: #52785d; stroke-width: 4; }
|
||||
.dimension { fill: none; stroke: #718b78; stroke-width: 1.5; }
|
||||
.dimension-tick { fill: none; stroke: #a5b5a5; stroke-width: 1; }
|
||||
.length-label { fill: #49694f; font-size: 16px; font-weight: 700; }
|
||||
.endpoint-label { fill: #566e5c; font-size: 12px; }
|
||||
.axis-labels path { stroke: #758e79; stroke-width: 2; }
|
||||
.axis-labels text { fill: #809083; font-size: 10px; }
|
||||
.stage-note { position: absolute; right: 15px; bottom: 12px; color: #9a835b; font-size: 9px; text-align: right; }
|
||||
.model-caption { display: flex; justify-content: space-between; gap: 14px; padding: 13px 20px; color: #839084; font-size: 10px; }
|
||||
.model-caption>span:first-child { display: inline-flex; align-items: center; gap: 8px; }
|
||||
.legend-line { width: 19px; height: 3px; border-radius: 2px; background: #547d62; }
|
||||
.bottom-grid { display: grid; grid-template-columns: 1.25fr 1fr; gap: 16px; margin-top: 17px; }
|
||||
.info-card { min-height: 172px; padding: 19px 21px; }
|
||||
.info-card h2 { margin-bottom: 10px; }
|
||||
.info-card p { max-width: 720px; }
|
||||
.text-link { display: inline-flex; align-items: center; gap: 9px; margin-top: 14px; padding: 8px 10px; border: 1px solid #d8e1d6; border-radius: 6px; color: #4b6b52; font-size: 10px; }
|
||||
.text-link span { font-size: 13px; }
|
||||
footer { padding-top: 18px; color: #89958a; font-size: 9px; }
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.page-shell { width: min(100% - 32px, 620px); }
|
||||
.topbar { flex-wrap: wrap; gap: 10px; padding: 13px 0; }
|
||||
.project-chip { margin-left: auto; }
|
||||
.file-links { width: 100%; margin: 0; }
|
||||
.file-links a { flex: 1; text-align: center; }
|
||||
.intro { align-items: flex-start; flex-direction: column; padding: 27px 0 19px; }
|
||||
.summary-grid { grid-template-columns: 1fr 1fr; }
|
||||
.summary-grid article { min-height: 98px; padding: 15px; border-bottom: 1px solid #e3e9e1; }
|
||||
.summary-grid article:nth-child(2) { border-right: 0; }
|
||||
.summary-grid article:nth-child(n+3) { border-bottom: 0; }
|
||||
.card-heading { align-items: flex-start; flex-direction: column; padding: 17px 15px 12px; }
|
||||
.model-stage { min-height: 260px; }
|
||||
.model-svg { min-height: 220px; }
|
||||
.endpoint-label { font-size: 11px; }
|
||||
.stage-note { max-width: 260px; line-height: 1.5; }
|
||||
.model-caption { flex-direction: column; padding: 12px 15px; }
|
||||
.bottom-grid { grid-template-columns: 1fr; gap: 11px; }
|
||||
.info-card { min-height: 0; padding: 17px; }
|
||||
}
|
||||
|
||||
@media (max-width: 400px) {
|
||||
.file-links { gap: 5px; }
|
||||
.file-links a { padding: 8px 5px; font-size: 10px; }
|
||||
.view-controls button { padding: 7px 9px; }
|
||||
.model-stage { min-height: 220px; }
|
||||
.length-label { font-size: 13px; }
|
||||
}
|
||||
Reference in new issue
Block a user