extension: global block links

This commit is contained in:
dragonwocky 2021-10-20 23:04:26 +11:00
parent b1ced4fac8
commit dbb94bc29b
8 changed files with 214 additions and 36 deletions

View File

@ -0,0 +1,70 @@
/*
* notion-enhancer: global block links
* (c) 2021 admiraldus (https://github.com/admiraldus)
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (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;
}

View File

@ -0,0 +1,96 @@
/*
* notion-enhancer: global block links
* (c) 2021 admiraldus (https://github.com/admiraldus)
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (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`
<div class="${topbarCopyClass}" role="button" tabindex="0">
<svg viewBox="0 0 30 30">
<path d="M2,12c0-3.309,2.691-6,6-6h8c3.309,0,6,2.691,6,6s-2.691,6-6,6h-6c0,0.736,
0.223,1.41,0.574,2H16c4.418,0,8-3.582,8-8 c0-4.418-3.582-8-8-8H8c-4.418,0-8,3.582-8,
8c0,2.98,1.634,5.575,4.051,6.951C4.021,18.638,4,18.321,4,18 c0-0.488,0.046-0.967,
0.115-1.436C2.823,15.462,2,13.827,2,12z M25.953,11.051C25.984,11.363,26,11.68,26,12
c0,0.489-0.047,0.965-0.117,1.434C27.176,14.536,28,16.172,28,18c0,3.309-2.691,6-6,6h-8c-3.309,
0-6-2.691-6-6s2.691-6,6-6h6 c0-0.731-0.199-1.413-0.545-2H14c-4.418,0-8,3.582-8,8c0,4.418,3.582,8,8,
8h8c4.418,0,8-3.582,8-8 C30,15.021,28.368,12.428,25.953,11.051z"></path>
</svg>
<span>Copy link</span>
<span class="${hiddenClass}">Link copied!</span>
</div>`;
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`
<div class="${blockCopyClass}" role="button" tabindex="0">
${await components.feather('globe')}
<span>Global link</span>
</div>`;
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]);
}

View File

@ -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
}
]
}

View File

@ -31,5 +31,6 @@
"weekly-view",
"collapse-properties",
"truncated-titles",
"focus-mode"
"focus-mode",
"global-block-links"
]

View File

@ -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,

View File

@ -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);

View File

@ -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();
};

View File

@ -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**');