rename: Outlook Relook → Outcut, add keyboard presets, remove design UI from popup

- Rename extension to "Outcut" throughout all source files and console logs
- Add KEY_PRESETS object (gmail/outlook) and matchesAction() helper to keyboard.js
- Rewrite handleKeydown to use preset-based dispatch instead of hardcoded switch
- Update updateSettings to re-init when keyboardPreset changes
- Add keyboardPreset: 'gmail' default to settings-defaults.js
- Replace popup Design Tweaks UI with preset dropdown + dynamic help text
- Keep all design tweak content script logic intact (activatable via storage)
- Update manifest: version 1.0.0, remove activeTab, add homepage_url
This commit is contained in:
Joel Brock
2026-04-27 14:11:45 -07:00
parent 93a5888d83
commit 3de2db7d89
10 changed files with 199 additions and 523 deletions

View File

@@ -7,7 +7,7 @@
<body>
<div class="or-header">
<h1>Outlook Relook</h1>
<h1>Outcut</h1>
<span class="or-version" id="version"></span>
</div>
@@ -15,263 +15,24 @@
<div class="or-section open" data-section="keyboard">
<div class="or-section-header">Keyboard Navigation</div>
<div class="or-section-body">
<div class="or-select-row">
<label for="keyboardPreset">Shortcut style</label>
<select id="keyboardPreset" data-setting="keyboardPreset">
<option value="gmail">Gmail</option>
<option value="outlook">Outlook</option>
</select>
</div>
<div class="or-toggle-row">
<label for="keyboardMultiSelect">Gmail-style keyboard multi-select</label>
<label for="keyboardMultiSelect">Enable keyboard multi-select</label>
<div class="or-switch"><input type="checkbox" id="keyboardMultiSelect" data-setting="keyboardMultiSelect"><span class="slider"></span></div>
</div>
<div style="font-size:11px;color:#888;padding:4px 0 2px;line-height:1.4;">
<div id="keyboardHelpText" style="font-size:11px;color:#888;padding:4px 0 2px;line-height:1.4;">
j/k navigate, x/Space select, # delete, e archive,
Shift+i/u read/unread, v move, f flag, p pin, Esc deselect
</div>
</div>
</div>
<!-- Design Tweaks Master Toggle -->
<div class="or-section" data-section="design-master">
<div class="or-section-header" style="cursor:default;">Design Tweaks</div>
<div class="or-section-body" style="display:block;">
<div class="or-toggle-row">
<label for="enableDesignTweaks">Enable experimental UI customization</label>
<div class="or-switch"><input type="checkbox" id="enableDesignTweaks" data-setting="enableDesignTweaks"><span class="slider"></span></div>
</div>
<div style="font-size:11px;color:#888;padding:2px 0;line-height:1.4;">
Themes, density, element hiding, and behavior patches. May conflict with OWA updates.
</div>
</div>
</div>
<!-- Design Tweaks Sections (hidden when enableDesignTweaks is off) -->
<div id="designSections">
<!-- Theme & Appearance -->
<div class="or-section" data-section="theme">
<div class="or-section-header">Theme &amp; Appearance</div>
<div class="or-section-body">
<div class="or-select-row">
<label for="theme">Theme</label>
<select id="theme" data-setting="theme">
<option value="swiss">Swiss</option>
<option value="material">Material</option>
<option value="brutalist">Brutalist</option>
</select>
</div>
<div class="or-radio-group" data-setting="colorScheme">
<label><input type="radio" name="colorScheme" value="light"> Light</label>
<label><input type="radio" name="colorScheme" value="dark"> Dark</label>
<label><input type="radio" name="colorScheme" value="system"> System</label>
</div>
<div class="or-color-row">
<label for="accentColor">Accent color</label>
<input type="color" id="accentColor" data-setting="accentColor" value="#1976d2">
</div>
</div>
</div>
<!-- Density & Spacing -->
<div class="or-section" data-section="density">
<div class="or-section-header">Density &amp; Spacing</div>
<div class="or-section-body">
<div class="or-select-row">
<label for="densityPreset">Density preset</label>
<select id="densityPreset" data-setting="densityPreset">
<option value="comfortable">Comfortable</option>
<option value="compact">Compact</option>
<option value="ultra-compact">Ultra-compact</option>
</select>
</div>
<div class="or-toggle-row">
<label for="compactTopBar">Compact top bar</label>
<div class="or-switch"><input type="checkbox" id="compactTopBar" data-setting="compactTopBar"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="compactCommandBar">Compact command bar</label>
<div class="or-switch"><input type="checkbox" id="compactCommandBar" data-setting="compactCommandBar"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="compactMessageList">Compact message list</label>
<div class="or-switch"><input type="checkbox" id="compactMessageList" data-setting="compactMessageList"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="compactReadingPane">Compact reading pane</label>
<div class="or-switch"><input type="checkbox" id="compactReadingPane" data-setting="compactReadingPane"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="compactFolderPane">Compact folder pane</label>
<div class="or-switch"><input type="checkbox" id="compactFolderPane" data-setting="compactFolderPane"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="narrowDateColumn">Narrow date column</label>
<div class="or-switch"><input type="checkbox" id="narrowDateColumn" data-setting="narrowDateColumn"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="compressComposeToolbar">Compress compose toolbar</label>
<div class="or-switch"><input type="checkbox" id="compressComposeToolbar" data-setting="compressComposeToolbar"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="readingPaneMaxWidth">Reading pane max-width</label>
<div class="or-switch"><input type="checkbox" id="readingPaneMaxWidth" data-setting="readingPaneMaxWidth"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="unifiedHeader">Unified header (collapse all bars)</label>
<div class="or-switch"><input type="checkbox" id="unifiedHeader" data-setting="unifiedHeader"><span class="slider"></span></div>
</div>
</div>
</div>
<!-- Hide Elements -->
<div class="or-section" data-section="hide">
<div class="or-section-header">Hide Elements</div>
<div class="or-section-body">
<div class="or-toggle-row">
<label for="hideCopilot">Copilot (button, pane, suggestions)</label>
<div class="or-switch"><input type="checkbox" id="hideCopilot" data-setting="hideCopilot"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideSuggestedReplies">Suggested replies</label>
<div class="or-switch"><input type="checkbox" id="hideSuggestedReplies" data-setting="hideSuggestedReplies"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hidePromoBanners">Promotional banners</label>
<div class="or-switch"><input type="checkbox" id="hidePromoBanners" data-setting="hidePromoBanners"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideFocusedOtherTabs">Focused / Other tabs</label>
<div class="or-switch"><input type="checkbox" id="hideFocusedOtherTabs" data-setting="hideFocusedOtherTabs"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideSidebarAppIcons">Sidebar app icons</label>
<div class="or-switch"><input type="checkbox" id="hideSidebarAppIcons" data-setting="hideSidebarAppIcons"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideGroupsSection">Groups section</label>
<div class="or-switch"><input type="checkbox" id="hideGroupsSection" data-setting="hideGroupsSection"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideMyDayButtons">My Day / panel buttons</label>
<div class="or-switch"><input type="checkbox" id="hideMyDayButtons" data-setting="hideMyDayButtons"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideSenderAvatars">Sender avatars</label>
<div class="or-switch"><input type="checkbox" id="hideSenderAvatars" data-setting="hideSenderAvatars"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideFeatureDiscovery">Feature discovery tooltips</label>
<div class="or-switch"><input type="checkbox" id="hideFeatureDiscovery" data-setting="hideFeatureDiscovery"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideVivaInsights">Viva Insights / Briefing</label>
<div class="or-switch"><input type="checkbox" id="hideVivaInsights" data-setting="hideVivaInsights"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideUnreadOtherBanner">Unread in Other banner</label>
<div class="or-switch"><input type="checkbox" id="hideUnreadOtherBanner" data-setting="hideUnreadOtherBanner"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="hideActivityFeed">Activity feed banners</label>
<div class="or-switch"><input type="checkbox" id="hideActivityFeed" data-setting="hideActivityFeed"><span class="slider"></span></div>
</div>
</div>
</div>
<!-- Readability -->
<div class="or-section" data-section="readability">
<div class="or-section-header">Readability</div>
<div class="or-section-body">
<div class="or-toggle-row">
<label for="unreadDistinction">Unread distinction (bold + border)</label>
<div class="or-switch"><input type="checkbox" id="unreadDistinction" data-setting="unreadDistinction"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="previewOwnLine">Preview text on own line</label>
<div class="or-switch"><input type="checkbox" id="previewOwnLine" data-setting="previewOwnLine"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="normalizeFontWeight">Normalize font weight</label>
<div class="or-switch"><input type="checkbox" id="normalizeFontWeight" data-setting="normalizeFontWeight"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="darkModeEmailFix">Dark mode email body fix</label>
<div class="or-switch"><input type="checkbox" id="darkModeEmailFix" data-setting="darkModeEmailFix"><span class="slider"></span></div>
</div>
<div class="or-select-row">
<label for="messageListFontSize">Message list font size</label>
<select id="messageListFontSize" data-setting="messageListFontSize">
<option value="small">Small</option>
<option value="medium">Medium</option>
<option value="large">Large</option>
</select>
</div>
</div>
</div>
<!-- Behavior -->
<div class="or-section" data-section="behavior">
<div class="or-section-header">Behavior</div>
<div class="or-section-body">
<div class="or-toggle-row">
<label for="autoCollapseRibbon">Auto-collapse ribbon</label>
<div class="or-switch"><input type="checkbox" id="autoCollapseRibbon" data-setting="autoCollapseRibbon"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="rememberSidebarState">Remember sidebar state</label>
<div class="or-switch"><input type="checkbox" id="rememberSidebarState" data-setting="rememberSidebarState"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="suppressContactHover">Suppress contact hover cards</label>
<div class="or-switch"><input type="checkbox" id="suppressContactHover" data-setting="suppressContactHover"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="autoAdvanceAfterDelete">Auto-advance after delete</label>
<div class="or-switch"><input type="checkbox" id="autoAdvanceAfterDelete" data-setting="autoAdvanceAfterDelete"><span class="slider"></span></div>
</div>
<div class="or-select-row">
<label for="autoDismissToasts">Auto-dismiss toasts</label>
<select id="autoDismissToasts" data-setting="autoDismissToasts">
<option value="off">Off</option>
<option value="3">3 seconds</option>
<option value="5">5 seconds</option>
<option value="10">10 seconds</option>
</select>
</div>
<div class="or-select-row">
<label for="toastPosition">Toast position</label>
<select id="toastPosition" data-setting="toastPosition">
<option value="bottom-left">Bottom-left</option>
<option value="top-right">Top-right</option>
</select>
</div>
<div class="or-toggle-row">
<label for="stickyReplyBar">Sticky Reply/Forward bar</label>
<div class="or-switch"><input type="checkbox" id="stickyReplyBar" data-setting="stickyReplyBar"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="autoResizeCompose">Auto-resize compose window</label>
<div class="or-switch"><input type="checkbox" id="autoResizeCompose" data-setting="autoResizeCompose"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="throttleNotifications">Throttle desktop notifications</label>
<div class="or-switch"><input type="checkbox" id="throttleNotifications" data-setting="throttleNotifications"><span class="slider"></span></div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="or-section" data-section="actions">
<div class="or-section-header">Quick Actions</div>
<div class="or-section-body">
<div class="or-toggle-row">
<label for="markAllReadButton">"Mark all as read" button</label>
<div class="or-switch"><input type="checkbox" id="markAllReadButton" data-setting="markAllReadButton"><span class="slider"></span></div>
</div>
<div class="or-toggle-row">
<label for="quickFolderJump">Quick folder jump (Ctrl+Shift+K)</label>
<div class="or-switch"><input type="checkbox" id="quickFolderJump" data-setting="quickFolderJump"><span class="slider"></span></div>
</div>
</div>
</div>
</div><!-- /designSections -->
<!-- Footer -->
<div class="or-footer">
<button id="exportBtn" title="Export settings as JSON">Export</button>

