@closerclick/closer-click-profile 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +29 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@closerclick/closer-click-profile",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Web Component (custom element) <closer-click-profile> reutilizable por cualquier app del ecosistema Closer Click: tarjeta de perfil + reputación (confianza/afinidad, web-of-trust, reputación de la red). Autohosteado, Shadow DOM, temable por CSS vars.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
package/src/index.js
CHANGED
|
@@ -245,6 +245,8 @@ const STYLE = `
|
|
|
245
245
|
width: fit-content;
|
|
246
246
|
}
|
|
247
247
|
.since { font-size: 12px; color: var(--_muted); }
|
|
248
|
+
.ind-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
|
|
249
|
+
.ind-badge { font-size: 12px; font-weight: 700; color: var(--_accent); border: 1px solid var(--_accent); border-radius: 8px; padding: 2px 8px; white-space: nowrap; }
|
|
248
250
|
|
|
249
251
|
/* ----- Sections ----- */
|
|
250
252
|
.section { display: flex; flex-direction: column; gap: 6px; position: relative; }
|
|
@@ -321,7 +323,7 @@ const STYLE = `
|
|
|
321
323
|
|
|
322
324
|
class CloserClickProfile extends HTMLElement {
|
|
323
325
|
static get observedAttributes() {
|
|
324
|
-
return ['pubkey', 'name', 'since', 'online', 'mode', 'modal', 'heading', 'lang']
|
|
326
|
+
return ['pubkey', 'name', 'since', 'online', 'mode', 'modal', 'heading', 'lang', 'indicators']
|
|
325
327
|
}
|
|
326
328
|
|
|
327
329
|
constructor() {
|
|
@@ -331,6 +333,7 @@ class CloserClickProfile extends HTMLElement {
|
|
|
331
333
|
this._my = { confianza: 0, afinidad: 0, notes: '' }
|
|
332
334
|
this._endorsements = []
|
|
333
335
|
this._derived = null
|
|
336
|
+
this._indicators = [] // indicadores derivados a mostrar (p. ej. ELO por juego)
|
|
334
337
|
this._cloud = null
|
|
335
338
|
this._cloudLoading = true
|
|
336
339
|
this._hover = 0
|
|
@@ -360,9 +363,17 @@ class CloserClickProfile extends HTMLElement {
|
|
|
360
363
|
attributeChangedCallback(name, oldV, newV) {
|
|
361
364
|
if (oldV === newV) return
|
|
362
365
|
if (name === 'pubkey') { this._resetState(); this.reload(); return }
|
|
366
|
+
if (name === 'indicators') { this._indicators = []; this.reload(); return }
|
|
363
367
|
if (this.shadowRoot.childElementCount) this._render()
|
|
364
368
|
}
|
|
365
369
|
|
|
370
|
+
// Indicadores derivados a mostrar (atributo `indicators`), p. ej.
|
|
371
|
+
// "elo:cuarenta" o "elo:chess,elo:cuarenta". Formato: nombre[:scope], coma.
|
|
372
|
+
get _indicatorSpecs() {
|
|
373
|
+
return (this.getAttribute('indicators') || '').split(',').map(s => s.trim()).filter(Boolean)
|
|
374
|
+
.map(s => { const [iName, scope] = s.split(':'); return { name: iName, scope: scope || undefined } })
|
|
375
|
+
}
|
|
376
|
+
|
|
366
377
|
_onKeydown(e) {
|
|
367
378
|
if (e.key === 'Escape' && this.hasAttribute('modal')) this._close()
|
|
368
379
|
}
|
|
@@ -388,6 +399,7 @@ class CloserClickProfile extends HTMLElement {
|
|
|
388
399
|
this._my = { confianza: 0, afinidad: 0, notes: '' }
|
|
389
400
|
this._endorsements = []
|
|
390
401
|
this._derived = null
|
|
402
|
+
this._indicators = []
|
|
391
403
|
this._cloud = null
|
|
392
404
|
this._cloudLoading = true
|
|
393
405
|
this._hover = 0
|
|
@@ -422,6 +434,17 @@ class CloserClickProfile extends HTMLElement {
|
|
|
422
434
|
this._derived = e ? e.derived : null
|
|
423
435
|
}
|
|
424
436
|
} catch (_) { /* best-effort */ }
|
|
437
|
+
// Indicadores derivados (p. ej. ELO por juego), vía provider.getDerived.
|
|
438
|
+
try {
|
|
439
|
+
const specs = this._indicatorSpecs
|
|
440
|
+
if (specs.length && typeof p.getDerived === 'function') {
|
|
441
|
+
const vals = await Promise.all(specs.map(async s => {
|
|
442
|
+
try { const d = await p.getDerived(pk, s.name, s.scope); return d ? { ...s, value: (d.value != null ? d.value : d.elo), count: (d.count != null ? d.count : d.games) } : null } catch (_) { return null }
|
|
443
|
+
}))
|
|
444
|
+
if (token !== this._loadToken) return
|
|
445
|
+
this._indicators = vals.filter(v => v && v.value != null)
|
|
446
|
+
}
|
|
447
|
+
} catch (_) { /* best-effort */ }
|
|
425
448
|
if (token === this._loadToken) this._render()
|
|
426
449
|
|
|
427
450
|
try {
|
|
@@ -559,6 +582,11 @@ class CloserClickProfile extends HTMLElement {
|
|
|
559
582
|
</label>` : `<div class="name">${this._esc(name)}</div>`}
|
|
560
583
|
<code class="pubkey">${this._esc(this._shortKey(pk))}</code>
|
|
561
584
|
${since ? `<div class="since">${this._esc(t.knownSince)} ${this._esc(this._fmtDate(since))}</div>` : ''}
|
|
585
|
+
${this._indicators.length ? `<div class="ind-badges">${this._indicators.map(i => {
|
|
586
|
+
const label = this._esc((i.name || '').toUpperCase())
|
|
587
|
+
const tip = label + (i.scope ? ' · ' + this._esc(i.scope) : '') + (i.count != null ? ' · ' + i.count : '')
|
|
588
|
+
return `<span class="ind-badge" title="${tip}">${label} ${this._esc(String(i.value))}</span>`
|
|
589
|
+
}).join('')}</div>` : ''}
|
|
562
590
|
</div>
|
|
563
591
|
</div>`
|
|
564
592
|
|