demos for spacedust

basic bad notif style

+87 -4
+6 -1
atproto-notifications/src/components/Feed.css
··· 9 9 } 10 10 11 11 .feed-filter-type h4, 12 - .feed-filter-secondary { 12 + .feed-filter-secondary h4 { 13 13 margin: 0; 14 14 } 15 15 ··· 21 21 top: 0.1rem; 22 22 margin-right: 0.25rem; 23 23 } 24 + 25 + .feed-notifications { 26 + text-align: left; 27 + margin: 2rem auto; 28 + }
+6 -3
atproto-notifications/src/components/Feed.tsx
··· 1 1 import { useEffect, useState } from 'react'; 2 2 import { getNotifications, getSecondary } from '../db'; 3 3 import { ButtonGroup } from './Buttons'; 4 + import { Notification } from './Notification'; 4 5 import psl from 'psl'; 5 6 import lexicons from 'lexicons'; 6 7 ··· 138 139 /> 139 140 </div> 140 141 )} 141 - {feed.map(([k, n]) => ( 142 - <p key={k}>{k}: {n.source} ({n.source_record}) <code>{JSON.stringify(n)}</code></p> 143 - ))} 142 + <div className="feed-notifications"> 143 + {feed.map(([k, n]) => ( 144 + <Notification key={k} {...n} /> 145 + ))} 146 + </div> 144 147 </div> 145 148 ); 146 149 }
+25
atproto-notifications/src/components/Notification.css
··· 1 + 2 + 3 + .notification { 4 + padding: 0.75rem; 5 + border: 0.5px solid hsla(0, 0%, 50%, 0.3); 6 + border-width: 0.5px 0; 7 + } 8 + a.notification { 9 + display: block; 10 + font: inherit; 11 + color: inherit; 12 + } 13 + a.notification:hover { 14 + /*box-shadow: 0 42px 42px -42px inset #2c343c;*/ 15 + /*, 0 -42px 42px -42px inset #221828;*/ 16 + /*box-shadow: 0 42px 42px -42px inset #2c343c;*/ 17 + /*background: #221828;*/ 18 + background: #0b0d0f; 19 + border-top-color: hsla(0, 0%, 100%, 0.3); 20 + border-bottom-color: hsla(0, 0%, 0%, 0.3); 21 + } 22 + 23 + .handle { 24 + color: skyblue; 25 + }
+50
atproto-notifications/src/components/Notification.tsx
··· 1 + import psl from 'psl'; 2 + import lexicons from 'lexicons'; 3 + import { resolveDid } from '../atproto/resolve'; 4 + import { Fetch } from './Fetch'; 5 + 6 + import './Notification.css'; 7 + 8 + export function Notification({ app, group, source, source_record, source_did, subject }) { 9 + 10 + // TODO: clean up / move this to lexicons package? 11 + let title = source; 12 + let icon; 13 + let appName; 14 + let appPrefix; 15 + try { 16 + appPrefix = app.split('.').toReversed().join('.'); 17 + } catch (e) { 18 + console.error('getting top app failed', e); 19 + } 20 + const lex = lexicons[appPrefix]; 21 + icon = lex?.clients[0]?.icon; 22 + const link = lex?.clients[0]?.notifications; 23 + appName = lex?.name; 24 + title = lex?.known_sources[source.slice(app.length + 1)] ?? source; 25 + 26 + const contents = ( 27 + <> 28 + {icon && ( 29 + <img className="app-icon" src={icon} title={appName ?? app} alt="" /> 30 + )} 31 + {title} from 32 + {' '} 33 + {source_did ? ( 34 + <Fetch 35 + using={resolveDid} 36 + args={[source_did]} 37 + ok={handle => <span className="handle">@{handle}</span>} 38 + /> 39 + ) : ( 40 + source_record 41 + )} 42 + </> 43 + ); 44 + 45 + return link 46 + ? <a className="notification" href={link} target="_blank"> 47 + {contents} 48 + </a> 49 + : <div className="notification">{contents}</div>; 50 + }