mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-20 13:52:24 +02:00
Merge pull request #18 from o3LL/fix/duplicate-keyframes
fix(css): collapse duplicate @keyframes names to the definition that wins
This commit is contained in:
@@ -28,10 +28,6 @@
|
|||||||
0%, 100% { transform: scale(1); opacity: 1; }
|
0%, 100% { transform: scale(1); opacity: 1; }
|
||||||
50% { transform: scale(1.5); opacity: 0.7; }
|
50% { transform: scale(1.5); opacity: 0.7; }
|
||||||
}
|
}
|
||||||
@keyframes research-pulse {
|
|
||||||
0%, 100% { background: color-mix(in srgb, var(--red) 12%, transparent); }
|
|
||||||
50% { background: color-mix(in srgb, var(--red) 22%, transparent); }
|
|
||||||
}
|
|
||||||
#cookbook-gguf-delete-overlay {
|
#cookbook-gguf-delete-overlay {
|
||||||
background:rgba(0,0,0,0.5);
|
background:rgba(0,0,0,0.5);
|
||||||
backdrop-filter:blur(4px);
|
backdrop-filter:blur(4px);
|
||||||
|
|||||||
@@ -1480,7 +1480,6 @@ body.bg-pattern-ascii-fireflies {
|
|||||||
0% { opacity: 1; transform: translateY(0) translateX(0) scale(1); }
|
0% { opacity: 1; transform: translateY(0) translateX(0) scale(1); }
|
||||||
100% { opacity: 0; transform: translateY(6px) translateX(-3px) scale(0.94); }
|
100% { opacity: 0; transform: translateY(6px) translateX(-3px) scale(0.94); }
|
||||||
}
|
}
|
||||||
@keyframes spin { to { transform: rotate(360deg); } }
|
|
||||||
.row { display:flex; gap:6px; align-items:center; }
|
.row { display:flex; gap:6px; align-items:center; }
|
||||||
.list-item:hover,
|
.list-item:hover,
|
||||||
.models-row:hover {
|
.models-row:hover {
|
||||||
@@ -6119,9 +6118,6 @@ body.bg-pattern-ascii-fireflies {
|
|||||||
#mobile-backdrop, #mobile-menu-btn { display:none !important; }
|
#mobile-backdrop, #mobile-menu-btn { display:none !important; }
|
||||||
#sidebar-backdrop { display:none !important; }
|
#sidebar-backdrop { display:none !important; }
|
||||||
/* ----- Loading spinner ----- */
|
/* ----- Loading spinner ----- */
|
||||||
@keyframes spin {
|
|
||||||
to { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
.spinner {
|
.spinner {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
@@ -6240,14 +6236,6 @@ body.bg-pattern-ascii-fireflies {
|
|||||||
.session-skeleton-bubble.is-user { width: 72%; }
|
.session-skeleton-bubble.is-user { width: 72%; }
|
||||||
.session-skeleton-line { height: 9px; margin-top: 7px; }
|
.session-skeleton-line { height: 9px; margin-top: 7px; }
|
||||||
}
|
}
|
||||||
@keyframes loading-bounce {
|
|
||||||
0%, 80%, 100% {
|
|
||||||
transform: scale(0);
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Modal styling */
|
/* Modal styling */
|
||||||
.modal {
|
.modal {
|
||||||
position:fixed;
|
position:fixed;
|
||||||
@@ -7555,11 +7543,6 @@ body.bg-pattern-ascii-fireflies {
|
|||||||
animation: pulse 1.5s infinite;
|
animation: pulse 1.5s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
50% { opacity: 0.7; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#recording-indicator {
|
#recording-indicator {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -8720,7 +8703,6 @@ pre { background: var(--code-bg, var(--hl-bg, #282c34)) !important; }
|
|||||||
}
|
}
|
||||||
.compare-probe-start-anyway svg { color: currentColor; }
|
.compare-probe-start-anyway svg { color: currentColor; }
|
||||||
.compare-probe-start-anyway span { font-weight: 700; }
|
.compare-probe-start-anyway span { font-weight: 700; }
|
||||||
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
||||||
@keyframes pane-shake {
|
@keyframes pane-shake {
|
||||||
0%, 100% { transform: translateX(0); }
|
0%, 100% { transform: translateX(0); }
|
||||||
15% { transform: translateX(-3px) rotate(-0.5deg); }
|
15% { transform: translateX(-3px) rotate(-0.5deg); }
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
"""No two @keyframes may share a name across the app's stylesheets.
|
||||||
|
|
||||||
|
Duplicate names resolve last-wins across the whole cascade, so an earlier
|
||||||
|
definition is dead code that still looks live at its call site. Two of them
|
||||||
|
existed and differed from the definition that actually won, which also blocked
|
||||||
|
moving either animation during the stylesheet decomposition: relocating one
|
||||||
|
changes which is last and therefore changes rendered behaviour.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
STATIC = ROOT / "static"
|
||||||
|
|
||||||
|
|
||||||
|
def _stylesheets() -> list[Path]:
|
||||||
|
"""App-owned stylesheets, in no particular order. Vendored CSS is excluded."""
|
||||||
|
sheets = [STATIC / "style.css"]
|
||||||
|
sheets.extend(sorted((STATIC / "css").glob("*.css")))
|
||||||
|
return [s for s in sheets if s.exists()]
|
||||||
|
|
||||||
|
|
||||||
|
def _keyframe_names(text: str) -> list[str]:
|
||||||
|
without_comments = re.sub(r"/\*.*?\*/", "", text, flags=re.S)
|
||||||
|
return re.findall(
|
||||||
|
r"@(?:-webkit-)?keyframes\s+([A-Za-z0-9_-]+)\s*\{", without_comments
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_stylesheets_exist() -> None:
|
||||||
|
"""Guard the guard: a rename must not turn this file into a no-op."""
|
||||||
|
assert _stylesheets(), "no app stylesheets found to check"
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_keyframes_name_is_declared_twice() -> None:
|
||||||
|
counts: collections.Counter[str] = collections.Counter()
|
||||||
|
where: dict[str, list[str]] = collections.defaultdict(list)
|
||||||
|
|
||||||
|
for sheet in _stylesheets():
|
||||||
|
for name in _keyframe_names(sheet.read_text(encoding="utf-8")):
|
||||||
|
counts[name] += 1
|
||||||
|
where[name].append(sheet.relative_to(ROOT).as_posix())
|
||||||
|
|
||||||
|
duplicates = {name: where[name] for name, n in counts.items() if n > 1}
|
||||||
|
|
||||||
|
assert duplicates == {}, (
|
||||||
|
"duplicate @keyframes names resolve last-wins, so every definition but "
|
||||||
|
f"the last is dead: {duplicates}"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user