mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-09 15:09:02 +00:00
desktop-only extension: integrated titlebar (inc. customisable icons)
This commit is contained in:
parent
022613d66b
commit
7f53445ab0
@ -6,7 +6,7 @@
|
|||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
:root:not(.dark) {
|
||||||
/*
|
/*
|
||||||
* variables are named for consistency with gruvbox dark,
|
* variables are named for consistency with gruvbox dark,
|
||||||
* but the _light variants are actually darker here
|
* but the _light variants are actually darker here
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* notion-enhancer: integrated titlebar
|
||||||
|
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
.integrated_titlebar--dragarea {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
background: var(--theme--bg_secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.integrated_titlebar--buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.integrated_titlebar--buttons[data-in-enhancer-menu] {
|
||||||
|
margin: -0.5rem 0 0.75rem auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.integrated_titlebar--buttons button {
|
||||||
|
user-select: none;
|
||||||
|
transition: background 20ms ease-in 0s;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 3px;
|
||||||
|
height: 28px;
|
||||||
|
width: 33px;
|
||||||
|
padding: 0 0.25px 0 0;
|
||||||
|
|
||||||
|
margin-left: 2px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.integrated_titlebar--buttons button svg {
|
||||||
|
display: block;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.integrated_titlebar--buttons button:focus,
|
||||||
|
.integrated_titlebar--buttons button:hover {
|
||||||
|
background: var(--theme--ui_interactive-hover);
|
||||||
|
}
|
||||||
|
.integrated_titlebar--buttons button:active {
|
||||||
|
background: var(--theme--ui_interactive-active);
|
||||||
|
}
|
||||||
|
#integrated_titlebar--close:focus,
|
||||||
|
#integrated_titlebar--close:hover,
|
||||||
|
#integrated_titlebar--close:active {
|
||||||
|
background: var(--theme--accent_red);
|
||||||
|
color: var(--theme--accent_red-text);
|
||||||
|
}
|
69
repo/integrated-titlebar/buttons.mjs
Normal file
69
repo/integrated-titlebar/buttons.mjs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* notion-enhancer: integrated titlebar
|
||||||
|
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
export const createWindowButtons = async ({ web, components }, db) => {
|
||||||
|
let minimizeIcon = (await db.get(['minimize_icon'])) || (await components.feather('minus')),
|
||||||
|
maximizeIcon = (await db.get(['maximize_icon'])) || (await components.feather('maximize')),
|
||||||
|
unmaximizeIcon =
|
||||||
|
(await db.get(['unmaximize_icon'])) || (await components.feather('minimize')),
|
||||||
|
closeIcon = await db.get(['close_icon'], await components.feather('x'));
|
||||||
|
minimizeIcon = minimizeIcon.trim();
|
||||||
|
maximizeIcon = maximizeIcon.trim();
|
||||||
|
unmaximizeIcon = unmaximizeIcon.trim();
|
||||||
|
closeIcon = closeIcon.trim();
|
||||||
|
|
||||||
|
minimizeIcon =
|
||||||
|
minimizeIcon.startsWith('<svg') && minimizeIcon.endsWith('</svg>')
|
||||||
|
? minimizeIcon
|
||||||
|
: web.escape(minimizeIcon);
|
||||||
|
maximizeIcon =
|
||||||
|
maximizeIcon.startsWith('<svg') && maximizeIcon.endsWith('</svg>')
|
||||||
|
? maximizeIcon
|
||||||
|
: web.escape(maximizeIcon);
|
||||||
|
unmaximizeIcon =
|
||||||
|
unmaximizeIcon.startsWith('<svg') && unmaximizeIcon.endsWith('</svg>')
|
||||||
|
? unmaximizeIcon
|
||||||
|
: web.escape(unmaximizeIcon);
|
||||||
|
closeIcon =
|
||||||
|
closeIcon.startsWith('<svg') && closeIcon.endsWith('</svg>')
|
||||||
|
? closeIcon
|
||||||
|
: web.escape(closeIcon);
|
||||||
|
|
||||||
|
const $windowButtons = web.html`<div class="integrated_titlebar--buttons"></div>`,
|
||||||
|
$minimize = web.html`<button id="integrated_titlebar--minimize">
|
||||||
|
${minimizeIcon}
|
||||||
|
</button>`,
|
||||||
|
$maximize = web.html`<button id="integrated_titlebar--maximize">
|
||||||
|
${maximizeIcon}
|
||||||
|
</button>`,
|
||||||
|
$unmaximize = web.html`<button id="integrated_titlebar--unmaximize">
|
||||||
|
${unmaximizeIcon}
|
||||||
|
</button>`,
|
||||||
|
$close = web.html`<button id="integrated_titlebar--close">
|
||||||
|
${closeIcon}
|
||||||
|
</button>`;
|
||||||
|
|
||||||
|
$minimize.addEventListener('click', () => __enhancerElectronApi.browser.minimize());
|
||||||
|
$maximize.addEventListener('click', () => __enhancerElectronApi.browser.maximize());
|
||||||
|
$unmaximize.addEventListener('click', () => __enhancerElectronApi.browser.unmaximize());
|
||||||
|
$close.addEventListener('click', () => __enhancerElectronApi.browser.close());
|
||||||
|
__enhancerElectronApi.browser.on('maximize', () => {
|
||||||
|
$maximize.replaceWith($unmaximize);
|
||||||
|
});
|
||||||
|
__enhancerElectronApi.browser.on('unmaximize', () => {
|
||||||
|
$unmaximize.replaceWith($maximize);
|
||||||
|
});
|
||||||
|
|
||||||
|
web.render(
|
||||||
|
$windowButtons,
|
||||||
|
$minimize,
|
||||||
|
__enhancerElectronApi.browser.isMaximized() ? $unmaximize : $maximize,
|
||||||
|
$close
|
||||||
|
);
|
||||||
|
return $windowButtons;
|
||||||
|
};
|
@ -6,6 +6,47 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import { createWindowButtons } from './buttons.mjs';
|
||||||
|
|
||||||
export default async function (api, db) {
|
export default async function (api, db) {
|
||||||
//
|
const { web } = api,
|
||||||
|
tilingMode = await db.get(['tiling']),
|
||||||
|
dragareaHeight = await db.get(['dragarea_height']),
|
||||||
|
sidebarSelector = '.notion-sidebar',
|
||||||
|
panelSelector = '#enhancer--panel',
|
||||||
|
topbarSelector = '.notion-topbar',
|
||||||
|
topbarActionsSelector = '.notion-topbar-action-buttons';
|
||||||
|
if (tilingMode) return;
|
||||||
|
|
||||||
|
let sidebarWidth = '0px',
|
||||||
|
panelWidth = '0px';
|
||||||
|
const updateDragareaOffsets = () => {
|
||||||
|
const $sidebar = document.querySelector(sidebarSelector),
|
||||||
|
newSidebarWidth = $sidebar.style.height === 'auto' ? '0px' : $sidebar.style.width,
|
||||||
|
$panel = document.querySelector(panelSelector),
|
||||||
|
newPanelWidth =
|
||||||
|
$panel && $panel.dataset.enhancerPanelPinned === 'true'
|
||||||
|
? window
|
||||||
|
.getComputedStyle(document.documentElement)
|
||||||
|
.getPropertyValue('--component--panel-width')
|
||||||
|
: '0px';
|
||||||
|
if (newSidebarWidth !== sidebarWidth) {
|
||||||
|
sidebarWidth = newSidebarWidth;
|
||||||
|
__enhancerElectronApi.sendMessageToHost('sidebar-width', sidebarWidth);
|
||||||
|
}
|
||||||
|
if (newPanelWidth !== panelWidth) {
|
||||||
|
panelWidth = newPanelWidth;
|
||||||
|
__enhancerElectronApi.sendMessageToHost('panel-width', panelWidth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
web.addDocumentObserver(updateDragareaOffsets);
|
||||||
|
|
||||||
|
await web.whenReady([topbarSelector, topbarActionsSelector]);
|
||||||
|
const $topbar = document.querySelector(topbarSelector),
|
||||||
|
$dragarea = web.html`<div class="integrated_titlebar--dragarea" style="height:${dragareaHeight}px"></div>`;
|
||||||
|
$topbar.prepend($dragarea);
|
||||||
|
|
||||||
|
const $topbarActions = document.querySelector(topbarActionsSelector),
|
||||||
|
$windowButtons = await createWindowButtons(api, db);
|
||||||
|
web.render($topbarActions.parentElement, $windowButtons);
|
||||||
}
|
}
|
||||||
|
@ -6,77 +6,21 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = async function (api, db, __exports) {
|
module.exports = async function (api, db, __exports, __eval) {
|
||||||
const notionCreateWindow = __exports.createWindow;
|
__eval(`
|
||||||
// __exports.createWindow = (relativeUrl = '', args) => {
|
const notionRectFromFocusedWindow = getRectFromFocusedWindow;
|
||||||
// const windowState = require('electron-window-state').default({
|
getRectFromFocusedWindow = (windowState) => {
|
||||||
// defaultWidth: 1320,
|
const rect = notionRectFromFocusedWindow(windowState);
|
||||||
// defaultHeight: 860,
|
rect.frame = false;
|
||||||
// });
|
return rect;
|
||||||
// const focusedWindow = electron_1.BrowserWindow.getFocusedWindow();
|
|
||||||
// const rect = getRectFromFocusedWindow(windowState);
|
|
||||||
// const windowCreationArgs = Object.assign(Object.assign({}, rect), {
|
|
||||||
// show: false,
|
|
||||||
// backgroundColor: '#ffffff',
|
|
||||||
// titleBarStyle: 'hiddenInset',
|
|
||||||
// autoHideMenuBar: true,
|
|
||||||
// webPreferences: {
|
|
||||||
// preload: path_1.default.resolve(__dirname, '../renderer/index.js'),
|
|
||||||
// webviewTag: true,
|
|
||||||
// session: electron_1.session.fromPartition(constants_1.electronSessionPartition),
|
|
||||||
// enableRemoteModule: true,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// const { window, warmed } = getNextWindow(windowCreationArgs);
|
|
||||||
// window.setMenuBarVisibility(false);
|
|
||||||
// warmWindowState.warmedWindow = undefined;
|
|
||||||
// window.once('ready-to-show', () => {
|
|
||||||
// if (args && args.isLocalhost) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (!warmed) {
|
|
||||||
// window.show();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// if (warmed) {
|
|
||||||
// if (warmWindowState.warmedLoaded) {
|
|
||||||
// notionIpc.sendMainToNotionWindow(window, 'notion:navigate-to-url', relativeUrl);
|
|
||||||
// } else {
|
|
||||||
// void window.loadURL(urlHelpers_1.getIndexUrl(relativeUrl));
|
|
||||||
// }
|
|
||||||
// window.setBounds(getRectFromFocusedWindow(windowState));
|
|
||||||
// window.show();
|
|
||||||
// } else {
|
|
||||||
// void window.loadURL(urlHelpers_1.getIndexUrl(relativeUrl));
|
|
||||||
// }
|
|
||||||
// if (focusedWindow) {
|
|
||||||
// if (focusedWindow.isFullScreen()) {
|
|
||||||
// window.setFullScreen(true);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// if (windowState.isFullScreen) {
|
|
||||||
// window.setFullScreen(true);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// window.on('close', () => {
|
|
||||||
// windowState.saveState(window);
|
|
||||||
// if (process.platform === 'win32') {
|
|
||||||
// const currentWindows = electron_1.BrowserWindow.getAllWindows();
|
|
||||||
// const hasNoOtherOpenWindows = currentWindows.every((currentWindow) =>
|
|
||||||
// Boolean(
|
|
||||||
// currentWindow.id === window.id ||
|
|
||||||
// (warmWindowState.warmedWindow &&
|
|
||||||
// currentWindow.id === warmWindowState.warmedWindow.id)
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// if (hasNoOtherOpenWindows) {
|
|
||||||
// electron_2.app.quit();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// setImmediate(() => {
|
|
||||||
// warmWindowState.warmedLoaded = false;
|
|
||||||
// });
|
|
||||||
// return window;
|
|
||||||
// };
|
|
||||||
};
|
};
|
||||||
|
`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// hide on open
|
||||||
|
// maybe only do once to hide first window?
|
||||||
|
|
||||||
|
// exports.createWindow = (...args) => {
|
||||||
|
// warmWindowState.warmedWindow = true;
|
||||||
|
// createWindow(...args);
|
||||||
|
// };
|
||||||
|
@ -6,6 +6,24 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import { createWindowButtons } from './buttons.mjs';
|
||||||
|
|
||||||
export default async function (api, db) {
|
export default async function (api, db) {
|
||||||
//
|
const { web } = api,
|
||||||
|
tilingMode = await db.get(['tiling']),
|
||||||
|
dragareaHeight = await db.get(['dragarea_height']),
|
||||||
|
bodyContainerSelector = '.body-container',
|
||||||
|
sidebarSelector = '.sidebar';
|
||||||
|
if (tilingMode) return;
|
||||||
|
|
||||||
|
await web.whenReady([bodyContainerSelector, sidebarSelector]);
|
||||||
|
const $bodyContainer = document.querySelector(bodyContainerSelector),
|
||||||
|
$dragarea = web.html`<div class="integrated_titlebar--dragarea" style="height:${dragareaHeight}px"></div>`;
|
||||||
|
document.body.prepend($dragarea);
|
||||||
|
$bodyContainer.style.height = `calc(100% - ${dragareaHeight}px)`;
|
||||||
|
|
||||||
|
const $sidebar = document.querySelector(sidebarSelector),
|
||||||
|
$windowButtons = await createWindowButtons(api, db);
|
||||||
|
$windowButtons.dataset.inEnhancerMenu = true;
|
||||||
|
$sidebar.prepend($windowButtons);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,10 @@
|
|||||||
"js": {
|
"js": {
|
||||||
"client": ["client.mjs"],
|
"client": ["client.mjs"],
|
||||||
"menu": ["menu.mjs"],
|
"menu": ["menu.mjs"],
|
||||||
"electron": [{ "source": "createWindow.cjs", "target": "main/createWindow.js" }]
|
"electron": [
|
||||||
|
{ "source": "createWindow.cjs", "target": "main/createWindow.js" },
|
||||||
|
{ "source": "rendererIndex.cjs", "target": "renderer/index.js" }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
@ -29,6 +32,41 @@
|
|||||||
"label": "tiling window manager mode",
|
"label": "tiling window manager mode",
|
||||||
"tooltip": "**completely remove the close/minimise/maximise buttons** (only for advanced use, not recommended)",
|
"tooltip": "**completely remove the close/minimise/maximise buttons** (only for advanced use, not recommended)",
|
||||||
"value": false
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"key": "dragarea_height",
|
||||||
|
"label": "dragarea height (px)",
|
||||||
|
"tooltip": "**the height of the rectangle added to the top of the window, used to drag/move the window around** (dragging is not possible in a frameless window without this bar)",
|
||||||
|
"value": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"key": "minimize_icon",
|
||||||
|
"label": "minimize window icon",
|
||||||
|
"tooltip": "**may be an svg string or any unicode symbol e.g. an emoji** (the default icon will be used if this field is left empty)",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"key": "maximize_icon",
|
||||||
|
"label": "maximize window icon",
|
||||||
|
"tooltip": "**may be an svg string or any unicode symbol e.g. an emoji** (the default icon will be used if this field is left empty)",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"key": "unmaximize_icon",
|
||||||
|
"label": "unmaximize window icon",
|
||||||
|
"tooltip": "**may be an svg string or any unicode symbol e.g. an emoji** (the default icon will be used if this field is left empty)",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"key": "close_icon",
|
||||||
|
"label": "close window icon",
|
||||||
|
"tooltip": "**may be an svg string or any unicode symbol e.g. an emoji** (the default icon will be used if this field is left empty)",
|
||||||
|
"value": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
41
repo/integrated-titlebar/rendererIndex.cjs
Normal file
41
repo/integrated-titlebar/rendererIndex.cjs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* notion-enhancer: integrated titlebar
|
||||||
|
* (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 (api, db, __exports, __eval) {
|
||||||
|
const dragareaSelector = '[style*="-webkit-app-region: drag;"]';
|
||||||
|
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
let isReadyInt;
|
||||||
|
isReadyInt = setInterval(isReadyTest, 100);
|
||||||
|
function isReadyTest() {
|
||||||
|
if (document.querySelector(dragareaSelector)) {
|
||||||
|
clearInterval(isReadyInt);
|
||||||
|
res(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isReadyTest();
|
||||||
|
});
|
||||||
|
|
||||||
|
const tilingMode = await db.get(['tiling']),
|
||||||
|
dragareaHeight = await db.get(['dragarea_height']);
|
||||||
|
|
||||||
|
const dragarea = document.querySelector(dragareaSelector);
|
||||||
|
dragarea.style.top = '2px';
|
||||||
|
dragarea.style.height = tilingMode ? '0' : `${dragareaHeight}px`;
|
||||||
|
|
||||||
|
document.getElementById('notion').addEventListener('ipc-message', (event) => {
|
||||||
|
switch (event.channel) {
|
||||||
|
case 'notion-enhancer:sidebar-width':
|
||||||
|
dragarea.style.left = event.args[0];
|
||||||
|
break;
|
||||||
|
case 'notion-enhancer:panel-width':
|
||||||
|
dragarea.style.right = event.args[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
@ -5,7 +5,7 @@
|
|||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
:root:not(.dark) {
|
||||||
--theme--accent_blue: var(--light_plus--accent_blue, rgb(46, 170, 220));
|
--theme--accent_blue: var(--light_plus--accent_blue, rgb(46, 170, 220));
|
||||||
--theme--accent_blue-selection: var(
|
--theme--accent_blue-selection: var(
|
||||||
--light_plus--accent_blue-selection,
|
--light_plus--accent_blue-selection,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
:root:not(.dark) {
|
||||||
--pinky_boom--brown: #a52a2a80;
|
--pinky_boom--brown: #a52a2a80;
|
||||||
--pinky_boom--orange: #ffa60080;
|
--pinky_boom--orange: #ffa60080;
|
||||||
--pinky_boom--yellow: #ffff0080;
|
--pinky_boom--yellow: #ffff0080;
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
--theme--accent_red-text: #fff;
|
--theme--accent_red-text: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root:not(.dark) {
|
||||||
--theme--bg: #fff;
|
--theme--bg: #fff;
|
||||||
--theme--bg_secondary: rgb(247, 246, 243);
|
--theme--bg_secondary: rgb(247, 246, 243);
|
||||||
--theme--bg_card: #fff;
|
--theme--bg_card: #fff;
|
||||||
|
Loading…
Reference in New Issue
Block a user