Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/sorcerer/llms.txt

Use this file to discover all available pages before exploring further.

The Contact page (/contact) invites visitors to reach out under the heading “Summon Me” with the subtitle “Send a message through the aether”. Submitting the form triggers a burst of 20 animated particle dots that fly outward across the screen, the button text changes to “Channeling…”, and after two seconds the entire form dissolves away to reveal a success confirmation. Each input field uses the site’s dark palette with turquoise focus rings to stay visually consistent with the rest of the portfolio.

Form Fields

The form contains three required fields. All inputs use a bg-midnight-base background with a border-velvet-purple border and a turquoise-glow focus ring.
Field IDLabelTypeRequired
nameTrue NametextYes
emailAether Address (Email)emailYes
messageIncantation (Message)textarea (4 rows)Yes
The submit button displays “Cast” in its resting state and switches to “Channeling…” while isSubmitting is true, giving the visitor clear feedback that their message is in transit.

Submit Animation

When the form is submitted (onSubmit with preventDefault), the following sequence occurs:
  1. isSubmitting is set to true, disabling the form and changing the button label to “Channeling…”.
  2. Twenty particle dots are rendered at x: 50%, y: 100% (the bottom-centre of the form). Each dot animates to a randomised position across the viewport while fading out, creating a dispersing spark effect.
  3. After a 2000 ms timeout, isSubmitting is set back to false and isSuccess is set to true, triggering the transition to the success state.
The particles are generated with Array.from({ length: 20 }) and each one receives a unique random target position, so the burst looks organic rather than uniform.

Success State

Once isSuccess becomes true, Framer Motion’s <AnimatePresence mode="wait"> swaps out the form for the success panel. The form exits with opacity: 0, filter: blur(10px), and scale: 1.1 over 1 second. The success panel then enters in its place and contains:
  • A turquoise circle icon confirming the action.
  • The heading “Spell Successful”.
  • The message: “Your message has traversed the aether. I shall consult my scrying orb and reply shortly.”
  • A “Cast another spell” button that resets both isSubmitting and isSuccess to false, restoring the form for another submission.

Connecting to a Backend

The current implementation uses a mock setTimeout to simulate a network request. To send form data to a real endpoint, replace the timeout with a fetch call.
1

Locate the submit handler in assets/main.js

Open assets/main.js and find the handleSubmit function inside the ContactPage component. You will see the existing setTimeout block that sets isSubmitting and isSuccess after a 2-second delay.
2

Replace the mock timeout with a fetch call

Remove the setTimeout and replace it with an async fetch to your chosen form-handling endpoint. Mark the handleSubmit function as async first, then add the following:
// Replace the mock setTimeout with:
const response = await fetch('/api/contact', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name, email, message }),
});
if (response.ok) {
  setIsSuccess(true);
}
Remember to call setIsSubmitting(false) in a finally block so the button always returns to its resting state, even if the request fails:
try {
  const response = await fetch('/api/contact', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name, email, message }),
  });
  if (response.ok) {
    setIsSuccess(true);
  }
} finally {
  setIsSubmitting(false);
}

Build docs developers (and LLMs) love