Capacidade de adicionar uma seção personalizada de links à barra lateral

Queremos permitir que os usuários adicionem uma seção personalizada de links à sua barra lateral.

Em uma primeira etapa para este recurso, planejamos expandir a página de preferências da barra lateral existente e permitir que um usuário adicione uma única seção personalizada para esses links.

Achamos que pode funcionar mais ou menos assim:

  1. caixa de seleção para “Mostrar Seção Personalizada”.
    Se marcada, a Seção Personalizada aparece acima da Seção de Categorias e os valores devem ter um Nome válido e pelo menos um Link válido para “Salvar Alterações”
  2. caixa de texto para o Nome da seção personalizada (padrão: Meus Links, não pode ficar em branco)
  3. botão para “Adicionar link”. quando clicado, exibe a caixa de diálogo para adicionar link
  4. Links adicionados mostram um botão para removê-lo

Caixa de diálogo Adicionar link

  1. A caixa de diálogo Adicionar link tem duas caixas de texto: Nome, URL
  2. O Nome não pode ficar em branco, pode incluir emoji (que deve ser renderizado na barra lateral)
  3. A URL deve ser um link para dentro do mesmo site Discourse*
  4. Salvar adiciona o link, Cancelar o descarta

Quando uma seção personalizada válida for configurada e salva, a barra lateral mostrará essa seção acima de “Categorias”.

* Por quê?

  1. Gostaríamos de poder “destacar”/“negritar” o link na barra lateral quando você estiver na página correspondente.
  2. Gostaríamos de armazenar a parte do “caminho”, para que as renomeações de sites funcionem como esperado.

Acreditamos que adicionar links hoje será valioso porque permitirá que as pessoas acessem facilmente coisas como “Bugs abertos da barra lateral” e nos permitirá aproveitar quaisquer melhorias futuras para listas de tópicos, como filtros aprimorados de listas de tópicos. Desde que as coisas tenham uma URL, as pessoas podem adicioná-las à sua barra lateral.

Pensamos que os usuários vão querer poder adicionar várias seções e reordená-las, mas manteremos isso fora do escopo inicialmente.

16 curtidas

Uma pergunta sobre isso, @mcwumbly. Isso parece uma estratégia para permitir que um usuário adicione links pessoais à barra lateral. Essa abordagem permitiria que os proprietários do site adicionassem links que todos os usuários veriam?

Spoiler - Eu acho que deveria. :slight_smile:

5 curtidas

Sim, acho que certamente poderia ser expandido para fazer algo assim, e vejo como isso seria um recurso mais útil para alguns sites do que o usuário.

8 curtidas

Eu realmente gosto dessa ideia. :+1:

Apenas algumas perguntas:

  1. Haverá um limite para o número de links personalizados que um usuário poderá adicionar?

  2. O final dos links (na barra lateral) será truncado como no mockup a seguir? (Eu ficaria bem com isso).
    E se forem, o usuário poderá ler o texto deles por completo em uma tooltip (se o cursor do mouse pairar sobre os links)?

Boa pergunta. Provavelmente precisaremos de alguns limites, mas não é algo que discutimos em detalhes. Que tipo de limites você espera ver (ou evitar)?

1 curtida

No início, pensei que 10 links poderiam ser suficientes, mas acho que outros membros do fórum vão querer mais. Talvez 20. Por isso, eu tentaria com 20 e esperaria o feedback dos usuários para ver se eles pedem mais (mas acho que 20 já é um bom número).

1 curtida

Para estender a “facilidade de uso” deste recurso, seria muito bom permitir que o usuário arraste e solte links (qualquer link da página atual do Discourse) diretamente para a barra lateral.

Um ponteiro (entre links que foram adicionados anteriormente à DIV “Meus Links”) indicaria onde o link seria colocado.

Mock-up (clique com o botão direito \u003e “abrir imagem em nova guia” para ver a animação em tamanho real):

anim01

