remake cases for single project style
This commit is contained in:
parent
dd2ada14e8
commit
3c92fbddca
3 changed files with 842 additions and 108 deletions
|
|
@ -1,94 +1,244 @@
|
|||
.day1-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: "Raleway", sans-serif;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.day1-wallpaper {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height:100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
z-index: 0;
|
||||
filter: brightness(0.35) saturate(0.6);
|
||||
}
|
||||
|
||||
/* HUD-шапка */
|
||||
.day1-header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
font-family: "Raleway", sans-serif;
|
||||
background: rgba(47, 37, 191, 0.4);
|
||||
padding: 15px;
|
||||
color: white;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
border-bottom: 1px solid rgba(0, 255, 255, 0.2);
|
||||
padding: 12px 28px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.day1-header-content {
|
||||
display: flex;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
justify-content: space-around;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.day1-panel {
|
||||
position: absolute;
|
||||
bottom: 100px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(47, 37, 191, 0.4);
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
.day1-header-title {
|
||||
color: #00FFFF;
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
text-shadow: 0 0 14px rgba(0,255,255,0.5);
|
||||
}
|
||||
|
||||
.day1-header-sub {
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Легенда */
|
||||
.day1-story {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
max-width: 700px;
|
||||
margin: 28px auto 0;
|
||||
padding: 14px 24px;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
border: 1px solid rgba(0, 255, 255, 0.15);
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: #aaa;
|
||||
text-align: center;
|
||||
min-width: 300px;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
/* Прогресс-бар версий */
|
||||
.day1-progress {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0;
|
||||
margin: 28px auto 0;
|
||||
max-width: 480px;
|
||||
}
|
||||
|
||||
.day1-step {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.day1-step-dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #444;
|
||||
background: #111;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.day1-step.active .day1-step-dot {
|
||||
border-color: #00FFFF;
|
||||
background: #00FFFF;
|
||||
box-shadow: 0 0 10px rgba(0,255,255,0.6);
|
||||
}
|
||||
|
||||
.day1-step.done .day1-step-dot {
|
||||
border-color: #00FF41;
|
||||
background: #00FF41;
|
||||
box-shadow: 0 0 8px rgba(0,255,65,0.5);
|
||||
}
|
||||
|
||||
.day1-step-label {
|
||||
font-size: 11px;
|
||||
color: #555;
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.day1-step.active .day1-step-label { color: #00FFFF; }
|
||||
.day1-step.done .day1-step-label { color: #00FF41; }
|
||||
|
||||
.day1-step-line {
|
||||
flex: 1;
|
||||
height: 2px;
|
||||
background: #222;
|
||||
margin: 0 8px;
|
||||
margin-bottom: 22px;
|
||||
transition: background 0.3s;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.day1-step-line.done { background: #00FF41; }
|
||||
|
||||
/* Панель управления */
|
||||
.day1-panel {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
margin: 32px auto 0;
|
||||
max-width: 440px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border: 1px solid rgba(0, 255, 255, 0.2);
|
||||
border-radius: 10px;
|
||||
padding: 24px 28px;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(6px);
|
||||
box-shadow: 0 0 30px rgba(0,255,255,0.06);
|
||||
}
|
||||
|
||||
.day1-version-info {
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 8px;
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.day1-version-name {
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #00FFFF;
|
||||
text-shadow: 0 0 16px rgba(0,255,255,0.4);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.day1-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.day1-update-btn {
|
||||
padding: 10px 20px;
|
||||
background: #2a0c84;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
padding: 11px 24px;
|
||||
background: rgba(0, 255, 65, 0.1);
|
||||
color: #00FF41;
|
||||
border: 1px solid #00FF41;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.day1-update-btn:hover:not(:disabled) {
|
||||
background: #4313a3;
|
||||
background: rgba(0, 255, 65, 0.2);
|
||||
box-shadow: 0 0 16px rgba(0,255,65,0.35);
|
||||
}
|
||||
|
||||
.day1-update-btn:disabled {
|
||||
opacity: 0.6;
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.day1-end-btn {
|
||||
padding: 10px 20px;
|
||||
background: #e0af0f;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
padding: 11px 24px;
|
||||
background: rgba(245, 166, 35, 0.1);
|
||||
color: #f5a623;
|
||||
border: 1px solid #f5a623;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.day1-end-btn:hover {
|
||||
background: #f38518;
|
||||
background: rgba(245, 166, 35, 0.2);
|
||||
box-shadow: 0 0 16px rgba(245,166,35,0.3);
|
||||
}
|
||||
|
||||
/* Лоадер обновления */
|
||||
.day1-loading-bar {
|
||||
margin-top: 16px;
|
||||
height: 3px;
|
||||
background: rgba(0,255,255,0.1);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.day1-loading-fill {
|
||||
height: 100%;
|
||||
background: #00FFFF;
|
||||
border-radius: 2px;
|
||||
animation: day1-load 2s linear forwards;
|
||||
box-shadow: 0 0 8px rgba(0,255,255,0.6);
|
||||
}
|
||||
|
||||
@keyframes day1-load {
|
||||
from { width: 0%; }
|
||||
to { width: 100%; }
|
||||
}
|
||||
|
||||
/* Модалка ошибки */
|
||||
.day1-modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
@ -96,31 +246,48 @@
|
|||
}
|
||||
|
||||
.day1-modal {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
background: #0d0d22;
|
||||
border: 1px solid #FF0040;
|
||||
border-radius: 10px;
|
||||
padding: 28px 32px;
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
max-width: 420px;
|
||||
box-shadow: 0 0 30px rgba(255,0,64,0.2);
|
||||
}
|
||||
|
||||
.day1-modal-icon {
|
||||
font-size: 36px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.day1-modal-title {
|
||||
color: #f44336;
|
||||
margin-bottom: 10px;
|
||||
color: #FF0040;
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.day1-modal-text {
|
||||
color: #aaa;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.day1-modal-btn {
|
||||
padding: 10px 20px;
|
||||
background: #4caf50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
padding: 10px 28px;
|
||||
background: transparent;
|
||||
border: 1px solid rgba(0,255,255,0.3);
|
||||
color: #888;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 13px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.day1-modal-btn:hover {
|
||||
background: #45a049;
|
||||
border-color: #00FFFF;
|
||||
color: #00FFFF;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,90 +6,102 @@ interface Case1DesktopProps {
|
|||
onComplete: (type: WallpaperType) => void;
|
||||
}
|
||||
|
||||
const VERSIONS = [
|
||||
{ v: 1, name: 'Windows XP', img: '/images/windows_xp.jpg', type: 'xp' as WallpaperType },
|
||||
{ v: 2, name: 'Windows 7', img: '/images/windows_7.jpg', type: 'win7' as WallpaperType },
|
||||
{ v: 3, name: 'Windows 10', img: '/images/windows_10.jpg', type: 'win10' as WallpaperType },
|
||||
];
|
||||
|
||||
const Case1Desktop: React.FC<Case1DesktopProps> = ({ onComplete }) => {
|
||||
const [version, setVersion] = useState(1);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const getImage = () => {
|
||||
if (version === 1) return '/images/windows_xp.jpg';
|
||||
if (version === 2) return '/images/windows_7.jpg';
|
||||
return '/images/windows_10.jpg';
|
||||
};
|
||||
|
||||
const getVersionName = () => {
|
||||
if (version === 1) return 'Windows XP';
|
||||
if (version === 2) return 'Windows 7';
|
||||
return 'Windows 10';
|
||||
};
|
||||
|
||||
const getWallpaperType = (): WallpaperType => {
|
||||
if (version === 1) return 'xp';
|
||||
if (version === 2) return 'win7';
|
||||
return 'win10';
|
||||
};
|
||||
const current = VERSIONS[version - 1];
|
||||
|
||||
const updateSystem = () => {
|
||||
if (version === 1) {
|
||||
if (version >= 3) return;
|
||||
setLoading(true);
|
||||
setTimeout(() => {
|
||||
setVersion(2);
|
||||
setVersion(v => v + 1);
|
||||
setLoading(false);
|
||||
}, 2000);
|
||||
} else if (version === 2) {
|
||||
setLoading(true);
|
||||
setTimeout(() => {
|
||||
setVersion(3);
|
||||
setLoading(false);
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
|
||||
const endDay = () => {
|
||||
if (version === 3) {
|
||||
onComplete(getWallpaperType());
|
||||
onComplete(current.type);
|
||||
} else {
|
||||
setError(`Ошибка! Нельзя завершить день на старой версии ${getVersionName()}. Нужно обновиться до Windows 10`);
|
||||
setError(`Нельзя завершить кейс на ${current.name}. Устаревшая ОС содержит незакрытые уязвимости — обновите систему до Windows 10.`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="day1-container">
|
||||
<img src={getImage()} alt="wallpaper" className="day1-wallpaper" />
|
||||
<img src={current.img} alt="wallpaper" className="day1-wallpaper" />
|
||||
|
||||
{/* HUD-шапка */}
|
||||
<div className="day1-header">
|
||||
<div className="day1-header-content">
|
||||
<span>Кейс 1: Обновление системы</span>
|
||||
<span>Выберите наиболее подходящую версию Windows</span>
|
||||
<span className="day1-header-title">КЕЙС 1 — ОБНОВЛЕНИЕ СИСТЕМЫ</span>
|
||||
<span className="day1-header-sub">Устаревшее ПО = открытая дверь для атак</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="day1-panel">
|
||||
<div className="day1-version-info">
|
||||
<strong>Текущая версия:</strong> {getVersionName()}
|
||||
{/* Легенда */}
|
||||
<div className="day1-story">
|
||||
Ваша рабочая станция работает на <b style={{ color: '#f5a623' }}>{current.name}</b>.
|
||||
Производитель прекратил поддержку этой версии — патчи безопасности больше не выходят.
|
||||
<br />
|
||||
Злоумышленники активно эксплуатируют известные уязвимости необновлённых систем.
|
||||
<b style={{ color: '#00FF41' }}> Обновите ОС до актуальной версии, чтобы закрыть бреши.</b>
|
||||
</div>
|
||||
|
||||
{/* Прогресс */}
|
||||
<div className="day1-progress">
|
||||
{VERSIONS.map((ver, i) => (
|
||||
<React.Fragment key={ver.v}>
|
||||
<div className={`day1-step ${version === ver.v ? 'active' : version > ver.v ? 'done' : ''}`}>
|
||||
<div className="day1-step-dot" />
|
||||
<span className="day1-step-label">{ver.name}</span>
|
||||
</div>
|
||||
{i < VERSIONS.length - 1 && (
|
||||
<div className={`day1-step-line ${version > ver.v ? 'done' : ''}`} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Панель управления */}
|
||||
<div className="day1-panel">
|
||||
<div className="day1-version-info">Текущая версия</div>
|
||||
<div className="day1-version-name">{current.name}</div>
|
||||
|
||||
<div className="day1-buttons">
|
||||
{version !== 3 && (
|
||||
<button
|
||||
className="day1-update-btn"
|
||||
onClick={updateSystem}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? 'Обновление...' : 'Обновить до Windows 10'}
|
||||
{version < 3 && (
|
||||
<button className="day1-update-btn" onClick={updateSystem} disabled={loading}>
|
||||
{loading ? '⟳ Обновление...' : `↑ Обновить систему`}
|
||||
</button>
|
||||
)}
|
||||
<button className="day1-end-btn" onClick={endDay}>
|
||||
Закончить день 1
|
||||
{version === 3 ? '✓ Завершить кейс' : '→ Продолжить без обновления'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{loading && (
|
||||
<div className="day1-loading-bar">
|
||||
<div className="day1-loading-fill" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="day1-modal-overlay">
|
||||
<div className="day1-modal">
|
||||
<h3 className="day1-modal-title">Ошибка</h3>
|
||||
<div className="day1-modal-icon">⚠️</div>
|
||||
<div className="day1-modal-title">Небезопасно</div>
|
||||
<p className="day1-modal-text">{error}</p>
|
||||
<button className="day1-modal-btn" onClick={() => setError('')}>OK</button>
|
||||
<button className="day1-modal-btn" onClick={() => setError('')}>← Назад</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,574 @@
|
|||
import React, { useState } from 'react';
|
||||
import type { WallpaperType } from '../App';
|
||||
import MainApp from '../MainApp';
|
||||
// import './Case2Desktop.css';
|
||||
|
||||
interface Case2DesktopProps {
|
||||
onComplete: (type: WallpaperType) => void;
|
||||
}
|
||||
|
||||
interface Site {
|
||||
id: number;
|
||||
name: string;
|
||||
domain: string;
|
||||
https: boolean;
|
||||
isLegit: boolean;
|
||||
adLabel?: boolean;
|
||||
description: string;
|
||||
version: string;
|
||||
fileName: string;
|
||||
fileSize: string;
|
||||
malwareType: string | null;
|
||||
malwareDesc: string | null;
|
||||
}
|
||||
|
||||
const SITES: Site[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'ТелеЛитр — скачать бесплатно быстро',
|
||||
domain: 'telelitr-download.net',
|
||||
https: false,
|
||||
isLegit: false,
|
||||
adLabel: true,
|
||||
description: 'Скачать ТелеЛитр бесплатно! Последняя версия 2024. Быстрая загрузка без регистрации.',
|
||||
version: 'v2.1.4',
|
||||
fileName: 'TeleLitrFREE_setup.exe',
|
||||
fileSize: '48 МБ',
|
||||
malwareType: 'Троян-шпион',
|
||||
malwareDesc: 'Файл содержит кейлоггер — программу, которая записывает все нажатия клавиш и передаёт злоумышленнику ваши пароли, переписку и данные карт.',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'TeleLitr — официальный сайт',
|
||||
domain: 'telelitr.ru',
|
||||
https: true,
|
||||
isLegit: true,
|
||||
description: 'Официальный сайт мессенджера ТелеЛитр. Безопасные звонки и сообщения с end-to-end шифрованием.',
|
||||
version: 'v2.1.4',
|
||||
fileName: 'TeleLitr_Setup_2.1.4.exe',
|
||||
fileSize: '52 МБ',
|
||||
malwareType: null,
|
||||
malwareDesc: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Скачать ТелеЛитр — все версии',
|
||||
domain: 'tele-litr.ru',
|
||||
https: false,
|
||||
isLegit: false,
|
||||
adLabel: true,
|
||||
description: 'ТелеЛитр для Windows, Mac, Android. Все версии. Без вирусов (проверено)!',
|
||||
version: 'v2.1.3',
|
||||
fileName: 'telelitr_installer_x64.exe',
|
||||
fileSize: '61 МБ',
|
||||
malwareType: 'Майнер криптовалюты',
|
||||
malwareDesc: 'Вместе с мессенджером устанавливается скрытый майнер, который использует ресурсы вашего компьютера для добычи криптовалюты в пользу злоумышленника.',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'TeleLitr Download — быстро и бесплатно',
|
||||
domain: 'telelitr-app.com',
|
||||
https: false,
|
||||
isLegit: false,
|
||||
description: 'Мессенджер ТелеЛитр. Скачать installer. Работает на Windows 7/8/10/11.',
|
||||
version: 'v2.0.9',
|
||||
fileName: 'TeleLitr_v209_win.exe',
|
||||
fileSize: '55 МБ',
|
||||
malwareType: 'Рекламное ПО (Adware)',
|
||||
malwareDesc: 'Инсталлятор содержит связку нежелательных программ: меняет стартовую страницу браузера, устанавливает тулбары и показывает навязчивую рекламу.',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'TeleLitr — мессенджер с шифрованием',
|
||||
domain: 'telelitr-official.net',
|
||||
https: true,
|
||||
isLegit: false,
|
||||
adLabel: true,
|
||||
description: 'Защищённый мессенджер. Скачайте официальную версию с нашего сайта.',
|
||||
version: 'v2.1.4',
|
||||
fileName: 'TeleLitr_Setup.exe',
|
||||
fileSize: '50 МБ',
|
||||
malwareType: 'Фишинговый клиент',
|
||||
malwareDesc: 'Это поддельный клиент мессенджера. Внешне он идентичен настоящему, но при входе передаёт ваш логин и пароль на сервер злоумышленников.',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'ТелеЛитр скачать — все платформы',
|
||||
domain: 'get-telelitr.xyz',
|
||||
https: false,
|
||||
isLegit: false,
|
||||
description: 'Скачать ТелеЛитр для Windows. Версия 2024. Установка за 1 минуту.',
|
||||
version: 'v2.1.1',
|
||||
fileName: 'get_telelitr.exe',
|
||||
fileSize: '43 МБ',
|
||||
malwareType: 'Программа-вымогатель',
|
||||
malwareDesc: 'После установки вирус шифрует файлы на вашем компьютере и требует выкуп за их восстановление. Домен .xyz — частый признак вредоносных сайтов.',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'TeleLitr для Windows — скачать',
|
||||
domain: 'telelitr-win.ru',
|
||||
https: false,
|
||||
isLegit: false,
|
||||
description: 'Мессенджер ТелеЛитр. Версия для Windows. Бесплатно.',
|
||||
version: 'v2.1.4',
|
||||
fileName: 'telelitr_windows_setup.exe',
|
||||
fileSize: '58 МБ',
|
||||
malwareType: 'Бэкдор',
|
||||
malwareDesc: 'Программа открывает скрытый удалённый доступ к вашему компьютеру. Злоумышленник может управлять системой, красть файлы и устанавливать другое вредоносное ПО.',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'ТелеЛитр — мессенджер 2024',
|
||||
domain: 'telelitrapp.ru',
|
||||
https: true,
|
||||
isLegit: false,
|
||||
description: 'Официальная загрузка. ТелеЛитр 2024 — новый интерфейс, улучшенное шифрование.',
|
||||
version: 'v3.0.0-beta',
|
||||
fileName: 'TeleLitr_2024_Pro.exe',
|
||||
fileSize: '67 МБ',
|
||||
malwareType: 'Поддельное ПО со шпионажем',
|
||||
malwareDesc: 'Версия "3.0.0-beta" не существует — это фейк. Программа имитирует мессенджер, но перехватывает все сообщения и звонки, отправляя их третьим лицам.',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: 'Скачать TeleLitr — зеркало',
|
||||
domain: 'mirror-telelitr.com',
|
||||
https: false,
|
||||
isLegit: false,
|
||||
adLabel: true,
|
||||
description: 'Зеркало официального сайта. Быстрая загрузка без ограничений.',
|
||||
version: 'v2.1.4',
|
||||
fileName: 'TeleLitr_mirror.exe',
|
||||
fileSize: '52 МБ',
|
||||
malwareType: 'Троян с руткитом',
|
||||
malwareDesc: '"Зеркала" официальных сайтов — распространённый способ распространения вредоносного ПО. Файл содержит руткит, скрывающий своё присутствие в системе.',
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: 'TeleLitr — официальный сайт приложения',
|
||||
domain: 'telelitr.ru',
|
||||
https: true,
|
||||
isLegit: true,
|
||||
description: 'Скачайте ТелеЛитр с официального сайта. Цифровая подпись подтверждена. Безопасно.',
|
||||
version: 'v2.1.4',
|
||||
fileName: 'TeleLitr_Setup_2.1.4.exe',
|
||||
fileSize: '52 МБ',
|
||||
malwareType: null,
|
||||
malwareDesc: null,
|
||||
},
|
||||
];
|
||||
|
||||
const Case2Desktop: React.FC<Case2DesktopProps> = ({ onComplete }) => {
|
||||
const [searched, setSearched] = useState(false);
|
||||
const [query, setQuery] = useState('скачать ТелеЛитр мессенджер');
|
||||
const [selectedSite, setSelectedSite] = useState<Site | null>(null);
|
||||
const [downloading, setDownloading] = useState(false);
|
||||
const [modal, setModal] = useState<'malware' | 'success' | null>(null);
|
||||
|
||||
const currentUrl = selectedSite ? selectedSite.domain : 'ya.ru';
|
||||
const isSecure = !selectedSite || selectedSite.https;
|
||||
|
||||
const openSite = (site: Site) => setSelectedSite(site);
|
||||
|
||||
const handleDownload = () => {
|
||||
if (!selectedSite) return;
|
||||
setDownloading(true);
|
||||
setTimeout(() => {
|
||||
setDownloading(false);
|
||||
setModal(selectedSite.isLegit ? 'success' : 'malware');
|
||||
}, 1800);
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
setModal(null);
|
||||
setSelectedSite(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={s.root}>
|
||||
{/* Легенда */}
|
||||
<div style={s.story}>
|
||||
<p style={{ margin: 0 }}>
|
||||
Ваша компания переходит на новый корпоративный мессенджер <b style={{ color: '#00FFFF' }}>ТелеЛитр</b>.
|
||||
IT-отдел прислал инструкцию: скачайте и установите его самостоятельно.
|
||||
<br />
|
||||
<b style={{ color: '#f5a623' }}>Задача:</b> найти официальный сайт и скачать настоящий установщик.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Браузер */}
|
||||
<div style={s.browser}>
|
||||
<div style={s.chrome}>
|
||||
{selectedSite && <button style={s.navBtn} onClick={reset}>←</button>}
|
||||
<div style={s.urlBar}>
|
||||
<span style={isSecure ? s.httpsIcon : s.httpIcon}>{isSecure ? '🔒' : '⚠'}</span>
|
||||
<span style={{ ...s.urlText, color: isSecure ? '#aaa' : '#f5a623' }}>{currentUrl}</span>
|
||||
{!isSecure && <span style={s.httpWarn}>Небезопасно</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={s.content}>
|
||||
|
||||
{/* Яндекс главная */}
|
||||
{!searched && !selectedSite && (
|
||||
<div style={s.yandexHome}>
|
||||
<div style={s.yandexLogo}>
|
||||
<span style={s.yandexY}>Я</span>
|
||||
<span style={s.yandexNdex}>ндекс</span>
|
||||
</div>
|
||||
<div style={s.searchBox}>
|
||||
<input
|
||||
style={s.searchInput}
|
||||
value={query}
|
||||
onChange={e => setQuery(e.target.value)}
|
||||
onKeyDown={e => e.key === 'Enter' && setSearched(true)}
|
||||
placeholder="Найти в интернете"
|
||||
/>
|
||||
<button style={s.searchBtn} onClick={() => setSearched(true)}>Найти</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Результаты поиска */}
|
||||
{searched && !selectedSite && (
|
||||
<div style={s.searchResults}>
|
||||
<div style={s.searchHeader}>
|
||||
<div style={s.searchBoxSmall}>
|
||||
<span style={s.yandexSmall}>Я</span>
|
||||
<input
|
||||
style={s.searchInputSmall}
|
||||
value={query}
|
||||
onChange={e => setQuery(e.target.value)}
|
||||
onKeyDown={e => e.key === 'Enter' && setSearched(true)}
|
||||
/>
|
||||
<button style={s.searchBtnSmall} onClick={() => setSearched(true)}>🔍</button>
|
||||
</div>
|
||||
<div style={s.resultCount}>Нашлось 10 результатов</div>
|
||||
</div>
|
||||
<div style={s.resultsList}>
|
||||
{SITES.map(site => (
|
||||
<div key={site.id} style={s.resultItem} onClick={() => openSite(site)}>
|
||||
{site.adLabel && <span style={s.adBadge}>Реклама</span>}
|
||||
<div style={s.resultName}>{site.name}</div>
|
||||
<div style={{ ...s.resultDomain, color: site.https ? '#4a9e6e' : '#f5a623' }}>
|
||||
{site.https ? '🔒' : '⚠'} {site.domain}
|
||||
</div>
|
||||
<div style={s.resultDesc}>{site.description}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Страница сайта */}
|
||||
{selectedSite && (
|
||||
<div style={s.sitePage}>
|
||||
<div style={s.siteHeader}>
|
||||
<span style={{ fontSize: 32 }}>📱</span>
|
||||
<div>
|
||||
<MainApp showGosuslugi={false} showAmnezia={false}/>
|
||||
<div style={s.siteTitle}>ТелеЛитр</div>
|
||||
<div style={s.siteDomain}>{selectedSite.domain}</div>
|
||||
</div>
|
||||
{!selectedSite.https && (
|
||||
<span style={s.unsafeBadge}>⚠ HTTP — небезопасный сайт</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={s.downloadCard}>
|
||||
<div style={s.appInfo}>
|
||||
<span style={{ fontSize: 56 }}>📱</span>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={s.appName}>TeleLitr Messenger</div>
|
||||
<div style={s.appVersion}>Версия {selectedSite.version}</div>
|
||||
<div style={{ fontSize: 13, marginBottom: 4 }}>
|
||||
<span style={{ color: '#666' }}>Файл: </span>
|
||||
<span style={{ color: selectedSite.isLegit ? '#00FF41' : '#f5a623' }}>
|
||||
{selectedSite.fileName}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ color: '#555', fontSize: 12 }}>Размер: {selectedSite.fileSize}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!selectedSite.isLegit && (
|
||||
<div style={s.warnHints}>
|
||||
<div style={s.warnTitle}>⚠ Признаки подозрительного сайта:</div>
|
||||
<ul style={s.hintList}>
|
||||
{!selectedSite.https && <li>Сайт работает по HTTP — данные не шифруются</li>}
|
||||
{(selectedSite.domain.includes('.xyz') || selectedSite.domain.includes('.net') || selectedSite.domain.includes('.com') || selectedSite.domain.includes('mirror') || selectedSite.domain.includes('download')) && (
|
||||
<li>Домен не совпадает с официальным <b>telelitr.ru</b></li>
|
||||
)}
|
||||
{selectedSite.domain !== 'telelitr.ru' && (
|
||||
<li>Имя файла отличается от официального: <b>TeleLitr_Setup_2.1.4.exe</b></li>
|
||||
)}
|
||||
{selectedSite.adLabel && <li>Рекламная ссылка в поиске — не гарантирует официальность</li>}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
{selectedSite.isLegit && (
|
||||
<div style={s.safeHints}>
|
||||
<div style={s.safeTitle}>✅ Признаки официального сайта:</div>
|
||||
<ul style={s.hintList}>
|
||||
<li>HTTPS — соединение зашифровано</li>
|
||||
<li>Домен <b>telelitr.ru</b> — совпадает с официальным</li>
|
||||
<li>Имя файла содержит точную версию: TeleLitr_Setup_<b>2.1.4</b>.exe</li>
|
||||
<li>Цифровая подпись файла подтверждена</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
style={downloading ? s.dlBtnLoading : selectedSite.isLegit ? s.dlBtnSafe : s.dlBtnDanger}
|
||||
onClick={handleDownload}
|
||||
disabled={downloading}
|
||||
>
|
||||
{downloading ? '⟳ Загрузка...' : `↓ Скачать ${selectedSite.fileName}`}
|
||||
</button>
|
||||
|
||||
{downloading && (
|
||||
<div style={s.progressBar}>
|
||||
<div style={s.progressFill} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Модал: вредонос */}
|
||||
{modal === 'malware' && selectedSite && (
|
||||
<div style={s.modalOverlay}>
|
||||
<div style={s.modalDanger}>
|
||||
<div style={s.modalIcon}>☠️</div>
|
||||
<div style={s.modalTitle}>Вредоносное ПО обнаружено!</div>
|
||||
<div style={s.modalText}>
|
||||
Файл <b style={{ color: '#FF0040' }}>{selectedSite.fileName}</b> с сайта{' '}
|
||||
<b style={{ color: '#FF0040' }}>{selectedSite.domain}</b> является вредоносным.
|
||||
</div>
|
||||
<div style={s.malwareBlock}>
|
||||
<div style={{ color: '#aaa', fontSize: 13, marginBottom: 6 }}>
|
||||
Тип угрозы: <b style={{ color: '#FF0040' }}>{selectedSite.malwareType}</b>
|
||||
</div>
|
||||
<div style={{ color: '#aaa', fontSize: 13, lineHeight: 1.6 }}>{selectedSite.malwareDesc}</div>
|
||||
</div>
|
||||
<div style={s.rulesBlock}>
|
||||
<div style={s.rulesTitle}>Как найти официальный сайт:</div>
|
||||
<ul style={s.rulesList}>
|
||||
<li>Проверяйте домен — он должен совпадать с официальным</li>
|
||||
<li>HTTPS важен, но сам по себе не гарантирует безопасность</li>
|
||||
<li>Имя файла должно содержать точную версию программы</li>
|
||||
<li>Берите ссылку с сайта разработчика или из документации к ПО</li>
|
||||
<li>Проверяйте цифровую подпись скачанного .exe файла</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button style={s.retryBtn} onClick={reset}>← Вернуться к поиску</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Модал: успех */}
|
||||
{modal === 'success' && selectedSite && (
|
||||
<div style={s.modalOverlay}>
|
||||
<div style={s.modalSuccess}>
|
||||
<div style={s.modalIcon}>✅</div>
|
||||
<div style={{ ...s.modalTitle, color: '#00FF41' }}>Официальный установщик загружен!</div>
|
||||
<div style={s.modalText}>
|
||||
Вы скачали <b style={{ color: '#00FF41' }}>{selectedSite.fileName}</b> с официального сайта{' '}
|
||||
<b style={{ color: '#00FF41' }}>{selectedSite.domain}</b>.
|
||||
</div>
|
||||
<div style={s.successDetails}>
|
||||
<div style={s.successRow}><span>Файл:</span><span style={{ color: '#00FF41' }}>{selectedSite.fileName}</span></div>
|
||||
<div style={s.successRow}><span>Версия:</span><span style={{ color: '#00FF41' }}>{selectedSite.version}</span></div>
|
||||
<div style={s.successRow}><span>Подпись:</span><span style={{ color: '#00FF41' }}>✓ Подтверждена</span></div>
|
||||
<div style={s.successRow}><span>Угрозы:</span><span style={{ color: '#00FF41' }}>Не обнаружены</span></div>
|
||||
</div>
|
||||
<button style={s.completeBtn} onClick={() => { setModal(null); onComplete('win10'); }}>
|
||||
✓ Завершить кейс
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const s: Record<string, React.CSSProperties> = {
|
||||
root: {
|
||||
minHeight: '100vh',
|
||||
background: 'linear-gradient(135deg, #0a0a14 0%, #0d1117 60%, #001400 100%)',
|
||||
color: '#ccc',
|
||||
fontFamily: "'Share Tech Mono', monospace",
|
||||
padding: '0 0 40px',
|
||||
},
|
||||
story: {
|
||||
maxWidth: 760, margin: '24px auto 0', padding: '14px 24px',
|
||||
background: 'rgba(0,255,255,0.04)', border: '1px solid rgba(0,255,255,0.15)',
|
||||
borderRadius: 8, fontSize: 14, lineHeight: 1.7, color: '#aaa', textAlign: 'center',
|
||||
},
|
||||
browser: {
|
||||
maxWidth: 860, margin: '24px auto 0',
|
||||
border: '1px solid rgba(0,255,255,0.2)', borderRadius: 10, overflow: 'hidden',
|
||||
boxShadow: '0 0 30px rgba(0,255,255,0.06)',
|
||||
},
|
||||
chrome: {
|
||||
background: '#080818', borderBottom: '1px solid rgba(0,255,255,0.15)',
|
||||
padding: '8px 12px', display: 'flex', alignItems: 'center', gap: 8,
|
||||
},
|
||||
navBtn: {
|
||||
background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)',
|
||||
color: '#888', borderRadius: 4, padding: '4px 10px', cursor: 'pointer',
|
||||
fontSize: 14, fontFamily: "'Share Tech Mono', monospace",
|
||||
},
|
||||
urlBar: {
|
||||
flex: 1, background: '#0a0a1a', border: '1px solid rgba(0,255,255,0.2)',
|
||||
borderRadius: 4, padding: '5px 12px', fontSize: 13,
|
||||
display: 'flex', alignItems: 'center', gap: 8,
|
||||
},
|
||||
httpsIcon: { color: '#00FF41', fontSize: 13 },
|
||||
httpIcon: { color: '#f5a623', fontSize: 13 },
|
||||
urlText: { flex: 1 },
|
||||
httpWarn: { color: '#f5a623', fontSize: 11 },
|
||||
content: { background: '#0d0d0d', minHeight: 480 },
|
||||
yandexHome: {
|
||||
display: 'flex', flexDirection: 'column', alignItems: 'center',
|
||||
justifyContent: 'center', paddingTop: 80, paddingBottom: 60, gap: 28,
|
||||
},
|
||||
yandexLogo: { fontSize: 52, fontWeight: 700, lineHeight: 1 },
|
||||
yandexY: { color: '#FF0040', fontFamily: 'Georgia, serif' },
|
||||
yandexNdex: { color: '#eee', fontFamily: 'Georgia, serif' },
|
||||
searchBox: { display: 'flex', width: '100%', maxWidth: 560 },
|
||||
searchInput: {
|
||||
flex: 1, padding: '12px 16px', background: '#1a1a2e',
|
||||
border: '1px solid rgba(0,255,255,0.25)', borderRight: 'none',
|
||||
borderRadius: '6px 0 0 6px', color: '#eee', fontSize: 15,
|
||||
fontFamily: "'Share Tech Mono', monospace", outline: 'none',
|
||||
},
|
||||
searchBtn: {
|
||||
padding: '12px 24px', background: '#FF0040', border: 'none',
|
||||
borderRadius: '0 6px 6px 0', color: '#fff',
|
||||
fontFamily: "'Orbitron', monospace", fontSize: 13, fontWeight: 700, cursor: 'pointer',
|
||||
},
|
||||
searchResults: { padding: '0 0 24px' },
|
||||
searchHeader: {
|
||||
background: '#080818', borderBottom: '1px solid rgba(0,255,255,0.1)',
|
||||
padding: '10px 16px', display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap' as const,
|
||||
},
|
||||
searchBoxSmall: {
|
||||
display: 'flex', alignItems: 'center', flex: 1, maxWidth: 400,
|
||||
background: '#0d0d22', border: '1px solid rgba(0,255,255,0.2)',
|
||||
borderRadius: 6, overflow: 'hidden',
|
||||
},
|
||||
yandexSmall: { color: '#FF0040', fontFamily: 'Georgia, serif', fontSize: 18, fontWeight: 700, padding: '0 8px' },
|
||||
searchInputSmall: {
|
||||
flex: 1, background: 'transparent', border: 'none', color: '#eee',
|
||||
fontSize: 13, fontFamily: "'Share Tech Mono', monospace", padding: '8px 4px', outline: 'none',
|
||||
},
|
||||
searchBtnSmall: { background: 'transparent', border: 'none', color: '#888', cursor: 'pointer', padding: '8px 12px', fontSize: 14 },
|
||||
resultCount: { color: '#555', fontSize: 12 },
|
||||
resultsList: { padding: '8px 20px', display: 'flex', flexDirection: 'column', gap: 2 },
|
||||
resultItem: { padding: '14px 16px', borderRadius: 6, cursor: 'pointer', borderBottom: '1px solid rgba(255,255,255,0.04)' },
|
||||
adBadge: {
|
||||
display: 'inline-block', background: 'rgba(245,166,35,0.15)',
|
||||
border: '1px solid rgba(245,166,35,0.4)', color: '#f5a623',
|
||||
fontSize: 10, padding: '1px 6px', borderRadius: 3, marginBottom: 4,
|
||||
fontFamily: "'Share Tech Mono', monospace",
|
||||
},
|
||||
resultName: { color: '#5b9bd5', fontSize: 15, marginBottom: 2 },
|
||||
resultDomain: { fontSize: 12, marginBottom: 4 },
|
||||
resultDesc: { color: '#777', fontSize: 13, lineHeight: 1.5 },
|
||||
sitePage: { padding: 24 },
|
||||
siteHeader: {
|
||||
display: 'flex', alignItems: 'center', gap: 14, marginBottom: 20,
|
||||
paddingBottom: 12, borderBottom: '1px solid rgba(255,255,255,0.06)',
|
||||
},
|
||||
siteTitle: { color: '#00FFFF', fontFamily: "'Orbitron', monospace", fontSize: 16, fontWeight: 700 },
|
||||
siteDomain: { color: '#555', fontSize: 12, marginTop: 2 },
|
||||
unsafeBadge: {
|
||||
marginLeft: 'auto', background: 'rgba(245,166,35,0.12)',
|
||||
border: '1px solid #f5a623', color: '#f5a623', fontSize: 11, padding: '4px 12px', borderRadius: 4,
|
||||
},
|
||||
downloadCard: {
|
||||
background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.08)',
|
||||
borderRadius: 10, padding: 20,
|
||||
},
|
||||
appInfo: { display: 'flex', gap: 20, alignItems: 'flex-start', marginBottom: 20 },
|
||||
appName: { color: '#ddd', fontSize: 18, fontWeight: 700, marginBottom: 4 },
|
||||
appVersion: { color: '#888', fontSize: 13, marginBottom: 6 },
|
||||
warnHints: {
|
||||
background: 'rgba(245,166,35,0.06)', border: '1px solid rgba(245,166,35,0.3)',
|
||||
borderRadius: 8, padding: '12px 16px', marginBottom: 16,
|
||||
},
|
||||
warnTitle: { color: '#f5a623', fontFamily: "'Orbitron', monospace", fontSize: 12, fontWeight: 700, marginBottom: 8 },
|
||||
safeHints: {
|
||||
background: 'rgba(0,255,65,0.05)', border: '1px solid rgba(0,255,65,0.25)',
|
||||
borderRadius: 8, padding: '12px 16px', marginBottom: 16,
|
||||
},
|
||||
safeTitle: { color: '#00FF41', fontFamily: "'Orbitron', monospace", fontSize: 12, fontWeight: 700, marginBottom: 8 },
|
||||
hintList: { margin: 0, paddingLeft: 20, color: '#aaa', fontSize: 13, lineHeight: 1.8 },
|
||||
dlBtnSafe: {
|
||||
width: '100%', padding: '13px', background: 'rgba(0,255,65,0.1)',
|
||||
border: '1px solid #00FF41', color: '#00FF41', borderRadius: 7, cursor: 'pointer',
|
||||
fontFamily: "'Orbitron', monospace", fontSize: 13, fontWeight: 700,
|
||||
},
|
||||
dlBtnDanger: {
|
||||
width: '100%', padding: '13px', background: 'rgba(245,166,35,0.08)',
|
||||
border: '1px solid #f5a623', color: '#f5a623', borderRadius: 7, cursor: 'pointer',
|
||||
fontFamily: "'Orbitron', monospace", fontSize: 13, fontWeight: 700,
|
||||
},
|
||||
dlBtnLoading: {
|
||||
width: '100%', padding: '13px', background: 'rgba(0,255,255,0.06)',
|
||||
border: '1px solid rgba(0,255,255,0.3)', color: '#00FFFF', borderRadius: 7, cursor: 'not-allowed',
|
||||
fontFamily: "'Orbitron', monospace", fontSize: 13, fontWeight: 700,
|
||||
},
|
||||
progressBar: { marginTop: 10, height: 3, background: 'rgba(0,255,255,0.1)', borderRadius: 2, overflow: 'hidden' },
|
||||
progressFill: {
|
||||
height: '100%', background: '#00FFFF', borderRadius: 2, width: '100%',
|
||||
animation: 'none', transition: 'none',
|
||||
boxShadow: '0 0 8px rgba(0,255,255,0.5)',
|
||||
},
|
||||
modalOverlay: {
|
||||
position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.82)',
|
||||
display: 'flex', alignItems: 'flex-start', justifyContent: 'center',
|
||||
zIndex: 200, overflowY: 'auto', padding: '40px 16px',
|
||||
},
|
||||
modalDanger: {
|
||||
background: '#0d0d22', border: '1px solid #FF0040', borderRadius: 12,
|
||||
padding: '28px 28px 24px', maxWidth: 520, width: '100%',
|
||||
boxShadow: '0 0 40px rgba(255,0,64,0.25)', textAlign: 'center',
|
||||
},
|
||||
modalSuccess: {
|
||||
background: '#0d0d22', border: '1px solid #00FF41', borderRadius: 12,
|
||||
padding: '28px 28px 24px', maxWidth: 480, width: '100%',
|
||||
boxShadow: '0 0 40px rgba(0,255,65,0.2)', textAlign: 'center',
|
||||
},
|
||||
modalIcon: { fontSize: 48, marginBottom: 12 },
|
||||
modalTitle: { color: '#FF0040', fontFamily: "'Orbitron', monospace", fontSize: 16, fontWeight: 700, marginBottom: 12 },
|
||||
modalText: { color: '#aaa', fontSize: 13, lineHeight: 1.7, marginBottom: 16 },
|
||||
malwareBlock: {
|
||||
background: 'rgba(255,0,64,0.07)', border: '1px solid rgba(255,0,64,0.3)',
|
||||
borderRadius: 8, padding: '12px 16px', marginBottom: 14, textAlign: 'left',
|
||||
},
|
||||
rulesBlock: {
|
||||
background: 'rgba(0,255,65,0.04)', border: '1px solid rgba(0,255,65,0.2)',
|
||||
borderRadius: 8, padding: '12px 16px', marginBottom: 20, textAlign: 'left',
|
||||
},
|
||||
rulesTitle: { color: '#00FF41', fontFamily: "'Orbitron', monospace", fontSize: 12, fontWeight: 700, marginBottom: 8 },
|
||||
rulesList: { margin: 0, paddingLeft: 20, color: '#aaa', fontSize: 13, lineHeight: 1.8 },
|
||||
retryBtn: {
|
||||
padding: '10px 20px', background: 'transparent',
|
||||
border: '1px solid rgba(0,255,255,0.3)', borderRadius: 6,
|
||||
color: '#888', cursor: 'pointer', fontFamily: "'Share Tech Mono', monospace", fontSize: 13,
|
||||
},
|
||||
successDetails: {
|
||||
background: 'rgba(0,255,65,0.05)', border: '1px solid rgba(0,255,65,0.2)',
|
||||
borderRadius: 8, padding: '12px 16px', marginBottom: 20, textAlign: 'left',
|
||||
},
|
||||
successRow: { display: 'flex', justifyContent: 'space-between', padding: '4px 0', fontSize: 13, color: '#aaa' },
|
||||
completeBtn: {
|
||||
padding: '12px 36px', background: '#00FF41', border: 'none',
|
||||
borderRadius: 6, color: '#000', fontFamily: "'Orbitron', monospace",
|
||||
fontSize: 14, fontWeight: 700, cursor: 'pointer',
|
||||
},
|
||||
};
|
||||
|
||||
export default Case2Desktop;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue