basic ui framing sketch

Changed files
+166 -36
atproto-notifications
+85 -5
atproto-notifications/src/App.css
··· 1 1 #root { 2 - max-width: 1280px; 3 2 margin: 0 auto; 4 - padding: 2rem; 3 + max-width: 1280px; 4 + padding: 0; 5 5 text-align: center; 6 + min-height: 100vh; 7 + display: flex; 8 + flex-direction: column; 9 + justify-content: space-between; 10 + } 11 + 12 + #app-header { 13 + background-color: #0b0d0f; 14 + padding: 0.25rem; 15 + border-bottom: 1px solid hsla(0, 0%, 50%, 0.3); 16 + display: flex; 17 + justify-content: space-around; 18 + align-items: baseline; 19 + } 20 + 21 + #app-header .handle { 22 + display: inline-block; 23 + margin-right: 0.5rem; 24 + color: #999; 6 25 } 7 26 8 - .card { 9 - padding: 2em; 27 + .demo { 28 + background: #2c343c; 29 + border-radius: 0.25rem; 30 + color: #f90; 31 + display: inline-block; 32 + font-size: 0.8rem; 33 + font-weight: normal; 34 + margin: 0 0 0 0.25rem; 35 + padding: 0.1rem 0.333rem 0.15rem; 36 + transform: rotate(-13deg); 37 + vertical-align: top; 38 + } 39 + 40 + #app-content { 41 + padding: 0.5rem 1rem; 10 42 } 11 43 12 - .read-the-docs { 44 + .detail { 45 + font-style: italic; 46 + font-size: 0.8rem; 47 + max-width: 24em; 48 + margin: 0 auto; 49 + } 50 + 51 + .footer { 52 + box-sizing: border-box; 53 + background: #0b0d0f; 54 + width: 100%; 55 + text-align: center; 56 + margin: 3rem 0 0; 57 + padding: 0.667rem 0.5rem 0; 58 + font-size: 0.85rem; 59 + 60 + font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace; 61 + font-weight: normal; 62 + line-height: 1.5rem; 63 + 64 + border-top: 1px solid hsla(0, 0%, 50%, 0.3); 65 + box-shadow: 0 108px 81px -81px inset #221828; 66 + 67 + color-scheme: dark; 68 + color: #e6ece6; 69 + } 70 + .footer p { 71 + margin: 0; 72 + } 73 + .footer p.from { 13 74 color: #888; 14 75 } 76 + .footer p.actions { 77 + display: flex; 78 + gap: 1rem; 79 + justify-content: center; 80 + margin: 0.5rem 0; 81 + } 82 + .footer p.secret-dev { 83 + font-size: 0.667rem; 84 + } 85 + .footer p.secret-dev:not(:hover) { 86 + opacity: 0.5; 87 + } 88 + 89 + @media screen and (max-width: 600px) { 90 + .footer { 91 + border-radius: 0; 92 + position: relative; 93 + } 94 + }
+63 -27
atproto-notifications/src/App.tsx
··· 100 100 } else if (notifPerm !== 'granted') { 101 101 content = ( 102 102 <> 103 - <h3>Step 2: Notification permission</h3> 104 - <p>To show atproto notifications we need permission:</p> 103 + <h3>Step 2: Allow notifications</h3> 104 + <p>To show notifications we need permission:</p> 105 105 <p> 106 106 <button 107 107 onClick={requestPermission(host, setAsking)} ··· 111 111 </button> 112 112 </p> 113 113 {notifPerm === 'denied' ? ( 114 - <p><em>Notification permission was denied. You may need to clear the browser setting to try again.</em></p> 114 + <p className="detail">Notification permission was denied. You may need to clear the browser setting to try again.</p> 115 115 ) : ( 116 - <p><em>You can revoke this any time</em></p> 116 + <p className="detail">You can revoke this any time</p> 117 117 )} 118 118 </> 119 119 ); 120 120 } else { 121 - content = ( 122 - <> 123 - <p> 124 - @{user.handle} 125 - <button onClick={() => setUser(null)}>&times;</button> 126 - </p> 127 - <Feed /> 128 - </> 129 - ); 121 + content = <Feed />; 130 122 } 131 123 132 124 return ( 133 125 <HostContext.Provider value={host}> 134 - <h1>🎇 atproto notifications demo</h1> 126 + <header id="app-header"> 127 + <h1>spacedust notifications <span className="demo">demo!</span></h1> 128 + {user && ( 129 + <div className="current-user"> 130 + <p> 131 + <span className="handle">@{user.handle}</span> 132 + {/* TODO: clear *all* info on logout */} 133 + <button className="subtle bad" onClick={() => setUser(null)}>&times;</button> 134 + </p> 135 + </div> 136 + )} 137 + </header> 135 138 136 - <p>Get browser push notifications from any app</p> 139 + <div id="app-content"> 140 + {content} 141 + </div> 137 142 138 - {content} 143 + <div className="footer"> 144 + <p className="from"> 145 + This demo is part of 146 + {' '} 147 + <a href="https://microcosm.blue" className="external" target="_blank"> 148 + <span style={{ color: '#f396a9' }}>m</span> 149 + <span style={{ color: '#f49c5c' }}>i</span> 150 + <span style={{ color: '#c7b04c' }}>c</span> 151 + <span style={{ color: '#92be4c' }}>r</span> 152 + <span style={{ color: '#4ec688' }}>o</span> 153 + <span style={{ color: '#51c2b6' }}>c</span> 154 + <span style={{ color: '#54bed7' }}>o</span> 155 + <span style={{ color: '#8fb1f1' }}>s</span> 156 + <span style={{ color: '#ce9df1' }}>m</span> 157 + 158 + </a> 159 + </p> 160 + <p className="actions"> 161 + <a href="https://bsky.app/profile/microcosm.blue" target="_blank" className="external"> 162 + 🦋 follow 163 + </a> 164 + <a href="https://github.com/sponsors/uniphil/" target="_blank" className="external"> 165 + 💸 support 166 + </a> 167 + <a href="https://github.com/at-microcosm/spacedust-utils" target="_blank" className="external"> 168 + 👩🏻‍💻 source 169 + </a> 170 + </p> 171 + 172 + <p className="secret-dev"> 173 + secret dev setting: 174 + {' '} 175 + <label> 176 + <input 177 + type="checkbox" 178 + onChange={e => setDev(e.target.checked)} 179 + checked={true /*isDev(ufosHost)*/} 180 + /> 181 + localhost 182 + </label> 183 + </p> 184 + </div> 139 185 </HostContext.Provider> 140 186 ) 141 187 } 142 188 143 - export default App 144 - 145 - 146 - // {user === null ? ( 147 - 148 - // ) : ( 149 - // <> 150 - // <p>hi {user.handle}</p> 151 - // <button onClick={() => setUser(null)}>clear</button> 152 - // </> 153 - // )} 189 + export default App;
+18 -4
atproto-notifications/src/index.css
··· 3 3 line-height: 1.5; 4 4 font-weight: 400; 5 5 6 - color-scheme: light dark; 6 + color-scheme: dark; 7 7 color: #d6dade; 8 8 background-color: #161a1e; 9 9 ··· 34 34 } 35 35 36 36 button { 37 - border-radius: 8px; 37 + border-radius: 0.5rem; 38 38 border: 1px solid transparent; 39 39 padding: 0.6em 1.2em; 40 40 font-size: 1em; 41 41 font-weight: 500; 42 42 font-family: inherit; 43 - background-color: #1a1a1a; 43 + background-color: #0b0d0f; 44 44 cursor: pointer; 45 - transition: border-color 0.25s; 45 + border: 1px solid hsla(0, 0%, 50%, 0.3); 46 + border-bottom-color: hsla(0, 0%, 0%, 0.3); 47 + border-right-color: hsla(0, 0%, 0%, 0.3); 48 + box-shadow: 0 42px 42px -42px inset #221828; 46 49 } 47 50 button:hover { 48 51 border-color: #646cff; ··· 50 53 button:focus, 51 54 button:focus-visible { 52 55 outline: 4px auto -webkit-focus-ring-color; 56 + } 57 + 58 + button.subtle { 59 + background: transparent; 60 + border: none; 61 + margin: 0; 62 + padding: 0; 63 + font: inherit; 64 + } 65 + button.bad { 66 + color: tomato; 53 67 } 54 68 55 69 @media (prefers-color-scheme: light) {