script.js:
```javascript
const { ipcRenderer } = require('electron');

const startMenu = document.querySelector('.start-menu');
const startButton = document.querySelector('.start-menu-button');
const taskbar = document.querySelector('.taskbar .middle-side');

startButton.addEventListener('click', () => {
    startMenu.classList.toggle('active');
});

startMenu.querySelectorAll('.start-icon').forEach(item => {
    item.addEventListener('click', () => {
        startMenu.classList.remove('active');
    });
});

let openApps = {};

function app(id, title = 'New App', event = 'click') {
    const appIdentifier = document.querySelector(`[data-app="${id}"]`);
    let openId = 0;
    let windows = [];
    let highestZIndex = 10;

    appIdentifier.addEventListener(event, () => {
        if (openApps[id]) {
            const win = openApps[id];
            if (win.style.display === 'none') {
                win.style.display = 'block';
                setTimeout(() => {
                    win.style.transform = 'scale(1)';
                    win.style.opacity = '1';
                    bringToFront(win);
                    taskbar.querySelector(`[src="./images/${id}.png"]`).closest('.taskbar-icon').classList.add('active');
                }, 10);
            } else {
                bringToFront(win);
            }
            return;
        }

        openId++;
        const win = document.createElement('div');
        win.classList.add('win');
        win.id = `win-app-${openId}`;
        win.style.opacity = '0';
        win.style.transform = 'scale(0.1)';
        win.style.zIndex = ++highestZIndex;
        document.body.appendChild(win);
        id = id.replace('sm-', '');
        openApps[id] = win;

        win.innerHTML = `
            <div class="win-header">
                <div class="win-header-title">
                    <img src="./images/${id}.png" height="30" draggable="false" alt="">
                    <span>${title}</span>
                </div>
                <div class="win-header-buttons">
                    <div class="win-header-button" title="Minimize" data-action="minimize">-</div>
                    <div class="win-header-button" title="Maximize/Restore" data-action="maximize">□</div>
                    <div class="win-header-button" title="Close" data-action="close">×</div>
                </div>
            </div>
            <div class="win-content"></div>
        `;

        ipcRenderer.send('loadAppContent', id);

        ipcRenderer.once(`appContent-${id}`, (event, content) => {
            if (content.startsWith('<h1>Error')) {
                console.error(`Error loading content for ${id}:`, content);
            }
            const winContent = win.querySelector('.win-content');
            winContent.innerHTML = content;
            winContent.querySelectorAll('script').forEach(script => {
                eval(script.textContent);
            });

            setTimeout(() => {
                win.style.transition = 'transform 0.3s ease-in-out, opacity 0.3s ease-in-out';
                win.style.transform = 'scale(1)';
                win.style.opacity = '1';
            }, 10);
        });

        win.addEventListener('mousedown', () => {
            bringToFront(win);
        });

        const header = win.querySelector('.win-header');
        let initialX, initialY, isDragging = false;

        header.addEventListener('mousedown', e => {
            if (e.target !== header || e.button !== 0) return;
            initialX = e.clientX - win.offsetLeft;
            initialY = e.clientY - win.offsetTop;
            isDragging = true;
        });

        document.addEventListener('mousemove', e => {
            if (!isDragging) return;
            let x = e.clientX - initialX;
            let y = e.clientY - initialY;

            const maxX = window.innerWidth - win.offsetWidth;
            const maxY = window.innerHeight - win.offsetHeight;

            x = Math.max(0, Math.min(x, maxX));
            y = Math.max(0, Math.min(y, maxY));

            win.style.left = `${x}px`;
            win.style.top = `${y}px`;
        });

        document.addEventListener('mouseup', () => {
            isDragging = false;
        });

        header.addEventListener('dblclick', () => {
            actions.maximize();
        });

        const taskbarIcon = document.createElement('div');
        taskbarIcon.classList.add('taskbar-icon');
        taskbarIcon.innerHTML = `
        <img src="./images/${id}.png" height="30" draggable="false" alt="">
        <div class="indicator"></div>
        `;
        taskbarIcon.style.transform = 'translateY(100%)';
        taskbarIcon.style.opacity = '0';
        taskbar.appendChild(taskbarIcon);

        setTimeout(() => {
            taskbarIcon.style.transition = 'transform 0.3s ease-out, opacity 0.3s ease-out';
            taskbarIcon.style.transform = 'translateY(0)';
            taskbarIcon.style.opacity = '1';
        }, 50);

        let isMaximized = false;

        const actions = {
            minimize() {
                win.style.transition = 'transform 0.3s ease-in-out, opacity 0.3s ease-in-out';
                win.style.transform = 'scale(0.1)';
                win.style.opacity = '0';
                setTimeout(() => {
                    win.style.display = 'none';
                    win.style.transform = '';
                    win.style.opacity = '';
                }, 300);
                taskbarIcon.classList.remove('active');
            },
            maximize() {
                win.style.transition = 'all 0.2s ease-in-out';
                if (isMaximized) {
                    win.style.width = '80%';
                    win.style.height = '60%';
                    win.style.top = '20%';
                    win.style.left = '10%';
                    win.style.border = '1px solid var(--primary-line)';
                    win.style.borderRadius = 'var(--common-px)';
                    win.style.resize = 'both';
                    setTimeout(() => {
                        win.style.transition = 'none';
                    }, 200);
                } else {
                    win.style.width = '100%';
                    win.style.height = 'calc(100% - 48px)';
                    win.style.top = '0';
                    win.style.left = '0';
                    win.style.border = 'none';
                    win.style.borderRadius = '0';
                    win.style.resize = 'none';
                }
                isMaximized = !isMaximized;
                taskbarIcon.classList.add('active');
                bringToFront(win);
            },
            close() {
                win.style.transition = 'transform 0.3s ease-in-out, opacity 0.3s ease-in-out';
                win.style.transform = 'scale(0.1)';
                win.style.opacity = '0';
                setTimeout(() => {
                    win.remove();
                    taskbarIcon.style.transition = 'transform 0.3s ease-in, opacity 0.3s ease-in';
                    taskbarIcon.style.transform = 'translateY(100%)';
                    taskbarIcon.style.opacity = '0';
                    setTimeout(() => {
                        taskbarIcon.remove();
                    }, 300);
                    windows = windows.filter(w => w.id !== win.id);
                    delete openApps[id];
                }, 300);
            }
        };

        win.querySelectorAll('.win-header-button').forEach(button => {
            button.addEventListener('click', () => {
                actions[button.dataset.action]();
            });
        });

        taskbarIcon.addEventListener('click', () => {
            if (win.style.display === 'none') {
                win.style.display = 'block';
                setTimeout(() => {
                    win.style.transform = 'scale(1)';
                    win.style.opacity = '1';
                    taskbarIcon.classList.add('active');
                    bringToFront(win);
                }, 10);
            } else {
                actions.minimize();
            }
        });

        function bringToFront(win) {
            highestZIndex++;
            win.style.zIndex = highestZIndex;

            Object.values(openApps).forEach(window => {
                if (window !== win) {
                    window.style.zIndex = window.style.zIndex < highestZIndex ? window.style.zIndex : highestZIndex - 1;
                }
            });
        }

        taskbarIcon.classList.add('active');
        windows.push(win);
    });
}

document.querySelectorAll('[data-app]').forEach(icon => {
    if (icon.classList.contains('app-icon')) {
        const name = icon.dataset.app.replace(/^./, match => match.toUpperCase());
        app(icon.dataset.app, name, 'dblclick');
    }
    if (icon.classList.contains('start-icon')) {
        const name = icon.dataset.app.replace(/sm-(.)/, (match, letter) => letter.toUpperCase());
        app(icon.dataset.app, name, 'click');
    }
});

document.querySelectorAll('.app-icon').forEach(icon => {
    icon.addEventListener('contextmenu', (e) => {
        e.preventDefault();
        const appId = icon.dataset.app;
        contextmenu.show([
            {
                title: 'Properties',
                onClick: () => showAppProperties(appId)
            }
        ], e.clientX, e.clientY);
    });
});

function showAppProperties(appId) {
    ipcRenderer.send('getAppProperties', appId);
}

ipcRenderer.on('appProperties', (event, properties) => {
    if (properties) {
        let propertiesString = Object.entries(properties)
            .map(([key, value]) => {
                let formattedKey = key
                    .replace(/([A-Z])/g, ' $1')
                    .replace(/^./, str => str.toUpperCase());
                return `<div style="margin-bottom: 6px;"><b>${formattedKey}</b>: ${Array.isArray(value) ? value.join(', ') : value}</div>`.trim();
            })
            .join('\n');
        alert(`<h3 style="margin-bottom: 14px;">App Properties</h3>\n\n${propertiesString}`);
    } else {
        alert('Unable to fetch app properties.');
    }
});

function moment(str) {
    const date = new Date();

    return str.replace(/YYYY|MM|DD/g, match => {
        return {
            'YYYY': date.getFullYear(),
            'MM': ('0' + (date.getMonth() + 1)).slice(-2),
            'DD': ('0' + date.getDate()).slice(-2)
        }[match];
    });
}

function time() {
    const date = new Date();
    const hours = date.getHours();
    const minutes = date.getMinutes();
    const ampm = hours >= 12 ? 'PM' : 'AM';
    const formattedHours = hours % 12 || 12;
    const formattedMinutes = ('0' + minutes).slice(-2);

    return {
        hours: formattedHours,
        minutes: formattedMinutes,
        'AM-PM': ampm
    };
}

const dateTime = document.querySelector('.date-time');
const timeEl = dateTime.querySelector('.time');
const dateEl = dateTime.querySelector('.date');

setInterval(() => {
    timeEl.textContent = `${time().hours}:${time().minutes} ${time()['AM-PM']}`;
    dateEl.textContent = moment('DD/MM/YYYY');
}, 1000);

(async () => {
    const day = document.querySelector('.day');
    const temp = document.querySelector('.temp');
    let isCelsius = true;

    const ipAddress = await fetch(`https://api64.ipify.org/?format=json`);
    const ipData = await ipAddress.json();
    ipcRenderer.send('getWeather', ipData.ip);

    ipcRenderer.on('weather', (event, data) => {
        const daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
        const dayName = daysOfWeek[new Date().getDay()];
        updateInformation(dayName, data);

        temp.addEventListener('click', () => {
            isCelsius = !isCelsius;
            temp.dataset.temp = isCelsius ? 'C' : 'F';
            updateInformation(dayName, data);
        });
    });

    function updateInformation(dayName, data) {
        day.textContent = day.textContent.replace('??', dayName);
        if (isCelsius) {
            temp.textContent = `Temperature: ${data}°C`;
        } else {
            const fahrenheit = celsiusToFahrenheit(data);
            temp.textContent = `Temperature: ${Math.round(fahrenheit)}°F`;
        }
    }
})();

