mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-06 21:49:03 +00:00
add new colour picker option
This commit is contained in:
parent
6f3c1691c4
commit
99c166a1ac
@ -394,6 +394,9 @@ web.addTooltip = ($element, text) => {
|
||||
* @namespace fmt
|
||||
*/
|
||||
export const fmt = {};
|
||||
import './dep/jscolor.min.js';
|
||||
/** color picker with alpha channel using https://jscolor.com/ */
|
||||
fmt.JSColor = JSColor;
|
||||
import './dep/prism.js';
|
||||
/** syntax highlighting using https://prismjs.com/ */
|
||||
fmt.Prism = Prism;
|
||||
@ -525,6 +528,18 @@ regexers.url = (str, err = () => {}) => {
|
||||
err(`invalid url ${str}`);
|
||||
return env.ERROR;
|
||||
};
|
||||
/**
|
||||
* check for a valid color (https://regexr.com/39cgj)
|
||||
* @param {string} str - the string to test
|
||||
* @param {function} err - a callback to execute if the test fails
|
||||
* @returns {boolean | env.ERROR} true or the env.ERROR constant
|
||||
*/
|
||||
regexers.color = (str, err = () => {}) => {
|
||||
const match = str.match(/^(?:#|0x)(?:[a-f0-9]{3}|[a-f0-9]{6})\b|(?:rgb|hsl)a?\([^\)]*\)$/i);
|
||||
if (match && match.length) return true;
|
||||
err(`invalid color ${str}`);
|
||||
return env.ERROR;
|
||||
};
|
||||
|
||||
/**
|
||||
* an api for interacting with the enhancer's repository of mods
|
||||
@ -704,6 +719,13 @@ registry.validate = async (mod, err, check) => {
|
||||
check('option.value', option.value, typeof option.value === 'number')
|
||||
);
|
||||
break;
|
||||
case 'color':
|
||||
conditions.push(
|
||||
check('option.value', option.value, typeof option.value === 'string').then(
|
||||
(color) => (color === env.ERROR ? env.ERROR : regexers.color(color, err))
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'file':
|
||||
conditions.push(
|
||||
check(
|
||||
@ -778,17 +800,14 @@ registry.defaults = async (id) => {
|
||||
for (const opt of mod.options) {
|
||||
switch (opt.type) {
|
||||
case 'toggle':
|
||||
case 'text':
|
||||
case 'number':
|
||||
case 'color':
|
||||
defaults[opt.key] = opt.value;
|
||||
break;
|
||||
case 'select':
|
||||
defaults[opt.key] = opt.values[0];
|
||||
break;
|
||||
case 'text':
|
||||
defaults[opt.key] = opt.value;
|
||||
break;
|
||||
case 'number':
|
||||
defaults[opt.key] = opt.value;
|
||||
break;
|
||||
case 'file':
|
||||
defaults[opt.key] = undefined;
|
||||
break;
|
||||
|
1
extension/dep/jscolor.min.js
vendored
Normal file
1
extension/dep/jscolor.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -16,5 +16,10 @@ import(chrome.runtime.getURL('api.js')).then(({ web, registry }) => {
|
||||
import(chrome.runtime.getURL(`repo/${mod._dir}/${script}`));
|
||||
}
|
||||
}
|
||||
const errors = await registry.errors();
|
||||
if (errors.length) {
|
||||
console.log('notion-enhancer errors:');
|
||||
console.table(errors);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
- documentation e.g. \_file
|
||||
- complete/bugfix theming variables
|
||||
- color pickers
|
||||
|
||||
#### app-specific
|
||||
|
||||
|
@ -25,7 +25,6 @@ web.whenReady([sidebarSelector]).then(async () => {
|
||||
list: await fs.getJSON('https://notion-enhancer.github.io/notifications.json'),
|
||||
dismissed: await storage.get(_id, 'notifications', []),
|
||||
};
|
||||
console.log($enhancerSidebarElement);
|
||||
notifications.waiting = notifications.list.filter(
|
||||
({ id }) => !notifications.dismissed.includes(id)
|
||||
);
|
||||
|
@ -250,6 +250,7 @@ main article img {
|
||||
.library--select_label,
|
||||
.library--text_label,
|
||||
.library--number_label,
|
||||
.library--color_label,
|
||||
.library--file_label {
|
||||
margin: 0.6rem 0;
|
||||
display: block;
|
||||
@ -260,6 +261,7 @@ main article img {
|
||||
.library--select_label *,
|
||||
.library--text_label *,
|
||||
.library--number_label *,
|
||||
.library--color_label *,
|
||||
.library--file_label * {
|
||||
appearance: none;
|
||||
font-family: var(--theme--font_sans);
|
||||
@ -282,6 +284,7 @@ label [data-icon='fa/solid/question-circle'] {
|
||||
.library--select_label > p,
|
||||
.library--text_label > p,
|
||||
.library--number_label > p,
|
||||
.library--color_label > p,
|
||||
.library--file_label > p {
|
||||
margin: 0.6rem 0;
|
||||
}
|
||||
@ -320,10 +323,11 @@ label [data-icon='fa/solid/question-circle'] {
|
||||
}
|
||||
.library--toggle_label:focus-within .library--toggle,
|
||||
.library--file_label:focus-within .library--file,
|
||||
.library--color_label:focus-within .library--color,
|
||||
.library--select_label .library--select:focus-within {
|
||||
outline: solid thin;
|
||||
outline: -webkit-focus-ring-color auto 1px;
|
||||
}
|
||||
.library--toggle_label input[type='checkbox'],
|
||||
.library--toggle_label input,
|
||||
.library--file_label input {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
@ -343,6 +347,7 @@ label [data-icon='fa/solid/question-circle'] {
|
||||
.library--text_label textarea,
|
||||
.library--number_label input,
|
||||
.library--select_label .library--select,
|
||||
.library--color_label .library--color,
|
||||
.library--file_label .library--file {
|
||||
width: 100%;
|
||||
padding: 6px 8px;
|
||||
@ -351,35 +356,44 @@ label [data-icon='fa/solid/question-circle'] {
|
||||
border: none;
|
||||
box-shadow: var(--theme--input-border) 0px 0px 0px 1px inset;
|
||||
}
|
||||
.library--select_label .library--select select {
|
||||
.library--select_label .library--select select,
|
||||
.library--color_label .library--color input {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.library--color_label .library--color input {
|
||||
border-radius: 0;
|
||||
}
|
||||
.library--select_label .library--select select option {
|
||||
background: var(--theme--tag_select);
|
||||
}
|
||||
.library--select_label .library--select,
|
||||
.library--color_label .library--color,
|
||||
.library--file_label .library--file {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
.library--select_label .library--select > :first-child,
|
||||
.library--color_label .library--color > :first-child,
|
||||
.library--file_label .library--file > :first-child {
|
||||
display: flex;
|
||||
padding: 6px 8px;
|
||||
background: var(--theme--input-border);
|
||||
}
|
||||
.library--select_label .library--select > :first-child svg,
|
||||
.library--color_label .library--color > :first-child svg,
|
||||
.library--file_label .library--file > :first-child svg {
|
||||
width: 0.9em;
|
||||
margin: auto 0;
|
||||
}
|
||||
.library--select_label .library--select > :first-child svg *,
|
||||
.library--color_label .library--color > :first-child svg *,
|
||||
.library--file_label .library--file > :first-child svg * {
|
||||
color: var(--theme--input_icon);
|
||||
}
|
||||
.library--select_label .library--select > :last-child,
|
||||
.library--color_label .library--color > :last-child,
|
||||
.library--file_label .library--file > :last-child {
|
||||
margin: auto 0;
|
||||
padding: 6px 8px;
|
||||
|
@ -7,7 +7,7 @@
|
||||
'use strict';
|
||||
|
||||
const _id = 'a6621988-551d-495a-97d8-3c568bca2e9e';
|
||||
import { env, storage, web, fmt, fs, registry } from '../../api.js';
|
||||
import { env, storage, web, fmt, fs, registry, regexers } from '../../api.js';
|
||||
|
||||
for (const mod of await registry.get((mod) => registry.isEnabled(mod.id))) {
|
||||
for (const sheet of mod.css?.menu || []) {
|
||||
@ -232,6 +232,46 @@ components.options = {
|
||||
if (tooltip) web.addTooltip(opt.querySelector('[data-tooltip]'), tooltip);
|
||||
return opt;
|
||||
},
|
||||
async color(id, { key, label, tooltip }) {
|
||||
const state = await storage.get(id, key),
|
||||
opt = web.createElement(web.html`
|
||||
<label for="color--${web.escapeHtml(`${id}.${key}`)}" class="library--color_label">
|
||||
<p class="library--color_title">
|
||||
<span data-tooltip>${web.escapeHtml(label)}
|
||||
<i data-icon="fa/solid/question-circle"></i>
|
||||
</span>
|
||||
<p class="library--color">
|
||||
<span><i data-icon="fa/solid/eye-dropper"></i></span>
|
||||
<input type="text" id="color--${web.escapeHtml(`${id}.${key}`)}"/>
|
||||
</p>
|
||||
</label>`);
|
||||
const $fill = opt.querySelector('input'),
|
||||
paintInput = () => {
|
||||
$fill.style.background = picker.toBackground();
|
||||
$fill.style.color = picker.isLight() ? '#000' : '#fff';
|
||||
},
|
||||
picker = new fmt.JSColor($fill, {
|
||||
value: state,
|
||||
previewSize: 0,
|
||||
borderRadius: 3,
|
||||
borderColor: 'var(--theme--divider)',
|
||||
controlBorderColor: 'var(--theme--divider)',
|
||||
backgroundColor: 'var(--theme--page)',
|
||||
onInput() {
|
||||
paintInput();
|
||||
},
|
||||
onChange() {
|
||||
paintInput();
|
||||
storage.set(id, key, this.toRGBAString());
|
||||
},
|
||||
});
|
||||
paintInput();
|
||||
opt.addEventListener('click', (event) => {
|
||||
picker.show();
|
||||
});
|
||||
if (tooltip) web.addTooltip(opt.querySelector('[data-tooltip]'), tooltip);
|
||||
return opt;
|
||||
},
|
||||
async file(id, { key, label, tooltip, extensions }) {
|
||||
const state = await storage.get(id, key),
|
||||
opt = web.createElement(web.html`
|
||||
@ -295,15 +335,13 @@ const actionButtons = {
|
||||
_reloadTriggered: false,
|
||||
async reload($fragment = document) {
|
||||
let $reload = $fragment.querySelector('[data-reload]');
|
||||
if (!$reload) {
|
||||
if (!$reload && this._reloadTriggered) {
|
||||
$reload = web.createElement(web.html`
|
||||
<button class="action--alert" data-reload>
|
||||
<span><i data-icon="fa/solid/redo"></i></span>
|
||||
<span>reload tabs to apply changes</span>
|
||||
</button>`);
|
||||
$reload.addEventListener('click', env.reloadTabs);
|
||||
}
|
||||
if (this._reloadTriggered) {
|
||||
$fragment.querySelector('.action--buttons').append($reload);
|
||||
await new Promise((res, rej) => requestAnimationFrame(res));
|
||||
$reload.dataset.triggered = true;
|
||||
@ -311,19 +349,19 @@ const actionButtons = {
|
||||
},
|
||||
async clearFilters($fragment = document) {
|
||||
let $clearFilters = $fragment.querySelector('[data-clear-filters]');
|
||||
if (!$clearFilters) {
|
||||
$clearFilters = web.createElement(web.html`
|
||||
<a class="action--alert" href="?view=library" data-clear-filters>
|
||||
<span><i data-icon="fa/solid/times"></i></span>
|
||||
<span>clear filters</span>
|
||||
</a>`);
|
||||
}
|
||||
const search = router.getSearch();
|
||||
if (search.get('tag') || search.has('enabled') || search.has('disabled')) {
|
||||
$fragment.querySelector('.action--buttons').append($clearFilters);
|
||||
await new Promise((res, rej) => requestAnimationFrame(res));
|
||||
$clearFilters.dataset.triggered = true;
|
||||
} else $clearFilters.remove();
|
||||
if (!$clearFilters) {
|
||||
$clearFilters = web.createElement(web.html`
|
||||
<a class="action--alert" href="?view=library" data-clear-filters>
|
||||
<span><i data-icon="fa/solid/times"></i></span>
|
||||
<span>clear filters</span>
|
||||
</a>`);
|
||||
$fragment.querySelector('.action--buttons').append($clearFilters);
|
||||
await new Promise((res, rej) => requestAnimationFrame(res));
|
||||
$clearFilters.dataset.triggered = true;
|
||||
}
|
||||
} else if ($clearFilters) $clearFilters.remove();
|
||||
},
|
||||
};
|
||||
storage.addChangeListener(async (event) => {
|
||||
@ -395,22 +433,24 @@ router.addView(
|
||||
.querySelector(`.action--buttons > [href="?view=library&${filter}"]`)
|
||||
.classList[active ? 'add' : 'remove']('action--active');
|
||||
}
|
||||
for (const card of document.querySelectorAll('main > .library--card')) {
|
||||
const { tags } = (await registry.get()).find((mod) => mod.id === card.dataset.mod),
|
||||
isEnabled = await registry.isEnabled(card.dataset.mod);
|
||||
if (
|
||||
(search.has('tag') ? tags.includes(search.get('tag')) : true) &&
|
||||
(search.has('enabled') && search.has('disabled')
|
||||
? true
|
||||
: search.has('enabled')
|
||||
? isEnabled
|
||||
: search.has('disabled')
|
||||
? !isEnabled
|
||||
: true)
|
||||
) {
|
||||
card.style.display = '';
|
||||
} else card.style.display = 'none';
|
||||
const visible = new Set();
|
||||
for (const mod of await registry.get()) {
|
||||
const isEnabled = await registry.isEnabled(mod.id),
|
||||
filterConditions =
|
||||
(search.has('tag') ? mod.tags.includes(search.get('tag')) : true) &&
|
||||
(search.has('enabled') && search.has('disabled')
|
||||
? true
|
||||
: search.has('enabled')
|
||||
? isEnabled
|
||||
: search.has('disabled')
|
||||
? !isEnabled
|
||||
: true);
|
||||
if (filterConditions) visible.add(mod.id);
|
||||
}
|
||||
for (const card of document.querySelectorAll('main > .library--card'))
|
||||
card.style.display = 'none';
|
||||
for (const card of document.querySelectorAll('main > .library--card'))
|
||||
if (visible.has(card.dataset.mod)) card.style.display = '';
|
||||
actionButtons.clearFilters();
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user