Dinamik-Resimli-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ştirebilir misiniz. Modelin bulunduğu sütun harfini Kod içinde tırnaklarıyla beraber yazıp "D" "Ctrl+F" ile yazıp bulunduğu harf ile değiştirmeniz önemli. Html dosyanın yanında "Resim" klasörü olmalı, bu klasörün içinde ürün model ismi, tabloda geçen isim ile bire bir aynı olmalı ve uzantı jpg olmalı.

Seçilen ürünün görseli başlık alanında görüntülenir.


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>

    <!-- SheetJS kütüphanesi - Excel okuma ve yazma için -->

    <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; 

        }


        /* --- BAŞLIK ALANI STİLLERİ (SABİT) --- */

        .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: 25px; 

            gap: 15px;

            

            position: sticky;

            top: 20px;

            z-index: 1000;

        }

        .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;

            flex-direction: column;

            align-items: center;

            gap: 15px;

        }

        

        .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);

            align-items: center;

        }


        .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;

        }


        .profile-photo-box {

            width: 360px;

            height: 200px;

            border-radius: 8px;

            background: #fff;

            border: 1px solid #eef0f3;

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

            display: flex;

            align-items: center;

            justify-content: center;

            overflow: hidden;

        }

        .profile-photo-box img {

            width: 100%;

            height: 100%;

            object-fit: contain;

            display: none;

        }


        .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;

            flex-direction: column;

            gap: 15px;

            background: #fff;

            padding: 15px;

            border-radius: var(--radius);

            box-shadow: var(--shadow);

            margin-bottom: 15px;

            border-left: 5px solid #00c6ff;

            

            position: sticky;

            top: 365px; 

            z-index: 999;

        }

        

        .controls-top {

            display: flex;

            gap: 15px;

            align-items: center;

            width: 100%;

        }


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

            padding: 8px 15px;

            border: 1px solid #d1d5da;

            border-radius: 6px;

            font-size: 13px;

            outline: none;

        }

        

        /* DAİMİ ODAKLI GENEL ARAMA ALANI */

        #globalSearch {

            flex-grow: 1;

            margin: 0 10px 0 0;

            padding: 10px 15px;

            border-radius: 8px;

            font-size: 14px;

            border: 1px solid #00c6ff !important;

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

            color: #24292e;

            transition: 0.3s;

        }

        #globalSearch::placeholder {

            color: #a0aab5; 

        }

        

        .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, #e9ecef, #dee2e6);

            color: #212529; border: 1px solid #ced4da; cursor: pointer; font-weight: bold; transition: 0.3s;

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

        }

        .btn-secondary:hover { box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1); transform: translateY(-1px); background: linear-gradient(135deg, #dee2e6, #ced4da); }


        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; }


        /* SEKME (SHEET) LİSTESİ STİLLERİ */

        #sheetListContainer {

            display: none;

            gap: 10px;

            flex-wrap: wrap;

            padding-top: 10px;

            border-top: 1px dashed #e1e4e8;

            width: 100%;

        }

        .sheet-btn {

            padding: 6px 15px;

            border: 1px solid #00c6ff;

            background: #fff;

            color: #007bff;

            border-radius: 6px;

            cursor: pointer;

            font-size: 13px;

            font-weight: bold;

            transition: 0.3s;

        }

        .sheet-btn.active {

            background: linear-gradient(135deg, #00c6ff, #0072ff);

            color: white;

            border-color: transparent;

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

        }

        .sheet-btn:hover:not(.active) {

            background: #e6f2ff;

        }


        /* --- EXCEL DİLİMLEYİCİ (SLICER) ALANI YENİ TASARIM --- */

        .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;

            margin-bottom: 15px;

        }

        .slicer-header-bar span { font-weight: 800; color: #0056b3; font-size: 14px; }

        

        #slicerColInput {

            min-width: 260px;

            border: 1px solid #ced4da;

            transition: all 0.3s ease;

        }

        #slicerColInput::placeholder {

            color: #adb5bd; 

        }

        #slicerColInput:focus::placeholder {

            color: transparent; 

        }

        #slicerColInput:focus {

            border-color: #00c6ff;

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

        }


        .slicer-area { 

            display: flex; 

            flex-direction: column; 

            gap: 15px; 

        }

        

        .slicer-row {

            display: flex;

            align-items: center;

            background: #fff;

            padding: 15px;

            border-radius: 8px;

            border: 1px solid #e1e4e8;

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

            width: 100%;

        }

        .slicer-row-header {

            flex: 0 0 250px; /* Genişletildi */

            display: flex;

            flex-direction: column;

            border-right: 1px solid #e1e4e8;

            margin-right: 15px;

            padding-right: 15px;

        }

        .slicer-row-title { font-size: 14px; font-weight: 800; color: #1a1e23; margin-bottom: 5px; }

        

        .slicer-row-stats { 

            font-size: 11px; 

            color: #6a737d; 

            font-weight: 600; 

        }

        

        .slicer-remove-link {

            color: #ff6b6b;

            cursor: pointer;

            font-weight: 800;

            text-decoration: none;

            transition: 0.2s;

            margin-left: 2px;

        }

        .slicer-remove-link:hover {

            color: #e63946;

            text-decoration: underline;

        }

        

        .slicer-row-buttons {

            display: flex;

            flex-wrap: wrap;

            gap: 8px;

            flex: 1;

        }

        

        .slicer-btn {

            padding: 6px 14px;

            border-radius: 6px;

            font-size: 12px;

            font-weight: 600;

            border: 1px solid rgba(255,255,255,0.2);

            cursor: pointer;

            transition: all 0.2s ease;

            

            /* İÇİNDE VERİ OLAN - CANLI CAM SİYAH */

            background: rgba(0, 0, 0, 0.85);

            color: #fff;

            backdrop-filter: blur(5px);

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

        }

        

        /* SEÇİLİ OLAN (TIKLANAN) */

        .slicer-btn.selected {

            background: #000;

            border: 1px solid #00c6ff;

            box-shadow: 0 0 10px rgba(0, 198, 255, 0.6);

            transform: scale(1.05);

        }


        .slicer-btn:hover:not(.disabled-slicer) {

            transform: translateY(-2px);

            background: #000;

        }


        /* PASİF OLAN - AÇIK GRİ */

        .slicer-btn.disabled-slicer {

            background: #e9ecef !important;

            color: #adb5bd !important;

            border: 1px solid #dee2e6 !important;

            box-shadow: none !important;

            cursor: not-allowed;

            backdrop-filter: none;

            transform: none !important;

        }


        /* --- TABLO 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 SÜTUN HARFLERİ (A, B, C...) */

        .col-letter-header th {

            text-align: center;

            color: #adb5bd; 

            font-size: 16px;

            font-weight: 800;

            text-transform: uppercase;

            background: #fff !important;

            border: none !important;

            border-bottom: 1px solid #e1e4e8 !important;

            padding: 8px 12px;

            pointer-events: 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; }

        

        /* Eşleşen Metin Vurgusu (Açık Yeşil) */

        .search-highlight {

            background-color: #a5d6a7 !important;

            color: #000 !important;

            border-radius: 3px;

            padding: 1px 2px;

            font-weight: bold;

        }


        /* --- 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; }

            .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; }

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

            

            .search-highlight { 

                background-color: transparent !important; 

                color: inherit !important;

                padding: 0 !important; 

                font-weight: normal !important;

            } 

            

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

        }

    </style>

</head>

<body>


    <!-- SVG GRADYAN TANIMLAMALARI -->

    <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>


    <!-- BAŞLIK ALANI BAŞLANGICI -->

    <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 class="profile-photo-box">

                <img id="profileImage" src="" alt="Kayıt Fotoğrafı" onerror="this.style.display='none'" onload="this.style.display='block'">

            </div>

            

        </div>

        

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

    </div>


    <!-- DOSYA YÜKLEME, ARAMA VE YAZDIRMA -->

    <div class="controls no-print">

        <div class="controls-top">

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

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

            

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


            <!-- ARAMA TEMİZLE BUTONU -->

            <button class="btn-danger" type="button" onclick="clearGlobalSearch()" title="Aramayı Temizle">Ara Temizle</button>

            

            <!-- GENEL ARAMA ALANI -->

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

            

            <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>

        

        <!-- ÇOKLU SEKME (SHEET) LİSTESİ -->

        <div id="sheetListContainer"></div>

    </div>


    <!-- EXCEL DİLİMLEYİCİ (SLICER) ALANI -->

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

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

            <span>🎛️ Veri Dilimleyici Ekle:</span>

            <!-- PENCERE VE BUTON OLUŞTUR ALANI -->

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

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

            

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

                <button class="btn-danger" id="btnClearSlicers">✖ Tüm Filtreleri Temizle</button>

                <span style="font-size: 10px; color: #ced4da; 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"></div>

    </div>


    <!-- TABLO ALANI -->

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

        <table id="dataTable">

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

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

        </table>

    </div>


    <!-- SAYFALAMA KONTROLLERİ -->

    <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 currentWorkbook = null; 

        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;


        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;

                    const sheetListContainer = document.getElementById('sheetListContainer');


                    if (sheetNames.length > 1) {

                        sheetListContainer.style.display = 'flex';

                        sheetListContainer.innerHTML = '';

                        sheetNames.forEach(sheet => {

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

                            btn.className = 'sheet-btn';

                            btn.innerText = sheet;

                            btn.onclick = () => loadSheet(sheet);

                            sheetListContainer.appendChild(btn);

                        });

                    } else {

                        sheetListContainer.style.display = 'none';

                        sheetListContainer.innerHTML = '';

                    }


                    pb.value = 80;

                    loadSheet(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 loadSheet(sheetName) {

            if (!currentWorkbook) return;


            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() !== "");

                });

            } else {

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

                excelData = [];

                actualHeaders = {};

                headerKeys = [];

            }

            

            currentSortCol = null;

            sortAsc = true;

            currentPage = 1;

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

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

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


            document.querySelectorAll('.sheet-btn').forEach(btn => {

                if (btn.innerText === sheetName) {

                    btn.classList.add('active');

                } else {

                    btn.classList.remove('active');

                }

            });


            renderHeaders();

            

            currentFilteredData = excelData; 

            renderPagination();

            updateGauges(excelData.length, excelData.length);

            updateProfileImage(currentFilteredData);

        }


        function updateProfileImage(filteredData) {

            const imgEl = document.getElementById('profileImage');

            if (filteredData && filteredData.length > 0) {

                let firstVal = filteredData[0]["D"]; 

                if (firstVal !== undefined && String(firstVal).trim() !== "") {

                    let cleanVal = String(firstVal).trim();

                    imgEl.style.display = 'none'; 

                    imgEl.src = `Resim/${cleanVal}.jpg`;

                } else {

                    imgEl.src = "";

                    imgEl.style.display = 'none';

                }

            } else {

                imgEl.src = "";

                imgEl.style.display = 'none';

            }

        }


        function renderHeaders() {

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

            thead.innerHTML = '';


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

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

            headerKeys.forEach(k => {

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

                th.innerText = k; 

                letterRow.appendChild(th);

            });

            thead.appendChild(letterRow);


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

            headerKeys.forEach(k => {

                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(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 toSafeLower(str) {

            return String(str)

                .replace(/İ/g, 'i').replace(/I/g, 'ı')

                .replace(/Ğ/g, 'ğ').replace(/Ü/g, 'ü')

                .replace(/Ş/g, 'ş').replace(/Ö/g, 'ö')

                .replace(/Ç/g, 'ç')

                .toLowerCase();

        }


        function highlightMatch(text, searchVal) {

            if (!searchVal) return text;

            

            let lowerText = toSafeLower(text);

            let lowerSearch = toSafeLower(searchVal);

            let startIndex = 0;

            let result = '';

            let matchIndex = lowerText.indexOf(lowerSearch, startIndex);

            

            if (matchIndex === -1) return text;


            while (matchIndex !== -1) {

                result += text.substring(startIndex, matchIndex);

                result += `<span class="search-highlight">${text.substring(matchIndex, matchIndex + searchVal.length)}</span>`;

                startIndex = matchIndex + searchVal.length;

                matchIndex = lowerText.indexOf(lowerSearch, startIndex);

            }

            result += text.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 globalSearchVal = document.getElementById('globalSearch').value; 


            pageData.forEach(row => {

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

                headerKeys.forEach(k => {

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

                    let cellText = row[k] !== undefined && row[k] !== null ? String(row[k]) : '';

                    td.innerHTML = highlightMatch(cellText, globalSearchVal);

                    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();

            XLSX.utils.book_append_sheet(wb, ws, "Filtrelenmis_Veri");

            XLSX.writeFile(wb, "Envanter_Raporu.xlsx");

        }


        // --- YENİ DİLİMLEYİCİ (BUTON OLUŞTUR) MANTIĞI ---

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

            const inputVal = document.getElementById('slicerColInput').value;

            if (!inputVal) return;

            

            const colsToCreate = inputVal.split(',').map(s => s.trim().toUpperCase()).filter(s => s);

            

            colsToCreate.forEach(colKey => {

                if (!headerKeys.includes(colKey)) return; 

                if (document.getElementById('slicer_' + colKey)) return; 


                const headerName = actualHeaders[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 slicerArea = document.getElementById('slicerArea');

                

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

                rowBox.className = 'slicer-row slicer-box';

                rowBox.id = 'slicer_' + colKey;

                rowBox.dataset.col = colKey; 

                

                let buttonsHtml = sortedVals.map(v => `

                    <button class="slicer-btn" data-val="${v.replace(/"/g, '&quot;')}">${v === "" ? "<i>(Boş Kayıtlar)</i>" : v}</button>

                `).join('');


                rowBox.innerHTML = `

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

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

                        <div class="slicer-row-stats" id="stats_${colKey}">Toplam: ${sortedVals.length} | Seçilen: 0 | Aktif: ${sortedVals.length} | <a class="slicer-remove-link" onclick="removeSlicer('${colKey}')" title="Bu filtreyi kaldır">Kaldır</a></div>

                    </div>

                    <div class="slicer-row-buttons">

                        ${buttonsHtml}

                    </div>

                `;

                

                slicerArea.appendChild(rowBox);

                

                rowBox.querySelectorAll('.slicer-btn').forEach(btn => {

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

                        if (this.classList.contains('disabled-slicer') && !this.classList.contains('selected')) return;

                        

                        this.classList.toggle('selected');

                        applyFiltersAndSlicers();

                    });

                });

            });

            

            applyFiltersAndSlicers();

        });


        window.removeSlicer = function(colKey) {

            const box = document.getElementById('slicer_' + colKey);

            if (box) {

                box.remove();

                applyFiltersAndSlicers(); 

            }

        };


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

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

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

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

            applyFiltersAndSlicers();

        });

        

        window.clearGlobalSearch = function() {

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

            applyFiltersAndSlicers();

        };


        // --- DİLİMLEYİCİ ARAYÜZ (BUTON) GÜNCELLEMESİ ---

        function updateSlicerUIs(slicerConds, globalSearchValText) {

            const boxes = document.querySelectorAll('.slicer-box');

            let globalSearchLower = toSafeLower(globalSearchValText);

            

            boxes.forEach(box => {

                const colKey = box.dataset.col;

                let otherSlicerConds = slicerConds.filter(cond => cond.col !== colKey);

                let subset = excelData;

                

                if (otherSlicerConds.length > 0 || globalSearchLower) {

                    subset = subset.filter(row => {

                        let passesSlicer = otherSlicerConds.every(cond => {

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

                            return cond.allowed.includes(cellVal);

                        });

                        if (!passesSlicer) return false;


                        let passesSearch = true;

                        if (globalSearchLower) {

                            passesSearch = headerKeys.some(k => {

                                let cellVal = row[k] !== undefined && row[k] !== null ? String(row[k]) : "";

                                return toSafeLower(cellVal).includes(globalSearchLower);

                            });

                        }

                        return passesSearch;

                    });

                }

                

                let validVals = new Set();

                subset.forEach(row => {

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

                    validVals.add(val);

                });

                

                const buttons = Array.from(box.querySelectorAll('.slicer-btn'));

                let activeCount = 0; 

                let selectedCount = 0;


                buttons.forEach(btn => {

                    const val = btn.dataset.val;

                    const isSelected = btn.classList.contains('selected');

                    

                    if (isSelected) selectedCount++;


                    if (validVals.has(val)) {

                        btn.classList.remove('disabled-slicer');

                        activeCount++; 

                    } else {

                        btn.classList.add('disabled-slicer');

                    }

                });

                

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

                if (statsSpan) {

                    const totalCount = buttons.length;

                    statsSpan.innerHTML = `Toplam: ${totalCount} | Seçilen: ${selectedCount} | Aktif: ${activeCount} | <a class="slicer-remove-link" onclick="removeSlicer('${colKey}')" title="Bu filtreyi kaldır">Kaldır</a>`;

                }

            });

        }


        window.applyFiltersAndSlicers = function() {

            const boxes = document.querySelectorAll('.slicer-box');

            let slicerConds = [];

            

            boxes.forEach(box => {

                const colKey = box.dataset.col;

                const checkedBtns = box.querySelectorAll('.slicer-btn.selected');

                if (checkedBtns.length > 0) {

                    let allowedVals = Array.from(checkedBtns).map(btn => btn.dataset.val);

                    slicerConds.push({ col: colKey, allowed: allowedVals });

                }

            });


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

            const globalSearchLower = toSafeLower(globalSearchValRaw);

            

            updateSlicerUIs(slicerConds, globalSearchValRaw);


            let dataToProcess = excelData;


            if (slicerConds.length > 0 || globalSearchLower) {

                dataToProcess = excelData.filter(row => {

                    let passesSlicer = slicerConds.every(cond => {

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

                        return cond.allowed.includes(cellVal);

                    });

                    if (!passesSlicer) return false;


                    let passesSearch = true;

                    if (globalSearchLower) {

                        passesSearch = headerKeys.some(k => {

                            let cellVal = row[k] !== undefined && row[k] !== null ? String(row[k]) : "";

                            return toSafeLower(cellVal).includes(globalSearchLower);

                        });

                    }

                    return passesSearch;

                });

            }


            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;

            

            renderPagination();

            updateGauges(excelData.length, dataToProcess.length);

            updateProfileImage(currentFilteredData); 

        };


        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>