Skip to content
This repository was archived by the owner on Aug 2, 2025. It is now read-only.

Commit 8ca5f02

Browse files
committed
feat: view transitions
1 parent 6d2909d commit 8ca5f02

File tree

9 files changed

+121
-45
lines changed

9 files changed

+121
-45
lines changed

apps/client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"react-dom": "^18.1.0",
5151
"react-error-boundary": "^4.0.10",
5252
"react-icons": "^4.4.0",
53-
"react-router-dom": "^6.5.0",
53+
"react-router-dom": "^6.20.1",
5454
"rollup-plugin-workbox": "^6.2.0",
5555
"typescript": "^5.1.6",
5656
"web-vitals": "^3.0.1",

apps/client/src/components/BottomNav/BottomNav.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const BottomNav = () => {
3131
border={"1px"}
3232
borderBottom="none"
3333
borderColor={useColorModeValue("gray.200", "gray.700")}
34+
className="bottom-nav"
3435
>
3536
{pages.pinned.map((routes) => (
3637
<SidebarButton
@@ -43,14 +44,15 @@ export const BottomNav = () => {
4344
))}
4445
<SidebarButton name={"More"} icon={DotsThree} onClick={onOpen} />
4546
<Drawer isOpen={isOpen} placement="bottom" onClose={onClose}>
46-
<DrawerOverlay />
47+
<DrawerOverlay className="bottom-nav-drawer-overlay" />
4748
<DrawerContent
4849
bg={useColorModeValue("whiteAlpha.600", "blackAlpha.600")}
4950
backdropFilter="auto"
5051
backdropBlur="36px"
5152
roundedTop="2xl"
5253
border={"1px"}
5354
borderColor={useColorModeValue("gray.200", "gray.700")}
55+
className="bottom-nav-drawer"
5456
>
5557
<DrawerCloseButton />
5658
<DrawerHeader fontFamily={"Poppins, sans-serif"}>

apps/client/src/components/Nav/Nav.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export const SettingsBTN = ({
144144
>
145145
<RouterLink
146146
to={pathname.startsWith("/app/settings") ? "/app" : "/app/settings"}
147+
unstable_viewTransition
147148
>
148149
<IconButton
149150
variant="outline"
@@ -188,6 +189,7 @@ export default function Nav() {
188189
backdropBlur="36px"
189190
border={"1px"}
190191
borderColor={useColorModeValue("gray.200", "gray.700")}
192+
className="main-nav"
191193
>
192194
<TimetablLogo color={logoColor} loggedIn={loggedIn} />
193195
{loggedIn && <RefetchingIndicator />}

apps/client/src/components/Sidebar/Sidebar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export default function Sidebar() {
2020
border={"1px"}
2121
borderTop={"none"}
2222
borderColor={useColorModeValue("gray.200", "gray.700")}
23+
className="sidebar"
2324
>
2425
{pages.pinned.map((routes) => (
2526
<SidebarButton

apps/client/src/components/Sidebar/SidebarButton.tsx

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,47 @@ export default React.memo(function SidebarButton(props: {
2222
const [secondary] = useToken("colors", ["primary.300"]);
2323
const active = to ? Boolean(useMatch(to)) : false;
2424

25-
return (
26-
<Box as={RouterLink} w="full" to={to} onClick={onClick}>
25+
const linkContents = (
26+
<Flex
27+
_hover={{ bg: hoverColor }}
28+
p={"12px"}
29+
h={"64px"}
30+
w="100%"
31+
direction={"column"}
32+
align={"center"}
33+
>
2734
<Flex
28-
_hover={{ bg: hoverColor }}
29-
p={"12px"}
30-
h={"64px"}
31-
w="100%"
32-
direction={"column"}
35+
as={motion.div}
36+
justify={"center"}
37+
bg={active ? secondary + "40" : undefined}
38+
animate={{ width: active ? "56px" : "0px" }}
3339
align={"center"}
40+
borderRadius={"16px"}
41+
h={"32px"}
3442
>
35-
<Flex
36-
as={motion.div}
37-
justify={"center"}
38-
bg={active ? secondary + "40" : undefined}
39-
animate={{ width: active ? "56px" : "0px" }}
40-
align={"center"}
41-
borderRadius={"16px"}
42-
h={"32px"}
43-
>
44-
<Box minH={"24px"}>
45-
<Icon
46-
size="24px"
47-
mirrored={mirrored}
48-
weight={active ? "fill" : "duotone"}
49-
/>
50-
</Box>
51-
</Flex>
52-
<Text as={active ? "b" : "label"} fontSize={"xs"} mt="4px">
53-
{name}
54-
</Text>
43+
<Box minH={"24px"}>
44+
<Icon
45+
size="24px"
46+
mirrored={mirrored}
47+
weight={active ? "fill" : "duotone"}
48+
/>
49+
</Box>
5550
</Flex>
51+
<Text as={active ? "b" : "label"} fontSize={"xs"} mt="4px">
52+
{name}
53+
</Text>
54+
</Flex>
55+
);
56+
57+
return (
58+
<Box w="full" onClick={onClick}>
59+
{to ? (
60+
<RouterLink unstable_viewTransition to={to}>
61+
{linkContents}
62+
</RouterLink>
63+
) : (
64+
linkContents
65+
)}
5666
</Box>
5767
);
5868
});

apps/client/src/index.css

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* Main contents */
2+
3+
@keyframes fade-in {
4+
from {
5+
opacity: 0;
6+
}
7+
}
8+
9+
@keyframes fade-out {
10+
to {
11+
opacity: 0;
12+
}
13+
}
14+
15+
@keyframes slide-from-bottom {
16+
from {
17+
transform: translateY(50px);
18+
}
19+
}
20+
21+
@keyframes slide-to-top {
22+
to {
23+
transform: translateY(-50px);
24+
}
25+
}
26+
27+
::view-transition-old(root) {
28+
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
29+
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-top;
30+
}
31+
32+
::view-transition-new(root) {
33+
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
34+
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-bottom;
35+
}
36+
37+
/* Static Navigation */
38+
.main-nav {
39+
view-transition-name: main-nav;
40+
}
41+
42+
.sidebar {
43+
view-transition-name: sidebar;
44+
}
45+
46+
.bottom-nav {
47+
view-transition-name: bottom-nav;
48+
}
49+
50+
.bottom-nav-drawer {
51+
view-transition-name: bottom-nav-drawer;
52+
}
53+
54+
.bottom-nav-drawer-overlay {
55+
view-transition-name: bottom-nav-drawer-overlay;
56+
}
57+
58+
.settings-nav {
59+
view-transition-name: settings-nav;
60+
}

apps/client/src/main.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import config from "./config";
22
import NetworkError from "./errors/NetworkError";
33
import { UnauthorizedError } from "./errors/UnauthorisedError";
4+
import "./index.css";
45
import reportWebVitals from "./reportWebVitals";
56
import AppRouter from "./services/AppRouter/";
67
import OAuth2Actions from "./services/OAuth2Actions";

apps/client/src/routes/Main/Settings/Settings.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const MenuEntry = ({
2121
}) => {
2222
const highlightColor = useToken("colors", "primary.400") + "aa";
2323
return (
24-
<Link to={to}>
24+
<Link to={to} unstable_viewTransition>
2525
<Flex
2626
bg={active ? highlightColor : undefined}
2727
p={3}
@@ -49,7 +49,7 @@ export default function Settings() {
4949
gap={3}
5050
h="full"
5151
>
52-
<Flex direction="column" minW={"20vw"}>
52+
<Flex direction="column" minW={"20vw"} className="settings-nav">
5353
<MenuEntry
5454
to="general"
5555
name="General"

pnpm-lock.yaml

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)