Talvez a seguinte página possa ajudar a implementar o arrastar e soltar?

7 curtidas

Eu adoraria poder definir links padrão para o meu site, que os usuários pudessem dispensar. Isso tornaria isso estritamente melhor do que os links de cabeçalho personalizados que estou usando agora, como vejo.

3 curtidas

+1 para adicionar links personalizados. Tivemos alguns links personalizados adicionados ao menu suspenso original. Seria bom adicioná-los de volta, semelhante a como o próprio Discourse tem “Aniversários” e “Docs” sob a opção “Mais”.

4 curtidas

Olá a todos!

Estou pensando em como adicionar links à nova barra lateral.

Parece não haver nenhum conector nessa área…

Qual seria a maneira mais eficaz de fazer isso?


Edição

Minha pergunta foi movida para cá… Não tenho certeza por quê, pois estou realmente perguntando sobre a mesma coisa.

De qualquer forma, eis o que fiz para resolver. NÃO é uma solução elegante e seria muito melhor se houvesse uma maneira de integrar com o sistema de templates do discourse.

Aqui está:

<script>
    let logo = "" // Removi os caminhos SVG porque vocês não precisam deles.
    const div = document.createElement('div') // Cria o link a ser adicionado
    div.className = 'sidebar-section-link-wrapper' // adiciona as classes relevantes
    div.innerHTML = `
          <a title="Todos os tópicos" href="https://www.latranchee.com" id="ember12" class="sidebar-section-link sidebar-section-link-everything sidebar-row ember-view">
            <span class="sidebar-section-link-prefix icon">
              <svg viewBox="0 0 100 100" class="logoIcon" xmlns="http://www.w3.org/2000/svg">${logo}</svg>
            </span>
            <span class="sidebar-section-link-content-text"> Accueil </span>
          </a>
    ` // Preenche o link
    
    $( document ).ready(() => { // Isso é necessário para esperar até que o ember termine sua coisa
        // adiciona navegação no desktop
        let desktop = document.getElementsByClassName('sidebar-section-content')[0];
        if(desktop) desktop.prepend(div)
        
        // adiciona navegação no mobile
        let hamburger = document.getElementById('toggle-hamburger-menu').addEventListener("click", addMobileNav);
        function addMobileNav () {
            setTimeout(function(){ // Força a esperar até que a navegação tenha sido carregada
                document.getElementsByClassName('sidebar-section-content')[0].prepend(div);
            }, 0);
        }
    })
</script>

Resultado no desktop…

& Resultado no mobile:

Até que haja uma maneira melhor, isso terá que servir!

Edição #2

Organizei o código para que as navegações sejam carregadas de um array de objetos.

