This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
================================================================================
|
||||
|
||||
【已完成】
|
||||
- V10.244 重整 `/observability/ppt_audit_history` 首屏資訊階層:改成簡報操作摘要、最新可預覽簡報、下一步動作與可橫向捲動報表類型 rail;產線覆蓋矩陣改為下方驗收明細,避免一進頁只看到大量「產線狀態」。
|
||||
- V10.242 修正 `/metabase`、`/grist` 外部工具入口:全域導覽固定回 momo-pro 內部橋接頁,避免資料協作錯連其他專案站;入口頁補路由狀態、設定診斷與可用替代分析入口,降低空白頁誤判。
|
||||
- V10.221 補 `/observability/ppt_audit_history` AiderHeal 背景任務可見性:正在修復中的簡報會顯示於產線頁,並提供 JSON 狀態端點讓派工後即時刷新,避免重新整理後不知道是否已在修。
|
||||
- V10.218 補 `/observability/ppt_audit_history` AiderHeal 去重鎖:同一份簡報已在背景修復時,再次點擊會回「已在執行中」,避免重複開 SSH / 模型 / git 修復流程。
|
||||
|
||||
@@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
|
||||
# ==========================================
|
||||
# 系統版本與路徑
|
||||
# ==========================================
|
||||
SYSTEM_VERSION = "V10.242"
|
||||
SYSTEM_VERSION = "V10.244"
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = PUBLIC_URL # 用於模板顯示
|
||||
|
||||
|
||||
@@ -2683,6 +2683,113 @@ def _build_ppt_pipeline_view(files, auto_generation, audit_stats, generation_run
|
||||
}
|
||||
|
||||
|
||||
def _build_ppt_operator_summary(files, auto_generation, pipeline_view, vision_status, audit_stats, generation_runs):
|
||||
"""Build first-screen operator copy that prioritizes deck work over raw pipeline states."""
|
||||
files = files or []
|
||||
auto_generation = auto_generation or {}
|
||||
pipeline_view = pipeline_view or {}
|
||||
vision_status = vision_status or {}
|
||||
audit_stats = audit_stats or {}
|
||||
generation_runs = generation_runs or []
|
||||
|
||||
latest_preview = next(
|
||||
(
|
||||
item for item in files
|
||||
if item.get('file_exists') and item.get('is_valid_ppt') and item.get('name')
|
||||
),
|
||||
None,
|
||||
)
|
||||
issue_count = int(audit_stats.get('total_issues') or 0) if audit_stats else 0
|
||||
missing_count = int(auto_generation.get('missing_count') or 0)
|
||||
valid_preview_count = int(pipeline_view.get('valid_preview_count') or 0)
|
||||
cached_preview_count = int(pipeline_view.get('cached_preview_count') or 0)
|
||||
audit_total = int(pipeline_view.get('audit_total') or 0)
|
||||
run_error_count = int(pipeline_view.get('run_error_count') or 0)
|
||||
broken_file_count = int(pipeline_view.get('broken_file_count') or 0)
|
||||
blockers = vision_status.get('blockers') or []
|
||||
|
||||
if run_error_count or broken_file_count:
|
||||
status = 'error'
|
||||
headline = '先處理異常,再放行簡報'
|
||||
message = f'目前有 {run_error_count} 筆產出失敗、{broken_file_count} 份檔案不可預覽,建議先看 Action Queue。'
|
||||
primary_action = '查看待處理'
|
||||
primary_anchor = '#ppt-action-queue'
|
||||
elif missing_count:
|
||||
status = 'partial'
|
||||
headline = '定期簡報尚未全數補齊'
|
||||
message = f'本期還有 {missing_count} 類定義簡報缺漏,可手動補齊或等待排程寫入 DB。'
|
||||
primary_action = '補齊缺漏'
|
||||
primary_anchor = '#ppt-production-center'
|
||||
elif not vision_status.get('ready'):
|
||||
status = 'partial'
|
||||
headline = '簡報可管理,視覺 QA 待啟用'
|
||||
message = 'PPT 產出與預覽入口仍可用;視覺模型、LibreOffice 或模型檔需補齊後才會自動審核。'
|
||||
primary_action = '查看就緒檢查'
|
||||
primary_anchor = '#ppt-runtime-diagnostic'
|
||||
elif issue_count:
|
||||
status = 'partial'
|
||||
headline = '有視覺問題待回放'
|
||||
message = f'本期視覺 QA 發現 {issue_count} 個問題,請從問題追蹤或審核歷史回放檢查。'
|
||||
primary_action = '查看問題'
|
||||
primary_anchor = '#ppt-issue-board'
|
||||
else:
|
||||
status = 'ready' if valid_preview_count else 'planned'
|
||||
headline = '簡報工作台待命'
|
||||
message = '最新簡報、PDF 預覽、DB 寫入與視覺 QA 都集中在同一頁追蹤。'
|
||||
primary_action = '查看簡報'
|
||||
primary_anchor = '#ppt-deck-workbench'
|
||||
|
||||
latest_run = generation_runs[0] if generation_runs else {}
|
||||
latest_deck_label = latest_preview.get('name') if latest_preview else '尚無可預覽 PPTX'
|
||||
latest_deck_meta = (
|
||||
f"{latest_preview.get('mtime') or '時間未知'} · "
|
||||
f"{latest_preview.get('size_kb') if latest_preview.get('size_kb') is not None else '—'} KB · "
|
||||
f"{'PDF 已快取' if latest_preview and latest_preview.get('preview_cache_ready') else '首次開啟轉檔'}"
|
||||
if latest_preview else
|
||||
'請先補齊本期簡報或切換月份 / 報表類型'
|
||||
)
|
||||
|
||||
return {
|
||||
'status': status,
|
||||
'headline': headline,
|
||||
'message': message,
|
||||
'primary_action': primary_action,
|
||||
'primary_anchor': primary_anchor,
|
||||
'latest_deck': latest_preview or {},
|
||||
'latest_deck_label': latest_deck_label,
|
||||
'latest_deck_meta': latest_deck_meta,
|
||||
'latest_run_label': latest_run.get('report_label') or latest_run.get('report_type') or '尚無 DB run',
|
||||
'latest_run_meta': latest_run.get('started_at') or '等待下一次排程寫入',
|
||||
'blocker_text': ';'.join(blockers[:2]) if blockers else '',
|
||||
'signals': [
|
||||
{
|
||||
'label': '可預覽簡報',
|
||||
'value': valid_preview_count,
|
||||
'meta': f'{cached_preview_count} 份 PDF 快取',
|
||||
'status': 'ready' if valid_preview_count else 'planned',
|
||||
},
|
||||
{
|
||||
'label': '待補齊定義',
|
||||
'value': missing_count,
|
||||
'meta': f"{auto_generation.get('ready_count', 0)}/{auto_generation.get('total', 0)} 已覆蓋",
|
||||
'status': 'ready' if missing_count == 0 and auto_generation.get('total') else 'partial',
|
||||
},
|
||||
{
|
||||
'label': '視覺 QA',
|
||||
'value': audit_total if audit_total else '待跑',
|
||||
'meta': '已就緒' if vision_status.get('ready') else 'runtime 待確認',
|
||||
'status': 'ready' if vision_status.get('ready') and not issue_count else 'partial',
|
||||
},
|
||||
{
|
||||
'label': '視覺問題',
|
||||
'value': issue_count,
|
||||
'meta': '需回放' if issue_count else '目前無待處理',
|
||||
'status': 'partial' if issue_count else 'ready',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def _enrich_ppt_coverage_items(auto_generation_items, files, generation_runs, audit_records):
|
||||
"""Join coverage rows with file, DB run, preview and QA state for the UI matrix."""
|
||||
files = files or []
|
||||
@@ -3312,6 +3419,14 @@ def ppt_audit_history():
|
||||
vision_status=vision_status,
|
||||
audit_records=audit_records,
|
||||
)
|
||||
operator_summary = _build_ppt_operator_summary(
|
||||
files=files,
|
||||
auto_generation=auto_generation,
|
||||
pipeline_view=pipeline_view,
|
||||
vision_status=vision_status,
|
||||
audit_stats=audit_30d_stats,
|
||||
generation_runs=generation_runs,
|
||||
)
|
||||
vision_audit_filenames = [
|
||||
item.get('name')
|
||||
for item in files
|
||||
@@ -3348,6 +3463,7 @@ def ppt_audit_history():
|
||||
auto_generation_missing_report_types=auto_generation.get('missing_report_types', []),
|
||||
generation_runs=generation_runs,
|
||||
pipeline_view=pipeline_view,
|
||||
operator_summary=operator_summary,
|
||||
vision_audit_filenames=vision_audit_filenames,
|
||||
issue_items=issue_items,
|
||||
issue_digest=issue_digest,
|
||||
|
||||
@@ -597,7 +597,7 @@ def get_defined_report_coverage(
|
||||
exact_count = exact_counts[job.report_type]
|
||||
if exact_count > 0:
|
||||
status = "ready"
|
||||
status_label = "目標已產生"
|
||||
status_label = "已產出"
|
||||
status_hint = "檔案參數與本期定義相符。"
|
||||
elif count > 0:
|
||||
status = "partial"
|
||||
|
||||
@@ -11,45 +11,55 @@
|
||||
|
||||
<div class="container-fluid mt-3">
|
||||
<section class="ppt-hero">
|
||||
<div class="ppt-kicker"><i class="fas fa-search me-1"></i> PPT 視覺 QA 產線 · minicpm-v / AiderHeal / RAG 修法</div>
|
||||
<h1 class="ppt-title">PPT 視覺 QA 產線</h1>
|
||||
<p class="ppt-subtitle">這頁追蹤每份自動簡報是否通過視覺審核:檔案產出、minicpm-v 審核、Telegram 推送、RAG 修法建議與 AiderHeal 自動修產生器。</p>
|
||||
<div class="ppt-command">
|
||||
<div class="ppt-signal">
|
||||
<div class="ppt-label">視覺模型</div>
|
||||
<span class="ppt-value {% if vision_enabled %}status-good{% else %}status-warn{% endif %}">{{ '啟用' if vision_enabled else '停用' }}</span>
|
||||
<small class="text-muted">minicpm-v + LibreOffice</small>
|
||||
<div class="ppt-hero-grid">
|
||||
<div class="ppt-hero-copy">
|
||||
<div class="ppt-kicker"><i class="fas fa-search me-1"></i> PPT 視覺 QA 產線 · {{ report_month }} · {{ selected_report_type.label }}</div>
|
||||
<h1 class="ppt-title">{{ operator_summary.headline }}</h1>
|
||||
<p class="ppt-subtitle">{{ operator_summary.message }}</p>
|
||||
{% if operator_summary.blocker_text %}
|
||||
<p class="ppt-hero-note"><i class="fas fa-circle-info me-1" aria-hidden="true"></i>{{ operator_summary.blocker_text }}</p>
|
||||
{% endif %}
|
||||
<div class="ppt-hero-actions">
|
||||
<a class="btn btn-primary btn-sm" href="{{ operator_summary.primary_anchor }}">{{ operator_summary.primary_action }}</a>
|
||||
<a class="btn btn-outline-primary btn-sm" href="#ppt-production-center">定期產出矩陣</a>
|
||||
{% if operator_summary.latest_deck.name %}
|
||||
<a class="btn btn-outline-secondary btn-sm"
|
||||
href="{{ url_for('admin_observability.ppt_audit_file', filename=operator_summary.latest_deck.name) }}"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
data-ppt-open-preview
|
||||
data-ppt-filename="{{ operator_summary.latest_deck.name }}"
|
||||
data-ppt-preview-title="最新簡報 · {{ operator_summary.latest_deck.name }}"
|
||||
data-ppt-preview-pdf="{{ url_for('admin_observability.ppt_audit_file', filename=operator_summary.latest_deck.name, action='pdf') }}"
|
||||
data-ppt-preview-page="{{ url_for('admin_observability.ppt_audit_file', filename=operator_summary.latest_deck.name) }}"
|
||||
data-ppt-download-url="{{ url_for('admin_observability.ppt_audit_file', filename=operator_summary.latest_deck.name, action='download') }}">
|
||||
<i class="fas fa-eye me-1"></i>預覽最新
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ppt-signal">
|
||||
<div class="ppt-label">{{ report_month }} {{ selected_report_type.label }}</div>
|
||||
<span class="ppt-value">{{ files|length }}</span>
|
||||
<small class="text-muted">檔案數</small>
|
||||
</div>
|
||||
<div class="ppt-signal">
|
||||
<div class="ppt-label">審核紀錄</div>
|
||||
<span class="ppt-value {% if audit_30d_stats and audit_30d_stats.pass_rate >= 80 %}status-good{% elif audit_30d_stats and audit_30d_stats.pass_rate >= 60 %}status-warn{% elif audit_30d_stats %}status-bad{% else %}status-blue{% endif %}">
|
||||
{{ audit_30d_stats.total if audit_30d_stats else '—' }}
|
||||
</span>
|
||||
<small class="text-muted">{{ selected_report_type.label }}</small>
|
||||
</div>
|
||||
<div class="ppt-signal">
|
||||
<div class="ppt-label">問題數</div>
|
||||
<span class="ppt-value {% if audit_30d_stats and audit_30d_stats.total_issues > 0 %}status-warn{% elif audit_30d_stats %}status-good{% else %}status-blue{% endif %}">
|
||||
{{ audit_30d_stats.total_issues if audit_30d_stats else '—' }}
|
||||
</span>
|
||||
<small class="text-muted">視覺問題數</small>
|
||||
</div>
|
||||
<div class="ppt-signal">
|
||||
<div class="ppt-label">定義覆蓋</div>
|
||||
<span class="ppt-value {% if auto_generation.missing_count == 0 and auto_generation.total > 0 %}status-good{% elif auto_generation.missing_count > 0 %}status-warn{% else %}status-blue{% endif %}">
|
||||
{{ auto_generation.ready_count }}/{{ auto_generation.total }}
|
||||
</span>
|
||||
<small class="text-muted">自動簡報產線</small>
|
||||
<aside class="ppt-hero-deck is-{{ operator_summary.status }}" aria-label="最新簡報狀態">
|
||||
<div class="ppt-label">Latest Deck</div>
|
||||
<strong>{{ operator_summary.latest_deck_label }}</strong>
|
||||
<small>{{ operator_summary.latest_deck_meta }}</small>
|
||||
<div class="ppt-hero-deck-run">
|
||||
<span>{{ operator_summary.latest_run_label }}</span>
|
||||
<small>{{ operator_summary.latest_run_meta }}</small>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
<div class="ppt-command ppt-command--compact">
|
||||
{% for signal in operator_summary.signals %}
|
||||
<div class="ppt-signal is-{{ signal.status }}">
|
||||
<div class="ppt-label">{{ signal.label }}</div>
|
||||
<span class="ppt-value">{{ signal.value }}</span>
|
||||
<small class="text-muted">{{ signal.meta }}</small>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% if not vision_status.ready %}
|
||||
<section class="ppt-diagnostic-strip">
|
||||
<section class="ppt-diagnostic-strip" id="ppt-runtime-diagnostic">
|
||||
<div>
|
||||
<div class="ppt-label">視覺 QA 尚未就緒</div>
|
||||
<strong>目前不是模型能力問題,而是執行環境尚未完整開啟。</strong>
|
||||
@@ -145,8 +155,7 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% if files %}
|
||||
<section class="ppt-deck-workbench" aria-label="最近可預覽簡報">
|
||||
<section class="ppt-deck-workbench" id="ppt-deck-workbench" aria-label="最近可預覽簡報">
|
||||
<div class="ppt-workbench-head">
|
||||
<div>
|
||||
<div class="ppt-label">Preview Workbench</div>
|
||||
@@ -165,6 +174,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if files %}
|
||||
<div class="ppt-deck-rail">
|
||||
{% for f in files[:4] %}
|
||||
<article class="ppt-deck-card {% if not f.file_exists or not f.is_valid_ppt %}is-disabled{% endif %}">
|
||||
@@ -210,8 +220,12 @@
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="ppt-empty ppt-deck-empty">
|
||||
目前沒有符合 {{ report_month }} / {{ selected_report_type.label }} 的簡報檔案;可先切換報表類型,或在下方補齊定義簡報。
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endif %}
|
||||
<section class="ppt-health-board" aria-label="PPT 產線健康總覽">
|
||||
<div class="ppt-health-main is-{{ pipeline_view.status }}">
|
||||
<div class="ppt-label">Pipeline Health</div>
|
||||
@@ -238,7 +252,7 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
<section class="ppt-action-queue" data-ppt-action-queue aria-label="PPT 工作隊列">
|
||||
<section class="ppt-action-queue" id="ppt-action-queue" data-ppt-action-queue aria-label="PPT 工作隊列">
|
||||
<div class="ppt-workbench-head">
|
||||
<div>
|
||||
<div class="ppt-label">Action Queue</div>
|
||||
@@ -293,7 +307,7 @@
|
||||
</div>
|
||||
</section>
|
||||
{% if issue_items %}
|
||||
<section class="ppt-issue-board" aria-label="視覺問題追蹤">
|
||||
<section class="ppt-issue-board" id="ppt-issue-board" aria-label="視覺問題追蹤">
|
||||
<div class="ppt-workbench-head">
|
||||
<div>
|
||||
<div class="ppt-label">Vision Findings</div>
|
||||
@@ -336,6 +350,7 @@
|
||||
</section>
|
||||
{% endif %}
|
||||
<section class="ppt-panel mt-3"
|
||||
id="ppt-production-center"
|
||||
data-ppt-auto-generation
|
||||
data-auto-start="{{ 'true' if auto_generation.can_auto_start else 'false' }}"
|
||||
data-report-types="{{ auto_generation_missing_report_types | join(',') }}">
|
||||
|
||||
@@ -393,7 +393,7 @@ def test_ppt_audit_history_coverage_matrix_joins_db_preview_qa(client, monkeypat
|
||||
'target_label': '2026/05/17',
|
||||
'ready': True,
|
||||
'status': 'ready',
|
||||
'status_label': '目標已產生',
|
||||
'status_label': '已產出',
|
||||
'status_hint': '檔案參數與本期定義相符。',
|
||||
'sources': ['database', 'filesystem'],
|
||||
'latest_generated_at': '2026-05-17 20:31',
|
||||
|
||||
@@ -101,7 +101,7 @@ def test_coverage_marks_ready_from_database(monkeypatch):
|
||||
by_key = {item["key"]: item for item in result["items"]}
|
||||
assert by_key["daily"]["ready"] is True
|
||||
assert by_key["daily"]["status"] == "ready"
|
||||
assert by_key["daily"]["status_label"] == "目標已產生"
|
||||
assert by_key["daily"]["status_label"] == "已產出"
|
||||
assert by_key["monthly"]["ready"] is True
|
||||
assert by_key["weekly"]["ready"] is False
|
||||
assert by_key["weekly"]["status"] == "missing"
|
||||
|
||||
@@ -11,10 +11,21 @@
|
||||
padding: var(--momo-space-5, 24px);
|
||||
background:
|
||||
radial-gradient(circle, rgba(45, 40, 32, 0.12) 1px, transparent 1.2px),
|
||||
linear-gradient(135deg, rgba(255, 248, 239, 0.98), rgba(255, 255, 255, 0.78));
|
||||
linear-gradient(135deg, rgba(255, 248, 239, 0.98), rgba(250, 247, 240, 0.78));
|
||||
background-size: 12px 12px, auto;
|
||||
}
|
||||
|
||||
.ppt-hero-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(280px, 0.34fr);
|
||||
gap: var(--momo-space-5, 24px);
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.ppt-hero-copy {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.ppt-kicker {
|
||||
color: var(--obs-accent);
|
||||
font-size: var(--momo-text-caption, 12px);
|
||||
@@ -36,6 +47,83 @@
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.ppt-hero-note {
|
||||
margin: var(--momo-space-2, 8px) 0 0;
|
||||
color: var(--obs-amber);
|
||||
font-size: var(--momo-text-body, 14px);
|
||||
font-weight: var(--momo-font-weight-bold, 700);
|
||||
}
|
||||
|
||||
.ppt-hero-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--momo-space-2, 8px);
|
||||
flex-wrap: wrap;
|
||||
margin-top: var(--momo-space-4, 16px);
|
||||
}
|
||||
|
||||
.ppt-hero-actions .btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--momo-space-1, 4px);
|
||||
}
|
||||
|
||||
.ppt-hero-deck {
|
||||
display: grid;
|
||||
align-content: space-between;
|
||||
gap: var(--momo-space-3, 12px);
|
||||
min-height: 180px;
|
||||
padding: var(--momo-space-4, 16px);
|
||||
border: 1px solid var(--obs-line);
|
||||
border-left: 5px solid var(--obs-blue);
|
||||
border-radius: var(--momo-radius-lg, 8px);
|
||||
background:
|
||||
radial-gradient(circle, rgba(45, 40, 32, 0.08) 1px, transparent 1.2px),
|
||||
rgba(250, 247, 240, 0.68);
|
||||
background-size: 10px 10px, auto;
|
||||
}
|
||||
|
||||
.ppt-hero-deck.is-ready {
|
||||
border-left-color: var(--obs-green);
|
||||
}
|
||||
|
||||
.ppt-hero-deck.is-partial,
|
||||
.ppt-hero-deck.is-planned {
|
||||
border-left-color: var(--obs-amber);
|
||||
}
|
||||
|
||||
.ppt-hero-deck.is-error {
|
||||
border-left-color: var(--obs-red);
|
||||
}
|
||||
|
||||
.ppt-hero-deck strong {
|
||||
display: block;
|
||||
color: var(--obs-ink);
|
||||
font-family: var(--momo-font-mono, "IBM Plex Mono", monospace);
|
||||
font-size: var(--momo-text-title, 18px);
|
||||
line-height: 1.35;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.ppt-hero-deck small,
|
||||
.ppt-hero-deck-run {
|
||||
color: var(--obs-muted);
|
||||
font-size: var(--momo-text-caption, 12px);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.ppt-hero-deck-run {
|
||||
display: grid;
|
||||
gap: var(--momo-space-1, 4px);
|
||||
padding-top: var(--momo-space-3, 12px);
|
||||
border-top: 1px solid var(--obs-line);
|
||||
}
|
||||
|
||||
.ppt-hero-deck-run span {
|
||||
color: var(--obs-ink);
|
||||
font-weight: var(--momo-font-weight-bold, 700);
|
||||
}
|
||||
|
||||
.ppt-diagnostic-strip {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 0.65fr) minmax(320px, 1fr) minmax(260px, 0.8fr);
|
||||
@@ -289,13 +377,31 @@
|
||||
margin-top: var(--momo-space-4, 16px);
|
||||
}
|
||||
|
||||
.ppt-command--compact {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.ppt-signal {
|
||||
padding: var(--momo-space-3, 12px);
|
||||
border: 1px solid var(--obs-line);
|
||||
border-left: 4px solid var(--obs-blue);
|
||||
border-radius: var(--momo-radius-lg, 8px);
|
||||
background: rgba(255, 255, 255, 0.62);
|
||||
}
|
||||
|
||||
.ppt-signal.is-ready {
|
||||
border-left-color: var(--obs-green);
|
||||
}
|
||||
|
||||
.ppt-signal.is-partial,
|
||||
.ppt-signal.is-planned {
|
||||
border-left-color: var(--obs-amber);
|
||||
}
|
||||
|
||||
.ppt-signal.is-error {
|
||||
border-left-color: var(--obs-red);
|
||||
}
|
||||
|
||||
.ppt-label {
|
||||
color: var(--obs-muted);
|
||||
font-size: var(--momo-text-caption, 12px);
|
||||
@@ -313,16 +419,21 @@
|
||||
|
||||
.ppt-toolbar {
|
||||
margin-top: var(--momo-space-4, 16px);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
align-items: start;
|
||||
gap: var(--momo-space-3, 12px);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ppt-type-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding-bottom: var(--momo-space-1, 4px);
|
||||
scrollbar-width: thin;
|
||||
flex-wrap: nowrap;
|
||||
gap: var(--momo-space-2, 8px);
|
||||
}
|
||||
|
||||
@@ -330,6 +441,8 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--momo-space-1, 4px);
|
||||
flex: 0 0 auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ppt-deck-workbench {
|
||||
@@ -344,6 +457,10 @@
|
||||
box-shadow: var(--momo-shadow-md, 0 16px 38px rgba(70, 46, 28, 0.08));
|
||||
}
|
||||
|
||||
.ppt-deck-empty {
|
||||
padding: var(--momo-space-4, 16px);
|
||||
}
|
||||
|
||||
.ppt-workbench-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -660,6 +777,14 @@ body.ppt-preview-open {
|
||||
box-shadow: var(--momo-shadow-md, 0 16px 38px rgba(70, 46, 28, 0.08));
|
||||
}
|
||||
|
||||
#ppt-deck-workbench,
|
||||
#ppt-action-queue,
|
||||
#ppt-issue-board,
|
||||
#ppt-production-center,
|
||||
#ppt-runtime-diagnostic {
|
||||
scroll-margin-top: 88px;
|
||||
}
|
||||
|
||||
.ppt-issue-board {
|
||||
margin-top: var(--momo-space-4, 16px);
|
||||
padding: var(--momo-space-4, 16px);
|
||||
@@ -1222,6 +1347,10 @@ body.ppt-preview-open {
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
.ppt-hero-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.ppt-command {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
@@ -1273,6 +1402,10 @@ body.ppt-preview-open {
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.ppt-hero {
|
||||
padding: var(--momo-space-4, 16px);
|
||||
}
|
||||
|
||||
.ppt-command,
|
||||
.ppt-auto-grid,
|
||||
.ppt-mini-grid,
|
||||
@@ -1285,6 +1418,15 @@ body.ppt-preview-open {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.ppt-toolbar {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.ppt-type-tabs {
|
||||
margin-inline: calc(var(--momo-space-2, 8px) * -1);
|
||||
padding-inline: var(--momo-space-2, 8px);
|
||||
}
|
||||
|
||||
.ppt-panel-head,
|
||||
.ppt-panel-actions,
|
||||
.ppt-table-title,
|
||||
|
||||
Reference in New Issue
Block a user