View File

@@ -1,4 +1,4 @@
// Outlook Relook — Popup Settings Logic
// Outcut — Popup Settings Logic
(function () {
'use strict';
@@ -9,6 +9,7 @@
var DEFAULTS = {
// Primary feature
keyboardMultiSelect: true,
keyboardPreset: 'gmail',
// Design tweaks master toggle
enableDesignTweaks: false,
@@ -67,44 +68,15 @@
quickFolderJump: true,
};
var DENSITY_PRESETS = {
comfortable: {
compactTopBar: false,
compactCommandBar: false,
compactMessageList: false,
compactReadingPane: false,
compactFolderPane: false,
narrowDateColumn: false,
compressComposeToolbar: false,
readingPaneMaxWidth: true,
},
compact: {
compactTopBar: true,
compactCommandBar: true,
compactMessageList: true,
compactReadingPane: true,
compactFolderPane: true,
narrowDateColumn: true,
compressComposeToolbar: true,
readingPaneMaxWidth: true,
},
'ultra-compact': {
compactTopBar: true,
compactCommandBar: true,
compactMessageList: true,
compactReadingPane: true,
compactFolderPane: true,
narrowDateColumn: true,
compressComposeToolbar: true,
readingPaneMaxWidth: true,
},
};
// --- Design sections visibility ---
var designSections = document.getElementById('designSections');
function updateDesignSectionsVisibility(enabled) {
designSections.style.display = enabled ? 'block' : 'none';
// --- Keyboard help text ---
function updateKeyboardHelp(presetName) {
var helpEl = document.getElementById('keyboardHelpText');
if (!helpEl) return;
var presets = {
gmail: 'j/k navigate, x/Space select, # delete, e archive, Shift+i/u read/unread, v move, f flag, p pin, Esc deselect',
outlook: 'Arrows navigate, Space select, Del/Backspace delete, e archive, q read/unread, v move, f flag, p pin, Esc deselect'
};
helpEl.textContent = presets[presetName] || presets.gmail;
}
// --- Load settings and populate UI ---
@@ -122,26 +94,12 @@
selects[j].value = settings[selects[j].dataset.setting] || '';
}
// Radio groups
var radioGroups = document.querySelectorAll('.or-radio-group[data-setting]');
for (var k = 0; k < radioGroups.length; k++) {
var key = radioGroups[k].dataset.setting;
var radio = radioGroups[k].querySelector('input[value="' + settings[key] + '"]');
if (radio) radio.checked = true;
}
// Color picker
var colorPicker = document.querySelector('input[type="color"][data-setting]');
if (colorPicker) {
colorPicker.value = settings.accentColor || '#1976d2';
}
// Version
var manifest = chrome.runtime.getManifest();
document.getElementById('version').textContent = 'v' + manifest.version;
// Show/hide design sections
updateDesignSectionsVisibility(settings.enableDesignTweaks);
// Update help text based on current preset
updateKeyboardHelp(settings.keyboardPreset || 'gmail');
});
}
@@ -165,11 +123,6 @@
for (var c = 0; c < checkboxes.length; c++) {
checkboxes[c].addEventListener('change', function () {
saveSetting(this.dataset.setting, this.checked);
// Toggle design sections visibility when master toggle changes
if (this.dataset.setting === 'enableDesignTweaks') {
updateDesignSectionsVisibility(this.checked);
}
});
}
@@ -181,41 +134,12 @@
var value = this.value;
saveSetting(settingKey, value);
// Density preset: apply to individual toggles
if (settingKey === 'densityPreset' && DENSITY_PRESETS[value]) {
var preset = DENSITY_PRESETS[value];
chrome.storage.sync.set(preset);
var toggleKeys = Object.keys(preset);
for (var p = 0; p < toggleKeys.length; p++) {
var checkbox = document.getElementById(toggleKeys[p]);
if (checkbox) checkbox.checked = preset[toggleKeys[p]];
}
if (settingKey === 'keyboardPreset') {
updateKeyboardHelp(value);
}
});
}
// --- Radio group change handlers ---
var radioGroups = document.querySelectorAll('.or-radio-group[data-setting]');
for (var r = 0; r < radioGroups.length; r++) {
var groupKey = radioGroups[r].dataset.setting;
var radios = radioGroups[r].querySelectorAll('input[type="radio"]');
for (var ri = 0; ri < radios.length; ri++) {
(function (gk) {
radios[ri].addEventListener('change', function () {
if (this.checked) saveSetting(gk, this.value);
});
})(groupKey);
}
}
// --- Color picker change handler ---
var colorPickers = document.querySelectorAll('input[type="color"][data-setting]');
for (var cp = 0; cp < colorPickers.length; cp++) {
colorPickers[cp].addEventListener('input', function () {
saveSetting(this.dataset.setting, this.value);
});
}
// --- Export settings ---
document.getElementById('exportBtn').addEventListener('click', function () {
chrome.storage.sync.get(DEFAULTS, function (settings) {
@@ -223,7 +147,7 @@
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'outlook-relook-settings.json';
a.download = 'outcut-settings.json';
a.click();
URL.revokeObjectURL(url);
});