<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

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

    <title>Project Previewer</title>

    <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap" rel="stylesheet">

    <style>

        body {

            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

            background: linear-gradient(to bottom right, #280f34, #120417);

            color: #ff6b00;

            margin: 0;

            padding: 0;

            display: flex;

            flex-direction: column;

            height: 100vh;

            overflow: hidden;

            /* Removed text-shadow */

        }

        /* Banner Header */

        #banner-header {

            background-color: rgba(0, 0, 0, 0.7);

            padding: 0 10px; /* Reduced padding */

            height: 40px; /* Fixed height */

            display: flex;

            align-items: center;

            justify-content: center; /* Center the title */

            backdrop-filter: blur(10px);

            border-bottom: 1px solid #ff6b0044;

        }

        #banner-title {

            font-family: 'Orbitron', sans-serif; /* Fancy Font */

            font-size: 1.8em; /* Increased font size */

            font-weight: 700;

            margin: 0;

            letter-spacing: 2px; /* Add letter spacing */

        }

        #header {

            background-color: rgba(0, 0, 0, 0.5);

            padding: 10px;

            display: flex;

            align-items: center;

            justify-content: space-between;

            backdrop-filter: blur(10px);

            border-bottom: 1px solid #ff6b0044;

        }

        #file-input-container {

            display: flex;

            align-items: center;

            position: relative;

        }

        #file-input {

            position: absolute;

            opacity: 0;

            width: 0.1px;

            height: 0.1px;

        }

        #open-folder-button, #save-file-button, #back-to-root, #fullscreen-button {

            background-color: #ff6b00;

            color: #120417;

            padding: 8px 16px;

            border: none;

            border-radius: 20px;

            cursor: pointer;

            margin-right: 10px;

            font-size: 14px;

            font-weight: 900; /* Bolder button text */

            box-shadow: 0 0 10px #ff6b00;

            transition: transform 0.2s, box-shadow 0.2s;

        }

        #open-folder-button:hover, #save-file-button:hover, #back-to-root:hover,  #fullscreen-button:hover{

            transform: scale(1.05);

            box-shadow: 0 0 15px #ff6b00;

        }

        #project-name {

            font-size: 1.5em;

            font-weight: bold;

            margin: 0;

            padding: 0 10px;

        }

        #file-list-container {

            overflow-y: auto;

            height: 150px;

            border-bottom: 1px solid #ff6b0044;

            padding: 10px;

        }

        #file-list {

            list-style: none;

            padding: 0;

            margin: 0;

        }

        #file-list li {

            padding: 8px 12px;

            border-bottom: 1px solid #ff6b0022;

            cursor: pointer;

            transition: background-color: 0.2s;

            white-space: nowrap;

            overflow: hidden;

            text-overflow: ellipsis;

            border-radius: 5px;

        }

        #file-list li:last-child {

            border-bottom: none;

        }

        #file-list li:hover {

            background-color: rgba(255, 107, 0, 0.2);

        }

        #preview-container {

            flex-grow: 1;

            overflow: hidden;

            position: relative;

            padding: 10px;

        }

        #preview-iframe {

            width: 100%;

            height: 100%;

            border: none;

            background-color: white;

            border-radius: 10px;

        }

        #status-bar {

            background-color: rgba(0, 0, 0, 0.5);

            padding: 5px 10px;

            font-size: 0.8em;

            text-align: right;

            backdrop-filter: blur(10px);

            border-top: 1px solid #ff6b0044;

        }

          /* Mobile Styles */

        @media (max-width: 768px) {

            #file-list-container {

                max-height: 150px; /* Smaller on mobile */

                width: 100%; /* Full width on small screen */

            }

            #preview-iframe, #editor-container{

                width: 100%;

            }

             #file-list-toggle {

                display: block; /* Show the toggle button */

            }

              #file-list.collapsed {

                display: none;

            }

             #open-folder-button, #save-file-button, #back-to-root,  #fullscreen-button {

                padding: 6px 12px; /* Smaller padding */

                font-size: 12px;

            }

              #project-name{

                 font-size: 1.2em;

              }

            #banner-header{

                height: auto; /*Allow height to adjust on smaller screens*/

            }

            #banner-title{

                font-size: 1.2em; /*Smaller Font size on mobile*/

            }

        }

         #file-list-toggle {

            display: none; /* Hidden by default */

            background-color: #ff6b00;

            color: #120417;

            padding: 8px 12px;

            border: none;

            border-radius: 4px;

            cursor: pointer;

            margin-bottom: 5px; /* Space below the button */

              font-weight: bold;

        }

    </style>

</head>

