improvements
This commit is contained in:
		@@ -1,20 +1,20 @@
 | 
			
		||||
import { useRef } from 'react'
 | 
			
		||||
import { motion, useInView } from 'framer-motion'
 | 
			
		||||
import { motion } from 'framer-motion'
 | 
			
		||||
 | 
			
		||||
export function AnimatedSection({ children, id }: { children: React.ReactNode; id?: string }) {
 | 
			
		||||
  const ref = useRef(null)
 | 
			
		||||
  const isInView = useInView(ref, { once: true, margin: '-20% 0px -20% 0px' })
 | 
			
		||||
type AnimatedSectionProps = {
 | 
			
		||||
  children: React.ReactNode
 | 
			
		||||
  id?: string
 | 
			
		||||
  className?: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function AnimatedSection({ children, id, className }: AnimatedSectionProps) {
 | 
			
		||||
  return (
 | 
			
		||||
    <motion.section
 | 
			
		||||
      id={id}
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      initial={{ opacity: 0, y: 50 }}
 | 
			
		||||
      animate={{
 | 
			
		||||
        opacity: isInView ? 1 : 0,
 | 
			
		||||
        y: isInView ? 0 : 50,
 | 
			
		||||
      }}
 | 
			
		||||
      transition={{ duration: 0.5 }}
 | 
			
		||||
      className={className}
 | 
			
		||||
      initial={{ opacity: 0, y: 40 }}
 | 
			
		||||
      whileInView={{ opacity: 1, y: 0 }}
 | 
			
		||||
      viewport={{ once: true, margin: '-25% 0px -20% 0px' }}
 | 
			
		||||
      transition={{ duration: 0.5, ease: 'easeOut' }}
 | 
			
		||||
    >
 | 
			
		||||
      {children}
 | 
			
		||||
    </motion.section>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										220
									
								
								src/components/ContactForm.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								src/components/ContactForm.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
			
		||||
'use client'
 | 
			
		||||
 | 
			
		||||
import { AnimatePresence, motion } from 'framer-motion'
 | 
			
		||||
import { useState, type ChangeEvent, type FormEvent } from 'react'
 | 
			
		||||
import emailjs from '@emailjs/browser'
 | 
			
		||||
import { CheckCircle, Send, X } from 'lucide-react'
 | 
			
		||||
 | 
			
		||||
interface ContactFormProps {
 | 
			
		||||
  isOpen: boolean
 | 
			
		||||
  onClose: () => void
 | 
			
		||||
  title?: string
 | 
			
		||||
  formType?: 'investor' | 'partner' | 'agent_waitlist'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const initialFormState = {
 | 
			
		||||
  name: '',
 | 
			
		||||
  email: '',
 | 
			
		||||
  company: '',
 | 
			
		||||
  message: '',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function ContactForm({
 | 
			
		||||
  isOpen,
 | 
			
		||||
  onClose,
 | 
			
		||||
  title = 'Book a Meeting',
 | 
			
		||||
  formType,
 | 
			
		||||
}: ContactFormProps) {
 | 
			
		||||
  const [formData, setFormData] = useState(initialFormState)
 | 
			
		||||
  const [isSubmitting, setIsSubmitting] = useState(false)
 | 
			
		||||
  const [isSubmitted, setIsSubmitted] = useState(false)
 | 
			
		||||
 | 
			
		||||
  const handleInputChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
 | 
			
		||||
    const { name, value } = e.target
 | 
			
		||||
    setFormData((prev) => ({
 | 
			
		||||
      ...prev,
 | 
			
		||||
      [name]: value,
 | 
			
		||||
    }))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
 | 
			
		||||
    e.preventDefault()
 | 
			
		||||
    setIsSubmitting(true)
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const templateParams = {
 | 
			
		||||
        from_name: formData.name,
 | 
			
		||||
        from_email: formData.email,
 | 
			
		||||
        company: formData.company,
 | 
			
		||||
        message: formData.message,
 | 
			
		||||
        to_email: 'emre@incubaid.com',
 | 
			
		||||
        form_type: formType || 'General Inquiry',
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      await emailjs.send(
 | 
			
		||||
        'service_03d0vf8',
 | 
			
		||||
        'template_6o6e8oe',
 | 
			
		||||
        templateParams,
 | 
			
		||||
        'bhkly3gzrO-SA9w7v',
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      setIsSubmitted(true)
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        setIsSubmitted(false)
 | 
			
		||||
        setFormData(initialFormState)
 | 
			
		||||
        onClose()
 | 
			
		||||
      }, 3000)
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error('Email sending failed:', error)
 | 
			
		||||
      alert('Failed to send message. Please try again.')
 | 
			
		||||
    } finally {
 | 
			
		||||
      setIsSubmitting(false)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <AnimatePresence>
 | 
			
		||||
      {isOpen && (
 | 
			
		||||
        <motion.div
 | 
			
		||||
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4 backdrop-blur-sm"
 | 
			
		||||
          initial={{ opacity: 0 }}
 | 
			
		||||
          animate={{ opacity: 1 }}
 | 
			
		||||
          exit={{ opacity: 0 }}
 | 
			
		||||
        >
 | 
			
		||||
          <motion.div
 | 
			
		||||
            className="relative w-full max-w-md overflow-hidden rounded-2xl bg-card shadow-2xl"
 | 
			
		||||
            initial={{ scale: 0.9, opacity: 0 }}
 | 
			
		||||
            animate={{ scale: 1, opacity: 1 }}
 | 
			
		||||
            exit={{ scale: 0.9, opacity: 0 }}
 | 
			
		||||
            transition={{ type: 'spring', damping: 25, stiffness: 300 }}
 | 
			
		||||
          >
 | 
			
		||||
            <div className="flex items-center justify-between border-b border-border p-6">
 | 
			
		||||
              <h3 className="text-xl font-bold text-foreground">{title}</h3>
 | 
			
		||||
              <button
 | 
			
		||||
                onClick={onClose}
 | 
			
		||||
                className="rounded-lg p-2 transition-colors hover:bg-muted"
 | 
			
		||||
                aria-label="Close form"
 | 
			
		||||
              >
 | 
			
		||||
                <X className="h-5 w-5 text-muted-foreground" />
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div className="p-6">
 | 
			
		||||
              {isSubmitted ? (
 | 
			
		||||
                <motion.div
 | 
			
		||||
                  className="py-8 text-center"
 | 
			
		||||
                  initial={{ opacity: 0, y: 20 }}
 | 
			
		||||
                  animate={{ opacity: 1, y: 0 }}
 | 
			
		||||
                >
 | 
			
		||||
                  <CheckCircle className="mx-auto mb-4 h-16 w-16 text-primary" />
 | 
			
		||||
                  <h4 className="mb-2 text-lg font-semibold text-foreground">Thank you!</h4>
 | 
			
		||||
                  <p className="text-muted-foreground">We'll get back to you soon.</p>
 | 
			
		||||
                </motion.div>
 | 
			
		||||
              ) : (
 | 
			
		||||
                <form onSubmit={handleSubmit} className="space-y-4">
 | 
			
		||||
                  <div>
 | 
			
		||||
                    <label
 | 
			
		||||
                      htmlFor="name"
 | 
			
		||||
                      className="mb-1 block text-sm font-medium text-muted-foreground"
 | 
			
		||||
                    >
 | 
			
		||||
                      Full Name *
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                      type="text"
 | 
			
		||||
                      id="name"
 | 
			
		||||
                      name="name"
 | 
			
		||||
                      value={formData.name}
 | 
			
		||||
                      onChange={handleInputChange}
 | 
			
		||||
                      required
 | 
			
		||||
                      className="w-full rounded-lg border border-border bg-muted/30 px-4 py-3 text-foreground placeholder:text-muted-foreground focus:border-transparent focus:outline-none focus:ring-2 focus:ring-primary"
 | 
			
		||||
                      placeholder="Your full name"
 | 
			
		||||
                    />
 | 
			
		||||
                  </div>
 | 
			
		||||
 | 
			
		||||
                  <div>
 | 
			
		||||
                    <label
 | 
			
		||||
                      htmlFor="email"
 | 
			
		||||
                      className="mb-1 block text-sm font-medium text-muted-foreground"
 | 
			
		||||
                    >
 | 
			
		||||
                      Email Address *
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                      type="email"
 | 
			
		||||
                      id="email"
 | 
			
		||||
                      name="email"
 | 
			
		||||
                      value={formData.email}
 | 
			
		||||
                      onChange={handleInputChange}
 | 
			
		||||
                      required
 | 
			
		||||
                      className="w-full rounded-lg border border-border bg-muted/30 px-4 py-3 text-foreground placeholder:text-muted-foreground focus:border-transparent focus:outline-none focus:ring-2 focus:ring-primary"
 | 
			
		||||
                      placeholder="your.email@company.com"
 | 
			
		||||
                    />
 | 
			
		||||
                  </div>
 | 
			
		||||
 | 
			
		||||
                  <div>
 | 
			
		||||
                    <label
 | 
			
		||||
                      htmlFor="company"
 | 
			
		||||
                      className="mb-1 block text-sm font-medium text-muted-foreground"
 | 
			
		||||
                    >
 | 
			
		||||
                      Company
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <input
 | 
			
		||||
                      type="text"
 | 
			
		||||
                      id="company"
 | 
			
		||||
                      name="company"
 | 
			
		||||
                      value={formData.company}
 | 
			
		||||
                      onChange={handleInputChange}
 | 
			
		||||
                      className="w-full rounded-lg border border-border bg-muted/30 px-4 py-3 text-foreground placeholder:text-muted-foreground focus:border-transparent focus:outline-none focus:ring-2 focus:ring-primary"
 | 
			
		||||
                      placeholder="Your company name"
 | 
			
		||||
                    />
 | 
			
		||||
                  </div>
 | 
			
		||||
 | 
			
		||||
                  <div>
 | 
			
		||||
                    <label
 | 
			
		||||
                      htmlFor="message"
 | 
			
		||||
                      className="mb-1 block text-sm font-medium text-muted-foreground"
 | 
			
		||||
                    >
 | 
			
		||||
                      Message
 | 
			
		||||
                    </label>
 | 
			
		||||
                    <textarea
 | 
			
		||||
                      id="message"
 | 
			
		||||
                      name="message"
 | 
			
		||||
                      value={formData.message}
 | 
			
		||||
                      onChange={handleInputChange}
 | 
			
		||||
                      rows={4}
 | 
			
		||||
                      className="w-full resize-none rounded-lg border border-border bg-muted/30 px-4 py-3 text-foreground placeholder:text-muted-foreground focus:border-transparent focus:outline-none focus:ring-2 focus:ring-primary"
 | 
			
		||||
                      placeholder={
 | 
			
		||||
                        formType === 'investor'
 | 
			
		||||
                          ? 'Tell us about your investment interests and how we can collaborate.'
 | 
			
		||||
                          : formType === 'agent_waitlist'
 | 
			
		||||
                            ? 'Tell us about your sovereign agent requirements.'
 | 
			
		||||
                            : 'Tell us about your project or how we can help.'
 | 
			
		||||
                      }
 | 
			
		||||
                    />
 | 
			
		||||
                  </div>
 | 
			
		||||
 | 
			
		||||
                  <button
 | 
			
		||||
                    type="submit"
 | 
			
		||||
                    disabled={isSubmitting}
 | 
			
		||||
                    className="flex w-full items-center justify-center rounded-lg bg-primary px-6 py-3 font-semibold text-primary-foreground transition-opacity disabled:cursor-not-allowed disabled:opacity-50"
 | 
			
		||||
                  >
 | 
			
		||||
                    {isSubmitting ? (
 | 
			
		||||
                      <>
 | 
			
		||||
                        <div className="mr-2 h-5 w-5 animate-spin rounded-full border-2 border-primary-foreground/30 border-t-primary-foreground" />
 | 
			
		||||
                        Sending...
 | 
			
		||||
                      </>
 | 
			
		||||
                    ) : (
 | 
			
		||||
                      <>
 | 
			
		||||
                        <Send className="h-5 w-5" />
 | 
			
		||||
                        <span className="ml-2">Send Message</span>
 | 
			
		||||
                      </>
 | 
			
		||||
                    )}
 | 
			
		||||
                  </button>
 | 
			
		||||
                </form>
 | 
			
		||||
              )}
 | 
			
		||||
            </div>
 | 
			
		||||
          </motion.div>
 | 
			
		||||
        </motion.div>
 | 
			
		||||
      )}
 | 
			
		||||
    </AnimatePresence>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
@@ -18,11 +18,10 @@ export function FadeIn({ children, transition, className }: FadeInProps) {
 | 
			
		||||
      className={className}
 | 
			
		||||
      initial={{ opacity: 0, y: 20 }}
 | 
			
		||||
      whileInView={{ opacity: 1, y: 0 }}
 | 
			
		||||
      viewport={{ once: false, margin: isMobile ? '0px 0px -50px 0px' : '0px 0px -100px 0px' }}
 | 
			
		||||
      transition={transition || { duration: 0.5 }}
 | 
			
		||||
      viewport={{ once: true, amount: isMobile ? 0.2 : 0.3 }}
 | 
			
		||||
      transition={transition || { duration: 0.5, ease: 'easeOut' }}
 | 
			
		||||
    >
 | 
			
		||||
      {children}
 | 
			
		||||
    </motion.div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,10 +35,10 @@ export function Footer() {
 | 
			
		||||
            </div>
 | 
			
		||||
            <div className="ml-4 lg:w-72">
 | 
			
		||||
              <p className="text-base font-semibold text-gray-900">
 | 
			
		||||
                <a href="https://github.com/threefoldtech/mycelium/releases/" target="_blank" rel="noopener noreferrer">
 | 
			
		||||
                <Link to="/download">
 | 
			
		||||
                  <span className="absolute inset-0 sm:rounded-2xl" />
 | 
			
		||||
                  Download Mycelium
 | 
			
		||||
                </a>
 | 
			
		||||
                  Download Mycelium Connector
 | 
			
		||||
                </Link>
 | 
			
		||||
              </p>
 | 
			
		||||
              <p className="mt-1 text-sm text-gray-700">
 | 
			
		||||
                Head to the GitHub to access the latest Mycelium builds for your devices.
 | 
			
		||||
 
 | 
			
		||||
@@ -12,12 +12,6 @@ export function Header() {
 | 
			
		||||
              <img src="/src/images/logomark.svg" alt="Mycelium" className="h-10 w-auto" />
 | 
			
		||||
            </Link>
 | 
			
		||||
            <div className="hidden lg:flex lg:gap-10">
 | 
			
		||||
              <Link
 | 
			
		||||
                to="/"
 | 
			
		||||
                className="text-base/7 tracking-tight text-gray-700 hover:text-cyan-500 transition-colors"
 | 
			
		||||
              >
 | 
			
		||||
                Home
 | 
			
		||||
              </Link>
 | 
			
		||||
              <Link
 | 
			
		||||
                to="/cloud"
 | 
			
		||||
                className="text-base/7 tracking-tight text-gray-700 hover:text-cyan-500 transition-colors"
 | 
			
		||||
@@ -41,16 +35,16 @@ export function Header() {
 | 
			
		||||
          <div className="flex items-center gap-6">
 | 
			
		||||
            <div className="flex items-center gap-6 max-lg:hidden">
 | 
			
		||||
              <Button
 | 
			
		||||
                to="https://threefold.info/mycelium_network/docs/"
 | 
			
		||||
                to="https://myceliumcloud.tf"
 | 
			
		||||
                variant="outline"
 | 
			
		||||
                as="a"
 | 
			
		||||
                target="_blank"
 | 
			
		||||
                rel="noopener noreferrer"
 | 
			
		||||
              >
 | 
			
		||||
                Docs
 | 
			
		||||
                Start Deployment
 | 
			
		||||
              </Button>
 | 
			
		||||
              <Button to="/download" variant="solid" color="cyan">
 | 
			
		||||
                Get Mycelium
 | 
			
		||||
                Get Mycelium Connector
 | 
			
		||||
              </Button>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -18,11 +18,10 @@ export function FadeIn({ children, transition, className }: FadeInProps) {
 | 
			
		||||
      className={className}
 | 
			
		||||
      initial={{ opacity: 0, y: 20 }}
 | 
			
		||||
      whileInView={{ opacity: 1, y: 0 }}
 | 
			
		||||
      viewport={{ once: false, margin: isMobile ? '0px 0px -50px 0px' : '0px 0px -100px 0px' }}
 | 
			
		||||
      transition={transition || { duration: 0.5 }}
 | 
			
		||||
      viewport={{ once: true, amount: isMobile ? 0.2 : 0.3 }}
 | 
			
		||||
      transition={transition || { duration: 0.5, ease: 'easeOut' }}
 | 
			
		||||
    >
 | 
			
		||||
      {children}
 | 
			
		||||
    </motion.div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,7 @@ export const FloatingNav = ({
 | 
			
		||||
            <span className="hidden sm:block text-sm">Docs</span>
 | 
			
		||||
          </a>
 | 
			
		||||
          <Button to="/download" variant="solid" color="cyan">
 | 
			
		||||
            Get Mycelium
 | 
			
		||||
            Get Mycelium Connector
 | 
			
		||||
          </Button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </motion.div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user