<script>
  let rss = `<path d="M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M7.5,15A1.5,1.5 0 0,0 6,16.5A1.5,1.5 0 0,0 7.5,18A1.5,1.5 0 0,0 9,16.5A1.5,1.5 0 0,0 7.5,15M6,10V12A6,6 0 0,1 12,18H14A8,8 0 0,0 6,10M6,6V8A10,10 0 0,1 16,18H18A12,12 0 0,0 6,6Z"></path>`
  let mdiSchool = `<path d="M12,3L1,9L12,15L21,10.09V17H23V9M5,13.18V17.18L12,21L19,17.18V13.18L12,17L5,13.18Z"></path>`
  let logo = `<g xmlns="http://www.w3.org/2000/svg" fill="#0e1e2b">
    <path d="M77.4 196.2 c-8 -6.9 -11.4 -16.9 -11.4 -33.2 0.1 -20.9 2.4 -30.2 6.7 -27.4 2.9 1.8 4.3 9.4 5.4 28.9 0.9 16.5 1.4 19.8 3.6 25 1.3 3.3 2.5 6.7 2.6 7.5 0.3 2.6 -3.6 2.1 -6.9 -0.8z"/>
    <path d="M2.9 167.3 c-5.1 -6.1 11.2 -24.2 21.9 -24.3 2.6 0 2.7 1.1 0.6 5.5 -1.4 3 -12.6 13.5 -14.3 13.5 -0.4 0 -1.4 1.2 -2.1 2.6 -2 3.6 -4.5 4.8 -6.1 2.7z"/>
    <path d="M87.4 160.5 c-1.9 -1.9 -2.4 -3.4 -2.2 -5.8 0.4 -4.5 3.2 -4.7 7.4 -0.6 3.9 3.8 4.1 4.9 1.6 7.2 -2.5 2.3 -3.9 2.1 -6.8 -0.8z"/>
    <path d="M126.5 158.9 c-6 -3 -10 -7.4 -17 -18.6 -7.6 -12.2 -8.2 -13.8 -5.8 -15.2 2.8 -1.5 7.3 1.8 21.3 15.4 6.9 6.8 13.5 12.6 14.7 12.9 2.7 0.8 3.9 4.2 2.3 6.1 -1.8 2.2 -10.7 1.8 -15.5 -0.6z"/>
    <path d="M36.2 156.7 c-1.5 -1.8 -1.8 -7.8 -0.4 -10.3 1.9 -3.6 3.8 -4.7 6.1 -3.4 1.7 0.9 2.1 2 2.1 6.1 0 2.8 -0.5 5.9 -1 7 -1.2 2.2 -5.2 2.5 -6.8 0.6z"/>
    <path d="M121.5 116 c-0.8 -2.5 1.1 -5.1 3 -4.4 2 0.8 2.7 3.4 1.4 5 -1.7 2 -3.7 1.7 -4.4 -0.6z"/>
    <path d="M4.3 113 c-2.6 -1.1 -2.8 -1.9 -1 -4.4 1.5 -2 7.5 -2.9 9.5 -1.4 1.8 1.5 1.5 4.6 -0.7 5.8 -2.3 1.2 -4.8 1.2 -7.8 0z"/>
    <path d="M32.7 82 c-6.3 -4 -10.3 -9.9 -13.2 -19.4 -2.5 -8.8 -4 -24 -2.7 -29.5 0.9 -4.2 3.4 -6.1 6 -4.5 1.7 1.1 1.9 2 4.6 17.9 1.8 10.8 7.3 22.5 14.1 30.3 2.8 3.1 4.5 5.8 4.1 6.7 -1 2.6 -7.7 1.8 -12.9 -1.5z"/>
    <path d="M133.6 80.4 c-2.1 -2.1 -2 -2.9 0.6 -5.4 2.8 -2.6 6.6 -3.6 8.6 -2.3 2.5 1.5 2.4 2.9 -0.3 6.2 -2.9 3.4 -6.4 4 -8.9 1.5z"/>
    <path d="M93.3 73.3 c-2 -0.8 -1.6 -2.8 2.6 -11.1 7.1 -14.1 10.8 -19.4 22.7 -31.9 9.8 -10.5 12.1 -12.4 14.3 -12.1 1.5 0.2 2.7 1 2.9 2 0.6 3.2 -18 29.9 -29.4 42.1 -6 6.5 -11.1 11.7 -11.4 11.6 -0.3 0 -1.1 -0.3 -1.7 -0.6z"/>
    <path d="M61.7 56.2 c-2.7 -3 -3.3 -7.9 -1.2 -10.2 1 -1.1 2.4 -2 3.1 -2 2.1 0 4.4 4.2 4.4 8 0 5.6 -3.1 7.7 -6.3 4.2z"/>
    <path d="M96.2 18.8 c-4.2 -4.2 4 -19.3 8.8 -16.3 1.8 1.1 1 6.9 -1.7 12.2 -2.6 5.3 -4.7 6.5 -7.1 4.1z"/>
    </g>`

  const div = document.createElement("div")
  div.className = "sidebar-section-link-wrapper"
  div.innerHTML = `
            <a href="https://www.latranchee.com" class="sidebar-section-link sidebar-section-link-everything sidebar-row">
              <span class="sidebar-section-link-prefix icon">
                <svg viewBox="0 0 100 100" class="logoIcon" xmlns="http://www.w3.org/2000/svg">${logo}</svg>
              </span>
              <span class="sidebar-section-link-content-text"> Accueil </span>
            </a>
      `

  const customHeader = document.createElement("div")
  customHeader.className = "sidebar-section-wrapper sidebar-section-community"
  customHeader.innerHTML = `
            <div class="sidebar-section-header-wrapper sidebar-row">
              <button id="ember11" class="sidebar-section-header sidebar-section-header-collapsable btn-flat btn no-text" type="button">
                <span class="sidebar-section-header-text"> Camp d'entraînement </span>
              </button>
          </div>
          <div class="sidebar-section-content" id="customNavigation"></div>
      `

  $(document).ready(function () {
    // Cria os links
    const links = [
      { title: "Accueil", src: "https://www.latranchee.com", svg: logo, viewbox: "0 0 100 100" },
      { title: "Formations", src: "https://www.latranchee.com/formations", svg: mdiSchool, viewbox: "2 -2 16 16" },
      { title: "Blogue", src: "https://www.latranchee.com/blogue", viewbox: "1 -3 16 16", svg: rss },
    ]

    // Mobile
    let hamburger = document.getElementById("toggle-hamburger-menu")
    if (hamburger) {
      hamburger.addEventListener("click", addCustomLinks)
    } else {
      addCustomLinks()
    }
    
    let bool = false;
    function addCustomLinks() {
      setTimeout(function () {
        // Força a esperar até que a navegação tenha sido carregada
        const sidebar = document.getElementsByClassName("sidebar-sections")[0]
        if (sidebar) {
          sidebar.prepend(customHeader)
          if (bool) return;
          // Obtém o ID do customNav
          const customNavigation = document.getElementById("customNavigation")
          if (customNavigation) {
            links.filter(function (link) {
              let linkDiv = document.createElement("div")
              linkDiv.className = "sidebar-section-link-wrapper"
              linkDiv.innerHTML = `<a href="${link.src}" class="sidebar-section-link sidebar-section-link-everything sidebar-row ember-view">
                        <span class="sidebar-section-link-prefix icon" id="link_${link.title}"></span>
                        <span class="sidebar-section-link-content-text"> ${link.title} </span>
                    </a>
                  `
              customNavigation.append(linkDiv)
              let linkIcon = document.getElementById("link_" + link.title)
              if (linkIcon && link.svg) {
                linkIcon.innerHTML = `<svg viewBox="${link.viewbox}" class="logoIcon" xmlns="http://www.w3.org/2000/svg"> ${link.svg}</svg>`
              }
            })
          }
        }
        bool = true
      }, 0)
      
    }
  })
