tab hotkeys: close, open, select + better drag indicator

This commit is contained in:
dragonwocky 2021-12-11 18:02:22 +11:00
parent 3e07f23128
commit 2ffc6e1e12
6 changed files with 92 additions and 32 deletions

View File

@ -7,6 +7,17 @@
'use strict';
export default async function ({ web, electron }, db) {
const newTabHotkey = await db.get(['new_tab']),
closeTabHotkey = await db.get(['close_tab']),
selectTabModifier = await db.get(['select_modifier']);
web.addHotkeyListener(newTabHotkey, () => electron.sendMessageToHost('new-tab'));
web.addHotkeyListener(closeTabHotkey, () => electron.sendMessageToHost('close-tab'));
for (let i = 1; i < 10; i++) {
web.addHotkeyListener([selectTabModifier, i.toString()], () => {
electron.sendMessageToHost('select-tab', i);
});
}
const breadcrumbSelector =
'.notion-topbar > div > :nth-child(2) > .notion-focusable:last-child',
imgIconSelector = `${breadcrumbSelector} .notion-record-icon img`,

View File

@ -20,6 +20,7 @@
"client": ["client.mjs"],
"electron": [
{ "source": "main.cjs", "target": "main/main.js" },
{ "source": "systemMenu.cjs", "target": "main/systemMenu.js" },
{ "source": "rendererIndex.cjs", "target": "renderer/index.js" }
]
},
@ -40,7 +41,7 @@
"type": "select",
"key": "select_modifier",
"label": "tab select modifier",
"tooltip": "**usage: Modifier+1 to Modifier+9, Modifier+ArrowLeft, Modifier+ArrowRight and Modifier+ link click**",
"tooltip": "**usage: Modifier+1 to Modifier+9, Modifier+ArrowLeft and Modifier+ArrowRight**",
"values": [
"Alt",
"Command",

View File

@ -29,28 +29,26 @@ module.exports = async function (api, db, __exports, __eval) {
notionUrl: url.parse(window.location.href, true).query.path,
cancelAnimation: true,
});
$newTab.addEventListener('click', () => {
new Tab($tabs, $root);
});
$newTab.addEventListener('click', () => new Tab($tabs, $root));
electron.ipcRenderer.on('notion-enhancer:close-tab', (event, id) => {
const tab = tabCache.get(id);
if (tab) tab.close();
});
electron.ipcRenderer.on(
'notion-enhancer:open-tab',
(event, opts) => new Tab($tabs, $root, opts)
);
let $draggedTab;
const getDragTarget = ($el) => {
const $dragIndicator = web.html`<span class="drag-indicator"></span>`,
getDragTarget = ($el) => {
while (!$el.matches('.tab, header, body')) $el = $el.parentElement;
if ($el.matches('header')) $el = $el.firstElementChild;
return $el.matches('#tabs, .tab') ? $el : undefined;
},
clearDragStatus = () => {
document
.querySelectorAll('.dragged-over')
.forEach(($el) => $el.classList.remove('dragged-over'));
},
resetDraggedTabs = () => {
if ($draggedTab) {
clearDragStatus();
$dragIndicator.remove();
$draggedTab.style.opacity = '';
$draggedTab = undefined;
}
@ -73,8 +71,11 @@ module.exports = async function (api, db, __exports, __eval) {
$header.addEventListener('dragover', (event) => {
const $target = getDragTarget(event.target);
if ($target) {
clearDragStatus();
$target.classList.add('dragged-over');
if ($target.matches('#tabs')) {
$target.after($dragIndicator);
} else if ($target.matches('#tabs > :first-child')) {
$tabs.before($dragIndicator);
} else $target.before($dragIndicator);
event.preventDefault();
}
});

20
repo/tabs/systemMenu.cjs Normal file
View File

@ -0,0 +1,20 @@
/**
* notion-enhancer: tabs
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
module.exports = async function ({}, db, __exports, __eval) {
const notionSetupSystemMenu = __exports.setupSystemMenu;
__exports.setupSystemMenu = (locale) => {
const { Menu } = require('electron'),
template = notionSetupSystemMenu(locale);
for (const category of template) {
category.submenu = category.submenu.filter((item) => item.role !== 'close');
}
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
return template;
};
};

View File

@ -48,8 +48,8 @@ module.exports = async function ({ components, env, web, fmt, fs }, db, tabCache
);
constructor(
$tabs,
$root,
$tabList,
$tabContainer,
{
notionUrl = 'notion://www.notion.so/',
cancelAnimation = false,
@ -57,14 +57,17 @@ module.exports = async function ({ components, env, web, fmt, fs }, db, tabCache
title = 'notion.so',
} = {}
) {
this.$tabList = $tabList;
this.$tabContainer = $tabContainer;
this.$notion.src = notionUrl;
this.$tabTitle.innerText = title;
this.setIcon(icon);
tabCache.set(this.$tab.id, this);
web.render($tabs, this.$tab);
web.render($root, this.$search);
web.render($root, this.$notion);
web.render($tabList, this.$tab);
web.render($tabContainer, this.$search);
web.render($tabContainer, this.$notion);
electronWindow.on('focus', () => {
if (focusedTab === this) this.$notion.focus();
});
@ -192,6 +195,16 @@ module.exports = async function ({ components, env, web, fmt, fs }, db, tabCache
this.$tabTitle.innerText = title;
});
fromNotion('notion-enhancer:set-tab-icon', (icon) => this.setIcon(icon));
fromNotion(
'notion-enhancer:new-tab',
() => new this.constructor(this.$tabList, this.$tabContainer)
);
fromNotion('notion-enhancer:close-tab', () => this.close());
fromNotion('notion-enhancer:select-tab', (i) => {
const $tab = i === 9 ? this.$tabList.lastElementChild : this.$tabList.children[i - 1];
if ($tab) $tab.click();
});
}
#firstQuery = true;

View File

@ -46,7 +46,7 @@ header {
width: 14em;
max-width: 14em;
overflow: hidden;
padding: 0.4em 0.6em 0.4em 0.6em;
padding: 0.4em 0.6em;
color: var(--theme--text_secondary);
background: var(--theme--bg);
@ -61,26 +61,28 @@ header {
.tab.current {
background: var(--theme--ui_interactive-active);
}
#tabs.dragged-over {
box-shadow: 2px 0 0 0 var(--theme--accent_blue-selection);
}
.tab.dragged-over {
box-shadow: inset 2px 0 0 0 var(--theme--accent_blue-selection);
.drag-indicator {
z-index: 1;
width: 0.125em;
margin: 0 -0.0625em;
background: var(--theme--accent_blue-selection);
}
.tab-title {
white-space: nowrap;
overflow: hidden;
margin-right: 0.25em;
}
.tab-icon {
font-size: 0.875em;
margin-right: 0.375em;
flex-shrink: 0;
}
.tab-icon[style*='background'] {
width: 0.875em;
height: 0.875em;
align-self: center;
margin: 0 0.5em 2px 0;
margin-right: 0.5em;
}
.tab-icon:not([style*='background']):empty,
.tab-icon + svg {
@ -88,6 +90,7 @@ header {
}
.tab-icon:not([style*='background']):empty + svg {
/* placeholder icon */
flex-shrink: 0;
display: inline-block;
margin: 1px 0.5em 0 0;
width: 1.125em;
@ -110,9 +113,9 @@ header {
width: 1.25em;
padding: 0 0.25px 0 0;
align-self: center;
border: none;
background: transparent;
font-size: 0.875em;
-webkit-app-region: no-drag;
}
.new-tab svg,
@ -134,7 +137,6 @@ header {
}
.new-tab {
align-self: center;
margin: 0 3em 0 0.375em;
}
.tab-close {
@ -165,9 +167,18 @@ header {
[data-tab-style='traditional tabbed'] .new-tab {
margin-bottom: -0.25em;
}
[data-tab-style='rectangular'] .tab-close,
[data-tab-style='traditional tabbed'] .tab-close {
align-self: auto;
}
[data-tab-style='rectangular'] .drag-indicator,
[data-tab-style='traditional tabbed'] .drag-indicator,
[data-tab-style='rectangular'] #tabs {
margin-bottom: -0.5em;
}
[data-tab-style='rectangular'] .tab {
padding: 0.6em 0.6em 0.8em 0.6em;
}
[data-tab-style='traditional tabbed'] header {
padding-top: 0.6875em;
}
@ -177,7 +188,7 @@ header {
[data-tab-style='traditional tabbed'] .tab {
border-top-left-radius: 0.875em;
border-top-right-radius: 0.875em;
padding: 0.6em 0.6em 0.4em 0.6em;
padding: 0.6em;
}
[data-tab-style='bubble'] .tab {
border-radius: 0.375em;
@ -185,13 +196,16 @@ header {
[data-tab-style='bubble'] .tab:not(:first-child) {
margin-left: 0.5em;
}
[data-tab-style='bubble'] .drag-indicator {
margin: 0 -0.3125em 0 0.1875em;
}
[data-tab-style='bubble'] .drag-indicator:first-child {
margin: 0 0.187em 0 -0.312em;
}
[data-tab-style='compact'] header {
padding: 0;
font-size: 14px;
}
[data-tab-style='compact'] .tab-close {
align-self: center;
}
[data-tab-style='compact'] #window-actions {
transform: scale(0.8);
margin-right: -0.35em;