docs: add detailed change documentation per feature phase
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ae7f0c1a4a
commit
07403d18c4
5 changed files with 717 additions and 84 deletions
186
CONTEXT/cambio_qr.txt
Normal file
186
CONTEXT/cambio_qr.txt
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
===============================================================
|
||||
CAMBIO QR — DOCUMENTACION TECNICA
|
||||
(commit 54ad8a1)
|
||||
===============================================================
|
||||
|
||||
OBJETIVO:
|
||||
Añadir QR codes en tres puntos de la app para facilitar
|
||||
el uso en movil: escanear en vez de copiar strings largos.
|
||||
|
||||
LIBRERIA:
|
||||
qrcode ^1.5.4
|
||||
Ya estaba en package.json (usada previamente en wallet_view.js).
|
||||
Path de require dentro de las vistas:
|
||||
const QRCode = require('../server/node_modules/qrcode');
|
||||
Uso: QRCode.toString(string, { type: 'svg' }) -> devuelve SVG como string
|
||||
Render: div({ class: 'qr-code', innerHTML: svgString })
|
||||
innerHTML es un atributo que hyperaxe inyecta directamente como HTML crudo.
|
||||
|
||||
--------------------------------------------------------------
|
||||
1. TRIBE INVITES — tribes_view.js
|
||||
--------------------------------------------------------------
|
||||
FUNCION MODIFICADA: renderInvitePage (linea 101)
|
||||
|
||||
ANTES:
|
||||
exports.renderInvitePage = (inviteCode) => { ... }
|
||||
|
||||
DESPUES:
|
||||
exports.renderInvitePage = async (inviteCode) => {
|
||||
const qrSvg = inviteCode
|
||||
? await QRCode.toString(inviteCode, { type: 'svg' })
|
||||
: '';
|
||||
// ... div con el codigo + div con innerHTML: qrSvg
|
||||
}
|
||||
|
||||
PORQUE NO REQUIRIO CAMBIOS EN BACKEND:
|
||||
backend.js ya tenia: ctx.body = await renderInvitePage(...)
|
||||
El await ya estaba, hacer la funcion async no rompio nada.
|
||||
|
||||
QUE SE MUESTRA:
|
||||
- Titulo h2 con el nombre de la tribe
|
||||
- p con el invite code en texto
|
||||
- SVG del QR debajo del codigo (clase: 'div-center qr-code')
|
||||
- Si inviteCode es null/undefined -> qrSvg = '' -> el div QR no se renderiza
|
||||
|
||||
--------------------------------------------------------------
|
||||
2. PUB INVITES — invites_view.js
|
||||
--------------------------------------------------------------
|
||||
FUNCION MODIFICADA: invitesView (linea 34)
|
||||
|
||||
La funcion padre invitesView ya era async (porque hace otras ops async).
|
||||
El bloque del QR usa un IIFE async para poder hacer await dentro
|
||||
de una expresion inline:
|
||||
|
||||
await (async () => {
|
||||
if (!snhInvite) return null;
|
||||
const qrSvg = snhInvite.code
|
||||
? await QRCode.toString(snhInvite.code, { type: 'svg' })
|
||||
: '';
|
||||
return div({ class: 'snh-invite-box' },
|
||||
h3({ class: 'snh-invite-name' }, snhInvite.name),
|
||||
span({ class: 'snh-invite-code' }, snhInvite.code),
|
||||
qrSvg ? div({ class: 'div-center qr-code', innerHTML: qrSvg }) : null
|
||||
);
|
||||
})()
|
||||
|
||||
POR QUE EL IIFE:
|
||||
La estructura de hyperaxe es funcional (cada elemento es un argumento
|
||||
pasado al elemento padre). No puedes poner un await suelto en medio
|
||||
de una lista de argumentos. El IIFE resuelve eso sin reestructurar
|
||||
toda la funcion.
|
||||
|
||||
ALTERNATIVA MAS LIMPIA (si se quisiera refactorizar):
|
||||
Extraer la caja snhInvite a una funcion separada async
|
||||
y llamarla antes de construir el arbol.
|
||||
El IIFE funciona, pero es menos legible para alguien que no lo conozca.
|
||||
|
||||
DATO DEL CONTEXTO:
|
||||
snhInvite viene de: src/configs/snh-invite-code.json
|
||||
Formato: { name: string, code: string }
|
||||
Es el invite code del pub publico de la instancia.
|
||||
|
||||
--------------------------------------------------------------
|
||||
3. PERFIL DE USUARIO — inhabitants_view.js
|
||||
--------------------------------------------------------------
|
||||
TRES FUNCIONES MODIFICADAS:
|
||||
|
||||
--- renderInhabitantCard (linea 83) ---
|
||||
async (user, filter, currentUserId)
|
||||
QR SOLO se genera si isMe === true (el usuario viendo su propio perfil).
|
||||
Razon: evitar generar 50 QRs en la lista de inhabitants.
|
||||
|
||||
const isMe = user.id === currentUserId;
|
||||
const qrSvg = isMe && user.id
|
||||
? await QRCode.toString(user.id, { type: 'svg' })
|
||||
: '';
|
||||
|
||||
El QR aparece dentro de 'div.user-id-qr', junto al enlace user-link.
|
||||
|
||||
--- inhabitantsView (linea 177) ---
|
||||
Debia hacerse async porque llama a renderInhabitantCard (que es async).
|
||||
Usa Promise.all para no hacer await uno por uno:
|
||||
|
||||
await Promise.all(inhabitants.map(user =>
|
||||
renderInhabitantCard(user, filter, currentUserId)
|
||||
))
|
||||
|
||||
IMPORTANTE: Solo genera QR para isMe, asi que en la practica
|
||||
solo hay 1 await real de QRCode.toString() en toda la lista.
|
||||
El Promise.all es correcto igualmente para el futuro.
|
||||
|
||||
--- inhabitantsProfileView (linea 233) ---
|
||||
QR se genera SIEMPRE (para cualquier perfil, no solo el propio).
|
||||
Razon: la pagina de perfil individual es de una sola persona,
|
||||
tiene sentido mostrar su QR para que otros lo escaneen y lo sigan.
|
||||
|
||||
const profileId = payload?.id || id || viewedId;
|
||||
const qrSvg = profileId
|
||||
? await QRCode.toString(profileId, { type: 'svg' })
|
||||
: '';
|
||||
|
||||
Aparece en 'div.inhabitant-left' junto al avatar.
|
||||
|
||||
--------------------------------------------------------------
|
||||
CSS PARA LOS QR
|
||||
--------------------------------------------------------------
|
||||
En style.css (al final del archivo):
|
||||
.qr-code svg -> max-width: 200px, display block, centrado
|
||||
.qr-code-inline svg -> max-width: 120px (en lista inhabitants, mas pequeno)
|
||||
.qr-code-profile svg -> max-width: 150px (en perfil individual)
|
||||
.user-id-qr -> flex column, align-items center
|
||||
.invite-code-text -> font monospace, fondo sutil
|
||||
|
||||
En mobile.css:
|
||||
.qr-code svg -> max-width: 180px
|
||||
.qr-code-inline svg -> max-width: 120px
|
||||
.qr-code-profile svg -> max-width: 150px
|
||||
.qr-lightbox-overlay -> lightbox CSS puro (sin JS), para ampliar QR
|
||||
.qr-lightbox-anchor -> ancla que activa el :target del overlay
|
||||
|
||||
En OasisMobile.css (tema oscuro):
|
||||
.qr-code svg rect -> fill: #1A1A1A (fondo del QR oscuro)
|
||||
.qr-code svg path -> fill: #FFD700 (puntos del QR en dorado)
|
||||
|
||||
--------------------------------------------------------------
|
||||
QUE PUEDE GUSTAR
|
||||
--------------------------------------------------------------
|
||||
- No rompe nada: el backend ya tenia await en todas las rutas afectadas
|
||||
- Libreria qrcode ya existia en el proyecto (no se añadio dependencia nueva)
|
||||
- QR solo donde tiene sentido: no hay QRs innecesarios en cada elemento
|
||||
- En lista de inhabitants, QR solo para el propio usuario = sin overhead
|
||||
- SVG directo (no imagen base64 ni PNG), escala perfecto en cualquier pantalla
|
||||
- El QR del perfil es el SSB ID completo (@xxx.ed25519), scaneable con
|
||||
cualquier cliente SSB para seguir al usuario
|
||||
- Lightbox CSS puro para ampliar QR en movil sin JS adicional
|
||||
- Tema oscuro: colores del QR adaptados (#1A1A1A fondo, #FFD700 puntos)
|
||||
|
||||
--------------------------------------------------------------
|
||||
QUE PUEDE NO GUSTAR / PUNTOS DE DISCUSION
|
||||
--------------------------------------------------------------
|
||||
1. El IIFE async en invites_view.js es un patron poco comun.
|
||||
Funciona, pero si alguien lee el codigo por primera vez le puede
|
||||
parecer raro. Alternativa: extraer a funcion separada.
|
||||
|
||||
2. El QR en inhabitantsProfileView se genera para TODOS los perfiles.
|
||||
Si se visita el perfil de un usuario con un SSB ID muy largo,
|
||||
el QR es pequeno y puede ser dificil de escanear. Considerar
|
||||
mostrar solo para isMe si se quiere ser mas conservador.
|
||||
|
||||
3. El innerHTML con SVG crudo: hyperaxe lo inyecta tal cual.
|
||||
Si el SVG tuviera algun caracter extraño o fallo de la libreria qrcode,
|
||||
podria romper el HTML. En la practica qrcode es fiable, pero
|
||||
es una inyeccion directa a tener en cuenta.
|
||||
|
||||
4. No hay boton "Copiar codigo" junto al QR.
|
||||
En movil es util para pegar el invite en otro lado.
|
||||
Pendiente de implementar.
|
||||
|
||||
5. El QR del tribe invite code es un string hex aleatorio (32 bytes = 64 chars).
|
||||
No es una URL ni tiene deep link. Solo sirve para copiar/pegar en la app,
|
||||
no para escanear con una app de QR generica de terceros.
|
||||
El del SSB ID si que es estandar y reconocible.
|
||||
|
||||
6. No se ha implementado lectura de QR (solo generacion).
|
||||
Leer QR desde la camara requiere acceso nativo Android.
|
||||
Esto esta fuera del scope del Node.js embebido, habria que
|
||||
hacerlo desde el wrapper Kotlin y pasar el resultado al servidor.
|
||||
Loading…
Add table
Add a link
Reference in a new issue