mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Add media controls seek bar tooltip
This commit is contained in:
77
ext/package-lock.json
generated
77
ext/package-lock.json
generated
@@ -6,7 +6,6 @@
|
|||||||
"": {
|
"": {
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/firefox-webext-browser": "^94.0.1",
|
"@types/firefox-webext-browser": "^94.0.1",
|
||||||
"@types/react-dom": "^18.0.2",
|
|
||||||
"@types/semver": "^7.3.9",
|
"@types/semver": "^7.3.9",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^8.3.4",
|
||||||
"esbuild": "^0.14.38",
|
"esbuild": "^0.14.38",
|
||||||
@@ -379,38 +378,12 @@
|
|||||||
"integrity": "sha512-z/FG/6DUO7pnze3AE3TBGIjGGKkvCcGcWINe1C7cADY8hKLJPDYpzsNE37uExQ4md5RFtTCvg+M8Mu1Enyeg2A==",
|
"integrity": "sha512-z/FG/6DUO7pnze3AE3TBGIjGGKkvCcGcWINe1C7cADY8hKLJPDYpzsNE37uExQ4md5RFtTCvg+M8Mu1Enyeg2A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/prop-types": {
|
|
||||||
"version": "15.7.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
|
||||||
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/pug": {
|
"node_modules/@types/pug": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz",
|
||||||
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/react": {
|
|
||||||
"version": "18.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.6.tgz",
|
|
||||||
"integrity": "sha512-bPqwzJRzKtfI0mVYr5R+1o9BOE8UEXefwc1LwcBtfnaAn6OoqMhLa/91VA8aeWfDPJt1kHvYKI8RHcQybZLHHA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/prop-types": "*",
|
|
||||||
"@types/scheduler": "*",
|
|
||||||
"csstype": "^3.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/react-dom": {
|
|
||||||
"version": "18.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.2.tgz",
|
|
||||||
"integrity": "sha512-UxeS+Wtj5bvLRREz9tIgsK4ntCuLDo0EcAcACgw3E+9wE8ePDr9uQpq53MfcyxyIS55xJ+0B6mDS8c4qkkHLBg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/react": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/sass": {
|
"node_modules/@types/sass": {
|
||||||
"version": "1.43.1",
|
"version": "1.43.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz",
|
||||||
@@ -420,12 +393,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/scheduler": {
|
|
||||||
"version": "0.16.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
|
||||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/semver": {
|
"node_modules/@types/semver": {
|
||||||
"version": "7.3.9",
|
"version": "7.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
|
||||||
@@ -1698,12 +1665,6 @@
|
|||||||
"url": "https://github.com/sponsors/fb55"
|
"url": "https://github.com/sponsors/fb55"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/csstype": {
|
|
||||||
"version": "3.0.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
|
|
||||||
"integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/dashdash": {
|
"node_modules/dashdash": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||||
@@ -8077,38 +8038,12 @@
|
|||||||
"integrity": "sha512-z/FG/6DUO7pnze3AE3TBGIjGGKkvCcGcWINe1C7cADY8hKLJPDYpzsNE37uExQ4md5RFtTCvg+M8Mu1Enyeg2A==",
|
"integrity": "sha512-z/FG/6DUO7pnze3AE3TBGIjGGKkvCcGcWINe1C7cADY8hKLJPDYpzsNE37uExQ4md5RFtTCvg+M8Mu1Enyeg2A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/prop-types": {
|
|
||||||
"version": "15.7.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
|
||||||
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@types/pug": {
|
"@types/pug": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.6.tgz",
|
||||||
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
"integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/react": {
|
|
||||||
"version": "18.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.6.tgz",
|
|
||||||
"integrity": "sha512-bPqwzJRzKtfI0mVYr5R+1o9BOE8UEXefwc1LwcBtfnaAn6OoqMhLa/91VA8aeWfDPJt1kHvYKI8RHcQybZLHHA==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/prop-types": "*",
|
|
||||||
"@types/scheduler": "*",
|
|
||||||
"csstype": "^3.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/react-dom": {
|
|
||||||
"version": "18.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.2.tgz",
|
|
||||||
"integrity": "sha512-UxeS+Wtj5bvLRREz9tIgsK4ntCuLDo0EcAcACgw3E+9wE8ePDr9uQpq53MfcyxyIS55xJ+0B6mDS8c4qkkHLBg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/react": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/sass": {
|
"@types/sass": {
|
||||||
"version": "1.43.1",
|
"version": "1.43.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz",
|
||||||
@@ -8118,12 +8053,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/scheduler": {
|
|
||||||
"version": "0.16.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
|
||||||
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@types/semver": {
|
"@types/semver": {
|
||||||
"version": "7.3.9",
|
"version": "7.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
|
||||||
@@ -9136,12 +9065,6 @@
|
|||||||
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
|
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"csstype": {
|
|
||||||
"version": "3.0.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
|
|
||||||
"integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"dashdash": {
|
"dashdash": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/firefox-webext-browser": "^94.0.1",
|
"@types/firefox-webext-browser": "^94.0.1",
|
||||||
"@types/react-dom": "^18.0.2",
|
|
||||||
"@types/semver": "^7.3.9",
|
"@types/semver": "^7.3.9",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^8.3.4",
|
||||||
"esbuild": "^0.14.38",
|
"esbuild": "^0.14.38",
|
||||||
|
|||||||
@@ -124,6 +124,31 @@
|
|||||||
ret += date.getUTCSeconds().toString().padStart(2, "0");
|
ret += date.getUTCSeconds().toString().padStart(2, "0");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let seekHoverPosition: Nullable<number> = null;
|
||||||
|
function onSeekMouseMove(node: HTMLInputElement) {
|
||||||
|
if (node.type !== "range") {
|
||||||
|
throw new Error("Wrong type of input!");
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseMove(ev: MouseEvent) {
|
||||||
|
const clientRect = node.getBoundingClientRect();
|
||||||
|
seekHoverPosition =
|
||||||
|
((ev.clientX - clientRect.left) / clientRect.width) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseLeave = () => (seekHoverPosition = null);
|
||||||
|
|
||||||
|
node.addEventListener("mousemove", onMouseMove);
|
||||||
|
node.addEventListener("mouseleave", onMouseLeave);
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
node.removeEventListener("mousemove", onMouseMove);
|
||||||
|
node.removeEventListener("mouseleave", onMouseLeave);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="media" style:--media-image="url({mediaImage?.url})">
|
<div class="media" style:--media-image="url({mediaImage?.url})">
|
||||||
@@ -160,13 +185,38 @@
|
|||||||
aria-label={_("popupMediaSeek")}
|
aria-label={_("popupMediaSeek")}
|
||||||
max={status.media.duration ?? currentTime}
|
max={status.media.duration ?? currentTime}
|
||||||
value={currentTime}
|
value={currentTime}
|
||||||
on:change={ev =>
|
on:change={ev => {
|
||||||
|
if (seekHoverPosition) {
|
||||||
|
ev.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
dispatch("seek", {
|
dispatch("seek", {
|
||||||
position: ev.currentTarget.valueAsNumber
|
position: ev.currentTarget.valueAsNumber
|
||||||
})}
|
});
|
||||||
|
}}
|
||||||
|
on:click={() => {
|
||||||
|
if (seekHoverPosition && status.media?.duration) {
|
||||||
|
dispatch("seek", {
|
||||||
|
position:
|
||||||
|
status.media.duration *
|
||||||
|
(seekHoverPosition / 100)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
use:onSeekMouseMove
|
||||||
/>
|
/>
|
||||||
|
{#if seekHoverPosition}
|
||||||
|
<div
|
||||||
|
class="media__seek-tooltip"
|
||||||
|
style:--seek-hover-position="{seekHoverPosition}%"
|
||||||
|
>
|
||||||
|
{formatTime(
|
||||||
|
status.media.duration * (seekHoverPosition / 100)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<span class="media__remaining-time">
|
<span class="media__remaining-time">
|
||||||
-{formatTime(status.media?.duration - currentTime)}
|
-{formatTime(status.media.duration - currentTime)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -193,20 +193,60 @@ body {
|
|||||||
|
|
||||||
.media__seek {
|
.media__seek {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
grid-template-areas: "current-time seek-bar remaining-time";
|
||||||
min-height: 24px;
|
min-height: 24px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.media__seek-bar {
|
.media__seek-bar {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
grid-area: seek-bar;
|
||||||
|
}
|
||||||
|
.media__seek-tooltip {
|
||||||
|
--tooltip-color: var(--button-background);
|
||||||
|
--tooltip-arrow-height: 5px;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--tooltip-color);
|
||||||
|
border-radius: 2px;
|
||||||
|
display: flex;
|
||||||
|
grid-area: seek-bar;
|
||||||
|
height: 20px;
|
||||||
|
justify-self: start;
|
||||||
|
left: var(--seek-hover-position);
|
||||||
|
padding: 0 5px;
|
||||||
|
pointer-events: none;
|
||||||
|
position: relative;
|
||||||
|
transform: translate(
|
||||||
|
-50%,
|
||||||
|
calc(
|
||||||
|
-60% - (var(--slider-track-height) / 2) - var(--tooltip-arrow-height)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.media__seek-tooltip::after {
|
||||||
|
border: var(--tooltip-arrow-height) solid transparent;
|
||||||
|
border-top-color: var(--tooltip-color);
|
||||||
|
bottom: 0;
|
||||||
|
content: "";
|
||||||
|
left: 50%;
|
||||||
|
position: absolute;
|
||||||
|
transform: translate(-50%, 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.media__current-time {
|
||||||
|
grid-area: current-time;
|
||||||
|
}
|
||||||
|
.media__remaining-time {
|
||||||
|
grid-area: remaining-time;
|
||||||
|
}
|
||||||
.media__current-time,
|
.media__current-time,
|
||||||
.media__remaining-time {
|
.media__remaining-time {
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
min-width: 5ch;
|
width: 5ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media__live {
|
.media__live {
|
||||||
@@ -291,13 +331,15 @@ body {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slider {
|
:root {
|
||||||
--slider-track-height: 5px;
|
--slider-track-height: 5px;
|
||||||
--slider-thumb-size: 13px;
|
--slider-thumb-size: 13px;
|
||||||
--slider-fill-color: #00b6f0;
|
--slider-fill-color: #00b6f0;
|
||||||
--slider-track-color: rgba(0, 0, 0, 0.7);
|
--slider-track-color: rgba(0, 0, 0, 0.7);
|
||||||
--slider-flare-color: rgba(255, 255, 255, 0.9);
|
--slider-flare-color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border: initial;
|
border: initial;
|
||||||
margin: initial;
|
margin: initial;
|
||||||
|
|||||||
Reference in New Issue
Block a user