mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-06 21:49:03 +00:00
scope all await statements
This commit is contained in:
parent
496305597a
commit
a72441ee86
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import { fmt, web, registry, components } from '../../api/_.mjs';
|
import { fmt, web, registry, components } from '../../api/_.mjs';
|
||||||
import { notifications } from './notifications.mjs';
|
import { notifications } from './notifications.mjs';
|
||||||
const profileDB = await registry.profileDB();
|
|
||||||
|
|
||||||
export const modComponents = {
|
export const modComponents = {
|
||||||
preview: (url) => web.html`<img
|
preview: (url) => web.html`<img
|
||||||
@ -56,7 +55,8 @@ export const modComponents = {
|
|||||||
|
|
||||||
export const options = {
|
export const options = {
|
||||||
toggle: async (mod, opt) => {
|
toggle: async (mod, opt) => {
|
||||||
const checked = await profileDB.get([mod.id, opt.key], opt.value),
|
const profileDB = await registry.profileDB(),
|
||||||
|
checked = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$toggle = modComponents.toggle(opt.label, checked),
|
$toggle = modComponents.toggle(opt.label, checked),
|
||||||
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = $toggle.children[0],
|
$label = $toggle.children[0],
|
||||||
@ -71,8 +71,10 @@ export const options = {
|
|||||||
});
|
});
|
||||||
return $toggle;
|
return $toggle;
|
||||||
},
|
},
|
||||||
|
|
||||||
select: async (mod, opt) => {
|
select: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.values[0]),
|
const profileDB = await registry.profileDB(),
|
||||||
|
value = await profileDB.get([mod.id, opt.key], opt.values[0]),
|
||||||
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
@ -96,8 +98,10 @@ export const options = {
|
|||||||
});
|
});
|
||||||
return web.render($label, $select, $icon);
|
return web.render($label, $select, $icon);
|
||||||
},
|
},
|
||||||
|
|
||||||
text: async (mod, opt) => {
|
text: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
const profileDB = await registry.profileDB(),
|
||||||
|
value = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
@ -112,8 +116,10 @@ export const options = {
|
|||||||
});
|
});
|
||||||
return web.render($label, $input, $icon);
|
return web.render($label, $input, $icon);
|
||||||
},
|
},
|
||||||
|
|
||||||
number: async (mod, opt) => {
|
number: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
const profileDB = await registry.profileDB(),
|
||||||
|
value = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
@ -128,8 +134,10 @@ export const options = {
|
|||||||
});
|
});
|
||||||
return web.render($label, $input, $icon);
|
return web.render($label, $input, $icon);
|
||||||
},
|
},
|
||||||
|
|
||||||
color: async (mod, opt) => {
|
color: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
const profileDB = await registry.profileDB(),
|
||||||
|
value = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
@ -166,8 +174,10 @@ export const options = {
|
|||||||
paint();
|
paint();
|
||||||
return web.render($label, $input, $icon);
|
return web.render($label, $input, $icon);
|
||||||
},
|
},
|
||||||
|
|
||||||
file: async (mod, opt) => {
|
file: async (mod, opt) => {
|
||||||
const { filename } = (await profileDB.get([mod.id, opt.key], {})) || {},
|
const profileDB = await registry.profileDB(),
|
||||||
|
{ filename } = (await profileDB.get([mod.id, opt.key], {})) || {},
|
||||||
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
@ -204,8 +214,10 @@ export const options = {
|
|||||||
$latest
|
$latest
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
hotkey: async (mod, opt) => {
|
hotkey: async (mod, opt) => {
|
||||||
const value = await profileDB.get([mod.id, opt.key], opt.value),
|
const profileDB = await registry.profileDB(),
|
||||||
|
value = await profileDB.get([mod.id, opt.key], opt.value),
|
||||||
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
|
||||||
$label = web.render(
|
$label = web.render(
|
||||||
web.html`<label class="input-label"></label>`,
|
web.html`<label class="input-label"></label>`,
|
||||||
|
@ -8,184 +8,185 @@
|
|||||||
|
|
||||||
import * as api from '../../api/_.mjs';
|
import * as api from '../../api/_.mjs';
|
||||||
import { notifications, $changelogModal } from './notifications.mjs';
|
import { notifications, $changelogModal } from './notifications.mjs';
|
||||||
const { env, fs, storage, registry, web, components } = api;
|
|
||||||
|
|
||||||
for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
|
|
||||||
for (const sheet of mod.css?.menu || []) {
|
|
||||||
web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
|
|
||||||
}
|
|
||||||
for (let script of mod.js?.menu || []) {
|
|
||||||
script = await import(fs.localPath(`repo/${mod._dir}/${script}`));
|
|
||||||
script.default(api, await registry.db(mod.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const errors = await registry.errors();
|
|
||||||
if (errors.length) {
|
|
||||||
console.log('[notion-enhancer] registry errors:');
|
|
||||||
console.table(errors);
|
|
||||||
notifications.add({
|
|
||||||
icon: 'alert-circle',
|
|
||||||
message: 'Failed to load mods (check console).',
|
|
||||||
color: 'red',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
import { modComponents, options } from './components.mjs';
|
import { modComponents, options } from './components.mjs';
|
||||||
import * as router from './router.mjs';
|
import * as router from './router.mjs';
|
||||||
import './styles.mjs';
|
import './styles.mjs';
|
||||||
|
|
||||||
const db = await registry.db('a6621988-551d-495a-97d8-3c568bca2e9e'),
|
(async () => {
|
||||||
profileName = await registry.profileName(),
|
const { env, fs, storage, registry, web, components } = api;
|
||||||
profileDB = await registry.profileDB();
|
|
||||||
|
|
||||||
web.addHotkeyListener(await db.get(['hotkey']), env.focusNotion);
|
for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
|
||||||
|
for (const sheet of mod.css?.menu || []) {
|
||||||
|
web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
|
||||||
|
}
|
||||||
|
for (let script of mod.js?.menu || []) {
|
||||||
|
script = await import(fs.localPath(`repo/${mod._dir}/${script}`));
|
||||||
|
script.default(api, await registry.db(mod.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const errors = await registry.errors();
|
||||||
|
if (errors.length) {
|
||||||
|
console.log('[notion-enhancer] registry errors:');
|
||||||
|
console.table(errors);
|
||||||
|
notifications.add({
|
||||||
|
icon: 'alert-circle',
|
||||||
|
message: 'Failed to load mods (check console).',
|
||||||
|
color: 'red',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const loadTheme = async () => {
|
const db = await registry.db('a6621988-551d-495a-97d8-3c568bca2e9e'),
|
||||||
document.documentElement.className =
|
profileName = await registry.profileName(),
|
||||||
(await storage.get(['theme'], 'light')) === 'dark' ? 'dark' : '';
|
profileDB = await registry.profileDB();
|
||||||
};
|
|
||||||
document.addEventListener('visibilitychange', loadTheme);
|
|
||||||
loadTheme();
|
|
||||||
|
|
||||||
window.addEventListener('beforeunload', (event) => {
|
web.addHotkeyListener(await db.get(['hotkey']), env.focusNotion);
|
||||||
// trigger input save
|
|
||||||
document.activeElement.blur();
|
|
||||||
});
|
|
||||||
|
|
||||||
const $main = web.html`<main class="main"></main>`,
|
const loadTheme = async () => {
|
||||||
$sidebar = web.html`<article class="sidebar"></article>`,
|
document.documentElement.className =
|
||||||
$options = web.html`<div class="options-container">
|
(await storage.get(['theme'], 'light')) === 'dark' ? 'dark' : '';
|
||||||
|
};
|
||||||
|
document.addEventListener('visibilitychange', loadTheme);
|
||||||
|
loadTheme();
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', (event) => {
|
||||||
|
// trigger input save
|
||||||
|
document.activeElement.blur();
|
||||||
|
});
|
||||||
|
|
||||||
|
const $main = web.html`<main class="main"></main>`,
|
||||||
|
$sidebar = web.html`<article class="sidebar"></article>`,
|
||||||
|
$options = web.html`<div class="options-container">
|
||||||
<p class="options-placeholder">Select a mod to view and configure its options.</p>
|
<p class="options-placeholder">Select a mod to view and configure its options.</p>
|
||||||
</div>`,
|
</div>`,
|
||||||
$profile = web.html`<button class="profile-trigger">
|
$profile = web.html`<button class="profile-trigger">
|
||||||
Profile: ${web.escape(profileName)}
|
Profile: ${web.escape(profileName)}
|
||||||
</button>`;
|
</button>`;
|
||||||
|
|
||||||
// profile
|
// profile
|
||||||
|
|
||||||
let _$profileConfig;
|
let _$profileConfig;
|
||||||
const openProfileMenu = async () => {
|
const openProfileMenu = async () => {
|
||||||
if (!_$profileConfig) {
|
if (!_$profileConfig) {
|
||||||
const profileNames = [
|
const profileNames = [
|
||||||
...new Set([
|
...new Set([
|
||||||
...Object.keys(await storage.get(['profiles'], { default: {} })),
|
...Object.keys(await storage.get(['profiles'], { default: {} })),
|
||||||
profileName,
|
profileName,
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
$options = profileNames.map(
|
$options = profileNames.map(
|
||||||
(profile) => web.raw`<option
|
(profile) => web.raw`<option
|
||||||
class="select-option"
|
class="select-option"
|
||||||
value="${web.escape(profile)}"
|
value="${web.escape(profile)}"
|
||||||
${profile === profileName ? 'selected' : ''}
|
${profile === profileName ? 'selected' : ''}
|
||||||
>${web.escape(profile)}</option>`
|
>${web.escape(profile)}</option>`
|
||||||
),
|
),
|
||||||
$select = web.html`<select class="input">
|
$select = web.html`<select class="input">
|
||||||
<option class="select-option" value="--">-- new --</option>
|
<option class="select-option" value="--">-- new --</option>
|
||||||
${$options.join('')}
|
${$options.join('')}
|
||||||
</select>`,
|
</select>`,
|
||||||
$edit = web.html`<input
|
$edit = web.html`<input
|
||||||
type="text"
|
type="text"
|
||||||
class="input"
|
class="input"
|
||||||
value="${web.escape(profileName)}"
|
value="${web.escape(profileName)}"
|
||||||
pattern="/^[A-Za-z0-9_-]+$/"
|
pattern="/^[A-Za-z0-9_-]+$/"
|
||||||
>`,
|
>`,
|
||||||
$export = web.html`<button class="profile-export">
|
$export = web.html`<button class="profile-export">
|
||||||
${await components.feather('download', { class: 'profile-icon-action' })}
|
${await components.feather('download', { class: 'profile-icon-action' })}
|
||||||
</button>`,
|
</button>`,
|
||||||
$import = web.html`<label class="profile-import">
|
$import = web.html`<label class="profile-import">
|
||||||
<input type="file" class="hidden" accept="application/json">
|
<input type="file" class="hidden" accept="application/json">
|
||||||
${await components.feather('upload', { class: 'profile-icon-action' })}
|
${await components.feather('upload', { class: 'profile-icon-action' })}
|
||||||
</label>`,
|
</label>`,
|
||||||
$save = web.html`<button class="profile-save">
|
$save = web.html`<button class="profile-save">
|
||||||
${await components.feather('save', { class: 'profile-icon-text' })} Save
|
${await components.feather('save', { class: 'profile-icon-text' })} Save
|
||||||
</button>`,
|
</button>`,
|
||||||
$delete = web.html`<button class="profile-delete">
|
$delete = web.html`<button class="profile-delete">
|
||||||
${await components.feather('trash-2', { class: 'profile-icon-text' })} Delete
|
${await components.feather('trash-2', { class: 'profile-icon-text' })} Delete
|
||||||
</button>`,
|
</button>`,
|
||||||
$error = web.html`<p class="profile-error"></p>`;
|
$error = web.html`<p class="profile-error"></p>`;
|
||||||
|
|
||||||
$export.addEventListener('click', async (event) => {
|
$export.addEventListener('click', async (event) => {
|
||||||
const now = new Date(),
|
const now = new Date(),
|
||||||
$a = web.html`<a
|
$a = web.html`<a
|
||||||
class="hidden"
|
class="hidden"
|
||||||
download="notion-enhancer_${web.escape($select.value)}_${now.getFullYear()}-${
|
download="notion-enhancer_${web.escape($select.value)}_${now.getFullYear()}-${
|
||||||
now.getMonth() + 1
|
now.getMonth() + 1
|
||||||
}-${now.getDate()}.json"
|
}-${now.getDate()}.json"
|
||||||
href="data:text/plain;charset=utf-8,${encodeURIComponent(
|
href="data:text/plain;charset=utf-8,${encodeURIComponent(
|
||||||
JSON.stringify(await storage.get(['profiles', $select.value], {}), null, 2)
|
JSON.stringify(await storage.get(['profiles', $select.value], {}), null, 2)
|
||||||
)}"
|
)}"
|
||||||
></a>`;
|
></a>`;
|
||||||
web.render(document.body, $a);
|
web.render(document.body, $a);
|
||||||
$a.click();
|
$a.click();
|
||||||
$a.remove();
|
$a.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
$import.addEventListener('change', (event) => {
|
$import.addEventListener('change', (event) => {
|
||||||
const file = event.target.files[0],
|
const file = event.target.files[0],
|
||||||
reader = new FileReader();
|
reader = new FileReader();
|
||||||
reader.onload = async (progress) => {
|
reader.onload = async (progress) => {
|
||||||
try {
|
try {
|
||||||
const profileUpload = JSON.parse(progress.currentTarget.result);
|
const profileUpload = JSON.parse(progress.currentTarget.result);
|
||||||
if (!profileUpload) throw Error;
|
if (!profileUpload) throw Error;
|
||||||
await storage.set(['profiles', $select.value], profileUpload);
|
await storage.set(['profiles', $select.value], profileUpload);
|
||||||
env.reload();
|
env.reload();
|
||||||
} catch {
|
} catch {
|
||||||
web.render(web.empty($error), 'Invalid JSON uploaded.');
|
web.render(web.empty($error), 'Invalid JSON uploaded.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
$select.addEventListener('change', async (event) => {
|
||||||
|
if ($select.value === '--') {
|
||||||
|
$edit.value = '';
|
||||||
|
} else $edit.value = $select.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
$save.addEventListener('click', async (event) => {
|
||||||
|
if (profileNames.includes($edit.value) && $select.value !== $edit.value) {
|
||||||
|
web.render(
|
||||||
|
web.empty($error),
|
||||||
|
`The profile "${web.escape($edit.value)}" already exists.`
|
||||||
|
);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
if (!$edit.value) {
|
||||||
reader.readAsText(file);
|
web.render(web.empty($error), 'Profile names cannot be empty.');
|
||||||
});
|
return false;
|
||||||
|
}
|
||||||
|
if (!$edit.value.match(/^[A-Za-z0-9_-]+$/)) {
|
||||||
|
web.render(
|
||||||
|
web.empty($error),
|
||||||
|
'Profile names can only contain letters, numbers, dashes and underscores.'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
await storage.set(['currentprofile'], $edit.value);
|
||||||
|
if ($select.value === '--') {
|
||||||
|
await storage.set(['profiles', $edit.value], {});
|
||||||
|
} else if ($select.value !== $edit.value) {
|
||||||
|
await storage.set(
|
||||||
|
['profiles', $edit.value],
|
||||||
|
await storage.get(['profiles', $select.value], {})
|
||||||
|
);
|
||||||
|
await storage.set(['profiles', $select.value], undefined);
|
||||||
|
}
|
||||||
|
env.reload();
|
||||||
|
});
|
||||||
|
|
||||||
$select.addEventListener('change', async (event) => {
|
$delete.addEventListener('click', async (event) => {
|
||||||
if ($select.value === '--') {
|
|
||||||
$edit.value = '';
|
|
||||||
} else $edit.value = $select.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
$save.addEventListener('click', async (event) => {
|
|
||||||
if (profileNames.includes($edit.value) && $select.value !== $edit.value) {
|
|
||||||
web.render(
|
|
||||||
web.empty($error),
|
|
||||||
`The profile "${web.escape($edit.value)}" already exists.`
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!$edit.value) {
|
|
||||||
web.render(web.empty($error), 'Profile names cannot be empty.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!$edit.value.match(/^[A-Za-z0-9_-]+$/)) {
|
|
||||||
web.render(
|
|
||||||
web.empty($error),
|
|
||||||
'Profile names can only contain letters, numbers, dashes and underscores.'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
await storage.set(['currentprofile'], $edit.value);
|
|
||||||
if ($select.value === '--') {
|
|
||||||
await storage.set(['profiles', $edit.value], {});
|
|
||||||
} else if ($select.value !== $edit.value) {
|
|
||||||
await storage.set(
|
|
||||||
['profiles', $edit.value],
|
|
||||||
await storage.get(['profiles', $select.value], {})
|
|
||||||
);
|
|
||||||
await storage.set(['profiles', $select.value], undefined);
|
await storage.set(['profiles', $select.value], undefined);
|
||||||
}
|
await storage.set(
|
||||||
env.reload();
|
['currentprofile'],
|
||||||
});
|
profileNames.find((profile) => profile !== $select.value) || 'default'
|
||||||
|
);
|
||||||
|
env.reload();
|
||||||
|
});
|
||||||
|
|
||||||
$delete.addEventListener('click', async (event) => {
|
_$profileConfig = web.render(
|
||||||
await storage.set(['profiles', $select.value], undefined);
|
web.html`<div></div>`,
|
||||||
await storage.set(
|
web.html`<p class="options-placeholder">
|
||||||
['currentprofile'],
|
|
||||||
profileNames.find((profile) => profile !== $select.value) || 'default'
|
|
||||||
);
|
|
||||||
env.reload();
|
|
||||||
});
|
|
||||||
|
|
||||||
_$profileConfig = web.render(
|
|
||||||
web.html`<div></div>`,
|
|
||||||
web.html`<p class="options-placeholder">
|
|
||||||
Profiles are used to switch entire configurations.
|
Profiles are used to switch entire configurations.
|
||||||
Here they can be selected, renamed or deleted.
|
Here they can be selected, renamed or deleted.
|
||||||
Profile names can only contain letters, numbers,
|
Profile names can only contain letters, numbers,
|
||||||
@ -193,261 +194,268 @@ const openProfileMenu = async () => {
|
|||||||
Be careful - deleting a profile deletes all configuration
|
Be careful - deleting a profile deletes all configuration
|
||||||
related to it.
|
related to it.
|
||||||
</p>`,
|
</p>`,
|
||||||
web.render(
|
|
||||||
web.html`<label class="input-label"></label>`,
|
|
||||||
$select,
|
|
||||||
web.html`${await components.feather('chevron-down', { class: 'input-icon' })}`
|
|
||||||
),
|
|
||||||
web.render(
|
|
||||||
web.html`<label class="input-label"></label>`,
|
|
||||||
$edit,
|
|
||||||
web.html`${await components.feather('type', { class: 'input-icon' })}`
|
|
||||||
),
|
|
||||||
web.render(web.html`<p class="profile-actions"></p>`, $export, $import, $save, $delete),
|
|
||||||
$error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
web.render(web.empty($options), _$profileConfig);
|
|
||||||
};
|
|
||||||
$profile.addEventListener('click', () => openSidebarMenu('profile'));
|
|
||||||
|
|
||||||
// mods
|
|
||||||
|
|
||||||
const $modLists = {},
|
|
||||||
generators = {
|
|
||||||
options: async (mod) => {
|
|
||||||
const $fragment = document.createDocumentFragment();
|
|
||||||
for (const opt of mod.options) {
|
|
||||||
if (!opt.environments.includes(env.name)) continue;
|
|
||||||
web.render($fragment, await options[opt.type](mod, opt));
|
|
||||||
}
|
|
||||||
if (!mod.options.length) {
|
|
||||||
web.render($fragment, web.html`<p class="options-placeholder">No options.</p>`);
|
|
||||||
}
|
|
||||||
return $fragment;
|
|
||||||
},
|
|
||||||
mod: async (mod) => {
|
|
||||||
const $mod = web.html`<div class="mod" data-id="${web.escape(mod.id)}"></div>`,
|
|
||||||
$toggle = modComponents.toggle('', await registry.enabled(mod.id));
|
|
||||||
$toggle.addEventListener('change', async (event) => {
|
|
||||||
if (event.target.checked && mod.tags.includes('theme')) {
|
|
||||||
const mode = mod.tags.includes('light') ? 'light' : 'dark',
|
|
||||||
id = mod.id,
|
|
||||||
mods = await registry.list(
|
|
||||||
(mod) =>
|
|
||||||
mod.environments.includes(env.name) &&
|
|
||||||
mod.tags.includes('theme') &&
|
|
||||||
mod.tags.includes(mode) &&
|
|
||||||
mod.id !== id
|
|
||||||
);
|
|
||||||
for (const mod of mods) {
|
|
||||||
profileDB.set(['_mods', mod.id], false);
|
|
||||||
document.querySelector(
|
|
||||||
`[data-id="${web.escape(mod.id)}"] .toggle-check`
|
|
||||||
).checked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
profileDB.set(['_mods', mod.id], event.target.checked);
|
|
||||||
notifications.onChange();
|
|
||||||
});
|
|
||||||
$mod.addEventListener('click', () => openSidebarMenu(mod.id));
|
|
||||||
return web.render(
|
|
||||||
web.html`<article class="mod-container"></article>`,
|
|
||||||
web.render(
|
web.render(
|
||||||
$mod,
|
web.html`<label class="input-label"></label>`,
|
||||||
mod.preview
|
$select,
|
||||||
? modComponents.preview(
|
web.html`${await components.feather('chevron-down', { class: 'input-icon' })}`
|
||||||
mod.preview.startsWith('http')
|
),
|
||||||
? mod.preview
|
web.render(
|
||||||
: fs.localPath(`repo/${mod._dir}/${mod.preview}`)
|
web.html`<label class="input-label"></label>`,
|
||||||
)
|
$edit,
|
||||||
: '',
|
web.html`${await components.feather('type', { class: 'input-icon' })}`
|
||||||
web.render(
|
),
|
||||||
web.html`<div class="mod-body"></div>`,
|
web.render(
|
||||||
web.render(modComponents.title(mod.name), modComponents.version(mod.version)),
|
web.html`<p class="profile-actions"></p>`,
|
||||||
modComponents.tags(mod.tags),
|
$export,
|
||||||
modComponents.description(mod.description),
|
$import,
|
||||||
modComponents.authors(mod.authors),
|
$save,
|
||||||
mod.environments.includes(env.name) && !registry.core.includes(mod.id)
|
$delete
|
||||||
? $toggle
|
),
|
||||||
: ''
|
$error
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
modList: async (category, message = '') => {
|
web.render(web.empty($options), _$profileConfig);
|
||||||
if (!$modLists[category]) {
|
|
||||||
const $search = web.html`<input type="search" class="search"
|
|
||||||
placeholder="Search ('/' to focus)">`,
|
|
||||||
$list = web.html`<div class="mods-list"></div>`,
|
|
||||||
mods = await registry.list(
|
|
||||||
(mod) => mod.environments.includes(env.name) && mod.tags.includes(category)
|
|
||||||
);
|
|
||||||
web.addHotkeyListener(['/'], () => $search.focus());
|
|
||||||
$search.addEventListener('input', (event) => {
|
|
||||||
const query = $search.value.toLowerCase();
|
|
||||||
for (const $mod of $list.children) {
|
|
||||||
const matches = !query || $mod.innerText.toLowerCase().includes(query);
|
|
||||||
$mod.classList[matches ? 'remove' : 'add']('hidden');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for (const mod of mods) {
|
|
||||||
mod.tags = mod.tags.filter((tag) => tag !== category);
|
|
||||||
web.render($list, await generators.mod(mod));
|
|
||||||
mod.tags.unshift(category);
|
|
||||||
}
|
|
||||||
$modLists[category] = web.render(
|
|
||||||
web.html`<div></div>`,
|
|
||||||
web.render(
|
|
||||||
web.html`<label class="search-container"></label>`,
|
|
||||||
$search,
|
|
||||||
web.html`${await components.feather('search', { class: 'input-icon' })}`
|
|
||||||
),
|
|
||||||
message ? web.render(web.html`<p class="main-message"></p>`, message) : '',
|
|
||||||
$list
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return $modLists[category];
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
$profile.addEventListener('click', () => openSidebarMenu('profile'));
|
||||||
|
|
||||||
async function openModMenu(id) {
|
// mods
|
||||||
let $mod;
|
|
||||||
for (const $list of Object.values($modLists)) {
|
const $modLists = {},
|
||||||
$mod = $list.querySelector(`[data-id="${web.escape(id)}"]`);
|
generators = {
|
||||||
if ($mod) break;
|
options: async (mod) => {
|
||||||
|
const $fragment = document.createDocumentFragment();
|
||||||
|
for (const opt of mod.options) {
|
||||||
|
if (!opt.environments.includes(env.name)) continue;
|
||||||
|
web.render($fragment, await options[opt.type](mod, opt));
|
||||||
|
}
|
||||||
|
if (!mod.options.length) {
|
||||||
|
web.render($fragment, web.html`<p class="options-placeholder">No options.</p>`);
|
||||||
|
}
|
||||||
|
return $fragment;
|
||||||
|
},
|
||||||
|
mod: async (mod) => {
|
||||||
|
const $mod = web.html`<div class="mod" data-id="${web.escape(mod.id)}"></div>`,
|
||||||
|
$toggle = modComponents.toggle('', await registry.enabled(mod.id));
|
||||||
|
$toggle.addEventListener('change', async (event) => {
|
||||||
|
if (event.target.checked && mod.tags.includes('theme')) {
|
||||||
|
const mode = mod.tags.includes('light') ? 'light' : 'dark',
|
||||||
|
id = mod.id,
|
||||||
|
mods = await registry.list(
|
||||||
|
(mod) =>
|
||||||
|
mod.environments.includes(env.name) &&
|
||||||
|
mod.tags.includes('theme') &&
|
||||||
|
mod.tags.includes(mode) &&
|
||||||
|
mod.id !== id
|
||||||
|
);
|
||||||
|
for (const mod of mods) {
|
||||||
|
profileDB.set(['_mods', mod.id], false);
|
||||||
|
document.querySelector(
|
||||||
|
`[data-id="${web.escape(mod.id)}"] .toggle-check`
|
||||||
|
).checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
profileDB.set(['_mods', mod.id], event.target.checked);
|
||||||
|
notifications.onChange();
|
||||||
|
});
|
||||||
|
$mod.addEventListener('click', () => openSidebarMenu(mod.id));
|
||||||
|
return web.render(
|
||||||
|
web.html`<article class="mod-container"></article>`,
|
||||||
|
web.render(
|
||||||
|
$mod,
|
||||||
|
mod.preview
|
||||||
|
? modComponents.preview(
|
||||||
|
mod.preview.startsWith('http')
|
||||||
|
? mod.preview
|
||||||
|
: fs.localPath(`repo/${mod._dir}/${mod.preview}`)
|
||||||
|
)
|
||||||
|
: '',
|
||||||
|
web.render(
|
||||||
|
web.html`<div class="mod-body"></div>`,
|
||||||
|
web.render(modComponents.title(mod.name), modComponents.version(mod.version)),
|
||||||
|
modComponents.tags(mod.tags),
|
||||||
|
modComponents.description(mod.description),
|
||||||
|
modComponents.authors(mod.authors),
|
||||||
|
mod.environments.includes(env.name) && !registry.core.includes(mod.id)
|
||||||
|
? $toggle
|
||||||
|
: ''
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
modList: async (category, message = '') => {
|
||||||
|
if (!$modLists[category]) {
|
||||||
|
const $search = web.html`<input type="search" class="search"
|
||||||
|
placeholder="Search ('/' to focus)">`,
|
||||||
|
$list = web.html`<div class="mods-list"></div>`,
|
||||||
|
mods = await registry.list(
|
||||||
|
(mod) => mod.environments.includes(env.name) && mod.tags.includes(category)
|
||||||
|
);
|
||||||
|
web.addHotkeyListener(['/'], () => $search.focus());
|
||||||
|
$search.addEventListener('input', (event) => {
|
||||||
|
const query = $search.value.toLowerCase();
|
||||||
|
for (const $mod of $list.children) {
|
||||||
|
const matches = !query || $mod.innerText.toLowerCase().includes(query);
|
||||||
|
$mod.classList[matches ? 'remove' : 'add']('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (const mod of mods) {
|
||||||
|
mod.tags = mod.tags.filter((tag) => tag !== category);
|
||||||
|
web.render($list, await generators.mod(mod));
|
||||||
|
mod.tags.unshift(category);
|
||||||
|
}
|
||||||
|
$modLists[category] = web.render(
|
||||||
|
web.html`<div></div>`,
|
||||||
|
web.render(
|
||||||
|
web.html`<label class="search-container"></label>`,
|
||||||
|
$search,
|
||||||
|
web.html`${await components.feather('search', { class: 'input-icon' })}`
|
||||||
|
),
|
||||||
|
message ? web.render(web.html`<p class="main-message"></p>`, message) : '',
|
||||||
|
$list
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $modLists[category];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async function openModMenu(id) {
|
||||||
|
let $mod;
|
||||||
|
for (const $list of Object.values($modLists)) {
|
||||||
|
$mod = $list.querySelector(`[data-id="${web.escape(id)}"]`);
|
||||||
|
if ($mod) break;
|
||||||
|
}
|
||||||
|
const mod = await registry.get(id);
|
||||||
|
if (!$mod || !mod || $mod.className === 'mod-selected') return;
|
||||||
|
|
||||||
|
$mod.className = 'mod-selected';
|
||||||
|
const fragment = [
|
||||||
|
web.render(modComponents.title(mod.name), modComponents.version(mod.version)),
|
||||||
|
modComponents.tags(mod.tags),
|
||||||
|
await generators.options(mod),
|
||||||
|
];
|
||||||
|
web.render(web.empty($options), ...fragment);
|
||||||
}
|
}
|
||||||
const mod = await registry.get(id);
|
|
||||||
if (!$mod || !mod || $mod.className === 'mod-selected') return;
|
|
||||||
|
|
||||||
$mod.className = 'mod-selected';
|
// views
|
||||||
const fragment = [
|
|
||||||
web.render(modComponents.title(mod.name), modComponents.version(mod.version)),
|
|
||||||
modComponents.tags(mod.tags),
|
|
||||||
await generators.options(mod),
|
|
||||||
];
|
|
||||||
web.render(web.empty($options), ...fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
// views
|
const $notionNavItem = web.html`<h1 class="nav-notion">
|
||||||
|
|
||||||
const $notionNavItem = web.html`<h1 class="nav-notion">
|
|
||||||
${(await fs.getText('media/colour.svg')).replace(
|
${(await fs.getText('media/colour.svg')).replace(
|
||||||
/width="\d+" height="\d+"/,
|
/width="\d+" height="\d+"/,
|
||||||
`class="nav-notion-icon"`
|
`class="nav-notion-icon"`
|
||||||
)}
|
)}
|
||||||
<span>notion-enhancer</span>
|
<span>notion-enhancer</span>
|
||||||
</h1>`;
|
</h1>`;
|
||||||
$notionNavItem.addEventListener('click', env.focusNotion);
|
$notionNavItem.addEventListener('click', env.focusNotion);
|
||||||
|
|
||||||
const $coreNavItem = web.html`<a href="?view=core" class="nav-item">core</a>`,
|
const $coreNavItem = web.html`<a href="?view=core" class="nav-item">core</a>`,
|
||||||
$extensionsNavItem = web.html`<a href="?view=extensions" class="nav-item">extensions</a>`,
|
$extensionsNavItem = web.html`<a href="?view=extensions" class="nav-item">extensions</a>`,
|
||||||
$themesNavItem = web.html`<a href="?view=themes" class="nav-item">themes</a>`,
|
$themesNavItem = web.html`<a href="?view=themes" class="nav-item">themes</a>`,
|
||||||
$integrationsNavItem = web.html`<a href="?view=integrations" class="nav-item">integrations</a>`,
|
$integrationsNavItem = web.html`<a href="?view=integrations" class="nav-item">integrations</a>`,
|
||||||
$changelogNavItem = web.html`<button class="nav-item nav-changelog">
|
$changelogNavItem = web.html`<button class="nav-item nav-changelog">
|
||||||
${await components.feather('clock', { class: 'nav-changelog-icon' })}
|
${await components.feather('clock', { class: 'nav-changelog-icon' })}
|
||||||
</button>`;
|
</button>`;
|
||||||
$changelogNavItem.addEventListener('click', () => {
|
$changelogNavItem.addEventListener('click', () => {
|
||||||
$changelogModal.scrollTop = 0;
|
$changelogModal.scrollTop = 0;
|
||||||
$changelogModal.classList.add('modal-visible');
|
$changelogModal.classList.add('modal-visible');
|
||||||
});
|
});
|
||||||
|
|
||||||
web.render(
|
|
||||||
document.body,
|
|
||||||
web.render(
|
web.render(
|
||||||
web.html`<div class="body-container"></div>`,
|
document.body,
|
||||||
web.render(
|
web.render(
|
||||||
web.html`<div class="content-container"></div>`,
|
web.html`<div class="body-container"></div>`,
|
||||||
web.render(
|
web.render(
|
||||||
web.html`<nav class="nav"></nav>`,
|
web.html`<div class="content-container"></div>`,
|
||||||
$notionNavItem,
|
web.render(
|
||||||
$coreNavItem,
|
web.html`<nav class="nav"></nav>`,
|
||||||
$extensionsNavItem,
|
$notionNavItem,
|
||||||
$themesNavItem,
|
$coreNavItem,
|
||||||
$integrationsNavItem,
|
$extensionsNavItem,
|
||||||
web.html`<a href="https://notion-enhancer.github.io" target="_blank" class="nav-item">docs</a>`,
|
$themesNavItem,
|
||||||
web.html`<a href="https://discord.gg/sFWPXtA" target="_blank" class="nav-item">community</a>`,
|
$integrationsNavItem,
|
||||||
$changelogNavItem
|
web.html`<a href="https://notion-enhancer.github.io" target="_blank" class="nav-item">docs</a>`,
|
||||||
|
web.html`<a href="https://discord.gg/sFWPXtA" target="_blank" class="nav-item">community</a>`,
|
||||||
|
$changelogNavItem
|
||||||
|
),
|
||||||
|
$main
|
||||||
),
|
),
|
||||||
$main
|
web.render($sidebar, $profile, $options)
|
||||||
),
|
)
|
||||||
web.render($sidebar, $profile, $options)
|
);
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
function selectNavItem($item) {
|
function selectNavItem($item) {
|
||||||
for (const $selected of document.querySelectorAll('.nav-item-selected')) {
|
for (const $selected of document.querySelectorAll('.nav-item-selected')) {
|
||||||
$selected.className = 'nav-item';
|
$selected.className = 'nav-item';
|
||||||
|
}
|
||||||
|
$item.className = 'nav-item-selected';
|
||||||
}
|
}
|
||||||
$item.className = 'nav-item-selected';
|
|
||||||
}
|
|
||||||
|
|
||||||
await generators.modList(
|
await generators.modList(
|
||||||
'core',
|
'core',
|
||||||
`Core mods provide the basics required for
|
`Core mods provide the basics required for
|
||||||
all other extensions and themes to work. They
|
all other extensions and themes to work. They
|
||||||
can't be disabled, but they can be configured
|
can't be disabled, but they can be configured
|
||||||
- just click on a mod to access its options.`
|
- just click on a mod to access its options.`
|
||||||
);
|
);
|
||||||
router.addView('core', async () => {
|
router.addView('core', async () => {
|
||||||
web.empty($main);
|
web.empty($main);
|
||||||
selectNavItem($coreNavItem);
|
selectNavItem($coreNavItem);
|
||||||
return web.render($main, await generators.modList('core'));
|
return web.render($main, await generators.modList('core'));
|
||||||
});
|
});
|
||||||
|
|
||||||
await generators.modList(
|
await generators.modList(
|
||||||
'extension',
|
'extension',
|
||||||
`Extensions build on the functionality and layout of
|
`Extensions build on the functionality and layout of
|
||||||
the Notion client, modifying and interacting with
|
the Notion client, modifying and interacting with
|
||||||
existing interfaces.`
|
existing interfaces.`
|
||||||
);
|
);
|
||||||
router.addView('extensions', async () => {
|
router.addView('extensions', async () => {
|
||||||
web.empty($main);
|
web.empty($main);
|
||||||
selectNavItem($extensionsNavItem);
|
selectNavItem($extensionsNavItem);
|
||||||
return web.render($main, await generators.modList('extension'));
|
return web.render($main, await generators.modList('extension'));
|
||||||
});
|
});
|
||||||
|
|
||||||
await generators.modList(
|
await generators.modList(
|
||||||
'theme',
|
'theme',
|
||||||
`Themes change Notion's colour scheme.
|
`Themes change Notion's colour scheme.
|
||||||
Dark themes will only work when Notion is in dark mode,
|
Dark themes will only work when Notion is in dark mode,
|
||||||
and light themes will only work when Notion is in light mode.
|
and light themes will only work when Notion is in light mode.
|
||||||
Only one theme of each mode can be enabled at a time.`
|
Only one theme of each mode can be enabled at a time.`
|
||||||
);
|
);
|
||||||
router.addView('themes', async () => {
|
router.addView('themes', async () => {
|
||||||
web.empty($main);
|
web.empty($main);
|
||||||
selectNavItem($themesNavItem);
|
selectNavItem($themesNavItem);
|
||||||
return web.render($main, await generators.modList('theme'));
|
return web.render($main, await generators.modList('theme'));
|
||||||
});
|
});
|
||||||
|
|
||||||
await generators.modList(
|
await generators.modList(
|
||||||
'integration',
|
'integration',
|
||||||
web.html`<span class="danger">Integrations are extensions that use an unofficial API
|
web.html`<span class="danger">Integrations are extensions that use an unofficial API
|
||||||
to access and modify content. They are used just like
|
to access and modify content. They are used just like
|
||||||
normal extensions, but may be more dangerous to use.</span>`
|
normal extensions, but may be more dangerous to use.</span>`
|
||||||
);
|
);
|
||||||
router.addView('integrations', async () => {
|
router.addView('integrations', async () => {
|
||||||
web.empty($main);
|
web.empty($main);
|
||||||
selectNavItem($integrationsNavItem);
|
selectNavItem($integrationsNavItem);
|
||||||
return web.render($main, await generators.modList('integration'));
|
return web.render($main, await generators.modList('integration'));
|
||||||
});
|
});
|
||||||
|
|
||||||
router.setDefaultView('extensions');
|
router.setDefaultView('extensions');
|
||||||
|
|
||||||
router.addQueryListener('id', openSidebarMenu);
|
router.addQueryListener('id', openSidebarMenu);
|
||||||
async function openSidebarMenu(id) {
|
async function openSidebarMenu(id) {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
id = web.escape(id);
|
id = web.escape(id);
|
||||||
|
|
||||||
const deselectedMods = `.mod-selected:not([data-id="${id}"])`;
|
const deselectedMods = `.mod-selected:not([data-id="${id}"])`;
|
||||||
for (const $list of Object.values($modLists)) {
|
for (const $list of Object.values($modLists)) {
|
||||||
for (const $selected of $list.querySelectorAll(deselectedMods)) {
|
for (const $selected of $list.querySelectorAll(deselectedMods)) {
|
||||||
$selected.className = 'mod';
|
$selected.className = 'mod';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
router.updateQuery(`?id=${id}`);
|
||||||
router.updateQuery(`?id=${id}`);
|
|
||||||
|
|
||||||
if (id === 'profile') {
|
if (id === 'profile') {
|
||||||
openProfileMenu();
|
openProfileMenu();
|
||||||
} else openModMenu(id);
|
} else openModMenu(id);
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
|
@ -10,8 +10,6 @@ import { tw } from './styles.mjs';
|
|||||||
const notificationsURL = 'https://notion-enhancer.github.io/notifications.json';
|
const notificationsURL = 'https://notion-enhancer.github.io/notifications.json';
|
||||||
export const notifications = {
|
export const notifications = {
|
||||||
$container: web.html`<div class="notifications-container"></div>`,
|
$container: web.html`<div class="notifications-container"></div>`,
|
||||||
cache: await storage.get(['notifications'], []),
|
|
||||||
provider: await fs.getJSON(notificationsURL),
|
|
||||||
async add({ icon, message, id = undefined, color = undefined, link = undefined }) {
|
async add({ icon, message, id = undefined, color = undefined, link = undefined }) {
|
||||||
const $notification = link
|
const $notification = link
|
||||||
? web.html`<a
|
? web.html`<a
|
||||||
@ -59,25 +57,40 @@ export const notifications = {
|
|||||||
$notification.addEventListener('click', env.reload);
|
$notification.addEventListener('click', env.reload);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
web.render(document.body, notifications.$container);
|
|
||||||
for (const notification of notifications.provider) {
|
|
||||||
const cached = notifications.cache.includes(notification.id),
|
|
||||||
versionMatches = notification.version === env.version,
|
|
||||||
envMatches = !notification.environments || notification.environments.includes(env.name);
|
|
||||||
if (!cached && versionMatches && envMatches) notifications.add(notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastReadChangelog = await storage.get(['last_read_changelog']),
|
(async () => {
|
||||||
$changelogModalButton = web.html`<button type="button" class="modal-button">
|
notifications.cache = await storage.get(['notifications'], []);
|
||||||
Accept & Continue
|
notifications.provider = await fs.getJSON(notificationsURL);
|
||||||
</button>`;
|
|
||||||
|
web.render(document.body, notifications.$container);
|
||||||
|
for (const notification of notifications.provider) {
|
||||||
|
const cached = notifications.cache.includes(notification.id),
|
||||||
|
versionMatches = notification.version === env.version,
|
||||||
|
envMatches = !notification.environments || notification.environments.includes(env.name);
|
||||||
|
if (!cached && versionMatches && envMatches) notifications.add(notification);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
export const $changelogModal = web.render(
|
export const $changelogModal = web.render(
|
||||||
web.html`<div class="modal" role="dialog" aria-modal="true">
|
web.html`<div class="modal" role="dialog" aria-modal="true">
|
||||||
<div class="modal-overlay" aria-hidden="true"></div>
|
<div class="modal-overlay" aria-hidden="true"></div>
|
||||||
</div>`,
|
</div>`
|
||||||
|
);
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const $changelogModalButton = web.html`<button type="button" class="modal-button">
|
||||||
|
Accept & Continue
|
||||||
|
</button>`;
|
||||||
|
$changelogModalButton.addEventListener('click', async () => {
|
||||||
|
$changelogModal.classList.remove('modal-visible');
|
||||||
|
await storage.set(['last_read_changelog'], env.version);
|
||||||
|
});
|
||||||
|
|
||||||
web.render(
|
web.render(
|
||||||
web.html`<div class="modal-box"></div>`,
|
$changelogModal,
|
||||||
web.html`<div class="modal-body">
|
web.render(
|
||||||
|
web.html`<div class="modal-box"></div>`,
|
||||||
|
web.html`<div class="modal-body">
|
||||||
<div class="modal-title">
|
<div class="modal-title">
|
||||||
${(await fs.getText('media/colour.svg')).replace(
|
${(await fs.getText('media/colour.svg')).replace(
|
||||||
/width="\d+" height="\d+"/,
|
/width="\d+" height="\d+"/,
|
||||||
@ -149,14 +162,13 @@ export const $changelogModal = web.render(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`,
|
</div>`,
|
||||||
web.render(web.html`<div class="modal-actions"></div>`, $changelogModalButton)
|
web.render(web.html`<div class="modal-actions"></div>`, $changelogModalButton)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
web.render(document.body, $changelogModal);
|
|
||||||
if (lastReadChangelog !== env.version) {
|
const lastReadChangelog = await storage.get(['last_read_changelog']);
|
||||||
$changelogModal.classList.add('modal-visible');
|
web.render(document.body, $changelogModal);
|
||||||
}
|
if (lastReadChangelog !== env.version) {
|
||||||
$changelogModalButton.addEventListener('click', async () => {
|
$changelogModal.classList.add('modal-visible');
|
||||||
$changelogModal.classList.remove('modal-visible');
|
}
|
||||||
await storage.set(['last_read_changelog'], env.version);
|
})();
|
||||||
});
|
|
||||||
|
@ -165,7 +165,7 @@ body,
|
|||||||
.notion-body.dark
|
.notion-body.dark
|
||||||
.notion-default-overlay-container
|
.notion-default-overlay-container
|
||||||
[style*='grid-template-columns: [boolean-start] 60px [boolean-end property-start] 120px [property-end opererator-start] 110px [operator-end value-start] auto [value-end menu-start] 32px [menu-end];'],
|
[style*='grid-template-columns: [boolean-start] 60px [boolean-end property-start] 120px [property-end opererator-start] 110px [operator-end value-start] auto [value-end menu-start] 32px [menu-end];'],
|
||||||
.notion-focusable[style*='background: rgb(80, 85, 88);'],
|
.notion-focusable[style*='background: rgb(80, 85, 88);']:not(.notion-help-button):not(.onboarding-checklist-button),
|
||||||
.notion-body:not(.dark)
|
.notion-body:not(.dark)
|
||||||
.notion-default-overlay-container
|
.notion-default-overlay-container
|
||||||
[style*='grid-template-columns: [boolean-start] 60px [boolean-end property-start] 120px [property-end opererator-start] 110px [operator-end value-start] auto [value-end menu-start] 32px [menu-end];']
|
[style*='grid-template-columns: [boolean-start] 60px [boolean-end property-start] 120px [property-end opererator-start] 110px [operator-end value-start] auto [value-end menu-start] 32px [menu-end];']
|
||||||
|
Loading…
Reference in New Issue
Block a user