Próximas alterações no cabeçalho - preparando temas e Plugins

Recentemente, trabalhamos na atualização do cabeçalho do Discourse, migrando do sistema de renderização legado ‘widget’ para componentes modernos Glimmer. Essa mudança já está disponível no núcleo do Discourse, por meio da configuração de site glimmer header mode.

:timer_clock: Cronograma Aproximado

(estimativas muito preliminares — sujeitas a alterações em qualquer direção)

T1 2024:

  • :white_check_mark: implementação no núcleo concluída e ativada no Meta

  • :white_check_mark: publicação de orientações sobre atualização; mensagens de descontinuação habilitadas no console

  • :white_check_mark: início do trabalho para atualizar todos os plugins e temas oficiais e de terceiros

T2 2024:

  • :white_check_mark: início da ativação da nova implementação do cabeçalho como padrão

  • :white_check_mark: temas e plugins oficiais e de terceiros prontos para a atualização

  • :white_check_mark: mensagens de descontinuação passam a acionar um banner de aviso para administradores em caso de problemas remanescentes

T3 2024:

  • :white_check_mark: tópico de anúncio publicado para maior visibilidade: Preparing your community for behind-the-scenes header changes

  • :white_check_mark: semana de 5 de agosto de 2024 (v3.4.0.beta1): novo cabeçalho ativado para todos os sites por padrão. Ainda será possível que administradores voltem ao cabeçalho antigo alterando a configuração de site glimmer header mode.

  • :white_check_mark: semana de 2 de setembro de 2024: remoção final da flag de recurso e do código legado

:eyes: O Que Isso Significa para Mim?

Se seu plugin ou tema utiliza alguma API de ‘widget’ para personalizar o cabeçalho, essas precisarão ser atualizadas para compatibilidade com o novo cabeçalho.

:person_tipping_hand: Como Posso Testar o Novo Cabeçalho?

Na versão mais recente do Discourse, o novo cabeçalho é ativado automaticamente quando todos os seus temas/plugins são compatíveis.

Se seus temas/plugins não forem compatíveis, o cabeçalho legado continuará sendo usado, e um aviso será exibido no console junto às mensagens de descontinuação existentes. Um banner de aviso também será mostrado aos administradores na interface.

No improvável evento de esse sistema automático não funcionar como esperado, você pode substituir temporariamente essa ‘flag de recurso automática’ por meio da configuração de site glimmer header mode. Se fizer isso, por favor, informe-nos o motivo neste tópico.

:technologist: Preciso Atualizar Meu Plugin/Tema?

Para determinar se sua personalização precisa ser atualizada, verifique se ela usa decorateWidget, changeWidgetSetting, reopenWidget ou attachWidgetAction em qualquer um desses widgets:

  • header
  • site-header
  • header-contents
  • header-buttons
  • user-status-bubble
  • sidebar-toggle
  • header-icons
  • header-topic-info
  • header-notifications
  • home-logo
  • user-dropdown

ou se utiliza um dos seguintes métodos da API de plugin:

  • addToHeaderIcons
  • addHeaderPanel

Todas essas ações agora gerarão mensagens de descontinuação no console. Os IDs de descontinuação são:

  • discourse.add-header-panel
  • discourse.header-widget-overrides

:warning: Se você usa mais de um tema na sua instância, certifique-se de verificar todos eles.

Aviso ao administrador

A partir de 20 de junho de 2024, ativamos o aviso ao administrador para as descontinuações acima.

Se sua instância foi implantada após essa data e seus plugins, temas ou componentes de tema atuais acionarem um dos avisos de descontinuação, a seguinte mensagem será exibida apenas para administradores*:

Essa mensagem serve apenas para alertar os administradores de que precisam agir em breve para modernizar as personalizações afetadas: as personalizações antigas continuarão funcionando até que removamos a base de código legado.

:twisted_rightwards_arrows: Quais São as Substituições?

Cada tema/plugin é diferente, mas aqui estão algumas orientações para os casos de uso mais comuns:

addToHeaderIcons

:information_source: Para ícones personalizados no cabeçalho, recomendamos remover seu código e instalar o componente oficial de tema Custom Header Links (Icons). Se isso não atender às suas necessidades, veja abaixo detalhes sobre as alterações de código necessárias:

A API de plugin addToHeaderIcons foi descontinuada em favor da nova API headerIcons. Ela permite adicionar, remover ou reordenar ícones no cabeçalho. É necessário passar um Componente.