</script>

Espero que isso ajude alguém!

2 curtidas

+1 da minha parte. Um pouco mais de personalização para a barra lateral, como links personalizados ou talvez até mais botões no topo, seria ótimo!

Obrigado por considerar isso, acho que para a base de usuários do meu fórum este é um recurso bastante importante. Os usuários geralmente são péssimos em descobrir até mesmo informações levemente ocultas, e preciso adicionar alguns links proeminentes para coisas como “Contatar administrador” e “Regras do fórum”. Não me importo se eles forem diretamente sob o título Comunidade, mas eles definitivamente não serão descobertos sob o menu Mais. Além disso, a flexibilidade para ter links internos e externos seria importante, links externos estão atualmente quebrados no Menu Hambúrguer Personalizado:

1 curtida

Aqui está outro exemplo que espero que seja útil para alguém, baseado fortemente nos exemplos acima. Este código não adiciona uma seção totalmente nova, mas adiciona links adicionais à parte inferior do painel “Mais” na seção Comunidade (mas antes dos links FAQ e Sobre no rodapé). Ele suporta ícones FontAwesome (assumindo que eles são adicionados nas configurações do site) e links externos. Ele lida com casos extremos onde a barra lateral é fechada e reaberta, e/ou a seção Comunidade é recolhida e expandida novamente. Funciona em desktop e mobile.

