Skip to content

No Hiding button ? #7

Description

@Medamine-Bahassou

my version :

translation

// Define language translations
const trans = {
    'cn': {
        working: '工作中',
        resting: '休息中',
        doWork: '干活',
        takeBreak: '休息',
        start: '开始',
        pause: '暂停',
        reset: '重置',
        restNotificationTitle: '放松自己',
        restNotificationBody: '该休息咯~',
        workNotificationTitle: '休息好了吗?',
        workNotificationBody: "干点活吧",
        takeBreakMessage: '休息一会儿.',
        timeToDoSomething: '该做点什么了.'
    },
    'en': {
        working: 'Working',
        resting: 'Resting',
        doWork: 'Do Work',
        takeBreak: 'Take Break',
        start: 'Start',
        pause: 'Pause',
        reset: 'Reset',
        restNotificationTitle: 'Relax yourself',
        restNotificationBody: 'Time to take a break~',
        workNotificationTitle: 'Rest well?',
        workNotificationBody: "Let's do some work",
        takeBreakMessage: 'Take a break.',
        timeToDoSomething: 'Time to do something.',
        // Add these new keys:
        hide: 'Hide',
    	show: 'Show',
        // Add these new keys:
        hideWidget: 'Hide Widget',
	    showWidget: 'Show Widget'


    },
    'pt-br': {
        working: 'Trabalhando',
        resting: 'Descansando',
        doWork: 'Trabalhar',
        takeBreak: 'Descansar',
        start: 'Começar',
        pause: 'Pausar',
        reset: 'Resetar',
        restNotificationTitle: 'Pausa',
        restNotificationBody: 'Hora de descansar um pouco',
        workNotificationTitle: 'Descansado?',
        workNotificationBody: "Mãos à massa! De volta ao trabalho.",
        takeBreakMessage: 'Faça uma pausa',
        timeToDoSomething: 'De volta a ativa'
    },
};

module.exports = {
    trans
}

tomato

/*
 * Pomodoro timer for Trilium Notes.
 * A gift designed for me, who suffers from lumbar disc herniation, reminding me to take a break every half an hour.
 *
 * 1. You can tweak configs in the `config` subnote.
 * 2. i18n support, check the `translations` subnote for the translated texts.
 * 3. There will be a notification tells you to rest :)
 * 4. Buttons comes with sound effects so does the notification alarm.
 * 5. Includes a small circular button on the right with a clock icon to hide/show the widget bar.
 */

const i18n = key => translations.trans[config.lang][key];

const initialWidgetHiddenState = localStorage.getItem('tomatoWidgetHidden') === 'true';

// Define icons
const SHOW_ICON_HTML = '<i class="bx bx-time"></i>'; // Clock icon for 'hide'
const HIDE_ICON_HTML = '<i class="bx bx-chevron-right"></i>'; // Chevron for 'show'

const TPL = `
<audio id="tomatoButtonSound" src="custom/sound/tomatoButton.mp3"></audio>
<audio id="tomatoAlarmSound" src="custom/sound/tomatoAlarm.mp3"></audio>

<div id="tomato-bar" class="tomato ${initialWidgetHiddenState ? 'widget-hidden' : ''}">
    <center class="widget-content"><div id="status">${i18n('working')}</div></center>
    <center class="widget-content"><div id="timer">--:--</div></center>
    <button id="workButton" class="widget-content">${i18n('doWork')}</button>
    <button id="restButton" class="widget-content">${i18n('takeBreak')}</button>
    <button id="startButton" class="widget-content">${i18n('start')}</button>
    <button id="pauseButton" class="widget-content">${i18n('pause')}</button>
    <button id="resetButton" class="widget-content">${i18n('reset')}</button>

    <button id="toggleWidgetButton" title="${initialWidgetHiddenState ? i18n('showWidget') : i18n('hideWidget')}">
        ${initialWidgetHiddenState ? SHOW_ICON_HTML : HIDE_ICON_HTML}
    </button>
</div>
`;