O componente pode ser passado da seguinte forma:

Antes Depois
api.addToHeaderIcons(“widget-foo”) api.headerIcons.add(“foo”, FooIcon)
api.decorateWidget(“header-icons:before”, () => return helper.h(“div”, “widget-foo”)) api.headerIcons.add(“foo”, FooIcon, { before: “search” })
api.decorateWidget(“header-icons:after”, () => return helper.h(“div”, “widget-foo”)) api.headerIcons.add(“foo”, FooComponent, { after: “search” })

Este exemplo usa o Formato de Tag de Template (gjs) do Ember para definir um componente inline e passá-lo à API headerButtons.add:

// .../discourse/api-initializers/add-my-button.gjs

import DButton from "discourse/components/d-button";
import { apiInitializer } from "discourse/lib/api";

export default apiInitializer("1.0", (api) => {
  api.headerIcons.add("some-unique-name", <template>
    <li><DButton class="icon btn-flat" @href="/u" @icon="address-book" /></li>
  </template>);
});

Ou, para um menu suspenso, você pode usar <DMenu em vez de <DButton:

import DButton from "discourse/components/d-button";
import { apiInitializer } from "discourse/lib/api";
import DMenu from "float-kit/components/d-menu";

export default apiInitializer("1.0", (api) => {
  api.headerIcons.add("some-unique-name", <template>
    <li>
      <DMenu class="icon btn-flat" @icon="address-book">
        <DButton @translatedLabel="Usuário 1" @href="/u/user1" />
        <DButton @translatedLabel="Usuário 2" @href="/u/user2" />
        <DButton @translatedLabel="Usuário 3" @href="/u/user3" />
      </DMenu>
    </li>
  </template>);
});

Exemplos de commits de atualização:

decorateWidget("header-buttons:*")

:information_source: Para links personalizados no cabeçalho, recomendamos remover seu código e instalar o componente oficial de tema Custom Header Links. Se isso não atender às suas necessidades, veja abaixo detalhes sobre as alterações de código necessárias:

O widget header-buttons foi descontinuado e introduzimos uma nova API de plugin headerButtons. Ela permite adicionar, remover ou reordenar botões no cabeçalho. É necessário passar um Componente.

Antes Depois
api.decorateWidget(“header-buttons:before”) api.headerButtons(“button-name”, ButtonComponent, { before: “auth” })
api.decorateWidget(“header-buttons:after”) api.headerButtons(“button-name”, ButtonComponent, { after: “auth” })

changeWidgetSetting(...) para widgets do cabeçalho

:information_source: Os usos mais comuns de changeWidgetSetting podem ser realizados usando estes componentes de tema:

Se esses não se adequarem ao seu caso de uso, continue lendo…

Algumas personalizações nos widgets do cabeçalho usavam a API changeWidgetSetting.

Embora não haja substituição direta para personalizações como a acima, devido ao funcionamento dos campos dos componentes Glimmer, introduzimos uma nova API de plugin no Discourse 3.3.0.beta3 para lidar com alguns desses casos.

registerValueTransformer pode ser usado para substituir valores marcados no código-fonte como substituíveis, uma abordagem semelhante à forma como funcionam as saídas de plugin.

Já adicionamos dois transformadores para os casos de uso mais comuns em nossa base de código:

  • home-logo-href: pode ser usado para substituir a URL no link do logotipo inicial. Veja a seção home-logo abaixo para exemplos.

  • header-notifications-avatar-size: pode ser usado para alterar o tamanho da imagem carregada para o avatar do usuário no cabeçalho. Exemplo:

O código abaixo:

api.changeWidgetSetting(
  "header-notifications",
  "avatarSize",
  settings.header_avatars_size
);

Seria convertido para:

api.registerValueTransformer(
  "header-notifications-avatar-size",
  () => settings.header_avatars_size
);

Esses transformadores precisam ser adicionados ao código-fonte do Discourse. Se precisar de um diferente, por favor, informe-nos postando seu caso de uso abaixo.

Mais detalhes sobre as novas APIs de transformador de valor podem ser encontrados aqui.

home-logo

Introduzimos uma saída de plugin chamada home-logo em substituição às decorações de widget home-logo:before ou home-logo:after. Você pode utilizar a nomenclatura automática __before e __after em seu arquivo de conector para especificar onde seu conteúdo personalizado deve ser colocado.