Eu não sou um especialista em JavaScript, então peço desculpas por qualquer código ruim ou não otimizado. No meu site, pelo menos, parece funcionar como pretendido.

Basta colocar este código na aba Header de um componente de tema e personalizar conforme necessário:

<script>
const links = [
    // Ícones FontAwesome podem precisar ser adicionados nas configurações do site se não aparecerem corretamente
    { title: "Minha Conta", src: "/my/billing/subscriptions", icon: "file-invoice-dollar" },
    { title: "Diretório de Usuários", src: "/u?asc=true&cards=yes&order=username&period=all", icon: "address-book" },
    { title: "Docs", src: "/docs", icon: "book-reader" },
    { title: "Site Externo", src: "https://google.com/", icon: "globe" }
]

$(document).ready(function () {
    if (document.getElementById("toggle-hamburger-menu")) {
        // Estamos em visualização mobile
        addToggleListener(document.getElementById("toggle-hamburger-menu"))
    } else {
        // Estamos em visualização desktop
        addToggleListener(document.getElementsByClassName("btn-sidebar-toggle")[0])
        addHeaderListener()
        addMoreListener()
    }

    function addToggleListener(toggleEl) {
        if (toggleEl) {
            toggleEl.addEventListener("click", function () {
                // Espere um pouco para a barra lateral carregar
                setTimeout(function() {
                    let sidebar = document.getElementsByClassName("sidebar-section-header").length
                    if (sidebar) {
                        addHeaderListener()
                        addMoreListener()
                    }
                }, 100)
            })
        }
    }

    function addHeaderListener() {
        let communityHeader = document.getElementsByClassName("sidebar-section-header")[0]
        if (communityHeader) {
            communityHeader.addEventListener("click", function () {
                // Espere um pouco para a seção expandir
                setTimeout(function() {
                    let communitySection = document.getElementById("sidebar-section-content-community")
                    if (communitySection) {
                        addMoreListener()
                    }
                }, 100)
            })
        }
    }
    
    function addMoreListener() {
        let buttonMore = document.getElementsByClassName("sidebar-more-section-links-details")[0]
        if (buttonMore) {
            buttonMore.addEventListener("click", addCustomLinks)
        }
    }
    
    function addCustomLinks() {
        // Espere um pouco até a navegação ter sido carregada
        setTimeout(function () {
            const parentEl = document.getElementsByClassName("sidebar-more-section-links-details-content-main")[0]
            let linksAlreadyAdded = document.getElementsByClassName("sidebar-section-custom-link").length
        
            if (parentEl && !linksAlreadyAdded) {
                links.filter(function (link) {
                    let linkDiv = document.createElement("li")
                    let linkTitleTrim = link.title.replace(/\s+/g, '')
                    linkDiv.className = "sidebar-section-link-wrapper sidebar-section-custom-link"
                    linkDiv.innerHTML = `<a href="${link.src}" class="sidebar-section-link sidebar-section-link-everything sidebar-row ember-view">
                            <span class="sidebar-section-link-prefix icon" id="link_${linkTitleTrim}"></span>
                            <span class="sidebar-section-link-content-text"> ${link.title} </span>
                        </a>
                      `
                    parentEl.append(linkDiv)
                    
                    let linkIcon = document.getElementById("link_" + linkTitleTrim)
                    if (linkIcon && link.icon) {
                        linkIcon.innerHTML = `<svg viewBox="0 0 640 512" class="fa d-icon svg-icon prefix-icon svg-string d-icon-${link.icon}" xmlns="http://www.w3.org/2000/svg">
                                <use xlink:href="#${link.icon}"></use>
                            </svg>
                        `
                    }
                })
            }
        }, 100)
    }
})
</script>
4 curtidas

