v1.0.1 Now Available

The Developer-First
FTP Client.

Stop fighting with your file transfer client. Integrated terminal, dual-pane explorer, and a workflow designed for flow state.

Download for Windows v1.0.1 • Windows 10/11
Shift App Interface
const connection = await client.connect();
// Connection established

Terminal First

Don't lose your muscle memory. Execute ls -la and grep directly while you manage files conceptually.

Dual Protocol

Seamless switching between legacy FTP and secure SFTP. Smart connection pooling keeps your session alive.

Config Driven

Settings as code. Export your site profiles and preferences as JSON. Portable and easy to version control.

Dual Pane

Local and remote file systems side by side. Drag, drop, and manage files with an intuitive interface.

Secure First

SSH key authentication, encrypted connections, and secure credential storage. Your data stays safe.

Lightning Fast

Built with Electron and optimized for speed. Parallel transfers and smart caching for maximum throughput.

`; } else if (type === 'error') { iconHtml = `
`; } else { iconHtml = `
`; } Swal.fire({ html: `
${iconHtml}

${title}

${message}

`, background: 'transparent', showConfirmButton: true, confirmButtonText: btnText, buttonsStyling: false, customClass: { popup: 'codend-popup', confirmButton: 'codend-confirm-btn', htmlContainer: 'no-padding' } }); }; // Auto-detect Currency based on Timezone if not already set by user // We check a cookie or a global js var. Since we don't have a cookie lib loaded, // we'll rely on the server passing 'default_currency' vs 'current_currency'. // Actually, we can check if the URL has ?currency. If not, and we haven't detected before (localStorage), do it. const savedCurrency = localStorage.getItem('codend_currency'); const urlParams = new URLSearchParams(window.location.search); const urlCurrency = urlParams.get('currency'); if (urlCurrency) { // User explicitly set via URL, save it localStorage.setItem('codend_currency', urlCurrency); } else if (!savedCurrency) { // No preference saved, try to detect try { const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; let targetCurrency = 'USD'; // Default if (tz === 'Asia/Colombo') { targetCurrency = 'LKR'; } else if (tz === 'Asia/Kolkata' || tz === 'Asia/Calcutta') { targetCurrency = 'INR'; } else if (tz.startsWith('Europe/')) { targetCurrency = 'EUR'; } // If we detected something other than USD (or if we want to be explicit about USD) // Let's redirect only if it's LKR/INR/EUR to avoid unnecessary reloads for Americans if (targetCurrency !== 'USD') { console.log('Detected currency preference:', targetCurrency); localStorage.setItem('codend_currency', targetCurrency); // Append currency param to current URL and reload // We use replaceState to avoid back-button loops preferably, but we need the server to render. // So we must reload. urlParams.set('currency', targetCurrency); window.location.search = urlParams.toString(); } } catch (e) { console.log('Currency detection failed', e); } } else if (savedCurrency && savedCurrency !== 'USD') { // We have a saved preference that differs from what server rendered (default 'USD') // Reload with saved currency urlParams.set('currency', savedCurrency); window.location.search = urlParams.toString(); } // Subscription Form const subForm = document.querySelector('.subscribe-form'); if (subForm) { subForm.addEventListener('submit', function (e) { e.preventDefault(); const emailInput = subForm.querySelector('input[type="email"]'); const email = emailInput.value; fetch('/subscribe', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Requested-With': 'XMLHttpRequest' }, body: 'email=' + encodeURIComponent(email) }) .then(response => response.json()) .then(data => { if (data.success) { showCodendDialog('Welcome Aboard!', 'You have successfully subscribed to our newsletter.', 'success'); subForm.reset(); } else { showCodendDialog('Already Subscribed', data.message, 'info', 'Got it'); } }) .catch(error => console.error('Error:', error)); }); } // Contact Form const contactForm = document.querySelector('.contact-form'); if (contactForm) { contactForm.addEventListener('submit', function (e) { e.preventDefault(); const formData = new FormData(contactForm); fetch('/contact-submit', { method: 'POST', headers: { 'X-Requested-With': 'XMLHttpRequest' }, body: formData }) .then(response => response.json()) .then(data => { if (data.success) { // Custom Icon for Message Swal.fire({ html: `

Message Sent!

We have received your message and will get back to you shortly.

`, background: 'transparent', showConfirmButton: true, confirmButtonText: 'Return to Site', buttonsStyling: false, customClass: { popup: 'codend-popup', confirmButton: 'codend-confirm-btn', htmlContainer: 'no-padding' } }); contactForm.reset(); } }) .catch(error => console.error('Error:', error)); }); } });