The mobile menu becomes a surface you drag rather than one that appears and vanishes: it tracks the finger, carries its velocity when flicked, can be caught mid-flight, and resists past the edge instead of stopping dead. Buttons react on press rather than on release, and the browser's tap delay is gone — nothing here zooms, so the wait bought nothing. prefers-reduced-motion, prefers-reduced-transparency and prefers-contrast are now respected instead of ignored: looping decoration stops, transitions fade rather than slide, the chat jumps to the newest message, frosted panels turn solid and edges get drawn. What stops is the movement, never the information — recording indicators and other status stay. Also bumps the desktop download buttons to 0.5.0. The version lives in one constant per source file and tests/desktop-download-links.test.mjs fetches every generated URL, so the links are proven to serve a real asset rather than merely looking well-formed. Claude-Session: https://claude.ai/code/session_01ARFZ9G6P1e1B4w75kFaeNw
97 lines
5.8 KiB
React
97 lines
5.8 KiB
React
// Desktop release these links point at. Bump this one constant when a new
|
|
// desktop version ships — the version used to be repeated in three URLs in two
|
|
// different forms, which is how they ended up stuck on 0.1.0.
|
|
//
|
|
// The tag is pinned rather than using /releases/latest/download/: the filenames
|
|
// carry the version, so a `latest` link 404s the moment a newer release exists,
|
|
// whereas a pinned tag keeps serving a working (if older) installer.
|
|
const DESKTOP_VERSION = '0.5.0';
|
|
const DESKTOP_RELEASE = `https://github.com/SecureBitChat/securebit-desktop/releases/download/v${DESKTOP_VERSION}`;
|
|
|
|
const DownloadApps = () => {
|
|
const apps = [
|
|
{ id: 'web', name: 'Web App', subtitle: 'Browser Version', icon: 'fas fa-globe', platform: 'Web', isActive: true, url: 'https://securebit.chat/', color: 'green' },
|
|
{ id: 'windows', name: 'Windows', subtitle: 'Desktop App', icon: 'fab fa-windows', platform: 'Desktop', isActive: true, url: `${DESKTOP_RELEASE}/SecureBit.Chat_${DESKTOP_VERSION}_x64-setup.exe`, color: 'blue' },
|
|
{ id: 'macos', name: 'macOS', subtitle: 'Desktop App', icon: 'fab fa-safari', platform: 'Desktop', isActive: true, url: `${DESKTOP_RELEASE}/SecureBit.Chat_${DESKTOP_VERSION}_x64.dmg`, color: 'gray' },
|
|
{ id: 'linux', name: 'Linux', subtitle: 'Desktop App', icon: 'fab fa-linux', platform: 'Desktop', isActive: true, url: `${DESKTOP_RELEASE}/SecureBit.Chat_${DESKTOP_VERSION}_amd64.AppImage`, color: 'orange' },
|
|
{ id: 'ios', name: 'iOS', subtitle: 'iPhone & iPad', icon: 'fab fa-apple', platform: 'Mobile', isActive: false, url: 'https://apps.apple.com/app/securebit-chat/', color: 'white' },
|
|
{ id: 'android', name: 'Android', subtitle: 'Google Play', icon: 'fab fa-android', platform: 'Mobile', isActive: false, url: 'https://play.google.com/store/apps/details?id=com.securebit.chat', color: 'green' },
|
|
{ id: 'chrome', name: 'Chrome', subtitle: 'Browser Extension', icon: 'fab fa-chrome', platform: 'Browser', isActive: false, url: '#', color: 'yellow' },
|
|
{ id: 'edge', name: 'Edge', subtitle: 'Browser Extension', icon: 'fab fa-edge', platform: 'Browser', isActive: false, url: '#', color: 'blue' },
|
|
{ id: 'opera', name: 'Opera', subtitle: 'Browser Extension', icon: 'fab fa-opera', platform: 'Browser', isActive: false, url: '#', color: 'red' },
|
|
{ id: 'firefox', name: 'Firefox', subtitle: 'Browser Extension', icon: 'fab fa-firefox-browser', platform: 'Browser', isActive: false, url: '#', color: 'orange' },
|
|
];
|
|
|
|
const handleDownload = (app) => {
|
|
if (app.isActive) window.open(app.url, '_blank');
|
|
};
|
|
|
|
const desktopApps = apps.filter(a => a.platform === 'Desktop' || a.platform === 'Web');
|
|
const mobileApps = apps.filter(a => a.platform === 'Mobile');
|
|
const browserApps = apps.filter(a => a.platform === 'Browser');
|
|
|
|
const cardSize = "w-28 h-28";
|
|
|
|
const colorClasses = {
|
|
green: 'text-green-500',
|
|
blue: 'text-blue-500',
|
|
gray: 'text-gray-500',
|
|
orange: 'text-orange-500',
|
|
red: 'text-red-500',
|
|
white: 'text-white',
|
|
yellow: 'text-yellow-400',
|
|
};
|
|
|
|
const renderAppCard = (app) => (
|
|
React.createElement('div', {
|
|
key: app.id,
|
|
className: `group relative ${cardSize} rounded-2xl overflow-hidden card-minimal cursor-pointer`
|
|
}, [
|
|
React.createElement('i', {
|
|
key: 'bg-icon',
|
|
className: `${app.icon} absolute text-[3rem] ${app.isActive ? colorClasses[app.color] : 'text-white/10'} top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none transition-all duration-500 group-hover:scale-105`
|
|
}),
|
|
React.createElement('div', {
|
|
key: 'overlay',
|
|
className: "absolute inset-0 bg-black/30 backdrop-blur-md flex flex-col items-center justify-center text-center opacity-0 transition-opacity duration-300 group-hover:opacity-100"
|
|
}, [
|
|
React.createElement('h4', { key: 'name', className: `text-sm font-semibold text-primary mb-1` }, app.name),
|
|
React.createElement('p', { key: 'subtitle', className: `text-xs text-secondary mb-2` }, app.subtitle),
|
|
app.isActive ?
|
|
React.createElement('button', {
|
|
key: 'btn',
|
|
onClick: () => handleDownload(app),
|
|
className: `px-2 py-1 rounded-xl bg-emerald-500 text-black font-medium hover:bg-emerald-600 transition-colors text-xs`
|
|
}, app.id === "web" ? "Launch" : "Download")
|
|
:
|
|
React.createElement('span', { key: 'coming', className: "text-gray-400 font-medium text-xs" }, "Coming Soon")
|
|
])
|
|
])
|
|
);
|
|
|
|
return React.createElement('div', { className: "mt-20 px-6" }, [
|
|
// Header
|
|
React.createElement('div', { key: 'header', className: "text-center max-w-3xl mx-auto mb-12" }, [
|
|
React.createElement('h3', { key: 'title', className: "text-3xl font-bold text-primary mb-3" }, 'Download SecureBit.chat'),
|
|
React.createElement('p', { key: 'subtitle', className: "text-secondary text-lg mb-5" }, 'Stay secure on every device. Choose your platform and start chatting privately.')
|
|
]),
|
|
|
|
// Desktop Apps
|
|
React.createElement('div', { key: 'desktop-row', className: "hidden sm:flex justify-center flex-wrap gap-6 mb-6" },
|
|
desktopApps.map(renderAppCard)
|
|
),
|
|
|
|
// Mobile Apps
|
|
React.createElement('div', { key: 'mobile-row', className: "flex justify-center gap-6 mb-6" },
|
|
mobileApps.map(renderAppCard)
|
|
),
|
|
|
|
// Browser Extensions
|
|
React.createElement('div', { key: 'browser-row', className: "flex justify-center gap-6" },
|
|
browserApps.map(renderAppCard)
|
|
)
|
|
]);
|
|
};
|
|
|
|
window.DownloadApps = DownloadApps;
|