Substituindo avatar e nome de usuário por um post específico

O problema: Quero que os usuários possam postar como personagens de RPG. Gostaria que eles pudessem inserir um modelo em uma postagem - algo como o abaixo:

[wrap="characterpost"]
[characterav]https://image.link.example.png[/characterav]
[charactername][[Nome do Personagem]][/charactername]
[/wrap]

E então usar um script para que a imagem substitua o avatar original e o link do tópico charactername vá para a frente do nome de usuário. Por exemplo, se a postagem normalmente diz “Nome de Usuário”, quero substituí-la por “Nome do Personagem interpretado por Nome de Usuário”.
(“Nome do Personagem” incluiria um link para um tópico com a ficha do personagem, espero que usando apenas o componente temático wikilinks para facilitar o uso.)

Colei um esqueleto de postagem em um Codepen e consegui escrever um javascript que faria exatamente isso. No entanto, ao adicioná-lo a um decorador de postagem e fazê-lo funcionar ao vivo com a API, encontrei um obstáculo.

Aqui está o que tenho no common>header no momento:

<script type="text/discourse-plugin" version="0.8">
api.decorateCookedElement(
  element => {
    
    // encontra a tag characterpost dentro da postagem
    const characterPost = element.querySelector('[data-wrap="characterpost"]');
	
    // encontra o pai da tag characterpost, que contém o avatar e o nome de usuário
    const characterPostParent = characterPost.closest('article');
	
    // deixa vermelho para ver se está funcionando
    characterPostParent.style.backgroundColor = "red";
    
  },
  {
    id: 'render-character-post', onlyStream: true, afterAdopt: true
  }
);
</script>

Isso tem gerado um erro. É possível acessar o wrapper “article” para postagens usando decorateCookedElement para que eu possa chegar ao nome de usuário e avatar? Se não, como posso prosseguir?

4 curtidas

Olá, unfairest,

Encontrei esta postagem e pensei em dar uma chance!

Aqui está a primeira versão; espero que o código não seja muito ruim. :slightly_smiling_face:
Não testei extensivamente todos os casos extremos. É um ponto de partida.

  • Formato de wrap esperado: [wrap=character avatar=\"<URL>\"]<Nome>[/wrap]
  • Certifique-se de que há uma linha vazia abaixo de [wrap]
  • Você pode personalizar o nome do personagem com CSS (veja as classes character e character-extra)

Me avise se tiver algum 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;
    }
}

Aqui está uma pequena demonstração de como ficou:

7 curtidas

Isso é muito legal, obrigado por compartilhar! Eu estava procurando algo semelhante também. Você sabe se isso afeta a forma como as postagens aparecem nos resultados de pesquisa também?

Boa pergunta! O nome da tag e seu conteúdo fazem parte do conteúdo da postagem; isso pode afetar o resultado da pesquisa.
Tentarei algo mais limpo, como usar um modal e salvar em campos personalizados em vez disso.

EDIT: Acho que entendi errado :smile: se você estiver falando sobre alterações que aparecem no resultado da pesquisa, a resposta é não (nem o HTML aparecerá).

2 curtidas

Isso é muito legal. Seu vídeo rola rápido. O URL está no site do fórum?

Ei, Dan. O que você quer dizer?

A URL do avatar é apenas uma imagem carregada ou aponta para um site externo?

Este é um URL externo. Deve ser possível trabalhar com um URL local.

2 curtidas

Legal, obrigado

1 curtida

Pensar que pode ser uma ideia propor, talvez na wiki da comunidade, um guia de template de fórum. Frequentemente, as pessoas procuram ideias sobre diferentes tipos de configurações de fórum.
Neste caso, pode ser um pouco específico. Mas um template de RPG de mesa que inclua este recurso que você criou.