mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-09 15:09:02 +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
|
* @namespace fmt
|
||||||
*/
|
*/
|
||||||
export const 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';
|
import './dep/prism.js';
|
||||||
/** syntax highlighting using https://prismjs.com/ */
|
/** syntax highlighting using https://prismjs.com/ */
|
||||||
fmt.Prism = Prism;
|
fmt.Prism = Prism;
|
||||||
@ -525,6 +528,18 @@ regexers.url = (str, err = () => {}) => {
|
|||||||
err(`invalid url ${str}`);
|
err(`invalid url ${str}`);
|
||||||
return env.ERROR;
|
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
|
* 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')
|
check('option.value', option.value, typeof option.value === 'number')
|
||||||
);
|
);
|
||||||
break;
|
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':
|
case 'file':
|
||||||
conditions.push(
|
conditions.push(
|
||||||
check(
|
check(
|
||||||
@ -778,17 +800,14 @@ registry.defaults = async (id) => {
|
|||||||
for (const opt of mod.options) {
|
for (const opt of mod.options) {
|
||||||
switch (opt.type) {
|
switch (opt.type) {
|
||||||
case 'toggle':
|
case 'toggle':
|
||||||
|
case 'text':
|
||||||
|
case 'number':
|
||||||
|
case 'color':
|
||||||
defaults[opt.key] = opt.value;
|
defaults[opt.key] = opt.value;
|
||||||
break;
|
break;
|
||||||
case 'select':
|
case 'select':
|
||||||
defaults[opt.key] = opt.values[0];
|
defaults[opt.key] = opt.values[0];
|
||||||
break;
|
break;
|
||||||
case 'text':
|
|
||||||
defaults[opt.key] = opt.value;
|
|
||||||
break;
|
|
||||||
case 'number':
|
|
||||||
defaults[opt.key] = opt.value;
|
|
||||||
break;
|
|
||||||
case 'file':
|
case 'file':
|
||||||
defaults[opt.key] = undefined;
|
defaults[opt.key] = undefined;
|
||||||
break;
|
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}`));
|
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
|
- documentation e.g. \_file
|
||||||
- complete/bugfix theming variables
|
- complete/bugfix theming variables
|
||||||
- color pickers
|
|
||||||
|
|
||||||
#### app-specific
|
#### app-specific
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ web.whenReady([sidebarSelector]).then(async () => {
|
|||||||
list: await fs.getJSON('https://notion-enhancer.github.io/notifications.json'),
|
list: await fs.getJSON('https://notion-enhancer.github.io/notifications.json'),
|
||||||
dismissed: await storage.get(_id, 'notifications', []),
|
dismissed: await storage.get(_id, 'notifications', []),
|
||||||
};
|
};
|
||||||
console.log($enhancerSidebarElement);
|
|
||||||
notifications.waiting = notifications.list.filter(
|
notifications.waiting = notifications.list.filter(
|
||||||
({ id }) => !notifications.dismissed.includes(id)
|
({ id }) => !notifications.dismissed.includes(id)
|
||||||
);
|
);
|
||||||
|
@ -250,6 +250,7 @@ main article img {
|
|||||||
.library--select_label,
|
.library--select_label,
|
||||||
.library--text_label,
|
.library--text_label,
|
||||||
.library--number_label,
|
.library--number_label,
|
||||||
|
.library--color_label,
|
||||||
.library--file_label {
|
.library--file_label {
|
||||||
margin: 0.6rem 0;
|
margin: 0.6rem 0;
|
||||||
display: block;
|
display: block;
|
||||||
@ -260,6 +261,7 @@ main article img {
|
|||||||
.library--select_label *,
|
.library--select_label *,
|
||||||
.library--text_label *,
|
.library--text_label *,
|
||||||
.library--number_label *,
|
.library--number_label *,
|
||||||
|
.library--color_label *,
|
||||||
.library--file_label * {
|
.library--file_label * {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
font-family: var(--theme--font_sans);
|
font-family: var(--theme--font_sans);
|
||||||
@ -282,6 +284,7 @@ label [data-icon='fa/solid/question-circle'] {
|
|||||||
.library--select_label > p,
|
.library--select_label > p,
|
||||||
.library--text_label > p,
|
.library--text_label > p,
|
||||||
.library--number_label > p,
|
.library--number_label > p,
|
||||||
|
.library--color_label > p,
|
||||||
.library--file_label > p {
|
.library--file_label > p {
|
||||||
margin: 0.6rem 0;
|
margin: 0.6rem 0;
|
||||||
}
|
}
|
||||||
@ -320,10 +323,11 @@ label [data-icon='fa/solid/question-circle'] {
|
|||||||
}
|
}
|
||||||
.library--toggle_label:focus-within .library--toggle,
|
.library--toggle_label:focus-within .library--toggle,
|
||||||
.library--file_label:focus-within .library--file,
|
.library--file_label:focus-within .library--file,
|
||||||
|
.library--color_label:focus-within .library--color,
|
||||||
.library--select_label .library--select:focus-within {
|
.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 {
|
.library--file_label input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
@ -343,6 +347,7 @@ label [data-icon='fa/solid/question-circle'] {
|
|||||||
.library--text_label textarea,
|
.library--text_label textarea,
|
||||||
.library--number_label input,
|
.library--number_label input,
|
||||||
.library--select_label .library--select,
|
.library--select_label .library--select,
|
||||||
|
.library--color_label .library--color,
|
||||||
.library--file_label .library--file {
|
.library--file_label .library--file {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
@ -351,35 +356,44 @@ label [data-icon='fa/solid/question-circle'] {
|
|||||||
border: none;
|
border: none;
|
||||||
box-shadow: var(--theme--input-border) 0px 0px 0px 1px inset;
|
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;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.library--color_label .library--color input {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
.library--select_label .library--select select option {
|
.library--select_label .library--select select option {
|
||||||
background: var(--theme--tag_select);
|
background: var(--theme--tag_select);
|
||||||
}
|
}
|
||||||
.library--select_label .library--select,
|
.library--select_label .library--select,
|
||||||
|
.library--color_label .library--color,
|
||||||
.library--file_label .library--file {
|
.library--file_label .library--file {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.library--select_label .library--select > :first-child,
|
.library--select_label .library--select > :first-child,
|
||||||
|
.library--color_label .library--color > :first-child,
|
||||||
.library--file_label .library--file > :first-child {
|
.library--file_label .library--file > :first-child {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
background: var(--theme--input-border);
|
background: var(--theme--input-border);
|
||||||
}
|
}
|
||||||
.library--select_label .library--select > :first-child svg,
|
.library--select_label .library--select > :first-child svg,
|
||||||
|
.library--color_label .library--color > :first-child svg,
|
||||||
.library--file_label .library--file > :first-child svg {
|
.library--file_label .library--file > :first-child svg {
|
||||||
width: 0.9em;
|
width: 0.9em;
|
||||||
margin: auto 0;
|
margin: auto 0;
|
||||||
}
|
}
|
||||||
.library--select_label .library--select > :first-child svg *,
|
.library--select_label .library--select > :first-child svg *,
|
||||||
|
.library--color_label .library--color > :first-child svg *,
|
||||||
.library--file_label .library--file > :first-child svg * {
|
.library--file_label .library--file > :first-child svg * {
|
||||||
color: var(--theme--input_icon);
|
color: var(--theme--input_icon);
|
||||||
}
|
}
|
||||||
.library--select_label .library--select > :last-child,
|
.library--select_label .library--select > :last-child,
|
||||||
|
.library--color_label .library--color > :last-child,
|
||||||
.library--file_label .library--file > :last-child {
|
.library--file_label .library--file > :last-child {
|
||||||
margin: auto 0;
|
margin: auto 0;
|
||||||
padding: 6px 8px;
|
padding: 6px 8px;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const _id = 'a6621988-551d-495a-97d8-3c568bca2e9e';
|
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 mod of await registry.get((mod) => registry.isEnabled(mod.id))) {
|
||||||
for (const sheet of mod.css?.menu || []) {
|
for (const sheet of mod.css?.menu || []) {
|
||||||
@ -232,6 +232,46 @@ components.options = {
|
|||||||
if (tooltip) web.addTooltip(opt.querySelector('[data-tooltip]'), tooltip);
|
if (tooltip) web.addTooltip(opt.querySelector('[data-tooltip]'), tooltip);
|
||||||
return opt;
|
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 }) {
|
async file(id, { key, label, tooltip, extensions }) {
|
||||||
const state = await storage.get(id, key),
|
const state = await storage.get(id, key),
|
||||||
opt = web.createElement(web.html`
|
opt = web.createElement(web.html`
|
||||||
@ -295,15 +335,13 @@ const actionButtons = {
|
|||||||
_reloadTriggered: false,
|
_reloadTriggered: false,
|
||||||
async reload($fragment = document) {
|
async reload($fragment = document) {
|
||||||
let $reload = $fragment.querySelector('[data-reload]');
|
let $reload = $fragment.querySelector('[data-reload]');
|
||||||
if (!$reload) {
|
if (!$reload && this._reloadTriggered) {
|
||||||
$reload = web.createElement(web.html`
|
$reload = web.createElement(web.html`
|
||||||
<button class="action--alert" data-reload>
|
<button class="action--alert" data-reload>
|
||||||
<span><i data-icon="fa/solid/redo"></i></span>
|
<span><i data-icon="fa/solid/redo"></i></span>
|
||||||
<span>reload tabs to apply changes</span>
|
<span>reload tabs to apply changes</span>
|
||||||
</button>`);
|
</button>`);
|
||||||
$reload.addEventListener('click', env.reloadTabs);
|
$reload.addEventListener('click', env.reloadTabs);
|
||||||
}
|
|
||||||
if (this._reloadTriggered) {
|
|
||||||
$fragment.querySelector('.action--buttons').append($reload);
|
$fragment.querySelector('.action--buttons').append($reload);
|
||||||
await new Promise((res, rej) => requestAnimationFrame(res));
|
await new Promise((res, rej) => requestAnimationFrame(res));
|
||||||
$reload.dataset.triggered = true;
|
$reload.dataset.triggered = true;
|
||||||
@ -311,19 +349,19 @@ const actionButtons = {
|
|||||||
},
|
},
|
||||||
async clearFilters($fragment = document) {
|
async clearFilters($fragment = document) {
|
||||||
let $clearFilters = $fragment.querySelector('[data-clear-filters]');
|
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();
|
const search = router.getSearch();
|
||||||
if (search.get('tag') || search.has('enabled') || search.has('disabled')) {
|
if (search.get('tag') || search.has('enabled') || search.has('disabled')) {
|
||||||
$fragment.querySelector('.action--buttons').append($clearFilters);
|
if (!$clearFilters) {
|
||||||
await new Promise((res, rej) => requestAnimationFrame(res));
|
$clearFilters = web.createElement(web.html`
|
||||||
$clearFilters.dataset.triggered = true;
|
<a class="action--alert" href="?view=library" data-clear-filters>
|
||||||
} else $clearFilters.remove();
|
<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) => {
|
storage.addChangeListener(async (event) => {
|
||||||
@ -395,22 +433,24 @@ router.addView(
|
|||||||
.querySelector(`.action--buttons > [href="?view=library&${filter}"]`)
|
.querySelector(`.action--buttons > [href="?view=library&${filter}"]`)
|
||||||
.classList[active ? 'add' : 'remove']('action--active');
|
.classList[active ? 'add' : 'remove']('action--active');
|
||||||
}
|
}
|
||||||
for (const card of document.querySelectorAll('main > .library--card')) {
|
const visible = new Set();
|
||||||
const { tags } = (await registry.get()).find((mod) => mod.id === card.dataset.mod),
|
for (const mod of await registry.get()) {
|
||||||
isEnabled = await registry.isEnabled(card.dataset.mod);
|
const isEnabled = await registry.isEnabled(mod.id),
|
||||||
if (
|
filterConditions =
|
||||||
(search.has('tag') ? tags.includes(search.get('tag')) : true) &&
|
(search.has('tag') ? mod.tags.includes(search.get('tag')) : true) &&
|
||||||
(search.has('enabled') && search.has('disabled')
|
(search.has('enabled') && search.has('disabled')
|
||||||
? true
|
? true
|
||||||
: search.has('enabled')
|
: search.has('enabled')
|
||||||
? isEnabled
|
? isEnabled
|
||||||
: search.has('disabled')
|
: search.has('disabled')
|
||||||
? !isEnabled
|
? !isEnabled
|
||||||
: true)
|
: true);
|
||||||
) {
|
if (filterConditions) visible.add(mod.id);
|
||||||
card.style.display = '';
|
|
||||||
} else card.style.display = 'none';
|
|
||||||
}
|
}
|
||||||
|
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();
|
actionButtons.clearFilters();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user