From 039670e6395b26098105195cf44a799786eb33ab Mon Sep 17 00:00:00 2001 From: Emir <31805948+admiraldus@users.noreply.github.com> Date: Wed, 2 Dec 2020 15:09:31 +0300 Subject: [PATCH] extension: truncated table titles (#292) --- .../admiraldus-truncated-table-titles/app.css | 43 ++++ .../icons/eye.svg | 44 ++++ mods/admiraldus-truncated-table-titles/mod.js | 207 ++++++++++++++++++ 3 files changed, 294 insertions(+) create mode 100644 mods/admiraldus-truncated-table-titles/app.css create mode 100644 mods/admiraldus-truncated-table-titles/icons/eye.svg create mode 100644 mods/admiraldus-truncated-table-titles/mod.js diff --git a/mods/admiraldus-truncated-table-titles/app.css b/mods/admiraldus-truncated-table-titles/app.css new file mode 100644 index 0000000..e03ef40 --- /dev/null +++ b/mods/admiraldus-truncated-table-titles/app.css @@ -0,0 +1,43 @@ +/* + * truncated table titles + * (c) 2020 admiraldus (https://github.com/admiraldus) + * under the MIT license + */ + +/* target tooltip */ +.admiraldus-truncated-table-titles-tooltip +{ + position: fixed; +} + +.admiraldus-truncated-table-titles-tooltip > div { + display: flex; + align-items: center; + border-radius: 3px; + background: var(--theme--card); + padding: 4px 8px; + box-shadow: var(--theme--box-shadow); +} + +/* target tooltip icon */ +.admiraldus-truncated-table-titles-tooltip-svg { + display: flex; + align-items: center; +} + +.admiraldus-truncated-table-titles-tooltip-svg > svg { + margin-right: 0.25em; + height: 1em; + width: 1em; + fill: var(--theme--text_ui_info); +} + +/* target tooltip text */ +.admiraldus-truncated-table-titles-tooltip-text { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 12px; + font-weight: 500; + color: var(--theme--text_ui); +} \ No newline at end of file diff --git a/mods/admiraldus-truncated-table-titles/icons/eye.svg b/mods/admiraldus-truncated-table-titles/icons/eye.svg new file mode 100644 index 0000000..b7b039a --- /dev/null +++ b/mods/admiraldus-truncated-table-titles/icons/eye.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mods/admiraldus-truncated-table-titles/mod.js b/mods/admiraldus-truncated-table-titles/mod.js new file mode 100644 index 0000000..9c71ff0 --- /dev/null +++ b/mods/admiraldus-truncated-table-titles/mod.js @@ -0,0 +1,207 @@ +/* + * truncated table titles + * (c) 2020 admiraldus (https://github.com/admiraldus) + * under the MIT license + */ + +'use strict'; + +const PATH = require('path'); +const FS = require('fs-extra'); + +module.exports = { + id: '1794c0bd-7b96-46ad-aa0b-fc4bd76fc7fb', + name: 'truncated table titles', + tags: ['extension', 'admiraldus'], + desc: 'see the full text of the truncated table titles on hover over.', + version: '0.1.0', + author: { + name: 'admiraldus', + link: 'https://github.com/admiraldus', + avatar: 'enhancement://admiraldus-cosmos/img/avatar.jpg', + }, + hacks: { + 'renderer/preload.js'(store, __exports) { + document.addEventListener('readystatechange', () => { + if (document.readyState !== 'complete') return false; + + /** + * Wait until frame exists to avoid "cannot read property" error. + */ + function wait() { + const frame = document.querySelector('.notion-frame'); + + if (frame !== null) { + (async () => { + const notionOverlayContainer = document.querySelector('.notion-overlay-container'); + const createSvgContainer = document.createElement('div'); + const svgContainerHtml = await FS.readFile(PATH.resolve(`${__dirname}/icons/eye.svg`)); + + createSvgContainer.innerHTML = svgContainerHtml; + createSvgContainer.setAttribute('style', 'display: none;'); + createSvgContainer.classList.add('admiraldus-truncated-table-titles-rendered-svg'); + notionOverlayContainer.append(createSvgContainer); + })(); + } else { + setTimeout(wait, 500); + } + } + + wait(); + + /** + * Set the offset values of the created tooltip. + * + * @param {HTMLDivElement} cell Target the table header cell. + * @param {HTMLDivElement} tooltip Target the created tooltip. + * + * @return {string} Return the offset values. + */ + function setTooltipOffset(cell, tooltip) { + const body = document.querySelector('body'); + const sidebar = document.querySelector('.notion-sidebar:not([style*="transform"])'); + Object.defineProperty(Object.prototype, 'offset', { + get: function() { + return { + left: this.getBoundingClientRect().left + window.scrollX, + top: this.getBoundingClientRect().top + window.scrollY, + }; + }, + configurable: true, + }); + + if (body.offsetWidth < tooltip.offsetWidth + cell.offset.left) { + if (body.offsetWidth > cell.offsetWidth + cell.offset.left) { + const horizontalOffset = `right: ${body.offsetWidth - cell.offsetWidth - cell.offset.left}px;`; + + return `top: ${cell.offset.top + 40}px; ${horizontalOffset}`; + } else { + const horizontalOffset = 'right: 8px;'; + + return `top: ${cell.offset.top + 40}px; ${horizontalOffset}`; + } + } else if (sidebar == null && cell.offset.left <= 0) { + const horizontalOffset = 'left: 8px;'; + + return `top: ${cell.offset.top + 40}px; ${horizontalOffset}`; + } else if (sidebar !== null && sidebar.offsetWidth >= cell.offset.left) { + const horizontalOffset = `left: ${sidebar.offsetWidth + 8}px;`; + + console.warn('4'); + return `top: ${cell.offset.top + 40}px; ${horizontalOffset}`; + } else { + const horizontalOffset = `left: ${cell.offset.left}px;`; + + return `top: ${cell.offset.top + 40}px;${horizontalOffset}`; + } + } + + /** + * Create and append tooltip HTML. + * + * @param {HTMLDivElement} cell Target the table header cell. + * @param {string} text Get the title of the table header cell. + * @param {string} icon Get the HTML of the rendered svg. + */ + function createTooltip(cell, text, icon) { + const frame = document.querySelector('.notion-frame'); + const notionOverlayContainer = document.querySelector('.notion-overlay-container'); + const createTooltipContainer = document.createElement('div'); + const tooltipText = text.innerText; + const tooltipIcon = icon; + const tooltipContainerHtml = + `
+
+ ${tooltipIcon} +
+ +
+ ${tooltipText} +
+
`; + + createTooltipContainer.innerHTML = tooltipContainerHtml; + createTooltipContainer.classList.add('admiraldus-truncated-table-titles-tooltip'); + createTooltipContainer.setAttribute('style', `max-width: ${cell.offsetWidth >= 450 ? cell.offsetWidth / 2 + 450 >= frame.offsetWidth ? frame.offsetWidth - 16 : cell.offsetWidth / 2 + 450 : 450}px;`); + notionOverlayContainer.append(createTooltipContainer); + + const tooltipOffset = setTooltipOffset(cell, document.querySelector('.admiraldus-truncated-table-titles-tooltip')); + createTooltipContainer.setAttribute('style', createTooltipContainer.getAttribute('style') + tooltipOffset); + } + + /** + * Remove all tooltips from the DOM. + */ + function removeTooltip() { + if (document.querySelector('.admiraldus-truncated-table-titles-tooltip')) { + while (document.querySelectorAll('.admiraldus-truncated-table-titles-tooltip').length !== 0) { + document.querySelectorAll('.admiraldus-truncated-table-titles-tooltip').forEach((tooltip) => tooltip.remove()); + } + } + } + + const BODY = document.querySelector('body'); + let tooltipDelay = null; + + BODY.addEventListener('mousedown', () => { + /** + * When the drag is detected, set the global variable to true and remove all tooltips. + */ + const dragStart = function() { + window.isCellDragging = true; + + window.clearTimeout(tooltipDelay); + removeTooltip(); + }; + + /** + * When the drag is over, set the global variable to false and remove the relevant event listeners. + */ + const dragEnd = function() { + window.isCellDragging = false; + + window.removeEventListener('mousemove', dragStart); + window.removeEventListener('mouseup', dragEnd); + }; + + window.addEventListener('mousemove', dragStart); + window.addEventListener('mouseup', dragEnd); + }); + + BODY.addEventListener('mouseenter', (event) => { + const el = event.target; + + if (window.isCellDragging !== true) { + if (el.classList.contains('notion-table-view-header-cell')) { + if (el.querySelector('div[style*="text-overflow"]').scrollWidth > el.querySelector('div[style*="text-overflow"]').clientWidth) { + tooltipDelay = window.setTimeout(function() { + createTooltip(el, el.querySelector('div[style*="text-overflow"]'), document.querySelector('.admiraldus-truncated-table-titles-rendered-svg').innerHTML); + }, 1000); + } + } + } + }, true); + + BODY.addEventListener('mouseleave', (event) => { + const el = event.target; + + if (el.classList.contains('notion-table-view-header-cell')) { + if (el.querySelector('div[style*="text-overflow"]').scrollWidth > el.querySelector('div[style*="text-overflow"]').clientWidth) { + window.clearTimeout(tooltipDelay); + removeTooltip(); + } + } + }, true); + + console.info( + '%cextension: ' + + `%c${module.exports.name} ` + + `%cfrom ${module.exports.author.name} ` + + '%c(operational)', 'font-weight: bold;', + 'font-weight: normal', + 'font-style: italic;', + 'color: #a5d6a7;'); + }); + }, + }, +};