Mais detalhes sobre a nomenclatura de arquivos de conector antes/depois podem ser encontrados aqui.

Antes Depois
api.decorateWidget(“home-logo:before”) Mover conteúdo para /connectors/home-logo__before
api.decorateWidget(“header-buttons:after”) Mover conteúdo para /connectors/home-logo__after)

Alterando a URL do link do home-logo:

Uma necessidade muito comum é alterar a URL para a qual o home-logo aponta. Introduzimos o transformador de valor home-logo-href para resolver isso. Exemplos:

  • para alterar o link para uma URL estática

    api.registerValueTransformer("home-logo-href", () => "https://example.com");
    
  • para retornar uma URL dinâmica com base no usuário atual

    api.registerValueTransformer("home-logo-href", () => {
      const currentUser = api.getCurrentUser();
      return `https://example.com/${currentUser.username}`;
    });
    
  • para retornar uma URL com base em uma configuração de componente de tema

    api.registerValueTransformer("home-logo-href", () => {
      return settings.example_logo_url_setting;
    });
    

:sos: E outras personalizações?

Se sua personalização não puder ser realizada usando CSS, PluginOutlets ou as novas APIs que introduzimos, por favor, informe-nos criando um novo tópico em Development para discutir.

:sparkles: Como atualizar um tema/plugin para suportar tanto o cabeçalho antigo quanto o novo?

Todas as novas APIs e saídas de plugin listadas neste documento são suportadas tanto no cabeçalho novo quanto no antigo. Portanto, você só precisa fazer uma atualização no seu tema/plugin agora, e os usuários estarão prontos para a troca.

Mas como eu defino um FooIcon?

Em um plugin, tentei criar /assets/javascripts/discourse/components/server-link.js (como para outros componentes que uso em um arquivo hbs)

import Component from "@ember/component";
import discourseComputed from "discourse-common/utils/decorators";

export default Component.extend({
// algo tem que ir aqui?
});

E um assets/javascripts/discourse/templates/components/server-link.hbs com
isto é um link (acho que posso torná-lo um link se conseguir fazer este “Olá, mundo” funcionar)

O exemplo acima tem const IconWithDropdown = ..., mas onde isso iria? Tentei colocá-lo em um inicializador (onde estava o api.decorateWidget), mas não parece ser um JavaScript válido para mim ou para o Ember, pelo que pude apurar.

Antes, eu tinha um array headerlinks e faria

        headerLinks.push(
          h(
            `li.headerLink.no-servers`,
            h("a", anchorAttributes, I18n.t("pfaffmanager.no_servers_title"))
          )
        );

para adicionar os links que eu queria. Acho que se eu conseguir fazer

      api.headerIcons.add("foo", ServerLink, { before: "search" });

funcionar, então posso simplesmente colocá-lo no loop que construiu esse array.

OMG. Então os componentes Glimmer vão em assets/javascripts/discourse/component e os componentes Ember vão em assets/javascripts/discourse/components?!?!\n\nAgora tenho um server-link.gjs

import Component from "@ember/component";
export default class ServerLink extends Component {
  // Argumento obrigatório para a URL
  url = null;
  // Argumento opcional para o texto do link
  text = 'asdf';
  click() {
    console.log('ServerLink clicado!',this);

  }
  // Template para o componente
  <template>
    {{log "meu template" this}}
    LINK!
    <a href={{this.url}}>{{this.text}}</a>
  </template>
}

e no meu inicializador isto:

      api.headerIcons.add("foo", ServerLink, { param: "url, yo", before: "search" });

Agora tenho algo no cabeçalho.

Mas como passo coisas para ServerLink? Preciso chamá-lo várias vezes com URLs diferentes e textos para clicar diferentes. Não consigo ver as coisas naquele {} no componente.

E você realmente não quer colocar javascript antes do <template>, pois meu console.log("") não será analisado!

Também tentei fazer:

      const x = new ServerLink({
        url: "mylink",
        text: "my-text",
        name: 'Bob',
        message: 'Generated from JavaScript',
      });

e depois passar x em vez de ServerLink, mas ainda assim sem sucesso.

Você quer vários botões nos cabeçalhos com ícones/textos/URLs diferentes ou o mesmo botão, mas dependendo do contexto, o texto/URL pode mudar?

Sim, você está em uma classe — você declararia variáveis, funções ou modelos lá!

