Capacidad para agregar una sección personalizada de enlaces en la barra lateral

Queremos permitir que los usuarios agreguen una sección personalizada de enlaces a su barra lateral.

En una primera pasada para esta función, planeamos basarnos en la página de preferencias de la barra lateral existente y permitir a un usuario agregar una única sección personalizada para estos enlaces.

Creemos que puede funcionar algo así:

  1. casilla de verificación para “Mostrar sección personalizada”.
    Si se marca, la Sección personalizada aparece encima de la Sección de categorías y los valores deben tener un Nombre válido y al menos un Enlace válido para “Guardar cambios”.
  2. cuadro de texto para el Nombre de la sección personalizada (predeterminado: Mis enlaces, no puede estar en blanco).
  3. botón para “Agregar enlace”. al hacer clic, se muestra el diálogo para agregar el enlace.
  4. Los enlaces agregados muestran un botón para eliminarlo.

Diálogo para agregar enlace

  1. El diálogo para agregar enlace tiene dos cuadros de texto: Nombre, URL.
  2. El Nombre no puede estar en blanco, puede incluir emojis (que deberían renderizarse en la barra lateral).
  3. La URL debe ser un enlace dentro del mismo sitio de Discourse*.
  4. Guardar agrega el enlace, Cancelar lo descarta.

Cuando se configura y guarda una sección personalizada válida, la barra lateral mostrará esa sección encima de “Categorías”.

* ¿Por qué?

  1. Nos gustaría poder “resaltar”/“poner en negrita” el enlace en la barra lateral cuando te encuentras en la página correspondiente.
  2. Nos gustaría almacenar la parte del “ruta”, para que los cambios de nombre del sitio funcionen como se espera.

Creemos que agregar enlaces hoy será valioso porque permitirá a las personas acceder fácilmente a cosas como “Errores abiertos de la barra lateral” y nos permitirá aprovechar cualquier mejora futura para las listas de temas, como filtros mejorados para listas de temas. Siempre que las cosas tengan una URL, las personas podrán agregarlas a su barra lateral.

Creemos que los usuarios querrán poder agregar múltiples secciones y reordenarlas, pero inicialmente lo mantendremos fuera del alcance.

16 Me gusta

Una pregunta sobre esto, @mcwumbly. Esto parece una estrategia para permitir que un usuario agregue enlaces personales a la barra lateral. ¿Permitiría este enfoque que los propietarios del sitio agreguen enlaces que todos los usuarios verían?

Spoiler: Creo que debería. :slight_smile:

5 Me gusta

Sí, creo que ciertamente podría ampliarse para hacer algo así, y veo cómo sería una característica más útil para algunos sitios que la del usuario.

8 Me gusta

Me gusta mucho esta idea. :+1:

Solo algunas preguntas:

  1. ¿Habrá un límite en la cantidad de enlaces personalizados que un usuario podrá agregar?

  2. ¿Se truncarán los extremos de los enlaces (en la barra lateral) como en la siguiente maqueta? (Estaría bien para mí).
    Y si es así, ¿podrá el usuario leer el texto completo en una información sobre herramientas (si el cursor del ratón se detiene sobre los enlaces)?

Buena pregunta. Probablemente necesitemos establecer algunos límites, pero no es algo que hayamos discutido en detalle. ¿Qué tipo de límites esperas ver (o evitar)?

1 me gusta

Al principio, pensé que 10 enlaces serían suficientes, pero supongo que otros miembros del foro querrán más. Quizás 20. Por eso, intentaría con 20 y esperaría los comentarios de los usuarios para ver si piden más (pero creo que 20 ya es un buen número).

1 me gusta

Para ampliar la “facilidad de uso” de esta función, sería genial permitir al usuario arrastrar y soltar enlaces (cualquier enlace de la página actual de Discourse) directamente en la barra lateral.

Un puntero (entre los enlaces que se agregaron previamente al DIV “Mis enlaces”) indicaría dónde se colocaría el enlace.

