mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-04 04:39:03 +00:00
feat(menu): profile deletion via confirmation popup
This commit is contained in:
parent
23834475c0
commit
72332acc58
@ -693,13 +693,13 @@ const styleAccents = () => {
|
||||
"rgb(211, 79, 67)",
|
||||
"rgb(205, 73, 69)",
|
||||
],
|
||||
secondaryHover = cssVariable({
|
||||
name: "accent-secondary_hover",
|
||||
value: "rgba(235, 87, 87, 0.1)",
|
||||
}),
|
||||
secondaryContrast = cssVariable({
|
||||
name: "accent-secondary_contrast",
|
||||
value: "white",
|
||||
}),
|
||||
secondaryTransparent = cssVariable({
|
||||
name: "accent-secondary_transparent",
|
||||
value: "rgba(235, 87, 87, 0.1)",
|
||||
});
|
||||
overrideStyle({
|
||||
property: "color",
|
||||
@ -746,7 +746,7 @@ const styleAccents = () => {
|
||||
});
|
||||
overrideStyle({
|
||||
property: "background",
|
||||
variable: secondaryTransparent,
|
||||
variable: secondaryHover,
|
||||
specificity: ["value"],
|
||||
});
|
||||
|
||||
|
@ -12,7 +12,7 @@ import { fileURLToPath } from "node:url";
|
||||
const dependencies = {
|
||||
"htm.min.js": "https://unpkg.com/htm@3.1.1/mini/index.js",
|
||||
"twind.min.js": "https://unpkg.com/@twind/cdn@1.0.7/cdn.global.js",
|
||||
"lucide.min.js": "https://unpkg.com/lucide@0.104.0/dist/umd/lucide.min.js",
|
||||
"lucide.min.js": "https://unpkg.com/lucide@0.105.0/dist/umd/lucide.min.js",
|
||||
"coloris.min.js":
|
||||
"https://cdn.jsdelivr.net/gh/mdbassit/Coloris@latest/dist/coloris.min.js",
|
||||
"coloris.min.css":
|
||||
|
@ -39,38 +39,35 @@ const sendMessage = (channel, message) => {
|
||||
const initDatabase = (namespace, fallbacks = {}) => {
|
||||
if (Array.isArray(namespace)) namespace = namespace.join("__");
|
||||
namespace = namespace ? namespace + "__" : "";
|
||||
const namespaceify = (key) =>
|
||||
key.startsWith(namespace) ? key : namespace + key;
|
||||
return {
|
||||
get: async (key) => {
|
||||
const fallback = fallbacks[key];
|
||||
key = key.startsWith(namespace) ? key : namespace + key;
|
||||
return new Promise((res, _rej) => {
|
||||
chrome.storage.local.get([key], ({ [key]: value }) => {
|
||||
return res(value ?? fallback);
|
||||
});
|
||||
});
|
||||
key = namespaceify(key);
|
||||
return (await chrome.storage.local.get([key]))[key] ?? fallback;
|
||||
},
|
||||
set: async (key, value) => {
|
||||
key = key.startsWith(namespace) ? key : namespace + key;
|
||||
return new Promise((res, _rej) => {
|
||||
chrome.storage.local.set({ [key]: value }, () => res(true));
|
||||
});
|
||||
set: (key, value) => {
|
||||
key = namespaceify(key);
|
||||
return chrome.storage.local.set({ [key]: value });
|
||||
},
|
||||
remove: (keys) => {
|
||||
keys = Array.isArray(keys) ? keys : [keys];
|
||||
keys = keys.map(namespaceify);
|
||||
return chrome.storage.local.remove(keys);
|
||||
},
|
||||
export: async () => {
|
||||
const obj = await new Promise((res, _rej) => {
|
||||
chrome.storage.local.get((value) => res(value));
|
||||
});
|
||||
const obj = await chrome.storage.local.get();
|
||||
if (!namespace) return obj;
|
||||
const entries = Object.entries(obj)
|
||||
.filter(([key]) => key.startsWith(namespace))
|
||||
.map(([key, value]) => [key.slice(namespace.length), value]);
|
||||
return Object.fromEntries(entries);
|
||||
},
|
||||
import: async (obj) => {
|
||||
import: (obj) => {
|
||||
const entries = Object.entries(obj) //
|
||||
.map(([key, value]) => [namespace + key, value]);
|
||||
return new Promise((res, _rej) => {
|
||||
chrome.storage.local.set(Object.fromEntries(entries), () => res(true));
|
||||
});
|
||||
return chrome.storage.local.set(Object.fromEntries(entries));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -50,6 +50,8 @@ let __db;
|
||||
const initDatabase = (namespace, fallbacks = {}) => {
|
||||
if (Array.isArray(namespace)) namespace = namespace.join("__");
|
||||
namespace = namespace ? namespace + "__" : "";
|
||||
const namespaceify = (key) =>
|
||||
key.startsWith(namespace) ? key : namespace + key;
|
||||
|
||||
// schema:
|
||||
// - ("profileIds") = $profileId[]
|
||||
@ -68,11 +70,11 @@ const initDatabase = (namespace, fallbacks = {}) => {
|
||||
init.run();
|
||||
__db = db;
|
||||
|
||||
// prettier-ignore
|
||||
const insert = db.prepare(`INSERT INTO ${table} (key, value) VALUES (?, ?)`),
|
||||
// prettier-ignore
|
||||
update = db.prepare(`UPDATE ${table} SET value = ? WHERE key = ?`),
|
||||
select = db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`),
|
||||
remove = db.prepare(`DELETE FROM ${table} WHERE key = ?`),
|
||||
removeMany = db.transaction((arr) => arr.forEach((key) => remove.run(key))),
|
||||
dump = db.prepare(`SELECT * FROM ${table}`),
|
||||
populate = db.transaction((obj) => {
|
||||
for (const key in obj) {
|
||||
@ -85,7 +87,7 @@ const initDatabase = (namespace, fallbacks = {}) => {
|
||||
// wrap methods in promises for consistency w/ chrome.storage
|
||||
get: (key) => {
|
||||
const fallback = fallbacks[key];
|
||||
key = key.startsWith(namespace) ? key : namespace + key;
|
||||
key = namespaceify(key);
|
||||
try {
|
||||
const value = JSON.parse(select.get(key)?.value);
|
||||
return Promise.resolve(value ?? fallback);
|
||||
@ -93,13 +95,19 @@ const initDatabase = (namespace, fallbacks = {}) => {
|
||||
return Promise.resolve(fallback);
|
||||
},
|
||||
set: (key, value) => {
|
||||
key = key.startsWith(namespace) ? key : namespace + key;
|
||||
key = namespaceify(key);
|
||||
value = JSON.stringify(value);
|
||||
if (select.get(key) === undefined) {
|
||||
insert.run(key, value);
|
||||
} else update.run(value, key);
|
||||
return Promise.resolve(true);
|
||||
},
|
||||
remove: (keys) => {
|
||||
keys = Array.isArray(keys) ? keys : [keys];
|
||||
keys = keys.map(namespaceify);
|
||||
removeMany(keys);
|
||||
return Promise.resolve(true);
|
||||
},
|
||||
export: () => {
|
||||
const entries = dump
|
||||
.all()
|
||||
|
@ -51,7 +51,16 @@ const getProfile = async () => {
|
||||
enabledMods = initDatabase([await getProfile(), "enabledMods"]);
|
||||
return Boolean(await enabledMods.get(id));
|
||||
},
|
||||
optionDefaults = async (id) => {
|
||||
setEnabled = async (id, enabled) => {
|
||||
const { initDatabase } = globalThis.__enhancerApi;
|
||||
// prettier-ignore
|
||||
return await initDatabase([
|
||||
await getProfile(),
|
||||
"enabledMods"
|
||||
]).set(id, enabled);
|
||||
};
|
||||
|
||||
const optionDefaults = async (id) => {
|
||||
const mod = (await getMods()).find((mod) => mod.id === id),
|
||||
optionEntries = mod.options
|
||||
.map((opt) => {
|
||||
@ -64,6 +73,10 @@ const getProfile = async () => {
|
||||
})
|
||||
.filter((opt) => opt);
|
||||
return Object.fromEntries(optionEntries);
|
||||
},
|
||||
modDatabase = async (id) => {
|
||||
const { initDatabase } = globalThis.__enhancerApi;
|
||||
return initDatabase([await getProfile(), id], await optionDefaults(id));
|
||||
};
|
||||
|
||||
globalThis.__enhancerApi ??= {};
|
||||
@ -75,5 +88,7 @@ Object.assign(globalThis.__enhancerApi, {
|
||||
getIntegrations,
|
||||
getProfile,
|
||||
isEnabled,
|
||||
setEnabled,
|
||||
optionDefaults,
|
||||
modDatabase,
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ import { setState, useState, getState } from "./state.mjs";
|
||||
// generic
|
||||
|
||||
function _Button(
|
||||
{ type, size, icon, primary, class: cls = "", ...props },
|
||||
{ type, size, variant, icon, class: cls = "", ...props },
|
||||
...children
|
||||
) {
|
||||
const { html } = globalThis.__enhancerApi,
|
||||
@ -20,10 +20,14 @@ function _Button(
|
||||
return html`<${type}
|
||||
class="flex gap-[8px] items-center px-[12px] shrink-0
|
||||
rounded-[4px] ${size === "sm" ? "h-[28px]" : "h-[32px]"}
|
||||
transition duration-[20ms] ${primary
|
||||
transition duration-[20ms] ${variant === "primary"
|
||||
? `text-[color:var(--theme--accent-primary\\_contrast)]
|
||||
font-medium bg-[color:var(--theme--accent-primary)]
|
||||
hover:bg-[color:var(--theme--accent-primary\\_hover)]`
|
||||
: variant === "secondary"
|
||||
? `text-[color:var(--theme--accent-secondary)]
|
||||
border-(& [color:var(--theme--accent-secondary)])
|
||||
hover:bg-[color:var(--theme--accent-secondary\\_hover)]`
|
||||
: `border-(& [color:var(--theme--fg-border)])
|
||||
hover:bg-[color:var(--theme--bg-hover)]`} ${cls}"
|
||||
...${props}
|
||||
@ -211,6 +215,79 @@ function View({ id }, ...children) {
|
||||
return $el;
|
||||
}
|
||||
|
||||
function Popup(
|
||||
{ for: $trigger, onopen, onclose, onbeforeclose, ...props },
|
||||
...children
|
||||
) {
|
||||
const { html } = globalThis.__enhancerApi,
|
||||
$popup = html`<div
|
||||
class="notion-enhancer--menu-popup
|
||||
group absolute top-0 left-0 w-full h-full
|
||||
flex flex-col justify-center items-end
|
||||
pointer-events-none z-20"
|
||||
...${props}
|
||||
>
|
||||
<div class="relative right-[100%]">
|
||||
<div
|
||||
class="bg-[color:var(--theme--bg-secondary)]
|
||||
w-[250px] max-w-[calc(100vw-24px)] max-h-[70vh]
|
||||
py-[6px] px-[4px] drop-shadow-xl overflow-y-auto
|
||||
transition duration-[200ms] opacity-0 scale-95 rounded-[4px]
|
||||
group-open:(pointer-events-auto opacity-100 scale-100)"
|
||||
>
|
||||
${children}
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const { onclick, onkeydown } = $trigger,
|
||||
enableTabbing = () => {
|
||||
$popup
|
||||
.querySelectorAll("[tabindex]")
|
||||
.forEach(($el) => ($el.tabIndex = 0));
|
||||
},
|
||||
disableTabbing = () => {
|
||||
$popup
|
||||
.querySelectorAll("[tabindex]")
|
||||
.forEach(($el) => ($el.tabIndex = -1));
|
||||
},
|
||||
openPopup = () => {
|
||||
$popup.setAttribute("open", true);
|
||||
enableTabbing();
|
||||
onopen?.();
|
||||
setState({ popupOpen: true });
|
||||
},
|
||||
closePopup = () => {
|
||||
$popup.removeAttribute("open");
|
||||
disableTabbing();
|
||||
onbeforeclose?.();
|
||||
setTimeout(() => {
|
||||
onclose?.();
|
||||
setState({ popupOpen: false });
|
||||
}, 200);
|
||||
};
|
||||
disableTabbing();
|
||||
$trigger.onclick = (event) => {
|
||||
onclick?.(event);
|
||||
openPopup();
|
||||
};
|
||||
$trigger.onkeydown = (event) => {
|
||||
onkeydown?.(event);
|
||||
if (event.key === "Enter") openPopup();
|
||||
};
|
||||
useState(["rerender"], () => {
|
||||
if ($popup.hasAttribute("open")) closePopup();
|
||||
});
|
||||
document.addEventListener("click", (event) => {
|
||||
if (!$popup.hasAttribute("open")) return;
|
||||
if ($popup.contains(event.target) || $popup === event.target) return;
|
||||
if ($trigger.contains(event.target) || $trigger === event.target) return;
|
||||
closePopup();
|
||||
});
|
||||
|
||||
return $popup;
|
||||
}
|
||||
|
||||
// input
|
||||
|
||||
function Input({
|
||||
@ -443,66 +520,26 @@ function Select({ values, _get, _set, ...props }) {
|
||||
></div>`,
|
||||
$options = values.map((value) => {
|
||||
return html`<${SelectOption} ...${{ value, _get, _set }} />`;
|
||||
}),
|
||||
$popup = html`<div
|
||||
class="group absolute top-0 left-0
|
||||
flex flex-col justify-center items-end
|
||||
pointer-events-none w-full h-full"
|
||||
>
|
||||
<div class="relative right-[100%]">
|
||||
<div
|
||||
class="bg-[color:var(--theme--bg-secondary)]
|
||||
w-[250px] max-w-[calc(100vw-24px)] max-h-[70vh]
|
||||
py-[6px] px-[4px] drop-shadow-xl overflow-y-auto
|
||||
transition duration-[200ms] opacity-0 scale-95 rounded-[4px]
|
||||
group-open:(pointer-events-auto opacity-100 scale-100)"
|
||||
>
|
||||
${$options}
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const { onclick, onkeydown } = $select,
|
||||
openPopup = () => {
|
||||
$popup.setAttribute("open", true);
|
||||
$options.forEach(($opt) => ($opt.tabIndex = 0));
|
||||
setState({ popupOpen: true });
|
||||
},
|
||||
closePopup = (value) => {
|
||||
$popup.removeAttribute("open");
|
||||
$options.forEach(($opt) => ($opt.tabIndex = -1));
|
||||
$select.style.width = `${$select.offsetWidth}px`;
|
||||
$select.style.background = "transparent";
|
||||
if (value) $select.innerText = value;
|
||||
setTimeout(() => {
|
||||
$select.style.width = "";
|
||||
$select.style.background = "";
|
||||
setState({ popupOpen: false });
|
||||
}, 200);
|
||||
};
|
||||
$select.onclick = (event) => {
|
||||
onclick?.(event);
|
||||
openPopup();
|
||||
};
|
||||
$select.onkeydown = (event) => {
|
||||
onkeydown?.(event);
|
||||
if (event.key === "Enter") openPopup();
|
||||
};
|
||||
useState(["rerender"], () => {
|
||||
_get?.().then((value) => {
|
||||
if ($popup.hasAttribute("open")) {
|
||||
closePopup(value);
|
||||
} else $select.innerText = value;
|
||||
});
|
||||
});
|
||||
document.addEventListener("click", (event) => {
|
||||
if (!$popup.hasAttribute("open")) return;
|
||||
if ($popup.contains(event.target) || event.target === $select) return;
|
||||
closePopup();
|
||||
useState(["rerender"], () => {
|
||||
_get?.().then((value) => ($select.innerText = value));
|
||||
});
|
||||
|
||||
return html`<div class="notion-enhancer--menu-select relative">
|
||||
${$select}${$popup}
|
||||
${$select}
|
||||
<${Popup}
|
||||
for=${$select}
|
||||
onbeforeclose=${() => {
|
||||
$select.style.width = `${$select.offsetWidth}px`;
|
||||
$select.style.background = "transparent";
|
||||
}}
|
||||
onclose=${() => {
|
||||
$select.style.width = "";
|
||||
$select.style.background = "";
|
||||
}}
|
||||
>
|
||||
${$options}
|
||||
<//>
|
||||
<i
|
||||
class="i-chevron-down pointer-events-none
|
||||
absolute right-[6px] top-[6px] w-[16px] h-[16px]
|
||||
@ -515,6 +552,7 @@ function SelectOption({ value, _get, _set, ...props }) {
|
||||
const { html } = globalThis.__enhancerApi,
|
||||
$selected = html`<i class="ml-auto i-check w-[16px] h-[16px]"></i>`,
|
||||
$option = html`<div
|
||||
tabindex="0"
|
||||
role="button"
|
||||
class="select-none cursor-pointer rounded-[3px]
|
||||
flex items-center w-full h-[28px] px-[12px] leading-[1.2]
|
||||
@ -608,7 +646,10 @@ function Checkbox({ _get, _set, ...props }) {
|
||||
return html`<label tabindex="0" class="cursor-pointer">
|
||||
${$input}
|
||||
<div class="flex items-center h-[16px] transition duration-[200ms]">
|
||||
<i class="i-check w-[14px] h-[14px]"></i>
|
||||
<i
|
||||
class="i-check w-[14px] h-[14px]
|
||||
text-[color:var(--theme--accent-primary\\_contrast)]"
|
||||
></i>
|
||||
</div>
|
||||
</label>`;
|
||||
}
|
||||
@ -778,6 +819,7 @@ function Profile({
|
||||
setActive,
|
||||
exportJson,
|
||||
importJson,
|
||||
deleteProfile,
|
||||
...props
|
||||
}) {
|
||||
const { html } = globalThis.__enhancerApi,
|
||||
@ -812,6 +854,35 @@ function Profile({
|
||||
$a.remove();
|
||||
};
|
||||
|
||||
const $delete = html`<${Icon} icon="x" />`,
|
||||
$name = html`<mark></mark>`,
|
||||
$confirmation = html`<${Popup}
|
||||
for=${$delete}
|
||||
onopen=${async () => ($name.innerText = await getName())}
|
||||
>
|
||||
<p class="text-[14px] pt-[2px] px-[8px]">
|
||||
Are you sure you want to delete the profile ${$name} permanently?
|
||||
</p>
|
||||
<div class="flex flex-col gap-[8px] pt-[8px] pb-[6px] px-[8px]">
|
||||
<${Button}
|
||||
tabindex="0"
|
||||
icon="trash"
|
||||
class="justify-center"
|
||||
variant="secondary"
|
||||
onclick=${() => deleteProfile()}
|
||||
>
|
||||
Delete
|
||||
<//>
|
||||
<${Button}
|
||||
tabindex="0"
|
||||
class="justify-center"
|
||||
onclick=${() => setState({ rerender: true })}
|
||||
>
|
||||
Cancel
|
||||
<//>
|
||||
</div>
|
||||
<//>`;
|
||||
|
||||
return html`<li class="flex items-center my-[14px] gap-[8px]" ...${props}>
|
||||
<${Checkbox}
|
||||
...${{ _get: isActive, _set: setActive }}
|
||||
@ -834,8 +905,8 @@ function Profile({
|
||||
/>
|
||||
Import
|
||||
<//>
|
||||
<${Button} size="sm" icon="upload" onclick=${downloadProfile}> Export <//>
|
||||
<${Icon} icon="x" />
|
||||
<${Button} size="sm" icon="upload" onclick=${downloadProfile}>Export<//>
|
||||
<div class="relative">${$delete}${$confirmation}</div>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ body > #skeleton .row-group .shimmer {
|
||||
height: 11px;
|
||||
}
|
||||
|
||||
.notion-enhancer--menu-description mark {
|
||||
mark {
|
||||
color: inherit;
|
||||
padding: 2px 4px;
|
||||
border-radius: 3px;
|
||||
|
@ -4,13 +4,7 @@
|
||||
* (https://notion-enhancer.github.io/) under the MIT license
|
||||
*/
|
||||
|
||||
import {
|
||||
getState,
|
||||
setState,
|
||||
useState,
|
||||
setEnabled,
|
||||
modDatabase,
|
||||
} from "./state.mjs";
|
||||
import { getState, setState, useState } from "./state.mjs";
|
||||
import {
|
||||
Button,
|
||||
Description,
|
||||
@ -72,7 +66,7 @@ const renderSidebar = (items, categories) => {
|
||||
return $sidebar;
|
||||
},
|
||||
renderList = async (id, mods, description) => {
|
||||
const { html, isEnabled } = globalThis.__enhancerApi;
|
||||
const { html, isEnabled, setEnabled } = globalThis.__enhancerApi;
|
||||
mods = mods.map(async (mod) => {
|
||||
const _get = () => isEnabled(mod.id),
|
||||
_set = async (enabled) => {
|
||||
@ -86,7 +80,7 @@ const renderSidebar = (items, categories) => {
|
||||
<//>`;
|
||||
},
|
||||
renderOptions = async (mod) => {
|
||||
const { html, platform, getProfile } = globalThis.__enhancerApi;
|
||||
const { html, platform, modDatabase } = globalThis.__enhancerApi;
|
||||
let options = mod.options.reduce((options, opt) => {
|
||||
if (!opt.key && (opt.type !== "heading" || !opt.label)) return options;
|
||||
if (opt.platforms && !opt.platforms.includes(platform)) return options;
|
||||
@ -116,14 +110,26 @@ const renderSidebar = (items, categories) => {
|
||||
db = initDatabase(),
|
||||
$list = html`<ul></ul>`,
|
||||
renderProfile = (id) => {
|
||||
const profile = initDatabase([id]);
|
||||
const profile = initDatabase([id]),
|
||||
isActive = async () => id === (await getProfile()),
|
||||
deleteProfile = async () => {
|
||||
const keys = Object.keys(await profile.export());
|
||||
profileIds.splice(profileIds.indexOf(id), 1);
|
||||
await db.set("profileIds", profileIds);
|
||||
await profile.remove(keys);
|
||||
if (isActive()) {
|
||||
await db.remove("activeProfile");
|
||||
setState({ databaseUpdated: true });
|
||||
}
|
||||
setState({ rerender: true });
|
||||
};
|
||||
return html`<${Profile}
|
||||
id=${id}
|
||||
getName=${async () =>
|
||||
(await profile.get("profileName")) ??
|
||||
(id === "default" ? "default" : "")}
|
||||
setName=${(name) => profile.set("profileName", name)}
|
||||
isActive=${async () => id === (await getProfile())}
|
||||
isActive=${isActive}
|
||||
setActive=${async () => {
|
||||
await db.set("activeProfile", id);
|
||||
setState({ rerender: true, databaseUpdated: true });
|
||||
@ -133,10 +139,12 @@ const renderSidebar = (items, categories) => {
|
||||
try {
|
||||
await profile.import(JSON.parse(json));
|
||||
setState({ rerender: true, databaseUpdated: true });
|
||||
// success
|
||||
} catch {
|
||||
// error
|
||||
}
|
||||
}}
|
||||
deleteProfile=${deleteProfile}
|
||||
/>`;
|
||||
},
|
||||
refreshProfiles = async () => {
|
||||
@ -164,9 +172,6 @@ const renderSidebar = (items, categories) => {
|
||||
};
|
||||
useState(["rerender"], () => refreshProfiles());
|
||||
|
||||
// todo: deleting profiles inc. clearing db keys,
|
||||
// throwing errors on invalid json upload
|
||||
|
||||
const $input = html`<${Input}
|
||||
size="md"
|
||||
type="text"
|
||||
@ -198,7 +203,7 @@ const renderSidebar = (items, categories) => {
|
||||
</div>`;
|
||||
},
|
||||
renderMods = async (mods) => {
|
||||
const { html, isEnabled } = globalThis.__enhancerApi;
|
||||
const { html, isEnabled, setEnabled } = globalThis.__enhancerApi;
|
||||
mods = mods
|
||||
.filter((mod) => {
|
||||
return mod.options?.filter((opt) => opt.type !== "heading").length;
|
||||
@ -325,8 +330,8 @@ const render = async () => {
|
||||
<//>`;
|
||||
});
|
||||
const $reload = html`<${Button}
|
||||
primary
|
||||
class="ml-auto"
|
||||
variant="primary"
|
||||
icon="refresh-cw"
|
||||
onclick=${() => reloadApp()}
|
||||
style="display: none"
|
||||
|
@ -21,18 +21,4 @@ const _state = {},
|
||||
callback(getState(keys));
|
||||
};
|
||||
|
||||
const setEnabled = async (id, enabled) => {
|
||||
const { getProfile, initDatabase } = globalThis.__enhancerApi;
|
||||
// prettier-ignore
|
||||
return await initDatabase([
|
||||
await getProfile(),
|
||||
"enabledMods"
|
||||
]).set(id, enabled);
|
||||
},
|
||||
modDatabase = async (id) => {
|
||||
const { getProfile, initDatabase } = globalThis.__enhancerApi,
|
||||
{ optionDefaults } = globalThis.__enhancerApi;
|
||||
return initDatabase([await getProfile(), id], await optionDefaults(id));
|
||||
};
|
||||
|
||||
export { setState, useState, getState, setEnabled, modDatabase };
|
||||
export { setState, useState, getState };
|
||||
|
2558
src/core/theme.css
2558
src/core/theme.css
File diff suppressed because one or more lines are too long
@ -57,8 +57,8 @@ body.dark {
|
||||
--theme--accent-primary_contrast: #fff;
|
||||
--theme--accent-primary_transparent: rgba(35, 131, 226, 0.14);
|
||||
--theme--accent-secondary: #eb5757;
|
||||
--theme--accent-secondary_hover: rgba(235, 87, 87, 0.1);
|
||||
--theme--accent-secondary_contrast: #fff;
|
||||
--theme--accent-secondary_transparent: rgba(235, 87, 87, 0.1);
|
||||
|
||||
--theme--scrollbar-track: rgba(202, 204, 206, 0.04);
|
||||
--theme--scrollbar-thumb: #474c50;
|
||||
@ -154,7 +154,7 @@ body:not(.dark) {
|
||||
--theme--accent-primary_transparent: rgba(35, 131, 226, 0.14);
|
||||
--theme--accent-secondary: #eb5757;
|
||||
--theme--accent-secondary_contrast: #fff;
|
||||
--theme--accent-secondary_transparent: rgba(235, 87, 87, 0.1);
|
||||
--theme--accent-secondary_hover: rgba(235, 87, 87, 0.1);
|
||||
|
||||
--theme--scrollbar-track: #edece9;
|
||||
--theme--scrollbar-thumb: #d3d1cb;
|
||||
|
@ -48,8 +48,8 @@ body.dark {
|
||||
--theme--accent-primary_contrast: #fff;
|
||||
--theme--accent-primary_transparent: rgb(46, 170, 220, 0.25);
|
||||
--theme--accent-secondary: #eb5757;
|
||||
--theme--accent-secondary_hover: rgba(235, 87, 87, 0.1);
|
||||
--theme--accent-secondary_contrast: #fff;
|
||||
--theme--accent-secondary_transparent: rgba(235, 87, 87, 0.1);
|
||||
|
||||
--theme--scrollbar-track: rgba(202, 204, 206, 0.04);
|
||||
--theme--scrollbar-thumb: #474c50;
|
||||
|
2
src/vendor/coloris.min.css
vendored
2
src/vendor/coloris.min.css
vendored
File diff suppressed because one or more lines are too long
2
src/vendor/coloris.min.js
vendored
2
src/vendor/coloris.min.js
vendored
File diff suppressed because one or more lines are too long
2
src/vendor/lucide.min.js
vendored
2
src/vendor/lucide.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user