chore(eslint): added new eslint rule (for jsx)

This commit is contained in:
JellyBrick
2025-09-06 04:51:31 +09:00
parent 4d83bd587d
commit 10384b6c4c
26 changed files with 177 additions and 166 deletions

View File

@ -31,6 +31,9 @@ export default tsEslint.config(
rules: {
'stylistic/arrow-parens': ['error', 'always'],
'stylistic/object-curly-spacing': ['error', 'always'],
'stylistic/jsx-pascal-case': 'error',
'stylistic/jsx-curly-spacing': ['error', { when: 'never', children: true }],
'stylistic/jsx-sort-props': 'error',
'prettier/prettier': ['error', { singleQuote: true, semi: true, tabWidth: 2, trailingComma: 'all', quoteProps: 'preserve' }],
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/no-misused-promises': ['off', { checksVoidReturn: false }],

View File

@ -81,26 +81,26 @@ export default createPlugin<
<>
<Show when={showUnDislike()}>
<UnDislikeButton
onClick={this.loadFullList}
maskSize={unDislikeMaskSize()}
onClick={this.loadFullList}
/>
</Show>
<Show when={showDislike()}>
<DislikeButton
onClick={this.loadFullList}
maskSize={dislikeMaskSize()}
onClick={this.loadFullList}
/>
</Show>
<Show when={showLike()}>
<LikeButton
onClick={this.loadFullList}
maskSize={likeMaskSize()}
onClick={this.loadFullList}
/>
</Show>
<Show when={showUnLike()}>
<UnLikeButton
onClick={this.loadFullList}
maskSize={unLikeMaskSize()}
onClick={this.loadFullList}
/>
</Show>
</>

View File

@ -6,22 +6,23 @@ export interface DislikeButtonProps {
export const DislikeButton = (props: DislikeButtonProps) => (
<div class="style-scope">
<button
id="alldislike"
data-type="dislike"
data-filled="false"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
aria-pressed="false"
aria-label="Dislike all"
aria-pressed="false"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
data-filled="false"
data-type="dislike"
id="alldislike"
onClick={(e) => props.onClick?.(e)}
>
<div
aria-hidden="true"
class="yt-spec-button-shape-next__icon"
style={{
'color': 'var(--ytmusic-setting-item-toggle-active)',
}}
aria-hidden="true"
>
<div
aria-hidden="true"
class="yt-spec-button-shape-next__icon"
style={{
'color': 'white',
@ -32,24 +33,23 @@ export const DislikeButton = (props: DislikeButtonProps) => (
'z-index': 1,
'position': 'absolute',
}}
aria-hidden="true"
>
<div style={{ 'width': '24px', 'height': '24px' }}>
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
class="style-scope yt-icon"
preserveAspectRatio="xMidYMid meet"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
viewBox="0 0 24 24"
>
<g class="style-scope yt-icon">
<path
d="M18,4h3v10h-3V4z M5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21c0.58,0,1.14-0.24,1.52-0.65L17,14V4H6.57 C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14z"
class="style-scope yt-icon"
d="M18,4h3v10h-3V4z M5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21c0.58,0,1.14-0.24,1.52-0.65L17,14V4H6.57 C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14z"
/>
</g>
</svg>
@ -62,20 +62,20 @@ export const DislikeButton = (props: DislikeButtonProps) => (
}}
>
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
class="style-scope yt-icon"
preserveAspectRatio="xMidYMid meet"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
viewBox="0 0 24 24"
>
<g class="style-scope yt-icon">
<path
d="M18,4h3v10h-3V4z M5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21c0.58,0,1.14-0.24,1.52-0.65L17,14V4H6.57 C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14z"
class="style-scope yt-icon"
d="M18,4h3v10h-3V4z M5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21c0.58,0,1.14-0.24,1.52-0.65L17,14V4H6.57 C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14z"
/>
</g>
</svg>
@ -87,8 +87,8 @@ export const DislikeButton = (props: DislikeButtonProps) => (
}}
>
<div
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
aria-hidden="true"
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
>
<div class="yt-spec-touch-feedback-shape__stroke" />
<div class="yt-spec-touch-feedback-shape__fill" />

View File

@ -6,22 +6,23 @@ export interface LikeButtonProps {
export const LikeButton = (props: LikeButtonProps) => (
<div class="style-scope">
<button
id="alllike"
data-type="like"
data-filled="false"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
aria-pressed="false"
aria-label="Like all"
aria-pressed="false"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
data-filled="false"
data-type="like"
id="alllike"
onClick={(e) => props.onClick?.(e)}
>
<div
aria-hidden="true"
class="yt-spec-button-shape-next__icon"
style={{
'color': 'var(--ytmusic-setting-item-toggle-active)',
}}
aria-hidden="true"
>
<div
aria-hidden="true"
class="yt-spec-button-shape-next__icon"
style={{
'color': 'white',
@ -32,24 +33,23 @@ export const LikeButton = (props: LikeButtonProps) => (
'z-index': 1,
'position': 'absolute',
}}
aria-hidden="true"
>
<div style={{ 'width': '24px', 'height': '24px' }}>
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
class="style-scope yt-icon"
preserveAspectRatio="xMidYMid meet"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
viewBox="0 0 24 24"
>
<g class="style-scope yt-icon">
<path
d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"
class="style-scope yt-icon"
d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"
/>
</g>
</svg>
@ -57,20 +57,20 @@ export const LikeButton = (props: LikeButtonProps) => (
</div>
<div style={{ 'width': '24px', 'height': '24px' }}>
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
class="style-scope yt-icon"
preserveAspectRatio="xMidYMid meet"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
viewBox="0 0 24 24"
>
<g class="style-scope yt-icon">
<path
d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"
class="style-scope yt-icon"
d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"
/>
</g>
</svg>
@ -78,8 +78,8 @@ export const LikeButton = (props: LikeButtonProps) => (
</div>
<yt-touch-feedback-shape style={{ 'border-radius': 'inherit' }}>
<div
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
aria-hidden="true"
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
>
<div class="yt-spec-touch-feedback-shape__stroke" />
<div class="yt-spec-touch-feedback-shape__fill" />

View File

@ -6,22 +6,23 @@ export interface UnDislikeButtonProps {
export const UnDislikeButton = (props: UnDislikeButtonProps) => (
<div class="style-scope">
<button
id="allundislike"
data-type="dislike"
data-filled="true"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
aria-pressed="false"
aria-label="Undislike all"
aria-pressed="false"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
data-filled="true"
data-type="dislike"
id="allundislike"
onClick={(e) => props.onClick?.(e)}
>
<div
aria-hidden="true"
class="yt-spec-button-shape-next__icon"
style={{
color: 'var(--ytmusic-setting-item-toggle-active)',
}}
aria-hidden="true"
>
<div
aria-hidden="true"
class="yt-spec-button-shape-next__icon"
style={{
'color': 'white',
@ -32,7 +33,6 @@ export const UnDislikeButton = (props: UnDislikeButtonProps) => (
'z-index': 1,
'position': 'absolute',
}}
aria-hidden="true"
>
<div
style={{
@ -41,20 +41,20 @@ export const UnDislikeButton = (props: UnDislikeButtonProps) => (
}}
>
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
class="style-scope yt-icon"
preserveAspectRatio="xMidYMid meet"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
viewBox="0 0 24 24"
>
<g class="style-scope yt-icon">
<path
d="M17,4h-1H6.57C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21 c0.58,0,1.14-0.24,1.52-0.65L17,14h4V4H17z M10.4,19.67C10.21,19.88,9.92,20,9.62,20c-0.26,0-0.5-0.11-0.63-0.3 c-0.07-0.1-0.15-0.26-0.09-0.47l1.52-4.94l0.4-1.29H9.46H5.23c-0.41,0-0.8-0.17-1.03-0.46c-0.12-0.15-0.25-0.4-0.18-0.72l1.34-6 C5.46,5.35,5.97,5,6.57,5H16v8.61L10.4,19.67z M20,13h-3V5h3V13z"
class="style-scope yt-icon"
d="M17,4h-1H6.57C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21 c0.58,0,1.14-0.24,1.52-0.65L17,14h4V4H17z M10.4,19.67C10.21,19.88,9.92,20,9.62,20c-0.26,0-0.5-0.11-0.63-0.3 c-0.07-0.1-0.15-0.26-0.09-0.47l1.52-4.94l0.4-1.29H9.46H5.23c-0.41,0-0.8-0.17-1.03-0.46c-0.12-0.15-0.25-0.4-0.18-0.72l1.34-6 C5.46,5.35,5.97,5,6.57,5H16v8.61L10.4,19.67z M20,13h-3V5h3V13z"
/>
</g>
</svg>
@ -67,20 +67,20 @@ export const UnDislikeButton = (props: UnDislikeButtonProps) => (
}}
>
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
class="style-scope yt-icon"
preserveAspectRatio="xMidYMid meet"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
viewBox="0 0 24 24"
>
<g class="style-scope yt-icon">
<path
d="M17,4h-1H6.57C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21 c0.58,0,1.14-0.24,1.52-0.65L17,14h4V4H17z M10.4,19.67C10.21,19.88,9.92,20,9.62,20c-0.26,0-0.5-0.11-0.63-0.3 c-0.07-0.1-0.15-0.26-0.09-0.47l1.52-4.94l0.4-1.29H9.46H5.23c-0.41,0-0.8-0.17-1.03-0.46c-0.12-0.15-0.25-0.4-0.18-0.72l1.34-6 C5.46,5.35,5.97,5,6.57,5H16v8.61L10.4,19.67z M20,13h-3V5h3V13z"
class="style-scope yt-icon"
d="M17,4h-1H6.57C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21 c0.58,0,1.14-0.24,1.52-0.65L17,14h4V4H17z M10.4,19.67C10.21,19.88,9.92,20,9.62,20c-0.26,0-0.5-0.11-0.63-0.3 c-0.07-0.1-0.15-0.26-0.09-0.47l1.52-4.94l0.4-1.29H9.46H5.23c-0.41,0-0.8-0.17-1.03-0.46c-0.12-0.15-0.25-0.4-0.18-0.72l1.34-6 C5.46,5.35,5.97,5,6.57,5H16v8.61L10.4,19.67z M20,13h-3V5h3V13z"
/>
</g>
</svg>
@ -92,8 +92,8 @@ export const UnDislikeButton = (props: UnDislikeButtonProps) => (
}}
>
<div
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
aria-hidden="true"
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
>
<div class="yt-spec-touch-feedback-shape__stroke" />
<div class="yt-spec-touch-feedback-shape__fill" />

View File

@ -6,22 +6,23 @@ export interface UnLikeButtonProps {
export const UnLikeButton = (props: UnLikeButtonProps) => (
<div class="style-scope">
<button
id="allunlike"
data-type="like"
data-filled="true"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
aria-pressed="false"
aria-label="Unlike all"
aria-pressed="false"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
data-filled="true"
data-type="like"
id="allunlike"
onClick={(e) => props.onClick?.(e)}
>
<div
aria-hidden="true"
class="yt-spec-button-shape-next__icon"
style={{
'color': 'var(--ytmusic-setting-item-toggle-active)',
}}
aria-hidden="true"
>
<div
aria-hidden="true"
class="yt-spec-button-shape-next__icon"
style={{
'color': 'white',
@ -32,7 +33,6 @@ export const UnLikeButton = (props: UnLikeButtonProps) => (
'z-index': 1,
'position': 'absolute',
}}
aria-hidden="true"
>
<div
style={{
@ -41,20 +41,20 @@ export const UnLikeButton = (props: UnLikeButtonProps) => (
}}
>
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
class="style-scope yt-icon"
preserveAspectRatio="xMidYMid meet"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
viewBox="0 0 24 24"
>
<g class="style-scope yt-icon">
<path
d="M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11H3v10h4h1h9.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z M7,20H4v-8h3V20z M19.98,13.17l-1.34,6 C18.54,19.65,18.03,20,17.43,20H8v-8.61l5.6-6.06C13.79,5.12,14.08,5,14.38,5c0.26,0,0.5,0.11,0.63,0.3 c0.07,0.1,0.15,0.26,0.09,0.47l-1.52,4.94L13.18,12h1.35h4.23c0.41,0,0.8,0.17,1.03,0.46C19.92,12.61,20.05,12.86,19.98,13.17z"
class="style-scope yt-icon"
d="M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11H3v10h4h1h9.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z M7,20H4v-8h3V20z M19.98,13.17l-1.34,6 C18.54,19.65,18.03,20,17.43,20H8v-8.61l5.6-6.06C13.79,5.12,14.08,5,14.38,5c0.26,0,0.5,0.11,0.63,0.3 c0.07,0.1,0.15,0.26,0.09,0.47l-1.52,4.94L13.18,12h1.35h4.23c0.41,0,0.8,0.17,1.03,0.46C19.92,12.61,20.05,12.86,19.98,13.17z"
/>
</g>
</svg>
@ -67,20 +67,20 @@ export const UnLikeButton = (props: UnLikeButtonProps) => (
}}
>
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
class="style-scope yt-icon"
preserveAspectRatio="xMidYMid meet"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
viewBox="0 0 24 24"
>
<g class="style-scope yt-icon">
<path
d="M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11H3v10h4h1h9.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z M7,20H4v-8h3V20z M19.98,13.17l-1.34,6 C18.54,19.65,18.03,20,17.43,20H8v-8.61l5.6-6.06C13.79,5.12,14.08,5,14.38,5c0.26,0,0.5,0.11,0.63,0.3 c0.07,0.1,0.15,0.26,0.09,0.47l-1.52,4.94L13.18,12h1.35h4.23c0.41,0,0.8,0.17,1.03,0.46C19.92,12.61,20.05,12.86,19.98,13.17z"
class="style-scope yt-icon"
d="M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11H3v10h4h1h9.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z M7,20H4v-8h3V20z M19.98,13.17l-1.34,6 C18.54,19.65,18.03,20,17.43,20H8v-8.61l5.6-6.06C13.79,5.12,14.08,5,14.38,5c0.26,0,0.5,0.11,0.63,0.3 c0.07,0.1,0.15,0.26,0.09,0.47l-1.52,4.94L13.18,12h1.35h4.23c0.41,0,0.8,0.17,1.03,0.46C19.92,12.61,20.05,12.86,19.98,13.17z"
/>
</g>
</svg>
@ -92,8 +92,8 @@ export const UnLikeButton = (props: UnLikeButtonProps) => (
}}
>
<div
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
aria-hidden="true"
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
>
<div class="yt-spec-touch-feedback-shape__stroke" />
<div class="yt-spec-touch-feedback-shape__fill" />

View File

@ -9,10 +9,10 @@ export const CaptionsSettingButton = (props: CaptionsSettingsButtonProps) => (
aria-label={props.label}
class="player-captions-button style-scope ytmusic-player-bar"
icon={'yt-icons:subtitles'}
on:click={(e) => props.onClick(e)}
role={'button'}
tabindex={0}
title={props.label}
on:click={(e) => props.onClick(e)}
>
<span class="yt-icon-shape style-scope yt-icon yt-spec-icon-shape">
<div

View File

@ -21,12 +21,18 @@ const updateDeviceList = async (
context.setConfig(options);
};
const updateSinkId = async (audioContext?: AudioContext, sinkId?: string) => {
const updateSinkId = async (
audioContext?: AudioContext & {
setSinkId?: (sinkId: string) => Promise<void>;
},
sinkId?: string,
) => {
if (!audioContext || !sinkId) return;
if (!('setSinkId' in audioContext)) return;
if (typeof audioContext.setSinkId !== 'function') return;
await audioContext.setSinkId(sinkId);
if (typeof audioContext.setSinkId === 'function') {
await audioContext.setSinkId(sinkId);
}
};
export const renderer = createRenderer<

View File

@ -5,8 +5,8 @@ export const DownloadButton = (props: {
<a
class="yt-simple-endpoint style-scope ytmusic-menu-navigation-item-renderer"
id="navigation-endpoint"
tabindex={-1}
onClick={props.onClick}
tabindex={-1}
>
<div class="icon ytmd-menu-item style-scope ytmusic-menu-navigation-item-renderer">
<svg

View File

@ -33,12 +33,12 @@ export const onRendererLoad = async ({
render(
() => (
<TitleBar
ipc={ipc}
isMacOS={isMacOS}
enableController={
isNotWindowsOrMacOS && !config().hideDOMWindowControls
}
initialCollapsed={window.mainConfig.get('options.hideMenu')}
ipc={ipc}
isMacOS={isMacOS}
/>
),
document.body,

View File

@ -149,17 +149,17 @@ export const Panel = (props: PanelProps) => {
<Portal>
<Transition
appear
enterClass={animationStyle().enter}
enterActiveClass={animationStyle().enterActive}
exitToClass={animationStyle().exitTo}
enterClass={animationStyle().enter}
exitActiveClass={animationStyle().exitActive}
exitToClass={animationStyle().exitTo}
>
<Show when={local.open}>
<ul
{...leftProps}
class={panelStyle()}
data-ytmd-sub-panel={true}
ref={setPanel}
class={panelStyle()}
style={{
'--offset-x': `${position.x}px`,
'--offset-y': `${position.y}px`,

View File

@ -290,80 +290,80 @@ export const PanelItem = (props: PanelItemProps) => {
return (
<li
ref={setAnchor}
class={itemStyle()}
onMouseEnter={handleHover}
onClick={handleClick}
data-selected={open()}
onClick={handleClick}
onMouseEnter={handleHover}
ref={setAnchor}
>
<Switch fallback={<div class={itemIconStyle()} />}>
<Match when={props.type === 'checkbox' && props.checked}>
<svg
class={itemIconStyle()}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M0 0h24v24H0z" fill="none" stroke="none" />
<path d="M5 12l5 5l10 -10" />
</svg>
</Match>
<Match when={props.type === 'radio' && props.checked}>
<svg
class={itemIconStyle()}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
style={{ padding: '6px' }}
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M10,5 C7.2,5 5,7.2 5,10 C5,12.8 7.2,15 10,15 C12.8,15 15,12.8 15,10 C15,7.2 12.8,5 10,5 L10,5 Z M10,0 C4.5,0 0,4.5 0,10 C0,15.5 4.5,20 10,20 C15.5,20 20,15.5 20,10 C20,4.5 15.5,0 10,0 L10,0 Z M10,18 C5.6,18 2,14.4 2,10 C2,5.6 5.6,2 10,2 C14.4,2 18,5.6 18,10 C18,14.4 14.4,18 10,18 L10,18 Z"
fill="currentColor"
/>
</svg>
</Match>
<Match when={props.type === 'radio' && !props.checked}>
<svg
class={itemIconStyle()}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
style={{ padding: '6px' }}
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M10,0 C4.5,0 0,4.5 0,10 C0,15.5 4.5,20 10,20 C15.5,20 20,15.5 20,10 C20,4.5 15.5,0 10,0 L10,0 Z M10,18 C5.6,18 2,14.4 2,10 C2,5.6 5.6,2 10,2 C14.4,2 18,5.6 18,10 C18,14.4 14.4,18 10,18 L10,18 Z"
fill="currentColor"
/>
</svg>
</Match>
</Switch>
<span class={itemLabelStyle()}>{props.name}</span>
<Show when={props.chip} fallback={<div />}>
<Show fallback={<div />} when={props.chip}>
<span class={itemChipStyle()}>{props.chip}</span>
</Show>
<Show when={props.type === 'submenu'}>
<svg
class={itemIconStyle()}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M0 0h24v24H0z" fill="none" stroke="none" />
<polyline points="9 6 15 12 9 18" />
</svg>
<Panel
ref={setChild}
open={open()}
anchor={anchor()}
placement={'right-start'}
data-level={props.type === 'submenu' && props.level.join('/')}
offset={{ mainAxis: 8 }}
open={open()}
placement={'right-start'}
ref={setChild}
>
{props.type === 'submenu' && props.children}
</Panel>
@ -371,8 +371,8 @@ export const PanelItem = (props: PanelItemProps) => {
<Show when={props.toolTip}>
<Portal>
<div
ref={setToolTip}
class={popupStyle()}
ref={setToolTip}
style={{
'--offset-x': `${position.x}px`,
'--offset-y': `${position.y}px`,
@ -380,10 +380,10 @@ export const PanelItem = (props: PanelItemProps) => {
>
<Transition
appear
enterClass={animationStyle().enter}
enterActiveClass={animationStyle().enterActive}
exitToClass={animationStyle().exitTo}
enterClass={animationStyle().enter}
exitActiveClass={animationStyle().exitActive}
exitToClass={animationStyle().exitTo}
>
<Show when={toolTipOpen()}>
<div class={toolTipStyle()}>{props.toolTip}</div>

View File

@ -120,22 +120,22 @@ const PanelRenderer = (props: PanelRendererProps) => {
<Switch>
<Match when={subItem().type === 'normal'}>
<PanelItem
type={'normal'}
name={subItem().label}
chip={subItem().sublabel}
toolTip={subItem().toolTip}
commandId={subItem().commandId}
name={subItem().label}
onClick={() => props.onClick?.(subItem().commandId)}
toolTip={subItem().toolTip}
type={'normal'}
/>
</Match>
<Match when={subItem().type === 'submenu'}>
<PanelItem
type={'submenu'}
name={subItem().label}
chip={subItem().sublabel}
toolTip={subItem().toolTip}
level={[...(props.level ?? []), subItem().commandId]}
commandId={subItem().commandId}
level={[...(props.level ?? []), subItem().commandId]}
name={subItem().label}
toolTip={subItem().toolTip}
type={'submenu'}
>
<PanelRenderer
items={subItem().submenu?.items ?? []}
@ -146,26 +146,26 @@ const PanelRenderer = (props: PanelRendererProps) => {
</Match>
<Match when={subItem().type === 'checkbox'}>
<PanelItem
type={'checkbox'}
name={subItem().label}
checked={subItem().checked}
chip={subItem().sublabel}
toolTip={subItem().toolTip}
commandId={subItem().commandId}
name={subItem().label}
onChange={() => props.onClick?.(subItem().commandId)}
toolTip={subItem().toolTip}
type={'checkbox'}
/>
</Match>
<Match when={subItem().type === 'radio'}>
<PanelItem
type={'radio'}
name={subItem().label}
checked={subItem().checked}
chip={subItem().sublabel}
toolTip={subItem().toolTip}
commandId={subItem().commandId}
name={subItem().label}
onChange={() =>
props.onClick?.(subItem().commandId, radioGroup())
}
toolTip={subItem().toolTip}
type={'radio'}
/>
</Match>
<Match when={subItem().type === 'separator'}>
@ -325,10 +325,10 @@ export const TitleBar = (props: TitleBarProps) => {
return (
<nav
data-ytmd-main-panel={true}
class={titleStyle()}
data-macos={props.isMacOS}
data-show={mouseY() < 32}
data-ytmd-main-panel={true}
>
<IconButton
onClick={() => setCollapsed(!collapsed())}
@ -336,7 +336,7 @@ export const TitleBar = (props: TitleBarProps) => {
'border-top-left-radius': '4px',
}}
>
<svg width={16} height={16} viewBox={'0 0 24 24'}>
<svg height={16} viewBox={'0 0 24 24'} width={16}>
<path
d="M3 17h12a1 1 0 0 1 .117 1.993L15 19H3a1 1 0 0 1-.117-1.993L3 17h12H3Zm0-6h18a1 1 0 0 1 .117 1.993L21 13H3a1 1 0 0 1-.117-1.993L3 11h18H3Zm0-6h15a1 1 0 0 1 .117 1.993L18 7H3a1 1 0 0 1-.117-1.993L3 5h15H3Z"
fill="currentColor"
@ -344,26 +344,29 @@ export const TitleBar = (props: TitleBarProps) => {
</svg>
</IconButton>
<TransitionGroup
enterClass={
ignoreTransition()
? animationStyle().fakeTarget
: animationStyle().enter
}
enterActiveClass={
ignoreTransition()
? animationStyle().fake
: animationStyle().enterActive
}
exitToClass={
enterClass={
ignoreTransition()
? animationStyle().fakeTarget
: animationStyle().exitTo
: animationStyle().enter
}
exitActiveClass={
ignoreTransition()
? animationStyle().fake
: animationStyle().exitActive
}
exitToClass={
ignoreTransition()
? animationStyle().fakeTarget
: animationStyle().exitTo
}
onAfterEnter={(element) => {
(element as HTMLElement).style.removeProperty('transition-delay');
}}
onBeforeEnter={(element) => {
if (ignoreTransition()) return;
const index = Number(element.getAttribute('data-index') ?? 0);
@ -373,9 +376,6 @@ export const TitleBar = (props: TitleBarProps) => {
`${index * 0.025}s`,
);
}}
onAfterEnter={(element) => {
(element as HTMLElement).style.removeProperty('transition-delay');
}}
onBeforeExit={(element) => {
if (ignoreTransition()) return;
const index = Number(element.getAttribute('data-index') ?? 0);
@ -405,18 +405,18 @@ export const TitleBar = (props: TitleBarProps) => {
return (
<>
<MenuButton
ref={setAnchor}
text={item().label}
onClick={handleClick}
selected={openTarget() === anchor()}
data-index={index}
data-length={data()?.items.length}
onClick={handleClick}
ref={setAnchor}
selected={openTarget() === anchor()}
text={item().label}
/>
<Panel
open={openTarget() === anchor()}
anchor={anchor()}
placement={'bottom-start'}
offset={{ mainAxis: 8 }}
open={openTarget() === anchor()}
placement={'bottom-start'}
>
<PanelRenderer
items={item().submenu?.items ?? []}
@ -433,9 +433,9 @@ export const TitleBar = (props: TitleBarProps) => {
<div style={{ flex: 1 }} />
<WindowController
isMaximize={isMaximized()}
onToggleMaximize={handleToggleMaximize}
onMinimize={handleMinimize}
onClose={handleClose}
onMinimize={handleMinimize}
onToggleMaximize={handleToggleMaximize}
/>
</Show>
</nav>

View File

@ -32,61 +32,61 @@ export const WindowController = (props: WindowControllerProps) => {
<div class={containerStyle()}>
<IconButton onClick={props.onMinimize}>
<svg
width={16}
height={16}
fill="none"
height={16}
viewBox="0 0 24 24"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M3.755 12.5h16.492a.75.75 0 0 0 0-1.5H3.755a.75.75 0 0 0 0 1.5Z"
fill="currentColor"
/>
</svg>
</IconButton>
<IconButton onClick={props.onToggleMaximize}>
<Show
when={props.isMaximize}
fallback={
<svg
width={16}
height={16}
fill="none"
height={16}
viewBox="0 0 24 24"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M6 3h12a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3Zm0 2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H6Z"
fill="currentColor"
/>
</svg>
}
when={props.isMaximize}
>
<svg
width={16}
height={16}
fill="none"
height={16}
viewBox="0 0 24 24"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M7.518 5H6.009a3.25 3.25 0 0 1 3.24-3h8.001A4.75 4.75 0 0 1 22 6.75v8a3.25 3.25 0 0 1-3 3.24v-1.508a1.75 1.75 0 0 0 1.5-1.732v-8a3.25 3.25 0 0 0-3.25-3.25h-8A1.75 1.75 0 0 0 7.518 5ZM5.25 6A3.25 3.25 0 0 0 2 9.25v9.5A3.25 3.25 0 0 0 5.25 22h9.5A3.25 3.25 0 0 0 18 18.75v-9.5A3.25 3.25 0 0 0 14.75 6h-9.5ZM3.5 9.25c0-.966.784-1.75 1.75-1.75h9.5c.967 0 1.75.784 1.75 1.75v9.5a1.75 1.75 0 0 1-1.75 1.75h-9.5a1.75 1.75 0 0 1-1.75-1.75v-9.5Z"
fill="currentColor"
/>
</svg>
</Show>
</IconButton>
<IconButton onClick={props.onClose}>
<svg
width={16}
height={16}
fill="none"
height={16}
viewBox="0 0 24 24"
width={16}
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="m4.21 4.387.083-.094a1 1 0 0 1 1.32-.083l.094.083L12 10.585l6.293-6.292a1 1 0 1 1 1.414 1.414L13.415 12l6.292 6.293a1 1 0 0 1 .083 1.32l-.083.094a1 1 0 0 1-1.32.083l-.094-.083L12 13.415l-6.293 6.292a1 1 0 0 1-1.414-1.414L10.585 12 4.293 5.707a1 1 0 0 1-.083-1.32l.083-.094-.083.094Z"
fill="currentColor"
/>
</svg>
</IconButton>

View File

@ -7,19 +7,19 @@ export const PictureInPictureButton = (props: PictureInPictureButtonProps) => (
<a
class="yt-simple-endpoint style-scope ytmusic-menu-navigation-item-renderer"
id="navigation-endpoint"
tabindex={-1}
onClick={(e) => props.onClick?.(e)}
tabindex={-1}
>
<div class="icon ytmd-menu-item style-scope ytmusic-menu-navigation-item-renderer">
<svg
class="style-scope yt-icon"
id="Layer_1"
style={{
'pointer-events': 'none',
'display': 'block',
'width': '100%',
'height': '100%',
}}
id="Layer_1"
viewBox="0 0 512 512"
x="0px"
xmlns="http://www.w3.org/2000/svg"
@ -28,10 +28,10 @@ export const PictureInPictureButton = (props: PictureInPictureButtonProps) => (
<g class="style-scope yt-icon" id="XMLID_6_">
<path
class="style-scope yt-icon"
fill="#aaaaaa"
d="M418.5,139.4H232.4v139.8h186.1V139.4z M464.8,46.7H46.3C20.5,46.7,0,68.1,0,93.1v325.9
c0,25.8,21.4,46.3,46.3,46.3h419.4c25.8,0,46.3-20.5,46.3-46.3V93.1C512,67.2,490.6,46.7,464.8,46.7z M464.8,418.9H46.3V92.2h419.4
v326.8H464.8z"
fill="#aaaaaa"
id="XMLID_11_"
/>
</g>

View File

@ -26,10 +26,10 @@ export const PlaybackSpeedSlider = (props: PlaybackSpeedSliderProps) => (
aria-valuenow={props.speed}
class="volume-slider style-scope ytmusic-player-bar on-hover"
dir="ltr"
on:immediate-value-changed={(e) => props.onImmediateValueChanged?.(e)}
onWheel={(e) => props.onWheel?.(e)}
max="2"
min="0"
on:immediate-value-changed={(e) => props.onImmediateValueChanged?.(e)}
onWheel={(e) => props.onWheel?.(e)}
role="slider"
step="0.125"
style={{ 'display': 'inherit !important' }}

View File

@ -43,8 +43,6 @@ export const onPlayerApiReady = () => {
render(
() => (
<PlaybackSpeedSlider
speed={speed()}
title={t('plugins.playback-speed.templates.button')}
onImmediateValueChanged={(e) => {
let targetSpeed = Number(e.detail.value ?? MIN_PLAYBACK_SPEED);
@ -78,6 +76,8 @@ export const onPlayerApiReady = () => {
updatePlayBackSpeed();
}}
speed={speed()}
title={t('plugins.playback-speed.templates.button')}
/>
),
sliderContainer,

View File

@ -9,10 +9,10 @@ export const QualitySettingButton = (props: QualitySettingButtonProps) => (
aria-label={props.label}
class="player-quality-button style-scope ytmusic-player"
icon={'yt-icons:settings'}
on:click={(e) => props.onClick(e)}
role={'button'}
tabindex={0}
title={props.label}
on:click={(e) => props.onClick(e)}
>
<span class="yt-icon-shape style-scope yt-icon yt-spec-icon-shape">
<div

View File

@ -45,7 +45,6 @@ export const ErrorDisplay = (props: ErrorDisplayProps) => {
</pre>
<yt-button-renderer
onClick={() => retrySearch(lyricsStore.provider, getSongInfo())}
data={{
icon: { iconType: 'REFRESH' },
isDisabled: false,
@ -54,6 +53,7 @@ export const ErrorDisplay = (props: ErrorDisplayProps) => {
simpleText: t('plugins.synced-lyrics.refetch-btn.normal')
},
}}
onClick={() => retrySearch(lyricsStore.provider, getSongInfo())}
style={{
'margin-top': '1em',
'width': '100%'

View File

@ -132,11 +132,11 @@ export const LyricsPicker = (props: {
>
<svg
class="style-scope yt-icon"
fill="#FFFFFF"
height={'40px'}
preserveAspectRatio="xMidYMid meet"
viewBox="0 -960 960 960"
height={'40px'}
width={'40px'}
fill="#FFFFFF"
>
<g class="style-scope yt-icon">
<path
@ -156,10 +156,10 @@ export const LyricsPicker = (props: {
{(provider) => (
<div
class="lyrics-picker-item"
tabindex="-1"
style={{
transform: `translateX(${providerIdx() * -100 - 5}%)`,
}}
tabindex="-1"
>
<Switch>
<Match
@ -170,16 +170,16 @@ export const LyricsPicker = (props: {
>
<tp-yt-paper-spinner-lite
active
tabindex="-1"
class="loading-indicator style-scope"
style={{ padding: '5px', transform: 'scale(0.5)' }}
tabindex="-1"
/>
</Match>
<Match when={currentLyrics().state === 'error'}>
<yt-icon-button
icon={errorIcon}
tabindex="-1"
style={{ padding: '5px', transform: 'scale(0.5)' }}
tabindex="-1"
/>
</Match>
<Match
@ -191,8 +191,8 @@ export const LyricsPicker = (props: {
>
<yt-icon-button
icon={successIcon}
tabindex="-1"
style={{ padding: '5px', transform: 'scale(0.5)' }}
tabindex="-1"
/>
</Match>
<Match
@ -204,8 +204,8 @@ export const LyricsPicker = (props: {
>
<yt-icon-button
icon={notFoundIcon}
tabindex="-1"
style={{ padding: '5px', transform: 'scale(0.5)' }}
tabindex="-1"
/>
</Match>
</Switch>
@ -252,11 +252,11 @@ export const LyricsPicker = (props: {
>
<svg
class="style-scope yt-icon"
fill="#FFFFFF"
height={'40px'}
preserveAspectRatio="xMidYMid meet"
viewBox="0 -960 960 960"
height={'40px'}
width={'40px'}
fill="#FFFFFF"
>
<g class="style-scope yt-icon">
<path

View File

@ -39,7 +39,6 @@ export const SyncedLine = (props: SyncedLineProps) => {
return (
<Show
when={text()}
fallback={
<yt-formatted-string
text={{
@ -47,6 +46,7 @@ export const SyncedLine = (props: SyncedLineProps) => {
}}
/>
}
when={text()}
>
<div
class={`synced-line ${props.status}`}
@ -54,7 +54,7 @@ export const SyncedLine = (props: SyncedLineProps) => {
_ytAPI?.seekTo((props.line.timeInMs + 10) / 1000);
}}
>
<div dir="auto" class="description ytmusic-description-shelf-renderer">
<div class="description ytmusic-description-shelf-renderer" dir="auto">
<yt-formatted-string
text={{
runs: [

View File

@ -301,8 +301,8 @@ export const LyricsRenderer = () => {
return (
<SyncedLine
{...props}
scroller={scroller()!}
index={idx()}
scroller={scroller()!}
status={statuses()[idx() - 1]}
/>
);

View File

@ -177,12 +177,12 @@ export default createPlugin({
() => (
<Show when={showButton()}>
<VideoSwitchButton
onClick={(e) => e.stopPropagation()}
onChange={(e) => {
const target = e.target as HTMLInputElement;
setVideoState(target.checked);
}}
onClick={(e) => e.stopPropagation()}
songButtonText={t('plugins.video-toggle.templates.button-song')}
videoButtonText={t('plugins.video-toggle.templates.button-video')}
/>

View File

@ -14,8 +14,8 @@ export const VideoSwitchButton = (props: VideoSwitchButtonProps) => (
>
<input
checked={true}
id="video-toggle-video-switch-button-checkbox"
class="video-switch-button-checkbox"
id="video-toggle-video-switch-button-checkbox"
type="checkbox"
/>
<label

View File

@ -1,5 +1,6 @@
// This is used for to control the songs
import { type BrowserWindow, ipcMain } from 'electron';
import { LikeType } from '@/types/datahost-get-state';
// see protocol-handler.ts

View File

@ -1,7 +1,8 @@
import { singleton } from './decorators';
import type { YoutubePlayer } from '@/types/youtube-player';
import { LikeType, type GetState } from '@/types/datahost-get-state';
import type { YoutubePlayer } from '@/types/youtube-player';
import type {
AlbumDetails,
PlayerOverlays,