menu design

WordPress benzeri, iç içe geçebilen (nested) menüler yapmak için en temiz yöntem SortableJS kütüphanesini kullanmaktır. jQuery bağımlılığı yoktur (Vanilla JS ile çalışır) ancak jQuery ile de kolayca entegre olur.

1. Frontend: SortableJS ile Menü Yönetimi

Önce CDN üzerinden gerekli kütüphaneyi HTML’ine ekle:

<script src="https://raw.githack.com/SortableJS/Sortable/master/Sortable.js"></script>

HTML Yapısı:

<ul id="menu-list" class="menu-container">
    <li data-id="1">Anasayfa</li>
    <li data-id="2">Hakkımızda
        <ul class="nested-menu">
            <li data-id="3">Ekibimiz</li>
        </ul>
    </li>
    <li data-id="4">İletişim</li>
</ul>

<button id="save-menu">Menüyü Kaydet</button>

JavaScript:

new Sortable(document.getElementById('menu-list'), {
    group: 'nested',
    animation: 150,
    fallbackOnBody: true,
    swapThreshold: 0.65
});

document.getElementById('save-menu').addEventListener('click', () => {
    // Tüm listeyi serialize et ve Go backend'e gönder
    const data = getOrder(document.getElementById('menu-list'));
    fetch('/api/menu/save', {
        method: 'POST',
        body: JSON.stringify(data),
        headers: {'Content-Type': 'application/json'}
    });
});

2. Backend: Go (Fiber) Skeleton

Veritabanında menüleri id, parent_id ve order sütunları ile tutman yeterlidir. Go tarafında gelen veriyi karşılayacak ve kaydedecek yapıyı kuralım.

Model (GORM):

type MenuItem struct {
    ID       uint   `json:"id"`
    ParentID uint   `json:"parent_id"`
    Title    string `json:"title"`
    Order    int    `json:"order"`
}

API Handler (Fiber):

package main

import (
    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()

    app.Post("/api/menu/save", func(c *fiber.Ctx) error {
        var menuItems []MenuItem
        if err := c.BodyParser(&menuItems); err != nil {
            return c.Status(400).JSON(fiber.Map{"error": "Geçersiz veri"})
        }

        // Veritabanı işlemi:
        // 1. Transaction başlat (db.Begin())
        // 2. Mevcut menüyü temizle veya update et
        // 3. Gelen yeni sıralamayı döngüyle veritabanına işle

        return c.JSON(fiber.Map{"status": "success"})
    })

    app.Listen(":3000")
}

Kritik İpuçları:

  1. Serialization: SortableJS ile iç içe listeleri çekerken nested yapıyı korumak için sortable.toArray() yerine her li elemanının verisini (id ve parent) manuel olarak bir map içinde toplamanı öneririm.
  2. Veritabanı: PostgreSQL kullanıyorsan, menüleri getirmek için WITH RECURSIVE sorgusunu bir “view” olarak tanımlarsan, Go tarafından menüyü çekmek tek bir satır sürer.
  3. Güvenlik: Menü kaydetme endpoint’ine mutlaka bir Auth Middleware ekle ki herkes menüleri değiştiremesin.

Bu skeleton üzerinden ilerleyerek, sortable.toArray() fonksiyonunun döndürdüğü veriyi JSON olarak backend’e nasıl parse edeceğin konusunda bir örneğe ihtiyaç duyarsan detaylandırabilirim. Hangi veritabanı kütüphanesini (GORM, sqlx vb.) kullanıyorsun?