feat: add prettier and eslint with pre-commit hook

This commit is contained in:
2026-05-10 19:23:53 +02:00
parent be9fbe0f64
commit 3703bbfcfe
33 changed files with 1643 additions and 1245 deletions

View File

@@ -1,95 +1,98 @@
import { state } from './state'
import { state } from './state';
export const formatTime = (seconds: number): string => {
if (!Number.isFinite(seconds) || seconds < 0) return '00:00'
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}
if (!Number.isFinite(seconds) || seconds < 0) return '00:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
};
export const showControls = (): void => {
state.container.classList.add('show-controls')
window.clearTimeout(state.playerControlsTimeout)
state.container.classList.add('show-controls');
window.clearTimeout(state.playerControlsTimeout);
state.playerControlsTimeout = window.setTimeout(() => {
if (!state.isScrubbing && !state.video.paused) {
state.container.classList.remove('show-controls')
state.container.classList.remove('show-controls');
}
}, 2000)
}
}, 2000);
};
export const seekBy = (delta: number): void => {
if (state.video.duration <= 0) return
state.video.currentTime = Math.max(0, Math.min(state.video.duration, state.video.currentTime + delta))
showControls()
}
if (state.video.duration <= 0) return;
state.video.currentTime = Math.max(
0,
Math.min(state.video.duration, state.video.currentTime + delta)
);
showControls();
};
export const togglePlayPause = (): void => {
if (state.video.paused) {
state.video.play()
state.video.play();
} else {
state.video.pause()
state.video.pause();
}
}
};
export const toggleMute = (): void => {
if (state.video.muted || state.video.volume === 0) {
const restored = state.lastKnownVolume > 0 ? state.lastKnownVolume : 1
state.video.muted = false
state.video.volume = restored
const restored = state.lastKnownVolume > 0 ? state.lastKnownVolume : 1;
state.video.muted = false;
state.video.volume = restored;
} else {
state.lastKnownVolume = state.video.volume > 0 ? state.video.volume : state.lastKnownVolume
state.video.muted = true
state.lastKnownVolume = state.video.volume > 0 ? state.video.volume : state.lastKnownVolume;
state.video.muted = true;
}
}
};
export const setVolume = (value: number): void => {
state.video.volume = Math.max(0, Math.min(1, value))
state.video.muted = value === 0
if (value > 0) state.lastKnownVolume = value
}
state.video.volume = Math.max(0, Math.min(1, value));
state.video.muted = value === 0;
if (value > 0) state.lastKnownVolume = value;
};
export const toggleFullscreen = (): void => {
if (document.fullscreenElement) {
document.exitFullscreen()
return
document.exitFullscreen();
return;
}
state.container.requestFullscreen?.()
}
state.container.requestFullscreen?.();
};
export const syncVolumeUI = (): void => {
const { volumeRange, volumeUnderline, iconVolume, iconMuted } = getControls()
const value = state.video.muted ? 0 : Math.round(state.video.volume * 100)
const { volumeRange, volumeUnderline, iconVolume, iconMuted } = getControls();
const value = state.video.muted ? 0 : Math.round(state.video.volume * 100);
if (volumeRange) {
volumeRange.value = String(value)
volumeRange.style.setProperty('--volume-percent', `${value}%`)
volumeRange.value = String(value);
volumeRange.style.setProperty('--volume-percent', `${value}%`);
}
if (volumeUnderline) volumeUnderline.style.height = `${value}%`
updateMuteIcons(state.video.muted || state.video.volume === 0)
}
if (volumeUnderline) volumeUnderline.style.height = `${value}%`;
updateMuteIcons(state.video.muted || state.video.volume === 0);
};
interface Controls {
playPause: HTMLButtonElement | null
muteBtn: HTMLButtonElement | null
volumePanel: HTMLElement | null
volumeRange: HTMLInputElement | null
volumeUnderline: HTMLElement | null
backwardBtn: HTMLButtonElement | null
forwardBtn: HTMLButtonElement | null
fullscreenBtn: HTMLButtonElement | null
iconPlay: SVGElement | null
iconPause: SVGElement | null
iconVolume: SVGElement | null
iconMuted: SVGElement | null
skipSegmentBtn: HTMLButtonElement | null
subtitleText: HTMLElement | null
autoplayBtn: HTMLInputElement | null
playPause: HTMLButtonElement | null;
muteBtn: HTMLButtonElement | null;
volumePanel: HTMLElement | null;
volumeRange: HTMLInputElement | null;
volumeUnderline: HTMLElement | null;
backwardBtn: HTMLButtonElement | null;
forwardBtn: HTMLButtonElement | null;
fullscreenBtn: HTMLButtonElement | null;
iconPlay: SVGElement | null;
iconPause: SVGElement | null;
iconVolume: SVGElement | null;
iconMuted: SVGElement | null;
skipSegmentBtn: HTMLButtonElement | null;
subtitleText: HTMLElement | null;
autoplayBtn: HTMLInputElement | null;
}
let controlsCache: Controls | null = null
let controlsCache: Controls | null = null;
const getControls = (): Controls => {
if (controlsCache) return controlsCache
const c = state.container
if (controlsCache) return controlsCache;
const c = state.container;
controlsCache = {
playPause: c.querySelector('[data-play-pause]'),
muteBtn: c.querySelector('[data-mute]'),
@@ -106,64 +109,88 @@ const getControls = (): Controls => {
skipSegmentBtn: c.querySelector('[data-skip]'),
subtitleText: c.querySelector('[data-subtitle-text]'),
autoplayBtn: document.querySelector('[data-autoplay]'),
}
return controlsCache
}
};
return controlsCache;
};
const updatePlayPauseIcons = (isPlaying: boolean): void => {
const { iconPlay, iconPause } = getControls()
iconPlay?.classList.toggle('hidden', isPlaying)
iconPause?.classList.toggle('hidden', !isPlaying)
}
const { iconPlay, iconPause } = getControls();
iconPlay?.classList.toggle('hidden', isPlaying);
iconPause?.classList.toggle('hidden', !isPlaying);
};
const updateMuteIcons = (isMuted: boolean): void => {
const { iconVolume, iconMuted } = getControls()
iconVolume?.classList.toggle('hidden', isMuted)
iconMuted?.classList.toggle('hidden', !isMuted)
}
const { iconVolume, iconMuted } = getControls();
iconVolume?.classList.toggle('hidden', isMuted);
iconMuted?.classList.toggle('hidden', !isMuted);
};
export const setupControls = (): void => {
const {
playPause, muteBtn, volumePanel, volumeRange,
backwardBtn, forwardBtn, fullscreenBtn, skipSegmentBtn,
} = getControls()
playPause,
muteBtn,
volumePanel,
volumeRange,
backwardBtn,
forwardBtn,
fullscreenBtn,
skipSegmentBtn,
} = getControls();
playPause?.addEventListener('click', () => { togglePlayPause(); showControls() })
state.video.addEventListener('click', () => { togglePlayPause(); showControls() })
playPause?.addEventListener('click', () => {
togglePlayPause();
showControls();
});
state.video.addEventListener('click', () => {
togglePlayPause();
showControls();
});
muteBtn?.addEventListener('click', () => { toggleMute(); showControls() })
muteBtn?.addEventListener('click', () => {
toggleMute();
showControls();
});
volumeRange?.addEventListener('input', () => {
const value = Number(volumeRange.value) / 100
setVolume(value)
showControls()
})
volumeRange?.addEventListener('pointerdown', () => volumePanel?.classList.add('is-dragging'))
window.addEventListener('pointerup', () => volumePanel?.classList.remove('is-dragging'))
const value = Number(volumeRange.value) / 100;
setVolume(value);
showControls();
});
volumeRange?.addEventListener('pointerdown', () => volumePanel?.classList.add('is-dragging'));
window.addEventListener('pointerup', () => volumePanel?.classList.remove('is-dragging'));
backwardBtn?.addEventListener('click', () => seekBy(-10))
forwardBtn?.addEventListener('click', () => seekBy(10))
backwardBtn?.addEventListener('click', () => seekBy(-10));
forwardBtn?.addEventListener('click', () => seekBy(10));
fullscreenBtn?.addEventListener('click', () => { toggleFullscreen(); showControls() })
fullscreenBtn?.addEventListener('click', () => {
toggleFullscreen();
showControls();
});
skipSegmentBtn?.addEventListener('click', () => {
if (!state.activeSkipSegment) return
state.video.currentTime = state.activeSkipSegment.end + 0.01
showControls()
})
if (!state.activeSkipSegment) return;
state.video.currentTime = state.activeSkipSegment.end + 0.01;
showControls();
});
document.addEventListener('fullscreenchange', () => {
state.isFullscreen = !!document.fullscreenElement
state.container.classList.toggle('fullscreen', state.isFullscreen)
if (state.isFullscreen) showControls()
})
state.isFullscreen = !!document.fullscreenElement;
state.container.classList.toggle('fullscreen', state.isFullscreen);
if (state.isFullscreen) showControls();
});
state.video.addEventListener('play', () => { updatePlayPauseIcons(true); showControls() })
state.video.addEventListener('pause', () => { updatePlayPauseIcons(false); showControls() })
state.video.addEventListener('volumechange', syncVolumeUI)
state.video.addEventListener('play', () => {
updatePlayPauseIcons(true);
showControls();
});
state.video.addEventListener('pause', () => {
updatePlayPauseIcons(false);
showControls();
});
state.video.addEventListener('volumechange', syncVolumeUI);
state.container.addEventListener('mousemove', showControls)
state.container.addEventListener('mousemove', showControls);
updatePlayPauseIcons(false)
syncVolumeUI()
}
updatePlayPauseIcons(false);
syncVolumeUI();
};