diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..e0aa528 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,12 @@ +/** + * Minimal ESLint config (legacy .eslintrc.cjs) so `next lint` runs non-interactively. + * It extends the Next.js recommended rules. Adjust rules as needed. + */ +module.exports = { + root: true, + extends: ["next/core-web-vitals"], + rules: { + // Keep rules conservative for automated fixes. + // You can add/adjust rules here. + }, +}; diff --git a/app/globals.css b/app/globals.css index 7648226..bf5415a 100644 --- a/app/globals.css +++ b/app/globals.css @@ -4,52 +4,61 @@ @layer base { :root { - --background: 0 0% 100%; - --foreground: 222.2 84% 4.9%; + --background: 220 33% 97%; + --foreground: 222 47% 11%; --card: 0 0% 100%; - --card-foreground: 222.2 84% 4.9%; + --card-foreground: 222 47% 11%; --popover: 0 0% 100%; - --popover-foreground: 222.2 84% 4.9%; - --primary: 221.2 83.2% 53.3%; + --popover-foreground: 222 47% 11%; + --primary: 239 84% 67%; --primary-foreground: 210 40% 98%; - --secondary: 210 40% 96%; - --secondary-foreground: 222.2 84% 4.9%; - --muted: 210 40% 96%; - --muted-foreground: 215.4 16.3% 46.9%; - --accent: 210 40% 96%; - --accent-foreground: 222.2 84% 4.9%; - --destructive: 0 84.2% 60.2%; + --secondary: 214 32% 88%; + --secondary-foreground: 222 47% 11%; + --muted: 217 25% 92%; + --muted-foreground: 219 15% 35%; + --accent: 214 32% 88%; + --accent-foreground: 222 47% 11%; + --destructive: 0 72% 51%; --destructive-foreground: 210 40% 98%; - --border: 214.3 31.8% 91.4%; - --input: 214.3 31.8% 91.4%; - --ring: 221.2 83.2% 53.3%; - --radius: 0.75rem; + --border: 214 32% 90%; + --input: 214 32% 88%; + --ring: 242 84% 70%; + --radius: 0.875rem; + --glow: 243 96% 76%; + --surface-glass: rgba(255, 255, 255, 0.68); + --surface-muted: rgba(242, 246, 255, 0.92); + --shadow-soft: 0 24px 80px rgba(15, 23, 42, 0.12); + --shadow-strong: 0 40px 120px rgba(30, 64, 175, 0.22); - /* Transition timing */ --theme-transition-duration: 0.5s; --theme-transition-timing: cubic-bezier(0.4, 0, 0.2, 1); } .dark { - --background: 0 0% 0%; - --foreground: 210 40% 98%; - --card: 0 0% 0%; - --card-foreground: 210 40% 98%; - --popover: 0 0% 0%; - --popover-foreground: 210 40% 98%; - --primary: 217.2 91.2% 59.8%; - --primary-foreground: 222.2 84% 4.9%; - --secondary: 262 83% 58%; - --secondary-foreground: 210 40% 98%; - --muted: 262 83% 14%; - --muted-foreground: 215.4 16.3% 65%; - --accent: 262 83% 14%; - --accent-foreground: 210 40% 98%; - --destructive: 0 62.8% 30.6%; + --background: 230 38% 3%; + --foreground: 216 100% 97%; + --card: rgba(9, 11, 25, 0.78); + --card-foreground: 216 100% 97%; + --popover: rgba(9, 11, 25, 0.78); + --popover-foreground: 216 100% 97%; + --primary: 240 84% 71%; + --primary-foreground: 216 100% 97%; + --secondary: rgba(33, 42, 80, 0.86); + --secondary-foreground: 216 100% 97%; + --muted: rgba(33, 42, 80, 0.68); + --muted-foreground: 220 35% 78%; + --accent: rgba(88, 28, 135, 0.68); + --accent-foreground: 216 100% 97%; + --destructive: 0 78% 48%; --destructive-foreground: 210 40% 98%; - --border: 262 83% 14%; - --input: 262 83% 14%; - --ring: 217.2 91.2% 59.8%; + --border: rgba(148, 163, 184, 0.12); + --input: rgba(148, 163, 184, 0.12); + --ring: rgba(129, 140, 248, 0.9); + --glow: rgba(124, 58, 237, 0.55); + --surface-glass: rgba(18, 22, 40, 0.62); + --surface-muted: rgba(24, 32, 68, 0.5); + --shadow-soft: 0 32px 96px rgba(15, 23, 42, 0.42); + --shadow-strong: 0 52px 160px rgba(59, 130, 246, 0.32); } } @@ -58,7 +67,6 @@ @apply border-border; } - /* Smooth transitions for all elements */ *, *::before, *::after { @@ -69,71 +77,475 @@ fill var(--theme-transition-duration) var(--theme-transition-timing), stroke var(--theme-transition-duration) var(--theme-transition-timing), box-shadow var(--theme-transition-duration) var(--theme-transition-timing), - backdrop-filter var(--theme-transition-duration) var(--theme-transition-timing); + backdrop-filter var(--theme-transition-duration) var(--theme-transition-timing), + transform 240ms ease; + } + + html { + @apply scroll-smooth; } body { - @apply bg-background text-foreground; - transition: background var(--theme-transition-duration) var(--theme-transition-timing), color - var(--theme-transition-duration) var(--theme-transition-timing); + @apply bg-background text-foreground antialiased; + font-family: var(--font-inter), system-ui, -apple-system, "Segoe UI", sans-serif; + background-image: radial-gradient( + circle at 10% 20%, + rgba(59, 130, 246, 0.16) 0%, + rgba(59, 130, 246, 0) 40% + ), + radial-gradient( + circle at 80% 0%, + rgba(147, 51, 234, 0.18) 0%, + rgba(147, 51, 234, 0) 45% + ), + linear-gradient( + 120deg, + rgba(255, 255, 255, 0.92), + rgba(229, 231, 235, 0.66) + ); + min-height: 100vh; + transition: background 700ms ease, + color var(--theme-transition-duration) var(--theme-transition-timing); } - /* Custom dark mode background with smooth transition */ .dark body { - background: linear-gradient(135deg, #1a1a2e 0%, #16213e 25%, #0f3460 50%, #533483 75%, #7209b7 100%); + background-image: radial-gradient( + circle at 3% -10%, + rgba(56, 189, 248, 0.25) 0%, + rgba(56, 189, 248, 0) 45% + ), + radial-gradient( + circle at 110% 20%, + rgba(124, 58, 237, 0.32) 0%, + rgba(124, 58, 237, 0) 55% + ), + linear-gradient(160deg, rgba(3, 7, 18, 0.98), rgba(15, 23, 42, 0.92)); background-attachment: fixed; } - .dark .bg-background { - background: rgba(26, 26, 46, 0.8); - backdrop-filter: blur(10px); + h1, + h2, + h3, + h4, + h5, + h6 { + @apply text-slate-900 dark:text-white; + font-family: var(--font-sora), "Inter", system-ui, sans-serif; + letter-spacing: -0.015em; } - .dark .bg-muted\/30 { - background: rgba(83, 52, 131, 0.2); - backdrop-filter: blur(10px); + h1 { + @apply text-4xl font-bold sm:text-5xl; } - .dark .bg-card { - background: rgba(22, 33, 62, 0.8); - backdrop-filter: blur(10px); - border: 1px solid rgba(83, 52, 131, 0.3); + h2 { + @apply text-3xl font-semibold sm:text-4xl; } - /* Smooth transitions for specific components */ - .theme-transition { - transition: all var(--theme-transition-duration) var(--theme-transition-timing); + h3 { + @apply text-2xl font-semibold sm:text-3xl; } - /* Enhanced transitions for interactive elements */ - button, - a, - .card, - .badge { - transition: - background-color var(--theme-transition-duration) var(--theme-transition-timing), - border-color var(--theme-transition-duration) var(--theme-transition-timing), - color var(--theme-transition-duration) var(--theme-transition-timing), - box-shadow var(--theme-transition-duration) var(--theme-transition-timing), - transform 0.2s ease; + h4 { + @apply text-xl font-semibold sm:text-2xl; + } + + h5 { + @apply text-lg font-semibold; + } + + h6 { + @apply text-base font-semibold; + } + + p { + @apply leading-relaxed; + } + + .font-display { + font-family: var(--font-sora), "Inter", system-ui, sans-serif; + } + + .font-sans { + font-family: var(--font-inter), system-ui, sans-serif; + } + + ::selection { + background-color: theme("colors.indigo.500"); + color: white; } - /* Gradient transitions */ - .gradient-transition { - background-size: 200% 200%; - transition: background-position var(--theme-transition-duration) var(--theme-transition-timing), background-color - var(--theme-transition-duration) var(--theme-transition-timing); + :-moz-focusring, + :focus-visible { + outline: 2px solid rgba(129, 140, 248, 0.9); + outline-offset: 2px; } - /* Icon transitions */ - svg { - transition: color var(--theme-transition-duration) var(--theme-transition-timing), fill - var(--theme-transition-duration) var(--theme-transition-timing), stroke var(--theme-transition-duration) + .glass-surface { + background: var(--surface-glass); + box-shadow: var(--shadow-soft); + backdrop-filter: blur(18px) saturate(140%); + border: 1px solid rgba(255, 255, 255, 0.18); + } + + .dark .glass-surface { + border-color: rgba(148, 163, 184, 0.16); + } + + .soft-shadow { + box-shadow: var(--shadow-soft); + } + + .strong-shadow { + box-shadow: var(--shadow-strong); + } + + .theme-transition { + transition: all var(--theme-transition-duration) var(--theme-transition-timing); } - /* Prevent transitions on page load */ - .preload * { + .preload *, + .preload *::before, + .preload *::after { transition: none !important; } } + +@layer components { + .container-responsive { + @apply mx-auto w-full max-w-6xl px-4 sm:px-6 lg:px-8; + } + + .section-shell { + @apply relative isolate overflow-hidden py-20; + } + + .interactive-card { + @apply rounded-3xl border border-white/10 bg-white/70 p-8 shadow-xl backdrop-blur-xl transition; + } + + .interactive-card:hover { + @apply -translate-y-2 shadow-2xl; + } + + .dark .interactive-card { + /* Use explicit dark-mode overrides rather than variant @apply to avoid + PostCSS/Tailwind @apply variant limitations in some environments. */ + border-color: rgba(255, 255, 255, 0.05); + background-color: rgba(255, 255, 255, 0.05); + box-shadow: 0 30px 120px rgba(15, 23, 42, 0.45); + } + + .glow-ring { + box-shadow: 0 0 0 1px rgba(99, 102, 241, 0.14), + 0 20px 80px rgba(99, 102, 241, 0.25); + } + + .floating { + animation: floating 8s ease-in-out infinite; + } + + .floating-delayed { + animation-delay: 2.5s; + } + + .gradient-border { + position: relative; + } + .gradient-border::before { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 1px; + background: linear-gradient( + 135deg, + rgba(129, 140, 248, 0.8), + rgba(236, 72, 153, 0.6) + ); + -webkit-mask: linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; + } + + .scroll-indicator-gradient { + background: linear-gradient( + 90deg, + rgba(129, 140, 248, 0.35), + rgba(236, 72, 153, 0.35) + ); + } + + .focus-ring { + /* Provide an accessible focus ring without using variant prefixes in @apply. */ + outline: none; + } + + .focus-ring:focus-visible { + outline: 2px solid rgba(129, 140, 248, 0.9); + outline-offset: 2px; + } +} + +@layer utilities { + .text-gradient-primary { + @apply bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 bg-clip-text text-transparent; + } + + .text-gradient-secondary { + @apply bg-gradient-to-br from-sky-400 via-indigo-400 to-fuchsia-500 bg-clip-text text-transparent; + } + + .bg-grid { + background-image: linear-gradient( + rgba(148, 163, 184, 0.12) 1px, + transparent 0 + ), + linear-gradient(90deg, rgba(148, 163, 184, 0.12) 1px, transparent 0); + background-size: 40px 40px; + } + + .dark .bg-grid { + background-image: linear-gradient(rgba(55, 65, 81, 0.32) 1px, transparent 0), + linear-gradient(90deg, rgba(55, 65, 81, 0.32) 1px, transparent 0); + } + + .backdrop-gradient { + background-image: linear-gradient( + 120deg, + rgba(59, 130, 246, 0.18), + rgba(236, 72, 153, 0.2) + ); + } + + .dark .backdrop-gradient { + background-image: linear-gradient( + 120deg, + rgba(59, 130, 246, 0.28), + rgba(236, 72, 153, 0.32) + ); + } + + .section-divider { + @apply relative isolate overflow-hidden py-6; + } +} + +@keyframes floating { + 0% { + transform: translate3d(0, 0, 0); + } + 50% { + transform: translate3d(0, -12px, 0); + } + 100% { + transform: translate3d(0, 0, 0); + } +} + +/* Scrollbar styling */ +* { + scrollbar-width: thin; + scrollbar-color: rgba(99, 102, 241, 0.8) rgba(148, 163, 184, 0.16); +} + +*::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +*::-webkit-scrollbar-track { + background: transparent; +} + +*::-webkit-scrollbar-thumb { + background: linear-gradient( + 180deg, + rgba(129, 140, 248, 0.92), + rgba(236, 72, 153, 0.85) + ); + border-radius: 9999px; + border: 2px solid rgba(255, 255, 255, 0.1); +} + +/* Entrance utilities */ +.fade-up { + opacity: 0; + transform: translateY(16px); + animation: fadeUp 0.8s ease forwards; +} + +.fade-right { + opacity: 0; + transform: translateX(-16px); + animation: fadeRight 0.8s ease forwards; +} + +@keyframes fadeUp { + 0% { + opacity: 0; + transform: translateY(24px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeRight { + 0% { + opacity: 0; + transform: translateX(-24px); + } + 100% { + opacity: 1; + transform: translateX(0); + } +} + +/* Animation delay utilities */ +.animate-delay-02s { + animation-delay: 0.2s; +} + +.animate-delay-04s { + animation-delay: 0.4s; +} + +.animate-delay-06s { + animation-delay: 0.6s; +} + +.animate-delay-08s { + animation-delay: 0.8s; +} + +.animate-delay-1s { + animation-delay: 1s; +} + +.animate-delay-2s { + animation-delay: 2s; +} + +.animate-delay-3s { + animation-delay: 3s; +} + +.animate-delay-4s { + animation-delay: 4s; +} + +/* Feature card animation delays */ +.animate-delay-01s { + animation-delay: 0.1s; +} + +.animate-delay-02s { + animation-delay: 0.2s; +} + +.animate-delay-03s { + animation-delay: 0.3s; +} + +.animate-delay-04s { + animation-delay: 0.4s; +} + +.animate-delay-05s { + animation-delay: 0.5s; +} + +.animate-delay-06s { + animation-delay: 0.6s; +} + +.animate-delay-09s { + animation-delay: 0.9s; +} + +.animate-delay-12s { + animation-delay: 1.2s; +} + +.animate-delay-15s { + animation-delay: 1.5s; +} + +.animate-delay-18s { + animation-delay: 1.8s; +} + +.animate-delay-21s { + animation-delay: 2.1s; +} + +.animate-delay-24s { + animation-delay: 2.4s; +} + +.animate-delay-27s { + animation-delay: 2.7s; +} + +.animate-delay-30s { + animation-delay: 3.0s; +} + +.animate-duration-15s { + animation-duration: 15s; +} + +.animate-duration-20s { + animation-duration: 20s; +} + +.animate-reverse { + animation-direction: reverse; +} + +/* Text shadow utilities */ +.text-shadow-glow { + text-shadow: 0 0 20px rgba(59, 130, 246, 0.5), 0 0 40px rgba(147, 51, 234, 0.3), 0 0 60px rgba(236, 72, 153, 0.2); +} + +/* Navbar link underline + active state */ +.nav-link { + position: relative; + display: inline-block; + padding-bottom: 6px; +} +.nav-link::after { + content: ""; + position: absolute; + left: 50%; + transform: translateX(-50%); + bottom: 0; + height: 3px; + width: 0; + border-radius: 9999px; + background: linear-gradient(90deg, rgba(99,102,241,0.95), rgba(168,85,247,0.9)); + transition: width 220ms cubic-bezier(.2,.9,.2,1); +} +.nav-link:hover::after, +.nav-link.active::after { + width: 48px; +} + +/* Mobile menu slide down */ +.mobile-popover { + transform-origin: top center; + transition: transform 220ms cubic-bezier(.2,.9,.2,1), opacity 180ms ease; +} +.mobile-popover.open { + transform: translateY(0) scaleY(1); + opacity: 1; +} +.mobile-popover.closed { + transform: translateY(-6px) scaleY(0.98); + opacity: 0; +} diff --git a/app/layout.tsx b/app/layout.tsx index 2674f82..7ca1a77 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -6,16 +6,69 @@ import { ThemeProvider } from "@/components/theme-provider" const inter = Inter({ subsets: ["latin"] }) +const siteUrl = "https://s3ducky.app" +const ogImage = "https://s3ducky.app/og-image.png" +const twitterHandle = "@s3ducky" + export const metadata: Metadata = { - title: "S3Ducky - Modern S3 Bucket Viewer for Windows", + metadataBase: new URL(siteUrl), + title: { + default: "S3Ducky — Advanced S3 Bucket Explorer", + template: "%s | S3Ducky", + }, description: - "A powerful, secure, and user-friendly desktop application for browsing, managing, and downloading files from your AWS S3 buckets.", - generator: 'v0.dev', + "S3Ducky is a modern, secure desktop experience for exploring, managing, and downloading AWS S3 bucket content with confidence.", + keywords: [ + "S3", + "AWS", + "object storage", + "desktop app", + "file manager", + "cloud explorer", + ], + generator: "Cascade", + applicationName: "S3Ducky", + authors: [{ name: "S3Ducky", url: siteUrl }], icons: { icon: [ - { url: '/S3DuckyLogo.ico', type: 'image/x-icon' } - ] - } + { url: "/S3DuckyLogo.ico", type: "image/x-icon" }, + { url: "/favicon-32x32.png", sizes: "32x32", type: "image/png" }, + { url: "/favicon-16x16.png", sizes: "16x16", type: "image/png" }, + ], + apple: { url: "/apple-touch-icon.png", sizes: "180x180", type: "image/png" }, + }, + manifest: "/site.webmanifest", + openGraph: { + title: "S3Ducky — Advanced S3 Bucket Explorer", + description: + "Discover a beautifully crafted S3 management experience with secure credential handling, intelligent filtering, and buttery-smooth UX.", + url: siteUrl, + siteName: "S3Ducky", + images: [ + { + url: ogImage, + width: 1200, + height: 630, + alt: "Preview of the S3Ducky desktop application UI", + }, + ], + locale: "en_US", + type: "website", + }, + twitter: { + card: "summary_large_image", + creator: twitterHandle, + site: twitterHandle, + title: "S3Ducky — Advanced S3 Bucket Explorer", + description: + "A bold reimagining of the S3 browsing experience with a focus on security, clarity, and speed.", + images: [ogImage], + }, + themeColor: "#f9fafb", + category: "software", + alternates: { + canonical: siteUrl, + }, } export default function RootLayout({ diff --git a/app/not-found.tsx b/app/not-found.tsx new file mode 100644 index 0000000..b8ee0e8 --- /dev/null +++ b/app/not-found.tsx @@ -0,0 +1,14 @@ +import React from "react" +import Link from "next/link" + +export default function NotFound() { + return ( +
+
+

404

+

We couldn't find the page you're looking for.

+ Return home +
+
+ ) +} diff --git a/app/page.tsx b/app/page.tsx index cd38654..9a9d3f6 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,52 +1,21 @@ "use client" import { useState, useEffect } from "react" +import { Download, Shield, FolderOpen, Filter, MousePointer, Monitor, AlertTriangle, ChevronDown, ExternalLink, Github } from "lucide-react" import { Button } from "@/components/ui/button" import { Card, CardContent } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" -import { - Download, - Shield, - FolderOpen, - Filter, - MousePointer, - Monitor, - AlertTriangle, - Github, - ExternalLink, - Moon, - Sun, - ChevronDown, -} from "lucide-react" -import { useTheme } from "next-themes" -import DownloadCards from "@/components/DownloadCards" import Header from "@/components/Header" +import DownloadCards from "@/components/DownloadCards" export default function S3DuckyLanding() { - const { theme, setTheme } = useTheme() - const [expandedVersion, setExpandedVersion] = useState(null) const [mounted, setMounted] = useState(false) + const [expandedVersion, setExpandedVersion] = useState(null) - // Ensure component is mounted before rendering theme-dependent content useEffect(() => { setMounted(true) - // Remove preload class after component mounts to enable transitions - const timer = setTimeout(() => { - document.body.classList.remove("preload") - }, 100) - return () => clearTimeout(timer) }, []) - // Add preload class to prevent transitions on initial load - useEffect(() => { - document.body.classList.add("preload") - }, []) - - const handleThemeToggle = () => { - const newTheme = theme === "dark" ? "light" : "dark" - setTheme(newTheme) - } - const features = [ { icon: Shield, @@ -110,88 +79,153 @@ export default function S3DuckyLanding() { } return ( -
- {/* Header */} +
+ {/* Animated Background Elements */} +
+
+
+
+
+
{/* Hero Section */} -
-
-
+
+
+ {/* Floating Elements */} +
+
+
+ +
+ {/* Animated Ring */} +
+
+
-

