-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* package lock version update * add shadcn dialog * Feat: add changelog component * increase dialog z-index * fix: indent wrapped title text and list items * fix: list overflow scroll and prevent fullscreen at small screen sizes * add recent changelogs * update usehooks-ts * fix: changelog overflow, only show on newUser/changes available * add spelling exception to workspace * fix: replace deprecated useElementSize hook * fix: changelog spelling * add changelog nav button * fix: more changelog text updates
- Loading branch information
1 parent
86c6a84
commit d788938
Showing
8 changed files
with
302 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
"luxon", | ||
"moveend", | ||
"ontime", | ||
"Openchange", | ||
"papaparse", | ||
"popupclose", | ||
"popupopen", | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogClose, | ||
DialogFooter, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "@/components/ui/dialog"; | ||
import { changelogs } from "./changelogs"; | ||
import Version from "./Version"; | ||
import { useLocalStorage } from "usehooks-ts"; | ||
import packageJson from "package.json"; | ||
import { useEffect } from "react"; | ||
const packageAppVersion = packageJson.version; | ||
|
||
const VERSION_KEY = "app-version"; | ||
const NEW_USER_KEY = "new-user"; | ||
|
||
type Props = { | ||
show: boolean; | ||
setShow: (s: boolean) => void; | ||
}; | ||
|
||
function Changelog({ show, setShow }: Props) { | ||
const [appVersion, setAppVersion] = useLocalStorage(VERSION_KEY, "default"); | ||
const [newUser, setNewUser] = useLocalStorage(NEW_USER_KEY, "default"); | ||
|
||
// Radix onOpenchange only triggers on dialog close | ||
const handleOpenChange = () => { | ||
setAppVersion(packageAppVersion); | ||
setShow(false); | ||
setNewUser("false"); | ||
}; | ||
|
||
useEffect(() => { | ||
if (appVersion === "default") { | ||
setAppVersion(packageAppVersion); | ||
} else if (appVersion === packageAppVersion && newUser === "default") { | ||
setNewUser("true"); | ||
setShow(true); | ||
} else if (appVersion !== packageAppVersion) { | ||
setShow(true); | ||
} | ||
}, [appVersion, newUser, setAppVersion, setNewUser, setShow]); | ||
|
||
if (appVersion === "default" || show === false) return null; | ||
|
||
return ( | ||
<Dialog open={show} onOpenChange={handleOpenChange}> | ||
<DialogTrigger className="sr-only">Open</DialogTrigger> | ||
<DialogContent className="max-w-[90dvw] md:max-w-lg rounded-lg"> | ||
<DialogHeader> | ||
<DialogTitle className="font-bold">Changelog</DialogTitle> | ||
</DialogHeader> | ||
<div className="overflow-y-auto max-h-[70dvh]"> | ||
{changelogs.map((record) => ( | ||
<Version key={"version: " + record.version} {...record} /> | ||
))} | ||
</div> | ||
<DialogFooter> | ||
<DialogClose>Dismiss</DialogClose> | ||
</DialogFooter> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
} | ||
|
||
export default Changelog; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import type { Changelog } from "./changelogs"; | ||
|
||
function Version({ version, changes, title }: Changelog) { | ||
return ( | ||
<section> | ||
<header> | ||
{!!title && <p className="italic py-2 pl-2 -indent-2">{title}</p>} | ||
<h3 className="text-lg">Version {version}:</h3> | ||
</header> | ||
<ul className="list-outside list-disc pl-5"> | ||
{changes.map((change) => ( | ||
<li className="last:pb-2" key={version + change}> | ||
{change} | ||
</li> | ||
))} | ||
</ul> | ||
</section> | ||
); | ||
} | ||
|
||
export default Version; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
export type Changelog = { | ||
version: string; | ||
changes: string[]; | ||
title?: string; | ||
}; | ||
export const changelogs: Changelog[] = [ | ||
{ | ||
version: "0.12.0", | ||
title: "Feature: Changelog dialog.", | ||
changes: [ | ||
"Add Shadcn dialog component.", | ||
"Add changelog component and recent app updates.", | ||
], | ||
}, | ||
{ | ||
version: "0.11.2", | ||
changes: [ | ||
"Fix dynamic map tiles url causing duplicate image caching.", | ||
"Fix security policy causing cached map tiles to use way too much storage space.", | ||
"Fix chrome service worker bug causing significant slowdown when ignoring url search params with many images cached.", | ||
], | ||
}, | ||
{ | ||
version: "0.11.1", | ||
changes: [ | ||
"Fix z-index inconsistencies in footer, global alerts, saved stops, and drawer/sheet ui components.", | ||
], | ||
}, | ||
{ | ||
version: "0.11.0", | ||
title: | ||
"Feature: change footer from accordion to mobile friendly drawer component.", | ||
changes: [ | ||
"Add shadcn drawer component.", | ||
"Adjust global muted color style.", | ||
], | ||
}, | ||
{ | ||
version: "0.10.0", | ||
title: "Feature: support installation as progressive web app (PWA).", | ||
changes: [ | ||
"High resolution icons for android and iOS.", | ||
"Cache map tiles for for reduced network bandwidth.", | ||
"Skip animations when changing map location.", | ||
"Adjust zoom level that displays vehicle markers.", | ||
], | ||
}, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import * as React from "react"; | ||
import * as DialogPrimitive from "@radix-ui/react-dialog"; | ||
import { X } from "lucide-react"; | ||
|
||
import { cn } from "@/lib/utils"; | ||
|
||
const Dialog = DialogPrimitive.Root; | ||
|
||
const DialogTrigger = DialogPrimitive.Trigger; | ||
|
||
const DialogPortal = DialogPrimitive.Portal; | ||
|
||
const DialogClose = DialogPrimitive.Close; | ||
|
||
const DialogOverlay = React.forwardRef< | ||
React.ElementRef<typeof DialogPrimitive.Overlay>, | ||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> | ||
>(({ className, ...props }, ref) => ( | ||
<DialogPrimitive.Overlay | ||
ref={ref} | ||
className={cn( | ||
"fixed inset-0 z-[2000] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; | ||
|
||
const DialogContent = React.forwardRef< | ||
React.ElementRef<typeof DialogPrimitive.Content>, | ||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> | ||
>(({ className, children, ...props }, ref) => ( | ||
<DialogPortal> | ||
<DialogOverlay /> | ||
<DialogPrimitive.Content | ||
ref={ref} | ||
className={cn( | ||
"fixed left-[50%] top-[50%] z-[3000] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", | ||
className, | ||
)} | ||
{...props} | ||
> | ||
{children} | ||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> | ||
<X className="h-4 w-4" /> | ||
<span className="sr-only">Close</span> | ||
</DialogPrimitive.Close> | ||
</DialogPrimitive.Content> | ||
</DialogPortal> | ||
)); | ||
DialogContent.displayName = DialogPrimitive.Content.displayName; | ||
|
||
const DialogHeader = ({ | ||
className, | ||
...props | ||
}: React.HTMLAttributes<HTMLDivElement>) => ( | ||
<div | ||
className={cn( | ||
"flex flex-col space-y-1.5 text-center sm:text-left", | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
); | ||
DialogHeader.displayName = "DialogHeader"; | ||
|
||
const DialogFooter = ({ | ||
className, | ||
...props | ||
}: React.HTMLAttributes<HTMLDivElement>) => ( | ||
<div | ||
className={cn( | ||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
); | ||
DialogFooter.displayName = "DialogFooter"; | ||
|
||
const DialogTitle = React.forwardRef< | ||
React.ElementRef<typeof DialogPrimitive.Title>, | ||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> | ||
>(({ className, ...props }, ref) => ( | ||
<DialogPrimitive.Title | ||
ref={ref} | ||
className={cn( | ||
"text-lg font-semibold leading-none tracking-tight", | ||
className, | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
DialogTitle.displayName = DialogPrimitive.Title.displayName; | ||
|
||
const DialogDescription = React.forwardRef< | ||
React.ElementRef<typeof DialogPrimitive.Description>, | ||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> | ||
>(({ className, ...props }, ref) => ( | ||
<DialogPrimitive.Description | ||
ref={ref} | ||
className={cn("text-sm text-muted-foreground", className)} | ||
{...props} | ||
/> | ||
)); | ||
DialogDescription.displayName = DialogPrimitive.Description.displayName; | ||
|
||
export { | ||
Dialog, | ||
DialogPortal, | ||
DialogOverlay, | ||
DialogClose, | ||
DialogTrigger, | ||
DialogContent, | ||
DialogHeader, | ||
DialogFooter, | ||
DialogTitle, | ||
DialogDescription, | ||
}; |
Oops, something went wrong.