function celsiusToFahrenheit(celsius) {
    return (celsius * 9 / 5) + 32;
}

function showConfirmation(title, message) {
    return new Promise((resolve) => {
        const modal = document.createElement('div');
        modal.classList.add('modal');
        modal.innerHTML = `
            <div class="modal-content">
                <div class="modal-header">
                    <h2>${title}</h2>
                </div>
                <div class="modal-body">
                    <p>${message}</p>
                    <div class="modal-buttons">
                        <button class="confirm-button">Confirm</button>
                        <button class="cancel-button">Cancel</button>
                    </div>
                </div>
            </div>
        `;

        document.body.appendChild(modal);

        const confirmButton = modal.querySelector('.confirm-button');
        const cancelButton = modal.querySelector('.cancel-button');

        function closeModal(result) {
            modal.style.opacity = '0';
            setTimeout(() => {
                modal.remove();
                resolve(result);
            }, 300);
        }

        confirmButton.addEventListener('click', () => closeModal(true));
        cancelButton.addEventListener('click', () => closeModal(false));

        setTimeout(() => modal.style.opacity = '1', 10);
    });
}

function prompt(message, defaultValue = '', selectAll) {
    return new Promise((resolve) => {
        const modal = document.createElement('div');
        modal.classList.add('modal');
        modal.innerHTML = `
            <div class="modal-content">
                <div class="modal-header">
                    <h2>Prompt</h2>
                </div>
                <div class="modal-body">
                    <p>${message}</p>
                    <input type="text" class="prompt-input" value="${defaultValue}">
                    <div class="modal-buttons">
                        <button class="confirm-button">OK</button>
                        <button class="cancel-button">Cancel</button>
                    </div>
                </div>
            </div>
        `;

        document.body.appendChild(modal);

        const input = modal.querySelector('.prompt-input');
        const confirmButton = modal.querySelector('.confirm-button');
        const cancelButton = modal.querySelector('.cancel-button');

        function closeModal(result) {
            modal.style.opacity = '0';
            setTimeout(() => {
                modal.remove();
                resolve(result);
            }, 300);
        }

        confirmButton.addEventListener('click', () => closeModal(input.value));
        cancelButton.addEventListener('click', () => closeModal(null));

        input.addEventListener('keyup', (event) => {
            if (event.key === 'Enter') {
                closeModal(input.value);
            }
        });

        setTimeout(() => {
            modal.style.opacity = '1';
            input.focus();
            if (selectAll) {
                input.select();
            } else {
                const extensionIndex = defaultValue.lastIndexOf('.');
                if (extensionIndex > 0) {
                    input.setSelectionRange(0, extensionIndex);
                } else {
                    input.select();
                }
            }
        }, 10);
    });
}

