Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions asset/javascript/CountdownOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import './helper.js';

export const FINISHED_MESSAGE = 'ACABOU!';

export function CountdownOverlay(reference) {
const container = reference.querySelector('.js-countdown-container');
const number = container.querySelector('.js-countdown-number');
const closeButton = container.querySelector('.js-close-countdown-button');
const restartButton = container.querySelector('.js-restart-countdown-button');

let dismissed = false;
let onCloseCallback = null;
let onRestartCallback = null;

function init() {
closeButton.addEventListener('click', close);

if (restartButton) restartButton.addEventListener('click', restart);
}

function show(seconds) {
if (dismissed) return;

container.showElement();
number.classList.remove('is-message');
number.textContent = seconds;

container.classList.toggle('even');
container.classList.toggle('odd');

const isEven = seconds % 2 === 0;
container.classList.toggle('inverted', isEven);
reference.classList.toggle('inverted', isEven);
}

function showFinished() {
if (dismissed) return;

container.showElement();
container.classList.remove('even', 'odd', 'inverted');
reference.classList.remove('inverted');

number.classList.add('is-message');
number.textContent = FINISHED_MESSAGE;

if (restartButton) restartButton.showElement();
}

function restart() {
hide();

if (onRestartCallback) onRestartCallback();
}

function close() {
dismissed = true;
hide();

if (onCloseCallback) onCloseCallback();
}

function hide() {
reference.classList.remove('inverted');
container.classList.remove('inverted');
container.classList.remove('even', 'odd');
container.hideElement();

number.classList.remove('is-message');
number.textContent = '';

if (restartButton) restartButton.hideElement();
}

function reset() {
dismissed = false;
hide();
}

function isDismissed() {
return dismissed;
}

function onClose(callback) {
onCloseCallback = callback;
}

function onRestart(callback) {
onRestartCallback = callback;
}

init();

return { show, showFinished, hide, reset, close, isDismissed, onClose, onRestart };
}

export default CountdownOverlay;
79 changes: 79 additions & 0 deletions asset/javascript/SoundController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import tickTackSoundUrl from '../sound/tick-tack.wav';
import stopSoundUrl from '../sound/stop.mp3';

const FADE_DELAY = 3000;
const FADE_INTERVAL = 200;
const FADE_STEP = 0.05;

export function SoundController() {
const tickTackSound = new Audio(tickTackSoundUrl);
const stopSound = new Audio(stopSoundUrl);

let fadeIntervalId = null;
let fadeTimeoutId = null;

tickTackSound.addEventListener('error', e => {
console.error('Erro ao carregar tick-tack.wav:', e);
});

stopSound.addEventListener('error', e => {
console.error('Erro ao carregar stop.mp3:', e);
});

function safePlay(sound) {
const played = sound.play();

if (played && typeof played.catch === 'function') {
played.catch(() => {});
}
}

function playTick() {
tickTackSound.volume = 0.5;
tickTackSound.loop = false;
tickTackSound.currentTime = 0;
safePlay(tickTackSound);
}

function playStop() {
clearFade();

stopSound.volume = 0.5;
stopSound.loop = false;
stopSound.currentTime = 0;
safePlay(stopSound);

fadeTimeoutId = setTimeout(() => {
fadeIntervalId = setInterval(() => {
if (stopSound.volume > FADE_STEP) {
stopSound.volume -= FADE_STEP;
return;
}

stopAll();
}, FADE_INTERVAL);
}, FADE_DELAY);
}

function clearFade() {
clearTimeout(fadeTimeoutId);
clearInterval(fadeIntervalId);
fadeTimeoutId = null;
fadeIntervalId = null;
}

function stopAll() {
clearFade();

stopSound.pause();
stopSound.currentTime = 0;
stopSound.volume = 0;

tickTackSound.pause();
tickTackSound.currentTime = 0;
}

return { playTick, playStop, stopAll };
}

export default SoundController;
44 changes: 33 additions & 11 deletions asset/javascript/ThemeController.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
export const THEMES = {
DEFAULT: 'default',
VERSUS: 'versus',
};

export function ThemeController(reference) {
const body = reference;

Expand All @@ -7,6 +12,9 @@ export function ThemeController(reference) {
const defaultThemeButton = body.querySelector('.js-default-theme-button');
const versusThemeButton = body.querySelector('.js-versus-theme-button');

let currentTheme = THEMES.DEFAULT;
let onChangeCallback = null;

function init() {
if (!themeMenuButton || !themeDropdown || !defaultThemeButton || !versusThemeButton) {
return;
Expand All @@ -17,29 +25,43 @@ export function ThemeController(reference) {

function bindButtons() {
themeMenuButton.addEventListener('click', toggleThemeMenu);
defaultThemeButton.addEventListener('click', setDefaultTheme);
versusThemeButton.addEventListener('click', setVersusTheme);
defaultThemeButton.addEventListener('click', () => selectTheme(THEMES.DEFAULT));
versusThemeButton.addEventListener('click', () => selectTheme(THEMES.VERSUS));
}

function toggleThemeMenu() {
themeDropdown.classList.toggle('hide');
}

function setDefaultTheme() {
body.classList.remove('versus-theme');
body.classList.remove('inverted');
closeThemeMenu();
function selectTheme(theme) {
setTheme(theme);
closeMenu();

if (onChangeCallback) onChangeCallback(currentTheme);
}

function setVersusTheme() {
body.classList.add('versus-theme');
function setTheme(theme) {
currentTheme = theme === THEMES.VERSUS ? THEMES.VERSUS : THEMES.DEFAULT;

body.classList.toggle('versus-theme', currentTheme === THEMES.VERSUS);
body.classList.remove('inverted');
closeThemeMenu();
}

function closeThemeMenu() {
themeDropdown.classList.add('hide');
function closeMenu() {
if (themeDropdown) themeDropdown.classList.add('hide');
}

function getTheme() {
return currentTheme;
}

function onChange(callback) {
onChangeCallback = callback;
}

init();

return { setTheme, getTheme, closeMenu, onChange };
}

export default ThemeController;
Loading
Loading