<body>

    <!-- Banner Header -->

    <div id="banner-header">

        <h1 id="banner-title">V I e w b a d g e r   2 0 2 5</h1>

    </div>

    <div id="header">

        <div id="file-input-container">

            <input type="file" id="file-input" webkitdirectory directory style="position: absolute; opacity: 0; width: 0.1px; height: 0.1px;">

            <button id="open-folder-button">Open Folder</button>

             <button id="back-to-root" style="display: none;">Back to Root</button>

             <button id="fullscreen-button">Fullscreen</button>

        </div>

        <h2 id="project-name"></h2>  <!-- Project Name -->

    </div>

    <div id="file-list-toggle">Toggle File List</div>  <!-- Toggle button for mobile -->

    <div id="file-list-container">

        <ul id="file-list"></ul>

    </div>

    <div id="preview-container">

        <iframe id="preview-iframe" sandbox="allow-scripts allow-same-origin allow-popups allow-forms"></iframe>

    </div>

     <div id="status-bar">

        Ready

    </div>

    <script>

    document.addEventListener('DOMContentLoaded', () => {

        const fileInput = document.getElementById('file-input');

        const openFolderButton = document.getElementById('open-folder-button');

        const fileList = document.getElementById('file-list');

        const backToRootButton = document.getElementById('back-to-root');

        const previewIframe = document.getElementById('preview-iframe');

        const projectNameDisplay = document.getElementById('project-name'); // Get element

        const fullscreenButton = document.getElementById('fullscreen-button');

        const fileListToggle = document.getElementById('file-list-toggle');

        const statusBar = document.getElementById("status-bar")

        let files = [];

        let rootPath = "";

        let currentPath = "";

          // --- Fullscreen Toggle ---

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

            if (document.fullscreenElement) {

                document.exitFullscreen();

            } else {

                previewIframe.requestFullscreen();

            }

        });

        // ---Mobile file list toggle

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

            fileList.classList.toggle('collapsed');

        });

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

            fileInput.click();

        });

        fileInput.addEventListener('change', (event) => {

            files = Array.from(event.target.files);

            if (files.length > 0) {

                rootPath = files[0].webkitRelativePath.split('/')[0] + "/";

                currentPath = rootPath;

                projectNameDisplay.textContent = rootPath; // Set project name

                backToRootButton.style.display = 'inline-block';

                renderFileList();

                 // Automatically load index.html if it exists

                const indexFile = files.find(file => file.webkitRelativePath === rootPath + 'index.html');

                if (indexFile) {

                    loadFile(indexFile);

                } else if (files.length > 0) {

                    loadFile(files[0]);

                }

            }

        });

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

            currentPath = rootPath;

            projectNameDisplay.textContent = rootPath; // Update display!

            renderFileList();

        });

         function getFileExtension(filename) {

            return filename.split('.').pop().toLowerCase();

        }

        function getRelativePath(fullPath, basePath) {

            if (fullPath.startsWith(basePath)) {

                return fullPath.substring(basePath.length);

            }

            return fullPath;

        }

        function escapeHtml(text) {

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

            div.textContent = text;

            return div.innerHTML;

        }

        function loadFile(file) {

            const reader = new FileReader();

            const fileExtension = getFileExtension(file.name);

            reader.onload = (event) => {

                if (['html', 'htm'].includes(fileExtension)) {

                    const url = URL.createObjectURL(file);

                    previewIframe.src = url;

                } else if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'].includes(fileExtension)) {

                    const url = URL.createObjectURL(file);

                    previewIframe.src = url;

                } else {

                    // Basic display for other file types

                    previewIframe.srcdoc = `<pre style="color: #ff6b00;">${escapeHtml(event.target.result)}</pre>`;

                }

                 statusBar.textContent = `Loaded: ${file.webkitRelativePath}`;

            };

             if (['js', 'css', 'txt', 'html', 'htm'].includes(file.name.split('.').pop().toLowerCase())) {

                reader.readAsText(file);  //Crucial for editable text

            } else {

                reader.readAsArrayBuffer(file); //Still needed for image object URLs

            }

        }

        function renderFileList() {

            fileList.innerHTML = '';

            const currentFiles = files.filter(file => file.webkitRelativePath.startsWith(currentPath));

            const entries = new Set();

            currentFiles.forEach(file => {

                const relativePath = getRelativePath(file.webkitRelativePath, currentPath);

                const parts = relativePath.split('/');

                if (parts.length > 1) {

                    entries.add(parts[0] + "/");

                } else if (parts[0]) {

                    entries.add(parts[0]);

                }

            });

            entries.forEach(entry => {

                const listItem = document.createElement('li');

                listItem.textContent = entry;

                listItem.dataset.path = currentPath + entry;

                fileList.appendChild(listItem);

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

                    if (entry.endsWith("/")) {

                        currentPath = listItem.dataset.path;

                         projectNameDisplay.textContent = listItem.dataset.path; // Update on folder click

                        renderFileList();

                    } else {

                        const fileToLoad = files.find(f => f.webkitRelativePath === listItem.dataset.path);

                        if (fileToLoad) {

                            loadFile(fileToLoad);

                        }

                    }

                });

            });

        }

          // Prevent iframe navigation to external URLs

        previewIframe.addEventListener('load', () => {

            try {

                if (previewIframe.contentWindow.location.origin !== window.location.origin) {

                    previewIframe.srcdoc = `<p style="color: #ff6b00;">Navigation to external URLs is blocked.</p>`;

                      statusBar.textContent = 'Blocked external navigation.';

                }

            } catch (error) {

                // Cross-origin access error (expected)

            }

        });

    });

    </script>

</body>

</html>

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.