const styles = `
#tomato-bar {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 4px;
    border-top: 1px solid var(--main-border-color, #555);
    border-bottom: 1px solid var(--main-border-color, #555);
    contain: none;
    white-space: nowrap;
    overflow: hidden;
    transition: padding 0.3s ease, border 0.3s ease, min-height 0.3s ease;
    position: relative;
    min-height: 30px; /* Adjusted for typical button heights */
    background-color: var(--main-background-color, #ffffff);
    color: var(--main-text-color, #000000);
}

#tomato-bar.widget-hidden {
    padding: 2px;
    border-top: 1px solid transparent;
    border-bottom: 1px solid transparent;
    background-color: transparent;
    gap: 0;
    justify-content: flex-end;
}

#tomato-bar.widget-hidden > .widget-content {
    display: none;
}

/* Toggle Button specific styles */
#toggleWidgetButton {
    order: 99;
    margin-left: auto;
    width: 28px; /* Slightly larger for icon */
    height: 28px;
    border-radius: 50%;
    padding: 0;
    font-size: 16px; /* Icon size */
    flex-shrink: 0;
    background-color: var(--button-secondary-background-color, #cccccc);
    border: 1px solid var(--button-secondary-border-color, #bbbbbb);
    color: var(--button-secondary-text-color, #333333);
    cursor: pointer;
    transition: background-color 0.3s, border-color 0.3s;
    display: inline-flex; /* Use flex to center icon */
    align-items: center;
    justify-content: center;
}

#toggleWidgetButton:hover {
    background-color: var(--button-secondary-hover-background-color, #bbbbbb);
    border-color: var(--button-secondary-hover-border-color, #aaaaaa);
}

#tomato-bar.widget-hidden > #toggleWidgetButton {
    display: inline-flex; /* Keep display consistent */
    margin-left: 0;
}

/* Other elements */
#status {
    font-size: 1em; /* Use relative units */
    width: auto;
    min-width: 60px;
    text-align: center;
    padding: 0 10px;
    font-weight: bold;
    color: var(--main-text-color, #000000);
}

#timer {
    font-size: 1.4em; /* Use relative units */
    width: 70px;
    border: 2px solid var(--accent-color, #FF6347);
    background-color: transparent;
    border-radius: var(--button-border-radius, 5px);
    text-align: center;
    display: block;
    padding: 2px 0;
    color: var(--main-text-color, #000000);
}

/* General Button styles (excluding toggle) */
.tomato button:not(#toggleWidgetButton) {
    border-radius: var(--button-border-radius, 5px);
    border: 1px solid var(--button-border-color, #adadad);
    padding: 6px 12px; /* Standard padding */
    font-size: 0.9em; /* Relative size */
    cursor: pointer;
    transition: background-color 0.2s, border-color 0.2s, color 0.2s;
    color: var(--button-text-color, #ffffff);
    background-color: var(--button-background-color, #777777); /* Default grey */
}

.tomato button:not(#toggleWidgetButton):hover {
    background-color: var(--button-hover-background-color, #666666);
    border-color: var(--button-hover-border-color, #999999);
}

/* Specific Button Colors (using more standard roles) */
#workButton, #startButton {
    background-color: var(--button-primary-background-color, #007bff); /* Blue */
    border-color: var(--button-primary-border-color, #0069d9);
    color: var(--button-primary-text-color, #ffffff);
}
#workButton:hover, #startButton:hover {
    background-color: var(--button-primary-hover-background-color, #0056b3);
    border-color: var(--button-primary-hover-border-color, #004085);
}

#restButton {
    background-color: var(--button-success-background-color, #28a745); /* Green */
    border-color: var(--button-success-border-color, #218838);
     color: var(--button-success-text-color, #ffffff);
}
#restButton:hover {
    background-color: var(--button-success-hover-background-color, #1e7e34);
    border-color: var(--button-success-hover-border-color, #1c7430);
}

#pauseButton {
    background-color: var(--button-warning-background-color, #ffc107); /* Yellow/Orange */
    border-color: var(--button-warning-border-color, #e0a800);
    color: var(--button-warning-text-color, #212529); /* Dark text for light bg */
}
#pauseButton:hover {
    background-color: var(--button-warning-hover-background-color, #d39e00);
    border-color: var(--button-warning-hover-border-color, #c69500);
}

#resetButton {
    background-color: var(--button-danger-background-color, #dc3545); /* Red */
    border-color: var(--button-danger-border-color, #c82333);
    color: var(--button-danger-text-color, #ffffff);
}
#resetButton:hover {
    background-color: var(--button-danger-hover-background-color, #bd2130);
    border-color: var(--button-danger-hover-border-color, #b21f2d);
}


#tomato-bar > center {
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Ensure BoxIcons/FontAwesome load if not already available globally */
/* @import url("https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css"); */
`;

