Reemplazar avatar y nombre de usuario en una publicación específica

El problema: Quiero que los usuarios puedan publicar como personajes de RPG. Me gustaría que pudieran insertar una plantilla en una publicación, algo como esto:

[wrap="characterpost"]
[characterav]https://image.link.example.png[/characterav]
[charactername][[Nombre del personaje]][/charactername]
[/wrap]

Y luego usar un script para que la imagen reemplace el avatar original y el enlace del tema charactername se coloque delante del nombre de usuario. Por ejemplo, si la publicación normalmente dice “Nombre de usuario”, quiero reemplazarlo con “Nombre del personaje interpretado por Nombre de usuario”.
(El “Nombre del personaje” incluiría un enlace a un tema con la hoja del personaje, con suerte usando el componente temático wikilinks para facilitar su uso).

Pegué un esqueleto de publicación en Codepen y pude escribir algo de javascript que haría exactamente esto. Sin embargo, cuando se trató de agregarlo a un decorador de publicaciones y hacerlo funcionar en vivo con la API, me encontré con un obstáculo.

Aquí está lo que tengo en common>header ahora mismo:

<script type="text/discourse-plugin" version="0.8">
api.decorateCookedElement(
  element => {
    
    // encuentra la etiqueta characterpost dentro de la publicación
    const characterPost = element.querySelector('[data-wrap="characterpost"]');
	
    // encuentra el padre de la etiqueta characterpost, que contiene el avatar y el nombre de usuario
    const characterPostParent = characterPost.closest('article');
	
    // lo pongo rojo para ver si funciona
    characterPostParent.style.backgroundColor = "red";
    
  },
  {
    id: 'render-character-post', onlyStream: true, afterAdopt: true
  }
);
</script>

Esto ha estado arrojando un error. ¿Es posible acceder al “wrapper” del “article” para las publicaciones usando decorateCookedElement para poder llegar al nombre de usuario y al avatar? Si no, ¿cómo puedo abordar esto?

4 Me gusta

Hola, unfairest,

¡Me encontré con esta publicación y pensé que podría intentarlo!

Aquí está la primera versión; espero que el código no sea demasiado horrible. :slightly_smiling_face:
No probé exhaustivamente todos los casos extremos. Es un punto de partida.

  • Formato de envoltura esperado: [wrap=character avatar=\"<URL>\"]<Nombre>[/wrap]
  • Asegúrate de que haya una línea vacía debajo de [wrap]
  • Puedes personalizar el nombre del personaje con CSS (consulta las clases character y character-extra)

Avísame si tienes algún problema :slight_smile:

Head
<script type="text/discourse-plugin" version="0.8.13">

let characters = new Map();

function searchTag(obj, tag) {
  if (!obj || !obj.firstObject) return;
  
  const firstObj = obj.firstObject;
  return firstObj.tagName === tag ? firstObj : searchTag(firstObj.children, tag);
}
            
api.addPostTransformCallback(post => 
{
    if (post.post_number <= 1 || post.post_type !== 1) {
        return;
    }

    const matches = post.cooked.match(/data-wrap="character"\s+data-avatar="(?<avatar>[^"]+)"\s+data-name="(?<name>[^"]+)"/i);
    
    if (!matches) {
        characters.delete(post.id);
        return;
    }
    
    // TODO: sanity check for avatar/name
    
    const {name, avatar} = matches.groups;
    
    characters.set(post.id, {name, avatar});
    
});

api.reopenWidget("post-avatar", {
    html(attrs) {
        const html = this._super(attrs);
        
        if (attrs.id && characters.has(attrs.id)) {
            const imageHtml = searchTag(html, 'IMG');
    
            if (imageHtml) {
                imageHtml.properties.attributes.src = characters.get(attrs.id).avatar;
            }
        }
        
        return html;
    }
});

api.reopenWidget("poster-name", {
    html(attrs) {
        let html = this._super(attrs);
        
        if (attrs.id && characters.has(attrs.id)) {
            const h = require("virtual-dom").h;
            
            html = [
                h('span.character', this.userLink(attrs, characters.get(attrs.id).name)),
                h('span.character-extra', 'played by'), // optional
                ...html
            ];
        }
        
        return html;
    }
});

</script>
CSS
.names {
    .character a {
        font-weight: bold;
        color: var(--tertiary-high);
    }
    
    .character-extra {
        
    }
}

.cooked, .d-editor-preview {
    p:has(> [data-wrap="character"]) {
        display: none;
    }
    
    p:has(> [data-wrap="character"]) + * {
        margin-top: 0;
    }
}

Aquí hay una pequeña demostración de cómo se veía:

7 Me gusta

¡Esto es muy genial, gracias por compartir! Yo también estaba buscando algo similar. ¿Sabes si esto también afecta cómo aparecen las publicaciones en la búsqueda?

¡Buena pregunta! El nombre de la etiqueta y su contenido forman parte del contenido de la publicación; esto podría afectar el resultado de la búsqueda.
Intentaré algo más limpio, como usar una ventana modal y guardar en campos personalizados en su lugar.

EDITAR: Creo que entendí mal :smile: si te refieres a que los cambios aparezcan en el resultado de la búsqueda, la respuesta es no (tampoco aparecerá el HTML).

2 Me gusta

Esto es genial. Tu video se desplaza rápido. ¿Está la URL en el sitio del foro?

Oye, Dan. ¿Qué quieres decir?

La URL del avatar. ¿Es solo una imagen subida o apunta a un sitio externo?

Esta es una URL externa. Debería ser posible trabajar con una URL local.

2 Me gusta

Genial, gracias

1 me gusta

Pensar que podría ser una buena idea proponer, quizás en la wiki de la comunidad, una guía de plantillas de foros. A menudo, la gente busca ideas sobre diferentes tipos de configuraciones de foros. En este caso, podría ser un poco específico. Pero una plantilla de RPG de mesa que incluya esta característica que creaste.