Skip to content

Commit

Permalink
Add demo mode
Browse files Browse the repository at this point in the history
  • Loading branch information
derwebcoder authored Nov 2, 2024
1 parent c9ff672 commit f604fe2
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 4 deletions.
69 changes: 69 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
"@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.2",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-slider": "^1.2.1",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.1",
"@radix-ui/react-toast": "^1.2.1",
"@tiptap/extension-list-keymap": "^2.6.6",
"@tiptap/extension-mention": "^2.8.0",
Expand Down
24 changes: 24 additions & 0 deletions src/common/components/shadcn/label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/common/lib/utils"

const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)

const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName

export { Label }
27 changes: 27 additions & 0 deletions src/common/components/shadcn/switch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from "react"
import * as SwitchPrimitives from "@radix-ui/react-switch"

import { cn } from "@/common/lib/utils"

const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
)}
/>
</SwitchPrimitives.Root>
))
Switch.displayName = SwitchPrimitives.Root.displayName

export { Switch }
28 changes: 27 additions & 1 deletion src/container/Settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,17 @@ import {
tagStyles,
type TagStyle,
} from "../../scripts/theme/tagStyles";
import {
disableDemoMode,
setDemoModeUntil,
useDemoModeStore,
} from "@/scripts/store/demoModeStore";
import { Switch } from "@/common/components/shadcn/switch";
import { Label } from "@/common/components/shadcn/label";

export const Settings = () => {
const { toast } = useToast();
const isDemoMode = useDemoModeStore((s) => !!s.context.demoModeUntil);
const [isAutomaticBackupsEnabled, setIsAutomaticBackupsEnabled] = useState(
fileSystemService.isAutomaticBackupEnabled(),
);
Expand Down Expand Up @@ -202,7 +210,7 @@ export const Settings = () => {
</div>
<div className="pb-10 px-16 grid grid-cols-3 gap-10">
<div className="flex flex-col gap-4">
<h3 className="font-semibold">Theme</h3>
<h3 className="font-semibold">Appearance</h3>
<div className="flex flex-col gap-4 p-1">
<div className="flex flex-col gap-2">
<span className="flex flex-row gap-1">
Expand Down Expand Up @@ -235,6 +243,24 @@ export const Settings = () => {
</SelectContent>
</Select>
</div>
<div className="flex flex-col gap-2">
<span className="flex flex-row gap-1">
<Label htmlFor="demo-mode-switch">
Demo Mode
</Label>
</span>
<Switch
id="demo-mode-switch"
checked={isDemoMode}
onCheckedChange={() => {
if (isDemoMode) {
disableDemoMode();
} else {
setDemoModeUntil(new Date());
}
}}
/>
</div>
</div>
</div>
<div className="flex flex-col gap-4">
Expand Down
5 changes: 3 additions & 2 deletions src/container/SparkList/SparkItem/SparkItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ import { Button } from "../../../common/components/shadcn/button";

type Props = {
spark: Spark;
blur?: boolean;
};

export const SparkItem = (props: Props) => {
const [isEditing, setIsEditing] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);
const { spark } = props;
const { spark, blur = "false" } = props;

const handleSubmit = async (plainText: string, html: string) => {
await sparkService.updateSpark(spark.id, plainText, html);
Expand All @@ -45,7 +46,7 @@ export const SparkItem = (props: Props) => {
return (
<article
key={spark.id}
className="flex group relative"
className={`flex group relative ${blur ? "blur-sm" : ""}`}
>
{isEditing ? (
<div className="w-full h-full">
Expand Down
12 changes: 11 additions & 1 deletion src/container/SparkList/SparkList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useLiveQuery } from "dexie-react-hooks";
import { sparkService } from "../../scripts/db/SparkService";
import { differenceInCalendarDays, format } from "date-fns";
import { differenceInCalendarDays, format, isAfter } from "date-fns";
import { EmptyState } from "../../common/components/EmptyState/EmptyState";
import type { Spark } from "../../interfaces/Spark";
import { useQueryStore } from "../../scripts/store/queryStore";
import { SparkItem } from "./SparkItem/SparkItem";
import { Tag as TagElement } from "../../common/components/Tag/Tag";
import type { Tag } from "../../interfaces/Tag";
import { useDemoModeStore } from "../../scripts/store/demoModeStore";

type SparkSection = {
key: string;
Expand All @@ -29,6 +30,7 @@ export const SparkList = () => {
() => sparkService.find(queryTags),
[queryTags],
);
const demoModeUntil = useDemoModeStore((s) => s.context.demoModeUntil);

const sections = sparksWithTags?.reduce<Section[]>(
(tmpSections, { spark, contextTagData }) => {
Expand Down Expand Up @@ -140,6 +142,14 @@ export const SparkList = () => {
<SparkItem
key={spark.id}
spark={spark}
blur={
demoModeUntil
? isAfter(
demoModeUntil,
spark.creationDate,
)
: false
}
/>
))}
</div>
Expand Down
57 changes: 57 additions & 0 deletions src/scripts/store/demoModeStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { createStore, type SnapshotFromStore } from "@xstate/store";
import { debounce } from "../utils/debounce";
import { extractTags } from "../utils/stringUtils";
import { useSelector } from "@xstate/store/react";

export const demoModeStore = createStore({
// Initial context
context: { demoModeUntil: undefined } as {
demoModeUntil: Date | undefined
},
// Transitions
on: {
update: {
demoModeUntil: (_context, event: { until: Date | undefined }) => {
return event.until;
},
},
},
});

export const setDemoModeUntil = (until: Date) => {
demoModeStore.send({
type: 'update',
until,
})
}

export const disableDemoMode = () => {
demoModeStore.send({
type: 'update',
until: undefined,
})
}

export const useDemoModeStore = <T>(
selector: (snapshot: SnapshotFromStore<typeof demoModeStore>) => T,
) => {
return useSelector(demoModeStore, selector);
};

declare global {
interface Window {
demoModeStore: typeof demoModeStore;
debugDemoModeStore?: boolean;
}
}

if (typeof window !== "undefined") {
window.demoModeStore = demoModeStore;
}

// window.debugQueryStore = true;
demoModeStore.inspect((event) => {
if (window.debugDemoModeStore) {
console.log(event);
}
});

0 comments on commit f604fe2

Please sign in to comment.