Skip to content

Commit

Permalink
feat: Nativize "No distraction" theme as "Focus Mode" (#758)
Browse files Browse the repository at this point in the history
Co-authored-by: Mo Bitar <me@bitar.io>
  • Loading branch information
amanharwara and moughxyz authored Dec 2, 2021
1 parent fbafc13 commit 9730006
Show file tree
Hide file tree
Showing 17 changed files with 488 additions and 141 deletions.
4 changes: 4 additions & 0 deletions app/assets/icons/ic-menu-close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions app/assets/icons/ic-premium-feature.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion app/assets/javascripts/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
6 changes: 5 additions & 1 deletion app/assets/javascripts/components/Icon.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -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;
Expand Down
75 changes: 75 additions & 0 deletions app/assets/javascripts/components/PremiumFeaturesModal.tsx
Original file line number Diff line number Diff line change
@@ -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;
};
Original file line number Diff line number Diff line change
@@ -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)}
/>
</>
);
};
Loading

0 comments on commit 9730006

Please sign in to comment.