Update slider UX/UI

This commit is contained in:
lockbitchat
2025-10-02 21:34:45 -04:00
parent 4359e5fab1
commit 8cd78a2aba
6 changed files with 672 additions and 285 deletions

253
dist/app-boot.js vendored
View File

@@ -15085,147 +15085,176 @@ window.DownloadApps = DownloadApps;
// src/components/ui/UniqueFeatureSlider.jsx
var UniqueFeatureSlider = () => {
const [currentSlide, setCurrentSlide] = React.useState(0);
const trackRef = React.useRef(null);
const wrapRef = React.useRef(null);
const dotsRef = React.useRef(null);
const [current, setCurrent] = React.useState(0);
const slides = [
{
icon: "fas fa-shield-halved",
color: "orange",
icon: "\u{1F6E1}\uFE0F",
bgImage: "linear-gradient(135deg, rgb(255 107 53 / 6%) 0%, rgb(255 140 66 / 45%) 100%)",
thumbIcon: "\u{1F512}",
title: "18-Layer Military Security",
description: "Revolutionary defense system with ECDH P-384 + AES-GCM 256 + ECDSA + Complete ASN.1 Validation. Enhanced Security Edition provides military-grade protection exceeding government standards with complete key structure verification."
description: "Revolutionary defense system with ECDH P-384 + AES-GCM 256 + ECDSA + Complete ASN.1 Validation."
},
{
icon: "fas fa-network-wired",
color: "purple",
title: "Pure P2P WebRTC Architecture",
description: "Direct peer-to-peer connections without any servers. Impossible to censor, block, or monitor. Complete decentralization with zero infrastructure."
icon: "\u{1F310}",
bgImage: "linear-gradient(135deg, rgb(147 51 234 / 6%) 0%, rgb(168 85 247 / 45%) 100%)",
thumbIcon: "\u{1F517}",
title: "Pure P2P WebRTC",
description: "Direct peer-to-peer connections without any servers. Complete decentralization with zero infrastructure."
},
{
icon: "fas fa-sync-alt",
color: "green",
icon: "\u{1F504}",
bgImage: "linear-gradient(135deg, rgb(16 185 129 / 6%) 0%, rgb(52 211 153 / 45%) 100%)",
thumbIcon: "\u26A1",
title: "Perfect Forward Secrecy",
description: "Automatic key rotation every 5 minutes or 100 messages. Non-extractable keys with hardware protection ensure past messages remain secure."
description: "Automatic key rotation every 5 minutes. Non-extractable keys with hardware protection."
},
{
icon: "fas fa-user-secret",
color: "cyan",
title: "Advanced Traffic Obfuscation",
description: "Fake traffic generation, packet padding, and pattern masking make communication indistinguishable from random noise. Defeats traffic analysis."
icon: "\u{1F3AD}",
bgImage: "linear-gradient(135deg, rgb(6 182 212 / 6%) 0%, rgb(34 211 238 / 45%) 100%)",
thumbIcon: "\u{1F32B}\uFE0F",
title: "Traffic Obfuscation",
description: "Fake traffic generation and pattern masking make communication indistinguishable from noise."
},
{
icon: "fas fa-eye-slash",
color: "blue",
icon: "\u{1F441}\uFE0F",
bgImage: "linear-gradient(135deg, rgb(37 99 235 / 6%) 0%, rgb(59 130 246 / 45%) 100%)",
thumbIcon: "\u{1F6AB}",
title: "Zero Data Collection",
description: "No registration, no servers, no logs. Messages exist only in browser memory. Complete anonymity with instant anonymous channels."
},
{
icon: "fas fa-code",
color: "emerald",
title: "100% Open Source Security",
description: "All code is open for audit under MIT license. Uses only standard WebCrypto APIs. Cryptography runs directly in browser without server dependencies."
description: "No registration, no servers, no logs. Complete anonymity with instant channels."
}
];
const nextSlide = () => setCurrentSlide((prev) => (prev + 1) % slides.length);
const prevSlide = () => setCurrentSlide((prev) => (prev - 1 + slides.length) % slides.length);
const goToSlide = (index) => setCurrentSlide(index);
React.useEffect(() => {
const timer = setInterval(() => {
nextSlide();
}, 15e3);
return () => clearInterval(timer);
const isMobile = () => window.matchMedia("(max-width:767px)").matches;
const center = React.useCallback((i) => {
if (!trackRef.current || !wrapRef.current) return;
const card = trackRef.current.children[i];
if (!card) return;
const axis = isMobile() ? "top" : "left";
const size = isMobile() ? "clientHeight" : "clientWidth";
const start2 = isMobile() ? card.offsetTop : card.offsetLeft;
wrapRef.current.scrollTo({
[axis]: start2 - (wrapRef.current[size] / 2 - card[size] / 2),
behavior: "smooth"
});
}, []);
return React.createElement("div", {
className: "mt-12"
}, [
const activate = React.useCallback((i, scroll = false) => {
if (i === current) return;
setCurrent(i);
if (scroll) {
setTimeout(() => center(i), 50);
}
}, [current, center]);
const go = (step) => {
const newIndex = Math.min(Math.max(current + step, 0), slides.length - 1);
activate(newIndex, true);
};
React.useEffect(() => {
const handleKeydown = (e) => {
if (["ArrowRight", "ArrowDown"].includes(e.key)) go(1);
if (["ArrowLeft", "ArrowUp"].includes(e.key)) go(-1);
};
window.addEventListener("keydown", handleKeydown, { passive: true });
return () => window.removeEventListener("keydown", handleKeydown);
}, [current]);
React.useEffect(() => {
center(current);
}, [current, center]);
return React.createElement("section", { style: { background: "transparent" } }, [
// Header
React.createElement("div", {
key: "header",
className: "text-center mb-8"
}, [
React.createElement("h3", {
key: "title",
className: "text-2xl font-semibold text-primary mb-3"
}, "Why SecureBit.chat is unique"),
React.createElement("p", {
key: "subtitle",
className: "text-secondary max-w-2xl mx-auto"
}, "The only messenger with military-grade cryptography")
]),
React.createElement("div", {
key: "slider-container",
className: "relative max-w-4xl mx-auto"
key: "head",
className: "head"
}, [
React.createElement("h2", { key: "title" }, "Why SecureBit.chat is unique"),
React.createElement("div", {
key: "slider-wrapper",
className: "overflow-hidden rounded-xl"
key: "controls",
className: "controls"
}, [
React.createElement("div", {
key: "slides",
className: "flex transition-transform duration-500 ease-in-out",
style: { transform: `translateX(-${currentSlide * 100}%)` }
}, slides.map(
(slide, index) => React.createElement("div", {
key: index,
className: "w-full flex-shrink-0 px-4"
React.createElement("button", {
key: "prev",
id: "prev-slider",
className: "nav-btn",
"aria-label": "Prev",
disabled: current === 0,
onClick: () => go(-1)
}, "\u2039"),
React.createElement("button", {
key: "next",
id: "next-slider",
className: "nav-btn",
"aria-label": "Next",
disabled: current === slides.length - 1,
onClick: () => go(1)
}, "\u203A")
])
]),
// Slider
React.createElement(
"div",
{
key: "slider",
className: "slider",
ref: wrapRef
},
React.createElement("div", {
className: "track",
ref: trackRef
}, slides.map(
(slide, index) => React.createElement("article", {
key: index,
className: "project-card",
...index === current ? { active: "" } : {},
onMouseEnter: () => {
if (window.matchMedia("(hover:hover)").matches) {
activate(index, true);
}
},
onClick: () => activate(index, true)
}, [
// Background
React.createElement("div", {
key: "bg",
className: "project-card__bg",
style: {
background: slide.bgImage,
backgroundSize: "cover",
backgroundPosition: "center"
}
}),
// Content
React.createElement("div", {
key: "content",
className: "project-card__content"
}, [
React.createElement("div", {
key: "slide-content",
className: "card-minimal rounded-xl p-8 text-center min-h-[300px] flex flex-col justify-center relative overflow-hidden"
}, [
// Background icon
React.createElement("i", {
key: "bg-icon",
className: `${slide.icon} absolute right-[-100px] top-1/2 -translate-y-1/2 opacity-10 text-[300px] pointer-events-none ${slide.color === "orange" ? "text-orange-500" : slide.color === "yellow" ? "text-yellow-500" : slide.color === "purple" ? "text-purple-500" : slide.color === "green" ? "text-green-500" : slide.color === "cyan" ? "text-cyan-500" : slide.color === "blue" ? "text-blue-500" : "text-emerald-500"}`
}),
// Content
React.createElement("h4", {
key: "slide-title",
className: "text-xl font-semibold text-primary mb-4 relative z-10"
// Text container
React.createElement("div", { key: "text" }, [
React.createElement("h3", {
key: "title",
className: "project-card__title"
}, slide.title),
React.createElement("p", {
key: "slide-description",
className: "text-secondary leading-relaxed max-w-2xl mx-auto relative z-10"
key: "desc",
className: "project-card__desc"
}, slide.description)
])
])
))
]),
// Navigation
React.createElement("button", {
key: "prev-btn",
onClick: prevSlide,
className: "absolute left-2 top-1/2 transform -translate-y-1/2 w-10 h-10 bg-gray-600/80 hover:bg-gray-500/80 text-white rounded-full flex items-center justify-center transition-all duration-200 z-10"
}, [
React.createElement("i", {
key: "prev-icon",
className: "fas fa-chevron-left"
})
]),
React.createElement("button", {
key: "next-btn",
onClick: nextSlide,
className: "absolute right-2 top-1/2 transform -translate-y-1/2 w-10 h-10 bg-gray-600/80 hover:bg-gray-500/80 text-white rounded-full flex items-center justify-center transition-all duration-200 z-10"
}, [
React.createElement("i", {
key: "next-icon",
className: "fas fa-chevron-right"
})
])
]),
// Enhanced dots navigation (оставляем улучшенные точки)
])
))
),
// Dots
React.createElement("div", {
key: "dots-container",
className: "flex justify-center space-x-3 mt-6"
key: "dots",
className: "dots",
ref: dotsRef,
...isMobile() ? { hidden: true } : {}
}, slides.map(
(slide, index) => React.createElement("button", {
(_, index) => React.createElement("span", {
key: index,
onClick: () => goToSlide(index),
className: `relative group transition-all duration-300 ${index === currentSlide ? "w-12 h-2 bg-orange-500 rounded-full" : "w-4 h-2 bg-gray-600 hover:bg-gray-500 rounded-full hover:scale-125"}`
}, [
// Tooltip on hover
React.createElement("div", {
key: "tooltip",
className: "absolute -top-10 left-1/2 transform -translate-x-1/2 bg-gray-800 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity duration-200 whitespace-nowrap pointer-events-none"
}, slide.title)
])
className: `dot ${index === current ? "active" : ""}`,
onClick: () => activate(index, true)
})
))
]);
};

File diff suppressed because one or more lines are too long