This commit is contained in:
@@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
|
||||
# ==========================================
|
||||
# 系統版本與路徑
|
||||
# ==========================================
|
||||
SYSTEM_VERSION = "V10.116"
|
||||
SYSTEM_VERSION = "V10.117"
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = PUBLIC_URL # 用於模板顯示
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Rendered visual contract for AI observability pages.
|
||||
*
|
||||
* This complements the static template guard by checking computed CSS in a
|
||||
* browser: typography, warm-token surfaces, radius, hero backgrounds, and
|
||||
* browser: typography, warm-token surfaces, dot-matrix texture, radius, and
|
||||
* mobile density across the 10 observability pages.
|
||||
*/
|
||||
|
||||
@@ -195,6 +195,11 @@ function contrastRatio(fg, bg) {
|
||||
return (lighter + 0.05) / (darker + 0.05);
|
||||
}
|
||||
|
||||
function isDotMatrixBackground(backgroundImage) {
|
||||
const value = String(backgroundImage || '');
|
||||
return value.includes('radial-gradient') && !value.includes('linear-gradient');
|
||||
}
|
||||
|
||||
async function collectMetrics(page) {
|
||||
return page.evaluate(({ heroSelectors, titleSelectors, surfaceSelectors }) => {
|
||||
const parseRgbValue = (value) => {
|
||||
@@ -234,6 +239,7 @@ async function collectMetrics(page) {
|
||||
const title = document.querySelector(titleSelectors);
|
||||
const badRadius = [];
|
||||
const badBackground = [];
|
||||
const missingMatrix = [];
|
||||
const badChipContrast = [];
|
||||
|
||||
for (const el of document.querySelectorAll(`.momo-observability-mode :is(${surfaceSelectors})`)) {
|
||||
@@ -246,13 +252,24 @@ async function collectMetrics(page) {
|
||||
text: String(el.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 80),
|
||||
});
|
||||
}
|
||||
if ((el.matches(heroSelectors) || el.matches('.obs-panel,.agent-panel,.biz-panel,.runtime-panel,.calls-panel,.gov-panel,.gate-panel,.rag-panel,.qa-panel,.quality-panel,.ppt-panel')) && style.backgroundImage !== 'none') {
|
||||
const mustUseMatrix = el.matches(heroSelectors)
|
||||
|| el.matches('.obs-panel,.agent-panel,.biz-panel,.runtime-panel,.calls-panel,.gov-panel,.gate-panel,.rag-panel,.qa-panel,.quality-panel,.ppt-panel')
|
||||
|| el.matches('.obs-signal,.agent-signal,.biz-signal,.runtime-signal,.calls-signal,.gov-signal,.gate-signal,.rag-signal,.qa-signal,.quality-signal,.ppt-signal');
|
||||
const hasRadialMatrix = style.backgroundImage.includes('radial-gradient');
|
||||
const hasLegacyGradient = style.backgroundImage.includes('linear-gradient');
|
||||
if (mustUseMatrix && (!hasRadialMatrix || hasLegacyGradient)) {
|
||||
badBackground.push({
|
||||
className: String(el.className || '').slice(0, 100),
|
||||
backgroundImage: style.backgroundImage.slice(0, 100),
|
||||
});
|
||||
}
|
||||
if (badRadius.length >= 8 && badBackground.length >= 8) break;
|
||||
if (mustUseMatrix && !hasRadialMatrix) {
|
||||
missingMatrix.push({
|
||||
className: String(el.className || '').slice(0, 100),
|
||||
text: String(el.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 80),
|
||||
});
|
||||
}
|
||||
if (badRadius.length >= 8 && badBackground.length >= 8 && missingMatrix.length >= 8) break;
|
||||
}
|
||||
|
||||
for (const el of document.querySelectorAll('.momo-observability-mode :is(.badge,.obs-pill,[class$="-pill"],.biz-badge)')) {
|
||||
@@ -292,6 +309,7 @@ async function collectMetrics(page) {
|
||||
} : null,
|
||||
badRadius,
|
||||
badBackground,
|
||||
missingMatrix,
|
||||
badChipContrast,
|
||||
};
|
||||
}, { heroSelectors: HERO_SELECTORS, titleSelectors: TITLE_SELECTORS, surfaceSelectors: SURFACE_SELECTORS });
|
||||
@@ -323,13 +341,16 @@ function issuesFor(metrics, viewport) {
|
||||
issues.push('missing hero selector');
|
||||
} else {
|
||||
if (px(metrics.hero.radius) > 8.5) issues.push(`hero radius ${metrics.hero.radius}`);
|
||||
if (metrics.hero.backgroundImage !== 'none') issues.push('hero background image is not none');
|
||||
if (!isDotMatrixBackground(metrics.hero.backgroundImage)) {
|
||||
issues.push('hero missing tokenized dot-matrix background');
|
||||
}
|
||||
if (metrics.hero.height > viewport.maxHeroHeight) {
|
||||
issues.push(`hero too tall ${metrics.hero.height}px > ${viewport.maxHeroHeight}px`);
|
||||
}
|
||||
}
|
||||
if (metrics.badRadius.length) issues.push(`surface radius offenders ${metrics.badRadius.length}`);
|
||||
if (metrics.badBackground.length) issues.push(`surface background-image offenders ${metrics.badBackground.length}`);
|
||||
if (metrics.badBackground.length) issues.push(`surface non-matrix background offenders ${metrics.badBackground.length}`);
|
||||
if (metrics.missingMatrix.length) issues.push(`surface missing dot-matrix offenders ${metrics.missingMatrix.length}`);
|
||||
if (metrics.badChipContrast.length) issues.push(`chip contrast offenders ${metrics.badChipContrast.length}`);
|
||||
return issues;
|
||||
}
|
||||
@@ -385,7 +406,7 @@ async function main() {
|
||||
const hero = result.metrics?.hero ? `${result.metrics.hero.height}px r=${result.metrics.hero.radius}` : 'n/a';
|
||||
console.log(`${status} ${result.viewport} ${result.route} title=${title} hero=${hero}${result.issues.length ? ` issues=${result.issues.join('; ')}` : ''}`);
|
||||
if (!result.passed && result.metrics) {
|
||||
for (const bucket of ['badRadius', 'badBackground', 'badChipContrast']) {
|
||||
for (const bucket of ['badRadius', 'badBackground', 'missingMatrix', 'badChipContrast']) {
|
||||
for (const offender of result.metrics[bucket] || []) {
|
||||
console.log(` ${bucket}: ${JSON.stringify(offender)}`);
|
||||
}
|
||||
|
||||
@@ -1761,6 +1761,101 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* v3.8 dot-matrix integration: surfaces carry the product texture without legacy gradients. */
|
||||
.momo-observability-mode {
|
||||
--obs-matrix-dot: radial-gradient(color-mix(in srgb, var(--obs-accent) 14%, transparent) 0.85px, transparent 0.95px);
|
||||
--obs-matrix-dot-soft: radial-gradient(color-mix(in srgb, var(--obs-muted) 12%, transparent) 0.75px, transparent 0.9px);
|
||||
--obs-matrix-size: 13px 13px;
|
||||
}
|
||||
|
||||
.momo-observability-mode :is(
|
||||
.obs-hero,
|
||||
.agent-hero,
|
||||
.biz-command,
|
||||
.runtime-hero,
|
||||
.calls-hero,
|
||||
.gov-hero,
|
||||
.gate-hero,
|
||||
.rag-hero,
|
||||
.qa-hero,
|
||||
.quality-hero,
|
||||
.ppt-hero,
|
||||
.obs-panel,
|
||||
.agent-panel,
|
||||
.biz-panel,
|
||||
.runtime-panel,
|
||||
.calls-panel,
|
||||
.gov-panel,
|
||||
.gate-panel,
|
||||
.rag-panel,
|
||||
.qa-panel,
|
||||
.quality-panel,
|
||||
.ppt-panel,
|
||||
.obs-signal,
|
||||
.agent-signal,
|
||||
.biz-signal,
|
||||
.runtime-signal,
|
||||
.calls-signal,
|
||||
.gov-signal,
|
||||
.gate-signal,
|
||||
.rag-signal,
|
||||
.qa-signal,
|
||||
.quality-signal,
|
||||
.ppt-signal,
|
||||
.biz-filter-card,
|
||||
.biz-alert-strip,
|
||||
.biz-strategy-card,
|
||||
.biz-mini-metric,
|
||||
.biz-decision-card,
|
||||
.episode-card,
|
||||
.similar-box,
|
||||
.fix-card,
|
||||
.root-card,
|
||||
.rec-card,
|
||||
.agent-card,
|
||||
.caller-card,
|
||||
.host-lane,
|
||||
.strategy-card,
|
||||
.obs-route-card
|
||||
) {
|
||||
background-color: var(--momo-bg-surface, #faf6ec) !important;
|
||||
background-image: var(--obs-matrix-dot) !important;
|
||||
background-position: 0 0 !important;
|
||||
background-size: var(--obs-matrix-size) !important;
|
||||
}
|
||||
|
||||
.momo-observability-mode :is(
|
||||
.obs-panel,
|
||||
.agent-panel,
|
||||
.biz-panel,
|
||||
.runtime-panel,
|
||||
.calls-panel,
|
||||
.gov-panel,
|
||||
.gate-panel,
|
||||
.rag-panel,
|
||||
.qa-panel,
|
||||
.quality-panel,
|
||||
.ppt-panel,
|
||||
.biz-filter-card,
|
||||
.biz-strategy-card,
|
||||
.episode-card,
|
||||
.host-lane,
|
||||
.caller-card,
|
||||
.agent-card,
|
||||
.rec-card,
|
||||
.fix-card,
|
||||
.root-card,
|
||||
.strategy-card
|
||||
) {
|
||||
background-image: var(--obs-matrix-dot-soft) !important;
|
||||
}
|
||||
|
||||
.momo-observability-mode :is(.obs-pill, [class$="-pill"], .biz-badge, .badge) {
|
||||
background-image: var(--obs-matrix-dot-soft) !important;
|
||||
background-position: 0 0 !important;
|
||||
background-size: 10px 10px !important;
|
||||
}
|
||||
|
||||
/* v3.7 typography tightening: no legacy tracking, poster-scale numerals, or wrapped action buttons. */
|
||||
.momo-observability-mode :is(
|
||||
.obs-kicker,
|
||||
|
||||
@@ -1761,6 +1761,101 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* v3.8 dot-matrix integration: surfaces carry the product texture without legacy gradients. */
|
||||
.momo-observability-mode {
|
||||
--obs-matrix-dot: radial-gradient(color-mix(in srgb, var(--obs-accent) 14%, transparent) 0.85px, transparent 0.95px);
|
||||
--obs-matrix-dot-soft: radial-gradient(color-mix(in srgb, var(--obs-muted) 12%, transparent) 0.75px, transparent 0.9px);
|
||||
--obs-matrix-size: 13px 13px;
|
||||
}
|
||||
|
||||
.momo-observability-mode :is(
|
||||
.obs-hero,
|
||||
.agent-hero,
|
||||
.biz-command,
|
||||
.runtime-hero,
|
||||
.calls-hero,
|
||||
.gov-hero,
|
||||
.gate-hero,
|
||||
.rag-hero,
|
||||
.qa-hero,
|
||||
.quality-hero,
|
||||
.ppt-hero,
|
||||
.obs-panel,
|
||||
.agent-panel,
|
||||
.biz-panel,
|
||||
.runtime-panel,
|
||||
.calls-panel,
|
||||
.gov-panel,
|
||||
.gate-panel,
|
||||
.rag-panel,
|
||||
.qa-panel,
|
||||
.quality-panel,
|
||||
.ppt-panel,
|
||||
.obs-signal,
|
||||
.agent-signal,
|
||||
.biz-signal,
|
||||
.runtime-signal,
|
||||
.calls-signal,
|
||||
.gov-signal,
|
||||
.gate-signal,
|
||||
.rag-signal,
|
||||
.qa-signal,
|
||||
.quality-signal,
|
||||
.ppt-signal,
|
||||
.biz-filter-card,
|
||||
.biz-alert-strip,
|
||||
.biz-strategy-card,
|
||||
.biz-mini-metric,
|
||||
.biz-decision-card,
|
||||
.episode-card,
|
||||
.similar-box,
|
||||
.fix-card,
|
||||
.root-card,
|
||||
.rec-card,
|
||||
.agent-card,
|
||||
.caller-card,
|
||||
.host-lane,
|
||||
.strategy-card,
|
||||
.obs-route-card
|
||||
) {
|
||||
background-color: var(--momo-bg-surface, #faf6ec) !important;
|
||||
background-image: var(--obs-matrix-dot) !important;
|
||||
background-position: 0 0 !important;
|
||||
background-size: var(--obs-matrix-size) !important;
|
||||
}
|
||||
|
||||
.momo-observability-mode :is(
|
||||
.obs-panel,
|
||||
.agent-panel,
|
||||
.biz-panel,
|
||||
.runtime-panel,
|
||||
.calls-panel,
|
||||
.gov-panel,
|
||||
.gate-panel,
|
||||
.rag-panel,
|
||||
.qa-panel,
|
||||
.quality-panel,
|
||||
.ppt-panel,
|
||||
.biz-filter-card,
|
||||
.biz-strategy-card,
|
||||
.episode-card,
|
||||
.host-lane,
|
||||
.caller-card,
|
||||
.agent-card,
|
||||
.rec-card,
|
||||
.fix-card,
|
||||
.root-card,
|
||||
.strategy-card
|
||||
) {
|
||||
background-image: var(--obs-matrix-dot-soft) !important;
|
||||
}
|
||||
|
||||
.momo-observability-mode :is(.obs-pill, [class$="-pill"], .biz-badge, .badge) {
|
||||
background-image: var(--obs-matrix-dot-soft) !important;
|
||||
background-position: 0 0 !important;
|
||||
background-size: 10px 10px !important;
|
||||
}
|
||||
|
||||
/* v3.7 typography tightening: no legacy tracking, poster-scale numerals, or wrapped action buttons. */
|
||||
.momo-observability-mode :is(
|
||||
.obs-kicker,
|
||||
|
||||
Reference in New Issue
Block a user