Compare commits

..

No commits in common. "10b517bcebd274575805ebcf2f29ce80f0f16055" and "e68384349a47602b209f34a13e2a6a68e7b1b46f" have entirely different histories.

4 changed files with 32 additions and 159 deletions

View file

@ -8,10 +8,6 @@ import {
} from "solid-js"; } from "solid-js";
import { ANIM_CURVE_STD } from "./theme"; import { ANIM_CURVE_STD } from "./theme";
import "./Menu.css"; import "./Menu.css";
import {
animateGrowFromTopRight,
animateShrinkToTopRight,
} from "../platform/anim";
type Props = { type Props = {
open?: boolean; open?: boolean;
@ -55,7 +51,23 @@ const Menu: ParentComponent<Props> = (props) => {
top, top,
}); });
animateGrowFromTopRight(root, { easing: ANIM_CURVE_STD }); const overflow = root.style.overflow;
root.style.overflow = "hidden";
const duration = (rend.height / 1600) * 1000;
const easing = ANIM_CURVE_STD;
const animation = root.animate(
{
height: [`${rend.height / 2}px`, `${rend.height}px`],
},
{
duration,
easing,
},
);
animation.addEventListener(
"finish",
() => (root.style.overflow = overflow),
);
} else { } else {
openAnimationOrigin = "lt"; openAnimationOrigin = "lt";
setAnchorPos({ left, top }); setAnchorPos({ left, top });
@ -107,10 +119,19 @@ const Menu: ParentComponent<Props> = (props) => {
root.close(); root.close();
}); });
} else { } else {
const animation = animateShrinkToTopRight(root, { const overflow = root.style.overflow;
easing: ANIM_CURVE_STD, root.style.overflow = "hidden";
}); const animation = root.animate(
{
height: [`${rend.height}px`, `${rend.height / 2}px`],
},
{
duration: (rend.height / 2 / 1600) * 1000,
easing: ANIM_CURVE_STD,
},
);
animation.addEventListener("finish", () => { animation.addEventListener("finish", () => {
root.style.overflow = overflow;
root.close(); root.close();
}); });
} }

View file

@ -117,7 +117,6 @@
--tutu-shadow-e24: 0px 24px 48px 0px var(--tutu-color-shadow-l2); --tutu-shadow-e24: 0px 24px 48px 0px var(--tutu-color-shadow-l2);
/* curves are also hard-coded in theme.ts */
--tutu-anim-curve-std: cubic-bezier(0.4, 0, 0.2, 1); --tutu-anim-curve-std: cubic-bezier(0.4, 0, 0.2, 1);
--tutu-anim-curve-deceleration: cubic-bezier(0, 0, 0.2, 1); --tutu-anim-curve-deceleration: cubic-bezier(0, 0, 0.2, 1);
--tutu-anim-curve-aceleration: cubic-bezier(0.4, 0, 1, 1); --tutu-anim-curve-aceleration: cubic-bezier(0.4, 0, 1, 1);

View file

@ -53,145 +53,3 @@ export function useHeroSignal(
return [() => undefined, () => undefined]; return [() => undefined, () => undefined];
} }
} }
export function animateRollOutFromTop(
root: HTMLElement,
options?: Omit<KeyframeAnimationOptions, "duration">,
) {
const overflow = root.style.overflow;
root.style.overflow = "hidden";
const { height } = root.getBoundingClientRect();
const opts = Object.assign(
{
duration: Math.floor((height / 1600) * 1000),
},
options,
);
const animation = root.animate(
{
height: ["0px", `${height}px`],
},
opts,
);
const restore = () => (root.style.overflow = overflow);
animation.addEventListener("finish", restore);
animation.addEventListener("cancel", restore);
return animation;
}
export function animateRollInFromBottom(
root: HTMLElement,
options?: Omit<KeyframeAnimationOptions, "duration">,
) {
const overflow = root.style.overflow;
root.style.overflow = "hidden";
const { height } = root.getBoundingClientRect();
const opts = Object.assign(
{
duration: Math.floor((height / 1600) * 1000),
},
options,
);
const animation = root.animate(
{
height: [`${height}px`, "0px"],
},
opts,
);
const restore = () => (root.style.overflow = overflow);
animation.addEventListener("finish", restore);
animation.addEventListener("cancel", restore);
return animation;
}
export function animateGrowFromTopRight(
root: HTMLElement,
options?: KeyframeAnimationOptions,
) {
const transformOrigin = root.style.transformOrigin;
root.style.transformOrigin = "top right";
const { width, height } = root.getBoundingClientRect();
const durationX = Math.floor((height / 1600) * 1000);
const durationY = Math.floor((width / 1600) * 1000);
// finds the offset for the center frame,
// it will stops at the (minDuration / maxDuration)%
const minDuration = Math.min(durationX, durationY);
const maxDuration = Math.max(durationX, durationY);
const centerOffset = minDuration / maxDuration;
const keyframes = [
{ transform: "scaleX(0)", opacity: 0, height: "0px", offset: 0 },
{
transform: `scaleX(${minDuration === durationX ? "1" : centerOffset})`,
height: `${(minDuration === durationY ? 1 : centerOffset) * height}px`,
offset: centerOffset,
opacity: 1,
},
{ transform: "scaleX(1)", height: `${height}px`, offset: 1 },
];
const animation = root.animate(
keyframes,
{ ...options, duration: maxDuration },
);
const restore = () => {
root.style.transformOrigin = transformOrigin;
};
animation.addEventListener("cancel", restore);
animation.addEventListener("finish", restore);
return animation;
}
export function animateShrinkToTopRight(
root: HTMLElement,
options?: KeyframeAnimationOptions,
) {
const overflow = root.style.overflow;
root.style.overflow = "hidden";
const transformOrigin = root.style.transformOrigin;
root.style.transformOrigin = "top right";
const { width, height } = root.getBoundingClientRect();
const duration = Math.floor(
Math.max((width / 1600) * 1000, (height / 1600) * 1000),
);
const animation = root.animate(
{
transform: ["scale(1)", "scale(0.5)"],
opacity: [1, 0],
},
{ ...options, duration },
);
const restore = () => {
root.style.overflow = overflow;
root.style.transformOrigin = transformOrigin;
};
animation.addEventListener("cancel", restore);
animation.addEventListener("finish", restore);
return animation;
}

View file

@ -106,9 +106,9 @@ const TootList: Component<{
const target = actionableElement as HTMLAnchorElement; const target = actionableElement as HTMLAnchorElement;
const acct = encodeURIComponent( const acct =
target.dataset.client || `@${new URL(target.href).origin}`, encodeURIComponent(target.dataset.client ||
); `@${new URL(target.href).origin}`);
navigate(`/${acct}/profile/${target.dataset.acctId}`); navigate(`/${acct}/profile/${target.dataset.acctId}`);
@ -116,11 +116,6 @@ const TootList: Component<{
} else { } else {
console.warn("unknown action", actionableElement.dataset.rel); console.warn("unknown action", actionableElement.dataset.rel);
} }
} else if (
event.target.parentElement &&
event.target.parentElement.tagName === "A"
) {
return;
} }
// else if (!actionableElement || !checkIsExpended(status) || <rel is not one of known action>) // else if (!actionableElement || !checkIsExpended(status) || <rel is not one of known action>)