Maqueta (clic derecho > “abrir imagen en una pestaña nueva” para ver la animación a tamaño completo):

anim01

¿Quizás la siguiente página podría ayudar a implementar el arrastrar y soltar?

7 Me gusta

Me encantaría poder establecer enlaces predeterminados para mi sitio, que los usuarios pudieran descartar. Eso lo haría estrictamente mejor que los enlaces de encabezado personalizados que estoy usando ahora, según mi punto de vista.

3 Me gusta

+1 en la adición de enlaces personalizados. Teníamos algunos enlaces personalizados añadidos al menú desplegable original. Sería bueno añadirlos de nuevo, de forma similar a como Discourse tiene “Cumpleaños” y “Documentos” bajo la opción “Más”.

4 Me gusta

¡Hola a todos!

Me pregunto cómo podría agregar enlaces a la nueva barra lateral.

No parece haber ningún conector en esa área…

¿Cuál sería la forma más efectiva de hacerlo?


Editar

Mi pregunta se ha trasladado aquí… No estoy seguro de por qué, ya que realmente estoy preguntando sobre lo mismo.

En cualquier caso, aquí está lo que hice para resolverlo. NO es una solución elegante y sería mucho mejor si hubiera una forma de integrarlo con el sistema de plantillas de Discourse.

Aquí va:

<script>
    let logo = "" // He eliminado las rutas SVG porque no las necesitan.
    const div = document.createElement('div') // Crear el enlace a agregar
    div.className = 'sidebar-section-link-wrapper' // agregar las clases relevantes
    div.innerHTML = `
          <a title="Tous les sujets" 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>
    ` // Rellenar el enlace
    
    $( document ).ready(() => { // Esto es necesario para esperar hasta que Ember haya terminado su trabajo
        // agregar navegación en el escritorio
        let desktop = document.getElementsByClassName('sidebar-section-content')[0];
        if(desktop) desktop.prepend(div)
        
        // agregar navegación en el móvil
        let hamburger = document.getElementById('toggle-hamburger-menu').addEventListener("click", addMobileNav);
        function addMobileNav () {
            setTimeout(function(){ // Forzar a esperar hasta que la navegación se haya cargado
                document.getElementsByClassName('sidebar-section-content')[0].prepend(div);
            }, 0);
        }
    })
</script>

Resultado en el escritorio…

Y resultado en el móvil:

¡Hasta que haya una mejor manera, esto tendrá que servir!

Editar #2

