dev-ghpages/windows7.html

273 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Windows 7 Explorer Demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/khang-nd/7.css/7.css">
<style>
:root{--taskbar-height:56px;--text:#eaf2ff;--muted:#bdd3f2;--accent:#2b579a;--bg1:#071827;--bg2:#0b2b49;}
*{box-sizing:border-box}
html,body{height:100%;margin:0;font-family:"Segoe UI",Arial,sans-serif;background:linear-gradient(135deg,var(--bg1),var(--bg2));color:var(--text)}
.wallpaper{position:absolute;inset:0;pointer-events:none;display:flex;align-items:center;justify-content:center}
.logo{width:620px;height:300px;opacity:.07;filter:blur(18px);background:linear-gradient(90deg,#00a2ff,#2baf2b,#ffb400,#ff3b30);border-radius:16px;transform:rotate(-8deg)}
.win7-window{position:absolute;top:70px;left:70px;width:min(1040px,calc(100% - 140px));height:min(640px,calc(100% - 160px));display:flex;flex-direction:column;background:rgba(4,10,20,.65);border:1px solid rgba(255,255,255,.1);border-radius:10px;box-shadow:0 20px 56px rgba(0,0,0,.6);overflow:hidden}
.titlebar{display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1px solid rgba(255,255,255,.08);background:linear-gradient(180deg,rgba(255,255,255,.08),rgba(255,255,255,.02))}
.title{font-weight:700}
.controls{margin-left:auto;display:flex;gap:8px}.btn{width:44px;height:30px;border:0;border-radius:6px;cursor:pointer;font-weight:700}
.btn.min{background:#dcecff}.btn.max{background:#2d8ad9;color:#fff}.btn.close{background:#d44f4f;color:#fff}
.toolbar{display:flex;flex-wrap:wrap;gap:8px;padding:10px 12px;border-bottom:1px solid rgba(255,255,255,.08)}
.toolbar button{border:1px solid rgba(255,255,255,.24);background:rgba(255,255,255,.08);color:var(--text);border-radius:6px;padding:6px 10px;cursor:pointer}
.pathbar{display:flex;align-items:center;gap:4px;padding:8px 12px;font-size:13px;background:rgba(0,0,0,.18);border-bottom:1px solid rgba(255,255,255,.08)}
.crumb{color:#d8ebff;cursor:pointer}.crumb:hover{text-decoration:underline}
.content{display:grid;grid-template-columns:230px 1fr;gap:12px;padding:12px;height:100%}
.sidebar,.main{border-radius:8px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1)}
.sidebar{padding:12px}.sidebar h4{margin:0 0 10px 0}.tree-node{padding:7px;border-radius:6px;cursor:pointer}.tree-node:hover{background:rgba(255,255,255,.08)}
.main{display:flex;flex-direction:column;overflow:hidden}
.list{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px;padding:12px;overflow:auto}
.item{padding:10px;border-radius:8px;background:rgba(6,16,30,.6);border:1px solid rgba(255,255,255,.12);cursor:pointer;user-select:none}
.item.selected{outline:2px solid #8ec5ff}.item-name{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.item-meta{font-size:12px;color:var(--muted);margin-top:5px}
.status{padding:8px 12px;font-size:12px;color:var(--muted);border-top:1px solid rgba(255,255,255,.08)}
.taskbar{position:fixed;left:8px;right:8px;bottom:8px;height:var(--taskbar-height);display:flex;align-items:center;justify-content:space-between;padding:8px 10px;border-radius:12px;background:linear-gradient(180deg,rgba(6,13,25,.65),rgba(3,7,14,.85));box-shadow:0 12px 40px rgba(0,0,0,.6)}
.taskbar-left{display:flex;align-items:center;gap:10px}
.start{display:flex;align-items:center;gap:8px}.orb{width:34px;height:34px;border-radius:8px;background:linear-gradient(135deg,#2fb3ff,#ffd05a)}
.taskbar-app{border:1px solid rgba(255,255,255,.32);background:rgba(255,255,255,.12);color:var(--text);padding:8px 12px;border-radius:8px;cursor:pointer}
.taskbar-app.active{background:rgba(142,197,255,.35)}
@media (max-width:900px){.content{grid-template-columns:1fr}.sidebar{display:none}.win7-window{left:16px;top:20px;width:calc(100% - 32px);height:calc(100% - 90px)}}
</style>
</head>
<body>
<div class="wallpaper"><div class="logo"></div></div>
<section class="win7-window" aria-label="Windows Explorer">
<div class="titlebar">
<div style="width:28px;height:28px;border-radius:6px;background:var(--accent);display:grid;place-items:center;">📁</div>
<div class="title">Windows Explorer — Music Library</div>
<div class="controls">
<button class="btn min" id="min-btn"></button>
<button class="btn max" id="max-btn"></button>
<button class="btn close" id="close-btn"></button>
</div>
</div>
<div class="toolbar">
<button id="up-btn">Up</button>
<button id="new-folder-btn">New Folder</button>
<button id="new-file-btn">New Text File</button>
<button id="rename-btn">Rename</button>
<button id="delete-btn">Delete</button>
</div>
<div class="pathbar" id="pathbar"></div>
<div class="content">
<aside class="sidebar">
<h4>Libraries</h4>
<div class="tree-node" data-path="/">🖥️ Computer</div>
<div class="tree-node" data-path="/Music">🎵 Music</div>
<div class="tree-node" data-path="/Music/NewJeans">💿 NewJeans</div>
<div class="tree-node" data-path="/Music/Blackpink">💿 Blackpink</div>
</aside>
<main class="main">
<div class="list" id="file-list"></div>
<div class="status" id="status">Ready</div>
</main>
</div>
</section>
<div class="taskbar">
<div class="taskbar-left">
<div class="start"><div class="orb"></div><strong>Start</strong></div>
<button class="taskbar-app active" id="explorer-taskbar-btn">📁 Windows Explorer</button>
</div>
<div id="clock"></div>
</div>
<script>
const fs = {
type: 'folder',
children: {
Music: {
type: 'folder',
children: {
NewJeans: {
type: 'folder',
children: {
'Attention.mp3': { type: 'file', size: '7.0 MB' },
'Hype Boy.mp3': { type: 'file', size: '6.8 MB' },
'Ditto.mp3': { type: 'file', size: '7.2 MB' },
'OMG.mp3': { type: 'file', size: '6.5 MB' },
'Super Shy.mp3': { type: 'file', size: '6.2 MB' }
}
},
Blackpink: {
type: 'folder',
children: {
'DDU-DU DDU-DU.mp3': { type: 'file', size: '7.3 MB' },
'How You Like That.mp3': { type: 'file', size: '7.1 MB' },
'Kill This Love.mp3': { type: 'file', size: '7.0 MB' },
'Pink Venom.mp3': { type: 'file', size: '6.9 MB' },
'Shut Down.mp3': { type: 'file', size: '6.7 MB' }
}
}
}
}
}
};
const fileList = document.getElementById('file-list');
const pathBar = document.getElementById('pathbar');
const status = document.getElementById('status');
let currentPath = ['/'];
let selectedName = null;
const normalize = (path) => path === '/' ? ['/'] : ['/', ...path.split('/').filter(Boolean)];
function getNode(pathArr) {
let node = fs;
for (const part of pathArr.slice(1)) {
if (!node.children || !node.children[part]) return null;
node = node.children[part];
}
return node;
}
function openPath(path) {
const target = normalize(path);
if (getNode(target)?.type !== 'folder') return;
currentPath = target;
selectedName = null;
render();
}
function renderPath() {
pathBar.innerHTML = '';
let built = '';
currentPath.forEach((part, i) => {
built = i === 0 ? '/' : `${built === '/' ? '' : built}/${part}`;
const crumb = document.createElement('span');
crumb.className = 'crumb';
crumb.textContent = i === 0 ? 'Computer' : part;
crumb.onclick = () => openPath(built);
pathBar.appendChild(crumb);
if (i < currentPath.length - 1) pathBar.append(' ');
});
}
function renderList() {
const folder = getNode(currentPath);
const entries = Object.entries(folder.children || {}).sort((a, b) => a[0].localeCompare(b[0]));
fileList.innerHTML = '';
for (const [name, node] of entries) {
const el = document.createElement('article');
el.className = `item${selectedName === name ? ' selected' : ''}`;
el.innerHTML = `<div class="item-name">${node.type === 'folder' ? '📁' : '🎵'} ${name}</div>
<div class="item-meta">${node.type === 'folder' ? 'File Folder' : node.size}</div>`;
el.onclick = () => {
selectedName = name;
renderList();
status.textContent = `${name} selected`;
};
el.ondblclick = () => {
if (node.type === 'folder') openPath(`${currentPath.join('/').replace('//', '/')}/${name}`);
else status.textContent = `Now playing: ${name}`;
};
fileList.appendChild(el);
}
status.textContent = `${entries.length} item(s) in ${currentPath[currentPath.length - 1] === '/' ? 'Computer' : currentPath[currentPath.length - 1]}`;
}
function render() {
renderPath();
renderList();
}
function parentPath() {
if (currentPath.length === 1) return ['/'];
return currentPath.slice(0, -1);
}
document.getElementById('up-btn').onclick = () => { currentPath = parentPath(); selectedName = null; render(); };
document.getElementById('new-folder-btn').onclick = () => {
const name = prompt('Folder name?');
if (!name) return;
const node = getNode(currentPath);
if (node.children[name]) return alert('Name already exists.');
node.children[name] = { type: 'folder', children: {} };
render();
};
document.getElementById('new-file-btn').onclick = () => {
const name = prompt('Text file name?', 'New File.txt');
if (!name) return;
const node = getNode(currentPath);
if (node.children[name]) return alert('Name already exists.');
node.children[name] = { type: 'file', size: '1 KB' };
render();
};
document.getElementById('rename-btn').onclick = () => {
if (!selectedName) return alert('Select a file or folder first.');
const node = getNode(currentPath);
const next = prompt('Rename to?', selectedName);
if (!next || next === selectedName) return;
if (node.children[next]) return alert('Name already exists.');
node.children[next] = node.children[selectedName];
delete node.children[selectedName];
selectedName = next;
render();
};
document.getElementById('delete-btn').onclick = () => {
if (!selectedName) return alert('Select a file or folder first.');
const node = getNode(currentPath);
delete node.children[selectedName];
selectedName = null;
render();
};
const windowEl = document.querySelector('.win7-window');
const explorerTaskbarBtn = document.getElementById('explorer-taskbar-btn');
function showExplorerWindow() {
if (!document.body.contains(windowEl)) return;
windowEl.style.display = 'flex';
explorerTaskbarBtn.classList.add('active');
status.textContent = 'Explorer restored';
}
function minimizeExplorerWindow() {
if (!document.body.contains(windowEl)) return;
windowEl.style.display = 'none';
explorerTaskbarBtn.classList.remove('active');
}
document.querySelectorAll('.tree-node').forEach((item) => item.onclick = () => openPath(item.dataset.path));
document.getElementById('close-btn').onclick = () => {
windowEl.remove();
explorerTaskbarBtn.disabled = true;
explorerTaskbarBtn.classList.remove('active');
explorerTaskbarBtn.textContent = '📁 Windows Explorer (Closed)';
};
document.getElementById('min-btn').onclick = () => minimizeExplorerWindow();
explorerTaskbarBtn.onclick = () => {
if (windowEl.style.display === 'none') showExplorerWindow();
else minimizeExplorerWindow();
};
document.getElementById('max-btn').onclick = () => {
const w = document.querySelector('.win7-window');
if (!w.dataset.maxed) {
w.dataset.maxed = '1';
w.style.top = '8px'; w.style.left = '8px'; w.style.width = 'calc(100% - 16px)'; w.style.height = 'calc(100% - 80px)';
} else {
delete w.dataset.maxed;
w.style.top = '70px'; w.style.left = '70px'; w.style.width = 'min(1040px,calc(100% - 140px))'; w.style.height = 'min(640px,calc(100% - 160px))';
}
};
const clock = document.getElementById('clock');
setInterval(() => clock.textContent = new Date().toLocaleString(), 500);
render();
</script>
</body>
</html>