Dinamik-Envanter-Butonlu_Dashboard

Dosya seçtikten sonra, Tablo başlıkların göre içeri aktarım gerçekleşir. Sütun başlıklarından ihtiyaç olanın harflerini "Veri Dilimleyici Ekle:" penceresine "," ler ile yazıp "Ör: a,b,d" "+ Buton Oluştur" basın.

Butonlara basarak filtreleme işlemlerini gerçekleştirebilirmisiniz.

Butonlar basınca, filtre içinde filtre gerçekleşir. Filtre başlığında yer alan "kaldır    linkine basınca ilgili başlığı kaldırabilir veya "Tüm filtreleri temizle" butonuna basarak filtreleri kaldırabilirsiniz.

Yazdırabilir, PDF olarak kaydedebilirsiniz.

Raporlama ve Analiz. Bu iki kavram etkin rapor sunmayla varlığını sürdürmektedir. Bu aşamada ise en önemli kısım hızdır. Farklı listeler üzerinde analizler söz konusu olduğunda, elimde bir tool olsa oradan hızlıca filtreleyip hızlıca sonuca varabilsem düşüncesinin bir sonucu olarak ortaya çıkan bir ürün.

HTML kod olarak hazırlanan çalışma, sayfa sonunda yer almaktadır. Bir not defteri açıp kodu not alanına yapıştırın. Dosya ismi verip, uzantıyı ".html" olarak kaydetmeniz yeterli. sonrasında, çift tıklayarak çalıştırın.

Aşağıda uygulamanın çalışmış hali görünmektedir. Helpdesk biriminin Envanterini görüntüleyip analiz etmek istiyoruz. Sayfanın sonunda bir logo yer almakta. Kurumunuzun logosunu "logo.jpg" dosya ismiyle html dosyasının bulunduğu alanda yer alması ile logo belirir. "Envanter,  Helpdesk Koordinatörlüğü, MYO MÜDÜRLÜĞÜ" ifadelerini, Kod üzerinde Not defteri ile açıp "Ctrl+F" ile bulup değiştirip kaydetmek suretiyle, kendinize göre uyarlayabilirsiniz.

Başlık alanında orta kısımda, tablodaki toplam satır sayısı, filtre durumunda bulunan sonuca göre oranı ve bulunan filtre adeti bu alana yansımaktadır. dosya seç ile Excel dosyanızı içeri aktarabilirsiniz. (Excel dosyasının tablosu köşelere yanaşık ve boşluk olmadan yer almalı) Filtreleme sonrası, Filtrelenen Excel dosyasını indirebilir ve PDF olarak kaydedebilir yazdırabilirsiniz.

Başlıklara göre, Veri dilimleyici ekleyebilir (Filtre içinde filtre seçimi ile) hızla sonuca ulaşabilir. "Tüm Filtreleri Temizle" butonuna basarak filtreleri kaldırabilirsiniz. Başlıklara tıklayarak (A-Z veya Z-A) sıralama yapabilir, her başlık üzerindeki arama penceresini kullanarak arama yapabilirsiniz. 

 
HTML Kod:

<!DOCTYPE html>