@Ryan_Hyer Muito bom! Você descobriu a maneira de fazer os itens aparecerem (ou continuarem aparecendo) após o evento de alternância do hambúrguer, que era o problema que eu estava tendo aqui:

Seu código também é muito organizado e limpo. Graças a isso, consegui adaptá-lo para exibir o que eu queria no menu Comunidade sem que ficasse escondido em Mais:

Cabeçalho:

<script>

const links = [
    // Ícones do FontAwesome podem precisar ser adicionados nas configurações do site se não aparecerem corretamente
    { title: "Diretório de Usuários", src: "/u?asc=true&cards=yes&order=username&period=all", icon: "address-book" },
    { title: "Documentos", src: "/docs", icon: "book-reader" },
    { title: "Site Externo", src: "https://google.com/", icon: "globe" }
]

$(document).ready(function () {
    if (document.getElementById("toggle-hamburger-menu")) {
        // Estamos na visualização móvel
        addToggleListener(document.getElementById("toggle-hamburger-menu"))
    } else {
        // Estamos na visualização desktop
        addToggleListener(document.getElementsByClassName("btn-sidebar-toggle")[0])
        addCustomLinks()
    }

    function addToggleListener(toggleEl) {
        if (toggleEl) {
            toggleEl.addEventListener("click", function () {
                // Espere um pouco para a barra lateral carregar
                setTimeout(function() {
                    let sidebar = document.getElementsByClassName("sidebar-section-header").length
                    if (sidebar) {
                        addCustomLinks()
                    }
                }, 100)
            })
        }
    }
    
    function addCustomLinks() {
        // Espere um pouco até que a navegação seja carregada
        setTimeout(function () {
            const parentEl = document.getElementsByClassName("sidebar-section-content")[0]
            let linksAlreadyAdded = document.getElementsByClassName("sidebar-section-custom-link").length
        
            if (parentEl && !linksAlreadyAdded) {
                links.filter(function (link) {
                    let linkDiv = document.createElement("li")
                    let linkTitleTrim = link.title.replace(/\s+/g, '')
                    linkDiv.className = "sidebar-section-link-wrapper sidebar-section-custom-link"
                    linkDiv.innerHTML = `<a href="${link.src}" class="sidebar-section-link sidebar-section-link-everything sidebar-row ember-view">
                            <span class="sidebar-section-link-prefix icon" id="link_${linkTitleTrim}"></span>
                            <span class="sidebar-section-link-content-text"> ${link.title} </span>
                        </a>
                      `
                    parentEl.append(linkDiv)
                    
                    let linkIcon = document.getElementById("link_" + linkTitleTrim)
                    if (linkIcon && link.icon) {
                        linkIcon.innerHTML = `<svg viewBox="0 0 640 512" class="fa d-icon svg-icon prefix-icon svg-string d-icon-${link.icon}" xmlns="http://www.w3.org/2000/svg">
                                <use xlink:href="#${link.icon}">
                            </use>
                        </svg>
                        `
                    }
                })
            }
        }, 100)
    }
})
</script>

E o CSS complementar:

.sidebar-section-content {
  display: flex; /* Configura um layout flexível para que você possa reordenar as coisas */
  flex-direction: column;
  .sidebar-more-section-links-details {
    order: +1;
  }
}

.sidebar-wrapper li a.sidebar-section-link-about {
    display: none;
}

.sidebar-wrapper li a.sidebar-section-link-faq {
    display: none;
}

.sidebar-more-section-links-details-content-secondary .sidebar-section-link.sidebar-section-link-about {
    display: none;
}

.sidebar-more-section-links-details-content-secondary .sidebar-section-link.sidebar-section-link-faq {
    display: none;
}
2 curtidas

Só quero chamar sua atenção para este tópico que acabou de sair:

Por favor, forneça feedback nesse tópico!

6 curtidas

Este tópico foi automaticamente fechado após 42 horas. Novas respostas não são mais permitidas.