Skip to content

Commit

Permalink
Support moar toast things
Browse files Browse the repository at this point in the history
  • Loading branch information
aeharding committed Dec 22, 2024
1 parent fe377f2 commit 2e21a6b
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 34 deletions.
1 change: 0 additions & 1 deletion src/features/settings/blocks/FilteredWebsites.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export default function FilteredWebsites() {
presentToast({
message: "Invalid website",
color: "danger",
centerText: true,
icon: close,
});
return false;
Expand Down
1 change: 0 additions & 1 deletion src/features/settings/tags/Reset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export default function ResetTags() {
presentToast({
message: "User tags reset",
color: "success",
centerText: true,
});
})();
},
Expand Down
42 changes: 34 additions & 8 deletions src/features/shared/toast/Toast.module.css
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
.container {
--top-offset: 44px;

html:global(.md) & {
--top-offset: 56px;
}

position: absolute;
top: calc(var(--top-offset) + var(--ion-safe-area-top, 0px));
left: 0;
right: 0;
width: 100%;
height: 100%;
overflow: hidden;

pointer-events: none;

--top-offset: 44px;

html:global(.md) & {
--top-offset: 56px;
--bottom-offset: 56px;
}

&.fullscreen {
--top-offset: 0 !important;
top: 0;
}

top: calc(var(--top-offset) + var(--ion-safe-area-top, 0px));

&.bottom {
top: auto;
bottom: 0;
}
}

.toast {
Expand All @@ -24,12 +36,26 @@
left: 0;
right: 0;
z-index: 200;

.bottom & {
top: initial;
bottom: 0;
}

.fullscreen & {
padding-top: var(--ion-safe-area-top, 0px);
}

.bottom.fullscreen & {
padding-top: 0;
padding-bottom: var(--ion-safe-area-bottom, 0px);
}
}

.toastContent {
height: 50px;
border-radius: 16px;
margin: 8px;
padding: 12px;

display: flex;
align-items: center;
Expand Down
30 changes: 24 additions & 6 deletions src/features/shared/toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
} from "react";
import { createPortal } from "react-dom";

import { cx } from "#/helpers/css";

import styles from "./Toast.module.css";

export interface ToastHandler {
Expand All @@ -29,6 +31,7 @@ interface OpenToastOptions {
onClick?: (e: MouseEvent) => void;
fullscreen?: boolean;
color?: Color;
position?: "top" | "bottom";
}

export default function Toast({ ref, onClose }: ToastProps) {
Expand All @@ -40,6 +43,7 @@ export default function Toast({ ref, onClose }: ToastProps) {
const { start, clear } = useTimeout(handleClose, options?.duration ?? 3_000);

const onCloseEvent = useEffectEvent(onClose ?? noop);
const isBottom = options?.position === "bottom";

useEffect(() => {
if (open) {
Expand All @@ -59,7 +63,9 @@ export default function Toast({ ref, onClose }: ToastProps) {

const yStart = typeof y.get() === "number" ? y.get() : 0;

const yEnd = -scope.current.clientHeight;
const yEnd = isBottom
? scope.current.clientHeight
: -scope.current.clientHeight;

await animate(scope.current, { y: [yStart, yEnd] }, { ease: "easeOut" });
setOpen(false);
Expand All @@ -75,16 +81,24 @@ export default function Toast({ ref, onClose }: ToastProps) {
const color = options?.color ?? "primary";

return createPortal(
<div className={styles.container}>
<div
className={cx(
styles.container,
options?.fullscreen && styles.fullscreen,
isBottom && styles.bottom,
)}
>
<motion.div
ref={scope}
className={styles.toast}
initial={{ y: "-100%" }}
initial={{ y: isBottom ? "100%" : "-100%" }}
animate={{ y: "0%" }}
style={{ y }}
transition={{ ease: "easeInOut" }}
onDragEnd={() => {
if (y.get() < -10) {
if (!isBottom && y.get() < -10) {
handleClose();
} else if (isBottom && y.get() > 10) {
handleClose();
} else {
start();
Expand All @@ -93,7 +107,9 @@ export default function Toast({ ref, onClose }: ToastProps) {
onDragStart={clear}
drag="y"
dragConstraints={{ top: 0, bottom: 0 }}
dragElastic={{ top: 0.5, bottom: 0 }}
dragElastic={
isBottom ? { top: 0, bottom: 0.5 } : { top: 0.5, bottom: 0 }
}
>
<div
className={styles.toastContent}
Expand All @@ -109,6 +125,8 @@ export default function Toast({ ref, onClose }: ToastProps) {
</div>
</motion.div>
</div>,
document.querySelector("ion-router-outlet")!,
options?.fullscreen
? document.body
: document.querySelector("ion-router-outlet")!,
);
}
3 changes: 0 additions & 3 deletions src/helpers/toastMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ const shortFailDefaults: Omit<AppToastOptions, "message"> = {
color: "danger",
position: "top",
icon: close,
centerText: true,
};

const shortSuccessDefaults: Omit<AppToastOptions, "message"> = {
color: "primary",
position: "top",
icon: checkmark,
centerText: true,
};

const shortModSuccessDefaults: Omit<AppToastOptions, "message"> = {
Expand All @@ -32,7 +30,6 @@ export const saveSuccess: AppToastOptions = {
color: "primary",
position: "top",
icon: checkmark,
centerText: true,
};

export const saveError: AppToastOptions = {
Expand Down
8 changes: 8 additions & 0 deletions src/helpers/useAppToast.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.icon {
font-size: 22px;
flex-shrink: 0;
}

.message {
font-weight: 500;
}
22 changes: 8 additions & 14 deletions src/helpers/useAppToast.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
import { NotificationType } from "@capacitor/haptics";
import { Color } from "@ionic/core";
import { IonIcon } from "@ionic/react";
import { styled } from "@linaria/react";
import { MouseEvent, createContext, useContext, useRef } from "react";
import { createContext, MouseEvent, useContext, useRef } from "react";

import Toast, { ToastHandler } from "#/features/shared/toast/Toast";

import { isNative } from "./device";
import useHapticFeedback from "./useHapticFeedback";

const Icon = styled(IonIcon)`
font-size: 22px;
`;

const Message = styled.div`
font-weight: 500;
`;
import styles from "./useAppToast.module.css";

export interface AppToastOptions {
message: string;
color?: Color;
position?: "top" | "bottom"; // todo
position?: "top" | "bottom";
icon?: string;
centerText?: boolean; // todo
fullscreen?: boolean; // todo
fullscreen?: boolean;
duration?: number;
onClick?: (e: MouseEvent, dismiss: () => void) => void;
}
Expand Down Expand Up @@ -63,8 +55,10 @@ export function AppToastProvider({ children }: React.PropsWithChildren) {

const content = (
<>
{options.icon && <Icon icon={options.icon} />}
<Message>{options.message}</Message>
{options.icon && (
<IonIcon icon={options.icon} className={styles.icon} />
)}
<div className={styles.message}>{options.message}</div>
</>
);

Expand Down
1 change: 0 additions & 1 deletion src/routes/pages/settings/about/AboutPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ export default function AboutPage() {
presentToast({
message: messages.current[messageIndex.current]!,
color: "success",
centerText: true,
});
messageIndex.current = (messageIndex.current + 1) % messages.current.length;
}
Expand Down

0 comments on commit 2e21a6b

Please sign in to comment.