| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- const terminal = document.getElementById('terminal');
- const titlebar = document.getElementById('titlebar');
- const startBtn = document.getElementById('tb-start');
- const startMenu = document.getElementById('startmenu');
- const tbWinItem = document.getElementById('tb-terminal-item');
- const smTermLaunch = document.getElementById('sm-terminal-launch');
- const MIN_W = 320, MIN_H = 160;
- let winState = 'normal';
- let savedRect = null;
- let menuOpen = false;
- function saveRect() {
- savedRect = {
- left: terminal.offsetLeft,
- top: terminal.offsetTop,
- width: terminal.offsetWidth,
- height: terminal.offsetHeight,
- };
- }
- function setWinState(s) {
- winState = s;
- updateTaskbarItem();
- }
- function updateTaskbarItem() {
- const indicator = tbWinItem.querySelector('.tb-win-indicator');
- const closed = winState === 'closed';
- tbWinItem.classList.toggle('tb-item-active', winState === 'normal' || winState === 'maximized');
- tbWinItem.classList.toggle('tb-item-minimized', winState === 'minimized');
- tbWinItem.classList.toggle('tb-item-closed', closed);
- indicator.style.opacity = closed ? '0' : '1';
- }
- function restoreWindow() {
- terminal.style.display = '';
- terminal.classList.remove('maximized');
- if (savedRect) {
- terminal.style.left = savedRect.left + 'px';
- terminal.style.top = savedRect.top + 'px';
- terminal.style.width = savedRect.width + 'px';
- terminal.style.height = savedRect.height + 'px';
- } else {
- centerWindow();
- }
- setWinState('normal');
- }
- function centerWindow() {
- terminal.style.left = Math.round(window.innerWidth / 2 - terminal.offsetWidth / 2) + 'px';
- terminal.style.top = Math.round((window.innerHeight - 44) / 2 - terminal.offsetHeight / 2) + 'px';
- }
- centerWindow();
- updateTaskbarItem();
- function toggleMenu(e) {
- e.stopPropagation();
- menuOpen = !menuOpen;
- startMenu.classList.toggle('open', menuOpen);
- startMenu.setAttribute('aria-hidden', String(!menuOpen));
- startBtn.classList.toggle('active', menuOpen);
- }
- startBtn.addEventListener('click', toggleMenu);
- document.addEventListener('click', (e) => {
- if (menuOpen && !startMenu.contains(e.target) && e.target !== startBtn) {
- menuOpen = false;
- startMenu.classList.remove('open');
- startMenu.setAttribute('aria-hidden', 'true');
- startBtn.classList.remove('active');
- }
- });
- startMenu.querySelectorAll('a').forEach(a => {
- a.addEventListener('click', () => {
- menuOpen = false;
- startMenu.classList.remove('open');
- startBtn.classList.remove('active');
- });
- });
- smTermLaunch.addEventListener('click', () => {
- menuOpen = false;
- startMenu.classList.remove('open');
- startBtn.classList.remove('active');
- if (winState === 'closed' || winState === 'minimized') {
- restoreWindow();
- } else if (winState === 'normal' || winState === 'maximized') {
- terminal.classList.add('flash');
- setTimeout(() => terminal.classList.remove('flash'), 300);
- }
- });
- tbWinItem.addEventListener('click', () => {
- if (winState === 'closed') {
- restoreWindow();
- } else if (winState === 'minimized') {
- restoreWindow();
- } else if (winState === 'normal' || winState === 'maximized') {
- saveRect();
- terminal.style.display = 'none';
- setWinState('minimized');
- }
- });
- document.getElementById('btn-close').addEventListener('click', () => {
- saveRect();
- terminal.style.display = 'none';
- setWinState('closed');
- });
- document.getElementById('btn-minimize').addEventListener('click', () => {
- if (winState === 'minimized') return;
- if (winState !== 'maximized') saveRect();
- terminal.style.display = 'none';
- setWinState('minimized');
- });
- document.getElementById('btn-maximize').addEventListener('click', toggleMaximize);
- titlebar.addEventListener('dblclick', (e) => {
- if (e.target.closest('.wm-btn')) return;
- toggleMaximize();
- });
- function toggleMaximize() {
- if (winState === 'maximized') {
- winState = 'normal';
- terminal.classList.remove('maximized');
- if (savedRect) {
- terminal.style.left = savedRect.left + 'px';
- terminal.style.top = savedRect.top + 'px';
- terminal.style.width = savedRect.width + 'px';
- terminal.style.height = savedRect.height + 'px';
- }
- setWinState('normal');
- } else {
- saveRect();
- terminal.classList.add('maximized');
- terminal.style.left = '0';
- terminal.style.top = '0';
- terminal.style.width = '100vw';
- terminal.style.height = 'calc(100vh - 44px)';
- setWinState('maximized');
- }
- }
- let dragging = false, dragSX, dragSY, dragL, dragT;
- titlebar.addEventListener('mousedown', (e) => {
- if (e.target.closest('.wm-btn') || winState === 'maximized') return;
- dragging = true;
- dragSX = e.clientX; dragSY = e.clientY;
- dragL = terminal.offsetLeft; dragT = terminal.offsetTop;
- titlebar.style.cursor = 'grabbing';
- e.preventDefault();
- });
- document.addEventListener('mousemove', (e) => {
- if (dragging) {
- terminal.style.left = (dragL + e.clientX - dragSX) + 'px';
- terminal.style.top = (dragT + e.clientY - dragSY) + 'px';
- }
- if (resizing) doResize(e.clientX, e.clientY);
- });
- document.addEventListener('mouseup', () => {
- dragging = false;
- titlebar.style.cursor = 'grab';
- stopResize();
- });
- let resizing = false, resDir = '', resStart = {};
- document.querySelectorAll('.resize-handle').forEach(h => {
- h.addEventListener('mousedown', (e) => {
- if (winState === 'maximized') return;
- resizing = true;
- resDir = h.dataset.dir;
- resStart = { mx: e.clientX, my: e.clientY,
- left: terminal.offsetLeft, top: terminal.offsetTop,
- width: terminal.offsetWidth, height: terminal.offsetHeight };
- document.body.style.cursor = getComputedStyle(h).cursor;
- e.preventDefault();
- });
- });
- function doResize(mx, my) {
- const dx = mx - resStart.mx, dy = my - resStart.my;
- let { left, top, width, height } = resStart;
- if (resDir.includes('e')) width = Math.max(MIN_W, width + dx);
- if (resDir.includes('s')) height = Math.max(MIN_H, height + dy);
- if (resDir.includes('w')) { const nw = Math.max(MIN_W, width-dx); left = left + width - nw; width = nw; }
- if (resDir.includes('n')) { const nh = Math.max(MIN_H, height-dy); top = top + height - nh; height = nh; }
- terminal.style.left = left + 'px';
- terminal.style.top = top + 'px';
- terminal.style.width = width + 'px';
- terminal.style.height = height + 'px';
- }
- function stopResize() {
- if (resizing) { resizing = false; document.body.style.cursor = ''; }
- }
- function updateClock() {
- const now = new Date();
- const hh = String(now.getHours()).padStart(2,'0');
- const mm = String(now.getMinutes()).padStart(2,'0');
- const days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
- const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
- document.getElementById('tb-time').textContent = `${hh}:${mm}`;
- document.getElementById('tb-date').textContent =
- `${days[now.getDay()]} ${String(now.getDate()).padStart(2,'0')} ${months[now.getMonth()]}`;
- }
- updateClock();
- setInterval(updateClock, 10000);
|