function alert(message) {
    const modal = document.createElement('div');
    modal.classList.add('modal');
    modal.innerHTML = `
        <div class="modal-content">
            <div class="modal-header">
                <h2>Alert</h2>
            </div>
            <div class="modal-body">
                <p>${message}</p>
                <div class="modal-buttons">
                    <button class="confirm-button">OK</button>
                </div>
            </div>
        </div>
    `;

    document.body.appendChild(modal);

    const confirmButton = modal.querySelector('.confirm-button');

    function closeModal() {
        modal.style.opacity = '0';
        setTimeout(() => {
            modal.remove();
        }, 300);
    }

    confirmButton.addEventListener('click', closeModal);

    setTimeout(() => modal.style.opacity = '1', 10);

    return undefined;
}

const contextmenu = {
    show(options, x, y) {
        let menu = document.querySelector('.context-menu');
        if (!menu) {
            menu = document.createElement('div');
            menu.classList.add('context-menu');
            document.body.appendChild(menu);
            document.addEventListener('click', this.hide);
        }
        menu.innerHTML = '';
        menu.style.position = 'fixed';
        menu.style.zIndex = '10000';

        options.forEach(option => {
            const item = document.createElement('div');
            item.classList.add('context-menu-item');
            item.textContent = option.title;
            item.addEventListener('click', () => {
                option.onClick();
                this.hide();
            });
            menu.appendChild(item);
        });

        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;
        const menuRect = menu.getBoundingClientRect();

        if (x + menuRect.width > viewportWidth) {
            x = viewportWidth - menuRect.width;
        }
        if (y + menuRect.height > viewportHeight) {
            y = viewportHeight - menuRect.height;
        }

        menu.style.left = `${Math.max(0, x)}px`;
        menu.style.top = `${Math.max(0, y)}px`;
    },
    hide() {
        const menu = document.querySelector('.context-menu');
        if (menu) {
            menu.remove();
        }
        document.removeEventListener('click', this.hide);
    }
};

