A web app for writing and sharing 301+ character Bluesky posts.
at main 89 lines 4.1 kB view raw
1import { useState } from 'react' 2import './App.css' 3import Login from './components/Login' 4import { UnifiedAuthProvider } from './providers/UnifiedAuthProvider' 5import { AtpAgent } from '@atproto/api' 6// import { TID } from '@atproto/common' 7 8function App() { 9 const agent = new AtpAgent({ service: 'https://skeetlonger.app' }) 10 11 const [postText, setPostText] = useState('') 12 const charCount = postText.length 13 14 const handleSubmit = async () => { 15 // Generate a time-based key for our record 16 const rkey = "self" 17 18 await agent.com.atproto.repo.putRecord({ 19 repo: agent.assertDid, // The user 20 collection: 'app.skeetlonger.post', // The collection 21 rkey, // The record key 22 record: { // The record value 23 post: postText, 24 createdAt: new Date().toISOString() 25 } 26 }) 27 28 // setError(null); 29 // try { 30 // localStorage.setItem("lastHandle", user); 31 // await loginWithPassword(user, password, `https://${serviceURL}`); 32 // } catch (err) { 33 // setError("Login failed. Check your handle and App Password."); 34 // } 35 }; 36 37 return ( 38 <UnifiedAuthProvider> 39 <div style={{ position: 'fixed', top: '1rem', right: '1rem', zIndex: 9999 }}> 40 <Login compact={true} /> 41 </div> 42 43 <div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '5rem 1rem', backgroundColor: '#242424' }}> 44 <div style={{ width: '100%', maxWidth: '72rem' }}> 45 {/* Title */} 46 <h1 style={{ fontSize: '2.25rem', fontWeight: 'bold', textAlign: 'center', marginBottom: '0.5rem', color: '#f3f4f6' }}> 47 SkeetLonger 48 </h1> 49 <p style={{ textAlign: 'center', marginBottom: '2rem', color: '#9ca3af' }}> 50 Post longer content to Bluesky 51 </p> 52 53 {/* Text Editor Card */} 54 <div style={{ padding: '1.5rem', borderRadius: '0.75rem', boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)', border: '1px solid #e5e7eb', backgroundColor: '#1a1a1a', borderColor: '#374151' }}> 55 <textarea 56 value={postText} 57 onChange={(e) => setPostText(e.target.value)} 58 placeholder="What's on your mind? Write as much as you'd like..." 59 style={{ width: '32rem', height: '32rem', padding: '0.75rem 1rem', borderRadius: '0.5rem', border: '1px solid #4b5563', fontSize: '1rem', lineHeight: '1.75', resize: 'none', backgroundColor: '#111827', color: '#f3f4f6', boxSizing: 'border-box' }} 60 className="placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500" 61 /> 62 63 {/* Footer with character count and post button */} 64 <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: '1rem' }}> 65 <div style={{ fontSize: '0.875rem' }}> 66 <span style={{ fontWeight: '500', color: charCount > 300 ? '#3b82f6' : '#9ca3af' }}> 67 {charCount} characters 68 </span> 69 </div> 70 71 <button 72 onClick={() => handleSubmit()} 73 type='submit' 74 disabled={charCount < 300} 75 style={{ padding: '0.625rem 1.5rem', borderRadius: '0.5rem', fontSize: '0.875rem', fontWeight: '600', border: 'none', cursor: charCount === 0 ? 'not-allowed' : 'pointer', transition: 'background-color 0.2s', backgroundColor: charCount === 0 ? '#6b7280' : '#2563eb', color: 'white' }} 76 onMouseEnter={(e) => { if (charCount !== 0) e.currentTarget.style.backgroundColor = '#1d4ed8'; }} 77 onMouseLeave={(e) => { if (charCount !== 0) e.currentTarget.style.backgroundColor = '#2563eb'; }} 78 > 79 Post 80 </button> 81 </div> 82 </div> 83 </div> 84 </div> 85 </UnifiedAuthProvider> 86 ) 87} 88 89export default App