Skip to content

Commit

Permalink
Add opt-in analytics #43
Browse files Browse the repository at this point in the history
  • Loading branch information
OlegWock committed Apr 28, 2023
1 parent 74b0606 commit dfd7265
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 21 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Anori",
"description": "Customizable new tab: compose your own page from widgets",
"version": "1.5.1",
"version": "1.6.0",
"repository": "git@github.com:OlegWock/anori.git",
"author": "OlegWock <olegwock@gmail.com>",
"license": "MIT",
Expand Down Expand Up @@ -59,6 +59,7 @@
"jotai": "^2.0.0",
"jotai-optics": "^0.3.0",
"jszip": "^3.10.1",
"mixpanel-browser": "juanfer0002/mixpanel-js-mv3#cc7d3a9e4c37e3f9d7de1789a38794e861c3e40a",
"moment-timezone": "^0.5.40",
"moment-timezone-data-webpack-plugin": "^1.5.1",
"optics-ts": "^2.4.0",
Expand All @@ -84,6 +85,7 @@
"webpack-cli": "^5.0.1"
},
"devDependencies": {
"@types/mixpanel-browser": "^2.38.1",
"@types/webpack-bundle-analyzer": "^4.6.0",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.6.0",
Expand Down
12 changes: 11 additions & 1 deletion src/background.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { availablePlugins } from '@plugins/all';
import { sendAnalyticsIfEnabled } from '@utils/analytics';
import { storage } from '@utils/storage';
import browser from 'webextension-polyfill';

console.log('Background init');

const VERSIONS_WITH_CHANGES = ['1.1.0', '1.2.0', '1.5.0'];
const VERSIONS_WITH_CHANGES = ['1.1.0', '1.2.0', '1.5.0', '1.6.0'];

const compareVersions = (v1: string, v2: string): -1 | 0 | 1 => {
// v1 is newer than v2 => -1
Expand Down Expand Up @@ -90,13 +91,22 @@ browser.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'scheduledCallbacks') {
runScheduledCallbacks();
}
if (alarm.name === 'sendAnalytics') {
sendAnalyticsIfEnabled();
}
});

// @ts-ignore Add this into global scope for debug
self.sendAnalyticsIfEnabled = sendAnalyticsIfEnabled;

browser.alarms.create('scheduledCallbacks', {
periodInMinutes: 5,
delayInMinutes: 5,
});

browser.alarms.create('sendAnalytics', {
periodInMinutes: 60,
});

