[Test A/B] Modification de la classe CSS parente en fonction de la variable de l'expérience

Nous disposons d’un thème existant que nous souhaitons expérimenter. Par exemple, tester différents styles de vue de la liste des sujets. Pour cela, nous utilisons les tests A/B de Google Optimize. Actuellement, nous prévoyons d’afficher le thème sans modification pour 50 % des utilisateurs, et le reste avec le thème mis à jour. L’original et la variante doivent être définis dans le même thème, car nous allons expérimenter sur une petite partie. Le problème est que les classes CSS parentes partagent le même nom, et nous souhaitons appliquer des styles à ces classes parentes en fonction d’une variable spécifique. Comment appliquer des styles distincts à différents modèles alors qu’ils partagent le même nom de classe parente ?

Voici un scénario simplifié de ce que nous essayons d’accomplir.

Supposons que j’ai un thème où le style de la liste des sujets est défini ainsi dans common/common.scss :

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

Et dans ma variante, je souhaite le définir comme suit :

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

Les fichiers Handlebar qui sont surchargés ressemblent à ceci :

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

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

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

<div class='example-div'>
  Bonjour,
  <div class='another-example-div'>
    Enchanté de faire votre connaissance
  </div>
</div>

Le nom de classe topic-list est mentionné dans le composant Discourse, mais la structure après rendu ressemble à ceci :

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

Je souhaite rendre l’un de ces fichiers en fonction de l’ID de l’utilisateur dans mon fichier d’en-tête :
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());
    }
  },
});

Merci.

Notez que cela provoque probablement une erreur non capturée pour les utilisateurs non connectés. Je recommande de remplacer cela par :

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

const userId = user.id;

Une fois cela réglé, revenons à votre question.

Contrairement au CSS, le SCSS prend en charge un sélecteur parent, ce que vous pouvez utiliser.

Puisque vous souhaitez appliquer cela à chaque deuxième utilisateur (id % 2),

Vous pouvez vérifier cela au chargement de l’application. Donc, quelque chose comme ceci tout en haut :

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

if (!userId) return;

const testThemeUser = userId % 2 === 0;

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

Vous pouvez ensuite utiliser testThemeUser dans vos conditions JS et la classe CSS test-theme dans vos styles.

Donc, quelque chose comme ceci.

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;
  }
  // test theme SCSS
  .test-theme & {
    .example-div {
      border: 2px solid black;
    }
    .another-example-div {
      font-size: 10px;
    }
  }
}

Merci pour ta réponse @Johani
Actuellement, je dois uniquement mettre à jour une classe de composant spécifique, à savoir topic-list, j’utilise donc cette approche :

const useTestTheme = userId % 2 === 0

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