diff --git a/docs/devnotes.md b/docs/devnotes.md index 31f8cb9..cf6e9a0 100644 --- a/docs/devnotes.md +++ b/docs/devnotes.md @@ -10,10 +10,6 @@ You can debug on the Safari on iOS only if you have mac (and run macOS). The cer - For visual bugs: on you iDevice, redirect the localhost.direct to your dev computer. Now you have the hot reload on you iDevice. - You can use network debugging apps like "Shadowrocket" to do such thing. -## Hero Animation won't work (after hot reload) - -That's a known issue. Hot reload won't refresh the module sets the hero cache. Refresh the whole page and it should work. - ## The components don't react to the change as I setting the store, until the page reloaded The `WritableAtom.set` might do an equals check. You must set a different object to ensure the atom sending a notify. @@ -47,3 +43,9 @@ Ja, the code is weird, but that's the best we know. Anyway, you need new object Idk why, but transition on logical directions may not work on WebKit - sometimes they work. Use physical directions to avoid trouble, like "margin-top, margin-bottom". + +## Safe area insets + +For isolating control of the UI effect, we already setup css variables `--safe-area-inset-*`. In components, you should use the variables unless you have reasons to use `env()`. + +Using `--safe-area-inset-*`, you can control the global value in settings (under dev mode). diff --git a/src/material/BottomSheet.tsx b/src/material/BottomSheet.tsx index c7e0671..a5d5d90 100644 --- a/src/material/BottomSheet.tsx +++ b/src/material/BottomSheet.tsx @@ -9,12 +9,10 @@ import { type ResolvedChildren, } from "solid-js"; import "./BottomSheet.css"; -import { useHeroSignal } from "../platform/anim"; import material from "./material.module.css"; import { ANIM_CURVE_ACELERATION, ANIM_CURVE_DECELERATION, - ANIM_CURVE_STD, } from "./theme"; import { animateSlideInFromRight, @@ -28,32 +26,11 @@ export type BottomSheetProps = { onClose?(reason: "backdrop"): void; }; -export const HERO = Symbol("BottomSheet Hero Symbol"); - -function composeAnimationFrame( - { - top, - left, - height, - width, - }: Record<"top" | "left" | "height" | "width", number>, - x: Record, -) { - return { - top: `${top}px`, - left: `${left}px`, - height: `${height}px`, - width: `${width}px`, - ...x, - }; -} - const MOVE_SPEED = 1600; const BottomSheet: ParentComponent = (props) => { let element: HTMLDialogElement; let animation: Animation | undefined; - const [hero, setHero] = useHeroSignal(HERO); const [cache, setCache] = createSignal(); const ochildren = children(() => props.children); @@ -74,24 +51,11 @@ const BottomSheet: ParentComponent = (props) => { }); const onClose = () => { - const srcElement = hero(); - if (srcElement) { - srcElement.style.visibility = "unset"; - } - element.close(); - setHero(); }; const animatedClose = () => { - const srcElement = hero(); - const endRect = srcElement?.getBoundingClientRect(); - if (endRect) { - const startRect = element.getBoundingClientRect(); - const animation = animateHero(startRect, endRect, element, true); - animation.addEventListener("finish", onClose); - animation.addEventListener("cancel", onClose); - } else { + if (window.innerWidth > 560 && !props.bottomUp) { onClose(); return; @@ -106,21 +70,12 @@ const BottomSheet: ParentComponent = (props) => { : animateSlideOutToRight(element, { easing: ANIM_CURVE_ACELERATION }); animation.addEventListener("finish", onAnimationEnd); animation.addEventListener("cancel", onAnimationEnd); - } + }; const animatedOpen = () => { element.showModal(); - const srcElement = hero(); - const startRect = srcElement?.getBoundingClientRect(); - if (!startRect) { - console.debug("no source element"); - } - if (startRect) { - srcElement!.style.visibility = "hidden"; - const endRect = element.getBoundingClientRect(); - animateHero(startRect, endRect, element); - } else if (props.bottomUp) { + if (props.bottomUp) { animateSlideInFromBottom(element); } else if (window.innerWidth <= 560) { element.classList.add("animated"); @@ -165,41 +120,6 @@ const BottomSheet: ParentComponent = (props) => { return animation; }; - const animateHero = ( - startRect: DOMRect, - endRect: DOMRect, - element: HTMLElement, - reserve?: boolean, - ) => { - const easing = ANIM_CURVE_STD; - element.classList.add("animated"); - // distance_lt = (|top_start - top_end|^2 + |left_end - left_end|^2)^(-2) - const distancelt = Math.sqrt( - Math.pow(Math.abs(startRect.top - endRect.top), 2) + - Math.pow(Math.abs(startRect.left - endRect.left), 2), - ); - const distancerb = Math.sqrt( - Math.pow(Math.abs(startRect.bottom - endRect.bottom), 2) + - Math.pow(Math.abs(startRect.right - endRect.right), 2), - ); - const distance = distancelt + distancerb; - const duration = distance / 1.6; - animation = element.animate( - [ - composeAnimationFrame(startRect, { transform: "none" }), - composeAnimationFrame(endRect, { transform: "none" }), - ], - { easing, duration }, - ); - const onAnimationEnd = () => { - element.classList.remove("animated"); - animation = undefined; - }; - animation.addEventListener("finish", onAnimationEnd); - animation.addEventListener("cancel", onAnimationEnd); - return animation; - }; - onCleanup(() => { if (animation) { animation.cancel(); diff --git a/src/material/Scaffold.css b/src/material/Scaffold.css index 56b2cd0..b4a7c74 100644 --- a/src/material/Scaffold.css +++ b/src/material/Scaffold.css @@ -32,7 +32,6 @@ left: 0; right: 0; z-index: var(--tutu-zidx-nav, auto); - padding-bottom: var(--safe-area-inset-bottom, 0); } .Scaffold { diff --git a/src/platform/anim.ts b/src/platform/anim.ts index dfffc87..f606872 100644 --- a/src/platform/anim.ts +++ b/src/platform/anim.ts @@ -1,58 +1,3 @@ -import { - createContext, - createRenderEffect, - createSignal, - untrack, - useContext, - type Accessor, - type Signal, -} from "solid-js"; - -export type HeroSource = { - [key: string | symbol | number]: HTMLElement | undefined; -}; - -const HeroSourceContext = createContext>( - /* __@PURE__ */ undefined, -); - -export const HeroSourceProvider = HeroSourceContext.Provider; - -export function useHeroSource() { - return useContext(HeroSourceContext); -} - -/** - * Use hero value for the {@link key}. - * - * Note: the setter here won't set the value of the hero source. - * To set hero source, use {@link useHeroSource} and set the corresponding key. - */ -export function useHeroSignal( - key: string | symbol | number, -): Signal { - const source = useHeroSource(); - if (source) { - const [get, set] = createSignal(); - - createRenderEffect(() => { - const value = source[0](); - if (value[key]) { - set(value[key]); - source[1]((x) => { - const cpy = Object.assign({}, x); - delete cpy[key]; - return cpy; - }); - } - }); - - return [get, set]; - } else { - console.debug("no hero source"); - return [() => undefined, () => undefined]; - } -} export function animateRollOutFromTop( root: HTMLElement, diff --git a/src/timelines/TootComposer.tsx b/src/timelines/TootComposer.tsx index 50d5e0e..5693332 100644 --- a/src/timelines/TootComposer.tsx +++ b/src/timelines/TootComposer.tsx @@ -98,7 +98,7 @@ const TootVisibilityPickerDialog: Component<{ style={{ "border-top": "1px solid #ddd", background: "var(--tutu-color-surface)", - padding: "8px 16px", + padding: "8px 16px calc(8px + var(--safe-area-inset-bottom, 0px))", width: "100%", "text-align": "end", }} diff --git a/src/timelines/TootList.tsx b/src/timelines/TootList.tsx index 38670e2..41e01f7 100644 --- a/src/timelines/TootList.tsx +++ b/src/timelines/TootList.tsx @@ -10,8 +10,6 @@ import { import { type mastodon } from "masto"; import { vibrate } from "../platform/hardware"; import { useDefaultSession } from "../masto/clients"; -import { useHeroSource } from "../platform/anim"; -import { HERO as BOTTOM_SHEET_HERO } from "../material/BottomSheet"; import { setCache as setTootBottomSheetCache } from "./TootBottomSheet"; import RegularToot, { findElementActionable, @@ -53,7 +51,6 @@ const TootList: Component<{ onChangeToot: (id: string, value: mastodon.v1.Status) => void; }> = (props) => { const session = useDefaultSession(); - const heroSrc = useHeroSource(); const [expandedThreadId, setExpandedThreadId] = createSignal(); const { push } = useNavigator(); @@ -124,9 +121,6 @@ const TootList: Component<{ console.warn("no account info?"); return; } - if (heroSrc) { - heroSrc[1]((x) => ({ ...x, [BOTTOM_SHEET_HERO]: srcElement })); - } const acct = `${inf.username}@${p.site}`; setTootBottomSheetCache(acct, toot);