chore(menu): add telemetry toggle

This commit is contained in:
dragonwocky 2023-01-30 23:11:55 +11:00
parent f999969c13
commit 567e678a6f
Signed by: dragonwocky
GPG Key ID: 7998D08F7D7BD7A8
9 changed files with 121 additions and 18 deletions

View File

@ -71,12 +71,14 @@ const initDatabase = (namespace, fallbacks = {}) => {
)`); )`);
init.run(); init.run();
// schema: // schema:
// - ("profileIds") = $profileId[] // - ("profileIds") -> $profileId[]
// - ("activeProfile") -> $profileId // - ("activeProfile") -> $profileId
// - $profileId: ("profileName") -> string // - $profileId: ("profileName") -> string
// - $profileId: ("telemetryEnabled") -> boolean
// - $profileId__enabledMods: ($modId) -> boolean // - $profileId__enabledMods: ($modId) -> boolean
// - $profileId__$modId: ($optionKey) -> value // - $profileId__$modId: ($optionKey) -> value
__statements = { __statements = {
insert: db.prepare(`INSERT INTO ${table} (key, value) VALUES (?, ?)`), insert: db.prepare(`INSERT INTO ${table} (key, value) VALUES (?, ?)`),
update: db.prepare(`UPDATE ${table} SET value = ? WHERE key = ?`), update: db.prepare(`UPDATE ${table} SET value = ? WHERE key = ?`),

View File

@ -9,8 +9,8 @@ import { extendProps } from "../state.mjs";
function Description(props, ...children) { function Description(props, ...children) {
const { html } = globalThis.__enhancerApi; const { html } = globalThis.__enhancerApi;
extendProps(props, { extendProps(props, {
class: `notion-enhancer--menu-description leading-[16px] class: `notion-enhancer--menu-description typography
text-([12px] [color:var(--theme--fg-secondary)])`, leading-[16px] text-([12px] [color:var(--theme--fg-secondary)])`,
}); });
return html`<p ...${props}>${children}</p>`; return html`<p ...${props}>${children}</p>`;
} }

View File

@ -6,11 +6,11 @@
import { extendProps } from "../state.mjs"; import { extendProps } from "../state.mjs";
function Heading(props, children) { function Heading(props, ...children) {
const { html } = globalThis.__enhancerApi; const { html } = globalThis.__enhancerApi;
extendProps(props, { extendProps(props, {
class: `notion-enhancer--menu-heading font-semibold class: `notion-enhancer--menu-heading flex items-center gap-[4px]
mb-[16px] mt-[48px] first:mt-0 pb-[12px] text-[16px] text-[16px] font-semibold mb-[16px] mt-[48px] first:mt-0 pb-[12px]
border-b-(& [color:var(--theme--fg-border)])`, border-b-(& [color:var(--theme--fg-border)])`,
}); });
return html`<h4 ...${props}>${children}</h4>`; return html`<h4 ...${props}>${children}</h4>`;

View File

@ -62,8 +62,9 @@ function Circle(rect) {
></div>`; ></div>`;
} }
function Banner({ version }) { function Banner() {
const { html } = globalThis.__enhancerApi; const { html, enhancerVersion } = globalThis.__enhancerApi;
// todo: show popup if update available
return html`<section class="notion-enhancer--menu-banner"> return html`<section class="notion-enhancer--menu-banner">
<div <div
class="relative flex overflow-hidden h-[192px] rounded-t-[4px] class="relative flex overflow-hidden h-[192px] rounded-t-[4px]
@ -94,7 +95,7 @@ function Banner({ version }) {
<span <span
class="text-[12px] py-[2px] px-[6px] class="text-[12px] py-[2px] px-[6px]
font-medium leading-tight tracking-wide" font-medium leading-tight tracking-wide"
>v${version} >v${enhancerVersion}
</span> </span>
</div> </div>
</div> </div>

View File

@ -0,0 +1,40 @@
/**
* notion-enhancer
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
import { Heading } from "../components/Heading.mjs";
import { Description } from "../components/Description.mjs";
import { Checkbox } from "../components/Checkbox.mjs";
import { Option } from "./Options.mjs";
const privacyPolicy = "https://notion-enhancer.github.io/about/privacy-policy/",
tsAndCs = "https://notion-enhancer.github.io/about/terms-and-conditions/";
function GetStarted() {
const { html } = globalThis.__enhancerApi;
return html`
<${Heading}>Get Started <i class="i-arrow-right"></i><//>
<div class="flex items-center my-[14px] gap-[8px]">
<${Checkbox}
...${{ _get: () => Promise.resolve(true), _set: () => {} }}
onchange=${(event) => (event.target.checked = true)}
/>
<p class="typography text-[14px]">
I have read and agreed to the
<a class="mx-[4px]" href=${privacyPolicy}>Privacy Policy</a>
and <a href=${tsAndCs}>Terms & Conditions</a>.
</p>
</div>
`;
}
export { GetStarted };
// - deidentified / anonymous
// - once a week
// - privacy policy
// - learn how the notion-enhancer is used and what parts need focusing on

View File

@ -47,7 +47,9 @@ function Option({ _get, _set, ...opt }) {
...${{ _get, _set }} ...${{ _get, _set }}
/>` />`
: ""} : ""}
<${Description} innerHTML=${opt.description} /> ${["string", "undefined"].includes(typeof opt.description)
? html`<${Description} innerHTML=${opt.description} />`
: html`<${Description}>${opt.description}<//>`}
</div> </div>
${["number", "hotkey", "color"].includes(opt.type) ${["number", "hotkey", "color"].includes(opt.type)
? html`<${Input} ? html`<${Input}
@ -83,4 +85,4 @@ function Options({ mod }) {
}); });
} }
export { Options }; export { Options, Option };

View File

@ -0,0 +1,50 @@
/**
* notion-enhancer
* (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
import { useState, setState } from "../state.mjs";
import { Option } from "./Options.mjs";
const privacyPolicy = "https://notion-enhancer.github.io/about/privacy-policy/";
function Telemetry() {
const { html, platform, getMods } = globalThis.__enhancerApi,
{ getProfile, isEnabled, initDatabase } = globalThis.__enhancerApi,
timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const $enabledMods = html`<code></code>`;
useState(["rerender"], async () => {
let enabledMods = [];
for (const mod of await getMods()) {
if (mod._src === "core") continue;
if (await isEnabled(mod.id)) enabledMods.push(mod.id);
}
$enabledMods.innerText = JSON.stringify(enabledMods);
});
const _get = async () => {
// defaults to true, must be explicitly set to false to disable
return initDatabase([await getProfile()]).get("telemetryEnabled") ?? true;
},
_set = async (value) => {
await initDatabase([await getProfile()]).set("telemetryEnabled", value);
setState({ rerender: true, databaseUpdated: true });
};
// todo: actually collect telemetry
return html`<${Option}
type="toggle"
label="Telemetry"
description=${html`If telemetry is enabled, basic usage data will be
collected at a regular interval from your device in order to better
understand how and where the notion-enhancer is used. This data is
anonymous and includes only your platform (<code>"${platform}"</code>),
timezone (<code>"${timezone}"</code>) and enabled mods (${$enabledMods}).
You can opt in or out of telemetry at any time. For more information,
please read the <a href=${privacyPolicy}>privacy policy</a>.`}
...${{ _get, _set }}
/>`;
}
export { Telemetry };

View File

@ -94,17 +94,23 @@ body > #skeleton .row-group .shimmer {
height: 11px; height: 11px;
} }
.notion-enhancer--menu-description mark { .typography mark {
color: inherit;
padding: 0 4px; padding: 0 4px;
border-radius: 3px; border-radius: 3px;
background-color: var(--theme--bg-hover); background-color: var(--theme--bg-hover);
color: inherit;
} }
.notion-enhancer--menu-description a { .typography code {
padding: 0 4px;
border-radius: 3px;
background-color: var(--theme--code-inline_bg);
color: var(--theme--code-inline_fg);
}
.typography a {
text-decoration: underline; text-decoration: underline;
transition: 100ms ease-in; transition: 100ms ease-in;
} }
.notion-enhancer--menu-description a:hover { .typography a:hover {
color: var(--theme--accent-secondary); color: var(--theme--accent-secondary);
} }

View File

@ -8,6 +8,7 @@ import { setState, useState } from "./state.mjs";
import { Sidebar } from "./islands/Sidebar.mjs"; import { Sidebar } from "./islands/Sidebar.mjs";
import { Footer } from "./islands/Footer.mjs"; import { Footer } from "./islands/Footer.mjs";
import { Banner } from "./islands/Banner.mjs"; import { Banner } from "./islands/Banner.mjs";
import { Telemetry } from "./islands/Telemetry.mjs";
import { View } from "./islands/View.mjs"; import { View } from "./islands/View.mjs";
import { List } from "./islands/List.mjs"; import { List } from "./islands/List.mjs";
import { Mod } from "./islands/Mod.mjs"; import { Mod } from "./islands/Mod.mjs";
@ -77,7 +78,7 @@ const categories = [
]; ];
const render = async () => { const render = async () => {
const { html, enhancerVersion } = globalThis.__enhancerApi, const { html, platform } = globalThis.__enhancerApi,
{ getMods, isEnabled, setEnabled } = globalThis.__enhancerApi, { getMods, isEnabled, setEnabled } = globalThis.__enhancerApi,
[icon, renderStarted] = useState(["icon", "renderStarted"]); [icon, renderStarted] = useState(["icon", "renderStarted"]);
if (!html || !getMods || !icon || renderStarted) return; if (!html || !getMods || !icon || renderStarted) return;
@ -116,9 +117,10 @@ const render = async () => {
<!-- wrappers necessary for transitions and breakpoints --> <!-- wrappers necessary for transitions and breakpoints -->
<div class="grow overflow-auto"> <div class="grow overflow-auto">
<div class="relative h-full w-full"> <div class="relative h-full w-full">
<${View} id="welcome"><${Banner} version=${enhancerVersion} /><//> <${View} id="welcome"><${Banner} /><//>
<${View} id="core"> <${View} id="core">
<${Options} mod=${mods.find(({ _src }) => _src === "core")} /> <${Options} mod=${mods.find(({ _src }) => _src === "core")} />
<${Telemetry} />
<${Profiles} /> <${Profiles} />
<//> <//>
${[...categories, ...mods] ${[...categories, ...mods]