mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-09 10:59:50 +00:00
Redesign media player more-info dialog (#26904)
* Redesign media player more-info dialog * Add missing imports * Add some more media player controls to gallery * Fix NaN * Fix first example source * Regroup * Remove * Add marquee text * Buttons * aria-label * Increase speed * Improve marquee text * Improve marquee text * Improve marquee text * Add touch events to marquee text * Use classMap * Remove chip styling * Make ha-marquee-text slotted and add to gallery * Format * Remove aria-label * Make turn on and off buttons have labels * Match more figma * Add integration logo and move grouping/inputs to top * Hm * Fix badge * Minor tweaks * Disable position slider when seek is not supported * Process code review * remove disabled color for slider * Process UX * Run prettier * Mark listener as passive * Improve bottom controls and styling * Remove unused function * Some minor improvements * Show remaining instead duration --------- Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
committed by
GitHub
parent
99d9c67492
commit
7be2c59295
178
src/components/ha-marquee-text.ts
Normal file
178
src/components/ha-marquee-text.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import {
|
||||
type TemplateResult,
|
||||
LitElement,
|
||||
html,
|
||||
css,
|
||||
type PropertyValues,
|
||||
} from "lit";
|
||||
import { customElement, eventOptions, property, query } from "lit/decorators";
|
||||
|
||||
@customElement("ha-marquee-text")
|
||||
export class HaMarqueeText extends LitElement {
|
||||
@property({ type: Number }) speed = 15; // pixels per second
|
||||
|
||||
@property({ type: Number, attribute: "pause-duration" }) pauseDuration = 1000; // ms delay at ends
|
||||
|
||||
@property({ type: Boolean, attribute: "pause-on-hover" })
|
||||
pauseOnHover = false;
|
||||
|
||||
private _direction: "left" | "right" = "left";
|
||||
|
||||
private _animationFrame?: number;
|
||||
|
||||
@query(".marquee-container")
|
||||
private _container?: HTMLDivElement;
|
||||
|
||||
@query(".marquee-text")
|
||||
private _textSpan?: HTMLSpanElement;
|
||||
|
||||
private _position = 0;
|
||||
|
||||
private _maxOffset = 0;
|
||||
|
||||
private _pauseTimeout?: number;
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
this._setupAnimation();
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (changedProps.has("text")) {
|
||||
this._setupAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
|
||||
if (this._animationFrame) {
|
||||
cancelAnimationFrame(this._animationFrame);
|
||||
}
|
||||
if (this._pauseTimeout) {
|
||||
clearTimeout(this._pauseTimeout);
|
||||
this._pauseTimeout = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div
|
||||
class="marquee-container"
|
||||
@mouseenter=${this._handleMouseEnter}
|
||||
@mouseleave=${this._handleMouseLeave}
|
||||
@touchstart=${this._handleMouseEnter}
|
||||
@touchend=${this._handleMouseLeave}
|
||||
>
|
||||
<span class="marquee-text"><slot></slot></span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _setupAnimation() {
|
||||
if (!this._container || !this._textSpan) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._position = 0;
|
||||
this._direction = "left";
|
||||
this._maxOffset = Math.max(
|
||||
0,
|
||||
this._textSpan.offsetWidth - this._container.offsetWidth
|
||||
);
|
||||
this._textSpan.style.transform = `translateX(0px)`;
|
||||
if (this._animationFrame) {
|
||||
cancelAnimationFrame(this._animationFrame);
|
||||
}
|
||||
if (this._pauseTimeout) {
|
||||
clearTimeout(this._pauseTimeout);
|
||||
this._pauseTimeout = undefined;
|
||||
}
|
||||
this._animate();
|
||||
}
|
||||
|
||||
private _animate = () => {
|
||||
if (!this._container || !this._textSpan) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dt = 1 / 60; // ~16ms per frame
|
||||
const pxPerFrame = this.speed * dt;
|
||||
let reachedEnd = false;
|
||||
if (this._direction === "left") {
|
||||
this._position -= pxPerFrame;
|
||||
if (this._position <= -this._maxOffset) {
|
||||
this._position = -this._maxOffset;
|
||||
this._direction = "right";
|
||||
reachedEnd = true;
|
||||
}
|
||||
} else {
|
||||
this._position += pxPerFrame;
|
||||
if (this._position >= 0) {
|
||||
this._position = 0;
|
||||
this._direction = "left";
|
||||
reachedEnd = true;
|
||||
}
|
||||
}
|
||||
this._textSpan.style.transform = `translateX(${this._position}px)`;
|
||||
if (reachedEnd) {
|
||||
this._pauseTimeout = window.setTimeout(() => {
|
||||
this._pauseTimeout = undefined;
|
||||
this._animationFrame = requestAnimationFrame(this._animate);
|
||||
}, this.pauseDuration);
|
||||
} else {
|
||||
this._animationFrame = requestAnimationFrame(this._animate);
|
||||
}
|
||||
};
|
||||
|
||||
@eventOptions({ passive: true })
|
||||
private _handleMouseEnter() {
|
||||
if (this.pauseOnHover && this._animationFrame) {
|
||||
cancelAnimationFrame(this._animationFrame);
|
||||
this._animationFrame = undefined;
|
||||
}
|
||||
if (this.pauseOnHover && this._pauseTimeout) {
|
||||
clearTimeout(this._pauseTimeout);
|
||||
this._pauseTimeout = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleMouseLeave() {
|
||||
if (this.pauseOnHover && !this._animationFrame && !this._pauseTimeout) {
|
||||
this._animate();
|
||||
}
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.marquee-container {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.marquee-text {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
will-change: transform;
|
||||
font-size: 1em;
|
||||
pointer-events: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-marquee-text": HaMarqueeText;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user