Butonlu Resimli Envanter Dashboard

Bu çalışma, Tüm Excel çalışmalarını hızlıca filtreleme ve kolayca aranan bilgiye erişebilmek için yapılan, uzun soluklu bir çalışmadır. 

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ündür.

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.

Bu çalışma ile, "Dosya Seç" ile dosya okuma sağlandıktan sonra; Başlıklara basarak, başlık içinde yer alan farklı ifadelere göre dilimleyici butonlar oluşması, butonlara tıklama ile, filtre ve birden fazla butona basılması ile, filtre içinde filtrelemeye imkan sunmaktadır. Tüm başlıkların sütun içeriklerinde ise, yukarıdaki arama alanında yazarken filtrelemeye imkan sunmaktadır.  

Kodda yapılan çalışmalarla, nihai sonuçtaki kazanımlar; başlık alanında "Envanter" ibaresi alanındaki ifade, dosya ismi olacak şekilde düzenlendi. Ayrıca varsayılan olarak atanan tüm ibareler, HELDESK KOORDİNATÖRLÜĞÜ" ve "MYO MÜDÜRLÜĞÜ" alanlarına seri olarak 5 defa art arda basılmasıyla başlıkta değişime izin verildi. 

Birde resim alanına 5 defa art arda basılmasıyla, resimin eşleşeceği sütun bilgisi ataması yapabilirsiniz. (Örneğin default olarak "D" sütunu atandı. Excelinizde resim içermesini istediğiniz ürün modelini "D" sütununa denk gelecek şekilde koyabilir veya 5 kez peş peşe basarak sütun harfi atayabilirsiniz. "C" atayabilirsiniz. (Resmin görünebilmesi için, html dosyanın bulunduğu yerde "Resim" isminde klasör olmalı. Bu klasörün içinde, tablodan eşleşmesini istediğiniz tüm ürünlerle aynı isim ve uzantılı resimler ".jpg" uzantılı olmalı. Örneğin: "ThinkPad E14.jpg" ve "WorkCentre 3025.jpg" gibi.

Uygulama adımları 1: 
Resim alanına 5 defa art arda basılmasıyla, resimin eşleşeceği sütun bilgisi ataması yapabilirsiniz. (Örneğin default olarak "D" sütunu atandı. Excelinizde resim içermesini istediğiniz ürün modelini "D" sütununa denk gelecek şekilde koyabilir veya 5 kez peş peşe basarak sütun harfi atayabilirsiniz. "C" atayabilirsiniz.


Uygulama adımları 2: 
HELDESK KOORDİNATÖRLÜĞÜ" alanına seri olarak 5 defa art arda basılmasıyla başlıkta değişim.

Uygulama adımları 3: 
"MYO MÜDÜRLÜĞÜ" alanlarına seri olarak 5 defa art arda basılmasıyla başlıkta değişim gerçekleşmektedir.

Başlıklara tıklayarak oluşturulan butonlar, istenirse oluşan satırdaki "Kaldır" butonuna basılarak kaldırılabilir. "Filtreleri Sıfırla" butonuna basarak tüm filtreler toplu olarak kaldırılabilir.

İçeri aktarılan tablodan, başlıklardan hangisine tıklarsanız, dilimleme başlıkları ve içeriğine göre butonlar oluşacaktır.

Butonlara basarak filtreleme işlemlerini gerçekleştirebilirsiniz. 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. 

Arama penceresi ile tüm sütunlarda alfa numerik olarak arama gerçekleştirebilirsiniz. "Ara Temizle" ile aramayı temizleyebilirsiniz. ("Sayfa Yenile" basıldığında, ilk çalıştığı ana döner, başlıklar üzerinde yapılan değişiklik, varsayılan ifadelere döner) PDF olarak sunma düşüncesi, kurumsal bir form kazandırılması, Telefonlardan da tam net görünüm sağlanması içindir. Html sayfanın çalıştırıldığı konumda "logo.jpg" isminde kurumsal logonuzun olması yeterli. Böylelikle başlıkta logonuz yer alır.

Filtreleme sonrası, Filtrelenen Excel dosyasını indirebilir ve PDF olarak kaydedebilir yazdırabilirsiniz.

Yazdırabilir, PDF olarak kaydedebilirsiniz.


HTML Kod:

<!DOCTYPE html>

<html lang="tr">

<head>

    <meta charset="UTF-8">

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

    <title>Dinamik_BUTONLU_Resimli_Envanter_Dashboard</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;

            cursor: pointer;

            user-select: none;

        }

        .header .title2 { 

            font-size: 12px; 

            color: #6a737d; 

            font-weight: 600; 

            text-transform: uppercase; 

            letter-spacing: 0.5px;

            cursor: pointer;

            user-select: none;

        }

        

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

            cursor: pointer;

            user-select: none;

        }

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

            cursor: pointer;

            user-select: none;

        }


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

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

        }


        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; 

        }


        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" id="mainTitle" title="Değiştirmek için 5 kez peş peşe tıklayın">Envanter</div>

                <div class="title2" id="subTitle" title="Değiştirmek için 5 kez peş peşe tıklayın">Helpdesk 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>


            <!-- RESİM ALANI (5 kez tıklayarak sütun değiştirilebilir) -->

            <div class="profile-photo-box" id="profileBox" title="Sütun değiştirmek için 5 kez peş peşe tıklayın">

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

            </div>

            

        </div>

        

        <div class="right" id="rightTitle" title="Değiştirmek için 5 kez peş peşe tıklayın">MYO MÜDÜRLÜĞÜ</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">

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


        // --- DİNAMİK RESİM SÜTUNU TANIMLAMASI ---

        let imageColumnKey = "D"; // Varsayılan: "D"


        // LocalStorage'dan kayıtlı verileri yükleme (Hata Korumalı)

        try {

            let savedCol = localStorage.getItem('profileImageCol');

            if (savedCol && savedCol.trim() !== "") {

                imageColumnKey = savedCol.trim().toUpperCase();

            }

            let savedRight = localStorage.getItem('headerRightText');

            if (savedRight && savedRight.trim() !== "") {

                document.getElementById('rightTitle').innerText = savedRight;

            }

            let savedSub = localStorage.getItem('headerSubTitle');

            if (savedSub && savedSub.trim() !== "") {

                document.getElementById('subTitle').innerText = savedSub;

            }

        } catch (e) {

            console.warn("LocalStorage erişim uyarısı:", e);

        }


        // --- 5 TIKLAMA İLE METİN GÜNCELLEME SİSTEMİ ---

        function attachFiveClickEditor(elementId, storageKey, promptMessage) {

            let clickCount = 0;

            let clickTimer = null;

            const el = document.getElementById(elementId);

            if (!el) return;


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

                clickCount++;

                clearTimeout(clickTimer);

                clickTimer = setTimeout(() => { clickCount = 0; }, 2000);


                if (clickCount >= 5) {

                    clickCount = 0;

                    clearTimeout(clickTimer);

                    let currentVal = el.innerText;

                    let newVal = prompt(promptMessage, currentVal);

                    if (newVal !== null && newVal.trim() !== "") {

                        el.innerText = newVal.trim();

                        if (storageKey) {

                            try {

                                localStorage.setItem(storageKey, newVal.trim());

                            } catch (e) {

                                console.warn("LocalStorage yazılamadı:", e);

                            }

                        }

                    }

                }

            });

        }


        // Başlık (title1), Alt Başlık (title2) ve Sağ Başlık (right) için 5 tık dinleyicileri

        // Not: mainTitle (title1) sayfa ilk açılışta ve yenilemede daima "Envanter" olması istendiği için localStorage'a yazılmaz.

        attachFiveClickEditor('mainTitle', null, "Yeni Başlık Giriniz:");

        attachFiveClickEditor('rightTitle', 'headerRightText', "Sağ Başlık Metnini Giriniz (Örn: MYO MÜDÜRLÜĞÜ):");

        attachFiveClickEditor('subTitle', 'headerSubTitle', "Alt Başlık Metnini Giriniz (Örn: Helpdesk Koordinatörlüğü):");


        // Resim Sütunu İçin 5 Tık Dinleyicisi

        let photoClickCount = 0;

        let photoClickTimer = null;

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

            photoClickCount++;

            clearTimeout(photoClickTimer);

            photoClickTimer = setTimeout(() => { photoClickCount = 0; }, 2000);


            if (photoClickCount >= 5) {

                photoClickCount = 0;

                clearTimeout(photoClickTimer);

                let colInput = prompt("Resim eşleşmesi yapılacak sütun harfini giriniz (Örn: D, E, F):", imageColumnKey);

                if (colInput !== null && colInput.trim() !== "") {

                    imageColumnKey = colInput.trim().toUpperCase();

                    try {

                        localStorage.setItem('profileImageCol', imageColumnKey);

                        alert(`Resim eşleşme sütunu başarıyla "${imageColumnKey}" olarak güncellendi ve tarayıcıya kaydedildi.`);

                    } catch (err) {

                        console.error("Kayıt hatası:", err);

                        alert(`Sütun "${imageColumnKey}" olarak güncellendi.`);

                    }

                    updateProfileImage(currentFilteredData);

                }

            }

        });


        const PATH_LENGTH = 125.6;


        // Dosya Seçildiğinde Başlığı Dosya Adı Yapma

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

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

            if (!file) return;


            // Dosya uzantısını temizle (.xlsx, .xls vb.) ve başlığa yaz

            let fileNameWithoutExt = file.name.replace(/\.[^/.]+$/, "");

            document.getElementById('mainTitle').innerText = fileNameWithoutExt;


            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 = [];

            }

            

            currentPage = 1;

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

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


            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][imageColumnKey]; 

                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 headerRow = document.createElement('tr');

            headerKeys.forEach(k => {

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

                th.className = 'main-header';

                th.title = 'Filtrelemek (Veri Dilimleyici Oluşturmak) için tıklayın';

                th.innerHTML = `<span>${actualHeaders[k]}</span>`;

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

                    createSlicer(k);

                });

                headerRow.appendChild(th);

            });

            thead.appendChild(headerRow);

        }


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

        }


        // --- DİNAMİK OLARAK TIKLANAN BAŞLIK İÇİN DİLİMLEYİCİ (SLICER) OLUŞTURMA ---

        function createSlicer(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 = '';

            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;

                });

            }


            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>