LilyScript / web /score-player.css
k-l-lambda's picture
added i18n.
8565c15
Raw
History Blame Contribute Delete
6.16 kB
/* LilyScript score player — preview + transport. Light theme to match Gradio Soft. */
/* Gradio's `.gradio-container .prose * { color: var(--body-text-color) }` sets a
color DIRECTLY on every descendant of our mount, overriding anything we set by
inheritance and out-specifying a plain class. We mount under id #ls-score, so
prefixing our color rules with that id (specificity beats two classes) lets them
win WITHOUT !important. This base rule pins the default text color for the whole
subtree; the specific rules below override per element. (The SVG ink color is a
separate concern — see the `.ls-svg svg` block.) */
#ls-score, #ls-score :where(.ls-status, .ls-btn, .ls-time, .ls-err-pre, span, div, button) {
color: #333;
}
.ls-score-root {
display: flex;
flex-direction: column;
height: 100%;
min-height: 600px;
}
.ls-preview {
flex: 1;
overflow: auto;
background: #fafafa;
border: 1px solid #e5e5e5;
border-radius: 8px;
padding: 12px;
position: relative;
}
#ls-score .ls-status {
font-size: 12px;
color: #888;
min-height: 16px;
margin-bottom: 4px;
}
#ls-score .ls-status.ls-busy { color: #2b7; }
#ls-score .ls-status.ls-err { color: #c0392b; }
/* multi-line parse errors: preserve the caret alignment, wrap overflow. */
#ls-score .ls-status.ls-err .ls-err-pre {
margin: 0;
font-family: ui-monospace, Consolas, Monaco, monospace;
font-size: 11px;
line-height: 1.35;
white-space: pre-wrap;
word-break: break-word;
color: #c0392b;
}
.ls-svg {
background: #fff;
display: inline-block;
min-width: 100%;
position: relative; /* anchor for the absolutely-positioned playback cursor */
}
/* faint warm/yellow tint behind the score while generating */
.ls-svg.ls-generating-bg {
background: #fffdf2;
}
.ls-svg svg {
max-width: 100%;
height: auto;
}
/* Stacked Verovio pages (a long score paginates into several SVGs). Each page is a
block so they stack vertically; a small gap separates pages. */
.ls-svg .ls-svg-page {
display: block;
margin: 0 auto 8px;
}
.ls-svg .ls-svg-page:last-of-type {
margin-bottom: 0;
}
/* Playback cursor: a vertical line tracking the currently-sounding note. */
.ls-cursor {
position: absolute;
width: 2px;
background: rgba(124, 92, 255, 0.85);
pointer-events: none;
z-index: 5;
display: none;
transition: left 0.06s linear;
}
/* Verovio draws everything with stroke|fill="currentColor", which resolves to the
computed `color`. We can't rely on inheritance from a container `color`: Gradio's
`.prose * { color: var(--body-text-color) }` sets color DIRECTLY on every
descendant (so it wins over an inherited value), which under the dark theme is a
light grey — leaving staff lines, bar lines and the per-system left brace/bracket
(grpSym) too pale. Force a dark `color` on the whole svg subtree (high enough
specificity + !important to beat `.prose *`), and pin stroke on the line elements
as belt-and-suspenders. */
.ls-svg svg,
.ls-svg svg * {
color: #1a1a1a !important;
}
.ls-svg svg .staff path,
.ls-svg svg .barLine path,
.ls-svg svg .ledgerLines path,
.ls-svg svg .grpSym path {
stroke: #1a1a1a;
}
/* playing-note highlight on the SVG */
.ls-hl {
fill: #ff6b35 !important;
stroke: #ff6b35 !important;
}
/* transport bar */
.ls-player {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
margin-bottom: 8px;
background: #f3f3f5;
border: 1px solid #e5e5e5;
border-radius: 8px;
}
#ls-score .ls-btn {
border: 1px solid #d0d0d6;
background: #fff;
color: #333;
width: 30px;
height: 30px;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
line-height: 1;
display: inline-flex;
align-items: center;
justify-content: center;
}
#ls-score .ls-btn:hover:not(:disabled) { border-color: #8aa; background: #f0f6ff; }
#ls-score .ls-btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* Loading state on the play button: while the sound library / MIDI player is still
loading, hide the ▶ glyph and spin a small ring in its place. Kept fully opaque
(overriding :disabled's dim) so the animation reads as "working", not just greyed.
The button stays disabled (cursor: wait) — clicking does nothing until ready. */
#ls-score .ls-btn.ls-loading {
opacity: 1;
cursor: wait;
color: transparent; /* hide the ▶ text glyph without reflow */
position: relative;
}
#ls-score .ls-btn.ls-loading::after {
content: '';
position: absolute;
width: 14px;
height: 14px;
border: 2px solid #c9c9d2;
border-top-color: #7c5cff; /* accent matches the progress fill */
border-radius: 50%;
animation: ls-spin 0.7s linear infinite;
}
@keyframes ls-spin {
to { transform: rotate(360deg); }
}
/* Respect reduced-motion: pulse the ring opacity instead of spinning. */
@media (prefers-reduced-motion: reduce) {
#ls-score .ls-btn.ls-loading::after {
animation: ls-sf-pulse 1.4s ease-in-out infinite;
}
}
#ls-score .ls-time {
font-family: ui-monospace, Consolas, monospace;
font-size: 12px;
color: #555;
min-width: 88px;
}
.ls-progress {
flex: 1;
height: 6px;
background: #ddd;
border-radius: 3px;
cursor: pointer;
overflow: hidden;
}
.ls-fill {
height: 100%;
width: 0;
background: #7c5cff;
transition: width 0.1s linear;
}
/* Sound-library status badge in the transport bar. While the GM soundfont loads:
dimmed + grayscaled + pulsing 🎹 (the small grand-piano fallback is audible).
Once ready: full-color 🎹 with a green ✓, shown 2s then faded out (hover reveals). */
#ls-score .ls-sf {
position: relative;
font-size: 14px;
line-height: 1;
margin-left: 2px;
flex: 0 0 auto;
cursor: default;
opacity: 0.45;
filter: grayscale(1);
animation: ls-sf-pulse 1.4s ease-in-out infinite;
}
#ls-score .ls-sf.ready {
opacity: 1;
filter: none;
animation: none;
}
@keyframes ls-sf-pulse {
0%, 100% { opacity: 0.30; }
50% { opacity: 0.65; }
}
/* green ✓ badge superscript on the ready piano */
#ls-score .ls-sf .ls-sf-check {
display: none;
position: absolute;
top: -0.4em;
right: -0.7em;
font-size: 0.85em;
font-weight: 700;
color: #3fb950;
text-shadow: 0 0 2px rgba(0, 0, 0, 0.4);
}
#ls-score .ls-sf.ready .ls-sf-check {
display: inline;
}