diff --git a/README.md b/README.md index 9c75c61..7637f85 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,8 @@ Sortana is implemented entirely with standard WebExtension scripts—no custom e deleting or archiving a message when it matches. Drag rules to reorder them, check *Only apply to unread messages* to skip read mail, set optional minimum or maximum message age limits, select the accounts or - folders a rule should apply to, uncheck *Enabled* to temporarily disable a rule, and + folders a rule should apply to. Use the + slashed-circle/check button to disable or re-enable a rule, and check *Stop after match* to halt further processing. Forward and reply actions open a compose window using the account that received the message. 3. Save your settings. New mail will be evaluated automatically using the diff --git a/options/options.js b/options/options.js index 3d02639..68b58da 100644 --- a/options/options.js +++ b/options/options.js @@ -315,26 +315,67 @@ document.addEventListener('DOMContentLoaded', async () => { const header = document.createElement('div'); header.className = 'message-header'; - header.appendChild(critInput); + + const leftWrap = document.createElement('div'); + leftWrap.style.display = 'flex'; + leftWrap.style.alignItems = 'center'; + leftWrap.style.flexGrow = '1'; + + const statusSpan = document.createElement('span'); + statusSpan.className = 'rule-status has-text-weight-semibold mr-2'; + + leftWrap.appendChild(statusSpan); + leftWrap.appendChild(critInput); + header.appendChild(leftWrap); + + const btnWrap = document.createElement('div'); + btnWrap.style.display = 'flex'; + btnWrap.style.gap = '0.25em'; + + let enabled = rule.enabled !== false; + + const toggleBtn = document.createElement('button'); + toggleBtn.type = 'button'; + toggleBtn.className = 'button is-small rule-toggle'; + const toggleIcon = document.createElement('img'); + toggleIcon.width = 16; + toggleIcon.height = 16; + toggleBtn.appendChild(toggleIcon); const delBtn = document.createElement('button'); - delBtn.className = 'delete'; - delBtn.setAttribute('aria-label', 'delete'); + delBtn.type = 'button'; + delBtn.className = 'button is-small is-danger is-light rule-delete'; + const delIcon = document.createElement('img'); + delIcon.src = browser.runtime.getURL('resources/svg/trash.svg'); + delIcon.width = 16; + delIcon.height = 16; + delBtn.appendChild(delIcon); + + function updateToggle() { + toggleIcon.src = browser.runtime.getURL( + `resources/svg/${enabled ? 'circleslash' : 'check'}.svg` + ); + statusSpan.textContent = enabled ? '' : '(Disabled)'; + article.dataset.enabled = String(enabled); + } + + toggleBtn.addEventListener('click', () => { + enabled = !enabled; + markDirty(); + updateToggle(); + }); + delBtn.addEventListener('click', () => { article.remove(); ruleCountEl.textContent = rulesContainer.querySelectorAll('.rule').length; + markDirty(); }); - header.appendChild(delBtn); - const enabledLabel = document.createElement('label'); - enabledLabel.className = 'checkbox ml-2'; - const enabledCheck = document.createElement('input'); - enabledCheck.type = 'checkbox'; - enabledCheck.className = 'rule-enabled'; - enabledCheck.checked = rule.enabled !== false; - enabledLabel.appendChild(enabledCheck); - enabledLabel.append(' Enabled'); - header.appendChild(enabledLabel); + btnWrap.appendChild(toggleBtn); + btnWrap.appendChild(delBtn); + header.appendChild(btnWrap); + + updateToggle(); const actionsContainer = document.createElement('div'); actionsContainer.className = 'rule-actions mb-2'; @@ -479,7 +520,7 @@ document.addEventListener('DOMContentLoaded', async () => { }); const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked; const unreadOnly = ruleEl.querySelector('.unread-only')?.checked; - const enabled = ruleEl.querySelector('.rule-enabled')?.checked !== false; + const enabled = ruleEl.dataset.enabled !== 'false'; const minAgeDays = parseFloat(ruleEl.querySelector('.min-age')?.value); const maxAgeDays = parseFloat(ruleEl.querySelector('.max-age')?.value); const accounts = [...(ruleEl.querySelector('.account-select')?.selectedOptions || [])].map(o => o.value); @@ -657,7 +698,7 @@ document.addEventListener('DOMContentLoaded', async () => { }); const stopProcessing = ruleEl.querySelector('.stop-processing')?.checked; const unreadOnly = ruleEl.querySelector('.unread-only')?.checked; - const enabled = ruleEl.querySelector('.rule-enabled')?.checked !== false; + const enabled = ruleEl.dataset.enabled !== 'false'; const minAgeDays = parseFloat(ruleEl.querySelector('.min-age')?.value); const maxAgeDays = parseFloat(ruleEl.querySelector('.max-age')?.value); const accounts = [...(ruleEl.querySelector('.account-select')?.selectedOptions || [])].map(o => o.value); diff --git a/resources/svg/circleslash.svg b/resources/svg/circleslash.svg new file mode 100644 index 0000000..3f16f96 --- /dev/null +++ b/resources/svg/circleslash.svg @@ -0,0 +1,4 @@ + + + +