Update your ATProto bio with what you're currently listening to

Mock up atproto login form

Bryan 1afe50f3 d71b1ba4

Changed files
+101 -43
app
components
+72 -43
app/page.tsx
··· 1 1 "use client"; 2 2 3 + import Button from "@/components/Button"; 3 4 import { useState } from "react"; 5 + import { AtSign, Server, Lock } from "lucide-react"; 4 6 5 7 const Home = () => { 8 + const [atProtoIdentifier, setAtProtoIdentifier] = useState(""); 9 + const [currentPlaying, setCurrentPlaying] = useState(""); 10 + const [hostingProvider, setHostingProvider] = useState(""); 6 11 const [lastFMUsername, setLastFMUsername] = useState(""); 12 + const [password, setPassword] = useState(""); 7 13 const [usernameInput, setUsernameInput] = useState(""); 8 - const [currentPlaying, setCurrentPlaying] = useState(""); 14 + 15 + const scp = async () => { 16 + const response = await fetch(`/api/lastfm?username=${usernameInput}`); 17 + const data = await response.json(); 18 + 19 + setLastFMUsername(usernameInput); 20 + setUsernameInput(""); 21 + 22 + console.log(data) 23 + 24 + const mostRecentlyScrobbledTrack = data?.recenttracks?.track?.[0]; 25 + 26 + if (mostRecentlyScrobbledTrack?.["@attr"]) { 27 + setCurrentPlaying( 28 + `${mostRecentlyScrobbledTrack?.name} by ${mostRecentlyScrobbledTrack?.artist?.["#text"]}` 29 + ); 30 + } 31 + }; 9 32 10 33 return ( 11 34 <div className="bg-linear-to-r from-red-800 grid grid-cols-2 grid-rows-1 h-screen to-[#6868B6] w-screen"> 12 35 <div className="col-span-1 flex flex-col gap-2 items-center justify-center"> 13 36 <div className="flex gap-2 items-center justify-center w-full"> 14 - <input 15 - className="border h-12 outline-none p-2 rounded-lg w-1/2" 16 - onChange={(e) => setUsernameInput(e.target.value)} 17 - placeholder="Enter your Last.fm username" 18 - value={usernameInput} 37 + <div className="border flex gap-2 h-12 items-center p-2 rounded-lg w-1/2"> 38 + <AtSign /> 39 + <input 40 + className="flex-1 outline-none" 41 + onChange={(e) => setUsernameInput(e.target.value)} 42 + placeholder="Enter your Last.fm username" 43 + value={usernameInput} 44 + /> 45 + </div> 46 + <Button 47 + label="Enter" 48 + onClick={scp} 49 + width="w-1/4" 19 50 /> 20 - <button 21 - className="bg-white/90 active:bg-white hover:cursor-pointer h-12 rounded-lg text-xl w-1/4" 22 - onClick={async () => { 23 - const response = await fetch( 24 - `/api/lastfm?username=${usernameInput}` 25 - ); 26 - const data = await response.json(); 27 - 28 - console.log(data); 29 - setLastFMUsername(usernameInput); 30 - setUsernameInput(""); 31 - 32 - const mostRecentlyScrobbledTrack = 33 - data?.recenttracks?.track?.[0]; 34 - 35 - if (mostRecentlyScrobbledTrack?.["@attr"]) { 36 - setCurrentPlaying( 37 - `${mostRecentlyScrobbledTrack?.name} by ${mostRecentlyScrobbledTrack?.artist?.["#text"]}` 38 - ); 39 - } 40 - }} 41 - > 42 - <span 43 - style={{ 44 - background: 45 - "linear-gradient(to right, #9F0712, #6868B6)", 46 - backgroundClip: "text", 47 - WebkitBackgroundClip: "text", 48 - WebkitTextFillColor: "transparent" 49 - }} 50 - > 51 - Enter 52 - </span> 53 - </button> 54 51 </div> 55 52 {lastFMUsername && <p>{lastFMUsername}</p>} 56 53 {currentPlaying && <p>{currentPlaying}</p>} 57 54 </div> 58 - 59 - <div className="col-span-1 flex items-center justify-center"> 60 - @proto 55 + <div className="col-span-1 flex flex-col gap-2 items-center justify-center row-span-1"> 56 + <div className="border flex gap-2 h-12 items-center p-2 rounded-lg w-1/2"> 57 + <Server /> 58 + <input 59 + className="flex-1 outline-none" 60 + onChange={(e) => setHostingProvider(e.target.value)} 61 + placeholder="Enter your hosting provider" 62 + type="url" 63 + value={hostingProvider} 64 + /> 65 + </div> 66 + <div className="border flex gap-2 h-12 items-center p-2 rounded-lg w-1/2"> 67 + <AtSign /> 68 + <input 69 + className="flex-1 outline-none" 70 + onChange={(e) => setAtProtoIdentifier(e.target.value)} 71 + placeholder="Enter your ATProto username or email" 72 + value={atProtoIdentifier} 73 + /> 74 + </div> 75 + <div className="border flex gap-2 h-12 items-center p-2 rounded-lg w-1/2"> 76 + <Lock /> 77 + <input 78 + className="flex-1 outline-none" 79 + onChange={(e) => setPassword(e.target.value)} 80 + placeholder="Enter your password" 81 + type="password" 82 + value={password} 83 + /> 84 + </div> 85 + <Button 86 + label="Log In" 87 + onClick={async () => {}} 88 + width="w-1/2" 89 + /> 61 90 </div> 62 91 </div> 63 92 );
+29
components/Button.tsx
··· 1 + const Button = ({ 2 + label, 3 + onClick, 4 + width 5 + }: { 6 + label: string; 7 + onClick: () => Promise<void>; 8 + width: string; 9 + }) => { 10 + return ( 11 + <button 12 + className={`bg-white/90 active:bg-white hover:cursor-pointer h-12 rounded-lg text-xl ${width}`} 13 + onClick={onClick} 14 + > 15 + <span 16 + style={{ 17 + background: "linear-gradient(to right, #9F0712, #6868B6)", 18 + backgroundClip: "text", 19 + WebkitBackgroundClip: "text", 20 + WebkitTextFillColor: "transparent" 21 + }} 22 + > 23 + {label} 24 + </span> 25 + </button> 26 + ); 27 + }; 28 + 29 + export default Button;