function factorial(n) {
    if (n === 0 || n === 1) return 1;
    if (n < 0) return NaN;
    let result = 1;
    for (let i = 2; i <= n; i++) result *= i;
    return result;
}

function abs(x) {
    return Math.abs(x);
}

function sqrt(x) {
    return Math.sqrt(x);
}
```

---

index.html (app):
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Files</title>
    <style>
        table {
            width: 100%;
            border-collapse: collapse;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        th, td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid var(--primary-line);
        }
        th {
            background-color: var(--primary-color);
        }
        tr:hover {
            background-color: #2e2e2e;
        }
        .toolbar {
            display: flex;
            align-items: center;
            padding: 10px;
            background-color: #1e1e1e;
            margin-bottom: var(--common-px);
        }
        .input-container {
            display: flex;
            flex-grow: 1;
            margin-left: 10px;
        }
        #pathInput {
            flex-grow: 1;
            padding: 5px;
            outline: none;
            border-radius: var(--common-px);
            border: 1px solid var(--primary-line);
            background-color: #2e2e2e;
            padding: var(--common-px);
        }
        #searchInput {
            width: 0;
            padding: 5px;
            outline: none;
            border-radius: var(--common-px);
            border: 1px solid var(--primary-line);
            background-color: #2e2e2e;
            padding: var(--common-px);
            transition: border 200ms;
        }
        #searchInput:focus {
            border-color: var(--primary-color);
        }
        .toolbar button {
            background-color: var(--secondary-color);
            border: none;
            padding: var(--common-px);
            width: 2rem;
            height: 2rem;
            margin-right: 10px;
            font-weight: bold;
            border-radius: 3px;
            transition: background 200ms;
        }
        .toolbar button:not(.toolbar button:disabled):hover {
            background-color: #2e2e2e;
        }
        .toolbar input[type="text"] {
            flex-grow: 1;
            padding: 5px;
            margin-right: 10px;
            outline: none;
            border-radius: var(--common-px);
            border: 1px solid var(--primary-line);
            background-color: #2e2e2e;
            padding: var(--common-px);
        }
        .sort-icon {
            fill: white;
            opacity: 0;
            transition: opacity 0.2s, transform 0.2s;
            margin-left: 5px;
        }
        th[data-sort].active .sort-icon {
            opacity: 1;
        }
        th[data-sort].active.asc .sort-icon {
            transform: rotate(0deg);
        }
        th[data-sort].active.desc .sort-icon {
            transform: rotate(180deg);
        }
        .selected {
            background-color: #333;
        }
        .selected:hover {
            background-color: #333;
        }
    </style>
</head>
<body>
    <div class="toolbar">
        <button id="upBtn" title="Upper directory" style="transform: rotate(90deg);">&lt;</button>
        <button id="backBtn" title="Back directory">&lt;</button>
        <button id="forwardBtn" title="Forward directory">&gt;</button>
        <button id="reload" title="Reload directory">↺</button>
        <div class="input-container">
            <input type="text" id="pathInput" readonly>
            <input type="text" id="searchInput" placeholder="Search apps...">
        </div>
    </div>
    <table>
        <thead>
            <tr>
                <th data-sort="name">Name <svg class="sort-icon" width="10" height="10" viewBox="0 0 10 10"><path d="M5 0 L10 10 L0 10 Z"/></svg></th>
                <th data-sort="size">Size <svg class="sort-icon" width="10" height="10" viewBox="0 0 10 10"><path d="M5 0 L10 10 L0 10 Z"/></svg></th>
                <th data-sort="type">Type <svg class="sort-icon" width="10" height="10" viewBox="0 0 10 10"><path d="M5 0 L10 10 L0 10 Z"/></svg></th>
                <th data-sort="lastModified">Last Modified <svg class="sort-icon" width="10" height="10" viewBox="0 0 10 10"><path d="M5 0 L10 10 L0 10 Z"/></svg></th>
            </tr>
        </thead>        
        <tbody class="files-container"></tbody>
    </table>
    <script>
        const { ipcRenderer } = require('electron');
        let currentPath = './web/root';
        let pathHistory = [];
        let currentSort = { column: 'name', direction: 'asc' };
        let lastSelectedFile = null;
        let selectedFiles = new Set();

        function createFileSystemItemElement(item) {
            const row = document.createElement('tr');
            row.innerHTML = `
                <td>${item.name}</td>
                <td>${item.size}</td>
                <td>${item.type}</td>
                <td>${item.lastModified}</td>
            `;

            row.addEventListener('click', e => handleFileSelection(e, row));

            if (item.type === 'directory') {
                row.addEventListener('dblclick', () => navigateToDirectory(item.name));
            }

            return row;
        }

        function handleFileSelection(event, row) {
            event.stopPropagation();
            if (event.ctrlKey) {
                row.classList.toggle('selected');
                if (row.classList.contains('selected')) {
                    selectedFiles.add(row);
                } else {
                    selectedFiles.delete(row);
                }
            } else if (event.shiftKey && lastSelectedFile) {
                const allRows = Array.from(document.querySelectorAll('.files-container tr'));
                const startIndex = allRows.indexOf(lastSelectedFile);
                const endIndex = allRows.indexOf(row);
                const start = Math.min(startIndex, endIndex);
                const end = Math.max(startIndex, endIndex);

                allRows.forEach((r, index) => {
                    if (index >= start && index <= end) {
                        r.classList.add('selected');
                        selectedFiles.add(r);
                    }
                });
            } else {
                deselectAllFiles();
                row.classList.add('selected');
                selectedFiles.add(row);
            }

            lastSelectedFile = row;
        }

        function handleBodyClick(event) {
            if (!event.target.closest('tr')) {
                deselectAllFiles();
            }
        }

        function deselectAllFiles() {
            selectedFiles.forEach(file => file.classList.remove('selected'));
            selectedFiles.clear();
            lastSelectedFile = null;
        }

        document.addEventListener('keydown', (event) => {
            if (event.key === 'Delete') {
                moveSelectedToTrash();
            }
        });

        function isSystemRelated(path) {
            return path.includes('/system/') || path.endsWith('/system') ||
                path.includes('/apps/') || path.endsWith('/apps') ||
                path === '.trash';
        }

        function moveSelectedToTrash() {
            if (selectedFiles.size === 0) return;

            const filesToProcess = Array.from(selectedFiles).map(row => {
                return {
                    name: row.children[0].textContent,
                    path: `${currentPath}/${row.children[0].textContent}`
                };
            }).filter(file => !isSystemRelated(file.path));

            if (filesToProcess.length === 0) {
                console.log('No valid files to process');
                return;
            }

            const trashPath = './web/root/.trash';
            const isInTrash = currentPath.includes(trashPath);

            if (isInTrash) {
                // This function is being called from 'script.js', which is evaluating all the script elements within this HTML file, so it doesn't have to be imported.
                showConfirmation('Warning', 'Are you sure you want to permanently delete these files? This action cannot be undone.').then(result => {
                    if (result) {
                        ipcRenderer.send('permanentlyDeleteFiles', filesToProcess);
                    }
                });
            } else {
                ipcRenderer.send('moveToTrash', filesToProcess, trashPath);
            }

            ipcRenderer.send('getFiles', currentPath);
        }

        ipcRenderer.on('movedToTrash', (event, success) => {
            if (success) {
                ipcRenderer.send('getFiles', currentPath);
            } else {
                console.error('Failed to move files to trash');
            }
        });

        ipcRenderer.on('refreshDirectory', () => {
            ipcRenderer.send('getFiles', currentPath);
        });

        let forwardHistory = [];

        function navigateToDirectory(dirName) {
            pathHistory.push(currentPath);
            forwardHistory = [];
            currentPath = `${currentPath}/${dirName}`;
            updatePath();
            ipcRenderer.send('getFiles', currentPath);
            updateNavigationButtons();
        }

        function goUp() {
            if (currentPath !== './web/root') {
                pathHistory.push(currentPath);
                forwardHistory = [];
                currentPath = currentPath.split('/').slice(0, -1).join('/');
                updatePath();
                ipcRenderer.send('getFiles', currentPath);
                updateNavigationButtons();
            }
        }

        function goBack() {
            if (pathHistory.length > 0) {
                forwardHistory.push(currentPath);
                currentPath = pathHistory.pop();
                updatePath();
                ipcRenderer.send('getFiles', currentPath);
                updateNavigationButtons();
            }
        }

        function goForward() {
            if (forwardHistory.length > 0) {
                pathHistory.push(currentPath);
                currentPath = forwardHistory.pop();
                updatePath();
                ipcRenderer.send('getFiles', currentPath);
                updateNavigationButtons();
            }
        }

        function updatePath() {
            document.getElementById('pathInput').value = currentPath.replace('./web', ''); // Begin from '/root' instead of '/web'
        }

        function isDirectoryEmpty() {
            const filesContainer = document.querySelector('.files-container');
            return filesContainer.children.length === 1 && filesContainer.children[0].textContent.includes('This directory has no content');
        }

        function searchApps() {
            const searchTerm = document.getElementById('searchInput').value.toLowerCase();
            const filesContainer = document.querySelector('.files-container');

            if (isDirectoryEmpty()) {
                filesContainer.innerHTML = '<tr><td colspan="4" style="text-align: center;">Cannot search in an empty directory.</td></tr>';
                return;
            }

            if (searchTerm === '') {
                ipcRenderer.send('getFiles', currentPath);
                return;
            }

            let visibleApps = 0;

            Array.from(filesContainer.children).forEach(row => {
                if (row.children.length >= 3) {
                    const name = row.children[0].textContent.toLowerCase();
                    const isApp = row.children[2].textContent === 'directory';
                    if (isApp && name.includes(searchTerm)) {
                        row.style.display = '';
                        visibleApps++;
                    } else {
                        row.style.display = 'none';
                    }
                }
            });

            if (visibleApps === 0) {
                filesContainer.innerHTML = '<tr><td colspan="4" style="text-align: center;">No results found.</td></tr>';
            }
        }

        function refreshDirectory() {
            ipcRenderer.send('getFiles', currentPath);
        }

        document.getElementById('upBtn').addEventListener('click', goUp);
        document.getElementById('backBtn').addEventListener('click', goBack);
        document.getElementById('forwardBtn').addEventListener('click', goForward);
        document.getElementById('searchInput').addEventListener('input', searchApps);
        document.getElementById('reload').addEventListener('click', refreshDirectory);

        document.addEventListener('keydown', e => {
            if (e.altKey) {
                switch (e.key) {
                    case 'ArrowLeft':
                        goBack();
                        break;
                    case 'ArrowRight':
                        goForward();
                        break;
                    case 'ArrowUp':
                        goUp();
                        break;
                }
            }
        });

        updatePath();

        function updateNavigationButtons() {
            document.getElementById('backBtn').disabled = pathHistory.length === 0;
            document.getElementById('forwardBtn').disabled = forwardHistory.length === 0;
            document.getElementById('upBtn').disabled = currentPath === './web/root';
        }

        updateNavigationButtons();

        function sortFiles(column) {
            const filesContainer = document.querySelector('.files-container');
            const files = Array.from(filesContainer.children);

            files.sort((a, b) => {
                const aValue = a.children[getColumnIndex(column)].textContent;
                const bValue = b.children[getColumnIndex(column)].textContent;

                if (column === 'size') {
                    return currentSort.direction === 'asc'
                        ? parseFloat(aValue) - parseFloat(bValue)
                        : parseFloat(bValue) - parseFloat(aValue);
                } else {
                    return currentSort.direction === 'asc'
                        ? aValue.localeCompare(bValue)
                        : bValue.localeCompare(aValue);
                }
            });

            filesContainer.innerHTML = '';
            files.forEach(file => filesContainer.appendChild(file));

            if (currentSort.column === column) {
                currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc';
            } else {
                currentSort = { column, direction: 'asc' };
            }

            document.querySelectorAll('th[data-sort]').forEach(th => {
                th.classList.remove('active', 'asc', 'desc');
            });
            const activeHeader = document.querySelector(`th[data-sort="${column}"]`);
            activeHeader.classList.add('active', currentSort.direction);
        }

        function getColumnIndex(column) {
            const columns = ['name', 'size', 'type', 'lastModified'];
            return columns.indexOf(column);
        }

        function renderFileList(filesAndFolders) {
            const container = document.querySelector('.files-container');
            container.innerHTML = '';

            if (filesAndFolders.length === 0) {
                const emptyRow = document.createElement('tr');
                emptyRow.innerHTML = '<td colspan="4" style="text-align: center;">This directory has no content.</td>';
                container.appendChild(emptyRow);
            } else {
                filesAndFolders.forEach(item => {
                    container.appendChild(createFileSystemItemElement(item));
                });

                sortFiles(currentSort.column);
            }

            selectedFiles.clear();
            lastSelectedFile = null;
        }

        document.querySelectorAll('th[data-sort]').forEach(th => {
            th.addEventListener('click', () => {
                const column = th.dataset.sort;
                sortFiles(column);
            });
        });

        document.body.addEventListener('click', handleBodyClick);

        ipcRenderer.send('getFiles', currentPath);

        ipcRenderer.on('files', (event, filesAndFolders) => {
            renderFileList(filesAndFolders);
        });

        ipcRenderer.on('files-error', (event, errorMessage) => {
            console.error('Error getting files:', errorMessage);
            const container = document.querySelector('.files-container');
            container.innerHTML = `<tr><td colspan="4">Error: ${errorMessage}</td></tr>`;
        });

        function checkInvalidCharacters(input) {
            const invalidChars = ['"', "'", '\\', '/', ':', '*', '?', '<', '>', '|'];
            for (let char of invalidChars) {
                if (input.includes(char)) {
                    return char;
                }
            }
            return null;
        }

        const toolbar = document.querySelector('.toolbar');

        toolbar.closest('.win-content').addEventListener('contextmenu', e => {
            e.preventDefault();
            const target = e.target.closest('tr:not(.no-results-row)');
            const isInTrash = currentPath.includes('.trash');

            const isMessageRow = e.target.closest('td[colspan="4"]');
            if (isMessageRow) return;

            let options;

            function showInputDialog(title, placeholder, callback) {
                const input = prompt(title, placeholder);
                if (input !== null) {
                    callback(input);
                }
            }

            async function createNewFile() {
                const fileName = await prompt('Create new file', 'Enter file name', true);
                if (fileName) {
                    const invalidChar = checkInvalidCharacters(fileName);
                    if (invalidChar) {
                        alert(`Invalid character used: "${invalidChar}". Please avoid using special characters in file names.`);
                        return;
                    }
                    const filePath = `${currentPath}/${fileName}`;
                    const exists = await ipcRenderer.invoke('checkItemExists', filePath);
                    if (exists) {
                        alert('A file with this name already exists. Please choose a different name.');
                        return;
                    }
                    ipcRenderer.send('createFile', currentPath, fileName);
                }
            }

            async function createNewDirectory() {
                const dirName = await prompt('Create new directory', 'Enter directory name', true);
                if (dirName) {
                    const invalidChar = checkInvalidCharacters(dirName);
                    if (invalidChar) {
                        alert(`Invalid character used: "${invalidChar}". Please avoid using special characters in directory names.`);
                        return;
                    }
                    const dirPath = `${currentPath}/${dirName}`;
                    const exists = await ipcRenderer.invoke('checkItemExists', dirPath);
                    if (exists) {
                        alert('A directory with this name already exists. Please choose a different name.');
                        return;
                    }
                    ipcRenderer.send('createDirectory', currentPath, dirName);
                }
            }

            async function renameItem(oldName) {
                const newName = await prompt('Rename item', oldName, true);
                if (newName) {
                    const invalidChar = checkInvalidCharacters(newName);
                    if (invalidChar) {
                        alert(`Invalid character used: "${invalidChar}". Please avoid using special characters in names.`);
                        return;
                    }
                    const newPath = `${currentPath}/${newName}`;
                    const exists = await ipcRenderer.invoke('checkItemExists', newPath);
                    if (exists) {
                        alert('An item with this name already exists. Please choose a different name.');
                        return;
                    }
                    const oldPath = `${currentPath}/${oldName}`;
                    ipcRenderer.send('renameItem', oldPath, newPath);
                }
            }

            function emptyTrash() {
                showConfirmation('Warning', 'Are you sure you want to permanently delete all files in the trash? This action cannot be undone.')
                    .then(result => {
                        if (result) {
                            ipcRenderer.send('emptyTrash', currentPath);
                        }
                    });
            }

            ipcRenderer.on('trashEmptied', (event, success) => {
                if (success) {
                    ipcRenderer.send('getFiles', currentPath);
                } else {
                    console.error('Failed to empty trash');
                }
            });

            if (target) {
                const fileName = target.querySelector('td').textContent;
                const filePath = `${currentPath}/${fileName}`;
                options = [
                    {
                        title: 'Copy path',
                        onClick: () => {
                            const filePath = `${currentPath}/${fileName}`;
                            navigator.clipboard.writeText(filePath.replace('./web', '')).then(() => {
                                console.log('Path copied to clipboard');
                            }).catch(err => {
                                console.error('Failed to copy path: ', err);
                            });
                        }
                    }
                ];

                if (!isSystemRelated(filePath) && fileName !== '.trash') {
                    options.unshift({
                        title: isInTrash ? 'Permanently Delete' : 'Delete',
                        onClick: () => {
                            if (isInTrash) {
                                showConfirmation('Warning', 'Are you sure you want to permanently delete this file? This action cannot be undone.').then(result => {
                                    if (result) {
                                        ipcRenderer.send('permanentlyDeleteFiles', [{
                                            name: fileName,
                                            path: `${currentPath}/${fileName}`
                                        }]);
                                    }
                                });
                            } else {
                                ipcRenderer.send('moveToTrash', [{
                                    name: fileName,
                                    path: `${currentPath}/${fileName}`
                                }], './web/root/.trash');
                            }
                        }
                    });
                    options.unshift({
                        title: 'Rename',
                        onClick: () => renameItem(fileName)
                    });
                }
            } else {
                options = [];
                if (!currentPath.includes('.trash')) {
                    options.push(
                        {
                            title: 'Create new file',
                            onClick: createNewFile
                        },
                        {
                            title: 'Create new directory',
                            onClick: createNewDirectory
                        }
                    );
                }
            
                if (currentPath.includes('.trash')) {
                    options.push({
                        title: 'Empty trash',
                        onClick: emptyTrash
                    });
                }
            }

            ipcRenderer.on('fileCreated', (event, success) => {
                if (success) {
                    ipcRenderer.send('getFiles', currentPath);
                } else {
                    console.error('Failed to create file');
                }
            });

            ipcRenderer.on('directoryCreated', (event, success) => {
                if (success) {
                    ipcRenderer.send('getFiles', currentPath);
                } else {
                    console.error('Failed to create directory');
                }
            });

            ipcRenderer.on('itemRenamed', (event, success) => {
                if (success) {
                    ipcRenderer.send('getFiles', currentPath);
                } else {
                    console.error('Failed to rename item');
                }
            });

            contextmenu.show(options, e.clientX, e.clientY);
        });
    </script>
</body>
</html>
```

---

I want to make selected items draggable to change their directory (when dropped in another folder). For brevity, write changes only