|
|
typescript |
|
|
|
|
|
const sounds: { [key: string]: HTMLAudioElement } = { |
|
|
click: new Audio('data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA='), |
|
|
select: new Audio('data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA='), |
|
|
hover: new Audio('data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=') |
|
|
}; |
|
|
|
|
|
|
|
|
Object.values(sounds).forEach(sound => { |
|
|
sound.volume = 0.1; |
|
|
}); |
|
|
|
|
|
function playSound(type: string): void { |
|
|
if (sounds[type]) { |
|
|
sounds[type].play().catch(e => console.log('Sound play failed:', e)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function scrollToSection(sectionId: string): void { |
|
|
playSound('click'); |
|
|
const element = document.getElementById(sectionId); |
|
|
if (element) { |
|
|
element.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
interface ModalContent { |
|
|
[key: string]: { |
|
|
title: string; |
|
|
content: string; |
|
|
}; |
|
|
} |
|
|
|
|
|
const modalData: ModalContent = { |
|
|
telemetry: { |
|
|
title: 'Отключение телеметрии Windows 11', |
|
|
content: ` |
|
|
<div class="space-y-4"> |
|
|
<h4 class="text-xl font-bold text-rose-500">Шаг за шагом:</h4> |
|
|
<ol class="list-decimal list-inside space-y-3 text-gray-300"> |
|
|
<li>Откройте Параметры (Win + I)</li> |
|
|
<li>Перейдите в "Конфиденциальность и безопасность"</li> |
|
|
<li>Выберите "Диагностика и отзывы"</li> |
|
|
<li>В разделе "Диагностические данные" выберите "Требуемые данные устройства"</li> |
|
|
<li>Отключите "Отправка дополнительных данных об использовании"</li> |
|
|
<li>В разделе "Отзыв о работе" отключите все опции</li> |
|
|
<li>Перейдите в "Журнал активности" и отключите хранение истории</li> |
|
|
</ol> |
|
|
<div class="bg-yellow-900/30 border border-yellow-500/50 rounded-lg p-4 mt-4"> |
|
|
<p class="text-yellow-300">⚠️ Внимание: После этих изменений некоторые функции Windows могут работать ограниченно</p> |
|
|
</div> |
|
|
</div> |
|
|
` |
|
|
}, |
|
|
apps: { |
|
|
title: 'Управление доступом приложений', |
|
|
content: ` |
|
|
<div class="space-y-4"> |
|
|
<h4 class="text-xl font-bold text-yellow-500">Настройки доступа:</h4> |
|
|
<div class="space-y-3"> |
|
|
<div class="bg-gray-700 rounded-lg p-3"> |
|
|
<h5 class="font-semibold mb-2">📷 Камера</h5> |
|
|
<p class="text-gray-300 text-sm">Параметры → Конфиденциальность → Камера → Отключите "Разрешить приложениям доступ к камере"</p> |
|
|
</div> |
|
|
<div class="bg-gray-700 rounded-lg p-3"> |
|
|
<h5 class="font-semibold mb-2">🎤 Микрофон</h5> |
|
|
<p class="text-gray-300 text-sm">Параметры → Конфиденциальность → Микрофон → Отключите доступ для ненужных приложений</p> |
|
|
</div> |
|
|
<div class="bg-gray-700 rounded-lg p-3"> |
|
|
<h5 class="font-semibold mb-2">📍 Местоположение</h5> |
|
|
<p class="text-gray-300 text-sm">Параметры → Конфиденциальность → Местоположение → Отключите службы определения местоположения</p> |
|
|
</div> |
|
|
<div class="bg-gray-700 rounded-lg p-3"> |
|
|
<h5 class="font-semibold mb-2">📊 Рекламный идентификатор</h5> |
|
|
<p class="text-gray-300 text-sm">Параметры → Конфиденциальность → Общие → Отключите "Разрешить приложениям использовать рекламный идентификатор"</p> |
|
|
</div> |
|
|
</div> |
|
|
<button onclick="executeCommand('gpedit.msc')" class="mt-4 px-4 py-2 bg-rose-600 hover:bg-rose-700 rounded-lg transition-colors"> |
|
|
Открыть Редактор групповой политики |
|
|
</button> |
|
|
</div> |
|
|
` |
|
|
} |
|
|
}; |
|
|
|
|
|
function showModal(type: string): void { |
|
|
playSound('click'); |
|
|
const modal = document.getElementById('modal') as HTMLElement; |
|
|
const title = document.getElementById('modal-title') as HTMLElement; |
|
|
const content = document.getElementById('modal-content') as HTMLElement; |
|
|
|
|
|
if (modal && title && content && modalData[type]) { |
|
|
title.textContent = modalData[type].title; |
|
|
content.innerHTML = modalData[type].content; |
|
|
modal.classList.remove('hidden'); |
|
|
document.body.style.overflow = 'hidden'; |
|
|
|
|
|
|
|
|
setTimeout(() => feather.replace(), 100); |
|
|
} |
|
|
} |
|
|
|
|
|
function closeModal(): void { |
|
|
playSound('click'); |
|
|
const modal = document.getElementById('modal') as HTMLElement; |
|
|
if (modal) { |
|
|
modal.classList.add('hidden'); |
|
|
document.body.style.overflow = 'auto'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
document.getElementById('modal')?.addEventListener('click', (e: MouseEvent) => { |
|
|
if (e.target === e.currentTarget) { |
|
|
closeModal(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
function executeCommand(command: string): void { |
|
|
playSound('select'); |
|
|
alert(`В реальном приложении здесь был бы выполнен запуск: ${command}`); |
|
|
} |
|
|
|
|
|
|
|
|
const observerOptions = { |
|
|
threshold: 0.1, |
|
|
rootMargin: '0px 0px -50px 0px' |
|
|
}; |
|
|
|
|
|
const observer = new IntersectionObserver((entries: IntersectionObserverEntry[]) => { |
|
|
entries.forEach(entry => { |
|
|
if (entry.isIntersecting) { |
|
|
entry.target.classList.add('animate-fade-in'); |
|
|
observer.unobserve(entry.target); |
|
|
} |
|
|
}); |
|
|
}, observerOptions); |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
document.querySelectorAll('section').forEach(section => { |
|
|
observer.observe(section); |
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelectorAll('button').forEach(button => { |
|
|
button.addEventListener('mouseenter', () => playSound('hover')); |
|
|
}); |
|
|
|
|
|
|
|
|
document.querySelectorAll('.cursor-pointer').forEach(card => { |
|
|
card.addEventListener('mouseenter', () => playSound('hover')); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('keydown', (e: KeyboardEvent) => { |
|
|
if (e.key === 'Escape') { |
|
|
closeModal(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
window.addEventListener('scroll', () => { |
|
|
const scrolled = window.pageYOffset; |
|
|
const parallaxElements = document.querySelectorAll('.parallax'); |
|
|
|
|
|
parallaxElements.forEach(element => { |
|
|
const speed = element.getAttribute('data-speed') || '0.5'; |
|
|
const yPos = -(scrolled * parseFloat(speed)); |
|
|
element.style.transform = `translateY(${yPos}px)`; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
function detectSystemTheme(): void { |
|
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)'); |
|
|
|
|
|
prefersDark.addEventListener('change', (e: MediaQueryListEvent) => { |
|
|
if (e.matches) { |
|
|
document.documentElement.classList.add('dark'); |
|
|
} else { |
|
|
document.documentElement.classList.remove('dark'); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
detectSystemTheme(); |
|
|
|
|
|
|
|
|
const performanceObserver = new PerformanceObserver((list) => { |
|
|
for (const entry of list.getEntries()) { |
|
|
console.log(`${entry.name}: ${entry.duration}ms`); |
|
|
} |
|
|
}); |
|
|
|
|
|
performanceObserver.observe({ entryTypes: ['measure', 'navigation'] }); |
|
|
|
|
|
|
|
|
function initTooltips(): void { |
|
|
const tooltipElements = document.querySelectorAll('[data-tooltip]'); |
|
|
|
|
|
tooltipElements.forEach(element => { |
|
|
element.addEventListener('mouseenter', (e: MouseEvent) => { |
|
|
const tooltip = document.createElement('div'); |
|
|
tooltip.className = 'absolute bg-gray-900 text-white text-sm px-2 py-1 rounded shadow-lg z-50'; |
|
|
tooltip.textContent = element.getAttribute('data-tooltip') || ''; |
|
|
tooltip.style.top = `${(e.target as HTMLElement).offsetTop - 30}px`; |
|
|
tooltip.style.left = `${(e.target as HTMLElement).offsetLeft}px`; |
|
|
document.body.appendChild(tooltip); |
|
|
}); |
|
|
|
|
|
element.addEventListener('mouseleave', () => { |
|
|
const tooltip = document.querySelector('.tooltip'); |
|
|
if (tooltip) tooltip.remove(); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
|
|
|
initTooltips(); |