diff --git a/repo/global-block-links/client.css b/repo/global-block-links/client.css new file mode 100644 index 0000000..cb7381d --- /dev/null +++ b/repo/global-block-links/client.css @@ -0,0 +1,70 @@ +/* + * notion-enhancer: global block links + * (c) 2021 admiraldus (https://github.com/admiraldus) + * (c) 2021 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +.global_block_links--topbar_copy { + display: inline-flex; + align-items: center; + border-radius: 3px; + height: 28px; + min-width: 0px; + padding-right: 8px; + padding-left: 6px; + font-size: 14px; + line-height: 1.2; + color: var(--theme--text); + cursor: pointer; + transition: background 20ms ease-in 0s; + user-select: none; +} +.global_block_links--topbar_copy > svg { + display: block; + margin-right: 6px; + height: 16px; + width: 16px; + fill: var(--theme--icon_secondary); +} +.global_block_links--topbar_copy > span { + opacity: 1; + transition: opacity 0.4s ease; +} + +.global_block_links--block_copy { + display: flex; + align-items: center; + height: 28px; + width: 100%; + font-size: 14px; + line-height: 1.2; + cursor: pointer; + transition: background 20ms ease-in 0s; + user-select: none; +} +.global_block_links--block_copy > svg { + display: block; + margin-left: 14px; + height: 17px; + width: 17px; + color: var(--theme--icon); +} +.global_block_links--block_copy > span { + margin-right: 14px; + margin-left: 8px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.global_block_links--topbar_copy:hover, +.global_block_links--block_copy:hover { + background: var(--theme--ui_interactive-hover); +} + +.global_block_links--hidden { + position: absolute; + top: -9999px; + opacity: 0 !important; +} diff --git a/repo/global-block-links/client.mjs b/repo/global-block-links/client.mjs new file mode 100644 index 0000000..dabdcde --- /dev/null +++ b/repo/global-block-links/client.mjs @@ -0,0 +1,96 @@ +/* + * notion-enhancer: global block links + * (c) 2021 admiraldus (https://github.com/admiraldus) + * (c) 2021 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +export default async function ({ web, components, notion }, db) { + const topbarShareSelector = '.notion-topbar-share-menu', + blockActionSelector = + '.notion-overlay-container .notion-scroller.vertical .notion-focusable > div > div > [style*="text-overflow: ellipsis;"]', + hoveredActionSelector = + '.notion-overlay-container .notion-scroller.vertical .notion-focusable[style*="background:"]', + topbarCopyClass = 'global_block_links--topbar_copy', + blockCopyClass = 'global_block_links--block_copy', + hiddenClass = 'global_block_links--hidden'; + + if (await db.get(['topbar_copy'])) { + const $topbarCopyTemplate = web.html` +
+ + + + Copy link + Link copied! +
`; + + const insertTopbarCopy = () => { + const $btns = document.querySelectorAll(topbarShareSelector); + $btns.forEach(($btn) => { + if (!$btn.previousElementSibling?.classList?.contains?.(topbarCopyClass)) { + const $copy = $topbarCopyTemplate.cloneNode(true); + $btn.before($copy); + + let resetButtonDelay; + $copy.addEventListener('click', () => { + $copy.children[1].classList.add(hiddenClass); + $copy.lastElementChild.classList.remove(hiddenClass); + clearTimeout(resetButtonDelay); + resetButtonDelay = setTimeout(() => { + $copy.children[1].classList.remove(hiddenClass); + $copy.lastElementChild.classList.add(hiddenClass); + }, 1250); + + web.copyToClipboard(`https://notion.so/${notion.getPageID().replace(/-/g, '')}`); + }); + } + }); + }; + insertTopbarCopy(); + web.addDocumentObserver(insertTopbarCopy, [topbarShareSelector]); + } + + const $blockCopyTemplate = web.html` +
+ ${await components.feather('globe')} + Global link +
`; + + const getLinkButtons = () => + [...document.querySelectorAll(blockActionSelector)] + .filter(($action) => + ['Copy link', '링크 복사', 'リンクをコピー'].includes($action.textContent) + ) + .map(($action) => $action.closest('.notion-focusable')), + insertBlockCopy = () => { + const $btns = getLinkButtons(); + $btns.forEach(($btn) => { + if (!$btn.previousElementSibling?.classList?.contains?.(blockCopyClass)) { + const $copy = $blockCopyTemplate.cloneNode(true); + $btn.before($copy); + + $copy.addEventListener('mouseover', () => { + document.querySelectorAll(hoveredActionSelector).forEach(($action) => { + $action.style.background = ''; + }); + }); + + $copy.addEventListener('click', async () => { + $btn.click(); + const link = await web.readFromClipboard(), + id = link.replace(/.+#(?=\w+)/, ''); + web.copyToClipboard(id.length === 32 ? `https://notion.so/${id}` : link); + }); + } + }); + }; + insertBlockCopy(); + web.addDocumentObserver(insertBlockCopy, [blockActionSelector]); +} diff --git a/repo/global-block-links/mod.json b/repo/global-block-links/mod.json new file mode 100644 index 0000000..0513248 --- /dev/null +++ b/repo/global-block-links/mod.json @@ -0,0 +1,28 @@ +{ + "name": "global block links", + "id": "74856af4-6970-455d-bd86-0a385a402dd1", + "version": "0.1.0", + "description": "easily copy the global link of a page or block.", + "tags": ["extension", "shortcut"], + "authors": [ + { + "name": "admiraldus", + "homepage": "https://github.com/admiraldus", + "avatar": "https://raw.githubusercontent.com/admiraldus/admiraldus/main/module.gif" + } + ], + "js": { + "client": ["client.mjs"] + }, + "css": { + "client": ["client.css"] + }, + "options": [ + { + "key": "topbar_copy", + "label": "copy page links from the topbar", + "type": "toggle", + "value": true + } + ] +} diff --git a/repo/registry.json b/repo/registry.json index ea86b06..1a04c7a 100644 --- a/repo/registry.json +++ b/repo/registry.json @@ -31,5 +31,6 @@ "weekly-view", "collapse-properties", "truncated-titles", - "focus-mode" + "focus-mode", + "global-block-links" ] diff --git a/repo/theming/theme.css b/repo/theming/theme.css index 18352c6..a4a8d9e 100644 --- a/repo/theming/theme.css +++ b/repo/theming/theme.css @@ -219,7 +219,7 @@ body, } .notion-body.dark [style*='background: rgb(71, 76, 80);'], -.notion-body:not(.dark) [style*='background: rgba(55, 53, 47, 0.08)'], +.notion-body:not(.dark) [style*='background: rgba(255, 255, 255, 0.1)'], .notion-focusable[style*='z-index:'][style*='box-shadow: '][style*='font-size: 12px;'][style*='min-height: 24px; overflow: hidden; pointer-events:']:hover, :not(.notion-login) > .notion-focusable[role='button'][tabindex='0'][style*='box-shadow:'][style*='background:'][style*='transition: background 20ms ease-in 0s; cursor: pointer;']:not([style*='rgb(46, 170, 220);']):not([style*='rgb(6, 156, 205);']):not([style*='rgb(0, 141, 190);']):not([style*='flex: 1 1 0%; white-space: nowrap; height: 26px; border-radius: 3px 0px 0px 3px;']):not([style*='rgb(225, 98, 89)']):hover, diff --git a/repo/theming/variables.css b/repo/theming/variables.css index 1460d7f..395017a 100644 --- a/repo/theming/variables.css +++ b/repo/theming/variables.css @@ -205,7 +205,7 @@ --theme--ui_shadow: rgba(15, 15, 15, 0.15); --theme--ui_divider: rgb(255, 255, 255, 0.07); - --theme--ui_interactive-hover: rgb(71, 76, 80); + --theme--ui_interactive-hover: rgba(255, 255, 255, 0.1); --theme--ui_interactive-active: rgb(63, 68, 71); --theme--ui_toggle-on: var(--theme--accent_blue); --theme--ui_toggle-off: rgba(202, 204, 206, 0.3); diff --git a/repo/topbar-icons/client.mjs b/repo/topbar-icons/client.mjs index 0c7f471..8891871 100644 --- a/repo/topbar-icons/client.mjs +++ b/repo/topbar-icons/client.mjs @@ -23,9 +23,7 @@ export default async function ({ web, components }, db) { if ($btn.innerHTML !== innerHTML) $btn.innerHTML = innerHTML; }); }; - web.addDocumentObserver(() => { - updateButton(); - }, [selector]); + web.addDocumentObserver(updateButton, [selector]); updateButton(); }; diff --git a/repo/word-counter/client.mjs b/repo/word-counter/client.mjs index 99131ec..d7f35e5 100644 --- a/repo/word-counter/client.mjs +++ b/repo/word-counter/client.mjs @@ -4,35 +4,20 @@ * (https://notion-enhancer.github.io/) under the MIT license */ -const copyToClipboard = async (str) => { - try { - await navigator.clipboard.writeText(str); - } catch { - const el = document.createElement('textarea'); - el.value = str; - el.setAttribute('readonly', ''); - el.style.position = 'absolute'; - el.style.left = '-9999px'; - document.body.appendChild(el); - el.select(); - document.execCommand('copy'); - document.body.removeChild(el); - } - }, - humanTime = (mins) => { - let readable = ''; - if (1 <= mins) { - readable += `${Math.floor(mins)} min`; - if (2 <= mins) readable += 's'; - } - const secs = Math.round((mins % 1) * 60); - if (1 <= secs) { - if (1 <= mins) readable += ' '; - readable += `${secs} sec`; - if (2 <= secs) readable += 's'; - } - return readable; - }; +const humanTime = (mins) => { + let readable = ''; + if (1 <= mins) { + readable += `${Math.floor(mins)} min`; + if (2 <= mins) readable += 's'; + } + const secs = Math.round((mins % 1) * 60); + if (1 <= secs) { + if (1 <= mins) readable += ' '; + readable += `${secs} sec`; + if (2 <= secs) readable += 's'; + } + return readable; +}; export default async function ({ web, components }, db) { const dbNoticeText = 'Open a page to see its word count.', @@ -67,7 +52,7 @@ export default async function ({ web, components }, db) { ) ); $statList.querySelectorAll('.word-counter--stat').forEach(($stat) => { - $stat.addEventListener('click', () => copyToClipboard($stat.innerText)); + $stat.addEventListener('click', () => web.copyToClipboard($stat.innerText)); }); components.setTooltip($readingTooltip, '**~ 275 wpm**'); components.setTooltip($speakingTooltip, '**~ 180 wpm**');