(X_BROWSER === 'chrome' ? browser.action : browser.browserAction).onClicked.addListener(() => {
browser.tabs.create({
Expand Down
5 changes: 3 additions & 2 deletions src/components/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ type CheckboxProps = {
disabled?: boolean,
checked?: boolean,
onChange?: (newState: boolean) => void,
className?: string,
}

export const Checkbox = ({ children, defaultChecked, checked, onChange, disabled }: CheckboxProps) => {
export const Checkbox = ({ children, defaultChecked, checked, onChange, disabled, className }: CheckboxProps) => {
const id = useId();
return (<div className={clsx('Checkbox', {'Checkbox-disabled': disabled})} data-disabled={disabled || undefined}>
return (<div className={clsx('Checkbox', {'Checkbox-disabled': disabled}, className)} data-disabled={disabled || undefined}>
<RadixCheckbox.Root disabled={disabled} className="Checkbox-root" defaultChecked={defaultChecked} id={id} checked={checked} onCheckedChange={onChange}>
<RadixCheckbox.Indicator className="Checkbox-indicator">
<Icon icon="ion:checkmark-sharp" width={14} height={14} />
Expand Down
5 changes: 3 additions & 2 deletions src/components/Hint.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ReactNode } from 'react';
import './Hint.scss';
import { Icon, IconProps } from './Icon';
import { Tooltip } from './Tooltip';
import clsx from 'clsx';

export const Hint = ({text, className, ...props}: {text: string} & Omit<IconProps, 'icon' | 'ref'>) => {
return (<Tooltip label={text} maxWidth={400}>
export const Hint = ({content, className, ...props}: {content: ReactNode} & Omit<IconProps, 'icon' | 'ref'>) => {
return (<Tooltip label={content} maxWidth={400}>
<Icon icon='ion:help-circle' className={clsx('Hint', className)} height={20} {...props}/>
</Tooltip>);
};
2 changes: 1 addition & 1 deletion src/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Icon } from './Icon';
import { createPortal } from 'react-dom';
import clsx from 'clsx';
import useMeasure from 'react-use-measure';
import { useHotkeys } from 'react-hotkeys-hook';
import { useHotkeys } from '@utils/hooks';

export type ModalProps = {
title: string;
Expand Down
9 changes: 5 additions & 4 deletions src/components/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { cloneElement, useState } from "react";
import { ReactNode, cloneElement, useId, useState } from "react";
import {
Placement,
offset,
Expand All @@ -20,7 +20,7 @@ import { AnimatePresence, motion } from "framer-motion";
import './Tooltip.scss';

interface Props {
label: string;
label: ReactNode;
showDelay?: number;
resetDelay?: number;
placement?: Placement;
Expand All @@ -32,6 +32,7 @@ interface Props {
export const Tooltip = ({ children, label, placement = "bottom", strategy = 'absolute', maxWidth = 0, showDelay = 200, resetDelay = 100 }: Props) => {
const { delay = showDelay, setCurrentId } = useDelayGroupContext();
const [open, setOpen] = useState(false);
const id = useId();

const { x, y, reference, floating, strategy: localStrategy, context } = useFloating({
placement,
Expand All @@ -41,7 +42,7 @@ export const Tooltip = ({ children, label, placement = "bottom", strategy = 'abs
setOpen(open);

if (open) {
setCurrentId(label);
setCurrentId(id);
}
},
middleware: [offset(5), flip(), shift({ padding: 8 })],
Expand All @@ -53,7 +54,7 @@ export const Tooltip = ({ children, label, placement = "bottom", strategy = 'abs
useFocus(context),
useRole(context, { role: "tooltip" }),
useDismiss(context),
useDelayGroup(context, { id: label })
useDelayGroup(context, { id })
]);

const translate = {
Expand Down
13 changes: 13 additions & 0 deletions src/components/WhatsNew.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
gap: 24px;
padding: 0 18px;
}

.margin-top {
margin-top: 1rem;
}

ul {
margin-left: 22px;
Expand All @@ -32,5 +36,14 @@
p:not(:first-of-type) {
margin-top: 2rem;
}

.analytics-checkbox {
margin-top: 1rem;
font-size: 1.25rem;
justify-content: center;
padding: 1rem;
border-radius: 8px;
background: var(--background-lighter);
}
}
}
43 changes: 42 additions & 1 deletion src/components/WhatsNew.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,52 @@
import { useAtom } from 'jotai';
import { ScrollArea } from './ScrollArea';
import { ShortcutHint } from './ShortcutHint';
import './WhatsNew.scss';
import { analyticsEnabledAtom } from '@utils/analytics';
import { Checkbox } from './Checkbox';

export const WhatsNew = () => {
const [analyticsEnabled, setAnalyticsEnabled] = useAtom(analyticsEnabledAtom);

return (<div className="WhatsNew">
<ScrollArea className='WhatsNew-scrollarea'>
<div className='WhatsNew-content'>
<section>
<h2>1.6.0</h2>
<p>
Recently, Anori got a lot of traction on tiki-toki app, and I'd like to use this opportunity to
welcome new users. I hope you get yourself comfortable with Anori. In this version, I addressed
some bugs and inconveniences you reported, now you can:
</p>
<ul className='margin-top'>
<li>
Open Anori tab by clicking on extension icon in top right
corner (especially useful for Opera users).
</li>
<li>
Reorder tasks in ToDo widget.
</li>
<li>
Import bookmark from browser (when adding new bookmark to folder).
</li>
</ul>

<p>
I also added analytics to better understand which functions you use the most and which aren't
used. Analytics is opt-in, so Anori won't send any data if you don't enable analytics. And
even when enabled, extension doesn't send any private info. All it collect is: how much folders
you have, which widgets you use, which theme you use, how many custom icons you have, how often
you use keyboard shortcuts. Anori doesn't send name of your folder, or URL of bookmarks, or
content of your notes.
</p>

<p>
I kindly ask you to enable this feature, as it will help me to develop better product.
You can always change your choice in settings.
</p>

<Checkbox className="analytics-checkbox" checked={analyticsEnabled} onChange={setAnalyticsEnabled}>Enable sending analytics</Checkbox>
</section>
<section>
<h2>1.5.0</h2>
<p>
Expand All @@ -26,7 +67,7 @@ export const WhatsNew = () => {
</p>

<p>
<strong>Please note.</strong> To support custom icons in backups, format of backups also changed
<strong>Please note.</strong> To support custom icons in backups, format of backups also changed
(now it's zip which includes your custom icons). So if you use this feature you might
want to export a fresh backup.
</p>
Expand Down
6 changes: 4 additions & 2 deletions src/components/command-menu/CommandMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Command } from 'cmdk';
import { useEffect, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import './CommandMenu.scss';
import { Icon } from '@components/Icon';
import { AnoriPlugin, CommandItem } from '@utils/user-data/types';
import { availablePlugins } from '@plugins/all';
import { wait } from '@utils/misc';
import { ScrollArea } from '@components/ScrollArea';
import { useHotkeys } from '@utils/hooks';
import { trackEvent } from '@utils/analytics';

const ON_COMMAND_INPUT_TIMEOUT = 300;

Expand Down Expand Up @@ -64,9 +65,10 @@ export const CommandMenu = () => {
{actions.filter(({ items }) => items.length !== 0).map(({ plugin, items }) => {
return (<Command.Group heading={plugin.name} key={plugin.id}>
{items.map(({ icon, text, hint, key, onSelected, image }) => {
return (<Command.Item key={key} value={key} onSelect={e => {
return (<Command.Item key={key} value={key} onSelect={async (e) => {
setOpen(false);
setQuery('');
await trackEvent('Command option selected', { plugin: plugin.id });
onSelected();
}}>
<div cmdk-item-icon="">
Expand Down
3 changes: 1 addition & 2 deletions src/pages/newtab/components/FolderContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import { WidgetCard } from '@components/WidgetCard';
import { FolderContentContext } from '@utils/FolderContentContext';
import { useRef } from 'react';
import { fixHorizontalOverflows, layoutTo2DArray, positionToPixelPosition, snapToSector, useGrid, willItemOverlay } from '@utils/grid';
import { useWindowIsResizing } from '@utils/hooks';
import { useHotkeys, useWindowIsResizing } from '@utils/hooks';
import { Modal } from '@components/Modal';
import { WidgetMetadataContext } from '@utils/plugin';
import { OnboardingCard } from '@components/OnboardingCard';
import { useHotkeys } from 'react-hotkeys-hook';
import { useSizeSettings } from '@utils/compact';


Expand Down
20 changes: 18 additions & 2 deletions src/pages/newtab/components/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { Input } from '@components/Input';
import { downloadBlob, showOpenFilePicker } from '@utils/files';
import { Tooltip } from '@components/Tooltip';
import JSZip from 'jszip';
import { analyticsEnabledAtom } from '@utils/analytics';
import { useAtom } from 'jotai';


const FolderItem = ({ folder, editable = false, onRemove, onNameChange, onIconChange }: {
Expand Down Expand Up @@ -191,6 +193,7 @@ export const Settings = () => {
const [isAutomaticCompact, setAutomaticCompact] = useBrowserStorageValue('automaticCompactMode', true);
const [manualCompactMode, setManualCompactMode] = useBrowserStorageValue('compactMode', false);
const [showLoadAnimation, setShowLoadAnimation] = useBrowserStorageValue('showLoadAnimation', false);
const [analyticsEnabled, setAnalyticsEnabled] = useAtom(analyticsEnabledAtom);

const { customIcons, addNewCustomIcon, removeCustomIcon } = useCustomIcons();
const [draftCustomIcons, setDraftCustomIcons] = useState<DraftCustomIcon[]>([]);
Expand All @@ -201,14 +204,27 @@ export const Settings = () => {
The Settings Menu is a powerful tool for customizing your user experience. Here, you can tweak everything from the default color scheme to the order of folders.
With the Settings Menu, you have total control over the look and feel of your new tab.

<motion.section layout="position">
<h2>Analytics</h2>
<Checkbox checked={analyticsEnabled} onChange={setAnalyticsEnabled}>
Enable sending analytics
<Hint content={<>
Analytics helps me better understand how users interact with Anori and
which features are used the most. I doesn't share any private info like content of
notes or URL of bookmarks.

<div style={{marginTop: '0.5rem'}}>This helps me to develop better product so I ask you to enable sending analytics.</div>
</>} />
</Checkbox>
</motion.section>

<motion.section layout="position">
<h2>Options</h2>
<div className='options-checkboxes'>
{/* Focus stealer works only in Chrome and Safari */}
{X_BROWSER !== 'firefox' && <Checkbox checked={stealFocus} onChange={setStealFocus}>
Steal focus from addressbar
<Hint text='If enabled, this will force browser to move focus from address bar to this page when opening new tab and you will be able to use command menu (Cmd+K) without needing to move focus to page manually (by clicking or pressing Tab).' />
<Hint content='If enabled, this will force browser to move focus from address bar to this page when opening new tab and you will be able to use command menu (Cmd+K) without needing to move focus to page manually (by clicking or pressing Tab).' />
</Checkbox>}
<Checkbox checked={isAutomaticCompact} onChange={setAutomaticCompact}>
Automatically switch to compact mode based on screen size
Expand All @@ -218,7 +234,7 @@ export const Settings = () => {
</Checkbox>
<Checkbox checked={showLoadAnimation} onChange={setShowLoadAnimation}>
Show animation on open
<Hint text={`If enabled, extension will show quick loading animation which will hide initial flicker of loading data and provide better look.`} />
<Hint content="If enabled, extension will show quick loading animation which will hide initial flicker of loading data and provide better look." />
</Checkbox>
</div>
</motion.section>
Expand Down
3 changes: 1 addition & 2 deletions src/pages/newtab/start.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ import { AnimatePresence, MotionConfig, motion } from 'framer-motion';
import { useFolders } from '@utils/user-data/hooks';
import { FolderContent } from './components/FolderContent';
import { homeFolder } from '@utils/user-data/types';
import { usePrevious } from '@utils/hooks';
import { useHotkeys, usePrevious } from '@utils/hooks';
import { storage, useBrowserStorageValue } from '@utils/storage';
import { applyTheme, defaultTheme } from '@utils/user-data/theme';
import { CommandMenu } from '@components/command-menu/CommandMenu';
import { watchForPermissionChanges } from '@utils/permissions';
import { useHotkeys } from 'react-hotkeys-hook';
import { ShortcutsHelp } from '@components/ShortcutsHelp';
import { WhatsNew } from '@components/WhatsNew';
import clsx from 'clsx';
Expand Down
Loading

0 comments on commit dfd7265

Please sign in to comment.