Sim. Os links mudam para usuários diferentes. O código antigo passava por um array de servers e os adicionava a este array:

            headerLinks.push(
              h(
                `li.headerLink${deviceClass}${newClass}`,
                h("a", anchorAttributes, linkText)
              )
            );

E então fazia isso:

      // api.decorateWidget("header-buttons:before", (helper) => {
      //   return helper.h("ul.pfaffmanager-header-links", headerLinks);
      // });

Então eu tinha até 3 links que eram adicionados ao cabeçalho, cada um linkando para uma URL de servidor separada.

Aha. Agora eu entendi.

Não, não se preocupe - a convenção ainda é /components/ :sweat_smile:

(Tecnicamente, você pode definir e passar componentes gjs como quiser, então pode escolher qualquer nome de diretório que preferir. Mas nós vamos manter /components/.)

Sim, essa é uma pergunta justa - vou trabalhar para escrever alguns documentos ‘do zero’ sobre como adicionar ícones ao cabeçalho para que tenhamos um ponto de referência melhor.

Enquanto isso, você pode gostar de dar uma olhada na atualização do discourse-icon-header-links para inspiração. A coisa legal sobre o uso de GJS é que você pode definir componentes em qualquer lugar, e eles têm acesso a variáveis no escopo local.

Então, se você renomear seu inicializador para .gjs, você pode fazer coisas como

servers.forEach((server) => {
  api.headerIcons.add(`server-${server.id}`, <li><DButton @translatedLabel={{server.name}} @icon="server" /></li>);
});

Ou você pode definir um componente anteriormente no mesmo arquivo e usá-lo como

class ServerButton extends Component {
  get icon(){
    // alguma lógica para decidir o ícone
  }
  <li><DButton @translatedLabel={{@server.name}} @icon={{this.icon}} /></li>
}

...

servers.forEach((server) => {
  api.headerIcons.add(`server-${server.id}`, <ServerButton @server={{server}} />);
});

Ou você poderia mover a iteração para dentro do template (útil se a lista de servidores for um TrackedArray que pode mudar em tempo de execução!)

