Files
notesnook/apps/web/src/components/dialogs/feature-dialog.tsx

160 lines
4.2 KiB
TypeScript
Raw Normal View History

2022-03-17 12:31:06 +05:00
import { Text, Flex } from "rebass";
import Dialog from "./dialog";
import * as Icon from "../icons";
import { getHomeRoute, hardNavigate } from "../../navigation";
import { appVersion } from "../../utils/version";
import Config from "../../utils/config";
import { isTesting } from "../../utils/platform";
2022-03-17 12:31:06 +05:00
type CallToAction = {
title: string;
icon?: (props: any) => JSX.Element;
action?: () => void;
};
type SubFeature = {
title: string;
icon?: (props: any) => JSX.Element;
subtitle?: string | JSX.Element;
};
type Feature = {
shouldShow?: () => boolean;
title: string;
subtitle?: string;
cta: CallToAction;
subFeatures?: SubFeature[];
};
export type FeatureKeys = "confirmed" | "highlights";
2022-03-17 12:31:06 +05:00
const features: Record<FeatureKeys, Feature> = {
confirmed: {
title: "Email confirmed!",
subtitle: "You can now sync your notes to unlimited devices.",
cta: {
title: "Continue",
icon: Icon.ArrowRight,
action: () => hardNavigate(getHomeRoute()),
},
},
highlights: {
title: "✨ Highlights ✨",
subtitle: `Welcome to v${appVersion.clean}`,
subFeatures: [
{
2022-04-14 15:55:54 +05:00
title: "All panes are now resizable",
2022-03-17 12:31:06 +05:00
subtitle: (
<>
2022-04-14 15:55:54 +05:00
You can now adjust the width of all the panes as you see fit. And
they persist across sessions too!
2022-03-17 12:31:06 +05:00
</>
),
2022-04-14 15:55:54 +05:00
icon: Icon.Resize,
},
{
title: "Sort alphabetically when group by = none",
subtitle: <>No idea why this wasn't included earlier.</>,
icon: Icon.SortBy,
2022-03-17 12:31:06 +05:00
},
],
cta: {
title: "Got it",
icon: Icon.Checkmark,
action: () => {
Config.set(`${appVersion.numerical}:highlights`, true);
},
},
shouldShow: () => {
const key = `${appVersion.numerical}:highlights`;
const hasShownBefore = Config.get(key, false) as boolean;
const hasShownAny = Config.has((k) => k.endsWith(":highlights"));
if (!hasShownAny) Config.set(key, true);
return hasShownAny && !isTesting() && !hasShownBefore;
2022-03-17 12:31:06 +05:00
},
},
};
type FeatureDialogProps = {
featureName: FeatureKeys;
onClose: (result: boolean) => void;
};
function FeatureDialog(props: FeatureDialogProps) {
const { featureName } = props;
const feature = features[featureName];
if (!feature || (feature.shouldShow && !feature.shouldShow())) {
props.onClose(false);
return null;
}
2022-03-17 12:31:06 +05:00
return (
<Dialog
isOpen={true}
title={feature.title}
description={feature.subtitle}
alignment="center"
positiveButton={{
text: (
<Flex>
{feature.cta.icon && (
<feature.cta.icon color="primary" size={16} sx={{ mr: 1 }} />
)}
{feature.cta.title}
</Flex>
),
onClick: () => {
if (feature.cta.action) feature.cta.action();
props.onClose(true);
},
}}
>
<Flex flexDirection="column" overflowY="auto" mt={2}>
{feature.subFeatures?.map((feature) => (
<Flex
mb={2}
bg="bgSecondary"
p={2}
sx={{ borderRadius: "default", ":hover": { bg: "hover" } }}
flexDirection="column"
>
<Flex alignItems={"center"} justifyContent="start">
{feature.icon && <feature.icon size={14} color="primary" />}
<Text variant="subtitle" fontWeight="normal" ml={1}>
{feature.title}
</Text>
</Flex>
{feature.subtitle && (
<Text variant="body" color="icon">
{feature.subtitle}
</Text>
)}
</Flex>
))}
</Flex>
</Dialog>
);
}
export default FeatureDialog;
type CodeProps = { text: string; href?: string };
export function Code(props: CodeProps) {
return (
<Text
as="code"
sx={{
bg: "background",
color: "text",
px: 1,
borderRadius: 5,
fontFamily: "monospace",
fontSize: "subBody",
border: "1px solid var(--border)",
cursor: props.href ? "pointer" : "unset",
}}
onClick={() => {
if (props.href) window.open(props.href, "_target");
}}
>
{props.text}
</Text>
);
}