Files
GhiVideo_v4/client/src/stationbar/components/PlaybackControls/PlaybackControls.module.scss
T
b23042andClaude Fable 5 d38b842e8d GhiVideo 소스 복제 — v4 작업 시작 기준
기존 GhiVideo 저장소 HEAD의 트래킹 소스 362개 파일을 복제.
(node_modules·storage·빌드 산출물·대용량 미디어는 .gitignore 규칙대로 제외)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 14:32:51 +09:00

332 lines
8.1 KiB
SCSS
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
$transport-gradient: linear-gradient(
180deg,
rgb(96, 79, 50) 0%,
rgb(85, 75, 49) 7%,
rgb(64, 51, 39) 11%,
rgb(40, 34, 22) 100%
);
$tool-gradient: linear-gradient(
180deg,
rgb(96, 79, 50) 0%,
rgb(59, 52, 34) 7%,
rgb(54, 43, 31) 11%,
rgb(66, 55, 35) 100%
);
$group-border: linear-gradient(
180deg,
rgba(255, 182, 135, 0.5) 0%,
rgba(255, 255, 255, 0) 100%,
);
$default-border: linear-gradient(
180deg,
rgba(255, 255, 255, 0.25) 25%,
rgba(153, 122, 101, 0.63) 63%,
rgba(98, 62, 39, 0.81) 81%,
rgba(80, 67, 60, 1) 100%
);
$hover-border: linear-gradient(
180deg,
#ffa812 8%,
#ffdfa7 38%,
#ffa812 72%,
#a96e09 95%
);
// ── 컨트롤 패널 치수 (이 값들만 바꾸면 관련 위치/크기가 자동 계산됨) ──
$panel-h: 96.67px; // transportGroup 높이
$panel-inset: 2px; // 그룹 가장자리 공통 인셋
// 재생·정지·측점입력 그룹
$transport-group-w: 161.33px;
$transport-btn-w: 78px;
$transport-btn-h: 55px;
$transport-btn-left: 3px; // 첫(재생) 버튼 좌측 인셋
$transport-btn-top: 4px;
$transport-btn-gap: 1px; // 재생 ↔ 정지 간격
// 화면캡처·측점선 그룹
$tool-group-w: 76px;
$tool-group-h: 96px;
$tool-btn-h: 47px;
$tool-btn-top: 0.5px; // 화면캡처(첫 버튼) top — 47×2가 96 안에 들어가도록 축소
$tool-btn-gap: 1px; // 화면캡처 ↔ 측점선 간격 (47px 버튼이 바 안에 들어가도록)
/* 컨트롤 묶음 — bottomBar flex 자식 (좌측 정렬, 세로 중앙) */
.controlsRow {
position: relative;
display: inline-flex;
gap: 4px;
padding-left: 1.33px;
align-items: center;
z-index: 4;
}
%control-button {
position: absolute;
z-index: 4;
box-sizing: border-box;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border: 1.5px solid transparent;
border-radius: 4px;
appearance: none;
cursor: pointer;
overflow: hidden;
background: $transport-gradient padding-box, $default-border border-box;
box-shadow: 0 0 0 2px rgb(0, 0, 0);
transition: box-shadow 150ms ease-out;
&:hover {
background: $transport-gradient padding-box, $hover-border border-box;
box-shadow:
0 0 0 2px #000,
0 0 8px rgba(255, 168, 18, 0.35);
}
}
/* 플레이·정지·측점 입력 패널 */
.transportGroup {
position: relative;
width: $transport-group-w;
height: $panel-h;
}
.leftPanel {
position: absolute;
left: -1px;
top: 0;
width: calc(100% + 4px);
height: 100%;
/* 그라데이션 테두리 두께 = 이 border 폭 (숫자를 키우면 더 굵어짐) */
border: 2px solid transparent;
box-sizing: border-box;
border-radius: 4px;
background:
linear-gradient(rgb(38, 29, 13), transparent) padding-box,
$group-border border-box;
z-index: 3;
}
.transportBtn {
@extend %control-button;
left: $transport-btn-left;
top: $transport-btn-top;
width: $transport-btn-w;
height: $transport-btn-h;
}
.stopBtn {
@extend %control-button;
// 재생 버튼 우측 + 간격 → 폭이 바뀌면 자동으로 따라옴
left: $transport-btn-left + $transport-btn-w + $transport-btn-gap + 1px;
top: $transport-btn-top;
width: $transport-btn-w;
height: $transport-btn-h;
}
/* 버튼 아이콘: 실제 SVG 파일(그라데이션·그림자·테두리 포함)을 배경으로 사용.
호버 시 버튼의 :hover 로 _on 버전으로 교체한다. 박스 크기는 SVG viewBox의 2/3
(= 기존 렌더 크기 유지). 새 아이콘은 SVG만 교체하면 되어 유지보수가 쉽다. */
%btn-icon {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
pointer-events: none;
}
.playIcon {
@extend %btn-icon;
width: 40px; // 60 × 2/3
height: 40px;
background-image: url('/assets/icons/ico_play.png');
}
.transportBtn:hover .playIcon {
background-image: url('/assets/icons/ico_play_on.png');
}
.pauseIcon {
@extend %btn-icon;
width: 33.33px; // 50 × 2/3
height: 33.33px;
background-image: url('/assets/icons/icon_pause.png');
}
.transportBtn:hover .pauseIcon {
background-image: url('/assets/icons/icon_pause_on.png');
}
.stopIcon {
@extend %btn-icon;
width: 40px; // 60 × 2/3
height: 40px;
background-image: url('/assets/icons/icon_stop.png');
}
.stopBtn:hover .stopIcon {
background-image: url('/assets/icons/icon_stop_on.png');
}
.mileageInput {
position: absolute;
left: $transport-btn-left;
top: 62px;
z-index: 4;
width: $transport-group-w - $transport-btn-left - $panel-inset;
height: 32.67px;
border: none;
border-radius: 4px;
background: rgba(0, 0, 0, 0.65);
box-shadow:
0 0 0 2px rgb(0, 0, 0),
0 0.5px 0 0 rgba(255, 255, 255, 0.1);
box-sizing: border-box;
padding: 0 8px;
font-family: 'Noto Sans KR', var(--font-ui);
font-size: 16px;
font-weight: 400;
letter-spacing: 0.04em;
color: #fff;
&::placeholder {
color: rgba(255, 255, 255, 0.5);
}
&:focus {
outline: none;
}
}
/* '측점 없음' 안내 — 입력창 위에 겹쳐 표시(패널 자식이 absolute 라 일반 흐름은 가려짐). */
.notFound {
position: absolute;
left: $transport-btn-left;
top: 62px;
height: 32.67px;
width: $transport-group-w - $transport-btn-left - $panel-inset;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
z-index: 6; // mileageInput(z:4) 위
border-radius: 4px;
background: rgba(20, 0, 0, 0.88);
box-shadow: 0 0 0 2px #000;
color: #ff6b6b;
font-family: 'Noto Sans KR', var(--font-ui);
font-size: 14px;
font-weight: 700;
letter-spacing: 0.02em;
white-space: nowrap;
pointer-events: none;
}
/* 화면캡처·측점선 보기 패널 */
.toolGroup {
position: relative;
width: $tool-group-w;
height: $tool-group-h;
margin-left: 1px; // transportGroup 패널 확장분만큼 1px 우측 이동
border-radius: 4px;
background: #1a1309;
}
.toolBtn {
@extend %control-button;
left: $panel-inset;
width: $tool-group-w - 2 * $panel-inset; // 좌우 인셋 제외 → 그룹 폭 바뀌면 자동
height: $tool-btn-h; // 바 영역을 벗어나지 않도록 축소 + 두 버튼 사이 간격 확보
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1px;
background: $tool-gradient padding-box, $default-border border-box;
&:hover {
background: $tool-gradient padding-box, $hover-border border-box;
box-shadow:
0 0 0 2px #000,
0 0 8px rgba(255, 168, 18, 0.35);
}
}
.captureBtn {
top: $tool-btn-top + $tool-btn-top;
}
/* 화면캡처 아래 = 첫 버튼 top + 높이 + 간격 → 높이/간격 바꾸면 자동으로 따라옴 */
.lineBtn {
top: $tool-btn-top + $tool-btn-h + $tool-btn-gap + $tool-btn-top + 1px;
}
.cameraIcon {
@extend %btn-icon;
width: 24px; // 확대
height: 20px;
background-image: url('/assets/icons/icon-camera-body.png');
}
.captureBtn:hover .cameraIcon {
background-image: url('/assets/icons/icon-camera-body_on.png');
}
.lineIcon {
@extend %btn-icon;
width: 19.2px; // 확대
height: 20px;
background-image: url('/assets/icons/icon-sturn.png');
}
.lineBtn:hover .lineIcon {
background-image: url('/assets/icons/icon-sturn_on.png');
}
.toolLabel {
font-family: 'Noto Sans KR', var(--font-ui);
font-weight: 700;
font-size: 13.33px; // 살짝 축소 (기존 14.67)
line-height: 1.2;
letter-spacing: -0.04em;
white-space: nowrap;
color: rgb(204, 199, 189);
text-shadow: 0 0.5px 1px rgb(0, 0, 0);
}
.toolBtn:hover .toolLabel {
color: #ffa812;
}
/* 측점선 보기 토글 ON 상태(클릭): 호버와 동일한 아이콘·라벨 색에,
눌린 어두운 그라데이션 배경 + 주황 그라데이션 테두리. 별도 동작 없음.
(채움 레이어는 padding-box, 테두리 그라데이션은 border-box) */
.lineBtn.active {
background:
linear-gradient(0deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%) padding-box,
linear-gradient(
180deg,
#211601 5%,
#211601 10%,
#352509 15%,
#352509 85%,
#231700 90%,
#000 95%
) padding-box,
$hover-border border-box;
box-shadow: 0 0 0 2px #000;
}
.lineBtn.active .lineIcon {
background-image: url('/assets/icons/icon-sturn_on.png');
}
.lineBtn.active .toolLabel {
color: #ffa812;
}