Listen to and share the music in the Atmosphere. musicsky.up.railway.app/
nextjs atproto music typescript react
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: move the repeating layout to root layout

+69 -71
+33 -35
src/app/auth/login/page.tsx
··· 17 17 const [loading, setLoading] = useState(false); 18 18 const [error, setError] = useState<string | null>(null); 19 19 20 - async function handleSubmit(e: React.FormEvent) { 21 - e.preventDefault(); 20 + async function handleSubmit(event: React.FormEvent) { 21 + event.preventDefault(); 22 22 setLoading(true); 23 23 setError(null); 24 24 ··· 44 44 } 45 45 46 46 return ( 47 - <div className="flex min-h-screen items-center justify-center bg-background"> 48 - <Card className="w-full max-w-sm mx-auto"> 49 - <CardHeader> 50 - <CardTitle>Sign in</CardTitle> 51 - <CardDescription> 52 - Enter your handle to sign in to your account. 53 - </CardDescription> 54 - </CardHeader> 55 - <CardContent> 56 - <form onSubmit={handleSubmit} className="space-y-4"> 57 - <Field data-invalid={!!error}> 58 - <FieldLabel htmlFor="handle">Handle</FieldLabel> 59 - <Input 60 - id="handle" 61 - type="text" 62 - value={handle} 63 - onChange={(e) => setHandle(e.target.value)} 64 - placeholder="user.example.com" 65 - disabled={loading} 66 - /> 67 - <FieldError>{error}</FieldError> 68 - </Field> 47 + <Card className="w-full max-w-sm mx-auto"> 48 + <CardHeader> 49 + <CardTitle>Sign in</CardTitle> 50 + <CardDescription> 51 + Enter your handle to sign in to your account. 52 + </CardDescription> 53 + </CardHeader> 54 + <CardContent> 55 + <form onSubmit={handleSubmit} className="space-y-4"> 56 + <Field data-invalid={!!error}> 57 + <FieldLabel htmlFor="handle">Handle</FieldLabel> 58 + <Input 59 + id="handle" 60 + type="text" 61 + value={handle} 62 + onChange={(event) => setHandle(event.target.value)} 63 + placeholder="user.example.com" 64 + disabled={loading} 65 + /> 66 + <FieldError>{error}</FieldError> 67 + </Field> 69 68 70 - <Button 71 - type="submit" 72 - className="w-full" 73 - disabled={loading || !handle} 74 - > 75 - {loading ? "Signing in..." : "Sign in"} 76 - </Button> 77 - </form> 78 - </CardContent> 79 - </Card> 80 - </div> 69 + <Button 70 + type="submit" 71 + className="w-full" 72 + disabled={loading || !handle} 73 + > 74 + {loading ? "Signing in..." : "Sign in"} 75 + </Button> 76 + </form> 77 + </CardContent> 78 + </Card> 81 79 ); 82 80 }
+3 -1
src/app/layout.tsx
··· 27 27 <body 28 28 className={`${geistSans.variable} ${geistMono.variable} antialiased`} 29 29 > 30 - {children} 30 + <div className="flex min-h-screen items-center justify-center bg-background"> 31 + {children} 32 + </div> 31 33 </body> 32 34 </html> 33 35 );
+33 -35
src/app/page.tsx
··· 19 19 const { data: profile } = await agent.getProfile({ actor: session.did }); 20 20 21 21 return ( 22 - <div className="flex min-h-screen items-center justify-center bg-background"> 23 - <main className="flex flex-col gap-4 w-full max-w-md mx-auto p-8"> 24 - <div className="text-center mb-8"> 25 - <h1 className="text-3xl font-bold text-indigo-600 mb-2">MusicSky</h1> 26 - </div> 22 + <main className="flex flex-col gap-4 w-full max-w-md mx-auto p-8"> 23 + <div className="text-center mb-8"> 24 + <h1 className="text-3xl font-bold text-indigo-600 mb-2">MusicSky</h1> 25 + </div> 27 26 28 - <div className="bg-card rounded-lg border border-input p-6"> 29 - <div className="space-y-4"> 30 - <div className="flex items-center justify-between"> 31 - <div className="flex flex-row gap-4 items-center"> 32 - <Activity mode={profile.avatar ? "visible" : "hidden"}> 33 - <Image 34 - src={profile.avatar!} 35 - alt={profile.handle} 36 - className="size-12 rounded-full" 37 - width={100} 38 - height={100} 39 - /> 27 + <div className="bg-card rounded-lg border border-input p-6"> 28 + <div className="space-y-4"> 29 + <div className="flex items-center justify-between"> 30 + <div className="flex flex-row gap-4 items-center"> 31 + <Activity mode={profile.avatar ? "visible" : "hidden"}> 32 + <Image 33 + src={profile.avatar!} 34 + alt={profile.handle} 35 + className="size-12 rounded-full" 36 + width={100} 37 + height={100} 38 + /> 39 + </Activity> 40 + <div className="flex flex-col"> 41 + <Activity mode={profile.displayName ? "visible" : "hidden"}> 42 + <p className="font-semibold">{profile.displayName}</p> 40 43 </Activity> 41 - <div className="flex flex-col"> 42 - <Activity mode={profile.displayName ? "visible" : "hidden"}> 43 - <p className="font-semibold">{profile.displayName}</p> 44 - </Activity> 45 - <p 46 - className={cn( 47 - profile.displayName && "text-sm text-muted-foreground", 48 - )} 49 - > 50 - @{profile.handle} 51 - </p> 52 - </div> 44 + <p 45 + className={cn( 46 + profile.displayName && "text-sm text-muted-foreground", 47 + )} 48 + > 49 + @{profile.handle} 50 + </p> 53 51 </div> 54 - <LogoutButton /> 55 52 </div> 53 + <LogoutButton /> 56 54 </div> 57 55 </div> 58 - <Button asChild> 59 - <Link href="/upload">Upload a track</Link> 60 - </Button> 61 - </main> 62 - </div> 56 + </div> 57 + <Button asChild> 58 + <Link href="/upload">Upload a song</Link> 59 + </Button> 60 + </main> 63 61 ); 64 62 }