Skip to content

Commit 93d07e0

Browse files
authored
Merge pull request #53 from justinfernald/justinfernald/issue51
Add mobile support for login page
2 parents 8e552ac + f579379 commit 93d07e0

File tree

6 files changed

+152
-47
lines changed

6 files changed

+152
-47
lines changed

packages/app/src/components/appshell.tsx

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { AppShell, LoadingOverlay } from "@mantine/core";
2-
import { useDisclosure } from "@mantine/hooks";
1+
import { AppShell, Drawer, LoadingOverlay, Text } from "@mantine/core";
2+
import { useDisclosure, useMediaQuery } from "@mantine/hooks";
33
import type { UserProfile } from "../api/auth";
44
import { useExtendedQuery } from "../hooks/useExtendedQuery";
55
import { useUrlStateSync } from "../hooks/useUrlState";
66
import { useParametersContext } from "../stores/parameters";
7+
import { MQ } from "../theme/media";
78
import { Skyline } from "../three/skyline";
89
import { HoverCard } from "./hover_card";
910
import { Sidebar } from "./sidebar";
@@ -20,6 +21,10 @@ export function EditorAppShell({ profile }: EditorAppShellProps) {
2021

2122
const [mobileOpened] = useDisclosure();
2223
const [desktopOpened] = useDisclosure(true);
24+
const [drawerOpened, { open: openDrawer, close: closeDrawer }] =
25+
useDisclosure(false);
26+
27+
const isMobile = useMediaQuery(MQ.sm);
2328

2429
const { years, fetching, ok } = useExtendedQuery({
2530
name,
@@ -43,7 +48,7 @@ export function EditorAppShell({ profile }: EditorAppShellProps) {
4348
<AppShell.Navbar p="md" pr={0}>
4449
<Sidebar profile={profile} ok={ok} />
4550
</AppShell.Navbar>
46-
<AppShell.Main style={{ height: "calc(100vh)" }}>
51+
<AppShell.Main style={{ height: "100vh" }}>
4752
<LoadingOverlay
4853
visible={fetching}
4954
zIndex={1000}
@@ -62,7 +67,27 @@ export function EditorAppShell({ profile }: EditorAppShellProps) {
6267
>
6368
<HoverCard />
6469
</div>
65-
<SkylineControls />
70+
<SkylineControls onOpenDrawer={openDrawer} />
71+
{isMobile && (
72+
<Drawer
73+
opened={drawerOpened}
74+
onClose={closeDrawer}
75+
position="bottom"
76+
size="xl"
77+
title={
78+
<Text
79+
flex={1}
80+
className="mona-sans-wide"
81+
tt="uppercase"
82+
size="md"
83+
>
84+
{import.meta.env.PUBLIC_APP_NAME}
85+
</Text>
86+
}
87+
>
88+
<Sidebar fromDrawer profile={profile} ok={ok} />
89+
</Drawer>
90+
)}
6691
</AppShell.Main>
6792
</AppShell>
6893
);

packages/app/src/components/sidebar.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,23 @@ import { TowerDampeningInput } from "./sidebar_inputs/tower_dampening";
3434
import { UsernameOverrideInput } from "./sidebar_inputs/username_override";
3535

3636
interface SidebarProps {
37+
fromDrawer?: boolean;
3738
profile: UserProfile | null;
3839
ok: boolean;
3940
}
4041

4142
export function Sidebar(props: SidebarProps) {
42-
const { profile, ok } = props;
43+
const { fromDrawer, profile, ok } = props;
4344

4445
return (
4546
<Stack h={"100%"} gap={10}>
46-
<AppShell.Section px={6} py={4}>
47-
<Title className="mona-sans-wide" tt="uppercase" order={5}>
48-
{import.meta.env.PUBLIC_APP_NAME}
49-
</Title>
50-
</AppShell.Section>
47+
{!fromDrawer && (
48+
<AppShell.Section px={6} py={4}>
49+
<Title className="mona-sans-wide" tt="uppercase" order={5}>
50+
{import.meta.env.PUBLIC_APP_NAME}
51+
</Title>
52+
</AppShell.Section>
53+
)}
5154
<Card h="100%" p="md">
5255
<AppShell.Section
5356
style={{

packages/app/src/components/skyline_controls.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
import { ActionIcon, Card, Group, Portal, Tooltip } from "@mantine/core";
2-
import { IconCamera, IconHome, IconRotate360 } from "@tabler/icons-react";
2+
import { useMediaQuery } from "@mantine/hooks";
3+
import {
4+
IconCamera,
5+
IconHome,
6+
IconPencil,
7+
IconRotate360,
8+
} from "@tabler/icons-react";
39
import { type ProjectionMode, useControlsStore } from "../stores/controls";
410
import classes from "../styles/dock.module.css";
11+
import { MQ } from "../theme/media";
512
import { capitalize } from "../utils";
613

7-
export function SkylineControls() {
14+
export function SkylineControls({
15+
onOpenDrawer,
16+
}: {
17+
onOpenDrawer?: () => void;
18+
}) {
819
const resetView = useControlsStore((state) => state.resetView);
920
const toggleAutoRotation = useControlsStore(
1021
(state) => state.toggleAutoRotate,
@@ -17,10 +28,23 @@ export function SkylineControls() {
1728
state.projectionMode === "orthographic" ? "perspective" : "orthographic",
1829
);
1930

31+
const isMobile = useMediaQuery(MQ.sm);
32+
2033
return (
2134
<Portal target="#skyline-canvas">
2235
<Card className={classes.dock} p={5} withBorder>
2336
<Group gap={5}>
37+
{isMobile && onOpenDrawer && (
38+
<Tooltip label="Edit Settings">
39+
<ActionIcon
40+
variant="subtle"
41+
aria-label="Open Settings"
42+
onClick={() => onOpenDrawer?.()}
43+
>
44+
<IconPencil stroke={1} />
45+
</ActionIcon>
46+
</Tooltip>
47+
)}
2448
<Tooltip label="Reset View">
2549
<ActionIcon
2650
variant="subtle"

packages/app/src/routes/login.tsx

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
LoadingOverlay,
88
Stack,
99
} from "@mantine/core";
10+
import { useMediaQuery } from "@mantine/hooks";
1011
import { IconBrandGithubFilled } from "@tabler/icons-react";
1112
import { createFileRoute, redirect, useRouter } from "@tanstack/react-router";
1213
import {
@@ -19,6 +20,7 @@ import {
1920
import { useEffect, useRef } from "react";
2021
import { isAuthenticated, resolveToken } from "../api/auth";
2122
import ContributionBackground from "../components/contribution_background";
23+
import { MQ } from "../theme/media";
2224
import "../styles/login.css";
2325
import "../styles/page.css";
2426

@@ -53,6 +55,9 @@ function Login() {
5355
const { code, redirect: redirectUrl } = Route.useSearch();
5456
const loading = useRef<boolean | null>(null);
5557

58+
// Prefer CSS for layout; JS flag helps toggle simplified title on small screens
59+
const isMobile = useMediaQuery(MQ.login);
60+
5661
// Persist redirect across OAuth flow
5762
useEffect(() => {
5863
if (redirectUrl) {
@@ -97,32 +102,35 @@ function Login() {
97102
delay: 1000,
98103
});
99104

100-
createTimeline()
101-
.sync(slideinfade)
102-
.add(".slide-up", {
103-
ease: "cubicBezier(.28,1,0,1)",
104-
y: stagger("-1.5rem"),
105-
delay: stagger(10),
106-
marginTop: "4.5rem",
107-
});
105+
if (isMobile) {
106+
// Mobile: only fade in the caption/buttons
107+
createTimeline()
108+
.sync(slideinfade)
109+
.add(".caption-item", { opacity: 1, delay: stagger(100) });
110+
} else {
111+
// Desktop: run stacked text animations
112+
createTimeline()
113+
.sync(slideinfade)
114+
.add(".slide-up", {
115+
ease: "cubicBezier(.28,1,0,1)",
116+
y: stagger("-1.5rem"),
117+
delay: stagger(10),
118+
marginTop: "4.5rem",
119+
});
108120

109-
createTimeline()
110-
.sync(slideinfade)
111-
.add(".slide-down", {
112-
ease: "cubicBezier(.28,1,0,1)",
113-
y: stagger("1.5rem"),
114-
delay: stagger(10, {
115-
reversed: true,
116-
}),
117-
marginBottom: "4.5rem",
118-
})
119-
.add(".caption-item", {
120-
opacity: 1,
121-
delay: stagger(100),
122-
});
121+
createTimeline()
122+
.sync(slideinfade)
123+
.add(".slide-down", {
124+
ease: "cubicBezier(.28,1,0,1)",
125+
y: stagger("1.5rem"),
126+
delay: stagger(10, { reversed: true }),
127+
marginBottom: "4.5rem",
128+
})
129+
.add(".caption-item", { opacity: 1, delay: stagger(100) });
130+
}
123131
});
124132
return () => scope.current?.revert();
125-
}, []);
133+
}, [isMobile]);
126134

127135
const _3D = (
128136
<span
@@ -147,20 +155,32 @@ function Login() {
147155
<Flex gap={20}>
148156
<Center>
149157
<Stack gap={30}>
150-
<div className="logo">
151-
<div className="stack mona-sans-wide title github-text">
152-
<span className="slide-up neon-blue">GITHUB</span>
153-
<span className="slide-up neon-blue">GITHUB</span>
154-
<span className="slide-up neon-blue">GITHUB</span>
155-
<span className="slide-up pink-text">GITHUB</span>
158+
{/* On mobile, render a simplified title; on larger screens use the animated stacked logo. */}
159+
{isMobile ? (
160+
<div className="logo">
161+
<div
162+
className="mona-sans-wide title"
163+
style={{ textAlign: "center" }}
164+
>
165+
GITHUB SKYLINE
166+
</div>
156167
</div>
157-
<div className="stack mona-sans-wide title skyline-text">
158-
<span className="slide-down neon-pink">SKYLINE</span>
159-
<span className="slide-down neon-pink">SKYLINE</span>
160-
<span className="slide-down neon-pink">SKYLINE</span>
161-
<span className="slide-down pink-text">SKYLINE</span>
168+
) : (
169+
<div className="logo">
170+
<div className="stack mona-sans-wide title">
171+
<span className="slide-up neon-blue">GITHUB</span>
172+
<span className="slide-up neon-blue">GITHUB</span>
173+
<span className="slide-up neon-blue">GITHUB</span>
174+
<span className="slide-up pink-text">GITHUB</span>
175+
</div>
176+
<div className="stack mona-sans-wide title">
177+
<span className="slide-down neon-pink">SKYLINE</span>
178+
<span className="slide-down neon-pink">SKYLINE</span>
179+
<span className="slide-down neon-pink">SKYLINE</span>
180+
<span className="slide-down pink-text">SKYLINE</span>
181+
</div>
162182
</div>
163-
</div>
183+
)}
164184
<Stack className="caption">
165185
<div className="caption-item mona-sans-wide">
166186
YOUR CONTRIBUTION STORY IN {_3D}

packages/app/src/styles/login.css

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,27 @@ body {
6666
will-change: opacity;
6767
opacity: 0;
6868
}
69+
70+
/* Mobile layout */
71+
@media (max-width: 640px) {
72+
.title {
73+
padding-inline: var(--mantine-spacing-xs);
74+
font-size: 2.25rem;
75+
line-height: 0.8;
76+
}
77+
78+
.logo {
79+
flex-direction: column;
80+
gap: 0.75rem;
81+
align-items: center;
82+
}
83+
84+
.stack {
85+
text-align: center;
86+
}
87+
88+
.caption {
89+
width: 100%;
90+
padding-inline: 1rem;
91+
}
92+
}

packages/app/src/theme/media.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/** This follows Mantine's default breakpoint */
2+
export const MQ_SM = "(max-width: 48em)";
3+
4+
export const MQ_LOGIN = "(max-width: 640px)";
5+
6+
export const MQ = {
7+
sm: MQ_SM,
8+
login: MQ_LOGIN,
9+
};

0 commit comments

Comments
 (0)