[Teste A/B] Alterando a classe CSS pai com base na variável do experimento

Temos um tema existente que gostaríamos de testar. Um exemplo seria experimentar diferentes estilos de visualização da lista de tópicos. Para isso, estamos usando o teste A/B do Google Optimize. Atualmente, planejamos mostrar o tema sem alterações para 50% dos usuários e o restante com o tema atualizado. O original e a variante devem ser definidos no mesmo tema, pois vamos experimentar apenas uma pequena parte. O problema é que as classes CSS pai compartilham o mesmo nome e queremos aplicar estilos a essas classes pai com base em uma variável específica. Como aplicar estilos separados a diferentes modelos, já que eles compartilham o mesmo nome de classe pai?

Abaixo está um cenário simplificado do que estamos tentando alcançar

Considere que tenho um tema onde o estilo da lista de tópicos é definido assim em common/common.scss

.topic-list {
  tbody {
    border: none;
  }
  tr {
    border: none;
  }
  .example-div {
    border: none;
  }
}

e na minha variante, quero defini-lo como:

.topic-list {
  tbody {
    display: block;
    tr {
      display: block;
    }
  }
  .example-div {
    border: 2px solid black;
  }
  .another-example-div { 
    font-size: 10px;
  }
}

Os arquivos handlebar que estão sendo sobrescritos se parecem com isso

javascripts/discourse/templates/list/custom-topic-list-item.hbr

<div class='example-div'>
  Hello
</div>

javascripts/discourse/templates/list/variant-custom-topic-list-item.hbr

<div class='example-div'>
  Hello,
  <div class='another-example-div'>
    Nice to meet you
  </div>
</div>

O nome da classe topic-list é mencionado no componente do Discourse, mas a estrutura após a renderização é assim

<table class="topic-list">
  <tr class="topic-list-item">
   <div class='example-div'>
      Hello
    </div>
  </tr>
</table>

Quero renderizar um desses arquivos dependendo do ID do usuário no meu arquivo de cabeçalho
common/header.html

const { findRawTemplate } = require("discourse-common/lib/raw-templates");
const user_id = api.getCurrentUser().id
 
api.modifyClass('component:topic-list-item', {
  renderTopicListItem() {
    let template = findRawTemplate("list/custom-topic-list-item");
    if (user_id % 2 === 0)
       template = findRawTemplate("list/variant-custom-topic-list-item");
    if (template) {
      this.set("topicListItemContents", template(this).htmlSafe());
    }
  },
});

Obrigado

Note que isso provavelmente está causando um erro não tratado para usuários que não estão logados. Recomendo alterar para:

const user = api.getCurrentUser();
if (!user) return;

const userId = user.id;

Com isso resolvido, vamos voltar à sua pergunta.

Diferente do CSS, o SCSS suporta um seletor de pai, então você pode usar isso.

Como você deseja aplicar isso a cada outro usuário (id % 2),

você pode verificar isso quando o aplicativo carregar. Algo assim, no topo:

const user = api.getCurrentUser();
const userId = user.id;

if (!userId) return;

const testThemeUser = userId % 2 === 0;

if (testThemeUser) {
  document.body.classList.add("test-theme");
}

Você pode então usar a variável testThemeUser em seus condicionais de JS e a classe CSS test-theme em seus estilos.

Então, algo assim.

JS

let template = findRawTemplate("list/custom-topic-list-item");
if (testThemeUser)
  template = findRawTemplate("list/variant-custom-topic-list-item");
if (template) {
  this.set("topicListItemContents", template(this).htmlSafe());
}

SCSS

.topic-list {
  tbody {
    border: none;
  }
  tr {
    border: none;
  }
  .example-div {
    border: none;
  }
  // SCSS do tema de teste
  .test-theme & {
    .example-div {
      border: 2px solid black;
    }
    .another-example-div {
      font-size: 10px;
    }
  }
}

Obrigado pela sua resposta @Johani
No momento, preciso apenas atualizar uma classe de componente específica, que é a topic-list, então estou usando essa abordagem

const useTestTheme = userId % 2 === 0

api.modifyClass('component:topic-list', {
    classNameBindings: ["test"],
    test: useTestTheme,
})