api.headerIcons.add("server-buttons",
  {{#each servers as |server|}}
    <ServerButton @server={{server}} />
  {{/each}}
);

Ah. Que bom. Achei que tinha tentado em components e não tinha funcionado.

Obrigado! Acho que consigo fazer uma dessas coisas funcionar. O link para os links do cabeçalho é uma grande ajuda. Tenho certeza de que, quando escrevi meu código, tive bom senso para olhar para esse componente para descobrir.

Vendo um raio de esperança!

Olá @david e @Arkshine! Consegui!

O q u e ? Apenas renomear? Isso é loucura. Mas, com certeza. Eu fiz isso, e agora

          servers.filter(Boolean).map((server) => {
            const linkHref = `/pfaffmanager/servers/${server.id}`;
            const linkTitle = `click to configure server ${server.id}`;
            let host = String(server.hostname);
            const linkText = host.replace(
              /www.|community.|forums?.|talk.|discourse./,
              ""
            );
            const serverLink = <template>
              <li class="headerLink">
                <a class="btn-flat" href={{linkHref}} title={{linkTitle}}>
                  {{host}}
                </a>
              </li>
            </template>;
            const beforeIcon = ["chat", "search", "hamburger", "user-menu"];
            api.headerIcons.add(host, serverLink, { before: beforeIcon });
          });

E está fazendo o que fazia antes, que era o que eu queria!

Sim, agora isso parece muito legal, e ainda mais o que eu quero, mas essas coisas não mudam muito, então vou parar por aqui. Se eles mudarem um nome de host, eles terão que recarregar a página para que o link mude.

Presumo que você excluirá minha “tralha” extra aqui quando atualizar as coisas acima (ou talvez eu não tivesse sido tão falante em um tópico de documentação…).

Atualizei o OP com alguns exemplos completos de gjs e incluí um link para a documentação upstream do Ember. O que você acha, @pfaffman? Há mais alguma coisa que você acha que valeria a pena adicionar?

É melhor, pois tem um exemplo funcional. Mas eu entendi corretamente que existem componentes Ember e componentes Glimmer? E se isso estiver certo, você deveria dizer que um componente Glimmer é necessário, eu acho?

E talvez vincular à documentação do Glimmer sobre como eles funcionam?

Parece que você pode ter componentes inline como no seu exemplo, e outro tipo onde você o atribui a algo como uma variável no mesmo arquivo ou o coloca em outro arquivo que você coloca no diretório de componentes e depois inclui? Acho que tudo isso pode ser demais para este tópico, mas eu adoraria um tópico dedicado sobre isso.

Eles são totalmente intercambiáveis - você pode usar um Componente Ember Clássico ou um Componente Glimmer. E para qualquer um deles, você pode optar por criá-los usando o formato antigo .js/.hbs ou o novo formato .gjs.

Vou ver se consigo incluir alguns links para a documentação do Ember :+1:

:mega: Hoje mesclamos esta alteração, que habilitará automaticamente a nova implementação do cabeçalho para sites com temas/plugins compatíveis.

Se seus temas/plugins não forem compatíveis, o cabeçalho legado ainda será usado e um aviso será impresso no console junto com as mensagens de descontinuação existentes. Em um futuro próximo, este aviso do console será atualizado para um banner de aviso na interface do usuário.

No improvável caso de essa alteração automática causar problemas, você pode substituir temporariamente este ‘sinalizador de recurso automático’ através da configuração do site glimmer header mode. Se fizer isso, por favor, informe-nos o motivo neste tópico.

Eu não estava procurando fazer nenhuma alteração, mas os avisos de depreciação me dizem o contrário,

Então há uma escolha e talvez uma maneira fácil de apenas manter o status quo?

ou

O que eu estaria perdendo ao optar por tentar manter um cabeçalho antigo, não entendo o que o novo significa, vejo configurações de grupo, personalização para diferentes grupos é intrigante, mas o que pode ser personalizado?

Isso é o que encontrei hoje,

Eu não sou um guru ou gênio com essas mudanças, elas levam tempo e eu não as faço com frequência suficiente para realmente desejar aprender as técnicas que os usuários aqui parecem facilmente compreender/saber

Eu meio que me ressinto de ter que fazê-las em primeiro lugar, mas antes que eu grite como um velho que ficou sem pudim, eu gostaria de saber, o quê, por quê e para onde isso está indo?

Eu faço isso como profissão e ainda acho esse negócio de JavaScript muito longe de ser fácil.

Eu sou um velho e sinto sua dor.

É apenas progresso, receio. Essa atualização do Ember quebrou um monte de coisas e ainda não acabou.

Você “pediu por isso” quando fez essa personalização. Aposto que nos últimos cinco anos você comprou um telefone ou laptop novo.

Se eu fosse você (e você fosse como eu, sem o trabalho em tempo integral no Discourse), eu postaria em Marketplace. Se eu fosse eu, provavelmente não responderia por menos de US$ 300, mas há uma chance razoável de que outra pessoa o faça por US$ 100 ou US$ 200. Eu estimaria que não quebrará novamente por mais 5 anos ou mais.

Acho que o seletor de tema de hambúrguer pode ser removido e você pode usar a barra lateral.

Resposta honesta e agradável, aprecio, mas não há muito com o que trabalhar, talvez haja mais por vir (espero)

Eu nem sabia que estávamos lidando com Java aqui :man_shrugging:

Não quero que ninguém pegue seu pudim também :face_with_hand_over_mouth:

Claro, mas qual é o objetivo desejado? Este software mexe com tantas coisas que me pergunto quem vê o quê no final?

Isso é simplesmente necessário pela atualização do Ember?

Eu também não sei por que o Ember foi feito, mas se funciona, por que consertar? Tenho certeza de que há uma explicação longa e profunda que leva ao futuro das coisas, mas não há uma visão verdadeira a ser compartilhada?

Eu visito outros fóruns que usam software muito antigo. Pessoalmente, vejo o Discourse como muito melhor do que qualquer um deles, mas eles não parecem sofrer em comparação, eles têm os mesmos problemas de crescimento, a maioria é personalidade vs software, na minha opinião, muitos veteranos que perderam seu pudim. Estou me perguntando, existe um futuro de IOT que tornará literalmente todos esses fóruns obsoletos, onde eles não funcionarão mais e o Discourse está ciente e se preparando?

Há mais dessa honestidade que você oferece :grin: Verdade, e eu estava mais ansioso para aprender, mais ambicioso, senti o que valia mais, fui espancado, atropelado e deixado para morrer desde então.

Ok, você está certo, aceito essa aposta e, como você já perdeu, me ajuda com isso, seremos amigos.

Então você provavelmente teria desistido há muito tempo, o espancado, atropelado e deixado para morrer foi uma descrição um tanto eufemística, sou só eu que restou ao volante, acho que qualquer outra pessoa está em algum painel tentando consertar o hiperdrive, sei lá, pois não me comunico muito com os outros, não temos financiamento, nós (FULL30) fomos desativados das mídias sociais e do Discourse também, me pergunto quantos outros clientes pagantes o Discourse cortou voluntariamente ou quantos outros foram considerados tão ofensivos em suas crenças que o Discourse publicamente investiu dinheiro contra eles?

No entanto, enquanto falo a verdade, não me ofendo, viva e deixe viver, sei que um futuro está chegando, o que não sei é por que ainda estou aqui e ainda tentando, mas estou, então, continuarei tentando, como AA, apenas por hoje :hugs:

Mas estava na moda quando o usei :expressionless:

A barra lateral (aqui) pode ser fechada com um menu “hamburger”, não há muita diferença na função, ela abre e fecha uma janela de navegação, mas a minha não pode ser salva facilmente?

Sim, eu adoraria e preferiria pagar alguém para limpar meu código personalizado e fazer as coisas funcionarem bem, e eu pagaria feliz, gosto de empregar outras pessoas, compartilhar a riqueza, quando eu crescer quero ser um filantropo, mas hoje preciso de um filantropo :innocent: e novamente aprecio qualquer ajuda que outros possam oferecer.

A outra forma de jogar é pedir ajuda à sua comunidade, parar de fazer o que quer que seja a personalização, iniciar um novo tópico que compartilhe seu código e pedir ajuda. Tenho recebido muita ajuda nesses assuntos recentemente.

Infelizmente não. A capacidade de manter o ‘cabeçalho antigo’ é apenas uma coisa temporária durante o período de transição. Em breve, o novo cabeçalho será a única opção.

Sim! Estamos sempre felizes em ajudar com perguntas em Dev. Além disso, compartilhar o código e as soluções publicamente cria um recurso útil para outras pessoas.

Ufa, minha comunidade está mais sintonizada com outras questões

Certamente eu poderia compartilhar aqui, mas então vai para o lado oposto, que programador se interessa em nos ajudar?

A ironia, programar pode muito bem ser as armas de fogo do futuro, pode muito bem causar muito mais morte e destruição também, divago

Muito bem, isso significa o quê exatamente para mim, criar um grupo de usuários, público e não logado, talvez?

Essas configurações de grupo, percebo que são baseadas em níveis de confiança versus grupos realmente diferentes, como um grupo de caça e um grupo de pesca?

Primeiro, preciso entender o objetivo e onde meus esforços como lobo solitário terão o maior impacto, economizando tempo e preservando a sensação personalizada do meu fórum.


Não quero descarrilar o tópico de ninguém, se for considerado que isso deveria ser um tópico próprio, tudo bem

mas como haverá um relacionamento verdadeiramente coeso quando as pessoas sentem a necessidade de remover algo que as ofende?

É preciso paciência para entender os outros, o link removido, mostrou um logo faltando depois, mas não enquanto postava, outro problema de cabeçalho para discutir?

Foi uma postagem no meu fórum escrita por um homem que acredito ter mais de 80 anos, eu poderia perguntar com certeza, mas ele se recusa a falar comigo, devo repreendê-lo, bani-lo ou evitá-lo?

Não, por quê, porque há um jeito melhor, mas isso significa aturar os outros e como eles pensam, encontro pessoas boas em lugares ruins, pessoas boas que parecem ruins, e exatamente o oposto em ambos.

Exatamente, acabei de encontrar os erros, desejo corrigi-los, mas não entendo a causa raiz, exceto que o futuro está avançando, precisamos de um novo cabeçalho, ok, tudo bem, qual é o curso correto para definir minhas metas, ajuste simples, uma correção de curso completa?

Estamos discutindo apenas a necessidade de trabalhar nessas três áreas?

Tenho uso misto de componentes, comecei sem nenhum e depois aprendi que eles podem ser benéficos, nunca usei componentes totalmente e tenho uma mistura.

Aqui está meu tema, pelo que vale, sem os componentes
discourse-full30-ii.zip (10,1 KB)
Posso postar esses também, alguns, os modais, já não estão funcionando recentemente