This is an automated email from the ASF dual-hosted git repository. shuber pushed a commit to branch UNOMI-932-website-modernization in repository https://gitbox.apache.org/repos/asf/unomi-site.git
commit 78731011d6f9426d4d39618e00671167d7fc2190 Author: Serge Huber <[email protected]> AuthorDate: Sat Feb 14 17:29:21 2026 +0100 CSS design system: centralized variables, utility classes, DRY cleanup - Add new CSS variables for rgba variants, opacity levels, and color tokens - Create 10+ utility classes to replace inline styles (badges, icons, overlays) - Merge duplicate CSS rules (.mermaid, media queries, button hovers) - Add vendor prefix (-webkit-backdrop-filter) for Safari - Fix color contrast for WCAG AA compliance (hero text opacity) - Add mobile overflow protection for Mermaid diagrams and code blocks - Extract shared Fisher-Yates shuffle script to assets/js/shuffle.js Co-authored-by: Cursor <[email protected]> --- src/main/webapp/assets/css/unomi.css | 161 +++++++++++++++++++++++++++-------- src/main/webapp/assets/js/shuffle.js | 24 ++++++ 2 files changed, 148 insertions(+), 37 deletions(-) diff --git a/src/main/webapp/assets/css/unomi.css b/src/main/webapp/assets/css/unomi.css index 06761e8..c5a1971 100644 --- a/src/main/webapp/assets/css/unomi.css +++ b/src/main/webapp/assets/css/unomi.css @@ -55,16 +55,29 @@ /* Overlay & glass */ --unomi-overlay: rgba(0,0,0,.6); + --unomi-shadow-dark: rgba(0,0,0,.2); --unomi-glass: rgba(255,255,255,.92); --unomi-hover-light: rgba(255,255,255,.1); + --unomi-glow-faint: rgba(255,255,255,.08); /* Text on dark backgrounds */ --unomi-on-dark: rgba(255,255,255,.8); --unomi-on-dark-muted: rgba(255,255,255,.75); --unomi-on-dark-subtle: rgba(255,255,255,.85); - --unomi-hero-label: rgba(255,255,255,.5); - --unomi-hero-muted: rgba(255,255,255,.45); - --unomi-hero-link: rgba(255,255,255,.6); + --unomi-hero-label: rgba(255,255,255,.6); + --unomi-hero-muted: rgba(255,255,255,.7); + --unomi-hero-link: rgba(255,255,255,.75); + + /* Brand translucent */ + --unomi-primary-glow: rgba(109,92,231,.3); + --unomi-primary-glow-strong: rgba(109,92,231,.6); + --unomi-primary-glow-soft: rgba(109,92,231,.85); + --unomi-primary-border-light: rgba(109,92,231,.2); + --unomi-hero-accent-glow: rgba(167,139,250,.15); + --unomi-hero-accent-ghost: rgba(167,139,250,.08); + --unomi-hero-accent-whisper: rgba(167,139,250,.06); + --unomi-gradient-start-fade: rgba(30,27,75,.2); + --unomi-on-dark-dim: rgba(255,255,255,.65); /* Gradient anchors */ --unomi-gradient-start: #312e81; @@ -139,10 +152,24 @@ a:hover { color: var(--unomi-primary-dark); } +/* ---------- Focus Indicators (WCAG 2.4.7) ---------- */ +a:focus-visible, +button:focus-visible, +.btn:focus-visible, +input:focus-visible, +select:focus-visible, +textarea:focus-visible, +[tabindex]:focus-visible { + outline: 2px solid var(--unomi-primary); + outline-offset: 2px; + border-radius: 2px; +} + /* ---------- Navbar ---------- */ .navbar { padding: 0.75rem 0; transition: box-shadow var(--unomi-transition), background var(--unomi-transition); + -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); background: var(--unomi-glass) !important; } @@ -198,34 +225,37 @@ a:hover { } /* ---------- Buttons ---------- */ -.btn-primary { - background: var(--unomi-primary); - border-color: var(--unomi-primary); +.btn-primary, +.btn-outline-primary { border-radius: var(--unomi-radius-sm); font-weight: 600; transition: all var(--unomi-transition); } -.btn-primary:hover { - background: var(--unomi-primary-dark); - border-color: var(--unomi-primary-dark); - transform: translateY(-1px); - box-shadow: 0 6px 20px rgba(109,92,231,.3); +.btn-primary { + background: var(--unomi-primary); + border-color: var(--unomi-primary); } .btn-outline-primary { color: var(--unomi-primary); border-color: var(--unomi-primary); - border-radius: var(--unomi-radius-sm); - font-weight: 600; - transition: all var(--unomi-transition); +} + +.btn-primary:hover, +.btn-outline-primary:hover { + transform: translateY(-1px); + box-shadow: 0 6px 20px var(--unomi-primary-glow); +} + +.btn-primary:hover { + background: var(--unomi-primary-dark); + border-color: var(--unomi-primary-dark); } .btn-outline-primary:hover { background: var(--unomi-primary); border-color: var(--unomi-primary); - transform: translateY(-1px); - box-shadow: 0 6px 20px rgba(109,92,231,.3); } .btn-lg { @@ -255,7 +285,7 @@ a:hover { right: -20%; width: 60%; height: 200%; - background: radial-gradient(ellipse, rgba(167,139,250,.15) 0%, transparent 70%); + background: radial-gradient(ellipse, var(--unomi-hero-accent-glow) 0%, transparent 70%); pointer-events: none; } @@ -266,7 +296,7 @@ a:hover { left: 0; right: 0; height: 4rem; - background: linear-gradient(to bottom, transparent, rgba(30,27,75,.2)); + background: linear-gradient(to bottom, transparent, var(--unomi-gradient-start-fade)); pointer-events: none; } @@ -290,7 +320,7 @@ a:hover { .hero .btn-primary:hover { background: var(--unomi-primary-light); color: var(--unomi-primary-dark); - box-shadow: 0 6px 20px rgba(0,0,0,.2); + box-shadow: 0 6px 20px var(--unomi-shadow-dark); } .hero .btn-outline-light { @@ -397,18 +427,14 @@ a:hover { } /* ---------- Architecture / Mermaid Diagrams ---------- */ -.mermaid { - background: var(--unomi-bg-soft); - border-radius: var(--unomi-radius); - padding: 2rem; - border: 1px solid var(--unomi-border); -} - +.mermaid, pre.mermaid { background: var(--unomi-bg-soft); border-radius: var(--unomi-radius); padding: 2rem; border: 1px solid var(--unomi-border); + overflow-x: auto; /* prevent horizontal page scroll on mobile */ + -webkit-overflow-scrolling: touch; } /* ---------- Steps / Process ---------- */ @@ -486,7 +512,7 @@ pre.mermaid { filter: brightness(.85); } .feature-card a[href*="youtube"]:hover .rounded-circle { - background: rgba(109,92,231,.85) !important; + background: var(--unomi-primary-glow-soft) !important; } /* ---------- Integration Cards ---------- */ @@ -569,6 +595,8 @@ pre { padding: 1.25rem; font-size: 0.85rem; overflow-x: auto; + max-width: 100%; /* prevent breaking out of container on mobile */ + -webkit-overflow-scrolling: touch; } code { @@ -603,7 +631,7 @@ code { right: -10%; width: 40%; height: 200%; - background: radial-gradient(ellipse, rgba(255,255,255,.08) 0%, transparent 70%); + background: radial-gradient(ellipse, var(--unomi-glow-faint) 0%, transparent 70%); pointer-events: none; } @@ -720,6 +748,9 @@ code { height: 2rem; font-size: 0.8rem; } + + .news-item { flex-wrap: wrap; } + .news-date { min-width: auto; width: 100%; margin-bottom: .15rem; } } /* ---------- Utility Classes ---------- */ @@ -792,7 +823,7 @@ code { flex: 0 0 auto; font-size: .75rem; font-weight: 600; - color: var(--unomi-muted); + color: var(--unomi-text-muted); font-variant-numeric: tabular-nums; min-width: 5.5rem; } @@ -810,19 +841,14 @@ code { white-space: nowrap; } -@media (max-width: 575.98px) { - .news-item { flex-wrap: wrap; } - .news-date { min-width: auto; width: 100%; margin-bottom: .15rem; } -} - /* ---------- Ecosystem marquee ---------- */ .ecosystem-marquee { overflow: hidden; position: relative; padding: 0.5rem 0 1rem; /* Fade edges */ - -webkit-mask-image: linear-gradient(to right, transparent, black 5%, black 95%, transparent); - mask-image: linear-gradient(to right, transparent, black 5%, black 95%, transparent); + -webkit-mask-image: linear-gradient(to right, transparent, var(--unomi-text) 5%, var(--unomi-text) 95%, transparent); + mask-image: linear-gradient(to right, transparent, var(--unomi-text) 5%, var(--unomi-text) 95%, transparent); } @keyframes marquee-scroll { @@ -854,7 +880,7 @@ code { .ecosystem-card-oss { background: var(--unomi-primary-light); - border-color: rgba(109,92,231,.2); + border-color: var(--unomi-primary-border-light); display: flex; align-items: center; justify-content: center; @@ -909,3 +935,64 @@ code { /* Tip / callout box */ .tip-box { background: var(--unomi-tip-bg); border-color: var(--unomi-tip-border); } + +/* ---------- Reusable utility classes ---------- */ + +/* Video thumbnail containers */ +.video-thumbnail { aspect-ratio: 16/9; } +.img-cover { object-fit: cover; } +.play-icon { font-size: 1.5rem; margin-left: 2px; } +.play-icon-sm { font-size: 1.2rem; margin-left: 2px; } + +/* Blockquote attribution (override fst-italic) */ +.quote-attribution { font-style: normal; } + +/* Emeritus / retired member cards */ +.card-emeritus { opacity: .75; } + +/* Small feature icon variant */ +.feature-icon-sm { width: 2rem; height: 2rem; font-size: 1rem; } + +/* Badge status dot */ +.badge-dot { font-size: .5em; } + +/* Info / empty-state box */ +.info-box { + background: var(--unomi-bg-soft); + border: 1px solid var(--unomi-border); + border-radius: var(--unomi-radius-sm); +} + +/* Hero illustration max-width */ +.hero-illustration { max-width: 560px; } + +/* Large primary icon (e.g. globe icon in CDP section) */ +.icon-lg-primary { font-size: 2rem; color: var(--unomi-primary); } + +/* Logo/image max-width variants */ +.mw-220 { max-width: 220px; } +.mw-234 { max-width: 234px; } + +/* Badge status dot (smaller variant for version badges) */ +.badge-dot-sm { font-size: .45em; } + +/* CVE badge */ +.badge-cve { font-size: .65rem; } + +/* Clickable summary */ +.cursor-pointer { cursor: pointer; } + +/* Background accent (light primary) */ +.bg-primary-light { background: var(--unomi-primary-light); } + +/* Section without bottom padding (e.g. TOC) */ +.section-flush-bottom { padding-bottom: 0; } + +/* Feature icon medium variant (2.5rem) */ +.feature-icon-md { width: 2.5rem; height: 2.5rem; font-size: 1rem; } + +/* Navbar brand image */ +.navbar-brand-img { width: auto; } + +/* Feather icon inline */ +.feather-icon { height: 1.2em; } diff --git a/src/main/webapp/assets/js/shuffle.js b/src/main/webapp/assets/js/shuffle.js new file mode 100644 index 0000000..98ccd74 --- /dev/null +++ b/src/main/webapp/assets/js/shuffle.js @@ -0,0 +1,24 @@ +/** + * ASF compliance: randomize element ordering on every page load. + * Elements with [data-shuffle-group] will have their direct children + * shuffled using the Fisher-Yates algorithm. + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. + */ +(function () { + 'use strict'; + document.querySelectorAll('[data-shuffle-group]').forEach(function (container) { + var items = Array.from(container.children); + // Fisher-Yates shuffle + for (var i = items.length - 1; i > 0; i--) { + var j = Math.floor(Math.random() * (i + 1)); + var temp = items[i]; + items[i] = items[j]; + items[j] = temp; + } + items.forEach(function (item) { + container.appendChild(item); + }); + }); +})();