var isInit = true;
var timerInterval;

class TomatoWidget extends api.NoteContextAwareWidget {
    get position() { return 200; }
    get parentWidget() { return "center-pane"; }

    constructor() {
        super();
        this.title = "";
        this.isWidgetHidden = localStorage.getItem('tomatoWidgetHidden') === 'true';
    }

    isEnabled() {
        if (!super.isEnabled()) return false;
        const widgetDisable = api.startNote && api.startNote.hasLabel("disable");
        return !widgetDisable;
    }

    doRender() {
        this.$widget = $(TPL);
        this.statusDisplayJQ = this.$widget.find("#status");

        const tomatoStatus = localStorage.getItem('tomatoStatus');
        if (tomatoStatus) {
            this.statusDisplayJQ.text(i18n(tomatoStatus));
        } else {
             this.statusDisplayJQ.text(i18n('working'));
        }

        this.cssBlock(styles);
        return this.$widget;
    }

    async refreshWithNote() {
         const tomatoBar = document.getElementById('tomato-bar');
         const toggleWidgetButton = document.getElementById('toggleWidgetButton');

         if (!isInit && tomatoBar && toggleWidgetButton) {
             this.isWidgetHidden = localStorage.getItem('tomatoWidgetHidden') === 'true';
             if (this.isWidgetHidden) {
                 tomatoBar.classList.add('widget-hidden');
                 toggleWidgetButton.innerHTML = SHOW_ICON_HTML;
                 toggleWidgetButton.setAttribute('title', i18n('showWidget'));
             } else {
                 tomatoBar.classList.remove('widget-hidden');
                 toggleWidgetButton.innerHTML = HIDE_ICON_HTML;
                 toggleWidgetButton.setAttribute('title', i18n('hideWidget'));
             }
         }

        if (!isInit) {
            return;
        }
        isInit = false;

        const timerDisplay = document.getElementById('timer');
        const statusDisplay = document.getElementById('status');
        const startButton = document.getElementById('startButton');
        const pauseButton = document.getElementById('pauseButton');
        const resetButton = document.getElementById('resetButton');
        const workButton = document.getElementById('workButton');
        const restButton = document.getElementById('restButton');
        const tomatoButtonSound = document.getElementById("tomatoButtonSound");
        const tomatoAlarmSound = document.getElementById("tomatoAlarmSound");

        if (!tomatoBar || !toggleWidgetButton || !timerDisplay || !statusDisplay || !startButton || !pauseButton || !resetButton || !workButton || !restButton || !tomatoButtonSound || !tomatoAlarmSound) {
            console.error("Tomato Timer: One or more essential elements not found. Aborting initialization.");
            api.showError("Pomodoro Timer Error: Failed to find essential elements. Widget might not work correctly.");
            if (this.$widget) this.$widget.html("Error loading Pomodoro Timer elements.");
            return;
        }

        const WORK_TIME = config.WORK_TIME;
        const BREAK_TIME = config.BREAK_TIME;
        let isWorking = localStorage.getItem('tomatoStatus') ? localStorage.getItem('tomatoStatus') == 'working' : true;
        let time = localStorage.getItem('tomatoTime') ? parseInt(localStorage.getItem('tomatoTime')): WORK_TIME;
        let running = false;

        const playButtonSound = () => {
            if (config.enableSound){
                tomatoButtonSound.currentTime = 0;
                tomatoButtonSound.play().catch(e => console.error("Error playing button sound:", e));
            }
        }
        const playAlarmSound = () => {
            if (config.enableSound){
                tomatoAlarmSound.currentTime = 0;
                tomatoAlarmSound.play().catch(e => console.error("Error playing alarm sound:", e));
            }
        }

        const startTimer = () => {
            if (!running) {
                running = true;
                clearInterval(timerInterval);
                timerInterval = setInterval(updateTimer, 1000);
                updateTimer();
            }
        };

        const pauseTimer = () => {
            if (running) {
                playButtonSound();
                running = false;
                clearInterval(timerInterval);
            }
        };

        const resetTimer = () => {
            playButtonSound();
            running = false;
            clearInterval(timerInterval);
            time = isWorking ? WORK_TIME : BREAK_TIME;
            localStorage.setItem('tomatoTime', time);
            updateDisplay();
        };

        const restTimer = () => {
            playButtonSound();
            running = false;
            clearInterval(timerInterval);
            time = BREAK_TIME;
            isWorking = false;
            localStorage.setItem('tomatoTime', time);
            localStorage.setItem('tomatoStatus', 'resting');
            statusDisplay.textContent = i18n('resting');
            updateDisplay();
            startTimer();
        };

        const workTimer = () => {
            playButtonSound();
            running = false;
            clearInterval(timerInterval);
            time = WORK_TIME;
            isWorking = true;
            localStorage.setItem('tomatoTime', time);
            localStorage.setItem('tomatoStatus', 'working');
            statusDisplay.textContent = i18n('working');
            updateDisplay();
            startTimer();
        };

        const updateDisplay = () => {
            const minutes = Math.floor(time / 60);
            let seconds = time % 60;
            seconds = seconds < 10 ? '0' + seconds : seconds;
            timerDisplay.textContent = `${minutes}:${seconds}`;
        };

        const updateTimer = () => {
            updateDisplay();

            if (time > 0 && running) {
                time--;
                localStorage.setItem('tomatoTime', time);
            } else if (time <= 0 && running) {
                if (isWorking) {
                    new window.Notification(i18n('restNotificationTitle'), { body: i18n('restNotificationBody') });
                    api.showMessage(i18n('takeBreakMessage'));
                    playAlarmSound();
                    restTimer();
                } else {
                    new window.Notification(i18n('workNotificationTitle'), { body: i18n('workNotificationBody') });
                    api.showMessage(i18n('timeToDoSomething'));
                    playAlarmSound();
                    workTimer();
                }
            }
        };

        startButton.addEventListener('click', () => { playButtonSound(); startTimer(); });
        pauseButton.addEventListener('click', pauseTimer);
        resetButton.addEventListener('click', resetTimer);
        workButton.addEventListener('click', workTimer);
        restButton.addEventListener('click', restTimer);

        toggleWidgetButton.addEventListener('click', () => {
            playButtonSound();
            this.isWidgetHidden = !this.isWidgetHidden;
            localStorage.setItem('tomatoWidgetHidden', this.isWidgetHidden);

            if (this.isWidgetHidden) {
                tomatoBar.classList.add('widget-hidden');
                toggleWidgetButton.innerHTML = SHOW_ICON_HTML;
                toggleWidgetButton.setAttribute('title', i18n('showWidget'));
            } else {
                tomatoBar.classList.remove('widget-hidden');
                toggleWidgetButton.innerHTML = HIDE_ICON_HTML;
                toggleWidgetButton.setAttribute('title', i18n('hideWidget'));
            }
        });

        statusDisplay.textContent = i18n(localStorage.getItem('tomatoStatus') || 'working');
        updateDisplay();

        if (config.autoStartCountDown && !this.isWidgetHidden){
            startTimer();
        } else {
            updateDisplay();
        }
    }

    async entitiesReloadedEvent({ loadResults }) {

    }
}

module.exports = new TomatoWidget();

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions