Zum Inhalt springen
Astrid

Navigation als Bootstratp 5 Akkordeon in Cassiopeia

Wer mit Bootstrap vertraut ist und die Navigation als Akkordeon anpassen möchte, kann dies unkompliziert erledigen. Cassiopia ist ein Bootstrap 5 Template. So kann es Bootstrap Komponenten verwenden.

Ich habe ein Override erstellt, welches die wesentlichen Bootstrap Klassen und Attribute ergänzt, um die Navigation in einer Seitenleiste vertikal als Akkordeon anzuzeigen.

Die Bootstrap Dokumentation findest du unter der Adresse getbootstrap.com/docs[^https://getbootstrap.com/docs/].

Wie das Akkordeon aussehen soll, zeigt die linke Seitenleiste.

Override anlegen

Anlegen müssen wir lediglich eine Datei. Die Datei /templates/cassiopeia/html/mod_menu/akkordeon.php, wenn man Cassiopeia verwendet. Die Datei /templates/cassiopeia_child_name/html/mod_menu/akkordeon.php, wenn man ein Child von Cassiopeia angelegt hat.

/templates/cassiopeia_yourchild/html/mod_menu/akkordeon.php

Der Code kann über den Template-Manager eingefügt werden.

<?php
defined('_JEXEC') or die;

use Joomla\CMS\Helper\ModuleHelper;

$wa = $app->getDocument()->getWebAssetManager();
$wa->useScript('bootstrap.collapse');

$id = '';
$unique = uniqid();

if ($tagId = $params->get('tag_id', '')) {
    $id = ' id="' . $tagId . '"';
} else {
    $id = ' id="accordion' . $unique . '"';
}
?>

<div class="accordion" id="<?php echo $id ?>">

    <?php foreach ($list as $i => &$item) : ?>



    <?php
    $itemParams = $item->getParams();
    $class = 'nav-item item-' . $item->id;

    if ($item->id == $default_id) {
        $class .= ' default';
    }

    if ($item->id == $active_id || ($item->type === 'alias' && $itemParams->get('aliasoptions') == $active_id)) {
        $class .= ' current';
    }

    if (in_array($item->id, $path)) {
        $class .= ' active';
    } elseif ($item->type === 'alias') {
        $aliasToId = $itemParams->get('aliasoptions');

        if (count($path) > 0 && $aliasToId == $path[count($path) - 1]) {
            $class .= ' active';
        } elseif (in_array($aliasToId, $path)) {
            $class .= ' alias-parent-active';
        }
    }

    if ($item->type === 'separator') {
        $class .= ' divider';
    }

    if ($item->deeper) {
        $class .= ' deeper';
    }

    if ($item->parent) {
        $class .= ' parent';
    }

    if ($item->shallower) {
        $class .= ' shallower';
    }

?>

    <?php if ($item->deeper) : ?>
    <div class="accordion-item">
        <h2 class="accordion-header" id="panelsStayOpen-heading<?php echo $item->id . $i ?>">
            <button class="accordion-button" type="button" data-bs-toggle="collapse"
                data-bs-target="#panelsStayOpen-collapse<?php echo $item->id . $i ?>" aria-expanded="true"
                aria-controls="panelsStayOpen-collapse<?php echo $item->id . $i ?>">
                <?php echo $item->title ?>
            </button>
        </h2>
        <div id="panelsStayOpen-collapse<?php echo $item->id . $i ?>" class="accordion-collapse collapse noshow"
            aria-labelledby="panelsStayOpen-heading<?php echo $item->id . $i ?>">
            <div class="accordion-body">
                <?php endif; ?>


                <?php if ($item->shallower): ?>
                <div class="accordion-item">
                    <h2 class="accordion-header">
                        <button class="accordion-button accordion-button-fake" type="button">
                            <?php 
                            switch ($item->type) :
                                case 'separator':
                                case 'component':
                                case 'url':
                                    require ModuleHelper::getLayoutPath('mod_menu', 'default_' . $item->type);
                                    break;
                                case 'heading':
                                    break;
                            
                                default:
                                    require ModuleHelper::getLayoutPath('mod_menu', 'default_url');
                                    break;
                            endswitch;
                            ?>
                        </button>
                    </h2>
                </div>
            </div>
        </div>
    </div>

    <?php endif; ?>

    <?php if (!$item->shallower && !$item->deeper): ?>
    <div class="accordion-item">
        <h2 class="accordion-header">
            <button class="accordion-button accordion-button-fake" type="button">
                <?php 
                    switch ($item->type) :
                        case 'separator':
                        case 'component':
                        case 'url':
                            require ModuleHelper::getLayoutPath('mod_menu', 'default_' . $item->type);
                            break;
                        case 'heading':
                            break;
                    
                        default:
                            require ModuleHelper::getLayoutPath('mod_menu', 'default_url');
                            break;
                    endswitch;
                    ?>
            </button>
        </h2>
    </div>
    <?php endif; ?>


    <?php endforeach; ?>
</div>

<script>
document.addEventListener("DOMContentLoaded", function() {
  var collapses = document.querySelectorAll(".collapse");

  function handleCollapseShow() {
    localStorage.setItem("coll_" + this.id, true);
  }

  function handleCollapseHide() {
    localStorage.removeItem("coll_" + this.id);
  }

  function checkCollapseState() {
    var id = this.id;
    var storedState = localStorage.getItem("coll_" + id);

    if (storedState === "true") {
      this.classList.add("show");
    } else {
      this.classList.remove("show");
    }
  }

  Array.from(collapses).forEach(function(collapse) {
    collapse.addEventListener("shown.bs.collapse", handleCollapseShow);
    collapse.addEventListener("hidden.bs.collapse", handleCollapseHide);
    checkCollapseState.call(collapse);
  });
});
</script>

Das Skript am Ende der PHP-Datei ist optional. Du brauchst es nur, wenn du den Zustand des Akkordeons speichern willst. Ohne den JavaScript-Code wird das Akkordeon nach dem Klicken auf einen Menüpunkt immer vollständig geöffnet angezeigt. Das Skript sorgt dafür, dass sich der Browser merkt, welche Bereiche des Akkordeons geöffnet und welche geschlossen sind.

Override auswählen

Last but not least ist erforderlich im Modul des Menüs das Layout für das Akkordeon auszuwählen und die gewünschte Position festzulegen.

Das Layout des Overrides wird im Module-Manager aktiviert.