3939 .card {background : var (--surface );border : 1px solid var (--line );border-radius : 16px ;padding : 1.2rem ;cursor : pointer;
4040 transition : transform .18s ease, box-shadow .18s ease, border-color .18s ;box-shadow : 0 1px 2px rgba (20 , 20 , 30 , .04 )}
4141 .card : hover {transform : translateY (-3px );box-shadow : 0 12px 30px rgba (80 , 70 , 160 , .13 );border-color : # dcd8f5 }
42- .av {width : 56px ;height : 56px ;border-radius : 50% ; object-fit : cover ;background : var (--accent-soft );display : grid;place-items : center;
42+ .av {position : relative; width : 56px ;height : 56px ;border-radius : 50% ;background : var (--accent-soft );display : grid;place-items : center;
4343 font-weight : 700 ;color : var (--accent );font-size : 1.3rem ;overflow : hidden}
44+ .av img , .fav img {position : absolute;inset : 0 ;width : 100% ;height : 100% ;object-fit : cover}
4445 .card .name {font-family : var (--serif );font-size : 1.25rem ;font-weight : 600 ;margin : .7rem 0 .1rem ;line-height : 1.2 }
4546 .card .nip05 {color : var (--accent );font-size : .82rem ;font-weight : 500 }
4647 .card .about {color : var (--muted );font-size : .9rem ;margin-top : .5rem ;display : -webkit-box;-webkit-line-clamp : 2 ;-webkit-box-orient : vertical;overflow : hidden}
6364 .panel {background : var (--surface );border : 1px solid var (--line );border-radius : 16px ;padding : 1.2rem 1.3rem ;box-shadow : 0 1px 2px rgba (20 , 20 , 30 , .04 )}
6465 .panel h3 {font-size : .74rem ;font-weight : 700 ;letter-spacing : .1em ;text-transform : uppercase;color : var (--faint );margin-bottom : .9rem }
6566 .follows {display : flex;flex-wrap : wrap;gap : .5rem }
66- .follows .fav {width : 34px ;height : 34px ;border-radius : 50% ;background : var (--accent-soft );object-fit : cover}
67+ .follows .fav {position : relative;width : 32px ;height : 32px ;border-radius : 50% ;background : var (--accent-soft );overflow : hidden;transition : transform .12s }
68+ .follows .fav : hover {transform : scale (1.2 );z-index : 1 }
6769 pre {font-family : var (--mono );font-size : .74rem ;line-height : 1.55 ;color : # 2a2a35 ;white-space : pre-wrap;word-break : break-word;max-height : 460px ;overflow : auto}
6870 .k {color : var (--accent )} .s {color : # 1c8c6b }
6971 footer {text-align : center;color : var (--faint );font-size : .8rem ;margin-top : 3rem }
@@ -91,10 +93,11 @@ <h1>A directory of <em style="font-style:italic">did:nostr</em> identities</h1>
9193const content = ( p ) => { try { return JSON . parse ( p . content || '{}' ) ; } catch { return { } ; } } ;
9294const initial = ( c , pk ) => ( c . name || c . display_name || pk || '?' ) . trim ( ) [ 0 ] ?. toUpperCase ( ) || '?' ;
9395
96+ function hueFrom ( s = '' ) { let h = 0 ; for ( const ch of String ( s ) ) h = ( h * 31 + ch . charCodeAt ( 0 ) ) % 360 ; return h ; }
97+ function gradStyle ( seed ) { const a = hueFrom ( seed ) , b = ( a + 38 ) % 360 ; return `background:linear-gradient(135deg,hsl(${ a } 68% 70%),hsl(${ b } 72% 55%));color:#fff` ; }
9498function avatar ( c , pk , cls = 'av' ) {
95- const pic = c . picture ;
96- if ( pic ) return `<img class="${ cls } " src="${ esc ( pic ) } " alt="" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'${ cls } ',textContent:'${ esc ( initial ( c , pk ) ) } '}))">` ;
97- return `<div class="${ cls } ">${ esc ( initial ( c , pk ) ) } </div>` ;
99+ const img = c . picture ? `<img src="${ esc ( c . picture ) } " alt="" onerror="this.style.display='none'">` : '' ;
100+ return `<div class="${ cls } " style="${ gradStyle ( pk ) } ">${ esc ( initial ( c , pk ) ) } ${ img } </div>` ;
98101}
99102
100103function highlight ( obj ) {
@@ -106,7 +109,7 @@ <h1>A directory of <em style="font-style:italic">did:nostr</em> identities</h1>
106109async function home ( ) {
107110 location . hash = '' ;
108111 view . innerHTML = '<div class="loading">loading recent identities…</div>' ;
109- const profiles = await fetch ( '/api/profiles' ) . then ( ( r ) => r . json ( ) ) . catch ( ( ) => [ ] ) ;
112+ const profiles = await fetch ( '/api/profiles?limit=36 ' ) . then ( ( r ) => r . json ( ) ) . catch ( ( ) => [ ] ) ;
110113 $ ( '#stat' ) . textContent = profiles . length ? `${ profiles . length } recently active identities` : '' ;
111114 if ( ! profiles . length ) { view . innerHTML = '<div class="loading">No profiles indexed yet. Start the indexer and refresh.</div>' ; return ; }
112115 view . innerHTML = `<div class="grid">${ profiles . map ( ( p ) => {
@@ -149,7 +152,7 @@ <h2>${esc(c.name || short(pk))}</h2>
149152 <div class="sections">
150153 <div class="panel"><h3>DID document</h3><pre>${ highlight ( doc ) } </pre></div>
151154 <div class="panel"><h3>Following · ${ follows . length } </h3>
152- ${ follows . length ? `<div class="follows">${ follows . slice ( 0 , 60 ) . map ( ( d ) => `<a class="fav" title="${ esc ( d ) } " href="#${ d . replace ( 'did:nostr:' , '' ) } "></a>` ) . join ( '' ) } </div>`
155+ ${ follows . length ? `<div class="follows">${ follows . slice ( 0 , 96 ) . map ( ( d ) => { const fk = d . replace ( 'did:nostr:' , '' ) ; return `<a class="fav" style=" ${ gradStyle ( fk ) } " title="${ esc ( fk ) } " href="#${ fk } "></a>` ; } ) . join ( '' ) } </div>`
153156 : '<div style="color:var(--faint);font-size:.9rem">No follow list indexed.</div>' }
154157 </div>
155158 </div>
0 commit comments