<html lang="tr">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width,initial-scale=1">

    <title>Envanter Sistemi</title>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>


    <style>

        /* --- TEMEL DEĞİŞKENLER VE SIFIRLAMALAR --- */

        :root {

            --bg: #f0f2f5;

            --shadow: 0 8px 24px rgba(0,0,0,.05);

            --radius: 10px;

        }

        * { 

            margin: 0; 

            padding: 0; 

            box-sizing: border-box; 

            font-family: "Segoe UI", system-ui, Arial, sans-serif; 

        }

        body { 

            background: var(--bg); 

            padding: 20px; 

        }


        /* --- ORTAK SABİT ALAN (BAŞLIK + ARAMA) --- */

        .sticky-container {

            position: sticky;

            top: 20px;

            z-index: 1000;

            margin-bottom: 20px;

        }

        .sticky-container::before {

            content: "";

            position: absolute;

            top: -20px; 

            left: -20px;

            right: -20px;

            bottom: -10px; 

            background: var(--bg);

            z-index: -1;

        }


        /* --- BAŞLIK ALANI STİLLERİ --- */

        .header { 

            display: flex; 

            justify-content: space-between; 

            align-items: center; 

            padding: 15px 20px; 

            background: #fff; 

            border: 1px solid #e1e4e8; 

            border-radius: var(--radius); 

            box-shadow: 0 4px 20px rgba(0,0,0,0.06); 

            margin-bottom: 15px; 

            gap: 15px;

        }

        .header .left { 

            display: flex; 

            align-items: center; 

            gap: 15px; 

            width: 30%;

        }

        .header .logo img { 

            height: 50px; 

        }

        .header .title1 { 

            font-size: 22px; 

            font-weight: 800; 

            color: #1a1e23; 

            letter-spacing: -0.5px;

        }

        .header .title2 { 

            font-size: 12px; 

            color: #6a737d; 

            font-weight: 600; 

            text-transform: uppercase;

            letter-spacing: 0.5px;

        }

        

        /* --- ESTETİK VE TEKNOLOJİK GRAFİK BÖLÜMÜ (HUD STİLİ) --- */

        .header .center-title { 

            flex-grow: 1; 

            display: flex;

            justify-content: center;

        }

        

        .gauges-wrapper {

            display: flex;

            gap: 30px;

            background: #fafbfc;

            border: 1px solid #eef0f3;

            padding: 12px 30px;

            border-radius: 50px;

            box-shadow: inset 0 2px 4px rgba(0,0,0,0.02), 0 4px 10px rgba(0,0,0,0.03);

        }


        .tech-gauge {

            display: flex;

            flex-direction: column;

            align-items: center;

            width: 100px;

            position: relative;

        }

        

        .tg-label {

            font-size: 11px;

            font-weight: 800;

            color: #586069;

            text-transform: uppercase;

            letter-spacing: 1px;

            margin-bottom: -2px;

            display: flex;

            align-items: center;

            gap: 5px;

            white-space: nowrap;

        }


        .tg-label.total::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: #00c6ff; box-shadow: 0 0 6px #00c6ff; }

        .tg-label.percent::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: #ff416c; box-shadow: 0 0 6px #ff416c; }

        .tg-label.filtered::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: #11998e; box-shadow: 0 0 6px #11998e; }


        .tech-gauge svg {

            width: 100%;

            overflow: visible;

            filter: drop-shadow(0px 4px 4px rgba(0,0,0,0.1));

        }

        

        .tg-value {

            font-size: 22px;

            font-weight: 900;

            fill: #24292e;

            font-family: "Courier New", Courier, monospace;

        }


        .header .right { 

            width: 30%;

            font-size: 13px; 

            font-weight: 800; 

            text-align: right; 

            color: #24292e; 

            letter-spacing: 0.5px;

        }


        /* --- KONTROL & DOSYA YÜKLEME PANELİ --- */

        .controls {

            display: flex;

            gap: 15px;

            align-items: center;

            background: #fff;

            padding: 15px;

            border-radius: var(--radius);

            box-shadow: var(--shadow);

            border-left: 5px solid #00c6ff;

            flex-wrap: wrap;

        }

        input[type="file"], button, select {

            padding: 8px 15px;

            border: 1px solid #d1d5da;

            border-radius: 6px;

            font-size: 13px;

            outline: none;

        }

        input[type="file"]:focus, select:focus { border-color: #00c6ff; }

        

        /* --- GENEL ARAMA (GLOBAL SEARCH) ALANI --- */

        .search-container {

            display: flex;

            flex-grow: 1;

            align-items: center;

            gap: 10px;

            margin: 0 15px;

        }

        

        #globalSearch {

            flex-grow: 1;

            margin: 0;

            padding: 10px 15px;

            border-radius: 6px;

            font-size: 14px;

            outline: none;

            transition: border-color 0.2s, box-shadow 0.2s;

            border: 1px solid #00c6ff;

            box-shadow: 0 0 0 3px rgba(0, 198, 255, 0.15);

        }

        #globalSearch::placeholder {

            color: #b0b3b8;

        }


        .btn-primary {

            background: linear-gradient(135deg, #007bff, #0056b3);

            color: white; border: none; cursor: pointer; font-weight: bold; transition: 0.3s;

            box-shadow: 0 4px 10px rgba(0, 123, 255, 0.3);

        }

        .btn-primary:hover { box-shadow: 0 6px 15px rgba(0, 123, 255, 0.5); transform: translateY(-1px); }

        

        .btn-danger {

            background: linear-gradient(135deg, #dc3545, #a71d2a);

            color: white; border: none; cursor: pointer; font-weight: bold; transition: 0.3s;

            box-shadow: 0 4px 10px rgba(220, 53, 69, 0.3);

        }

        .btn-danger:hover { box-shadow: 0 6px 15px rgba(220, 53, 69, 0.5); transform: translateY(-1px); }


        .btn-success {

            background: linear-gradient(135deg, #28a745, #218838);

            color: white; border: none; cursor: pointer; font-weight: bold; transition: 0.3s;

            box-shadow: 0 4px 10px rgba(40, 167, 69, 0.3);

        }

        .btn-success:hover { box-shadow: 0 6px 15px rgba(40, 167, 69, 0.5); transform: translateY(-1px); }


        .btn-secondary {

            background: linear-gradient(135deg, #e1e4e8, #d1d5da);

            color: #24292e; border: none; cursor: pointer; font-weight: bold; transition: 0.3s;

            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);

        }

        .btn-secondary:hover { box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15); transform: translateY(-1px); }


        progress { width: 150px; height: 18px; display: none; border-radius: 10px; }

        progress::-webkit-progress-bar { background-color: #f0f2f5; border-radius: 10px; }

        progress::-webkit-progress-value { background: linear-gradient(90deg, #00c6ff, #0072ff); border-radius: 10px; }


        /* --- EXCEL SEKMELERİ (TABS) STİLLERİ --- */

        .sheet-tabs-container {

            width: 100%;

            display: flex;

            gap: 8px;

            margin-top: 10px;

            overflow-x: auto;

            padding-bottom: 5px;

        }

        .sheet-tab-btn {

            background: #f8f9fc;

            color: #007bff;

            border: 1px solid #cce5ff;

            padding: 6px 16px;

            border-radius: 20px;

            cursor: pointer;

            font-size: 13px;

            font-weight: 700;

            transition: all 0.3s ease;

            white-space: nowrap;

        }

        .sheet-tab-btn:hover {

            background: #e6f2ff;

            border-color: #007bff;

        }

        .sheet-tab-btn.active {

            background: linear-gradient(135deg, #007bff, #0056b3);

            color: #fff;

            border-color: transparent;

            box-shadow: 0 4px 10px rgba(0, 123, 255, 0.3);

        }


        /* --- VERİ DİLİMLEYİCİ VE BİLEŞEN STİLLERİ --- */

        .slicer-container {

            background: #f8f9fc; 

            padding: 20px;

            border-radius: var(--radius);

            box-shadow: var(--shadow);

            margin-bottom: 20px;

            border: 1px solid #e1e4e8;

        }

        .slicer-header-bar {

            display: flex;

            align-items: center;

            gap: 15px;

            flex-wrap: wrap;

        }

        .slicer-header-bar span.slicer-title-label { 

            font-weight: 800; 

            color: #0056b3; 

            font-size: 14px; 

        }


        .slicer-input-wrapper {

            display: flex;

            align-items: center;

            gap: 10px;

        }

        .slicer-input {

            padding: 8px 14px;

            border: 1px solid #cce5ff;

            border-radius: 6px;

            font-size: 13px;

            outline: none;

            width: 280px;

            background: #ffffff;

            transition: all 0.2s ease;

        }

        .slicer-input:focus {

            border-color: #007bff;

            box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.15);

        }

        .slicer-input::placeholder {

            color: #adb5bd;

            font-style: italic;

        }


        .slicer-area-rows {

            display: flex;

            flex-direction: column;

            gap: 12px;

            margin-top: 15px;

        }


        .slicer-row {

            display: flex;

            align-items: flex-start;

            background: #ffffff;

            border: 1px solid #e1e4e8;

            border-radius: 10px;

            padding: 15px 18px;

            box-shadow: 0 2px 8px rgba(0,0,0,0.03);

            gap: 20px;

        }


        /* YENİ BAŞLIK VE İSTATİSTİK BÖLÜMÜ GÖRÜNÜMÜ */

        .slicer-row-header {

            min-width: 250px;

            flex-shrink: 0;

            display: flex;

            flex-direction: column;

            gap: 6px;

            border-right: 2px solid #f0f2f5;

            padding-right: 15px;

            margin-top: 2px;

        }


        .slicer-row-title {

            font-size: 16px;

            font-weight: 800;

            color: #1a1e23;

            letter-spacing: -0.2px;

        }


        .slicer-row-stats {

            font-size: 13px;

            color: #6a737d;

            display: flex;

            gap: 4px;

            align-items: center;

            flex-wrap: wrap; /* Daralırsa alta inmesi için */

        }

        

        .slicer-stat-text {

            color: #586069;

        }


        .slicer-stat-separator {

            color: #d1d5da;

            margin: 0 2px;

        }


        /* GÖRSELE UYGUN KALDIR BUTONU (Kırmızı Metin) */

        .slicer-remove-text-btn {

            background: none;

            border: none;

            color: #f43f5e; /* Görseldeki kırmızı/pembe ton */

            font-size: 13px;

            font-weight: 700;

            cursor: pointer;

            padding: 0;

            margin: 0;

            transition: all 0.2s ease;

        }

        .slicer-remove-text-btn:hover {

            color: #e11d48;

            text-decoration: underline;

        }


        /* ÇOK SATIRLI (WRAP) BUTON ALANI */

        .slicer-row-buttons {

            display: flex;

            flex-wrap: wrap; /* Butonlar sığmadığında alt satıra geçer */

            gap: 8px;

            align-items: center;

            flex-grow: 1;

        }


        /* DİLİMLEYİCİ MODERN SIYAH BUTONLARI */

        .glass-btn {

            padding: 7px 16px;

            border-radius: 20px;

            font-size: 12px;

            font-weight: 700;

            cursor: pointer;

            transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);

            user-select: none;

            display: inline-flex;

            align-items: center;

            gap: 6px;

            outline: none;

            white-space: nowrap;

            flex-shrink: 0;

        }


        /* Modern Siyah (İçinde veri olan aktif butonlar) */

        .glass-btn.active-glass {

            background: linear-gradient(135deg, #1f242d, #11141a);

            color: #ffffff;

            border: 1px solid #333a48;

            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.1);

        }

        .glass-btn.active-glass:hover {

            transform: translateY(-2px);

            box-shadow: 0 6px 14px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.2);

            border-color: #00c6ff;

        }


        /* Seçili Durum Vurgusu (Mavi Cam Vurgulu Modern Siyah) */

        .glass-btn.selected-glass {

            background: linear-gradient(135deg, #0f172a, #020617) !important;

            color: #38bdf8 !important;

            border: 1px solid #38bdf8 !important;

            box-shadow: 0 0 12px rgba(56, 189, 248, 0.4), inset 0 1px 0 rgba(56, 189, 248, 0.2) !important;

            transform: translateY(-1px);

        }


        /* Pasif (İçinde veri olmayan) Açık Mat Butonlar */

        .glass-btn.passive-glass {

            background: #f1f5f9;

            color: #94a3b8;

            border: 1px solid #e2e8f0;

            cursor: pointer;

            opacity: 0.6;

            box-shadow: none;

        }

        .glass-btn.passive-glass:hover {

            background: #e2e8f0;

            color: #64748b;

        }


        /* --- TABLO VE SÜTUN HARFLERİ STİLLERİ --- */

        .table-container {

            width: 100%; 

            max-height: 65vh; 

            overflow: auto; 

            background: #fff; 

            border-radius: var(--radius); 

            box-shadow: var(--shadow);

            position: relative;

        }

        

        table { width: max-content; min-width: 100%; border-collapse: separate; border-spacing: 0; }

        th, td { border-bottom: 1px solid #e1e4e8; border-right: 1px solid #e1e4e8; padding: 12px; text-align: left; font-size: 13px; white-space: nowrap; }

        th:first-child, td:first-child { border-left: 1px solid #e1e4e8; }

        

        thead { 

            position: sticky; 

            top: 0; 

            z-index: 20; 

            background: #fff;

            box-shadow: 0 4px 6px rgba(0,0,0,0.06); 

        }


        /* TABLO BAŞLIKLARININ ÜSTÜNDEKİ SÜTUN HARFLERİ (A, B, C...) */

        thead th.col-letter-header {

            background: #f8f9fc !important;

            color: #8c939d !important;

            font-weight: 800;

            font-size: 11px;

            text-align: center !important;

            padding: 5px 12px;

            letter-spacing: 0.5px;

            border-bottom: 1px solid #e1e4e8;

            user-select: none;

        }

        

        thead th.main-header { 

            background: #1a1e23 !important; 

            color: white !important; 

            font-weight: bold; 

            border-top: 1px solid #1a1e23;

            cursor: pointer; 

            user-select: none; 

            transition: background 0.2s;

        }

        thead th.main-header:hover {

            background: #2c3238 !important; 

        }

        

        .sort-icon {

            font-size: 11px;

            margin-left: 5px;

            color: #00c6ff;

            display: inline-block;

            width: 12px;

        }


        tbody tr:nth-child(even) { background-color: #f8f9fc; }

        tbody tr:hover { background-color: #e6f2ff; }


        /* --- ARAMA VURGUSU (HIGHLIGHT) STİLİ --- */

        .highlight-match {

            background-color: #d4edda;

            color: #155724;

            font-weight: bold;

            border-radius: 3px;

            padding: 1px 2px;

        }


        /* --- SAYFALAMA (PAGINATION) STİLLERİ --- */

        .pagination-container {

            display: flex;

            justify-content: space-between;

            align-items: center;

            padding: 15px;

            background: #fff;

            border-radius: var(--radius);

            box-shadow: var(--shadow);

            margin-top: 15px;

        }

        .pagination-controls button { margin: 0 5px; }


        /* --- YAZDIRMA (PRINT) VE PDF STİLLERİ --- */

        @media print {

            .no-print { display: none !important; }

            body { background: white; padding: 0; margin: 0; }

            

            .sticky-container { position: static !important; }

            .sticky-container::before { content: none !important; }


            .header { box-shadow: none; border-color: #000; margin-bottom: 20px; position: static; }

            .table-container { box-shadow: none; border-radius: 0; overflow: visible; max-height: none; }

            table { width: 100%; max-width: 100%; font-size: 10px; }

            th, td { white-space: nowrap !important; padding: 6px; }

            thead { position: static; box-shadow: none; }

            

            .col-letter-row { display: none !important; }

            

            thead th.main-header { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }

            

            .highlight-match { 

                background-color: transparent !important; 

                color: inherit !important; 

                font-weight: normal !important; 

                padding: 0 !important; 

            }

            

            @page { size: landscape; margin: 10mm; @bottom-right { content: "Sayfa " counter(page) " / " counter(pages); font-size: 10px; } }

        }

    </style>

</head>

<body>


    <svg style="width:0; height:0; position:absolute;" aria-hidden="true" focusable="false">

        <defs>

            <linearGradient id="gradTotal" x1="0%" y1="0%" x2="100%" y2="0%">

                <stop offset="0%" stop-color="#00c6ff" />

                <stop offset="100%" stop-color="#0072ff" />

            </linearGradient>

            <linearGradient id="gradPercent" x1="0%" y1="0%" x2="100%" y2="0%">

                <stop offset="0%" stop-color="#ff416c" />

                <stop offset="100%" stop-color="#ff4b2b" />

            </linearGradient>

            <linearGradient id="gradFiltered" x1="0%" y1="0%" x2="100%" y2="0%">

                <stop offset="0%" stop-color="#11998e" />

                <stop offset="100%" stop-color="#38ef7d" />

            </linearGradient>

        </defs>

    </svg>


    <div class="sticky-container">

        <div class="header">

            <div class="left">

                <div class="logo"><img src="logo.jpg" alt="Logo" onerror="this.style.display='none'"></div>

                <div>

                    <div class="title1">Envanter</div>

                    <div class="title2">Kullanıcı Destek Koordinatörlüğü</div>

                </div>

            </div>

            

            <div class="center-title">

                <div class="gauges-wrapper">

                    <div class="tech-gauge">

                        <div class="tg-label total">Adet</div>

                        <svg viewBox="0 0 100 55">

                            <path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#e1e4e8" stroke-width="14" stroke-linecap="round" />

                            <path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#ffffff" stroke-width="14" stroke-dasharray="2 4" />

                            <path id="pathTotal" d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="url(#gradTotal)" stroke-width="10" stroke-linecap="round" 

                                  style="stroke-dasharray: 125.6; stroke-dashoffset: 0; transition: stroke-dashoffset 1s ease-out;" />

                            <text x="50" y="47" text-anchor="middle" class="tg-value" id="gTotal">0</text>

                        </svg>

                    </div>

                    

                    <div class="tech-gauge">

                        <div class="tg-label percent">Oran</div>

                        <svg viewBox="0 0 100 55">

                            <path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#e1e4e8" stroke-width="14" stroke-linecap="round" />

                            <path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#ffffff" stroke-width="14" stroke-dasharray="2 4" />

                            <path id="pathPercent" d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="url(#gradPercent)" stroke-width="10" stroke-linecap="round" 

                                  style="stroke-dasharray: 125.6; stroke-dashoffset: 125.6; transition: stroke-dashoffset 1s ease-out;" />

                            <text x="50" y="47" text-anchor="middle" class="tg-value" id="gPercent">%0</text>

                        </svg>

                    </div>

                    

                    <div class="tech-gauge">

                        <div class="tg-label filtered">Filtre Adet</div> 

                        <svg viewBox="0 0 100 55">

                            <path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#e1e4e8" stroke-width="14" stroke-linecap="round" />

                            <path d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="#ffffff" stroke-width="14" stroke-dasharray="2 4" />

                            <path id="pathFiltered" d="M 10 50 A 40 40 0 0 1 90 50" fill="none" stroke="url(#gradFiltered)" stroke-width="10" stroke-linecap="round" 

                                  style="stroke-dasharray: 125.6; stroke-dashoffset: 125.6; transition: stroke-dashoffset 1s ease-out;" />

                            <text x="50" y="47" text-anchor="middle" class="tg-value" id="gFiltered">0</text>

                        </svg>

                    </div>

                </div>

            </div>

            

            <div class="right">TEKNİK İŞLETME DAİRESİ BAŞKANLIĞI</div>

        </div>


        <div class="controls no-print">

            <input type="file" id="excelFile" accept=".xls,.xlsx">

            <progress id="progressBar" value="0" max="100"></progress>

            

            <div class="search-container no-print">

                <button class="btn-secondary" type="button" onclick="window.location.reload();">Sayfa Yenile</button>

                <button class="btn-danger" type="button" onclick="document.getElementById('globalSearch').value=''; applyFiltersAndSlicers();">Ara Temizle</button>

                <input type="text" id="globalSearch" placeholder="Tüm başlıklarda, tek yerde Ara..." oninput="applyFiltersAndSlicers()">

            </div>

            

            <div style="margin-left: auto; display: flex; gap: 10px;">

                <button class="btn-success" type="button" onclick="exportToExcel()">📥 Excel İndir</button>

                <button class="btn-primary" type="button" onclick="window.print()">🖨️ PDF / Yazdır</button>

            </div>

            

            <div id="sheetTabsContainer" class="sheet-tabs-container" style="display: none;"></div>

        </div>

    </div> <div class="slicer-container no-print">

        <div class="slicer-header-bar">

            <span class="slicer-title-label">🎛️ Veri Dilimleyici Oluştur:</span>

            

            <div class="slicer-input-wrapper">

                <input type="text" id="columnInput" class="slicer-input" placeholder="Sütun bilgisi gir (Örn: B, E, F, G)">

                <button class="btn-primary" id="btnCreateSlicers">Buton Oluştur</button>

            </div>

            

            <div style="margin-left: auto; display: flex; flex-direction: column; align-items: flex-end;">

                <button class="btn-danger" id="btnClearSlicers">✖ Filtreleri Sıfırla</button>

                <span style="font-size: 10px; color: #6c757d; margin-top: 5px; font-weight: 600; letter-spacing: 0.5px;">AI Web Designer: Muhammed Yusuf OLGUN</span>

            </div>

        </div>


        <div id="slicerArea" class="slicer-area-rows"></div>

    </div>


    <div class="table-container" id="tableContainer">

        <table id="dataTable">

            <thead id="tableHead"></thead>

            <tbody id="tableBody"></tbody>

        </table>

    </div>


    <div class="pagination-container no-print" id="paginationContainer" style="display:none;">

        <div id="pageInfo" style="font-size: 13px; font-weight: bold; color: #586069;"></div>

        <div class="pagination-controls">

            <button class="btn-primary" onclick="changePage(-1)">Önceki</button>

            <span id="pageIndicator" style="margin: 0 10px; font-weight: bold; color: #24292e;"></span>

            <button class="btn-primary" onclick="changePage(1)">Sonraki</button>

        </div>

        <div>

            <select id="rowsPerPage" onchange="changeRowsPerPage()">

                <option value="50">Sayfada 50 Kayıt</option>

                <option value="100" selected>Sayfada 100 Kayıt</option>

                <option value="500">Sayfada 500 Kayıt</option>

                <option value="1000">Sayfada 1000 Kayıt</option>

            </select>

        </div>

    </div>


    <script>

        let excelData = [];      

        let actualHeaders = {};  

        let headerKeys = [];     


        let currentFilteredData = [];

        let currentPage = 1;

        let rowsPerPage = 100;


        let currentSortCol = null;

        let sortAsc = true;


        const PATH_LENGTH = 125.6;

        

        let currentWorkbook = null;

        let currentSheetName = "";


        // DİLİMLEYİCİ DURUM YÖNETİMİ

        let activeSlicerCols = []; 

        let slicerSelections = {}; 


        document.getElementById('excelFile').addEventListener('change', function(e) {

            const file = e.target.files[0];

            if (!file) return;


            const pb = document.getElementById('progressBar');

            pb.style.display = 'block';

            pb.value = 10;


            const reader = new FileReader();

            reader.onload = function(event) {

                pb.value = 40;

                try {

                    const data = new Uint8Array(event.target.result);

                    currentWorkbook = XLSX.read(data, {type: 'array'});

                    pb.value = 60;


                    const sheetNames = currentWorkbook.SheetNames;

                    renderSheetTabs(sheetNames);

                    

                    loadSheetData(sheetNames[0]);


                    pb.value = 100;

                    setTimeout(() => { pb.style.display = 'none'; }, 500);


                } catch (error) {

                    alert("Dosya okunurken bir hata oluştu: " + error.message);

                    pb.style.display = 'none';

                }

            };

            reader.readAsArrayBuffer(file);

        });


        function renderSheetTabs(sheetNames) {

            const container = document.getElementById('sheetTabsContainer');

            

            if (sheetNames.length <= 1) {

                container.style.display = 'none';

                container.innerHTML = '';

                return;

            }

            

            container.style.display = 'flex';

            container.innerHTML = '';

            

            sheetNames.forEach(name => {

                const btn = document.createElement('button');

                btn.className = 'sheet-tab-btn';

                btn.innerText = name;

                btn.onclick = () => {

                    const pb = document.getElementById('progressBar');

                    pb.style.display = 'block';

                    pb.value = 50;

                    

                    setTimeout(() => {

                        loadSheetData(name);

                        pb.style.display = 'none';

                    }, 50);

                };

                container.appendChild(btn);

            });

        }


        function loadSheetData(sheetName) {

            currentSheetName = sheetName;

            

            const container = document.getElementById('sheetTabsContainer');

            if(container.style.display !== 'none') {

                const btns = container.querySelectorAll('.sheet-tab-btn');

                btns.forEach(btn => {

                    if (btn.innerText === sheetName) btn.classList.add('active');

                    else btn.classList.remove('active');

                });

            }


            const worksheet = currentWorkbook.Sheets[sheetName];

            const rawData = XLSX.utils.sheet_to_json(worksheet, {header: "A", defval: ""});


            if (rawData.length > 0) {

                actualHeaders = rawData[0];

                headerKeys = Object.keys(actualHeaders).filter(key => String(actualHeaders[key]).trim() !== "");

                

                excelData = rawData.slice(1).filter(row => {

                    return headerKeys.some(key => String(row[key]).trim() !== "");

                });

                

                currentSortCol = null;

                sortAsc = true;

                currentPage = 1;


                activeSlicerCols = [];

                slicerSelections = {};

                document.getElementById('slicerArea').innerHTML = '';

                document.getElementById('columnInput').value = '';


                renderHeaders();

                

                currentFilteredData = excelData; 

                renderPagination();

                updateGauges(excelData.length, excelData.length);

                

                document.getElementById('globalSearch').value = ''; 

            } else {

                alert(`"${sheetName}" sekmesinde veri bulunamadı!`);

                excelData = [];

                currentFilteredData = [];

                renderHeaders();

                renderPagination();

                updateGauges(0, 0);

            }

        }


        function renderHeaders() {

            const thead = document.getElementById('tableHead');

            thead.innerHTML = '';


            // 1. ÜST SATIR: AÇIK GRİ BÜYÜK HARFLER SATIRI (A, B, C, D...)

            let letterRow = document.createElement('tr');

            letterRow.className = 'col-letter-row no-print';


            // 2. ALT SATIR: ANA BAŞLIKLAR SATIRI

            let headerRow = document.createElement('tr');


            headerKeys.forEach(k => {

                let letterTh = document.createElement('th');

                letterTh.className = 'col-letter-header';

                letterTh.textContent = String(k).toUpperCase(); // A, B, C...

                letterRow.appendChild(letterTh);


                let th = document.createElement('th');

                th.className = 'main-header';

                th.title = 'Sıralamak için tıklayın';

                th.innerHTML = `<span>${actualHeaders[k]}</span><span class="sort-icon" id="sort_icon_${k}"></span>`;

                

                th.addEventListener('click', () => {

                    if (currentSortCol === k) {

                        sortAsc = !sortAsc; 

                    } else {

                        currentSortCol = k; 

                        sortAsc = true;

                    }

                    updateSortIcons();

                    applyFiltersAndSlicers(); 

                });


                headerRow.appendChild(th);

            });


            thead.appendChild(letterRow);

            thead.appendChild(headerRow);

        }


        function updateSortIcons() {

            headerKeys.forEach(k => {

                const iconSpan = document.getElementById('sort_icon_' + k);

                if (iconSpan) {

                    if (currentSortCol === k) {

                        iconSpan.innerHTML = sortAsc ? '&#9650;' : '&#9660;';

                    } else {

                        iconSpan.innerHTML = '';

                    }

                }

            });

        }


        function escapeHTML(str) {

            return String(str !== undefined ? str : '').replace(/[&<>'"]/g, 

                tag => ({

                    '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#39;', '"': '&quot;'

                }[tag])

            );

        }


        function getHighlightedHTML(text, searchVal) {

            const str = String(text !== undefined ? text : '');

            if (!searchVal) return escapeHTML(str);

            

            const lowerText = str.toLocaleLowerCase('tr-TR');

            const lowerSearch = searchVal.toLocaleLowerCase('tr-TR');

            

            let startIndex = 0;

            let result = '';

            let index;

            

            while ((index = lowerText.indexOf(lowerSearch, startIndex)) > -1) {

                result += escapeHTML(str.substring(startIndex, index));

                result += `<span class="highlight-match">${escapeHTML(str.substring(index, index + searchVal.length))}</span>`;

                startIndex = index + searchVal.length;

            }

            result += escapeHTML(str.substring(startIndex));

            return result;

        }


        function renderPagination() {

            const tbody = document.getElementById('tableBody');

            tbody.innerHTML = '';


            const totalRows = currentFilteredData.length;

            if (totalRows === 0) {

                document.getElementById('paginationContainer').style.display = 'none';

                return;

            }


            document.getElementById('paginationContainer').style.display = 'flex';

            

            const totalPages = Math.ceil(totalRows / rowsPerPage);

            if (currentPage > totalPages) currentPage = totalPages;

            if (currentPage < 1) currentPage = 1;


            const startIndex = (currentPage - 1) * rowsPerPage;

            const endIndex = Math.min(startIndex + rowsPerPage, totalRows);


            const pageData = currentFilteredData.slice(startIndex, endIndex);

            const searchVal = document.getElementById('globalSearch').value.trim();


            pageData.forEach(row => {

                let tr = document.createElement('tr');

                headerKeys.forEach(k => {

                    let td = document.createElement('td');

                    td.innerHTML = getHighlightedHTML(row[k], searchVal);

                    tr.appendChild(td);

                });

                tbody.appendChild(tr);

            });


            document.getElementById('pageInfo').innerText = `Toplam ${totalRows} kayıttan ${startIndex + 1} - ${endIndex} arası gösteriliyor.`;

            document.getElementById('pageIndicator').innerText = `Sayfa ${currentPage} / ${totalPages}`;

        }


        window.changePage = function(dir) {

            currentPage += dir;

            renderPagination();

            document.getElementById('tableContainer').scrollTo({ top: 0, behavior: 'smooth' });

        }


        window.changeRowsPerPage = function() {

            rowsPerPage = parseInt(document.getElementById('rowsPerPage').value);

            currentPage = 1;

            renderPagination();

            document.getElementById('tableContainer').scrollTo({ top: 0, behavior: 'smooth' });

        }


        window.exportToExcel = function() {

            if (!currentFilteredData || currentFilteredData.length === 0) {

                alert("Dışa aktarılacak veri bulunamadı.");

                return;

            }

            

            const exportData = currentFilteredData.map(row => {

                let cleanRow = {};

                headerKeys.forEach(k => {

                    cleanRow[actualHeaders[k]] = row[k];

                });

                return cleanRow;

            });


            const ws = XLSX.utils.json_to_sheet(exportData);

            const wb = XLSX.utils.book_new();

            

            let exportSheetName = currentSheetName ? currentSheetName.substring(0, 31) : "Filtrelenmis_Veri"; 

            

            XLSX.utils.book_append_sheet(wb, ws, exportSheetName);

            XLSX.writeFile(wb, `Envanter_Raporu_${exportSheetName}.xlsx`);

        }


        /* --- VERİ DİLİMLEYİCİ (SLICER) BUTON OLUŞTURMA VE FİLTRELEME MANTIĞI --- */


        document.getElementById('btnCreateSlicers').addEventListener('click', function() {

            const inputVal = document.getElementById('columnInput').value.trim();

            if (!inputVal) {

                alert("Lütfen en az bir sütun harfi giriniz (Örn: B, E, F, G)");

                return;

            }


            if (!excelData || excelData.length === 0) {

                alert("Lütfen önce bir Excel dosyası yükleyin.");

                return;

            }


            const rawCols = inputVal.split(',').map(c => c.trim().toUpperCase()).filter(c => c !== "");

            

            let validCols = [];

            rawCols.forEach(c => {

                if (headerKeys.includes(c)) {

                    if (!validCols.includes(c)) validCols.push(c);

                }

            });


            if (validCols.length === 0) {

                alert("Girilen sütun harfleri Excel tablosunda bulunamadı! Lütfen geçerli sütun harfleri giriniz (Örn: A, B, C...).");

                return;

            }


            activeSlicerCols = validCols;

            slicerSelections = {};

            validCols.forEach(col => {

                slicerSelections[col] = new Set();

            });


            renderSlicerStructure();

            applyFiltersAndSlicers();

        });


        function renderSlicerStructure() {

            const container = document.getElementById('slicerArea');

            container.innerHTML = '';


            activeSlicerCols.forEach(colKey => {

                const headerName = actualHeaders[colKey] || colKey;

                

                let uniqueVals = new Set();

                excelData.forEach(row => {

                    let val = row[colKey] !== undefined ? String(row[colKey]).trim() : "";

                    uniqueVals.add(val);

                });

                let sortedVals = Array.from(uniqueVals).sort((a, b) => a.localeCompare(b, 'tr-TR', {numeric: true}));


                const rowDiv = document.createElement('div');

                rowDiv.className = 'slicer-row';

                rowDiv.id = 'slicer_row_' + colKey;


                const headerDiv = document.createElement('div');

                headerDiv.className = 'slicer-row-header';

                

                // GÖRSELE UYGUN YENİ METİN VE AYIRICI (|) TASARIMI

                headerDiv.innerHTML = `

                    <div class="slicer-row-title">${escapeHTML(headerName)}</div>

                    <div class="slicer-row-stats" id="stats_${colKey}">

                        <span class="slicer-stat-text">Toplam: ${sortedVals.length}</span> <span class="slicer-stat-separator">|</span>

                        <span class="slicer-stat-text">Seçilen: 0</span> <span class="slicer-stat-separator">|</span>

                        <span class="slicer-stat-text">Aktif: ${sortedVals.length}</span> <span class="slicer-stat-separator">|</span>

                        <button type="button" class="slicer-remove-text-btn" onclick="removeSlicerRow('${colKey}')" title="Bu dilimleyiciyi kaldır">Kaldır</button>

                    </div>

                `;


                const buttonsDiv = document.createElement('div');

                buttonsDiv.className = 'slicer-row-buttons';

                buttonsDiv.id = 'buttons_' + colKey;


                sortedVals.forEach(val => {

                    const btn = document.createElement('button');

                    btn.type = 'button';

                    btn.className = 'glass-btn active-glass';

                    btn.dataset.col = colKey;

                    btn.dataset.val = val;

                    btn.innerHTML = val === "" ? "<i>(Boş Kayıtlar)</i>" : escapeHTML(val);

                    

                    btn.addEventListener('click', function() {

                        toggleSlicerValue(colKey, val);

                    });


                    buttonsDiv.appendChild(btn);

                });


                rowDiv.appendChild(headerDiv);

                rowDiv.appendChild(buttonsDiv);

                container.appendChild(rowDiv);

            });

        }


        // TEK BİR SÜTUN DİLİMLEYİCİSİNİ KALDIRMA FONKSİYONU

        window.removeSlicerRow = function(colKey) {

            activeSlicerCols = activeSlicerCols.filter(c => c !== colKey);

            delete slicerSelections[colKey];

            const row = document.getElementById('slicer_row_' + colKey);

            if (row) row.remove();

            applyFiltersAndSlicers();

        };


        function toggleSlicerValue(colKey, val) {

            if (!slicerSelections[colKey]) {

                slicerSelections[colKey] = new Set();

            }

            const set = slicerSelections[colKey];

            if (set.has(val)) {

                set.delete(val);

            } else {

                set.add(val);

            }

            applyFiltersAndSlicers();

        }


        document.getElementById('btnClearSlicers').addEventListener('click', function() {

            document.getElementById('columnInput').value = '';

            activeSlicerCols = [];

            slicerSelections = {};

            document.getElementById('slicerArea').innerHTML = '';

            document.getElementById('globalSearch').value = '';

            applyFiltersAndSlicers();

        });


        window.applyFiltersAndSlicers = function() {

            const globalSearchVal = document.getElementById('globalSearch').value.trim().toLocaleLowerCase('tr-TR');


            let dataToProcess = excelData.filter(row => {

                for (let col of activeSlicerCols) {

                    const selectedSet = slicerSelections[col];

                    if (selectedSet && selectedSet.size > 0) {

                        let cellVal = row[col] !== undefined ? String(row[col]).trim() : "";

                        if (!selectedSet.has(cellVal)) return false;

                    }

                }

                if (globalSearchVal !== "") {

                    let passesSearch = headerKeys.some(key => {

                        let cellVal = String(row[key] || '').toLocaleLowerCase('tr-TR');

                        return cellVal.includes(globalSearchVal);

                    });

                    if (!passesSearch) return false;

                }

                return true;

            });


            if (currentSortCol) {

                dataToProcess = [...dataToProcess];

                dataToProcess.sort((a, b) => {

                    let valA = a[currentSortCol] !== undefined ? String(a[currentSortCol]).trim() : "";

                    let valB = b[currentSortCol] !== undefined ? String(b[currentSortCol]).trim() : "";


                    let numA = parseFloat(valA.replace(',', '.'));

                    let numB = parseFloat(valB.replace(',', '.'));

                    let isNum = !isNaN(numA) && !isNaN(numB) && valA !== "" && valB !== "";


                    if (isNum) {

                        return sortAsc ? numA - numB : numB - numA;

                    } else {

                        return sortAsc 

                            ? valA.localeCompare(valB, 'tr-TR', { numeric: true }) 

                            : valB.localeCompare(valA, 'tr-TR', { numeric: true });

                    }

                });

            }


            currentPage = 1;

            currentFilteredData = dataToProcess;


            updateSlicerRowsUI(globalSearchVal);


            renderPagination();

            updateGauges(excelData.length, dataToProcess.length);

        };


        function updateSlicerRowsUI(globalSearchVal) {

            activeSlicerCols.forEach(colKey => {

                let subsetForCol = excelData.filter(row => {

                    for (let otherCol of activeSlicerCols) {

                        if (otherCol === colKey) continue; 

                        const set = slicerSelections[otherCol];

                        if (set && set.size > 0) {

                            let cellVal = row[otherCol] !== undefined ? String(row[otherCol]).trim() : "";

                            if (!set.has(cellVal)) return false;

                        }

                    }

                    if (globalSearchVal !== "") {

                        return headerKeys.some(key => {

                            let cellVal = String(row[key] || '').toLocaleLowerCase('tr-TR');

                            return cellVal.includes(globalSearchVal);

                        });

                    }

                    return true;

                });


                let validVals = new Set();

                subsetForCol.forEach(row => {

                    let val = row[colKey] !== undefined ? String(row[colKey]).trim() : "";

                    validVals.add(val);

                });


                const selectedSet = slicerSelections[colKey] || new Set();


                const statsElem = document.getElementById('stats_' + colKey);

                const buttonsElem = document.getElementById('buttons_' + colKey);


                if (buttonsElem) {

                    const buttons = buttonsElem.querySelectorAll('.glass-btn');

                    const totalCount = buttons.length;

                    const selectedCount = selectedSet.size;

                    const activeCount = validVals.size;


                    if (statsElem) {

                        // GÖRSELE UYGUN GÜNCELLEME

                        statsElem.innerHTML = `

                            <span class="slicer-stat-text">Toplam: ${totalCount}</span> <span class="slicer-stat-separator">|</span>

                            <span class="slicer-stat-text">Seçilen: ${selectedCount}</span> <span class="slicer-stat-separator">|</span>

                            <span class="slicer-stat-text">Aktif: ${activeCount}</span> <span class="slicer-stat-separator">|</span>

                            <button type="button" class="slicer-remove-text-btn" onclick="removeSlicerRow('${colKey}')" title="Bu dilimleyiciyi kaldır">Kaldır</button>

                        `;

                    }


                    buttons.forEach(btn => {

                        const val = btn.dataset.val;

                        const isSelected = selectedSet.has(val);

                        const isActive = validVals.has(val);


                        btn.className = 'glass-btn';


                        if (isSelected) {

                            btn.classList.add('selected-glass');

                        } else if (isActive) {

                            btn.classList.add('active-glass'); 

                        } else {

                            btn.classList.add('passive-glass'); 

                        }

                    });

                }

            });

        }


        function updateGauges(total, filtered) {

            document.getElementById('gTotal').textContent = total;

            

            let percent = total === 0 ? 0 : Math.round((filtered / total) * 100);

            document.getElementById('gPercent').textContent = '%' + percent;

            document.getElementById('gFiltered').textContent = filtered;


            document.getElementById('pathTotal').style.strokeDashoffset = total > 0 ? 0 : PATH_LENGTH;

            

            let pOffset = PATH_LENGTH - (PATH_LENGTH * percent / 100);

            document.getElementById('pathPercent').style.strokeDashoffset = isNaN(pOffset) ? PATH_LENGTH : pOffset;

            

            let fOffset = PATH_LENGTH - (PATH_LENGTH * percent / 100);

            document.getElementById('pathFiltered').style.strokeDashoffset = isNaN(fOffset) ? PATH_LENGTH : fOffset;

        }

    </script>

</body>

</html>