He ordenado el código para que las navegaciones se carguen desde una matriz 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 () {
    // Crear los enlaces
    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 },
    ]

    // Móvil
    let hamburger = document.getElementById("toggle-hamburger-menu")
    if (hamburger) {
      hamburger.addEventListener("click", addCustomLinks)
    } else {
      addCustomLinks()
    }
    
    let bool = false;
    function addCustomLinks() {
      setTimeout(function () {
        // Forzar a esperar hasta que la navegación se haya cargado
        const sidebar = document.getElementsByClassName("sidebar-sections")[0]
        if (sidebar) {
          sidebar.prepend(customHeader)
          if (bool) return;
          // Obtener el ID de 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 esto pueda ayudar a alguien!

2 Me gusta

+1 de mi parte. ¡Un poco más de personalización para la barra lateral, como enlaces personalizados o incluso más botones en la parte superior, sería genial!

Gracias por considerarlo, creo que para la base de usuarios de mi foro esta es una característica bastante importante. Los usuarios suelen ser terribles para descubrir incluso información ligeramente oculta, y necesito agregar algunos enlaces prominentes para cosas como “Contactar administrador” y “Reglas del foro”. No me importa si van directamente debajo del encabezado Comunidad, pero definitivamente no serán descubiertos en el menú Más. Además, la flexibilidad para tener enlaces internos y externos sería importante, los enlaces externos actualmente están rotos en el Menú Hamburguesa Personalizado:

1 me gusta

Aquí tienes otro ejemplo que espero sea útil para alguien, basado en gran medida en los ejemplos anteriores. Este código no añade una sección completamente nueva, sino que añade enlaces adicionales al final del panel “Más” en la sección Comunidad (pero antes de los enlaces de FAQ y Acerca de en el pie de página). Soporta iconos de FontAwesome (asumiendo que se añaden en la configuración del sitio) y enlaces externos. Maneja casos extremos donde la barra lateral se cierra y se vuelve a abrir, y/o la sección Comunidad se colapsa y se expande de nuevo. Funciona en escritorio y móvil.

Apenas soy un experto en JavaScript, así que me disculpo por cualquier código malo o no óptimo. En mi sitio, al menos, parece funcionar como se esperaba.

Simplemente coloca este código en la pestaña Encabezado de un componente de tema y personalízalo según sea necesario:

<script>
const links = [
    // Es posible que los iconos de FontAwesome deban añadirse en la configuración del sitio si no aparecen correctamente
    { title: "Mi Cuenta", src: "/my/billing/subscriptions", icon: "file-invoice-dollar" },
    { title: "Directorio de Usuarios", src: "/u?asc=true&cards=yes&order=username&period=all", icon: "address-book" },
    { title: "Documentos", src: "/docs", icon: "book-reader" },
    { title: "Sitio Externo", src: "https://google.com/", icon: "globe" }
]

$(document).ready(function () {
    if (document.getElementById("toggle-hamburger-menu")) {
        // Estamos en vista móvil
        addToggleListener(document.getElementById("toggle-hamburger-menu"))
    } else {
        // Estamos en vista de escritorio
        addToggleListener(document.getElementsByClassName("btn-sidebar-toggle")[0])
        addHeaderListener()
        addMoreListener()
    }

    function addToggleListener(toggleEl) {
        if (toggleEl) {
            toggleEl.addEventListener("click", function () {
                // Espera un poco a que se cargue la barra lateral
                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 () {
                // Espera un poco a que la sección se expanda
                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() {
        // Espera un poco hasta que se cargue la navegación
        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 Me gusta

@Ryan_Hyer ¡Muy bien! Descubriste la forma de hacer que los elementos aparezcan (o sigan apareciendo) después del evento de alternancia de la hamburguesa, que era el problema que estaba teniendo aquí:

Tu código también es muy ordenado y limpio. Gracias a eso, pude adaptarlo para que muestre lo que quiero en el menú de Comunidad sin que quede oculto bajo “Más”:

Encabezado:

<script>

const links = [
    // Es posible que los iconos de FontAwesome deban agregarse en la configuración del sitio si no aparecen correctamente
    { title: "Directorio de usuarios", src: "/u?asc=true&cards=yes&order=username&period=all", icon: "address-book" },
    { title: "Documentos", src: "/docs", icon: "book-reader" },
    { title: "Sitio externo", src: "https://google.com/", icon: "globe" }
]

$(document).ready(function () {
    if (document.getElementById("toggle-hamburger-menu")) {
        // Estamos en vista móvil
        addToggleListener(document.getElementById("toggle-hamburger-menu"))
    } else {
        // Estamos en vista de escritorio
        addToggleListener(document.getElementsByClassName("btn-sidebar-toggle")[0])
        addCustomLinks()
    }

    function addToggleListener(toggleEl) {
        if (toggleEl) {
            toggleEl.addEventListener("click", function () {
                // Espera un poco a que se cargue la barra lateral
                setTimeout(function() {
                    let sidebar = document.getElementsByClassName("sidebar-section-header").length
                    if (sidebar) {
                        addCustomLinks()
                    }
                }, 100)
            })
        }
    }
    
    function addCustomLinks() {
        // Espera un poco hasta que se cargue la navegación
        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>

Y el CSS complementario:

.sidebar-section-content {
  display: flex; /* Configura un diseño flexible para que puedas reordenar las cosas */
  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 Me gusta

Solo quiero llamar su atención sobre este tema que acaba de salir:

¡Por favor, den su opinión en ese tema!

6 Me gusta

Este tema se cerró automáticamente después de 42 horas. Ya no se permiten nuevas respuestas.