feat: complete legacy parity and modernize operator UI
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -92,12 +92,12 @@
|
||||
<span class="workspace-nav-label">테마</span>
|
||||
</button>
|
||||
<button class="workspace-nav-item workspace-market-item" type="button"
|
||||
draggable="true" data-tab-id="overseasStocks" aria-label="해외종목" title="해외종목"
|
||||
draggable="true" data-tab-id="overseasStocks" aria-label="해외시장" title="해외시장"
|
||||
aria-current="false" aria-controls="catalog-workspace">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" focusable="false">
|
||||
<circle cx="8" cy="9" r="4"></circle><path d="M3 19c.7-3 2.3-5 5-5s4.3 2 5 5M15 7h6M18 4v6M15 14h6M18 11v6"></path>
|
||||
</svg>
|
||||
<span class="workspace-nav-label">해외종목</span>
|
||||
<span class="workspace-nav-label">해외시장</span>
|
||||
</button>
|
||||
<button class="workspace-nav-item workspace-market-item" type="button"
|
||||
draggable="true" data-tab-id="expert" aria-label="전문가" title="전문가"
|
||||
@@ -108,12 +108,12 @@
|
||||
<span class="workspace-nav-label">전문가</span>
|
||||
</button>
|
||||
<button class="workspace-nav-item workspace-market-item" type="button"
|
||||
draggable="true" data-tab-id="tradingHalt" aria-label="정지" title="정지"
|
||||
draggable="true" data-tab-id="tradingHalt" aria-label="거래정지" title="거래정지"
|
||||
aria-current="false" aria-controls="catalog-workspace">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" focusable="false">
|
||||
<circle cx="12" cy="12" r="8"></circle><path d="M9.5 8v8M14.5 8v8"></path>
|
||||
</svg>
|
||||
<span class="workspace-nav-label">정지</span>
|
||||
<span class="workspace-nav-label">거래정지</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -313,9 +313,9 @@
|
||||
<div class="settings-folder-copy">
|
||||
<div class="settings-folder-title-line">
|
||||
<h4 id="operator-background-folder-title">운영 배경 폴더</h4>
|
||||
<span class="settings-folder-kind">VRV</span>
|
||||
<span class="settings-folder-kind">VRV/JPG/PNG</span>
|
||||
</div>
|
||||
<p>F2에서 선택할 수 있는 검증된 .vrv 배경의 기준·허용 위치입니다.</p>
|
||||
<p>F2에서 선택할 수 있는 검증된 VRV/JPG/PNG 배경의 기준·허용 위치입니다.</p>
|
||||
<div class="settings-folder-value">
|
||||
<strong id="operator-background-folder-name">앱 기본 배경 폴더</strong>
|
||||
<span id="operator-background-folder-status" class="settings-status-badge neutral">확인 중</span>
|
||||
@@ -393,6 +393,8 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div><small>항상 표시</small><h2>송출 스케줄</h2></div>
|
||||
<div id="playlist-heading-count" class="playlist-heading-count"
|
||||
role="status" aria-live="polite" aria-atomic="true">총 0개 · 송출 0개</div>
|
||||
</header>
|
||||
<div class="playlist-toolbar">
|
||||
<label><input id="playlist-enable-all" type="checkbox" checked disabled> 전체</label>
|
||||
@@ -494,6 +496,9 @@
|
||||
<button id="manual-financial-close" type="button" aria-label="닫기">×</button>
|
||||
</header>
|
||||
<div id="manual-financial-workspace" class="manual-financial-workspace"></div>
|
||||
<footer class="manual-dialog-footer">
|
||||
<button id="manual-financial-exit" type="button">나가기</button>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -505,6 +510,9 @@
|
||||
<button id="manual-list-close" type="button" aria-label="닫기">×</button>
|
||||
</header>
|
||||
<div id="manual-list-workspace" class="manual-list-workspace"></div>
|
||||
<footer class="manual-dialog-footer">
|
||||
<button id="manual-list-cancel" type="button">취소</button>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -545,6 +553,14 @@
|
||||
aria-labelledby="operator-catalog-editor-title">
|
||||
<div class="operator-catalog-panel-header">
|
||||
<h3 id="operator-catalog-editor-title">추가·편집</h3>
|
||||
<label id="operator-catalog-editor-market-field"
|
||||
class="operator-catalog-editor-market" hidden>
|
||||
<span>시장</span>
|
||||
<select id="operator-catalog-editor-market" aria-label="새 ThemeA 시장" disabled>
|
||||
<option value="krx">KRX</option>
|
||||
<option value="nxt">NXT</option>
|
||||
</select>
|
||||
</label>
|
||||
<span id="operator-catalog-code" class="operator-catalog-code"></span>
|
||||
</div>
|
||||
<div class="operator-catalog-name-field">
|
||||
|
||||
@@ -23,7 +23,7 @@ button:disabled { color: #555; opacity: 1; }
|
||||
|
||||
.operator-shell {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(900px, 2fr) minmax(600px, 1fr);
|
||||
grid-template-columns: minmax(900px, 1.75fr) minmax(600px, 1fr);
|
||||
width: 100%;
|
||||
min-width: 1500px;
|
||||
height: 100vh;
|
||||
@@ -224,18 +224,27 @@ button:disabled { color: #555; opacity: 1; }
|
||||
|
||||
.manual-financial-backdrop { position: fixed; inset: 0; z-index: 18; background: rgba(0, 0, 0, .3); }
|
||||
.manual-financial-backdrop[hidden] { display: none; }
|
||||
.manual-financial-dialog { position: absolute; left: 50%; top: 50%; width: min(1120px, 92vw); height: min(800px, 90vh); transform: translate(-50%, -50%); display: grid; grid-template-rows: 46px minmax(0, 1fr); border: 1px solid #666; background: #f3f3f3; box-shadow: 0 10px 36px rgba(0, 0, 0, .4); }
|
||||
.manual-financial-dialog { position: absolute; left: 50%; top: 50%; width: min(1120px, 92vw); height: min(800px, 90vh); transform: translate(-50%, -50%); display: grid; grid-template-rows: 46px minmax(0, 1fr) auto; border: 1px solid #666; background: #f3f3f3; box-shadow: 0 10px 36px rgba(0, 0, 0, .4); }
|
||||
.manual-financial-dialog > header { display: flex; align-items: center; justify-content: space-between; padding: 0 12px; border-bottom: 1px solid #999; background: #ececec; }
|
||||
.manual-financial-dialog h2 { margin: 0; font-size: 18px; }
|
||||
.manual-financial-dialog > header button { width: 34px; height: 29px; font-size: 20px; }
|
||||
.manual-financial-workspace { min-height: 0; display: grid; grid-template-rows: auto minmax(0, 1fr); gap: 7px; padding: 8px; }
|
||||
.manual-financial-toolbar { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 5px; }
|
||||
.manual-financial-toolbar input, .manual-financial-toolbar button { min-width: 0; height: 30px; }
|
||||
.manual-financial-body { min-height: 0; display: grid; grid-template-columns: 270px minmax(0, 1fr); gap: 8px; }
|
||||
.manual-financial-body { min-height: 0; display: grid; grid-template-columns: minmax(430px, .95fr) minmax(0, 1.05fr); gap: 8px; }
|
||||
.manual-financial-list { min-height: 0; overflow: auto; border: 1px solid #999; background: #fff; }
|
||||
.manual-financial-list button { display: block; width: 100%; min-height: 25px; padding: 3px 7px; border: 0; border-bottom: 1px solid #ddd; background: #fff; text-align: left; }
|
||||
.manual-financial-list button.selected { background: #dcdcdc; }
|
||||
.manual-financial-list button.manual-financial-row-unreadable { border-left: 3px solid #c4475d; background: #fff6f8; color: #92263a; }
|
||||
.manual-financial-list button.manual-financial-row-unreadable::after { content: "읽기 불가"; position: absolute; top: 3px; right: 4px; padding: 1px 3px; background: inherit; font-size: 11px; font-weight: 700; }
|
||||
.manual-financial-list button.manual-financial-row-legacy { border-left: 3px solid #b7791f; background: #fffaf0; color: #744210; }
|
||||
.manual-financial-list button.manual-financial-row-legacy::after { content: "기존 원문"; position: absolute; top: 3px; right: 4px; padding: 1px 3px; background: inherit; font-size: 11px; font-weight: 700; }
|
||||
.manual-financial-list button.manual-financial-list-header { position: sticky; top: 0; z-index: 1; background: #ececec; border-bottom: 1px solid #888; font-weight: 700; }
|
||||
.manual-financial-list button.manual-financial-list-row { position: relative; display: grid; align-items: stretch; width: 100%; padding: 0; }
|
||||
.manual-financial-preview-columns-6 button.manual-financial-list-row { min-width: 560px; grid-template-columns: minmax(112px, 1.35fr) repeat(5, minmax(82px, 1fr)); }
|
||||
.manual-financial-preview-columns-7 button.manual-financial-list-row { min-width: 600px; grid-template-columns: minmax(112px, 1.35fr) repeat(6, minmax(76px, 1fr)); }
|
||||
.manual-financial-preview-cell { min-width: 0; overflow: hidden; padding: 4px 6px; border-right: 1px solid #e2e2e2; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.manual-financial-preview-cell:last-child { border-right: 0; }
|
||||
.manual-financial-editor { min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 7px; padding: 8px; border: 1px solid #999; background: #fff; }
|
||||
.manual-financial-stock-line { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 5px; }
|
||||
.manual-financial-stock-line input, .manual-financial-stock-line button { height: 30px; }
|
||||
@@ -243,6 +252,9 @@ button:disabled { color: #555; opacity: 1; }
|
||||
.manual-financial-stock-results button { padding: 3px 7px; }
|
||||
.manual-financial-stock-results button.selected { border-color: #145ab4; background: #dceaff; }
|
||||
.manual-financial-verification { min-height: 22px; color: #145ab4; }
|
||||
.manual-financial-reference { align-self: center; width: min(100%, 360px); margin: 0; padding: 6px; border: 1px solid #ccc; background: #f7f7f7; }
|
||||
.manual-financial-reference img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; background: #111; }
|
||||
.manual-financial-reference figcaption { margin-top: 5px; color: #555; font-size: 12px; text-align: center; }
|
||||
.manual-financial-fields { display: grid; gap: 7px; }
|
||||
.manual-financial-field { display: grid; grid-template-columns: 100px minmax(0, 1fr); align-items: center; gap: 6px; }
|
||||
.manual-financial-field input { min-width: 0; height: 28px; }
|
||||
@@ -257,7 +269,7 @@ button:disabled { color: #555; opacity: 1; }
|
||||
.manual-financial-warning { padding: 7px; border: 1px solid #b00020; background: #fff1f3; color: #9b001b; font-weight: 700; }
|
||||
.manual-list-backdrop { position: fixed; inset: 0; z-index: 19; background: rgba(0, 0, 0, .32); }
|
||||
.manual-list-backdrop[hidden] { display: none; }
|
||||
.manual-list-dialog { position: absolute; left: 50%; top: 50%; width: min(980px, 94vw); height: min(760px, 91vh); transform: translate(-50%, -50%); display: grid; grid-template-rows: 46px minmax(0, 1fr); border: 1px solid #666; background: #f3f3f3; box-shadow: 0 10px 36px rgba(0, 0, 0, .4); }
|
||||
.manual-list-dialog { position: absolute; left: 50%; top: 50%; width: min(980px, 94vw); height: min(760px, 91vh); transform: translate(-50%, -50%); display: grid; grid-template-rows: 46px minmax(0, 1fr) auto; border: 1px solid #666; background: #f3f3f3; box-shadow: 0 10px 36px rgba(0, 0, 0, .4); }
|
||||
.manual-list-dialog > header { display: flex; align-items: center; justify-content: space-between; padding: 0 12px; border-bottom: 1px solid #999; }
|
||||
.manual-list-dialog h2 { margin: 0; font-size: 18px; }
|
||||
.manual-list-dialog > header button { width: 34px; height: 29px; font-size: 20px; }
|
||||
@@ -274,9 +286,12 @@ button:disabled { color: #555; opacity: 1; }
|
||||
.manual-list-search-results button.selected { background: #dcdcdc; font-weight: 600; }
|
||||
.manual-list-status { padding: 7px; border: 1px solid #bbb; background: #fff; }
|
||||
.manual-list-status.error { border-color: #b00020; background: #fff1f3; color: #9b001b; font-weight: 700; }
|
||||
.manual-list-status.warning { border-color: #c68a00; background: #fff8e5; color: #765000; font-weight: 700; }
|
||||
.manual-list-actions-row { margin-top: auto; justify-content: flex-end; }
|
||||
.manual-list-actions-row button { min-width: 100px; height: 34px; }
|
||||
.manual-list-actions-row .primary { border-color: #4774a8; background: linear-gradient(#f8fbff, #d9e8f9); font-weight: 700; }
|
||||
.manual-dialog-footer { display: flex; justify-content: flex-end; padding: 9px 10px; border-top: 1px solid #aaa; background: #ececec; }
|
||||
.manual-dialog-footer button { min-width: 100px; height: 34px; }
|
||||
|
||||
.cut-list { flex: 1; min-height: 0; border: 1px solid #999; background: #fff; overflow-y: auto; user-select: none; }
|
||||
.cut-row { display: grid; grid-template-columns: 62px 1fr; min-height: 23px; border-bottom: 1px solid #ddd; background: #fff; font-size: 15px; }
|
||||
@@ -286,7 +301,8 @@ button:disabled { color: #555; opacity: 1; }
|
||||
.cut-row:focus { outline: 1px dotted #222; outline-offset: -2px; }
|
||||
.cut-row.separator { background: #fff; }
|
||||
.cut-row[data-cut-drag-enabled="true"] { cursor: grab; }
|
||||
.cut-row.dragging { opacity: .58; cursor: grabbing; }
|
||||
.cut-row.dragging { opacity: .58; cursor: not-allowed; }
|
||||
.cut-row.dragging.drag-allowed { cursor: move; }
|
||||
.playlist-grid.cut-drag-over { box-shadow: inset 0 0 0 3px #176b2d; }
|
||||
.cut-drag-feedback { position: fixed; z-index: 10000; display: flex; align-items: center; gap: 7px; max-width: 260px; padding: 7px 10px; border: 1px solid #8a8a8a; border-radius: 4px; background: rgba(255, 255, 255, .97); box-shadow: 0 3px 10px rgba(0, 0, 0, .28); color: #555; font-size: 13px; font-weight: 700; line-height: 1; pointer-events: none; user-select: none; white-space: nowrap; }
|
||||
.cut-drag-feedback[hidden] { display: none; }
|
||||
@@ -371,8 +387,9 @@ summary[data-tree-root][aria-disabled="true"] { color: #777; }
|
||||
.overseas-results button { display: block; width: 100%; min-height: 22px; padding: 2px 6px; border: 0; border-bottom: 1px solid #ddd; background: #fff; text-align: left; }
|
||||
.comparison-workspace { display: grid; grid-template-rows: minmax(110px, 22%) minmax(70px, 16%) minmax(150px, 1fr) auto; height: 100%; gap: 6px; }
|
||||
.comparison-searches { display: grid; grid-template-columns: 1fr 1fr; min-height: 0; gap: 6px; }
|
||||
.comparison-search-panel { display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0; }
|
||||
.comparison-search-panel { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; min-height: 0; }
|
||||
.comparison-search-line { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px; }
|
||||
.comparison-search-warning { color: #9a4b00; font-size: 11px; font-weight: 600; padding: 3px 1px 0; }
|
||||
.comparison-results, .comparison-saved { min-height: 0; overflow: auto; border: 1px solid #aaa; background: #fff; }
|
||||
.comparison-results button, .comparison-saved button { display: block; width: 100%; padding: 2px 5px; border: 0; background: #fff; text-align: left; }
|
||||
.comparison-results button:hover, .comparison-results button.selected, .comparison-saved button.selected { background: #dcdcdc; }
|
||||
@@ -380,10 +397,11 @@ summary[data-tree-root][aria-disabled="true"] { color: #777; }
|
||||
.comparison-fixed-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); overflow: auto; border: 1px solid #aaa; }
|
||||
.comparison-fixed-list button { padding: 2px 4px; text-align: left; }
|
||||
.comparison-fixed-list button.selected { background: #dcdcdc; font-weight: 600; }
|
||||
.comparison-pair-panel { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; min-height: 0; gap: 4px; }
|
||||
.comparison-pair-panel { display: grid; grid-template-rows: auto minmax(0, 1fr) auto auto; min-height: 0; gap: 4px; }
|
||||
.comparison-draft { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto auto; gap: 4px; }
|
||||
.comparison-draft input { min-width: 0; }
|
||||
.comparison-saved-tools { display: flex; gap: 4px; justify-content: flex-end; }
|
||||
.comparison-import-status { min-height: 18px; color: var(--text-secondary, #4b5563); font-size: 11px; }
|
||||
.comparison-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; }
|
||||
.theme-workspace { display: grid; grid-template-rows: auto minmax(72px, .8fr) auto auto minmax(72px, 1fr); height: 100%; gap: 7px; }
|
||||
.theme-search-line { display: grid; grid-template-columns: minmax(120px, 2.1fr) repeat(4, minmax(64px, 1fr)); gap: 5px; }
|
||||
@@ -391,6 +409,7 @@ summary[data-tree-root][aria-disabled="true"] { color: #777; }
|
||||
.theme-results-panel, .theme-preview-panel { display: grid; min-height: 0; overflow: hidden; border: 1px solid #aaa; background: #fff; }
|
||||
.theme-results-panel { grid-template-rows: auto minmax(0, 1fr); }
|
||||
.theme-column-title { padding: 4px 6px; border-bottom: 1px solid #aaa; background: #eee; text-align: center; }
|
||||
.theme-search-truncation { margin-left: 8px; color: #9a4b00; font-size: 11px; font-weight: 600; }
|
||||
.theme-results { min-height: 0; overflow: auto; }
|
||||
.theme-results button { display: block; width: 100%; padding: 3px 6px; border: 0; background: #fff; text-align: left; }
|
||||
.theme-results button.selected { background: #dcdcdc; }
|
||||
@@ -427,6 +446,9 @@ summary[data-tree-root][aria-disabled="true"] { color: #777; }
|
||||
.operator-catalog-list-panel { grid-template-rows: auto minmax(0, 1fr); }
|
||||
.operator-catalog-panel-header { display: flex; align-items: center; min-height: 40px; gap: 6px; padding: 6px 8px; border-bottom: 1px solid #bbb; background: #f3f3f3; }
|
||||
.operator-catalog-panel-header h3 { flex: 1; margin: 0; font-size: 15px; }
|
||||
.operator-catalog-editor-market { display: inline-flex; align-items: center; gap: 5px; color: #555; font-size: 12px; }
|
||||
.operator-catalog-editor-market[hidden] { display: none; }
|
||||
.operator-catalog-editor-market select { min-width: 72px; }
|
||||
.operator-catalog-code { color: #555; font-family: Consolas, monospace; }
|
||||
.operator-catalog-results, .operator-catalog-stock-results, .operator-catalog-draft-rows { min-height: 0; overflow: auto; }
|
||||
.operator-catalog-results button { display: grid; grid-template-columns: 84px minmax(0, 1fr); width: 100%; gap: 2px 8px; padding: 6px 8px; border: 0; border-bottom: 1px solid #ddd; background: #fff; text-align: left; }
|
||||
@@ -520,7 +542,8 @@ summary[data-tree-root][aria-disabled="true"] { color: #777; }
|
||||
.playlist-data-row.on-air.selected { background: #dcdcdc; }
|
||||
.playlist-data-row:focus { outline: 1px dotted #333; outline-offset: -2px; }
|
||||
.playlist-data-row.dragging { opacity: .55; }
|
||||
.playlist-data-row.dragging .playlist-row-header { cursor: grabbing; }
|
||||
.playlist-data-row.dragging .playlist-row-header { cursor: not-allowed; }
|
||||
.playlist-data-row.dragging.drag-allowed .playlist-row-header { cursor: move; }
|
||||
.playlist-data-row.drag-before { box-shadow: inset 0 3px #176b2d; }
|
||||
.playlist-data-row.drag-after { box-shadow: inset 0 -3px #176b2d; }
|
||||
|
||||
@@ -1218,6 +1241,23 @@ summary[data-tree-root]:focus-visible,
|
||||
box-shadow: inset 4px 0 #d92d4b, inset 0 3px var(--ui-warning),
|
||||
inset 0 0 0 2px rgba(37, 99, 235, .7);
|
||||
}
|
||||
.playlist-data-row.scene-unresolved .playlist-row-header {
|
||||
color: #b54708;
|
||||
}
|
||||
.playlist-data-row.scene-unresolved .playlist-row-header::after {
|
||||
content: "!";
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
margin-left: 2px;
|
||||
border-radius: 50%;
|
||||
background: #f79009;
|
||||
color: #fff;
|
||||
font-size: 9px;
|
||||
line-height: 1;
|
||||
}
|
||||
.playlist-data-row.playout-current:not(.on-air):not([data-active="true"]) {
|
||||
box-shadow: inset 0 3px var(--ui-warning);
|
||||
}
|
||||
@@ -1351,6 +1391,7 @@ summary[data-tree-root]:focus-visible,
|
||||
color: #174ea6;
|
||||
}
|
||||
.named-playlist-dialog > footer,
|
||||
.manual-dialog-footer,
|
||||
.operator-catalog-toolbar {
|
||||
border-color: var(--ui-border);
|
||||
background: var(--ui-surface-subtle);
|
||||
@@ -1781,6 +1822,321 @@ summary[data-tree-root]:focus-visible {
|
||||
}
|
||||
.settings-protected-copy h3 { margin-bottom: 5px; }
|
||||
|
||||
/* Contemporary density refinement: keep operator geometry, clarify visual hierarchy. */
|
||||
:root {
|
||||
--ui-canvas: #f3f6fa;
|
||||
--ui-surface-subtle: #fafbfd;
|
||||
--ui-surface-muted: #f2f5f8;
|
||||
--ui-surface-hover: #eef4ff;
|
||||
--ui-border: #dfe5ed;
|
||||
--ui-control-border: #c4cedb;
|
||||
--ui-radius-sm: 8px;
|
||||
--ui-radius: 11px;
|
||||
--ui-radius-lg: 16px;
|
||||
--ui-shadow-sm: 0 1px 2px rgba(15, 23, 42, .04);
|
||||
--ui-shadow-card: 0 1px 2px rgba(15, 23, 42, .055),
|
||||
0 8px 24px rgba(15, 23, 42, .035);
|
||||
}
|
||||
|
||||
button {
|
||||
border-color: var(--ui-control-border);
|
||||
box-shadow: none;
|
||||
}
|
||||
button:not(:disabled):hover {
|
||||
border-color: #96a3b5;
|
||||
box-shadow: 0 1px 2px rgba(15, 23, 42, .07);
|
||||
}
|
||||
button:not(:disabled):active { box-shadow: inset 0 1px 2px rgba(15, 23, 42, .08); }
|
||||
|
||||
.workspace-nav-header {
|
||||
background: rgba(255, 255, 255, .72);
|
||||
background-image: none;
|
||||
}
|
||||
.workspace-nav-items,
|
||||
.workspace-navigation .market-tabs { gap: 2px; }
|
||||
.workspace-nav-item,
|
||||
.workspace-navigation .market-tabs button { border-radius: 9px; }
|
||||
.workspace-nav-toggle svg,
|
||||
.workspace-nav-item svg,
|
||||
.workspace-navigation .market-tabs button svg { color: #5f6c80; }
|
||||
.workspace-nav-item.workspace-current svg,
|
||||
.workspace-navigation .market-tabs button.workspace-current svg { color: var(--ui-accent); }
|
||||
.workspace-nav-section-label {
|
||||
color: var(--ui-text-muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.workspace-header,
|
||||
.playlist-heading {
|
||||
background: rgba(255, 255, 255, .97);
|
||||
background-image: none;
|
||||
box-shadow: 0 1px 0 rgba(15, 23, 42, .055);
|
||||
backdrop-filter: saturate(140%) blur(12px);
|
||||
}
|
||||
.workspace-header::before {
|
||||
right: auto;
|
||||
left: 20px;
|
||||
width: 72px;
|
||||
height: 3px;
|
||||
border-radius: 999px 999px 0 0;
|
||||
background: linear-gradient(90deg, #f26b38 0 28%, var(--ui-accent) 28% 100%);
|
||||
opacity: .88;
|
||||
}
|
||||
.playlist-heading::before {
|
||||
right: auto;
|
||||
left: 14px;
|
||||
width: 58px;
|
||||
height: 3px;
|
||||
border-radius: 999px 999px 0 0;
|
||||
background: var(--ui-accent);
|
||||
opacity: .8;
|
||||
}
|
||||
.brand .brand-symbol { box-shadow: 0 5px 13px rgba(218, 78, 29, .18); }
|
||||
.workspace-heading h1,
|
||||
.playlist-heading h2 { letter-spacing: -.02em; }
|
||||
|
||||
.search-line {
|
||||
width: min(100%, 660px);
|
||||
min-height: 48px;
|
||||
margin-bottom: 8px;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid var(--ui-border);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, .82);
|
||||
box-shadow: var(--ui-shadow-sm);
|
||||
}
|
||||
.search-line button {
|
||||
box-shadow: 0 5px 13px rgba(37, 99, 235, .18);
|
||||
}
|
||||
.stock-result,
|
||||
.category-tree button,
|
||||
.industry-list button,
|
||||
.overseas-fixed-list button,
|
||||
.overseas-results button,
|
||||
.comparison-results button,
|
||||
.comparison-saved button,
|
||||
.comparison-fixed-list button,
|
||||
.theme-results button,
|
||||
.expert-results button,
|
||||
.halt-results button,
|
||||
.named-playlist-definitions button,
|
||||
.manual-financial-list button,
|
||||
.operator-catalog-results button,
|
||||
.operator-catalog-stock-results button { font-weight: 500; }
|
||||
.stock-result.selected {
|
||||
background: var(--ui-accent-soft);
|
||||
color: #174ea6;
|
||||
box-shadow: inset 3px 0 var(--ui-accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
.industry-list button.selected,
|
||||
.overseas-fixed-list button.selected,
|
||||
.overseas-results button.selected,
|
||||
.comparison-results button.selected,
|
||||
.comparison-saved button.selected,
|
||||
.comparison-fixed-list button.selected,
|
||||
.theme-results button.selected,
|
||||
.expert-results button.selected,
|
||||
.halt-results button.selected,
|
||||
.named-playlist-definitions button.selected,
|
||||
.manual-financial-list button.selected,
|
||||
.operator-catalog-results button.selected,
|
||||
.operator-catalog-stock-results button.selected { font-weight: 650; }
|
||||
|
||||
.manual-actions button,
|
||||
.manual-list-actions button {
|
||||
border-color: var(--ui-control-border);
|
||||
background: var(--ui-surface);
|
||||
color: #344054;
|
||||
}
|
||||
|
||||
.stock-results,
|
||||
.cut-list,
|
||||
.category-tree,
|
||||
.playlist-grid,
|
||||
.industry-list,
|
||||
.overseas-fixed-list,
|
||||
.overseas-results,
|
||||
.comparison-results,
|
||||
.comparison-saved,
|
||||
.comparison-fixed-list,
|
||||
.theme-results-panel,
|
||||
.theme-preview-panel,
|
||||
.expert-results,
|
||||
.expert-preview,
|
||||
.halt-results {
|
||||
border-radius: 8px;
|
||||
box-shadow: none;
|
||||
}
|
||||
.cut-row:nth-child(even):not(.separator):not(.selected) { background: #fbfcfe; }
|
||||
.playlist-row,
|
||||
.cut-row .cut-number,
|
||||
.playout-status { font-variant-numeric: tabular-nums; }
|
||||
|
||||
.playlist-heading-count {
|
||||
display: inline-flex;
|
||||
min-height: 28px;
|
||||
margin-left: auto;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
padding: 4px 9px;
|
||||
border: 1px solid #cddbf3;
|
||||
border-radius: 999px;
|
||||
background: var(--ui-accent-soft);
|
||||
color: #315a96;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.playlist-heading-count::before {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
flex: 0 0 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--ui-accent);
|
||||
content: "";
|
||||
}
|
||||
.playlist-toolbar {
|
||||
margin: 8px 0;
|
||||
padding: 6px;
|
||||
border: 1px solid var(--ui-border);
|
||||
border-radius: 11px;
|
||||
background: rgba(255, 255, 255, .82);
|
||||
box-shadow: var(--ui-shadow-sm);
|
||||
}
|
||||
.playlist-toolbar label {
|
||||
min-height: 27px;
|
||||
padding: 2px 7px;
|
||||
border-color: transparent;
|
||||
border-radius: 8px;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
.playlist-toolbar label:has(input:checked) {
|
||||
border-color: #c7d6f1;
|
||||
background: var(--ui-accent-soft);
|
||||
color: #315a96;
|
||||
}
|
||||
.playlist-toolbar button { height: 27px; padding-inline: 8px; border-radius: 8px; }
|
||||
#playlist-move-up,
|
||||
#playlist-move-down {
|
||||
width: 28px;
|
||||
min-width: 28px;
|
||||
padding: 0;
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
#playlist-move-up:not(:disabled):hover,
|
||||
#playlist-move-down:not(:disabled):hover {
|
||||
border-color: var(--ui-control-border);
|
||||
background: var(--ui-surface-muted);
|
||||
}
|
||||
#db-save-button { margin-left: 4px; }
|
||||
#db-save-button:not(:disabled),
|
||||
#db-load-button:not(:disabled) {
|
||||
border-color: #bdcce5;
|
||||
background: #f5f8ff;
|
||||
color: #315a96;
|
||||
}
|
||||
.playlist-toolbar label:has(#playout-background-none) { margin-left: 4px; }
|
||||
.background-name { background: #f8fafc; }
|
||||
|
||||
.playlist-grid { background: #f7f9fc; }
|
||||
.playlist-header {
|
||||
border-bottom-color: #cbd5e1;
|
||||
background: #f8fafc;
|
||||
}
|
||||
.playlist-data-row > div { border-right-color: #eef2f6; }
|
||||
.playlist-data-row:nth-child(even):not(.on-air):not([aria-selected="true"]):not([data-active="true"]):not(.playout-current) {
|
||||
background: #fbfcfe;
|
||||
}
|
||||
.playlist-data-row:not(.on-air):not([aria-selected="true"]):not([data-active="true"]):hover {
|
||||
background: #f1f5fb;
|
||||
}
|
||||
.playlist-rows { min-height: calc(100% - 29px); background: var(--ui-surface-subtle); }
|
||||
.playlist-rows:empty {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
.playlist-rows:empty::after {
|
||||
max-width: 260px;
|
||||
padding: 16px;
|
||||
color: #8a96a8;
|
||||
content: "왼쪽 목록에서 컷을 더블클릭하거나 드래그해 추가하세요";
|
||||
font-size: 12px;
|
||||
line-height: 1.55;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.playout-actions button { border-radius: 12px; }
|
||||
.playout-actions .take-in:not(:disabled) {
|
||||
border-color: #147a46;
|
||||
background: #147a46;
|
||||
box-shadow: 0 6px 16px rgba(20, 122, 70, .18);
|
||||
color: #fff;
|
||||
}
|
||||
.playout-actions .take-in:not(:disabled):hover {
|
||||
border-color: #106b3d;
|
||||
background: #106b3d;
|
||||
}
|
||||
.playout-actions .next:not(:disabled) {
|
||||
border-color: var(--ui-accent);
|
||||
background: var(--ui-accent);
|
||||
box-shadow: 0 6px 16px rgba(37, 99, 235, .18);
|
||||
color: #fff;
|
||||
}
|
||||
.playout-actions .next:not(:disabled):hover {
|
||||
border-color: var(--ui-accent-hover);
|
||||
background: var(--ui-accent-hover);
|
||||
}
|
||||
.playout-actions .take-out:not(:disabled) {
|
||||
border-color: #d35b70;
|
||||
background: var(--ui-surface);
|
||||
color: #ad2941;
|
||||
}
|
||||
.playout-actions .take-out:not(:disabled):hover {
|
||||
border-color: var(--ui-danger);
|
||||
background: var(--ui-danger-soft);
|
||||
}
|
||||
.playout-status {
|
||||
justify-content: flex-start;
|
||||
padding: 0 10px;
|
||||
background: #f8fafc;
|
||||
color: #475467;
|
||||
}
|
||||
.operator-status { color: var(--ui-text-muted); font-weight: 600; }
|
||||
|
||||
.named-playlist-backdrop,
|
||||
.named-playlist-confirmation-backdrop,
|
||||
.manual-financial-backdrop,
|
||||
.manual-list-backdrop,
|
||||
.operator-catalog-backdrop,
|
||||
.dialog-backdrop {
|
||||
background: rgba(15, 23, 42, .36);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
.named-playlist-dialog,
|
||||
.named-playlist-confirmation-dialog,
|
||||
.manual-financial-dialog,
|
||||
.manual-list-dialog,
|
||||
.operator-catalog-dialog,
|
||||
.legacy-dialog { background: var(--ui-surface); }
|
||||
.named-playlist-body,
|
||||
.manual-financial-workspace,
|
||||
.manual-list-workspace,
|
||||
.operator-catalog-body { background: var(--ui-surface-subtle); }
|
||||
.named-playlist-dialog > header button,
|
||||
.manual-financial-dialog > header button,
|
||||
.manual-list-dialog > header button,
|
||||
.operator-catalog-dialog > header button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
.legacy-dialog { width: min(400px, calc(100vw - 40px)); padding: 28px; }
|
||||
#legacy-dialog-message { line-height: 1.6; }
|
||||
|
||||
@media (max-width: 1720px) {
|
||||
.settings-folder-row { grid-template-columns: 38px minmax(0, 1fr); }
|
||||
.settings-folder-actions { grid-column: 2; }
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
function syncMarket(tabId) {
|
||||
function syncMarket(tabId, options) {
|
||||
const button = marketButton(tabId);
|
||||
if (!button) return false;
|
||||
activeMarketTabId = tabId;
|
||||
@@ -110,20 +110,42 @@
|
||||
refreshCurrentMenu();
|
||||
title.textContent = marketLabel(button);
|
||||
}
|
||||
if (pendingKeyboardMarketTabId && !button.disabled) {
|
||||
const pendingButton = marketButton(pendingKeyboardMarketTabId);
|
||||
const focusWasLost = !document.activeElement ||
|
||||
document.activeElement === document.body ||
|
||||
document.activeElement === document.documentElement;
|
||||
if (activeWorkspace === "catalog" && pendingButton &&
|
||||
!pendingButton.disabled && focusWasLost) {
|
||||
pendingButton.focus();
|
||||
}
|
||||
const authoritativeNativeRender = options &&
|
||||
options.authoritativeNativeRender === true;
|
||||
if (authoritativeNativeRender && pendingKeyboardMarketTabId &&
|
||||
pendingKeyboardMarketTabId !== tabId) {
|
||||
// The native operation completed on a different tab. Do not carry a
|
||||
// failed or superseded keyboard request into a later render.
|
||||
pendingKeyboardMarketTabId = null;
|
||||
}
|
||||
if (authoritativeNativeRender && pendingKeyboardMarketTabId === tabId &&
|
||||
!button.disabled) {
|
||||
const pendingTabId = pendingKeyboardMarketTabId;
|
||||
// Native loading temporarily disables the selected menu button, which
|
||||
// can move focus to <body>. Only the final, non-busy native render may
|
||||
// consume this request; the optimistic capture-phase click must not.
|
||||
window.requestAnimationFrame(function () {
|
||||
if (pendingKeyboardMarketTabId !== pendingTabId) return;
|
||||
pendingKeyboardMarketTabId = null;
|
||||
const pendingButton = marketButton(pendingTabId);
|
||||
const active = document.activeElement;
|
||||
const focusWasLost = !active ||
|
||||
active === document.body ||
|
||||
active === document.documentElement;
|
||||
if (activeWorkspace === "catalog" && pendingButton &&
|
||||
!pendingButton.disabled && focusWasLost) {
|
||||
pendingButton.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function hasPendingKeyboardMarketFocus(tabId) {
|
||||
return pendingKeyboardMarketTabId !== null &&
|
||||
(tabId === undefined || tabId === pendingKeyboardMarketTabId);
|
||||
}
|
||||
|
||||
function select(name) {
|
||||
if (views[name]) return setWorkspace(name);
|
||||
if (!syncMarket(name)) return false;
|
||||
@@ -154,8 +176,12 @@
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const keyboardMarketTabId = menuButton.dataset.tabId || null;
|
||||
pendingKeyboardMarketTabId = keyboardMarketTabId;
|
||||
menuButton.click();
|
||||
if (keyboardMarketTabId) pendingKeyboardMarketTabId = keyboardMarketTabId;
|
||||
return;
|
||||
}
|
||||
if (event.key === "Tab") {
|
||||
pendingKeyboardMarketTabId = null;
|
||||
return;
|
||||
}
|
||||
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
||||
@@ -164,6 +190,12 @@
|
||||
focusAdjacentItem(event.key === "ArrowUp" ? -1 : 1);
|
||||
});
|
||||
|
||||
document.addEventListener("pointerdown", function () {
|
||||
// A real pointer action transfers focus ownership to the user. A delayed
|
||||
// native response must never pull it back to the keyboard-selected menu.
|
||||
pendingKeyboardMarketTabId = null;
|
||||
}, true);
|
||||
|
||||
// Reveal the selected catalog screen before app.js dispatches its native
|
||||
// select-tab intent. The native state response remains authoritative and
|
||||
// is reconciled through syncMarket after every render.
|
||||
@@ -180,6 +212,7 @@
|
||||
window.LegacyWorkspaceNavigation = Object.freeze({
|
||||
select: select,
|
||||
syncMarket: syncMarket,
|
||||
hasPendingKeyboardMarketFocus: hasPendingKeyboardMarketFocus,
|
||||
setExpanded: setNavigationExpanded,
|
||||
active: function () { return activeWorkspace; },
|
||||
activeMarket: function () { return activeMarketTabId; },
|
||||
|
||||
Reference in New Issue
Block a user