Skip to content

Commit

Permalink
Merge pull request #57 from jiftechnify/scroll-to-top
Browse files Browse the repository at this point in the history
Scroll list to top when title was clicked
  • Loading branch information
jiftechnify authored Nov 22, 2023
2 parents e243464 + e85a7fb commit 3ecb992
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 8 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"i18next": "^23.5.1",
"i18next-browser-languagedetector": "^7.1.0",
"jotai": "^2.4.2",
"js-easing-functions": "^1.0.3",
"lucide-react": "^0.277.0",
"nip07-awaiter": "^0.2.1",
"nostr-fetch": "^0.13.0",
Expand Down
17 changes: 13 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { css, cx } from "@shadow-panda/styled-system/css";
import { circle, vstack } from "@shadow-panda/styled-system/patterns";
import { icon } from "@shadow-panda/styled-system/recipes";
import { ArrowUpCircle } from "lucide-react";
import { Suspense } from "react";
import { Suspense, useRef } from "react";
import { HeaderMenu } from "./components/HeaderMenu";
import { LoginForm } from "./components/LoginForm";
import { UpdateStatusDialog } from "./components/UpdateStatusDialog";
import { UserStatusList } from "./components/UserStatusList";
import { UserStatusList, UserStatusListHandle } from "./components/UserStatusList";
import { useMyPubkey, useWriteOpsEnabled } from "./states/nostr";
import { useColorTheme } from "./states/theme";
import { button } from "./styles/recipes";
Expand All @@ -18,6 +18,11 @@ export const App = () => {

const isTouch = isTouchDevice();

const refStatusList = useRef<UserStatusListHandle>(null);
const handleClickHeader = () => {
refStatusList.current?.scrollToTop();
};

return (
<div
className={vstack({
Expand All @@ -40,7 +45,11 @@ export const App = () => {
})}
>
<div className={css({ mr: "auto" })}></div>
<div className={css({ lineHeight: "tight", textAlign: "center" })}>
<div
className={css({ lineHeight: "tight", textAlign: "center", cursor: "pointer" })}
role="button"
onClick={handleClickHeader}
>
<h1 className={css({ textStyle: "title" })}>nostatus</h1>
<p className={css({ textStyle: "tagline", color: "text.sub" })}>Have an eye on your friends' status.</p>
</div>
Expand All @@ -54,7 +63,7 @@ export const App = () => {
<main className={css({ h: "100%", w: "100vw" })}>
<Suspense>
{pubkey !== undefined ? (
<UserStatusList />
<UserStatusList ref={refStatusList} />
) : (
<LoginForm css={{ position: "relative", top: isTouch ? "max(calc(50% - 14rem), 16px)" : "16px" }} />
)}
Expand Down
45 changes: 41 additions & 4 deletions src/components/UserStatusList.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
import { css } from "@shadow-panda/styled-system/css";
import { useAtomValue } from "jotai";
import { VList } from "virtua";
import { easeInOutQuart } from "js-easing-functions";
import { forwardRef, useImperativeHandle, useRef } from "react";
import { useTranslation } from "react-i18next";
import { VList, VListHandle } from "virtua";
import { pubkeysOrderByLastStatusUpdateTimeAtom } from "../states/nostr";
import { UserStatusCard } from "./UserStatusCard";
import { useTranslation } from "react-i18next";

export const UserStatusList: React.FC = () => {
export type UserStatusListHandle = {
scrollToTop(): void;
};

export const UserStatusList = forwardRef<UserStatusListHandle>(function UserStatusList(_, ref) {
const orderedPubkeys = useAtomValue(pubkeysOrderByLastStatusUpdateTimeAtom);

const refVList = useRef<VListHandle>(null);
useImperativeHandle(
ref,
() => {
return {
scrollToTop() {
if (refVList.current === null) {
return;
}
const vl = refVList.current;
animatedScroll(vl.scrollOffset, (n) => vl.scrollTo(n));
},
};
},
[]
);

const { t } = useTranslation();

return (
<VList>
<VList ref={refVList} overscan={10}>
{/* spacer above the top item */}
<div className={css({ h: "2" })}></div>

Expand Down Expand Up @@ -42,4 +65,18 @@ export const UserStatusList: React.FC = () => {
<div className={css({ h: "4" })}></div>
</VList>
);
});

const animatedScroll = (start: number, scrollTo: (n: number) => void) => {
const duration = Math.max(Math.min(start / 7, 1000), 200);

const startedAt = Date.now();
const tick = () => {
const elapsed = Date.now() - startedAt;
scrollTo(easeInOutQuart(elapsed, start, -start, duration));
if (elapsed < duration) {
requestAnimationFrame(tick);
}
};
tick();
};
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4427,6 +4427,11 @@ jotai@^2.4.2:
resolved "https://registry.yarnpkg.com/jotai/-/jotai-2.4.2.tgz#85610d82d247a7b19de7cce82e8d3ddf007f8d4d"
integrity sha512-90jXVOd9h6gi5JXk558M+wnJfaaVN2WegcNOCfiFbWboNaDl6DkRgiY/K1oeqTfYJmq8yM7XPsL99LAvcOPqhw==

js-easing-functions@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/js-easing-functions/-/js-easing-functions-1.0.3.tgz#01bcf4d4779994a55e3d7790ba755ef7872ba629"
integrity sha512-skDTLPuwWvAVYQVPwmjcFuCv8i8jtVD4L4FELxICwbS1HWFhs+627vOdDhQUGJMe9os6QO2XgEI4qb5umiUQFg==

"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
Expand Down

0 comments on commit 3ecb992

Please sign in to comment.