feat: Nativize "No distraction" theme as "Focus Mode" (#758)

Co-authored-by: Mo Bitar <me@bitar.io>
This commit is contained in:
Aman Harwara
2021-12-02 22:34:57 +05:30
committed by GitHub
parent fbafc136e8
commit 9730006cba
17 changed files with 488 additions and 141 deletions

View File

@@ -0,0 +1,4 @@
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M17.5 13.0083L16.325 14.1667L12.15 10L16.325 5.83333L17.5 6.99167L14.5333 10L17.5 13.0083ZM2.5 5H13.3333V6.66667H2.5V5ZM2.5 10.8333V9.16667H10.8333V10.8333H2.5ZM2.5 15V13.3333H13.3333V15H2.5Z" />
</svg>

After

Width:  |  Height:  |  Size: 290 B

View File

@@ -0,0 +1,6 @@
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect opacity="0.36" x="1" y="1" width="18" height="18" rx="9" fill="#BBBEC4" />
<path
d="M6.6665 12H7.99984C7.99984 12.72 8.91317 13.3333 9.99984 13.3333C11.0865 13.3333 11.9998 12.72 11.9998 12C11.9998 11.2667 11.3065 11 9.83984 10.6467C8.4265 10.2933 6.6665 9.85333 6.6665 8C6.6665 6.80667 7.6465 5.79333 8.99984 5.45333V4H10.9998V5.45333C12.3532 5.79333 13.3332 6.80667 13.3332 8H11.9998C11.9998 7.28 11.0865 6.66667 9.99984 6.66667C8.91317 6.66667 7.99984 7.28 7.99984 8C7.99984 8.73333 8.69317 9 10.1598 9.35333C11.5732 9.70667 13.3332 10.1467 13.3332 12C13.3332 13.1933 12.3532 14.2067 10.9998 14.5467V16H8.99984V14.5467C7.6465 14.2067 6.6665 13.1933 6.6665 12Z"
fill="#72767E" />
</svg>

After

Width:  |  Height:  |  Size: 779 B

View File

@@ -78,7 +78,7 @@ import { PreferencesDirective } from './preferences';
import { AppVersion, IsWebPlatform } from '@/version';
import { NotesListOptionsDirective } from './components/NotesListOptionsMenu';
import { PurchaseFlowDirective } from './purchaseFlow';
import { QuickSettingsMenuDirective } from './components/QuickSettingsMenu';
import { QuickSettingsMenuDirective } from './components/QuickSettingsMenu/QuickSettingsMenu';
import { ComponentViewDirective } from '@/components/ComponentView';
import { TagsListDirective } from '@/components/TagsList';

View File

@@ -1,3 +1,4 @@
import PremiumFeatureIcon from '../../icons/ic-premium-feature.svg';
import PencilOffIcon from '../../icons/ic-pencil-off.svg';
import PlainTextIcon from '../../icons/ic-text-paragraph.svg';
import RichTextIcon from '../../icons/ic-text-rich.svg';
@@ -15,6 +16,7 @@ import TrashSweepIcon from '../../icons/ic-trash-sweep.svg';
import MoreIcon from '../../icons/ic-more.svg';
import TuneIcon from '../../icons/ic-tune.svg';
import MenuArrowDownIcon from '../../icons/ic-menu-arrow-down.svg';
import MenuCloseIcon from '../../icons/ic-menu-close.svg';
import AuthenticatorIcon from '../../icons/ic-authenticator.svg';
import SpreadsheetsIcon from '../../icons/ic-spreadsheets.svg';
import TasksIcon from '../../icons/ic-tasks.svg';
@@ -107,7 +109,9 @@ const ICONS = {
'check-bold': CheckBoldIcon,
'account-circle': AccountCircleIcon,
'menu-arrow-down': MenuArrowDownIcon,
window: WindowIcon
'menu-close': MenuCloseIcon,
window: WindowIcon,
'premium-feature': PremiumFeatureIcon
};
export type IconType = keyof typeof ICONS;

View File

@@ -0,0 +1,75 @@
import {
AlertDialog,
AlertDialogDescription,
AlertDialogLabel,
} from '@reach/alert-dialog';
import { FunctionalComponent } from 'preact';
import { Icon } from './Icon';
import PremiumIllustration from '../../svg/il-premium.svg';
import { useRef } from 'preact/hooks';
type Props = {
featureName: string;
onClose: () => void;
showModal: boolean;
};
export const PremiumFeaturesModal: FunctionalComponent<Props> = ({
featureName,
onClose,
showModal,
}) => {
const plansButtonRef = useRef<HTMLButtonElement>(null);
const onClickPlans = () => {
if (window._plans_url) {
window.location.assign(window._plans_url);
}
};
return showModal ? (
<AlertDialog leastDestructiveRef={plansButtonRef}>
<div tabIndex={-1} className="sn-component">
<div
tabIndex={0}
className="max-w-89 bg-default rounded shadow-overlay p-4"
>
<AlertDialogLabel>
<div className="flex justify-end p-1">
<button
className="flex p-0 cursor-pointer bg-transparent border-0"
onClick={onClose}
aria-label="Close modal"
>
<Icon className="color-neutral" type="close" />
</button>
</div>
<div
className="flex items-center justify-center p-1"
aria-hidden={true}
>
<PremiumIllustration className="mb-2" />
</div>
<div className="text-lg text-center font-bold mb-1">
Enable premium features
</div>
</AlertDialogLabel>
<AlertDialogDescription className="text-sm text-center color-grey-1 px-4.5 mb-2">
In order to use <span className="font-semibold">{featureName}</span>{' '}
and other premium features, please purchase a subscription or
upgrade your current plan.
</AlertDialogDescription>
<div className="p-4">
<button
onClick={onClickPlans}
className="w-full rounded no-border py-2 font-bold bg-info color-info-contrast hover:brightness-130 focus:brightness-130 cursor-pointer"
ref={plansButtonRef}
>
See our plans
</button>
</div>
</div>
</div>
</AlertDialog>
) : null;
};

View File

@@ -0,0 +1,66 @@
import { WebApplication } from '@/ui_models/application';
import { FeatureIdentifier } from '@standardnotes/features';
import { FeatureStatus } from '@standardnotes/snjs';
import { FunctionComponent } from 'preact';
import { useState } from 'preact/hooks';
import { JSXInternal } from 'preact/src/jsx';
import { Icon } from '../Icon';
import { PremiumFeaturesModal } from '../PremiumFeaturesModal';
import { Switch } from '../Switch';
type Props = {
application: WebApplication;
closeQuickSettingsMenu: () => void;
focusModeEnabled: boolean;
setFocusModeEnabled: (enabled: boolean) => void;
};
export const FocusModeSwitch: FunctionComponent<Props> = ({
application,
closeQuickSettingsMenu,
focusModeEnabled,
setFocusModeEnabled,
}) => {
const [showUpgradeModal, setShowUpgradeModal] = useState(false);
const isEntitledToFocusMode =
application.getFeatureStatus(FeatureIdentifier.FocusMode) ===
FeatureStatus.Entitled;
const toggleFocusMode = (
e: JSXInternal.TargetedMouseEvent<HTMLButtonElement>
) => {
e.preventDefault();
if (isEntitledToFocusMode) {
setFocusModeEnabled(!focusModeEnabled);
closeQuickSettingsMenu();
} else {
setShowUpgradeModal(true);
}
};
return (
<>
<button
className="sn-dropdown-item focus:bg-info-backdrop focus:shadow-none justify-between"
onClick={toggleFocusMode}
>
<div className="flex items-center">
<Icon type="menu-close" className="color-neutral mr-2" />
Focused Writing
</div>
{isEntitledToFocusMode ? (
<Switch className="px-0" checked={focusModeEnabled} />
) : (
<div title="Premium feature">
<Icon type="premium-feature" />
</div>
)}
</button>
<PremiumFeaturesModal
showModal={showUpgradeModal}
featureName="Focus Mode"
onClose={() => setShowUpgradeModal(false)}
/>
</>
);
};

View File

@@ -15,81 +15,46 @@ import { observer } from 'mobx-react-lite';
import { FunctionComponent } from 'preact';
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { JSXInternal } from 'preact/src/jsx';
import { Icon } from './Icon';
import { Switch } from './Switch';
import { toDirective, useCloseOnBlur } from './utils';
import { Icon } from '../Icon';
import { Switch } from '../Switch';
import { toDirective, useCloseOnBlur } from '../utils';
import {
quickSettingsKeyDownHandler,
themesMenuKeyDownHandler,
} from './eventHandlers';
import { FocusModeSwitch } from './FocusModeSwitch';
import { ThemesMenuButton } from './ThemesMenuButton';
const MENU_CLASSNAME =
'sn-menu-border sn-dropdown min-w-80 max-h-120 max-w-xs flex flex-col py-2 overflow-y-auto';
type ThemeButtonProps = {
theme: SNTheme;
application: WebApplication;
onBlur: (event: { relatedTarget: EventTarget | null }) => void;
};
type MenuProps = {
appState: AppState;
application: WebApplication;
};
const ThemeButton: FunctionComponent<ThemeButtonProps> = ({
application,
theme,
onBlur,
}) => {
const toggleTheme = (e: any) => {
e.preventDefault();
if (theme.isLayerable() || !theme.active) {
application.toggleComponent(theme);
const toggleFocusMode = (enabled: boolean) => {
if (enabled) {
document.body.classList.add('focus-mode');
} else {
if (document.body.classList.contains('focus-mode')) {
document.body.classList.add('disable-focus-mode');
document.body.classList.remove('focus-mode');
setTimeout(() => {
document.body.classList.remove('disable-focus-mode');
}, 315);
}
};
return (
<button
className={`sn-dropdown-item focus:bg-info-backdrop focus:shadow-none ${
theme.isLayerable() ? `justify-start` : `justify-between`
}`}
onClick={toggleTheme}
onBlur={onBlur}
>
{theme.isLayerable() ? (
<>
<Switch
className="px-0 mr-2"
checked={theme.active}
onChange={toggleTheme}
/>
{theme.package_info.name}
</>
) : (
<>
<div className="flex items-center">
<div
className={`pseudo-radio-btn ${
theme.active ? 'pseudo-radio-btn--checked' : ''
} mr-2`}
></div>
<span className={theme.active ? 'font-semibold' : undefined}>
{theme.package_info.name}
</span>
</div>
<div
className="w-5 h-5 rounded-full"
style={{
backgroundColor: theme.package_info?.dock_icon?.background_color,
}}
></div>
</>
)}
</button>
);
}
};
const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
({ application, appState }) => {
const { closeQuickSettingsMenu, shouldAnimateCloseMenu } =
appState.quickSettingsMenu;
const {
closeQuickSettingsMenu,
shouldAnimateCloseMenu,
focusModeEnabled,
setFocusModeEnabled,
} = appState.quickSettingsMenu;
const [themes, setThemes] = useState<SNTheme[]>([]);
const [toggleableComponents, setToggleableComponents] = useState<
SNComponent[]
@@ -104,6 +69,10 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
const quickSettingsMenuRef = useRef<HTMLDivElement>(null);
const defaultThemeButtonRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
toggleFocusMode(focusModeEnabled);
}, [focusModeEnabled]);
const reloadThemes = useCallback(() => {
application.streamItems(ContentType.Theme, () => {
const themes = application.getDisplayableItems(
@@ -157,12 +126,12 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
useEffect(() => {
if (themesMenuOpen) {
defaultThemeButtonRef.current!.focus();
defaultThemeButtonRef.current?.focus();
}
}, [themesMenuOpen]);
useEffect(() => {
prefsButtonRef.current!.focus();
prefsButtonRef.current?.focus();
}, []);
const [closeOnBlur] = useCloseOnBlur(
@@ -171,9 +140,9 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
);
const toggleThemesMenu = () => {
if (!themesMenuOpen) {
if (!themesMenuOpen && themesButtonRef.current) {
const themesButtonRect =
themesButtonRef.current!.getBoundingClientRect();
themesButtonRef.current.getBoundingClientRect();
setThemesMenuPosition({
left: themesButtonRect.right,
bottom:
@@ -200,7 +169,7 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
switch (event.key) {
case 'Escape':
setThemesMenuOpen(false);
themesButtonRef.current!.focus();
themesButtonRef.current?.focus();
break;
case 'ArrowRight':
if (!themesMenuOpen) {
@@ -211,65 +180,23 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
const handleQuickSettingsKeyDown: JSXInternal.KeyboardEventHandler<HTMLDivElement> =
(event) => {
const items: NodeListOf<HTMLButtonElement> =
quickSettingsMenuRef.current!.querySelectorAll(':scope > button');
const currentFocusedIndex = Array.from(items).findIndex(
(btn) => btn === document.activeElement
quickSettingsKeyDownHandler(
closeQuickSettingsMenu,
event,
quickSettingsMenuRef,
themesMenuOpen
);
if (!themesMenuOpen) {
switch (event.key) {
case 'Escape':
closeQuickSettingsMenu();
break;
case 'ArrowDown':
if (items[currentFocusedIndex + 1]) {
items[currentFocusedIndex + 1].focus();
} else {
items[0].focus();
}
break;
case 'ArrowUp':
if (items[currentFocusedIndex - 1]) {
items[currentFocusedIndex - 1].focus();
} else {
items[items.length - 1].focus();
}
break;
}
}
};
const handlePanelKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (
event
) => {
const themes = themesMenuRef.current!.querySelectorAll('button');
const currentFocusedIndex = Array.from(themes).findIndex(
(themeBtn) => themeBtn === document.activeElement
themesMenuKeyDownHandler(
event,
themesMenuRef,
setThemesMenuOpen,
themesButtonRef
);
switch (event.key) {
case 'Escape':
case 'ArrowLeft':
event.stopPropagation();
setThemesMenuOpen(false);
themesButtonRef.current!.focus();
break;
case 'ArrowDown':
if (themes[currentFocusedIndex + 1]) {
themes[currentFocusedIndex + 1].focus();
} else {
themes[0].focus();
}
break;
case 'ArrowUp':
if (themes[currentFocusedIndex - 1]) {
themes[currentFocusedIndex - 1].focus();
} else {
themes[themes.length - 1].focus();
}
break;
}
};
const toggleDefaultTheme = () => {
@@ -332,7 +259,7 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
Default
</button>
{themes.map((theme) => (
<ThemeButton
<ThemesMenuButton
theme={theme}
application={application}
key={theme.uuid}
@@ -341,7 +268,6 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
))}
</DisclosurePanel>
</Disclosure>
{toggleableComponents.map((component) => (
<Switch
className="sn-dropdown-item focus:bg-info-backdrop focus:shadow-none"
@@ -356,10 +282,15 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = observer(
</div>
</Switch>
))}
<FocusModeSwitch
application={application}
closeQuickSettingsMenu={closeQuickSettingsMenu}
focusModeEnabled={focusModeEnabled}
setFocusModeEnabled={setFocusModeEnabled}
/>
<div className="h-1px my-2 bg-border"></div>
<button
class="sn-dropdown-item focus:bg-info-backdrop focus:shadow-none"
className="sn-dropdown-item focus:bg-info-backdrop focus:shadow-none"
onClick={openPreferences}
ref={prefsButtonRef}
>

View File

@@ -0,0 +1,60 @@
import { WebApplication } from '@/ui_models/application';
import { SNTheme } from '@standardnotes/snjs';
import { FunctionComponent } from 'preact';
import { JSXInternal } from 'preact/src/jsx';
import { Switch } from '../Switch';
type Props = {
theme: SNTheme;
application: WebApplication;
onBlur: (event: { relatedTarget: EventTarget | null }) => void;
};
export const ThemesMenuButton: FunctionComponent<Props> = ({
application,
theme,
onBlur,
}) => {
const toggleTheme: JSXInternal.MouseEventHandler<HTMLButtonElement> = (e) => {
e.preventDefault();
if (theme.isLayerable() || !theme.active) {
application.toggleComponent(theme);
}
};
return (
<button
className={`sn-dropdown-item focus:bg-info-backdrop focus:shadow-none ${
theme.isLayerable() ? `justify-start` : `justify-between`
}`}
onClick={toggleTheme}
onBlur={onBlur}
>
{theme.isLayerable() ? (
<>
<Switch className="px-0 mr-2" checked={theme.active} />
{theme.package_info.name}
</>
) : (
<>
<div className="flex items-center">
<div
className={`pseudo-radio-btn ${
theme.active ? 'pseudo-radio-btn--checked' : ''
} mr-2`}
></div>
<span className={theme.active ? 'font-semibold' : undefined}>
{theme.package_info.name}
</span>
</div>
<div
className="w-5 h-5 rounded-full"
style={{
backgroundColor: theme.package_info?.dock_icon?.background_color,
}}
></div>
</>
)}
</button>
);
};

View File

@@ -0,0 +1,77 @@
import { RefObject } from 'preact';
import { StateUpdater } from 'preact/hooks';
import { JSXInternal } from 'preact/src/jsx';
export const quickSettingsKeyDownHandler = (
closeQuickSettingsMenu: () => void,
event: JSXInternal.TargetedKeyboardEvent<HTMLDivElement>,
quickSettingsMenuRef: RefObject<HTMLDivElement>,
themesMenuOpen: boolean
) => {
if (quickSettingsMenuRef?.current) {
const items: NodeListOf<HTMLButtonElement> =
quickSettingsMenuRef.current.querySelectorAll(':scope > button');
const currentFocusedIndex = Array.from(items).findIndex(
(btn) => btn === document.activeElement
);
if (!themesMenuOpen) {
switch (event.key) {
case 'Escape':
closeQuickSettingsMenu();
break;
case 'ArrowDown':
if (items[currentFocusedIndex + 1]) {
items[currentFocusedIndex + 1].focus();
} else {
items[0].focus();
}
break;
case 'ArrowUp':
if (items[currentFocusedIndex - 1]) {
items[currentFocusedIndex - 1].focus();
} else {
items[items.length - 1].focus();
}
break;
}
}
}
};
export const themesMenuKeyDownHandler = (
event: React.KeyboardEvent<HTMLDivElement>,
themesMenuRef: RefObject<HTMLDivElement>,
setThemesMenuOpen: StateUpdater<boolean>,
themesButtonRef: RefObject<HTMLButtonElement>
) => {
if (themesMenuRef?.current) {
const themes = themesMenuRef.current.querySelectorAll('button');
const currentFocusedIndex = Array.from(themes).findIndex(
(themeBtn) => themeBtn === document.activeElement
);
switch (event.key) {
case 'Escape':
case 'ArrowLeft':
event.stopPropagation();
setThemesMenuOpen(false);
themesButtonRef.current?.focus();
break;
case 'ArrowDown':
if (themes[currentFocusedIndex + 1]) {
themes[currentFocusedIndex + 1].focus();
} else {
themes[0].focus();
}
break;
case 'ArrowUp':
if (themes[currentFocusedIndex - 1]) {
themes[currentFocusedIndex - 1].focus();
} else {
themes[themes.length - 1].focus();
}
break;
}
}
};

View File

@@ -10,7 +10,8 @@ import '@reach/checkbox/styles.css';
export type SwitchProps = HTMLProps<HTMLInputElement> & {
checked?: boolean;
onChange: (checked: boolean) => void;
// Optional in case it is wrapped in a button (e.g. a menu item)
onChange?: (checked: boolean) => void;
className?: string;
children?: ComponentChildren;
role?: string;
@@ -32,7 +33,7 @@ export const Switch: FunctionalComponent<SwitchProps> = (
checked={checked}
onChange={(event) => {
setChecked(event.target.checked);
props.onChange(event.target.checked);
props.onChange?.(event.target.checked);
}}
className={`sn-switch ${checked ? 'bg-info' : 'bg-neutral'}`}
>

View File

@@ -3,14 +3,17 @@ import { action, makeObservable, observable } from 'mobx';
export class QuickSettingsState {
open = false;
shouldAnimateCloseMenu = false;
focusModeEnabled = false;
constructor() {
makeObservable(this, {
open: observable,
shouldAnimateCloseMenu: observable,
focusModeEnabled: observable,
setOpen: action,
setShouldAnimateCloseMenu: action,
setFocusModeEnabled: action,
toggle: action,
closeQuickSettingsMenu: action,
});
@@ -24,6 +27,10 @@ export class QuickSettingsState {
this.shouldAnimateCloseMenu = shouldAnimate;
};
setFocusModeEnabled = (enabled: boolean): void => {
this.focusModeEnabled = enabled;
};
toggle = (): void => {
if (this.open) {
this.closeQuickSettingsMenu();

View File

@@ -0,0 +1,88 @@
.section.tags,
.section.notes {
transition: width 1.25s;
}
.focus-mode {
.mac-desktop #editor-column {
// To offset colored circles in Mac
padding-top: 35px;
}
.mac-desktop #editor-column:before {
content: '';
display: block;
position: absolute;
top: 0;
width: 100%;
height: 38px;
-webkit-app-region: drag;
}
#editor-title-bar {
display: none;
}
#editor-menu-bar {
display: none;
}
#editor-pane-component-stack {
display: none;
}
#footer-bar {
opacity: 0.08;
transition: opacity 0.25s;
}
#footer-bar:hover {
opacity: 1;
}
.section.tags,
.section.notes {
will-change: opacity;
animation: fade-out 1.25s forwards;
transition-delay: 0s;
width: 0px !important;
flex: none !important;
}
.section.tags:hover {
flex: initial;
width: 0px !important;
}
.section.notes:hover {
flex: initial;
width: 0px !important;
}
}
.disable-focus-mode {
.section.tags,
.section.notes {
will-change: opacity;
animation: fade-in 1.25s forwards;
}
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
border: none !important;
}
}

View File

@@ -289,6 +289,10 @@
max-width: 18rem;
}
.max-w-89 {
max-width: 22.25rem;
}
.mb-4 {
margin-bottom: 1rem;
}
@@ -300,10 +304,6 @@
margin-bottom: 2rem;
}
.max-w-89 {
max-width: 22.25rem;
}
.w-26 {
width: 6.5rem;
}
@@ -461,6 +461,11 @@
padding-right: 0;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.sn-component .px-4\.5,
.sn-component .sk-panel .px-4\.5 {
padding-left: 1.375rem;

View File

@@ -13,4 +13,5 @@
@import 'reach-sub';
@import 'sessions-modal';
@import 'preferences';
@import 'focused';
@import 'sn';

View File

@@ -0,0 +1,22 @@
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="60" cy="60" r="60" fill="#F4F5F7" />
<g filter="url(#filter0_d_5_1809)">
<rect x="31" y="31" width="58" height="58" rx="4" fill="white" />
<path
d="M49.9997 66H53.9997C53.9997 68.16 56.7397 70 59.9997 70C63.2596 70 65.9996 68.16 65.9996 66C65.9996 63.8 63.9197 63 59.5197 61.94C55.2797 60.88 49.9997 59.56 49.9997 54C49.9997 50.42 52.9397 47.38 56.9997 46.36V42H62.9996V46.36C67.0596 47.38 69.9996 50.42 69.9996 54H65.9996C65.9996 51.84 63.2596 50 59.9997 50C56.7397 50 53.9997 51.84 53.9997 54C53.9997 56.2 56.0796 57 60.4796 58.06C64.7196 59.12 69.9996 60.44 69.9996 66C69.9996 69.58 67.0596 72.62 62.9996 73.64V78H56.9997V73.64C52.9397 72.62 49.9997 69.58 49.9997 66Z"
fill="#BBBEC4" />
</g>
<defs>
<filter id="filter0_d_5_1809" x="19" y="23" width="82" height="82" filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha" />
<feOffset dy="4" />
<feGaussianBlur stdDeviation="6" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.16 0" />
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5_1809" />
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5_1809" result="shape" />
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -78,9 +78,9 @@
"@reach/checkbox": "^0.16.0",
"@reach/dialog": "^0.16.2",
"@reach/listbox": "^0.16.2",
"@standardnotes/features": "1.9.0",
"@standardnotes/features": "1.10.1",
"@standardnotes/sncrypto-web": "1.5.3",
"@standardnotes/snjs": "2.18.2",
"@standardnotes/snjs": "2.18.3",
"mobx": "^6.3.5",
"mobx-react-lite": "^3.2.2",
"preact": "^10.5.15",

View File

@@ -2587,10 +2587,10 @@
dependencies:
"@standardnotes/auth" "^3.8.1"
"@standardnotes/features@1.9.0", "@standardnotes/features@^1.8.3":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.9.0.tgz#6b563dbc177592a6c0741abc7794b0cd6f1989e0"
integrity sha512-fuRfLrnKEq43ti7FpYZhZu9SLk6j8ruuLcDygoS8gDKB3LU3yuAbKfumqnt0NDF/hXg5/y5FhxxjYQX2GxykoA==
"@standardnotes/features@1.10.1", "@standardnotes/features@^1.10.1":
version "1.10.1"
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.10.1.tgz#5b5a59d2d69751ca040a270d04a08662b1591bfc"
integrity sha512-fN7WyR8jeaAsDWkm4a6SSz3JZeaNfL+CkmWAYqxRI5XoXZlWy+kBVaYWaGe7vI4T6ncwdhxRTjE7mirG4PEQ6g==
dependencies:
"@standardnotes/auth" "3.8.3"
"@standardnotes/common" "^1.2.1"
@@ -2614,15 +2614,15 @@
buffer "^6.0.3"
libsodium-wrappers "^0.7.9"
"@standardnotes/snjs@2.18.2":
version "2.18.2"
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.18.2.tgz#42957cf50b18e2db3f10dacb2c3dfa95c16719e7"
integrity sha512-KcYRwxJJmA+b9E0xXJGDsdCC3ptNaDLiGDpB8Lv4lUpjH6Z1VC43oxhFDXVxLLrQxTpQULvhlkW8Mc38Kxtzxg==
"@standardnotes/snjs@2.18.3":
version "2.18.3"
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.18.3.tgz#5dd685c6e0df4c07c98b087aa672411e9becde4c"
integrity sha512-Q8X1UUSUw4NkKcZPHFYZ/WH9weOXW7LelOE1kCBx/O1g284dJWvHhqQh8qTgjHQnrcYR8Xh3AfoR0bh1Ms+iyA==
dependencies:
"@standardnotes/auth" "^3.8.1"
"@standardnotes/common" "^1.2.1"
"@standardnotes/domain-events" "^2.5.1"
"@standardnotes/features" "^1.8.3"
"@standardnotes/features" "^1.10.1"
"@standardnotes/settings" "^1.2.1"
"@standardnotes/sncrypto-common" "^1.5.2"