- S3Ducky + +

+ + S3Ducky + {/* Enhanced Glow Effect */} +
+
+ {/* Light mode text shadow for better visibility */} +
+ S3Ducky +
+

-

+ +

Modern S3 Bucket Viewer for Windows

-

+ +

A powerful, secure, and user-friendly desktop application for browsing, managing, and downloading files from - your AWS S3 buckets. + your AWS S3 buckets with stunning visual design.

-
+ + -
+ +
- Windows 10+ +
+ Windows 10+ +
+
- Free & Open Source +
+ Free & Open Source +
+
- MIT License +
+ MIT License +
+
- {/* Features Section */} -
-
+ {/* Features Section */} +
+ {/* Section Background Effects */} +
+
+
+ +
-

Powerful Features

-

+

Powerful Features

+

Everything you need to manage your S3 buckets efficiently and securely

+ {/* Decorative Line */} +
+
+
{features.map((feature, index) => ( - + {/* Card Background Glow */} +
+ + {/* Floating Particles */} +
+
+ +
-
- +
+ + {/* Icon Glow */} +
-

{feature.title}

+

{feature.title}

-

{feature.description}

+

{feature.description}

))} @@ -199,87 +233,176 @@ export default function S3DuckyLanding() {
- {/* Screenshots Section */} -
-
+ {/* Screenshots / Action Section */} +
+ {/* Section Background Effects */} +
+
+
+ +
-

See S3Ducky in Action

-

- Clean, intuitive interface designed for productivity +

See S3Ducky in Action

+

+ Explore the intuitive interface and powerful features through these screenshots

+ {/* Decorative Line */} +
+
+
-
- - -
-
- -

Credential Input Screenshot

-
+
+ + {/* Card Background Glow */} +
+ + {/* Floating Particles */} +
+
+ +
+ {/* Animated Background Pattern */} +
+
+
-
-

Secure Credential Input

-

- Simple and secure AWS credential management with encrypted local storage -

+
+ +

Main Interface

+
+ +

Clean Modern Interface

+

+ Intuitive design with easy navigation and clear visual hierarchy +

- - -
-
- -

File Browser Screenshot

-
+ + + {/* Card Background Glow */} +
+ + {/* Floating Particles */} +
+
+ +
+ {/* Animated Background Pattern */} +
+
+
-
-

Intuitive File Browser

-

- Browse your S3 buckets with full metadata, filtering, and multi-selection support -

+
+ +

File Browser

+
+ +

S3 Bucket Explorer

+

+ Browse files and folders with full metadata display and navigation +

+
+ + + + {/* Card Background Glow */} +
+ + {/* Floating Particles */} +
+
+ +
+ {/* Animated Background Pattern */} +
+
+
+
+
+ +

Multi-Selection

+
+
+ +

Batch Operations

+

+ Select multiple files for batch downloads and ZIP creation +

- {/* Version Info Section */} -
-
+ {/* Version Info Section */} +
+ {/* Section Background Effects */} +
+
+
+ +
-

Release History

-

Track the evolution of S3Ducky

+

Version History

+

+ Stay updated with the latest features and improvements +

+ {/* Decorative Line */} +
+
+
{versions.map((version, index) => ( - - + + {/* Card Background Glow */} +
+ + {/* Floating Particles */} +
+
+ +
setExpandedVersion(expandedVersion === version.version ? null : version.version)} >
- - {version.version} - - {version.date} +
+ {version.version} + {/* Icon Glow */} +
+
+
+

Version {version.version}

+

Released on {version.date}

+
{expandedVersion === version.version && ( -
+
+

What's New:

    {version.changes.map((change, changeIndex) => ( -
  • - - {change} +
  • +
    +

    {change}

  • ))}
@@ -289,133 +412,78 @@ export default function S3DuckyLanding() { ))}
-
- {/* Download Section */} - + {/* Get Started / Download Section */} +
+
+

Ready to Get Started?

+

Download S3Ducky and start browsing your S3 buckets securely.

+
+ +
{/* Footer */} -