Welcome, !
+This is your dashboard. You are successfully logged in.
+diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..5e8d48f --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,152 @@ +/* Aperture - Custom Styles */ +:root { + --bg-dark: #0D1117; + --surface: #161B22; + --primary: #58A6FF; + --primary-darker: #3081F7; + --text-primary: #C9D1D9; + --text-headings: #F0F6FC; + --border-color: #30363d; +} + +body { + background-color: var(--bg-dark); + color: var(--text-primary); + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; +} + +h1, h2, h3, h4, h5, h6 { + color: var(--text-headings); + font-weight: 700; +} + +.navbar { + background-color: rgba(13, 17, 23, 0.8); + backdrop-filter: blur(10px); + border-bottom: 1px solid var(--border-color); +} + +.navbar-brand { + font-weight: 700; + color: var(--text-headings); +} + +.nav-link { + color: var(--text-primary); +} +.nav-link:hover { + color: var(--text-headings); +} + +.btn-primary { + background-image: linear-gradient(45deg, var(--primary), var(--primary-darker)); + border: none; + border-radius: 0.75rem; + font-weight: 600; + padding: 0.75rem 1.5rem; + transition: transform 0.2s ease-in-out; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 4px 20px rgba(88, 166, 255, 0.3); +} + +.btn-secondary { + background-color: var(--surface); + border: 1px solid var(--border-color); + color: var(--text-headings); + border-radius: 0.75rem; + font-weight: 600; + padding: 0.75rem 1.5rem; +} +.btn-secondary:hover { + background-color: #21262d; +} + +.hero { + padding: 8rem 0; + background-image: url('https://picsum.photos/seed/aperture-hero/1600/900'); + background-size: cover; + background-position: center; + position: relative; +} + +.hero::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(13, 17, 23, 0.7); +} + +.hero .container { + position: relative; + z-index: 2; +} + +.section { + padding: 6rem 0; +} + +.feature-card, .offer-explorer-card { + background-color: var(--surface); + border: 1px solid var(--border-color); + border-radius: 0.75rem; + padding: 2rem; + height: 100%; +} + +.social-proof img { + filter: grayscale(100%) contrast(0.5); + opacity: 0.6; + transition: all 0.3s ease; + max-height: 40px; +} +.social-proof img:hover { + filter: none; + opacity: 1; +} + +.form-control, .form-select { + background-color: var(--bg-dark); + border-color: var(--border-color); + color: var(--text-primary); +} +.form-control:focus, .form-select:focus { + background-color: var(--bg-dark); + border-color: var(--primary); + color: var(--text-primary); + box-shadow: 0 0 0 0.25rem rgba(88, 166, 255, 0.25); +} + +.table { + --bs-table-bg: var(--surface); + --bs-table-striped-bg: #21262d; + --bs-table-color: var(--text-primary); + --bs-table-border-color: var(--border-color); +} + +.footer { + background-color: var(--surface); + padding: 3rem 0; + border-top: 1px solid var(--border-color); +} + +/* Contact Form Status */ +#contact-form-status p { + margin-bottom: 0; + text-align: center; + font-weight: 600; +} +.text-success { + color: #28a745 !important; +} +.text-danger { + color: #dc3545 !important; +} +.text-info { + color: #0dcaf0 !important; +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..34d4f4d --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,97 @@ +document.addEventListener('DOMContentLoaded', function () { + const offerForm = document.getElementById('offer-explorer-form'); + const resultsTableBody = document.getElementById('offer-results-body'); + + const mockOffers = [ + { provider: 'AWS', gpu: 'H100', region: 'us-east-1', price: 2.10, spot: true }, + { provider: 'GCP', gpu: 'H100', region: 'us-central1', price: 2.25, spot: true }, + { provider: 'Azure', gpu: 'H100', region: 'eastus', price: 2.30, spot: false }, + { provider: 'CoreWeave', gpu: 'H100', region: 'us-east', price: 1.89, spot: false }, + { provider: 'RunPod', gpu: 'H100', region: 'us-east', price: 1.79, spot: true }, + { provider: 'AWS', gpu: 'A100', region: 'us-west-2', price: 1.10, spot: true }, + { provider: 'GCP', gpu: 'A100', region: 'us-east4', price: 1.20, spot: true }, + { provider: 'Vast.ai', gpu: 'A100', region: 'us-west', price: 0.95, spot: true }, + { provider: 'AWS', gpu: 'RTX 4090', region: 'eu-west-1', price: 0.70, spot: true }, + { provider: 'RunPod', gpu: 'RTX 4090', region: 'eu-central-1', price: 0.65, spot: true }, + ]; + + if (offerForm) { + offerForm.addEventListener('submit', function (e) { + e.preventDefault(); + + const gpuType = document.getElementById('gpuType').value; + const spotOk = document.getElementById('spotOk').checked; + + const filteredOffers = mockOffers.filter(offer => { + const gpuMatch = gpuType === 'any' || offer.gpu === gpuType; + const spotMatch = !spotOk || offer.spot === true; + return gpuMatch && spotMatch; + }); + + renderResults(filteredOffers); + }); + } + + function renderResults(offers) { + if (!resultsTableBody) return; + + resultsTableBody.innerHTML = ''; + + if (offers.length === 0) { + resultsTableBody.innerHTML = '
Sending...
'; + submitButton.disabled = true; + + const formData = new FormData(this); + + fetch('contact.php', { + method: 'POST', + body: formData + }) + .then(response => response.json().then(data => ({ ok: response.ok, data }))) + .then(({ ok, data }) => { + if (ok) { + statusDiv.innerHTML = `${data.success}
`; + contactForm.reset(); + } else { + statusDiv.innerHTML = `${data.error || 'An unknown error occurred.'}
`; + } + }) + .catch(error => { + console.error('Error:', error); + statusDiv.innerHTML = 'A network error occurred. Please try again.
'; + }) + .finally(() => { + submitButton.disabled = false; + }); + }); + } +}); \ No newline at end of file diff --git a/contact.php b/contact.php new file mode 100644 index 0000000..ee01698 --- /dev/null +++ b/contact.php @@ -0,0 +1,41 @@ + 'Method Not Allowed']); + exit; +} + +// Include the MailService +require_once __DIR__ . '/mail/MailService.php'; + +// Get and sanitize inputs +$name = trim($_POST['name'] ?? ''); +$email = trim($_POST['email'] ?? ''); +$message = trim($_POST['message'] ?? ''); + +// Basic validation +if (empty($name) || empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL) || empty($message)) { + http_response_code(400); + echo json_encode(['error' => 'Please fill out all fields correctly.']); + exit; +} + +// Prepare email details +$subject = 'New Contact Form Submission from Aperture Website'; + +// Send the email using the MailService. +// The `$to` address is omitted to use the default from the .env configuration. +$res = MailService::sendContactMessage($name, $email, $message, null, $subject); + +// Respond to the client +if (!empty($res['success'])) { + echo json_encode(['success' => 'Thank you for your message! We will get back to you shortly.']); +} else { + http_response_code(500); + // Note: In a real app, you would log the detailed error. + // error_log('MailService Error: ' . ($res['error'] ?? 'Unknown error')); + echo json_encode(['error' => 'Sorry, there was an error sending your message. Please try again later.']); +} diff --git a/dashboard.php b/dashboard.php new file mode 100644 index 0000000..15d30a9 --- /dev/null +++ b/dashboard.php @@ -0,0 +1,42 @@ + + + + + + +This is your dashboard. You are successfully logged in.
+= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWiZZy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-This page will update automatically as the plan is implemented.
-Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
Aperture is the intelligent compute layer for AI. Submit once, run anywhere—cheapest, fastest, compliant.
+Routing workloads across the world's best providers
+
+ Query our global index of compute providers to find the perfect balance of price, performance, and availability for your workload. Stop overpaying for idle instances.
+| Provider | +GPU | +Region | +Price/hr | +Spot | +
|---|
Aperture decouples your workload from the underlying infrastructure, so you can focus on building, not billing.
+Define your workload, data, and constraints using our simple API or web console.
+Aperture's intelligent scheduler finds the globally optimal compute to run your job.
+We deploy your job, monitor its status, and stream logs and metrics back to you.
+Have questions about pricing, features, or anything else? Our team is ready to answer all your questions.
+
+ Note: This is for testing purposes only. Flatlogic does not guarantee usage of the mail server. Please set up your own SMTP in .env.
+