mirror of
https://github.com/bdnugget/alpine-chemistry.git
synced 2026-11-07 03:17:27 +00:00
feat: simple Formspree integration
This commit is contained in:
1 parent
b52bd93487
commit
413a2dcd06
7 files changed
+57
-55
No files matched your search
@@ -33,6 +33,14 @@ export default defineAppConfig({
|
||||
label: 'LinkedIn',
|
||||
href: 'https://www.linkedin.com/company/nuxtlabs'
|
||||
}
|
||||
},
|
||||
form: {
|
||||
successMessage: 'Message sent. Thank you!'
|
||||
},
|
||||
integrations: {
|
||||
formspree: {
|
||||
url: 'https://formspree.io/f/xdovneqb'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -100,8 +100,8 @@ css({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
'@xs': {
|
||||
gridColumn: 'span 1 / span 1',
|
||||
gridColumnStart: 12,
|
||||
gridColumn: 'span 2 / span 2',
|
||||
gridColumnStart: 11,
|
||||
justifyContent: 'flex-end',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@ css({
|
||||
py: 'var(--header-padding)',
|
||||
'.menu': {
|
||||
position: 'absolute',
|
||||
':hover': {
|
||||
color: '{color.primary.500}',
|
||||
},
|
||||
'.left &&': {
|
||||
right: 0
|
||||
},
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
onClick: {
|
||||
type: Function,
|
||||
required: true
|
||||
type: {
|
||||
type: String,
|
||||
default: 'submit'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button @click="onClick()">
|
||||
<button :type="type">
|
||||
<slot />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
@@ -26,6 +26,9 @@ css({
|
||||
'--color-mode-switcher-size': '24px',
|
||||
width: 'var(--color-mode-switcher-size)',
|
||||
height: 'var(--color-mode-switcher-size)',
|
||||
':hover': {
|
||||
color: '{color.primary.500}',
|
||||
},
|
||||
svg: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import type { PropType } from 'vue'
|
||||
import type { Field, ContactField } from '../types/contact'
|
||||
import type { Field } from '../types/contact'
|
||||
const alpine = useAppConfig().alpine
|
||||
|
||||
const status = ref()
|
||||
|
||||
const props = defineProps({
|
||||
sendButton: {
|
||||
type: String,
|
||||
default: 'Send message'
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
subject: {
|
||||
type: String,
|
||||
default: 'Contact from Alpine Theme !'
|
||||
},
|
||||
fields: {
|
||||
type: Array as PropType<Field[]>,
|
||||
default: () => [
|
||||
@@ -49,57 +44,55 @@ const props = defineProps({
|
||||
required: true,
|
||||
layout: 'big'
|
||||
}
|
||||
] /* ,
|
||||
validator: (fields: Field[]) => {
|
||||
for (const field of fields) {
|
||||
if (!field.name) {
|
||||
return false
|
||||
}
|
||||
if (!field.required) {
|
||||
return false
|
||||
}
|
||||
if (!field.layout) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
} */
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
const form = reactive(props.fields.map(v => ({ ...v, data: '' })))
|
||||
|
||||
const onSend = async () => {
|
||||
const formatedData: ContactField[] = []
|
||||
await form.forEach((field) => {
|
||||
const data: ContactField = {
|
||||
name: field.name,
|
||||
data: field.data
|
||||
const onSend = async (e) => {
|
||||
e.preventDefault()
|
||||
const data = new FormData(e.target)
|
||||
|
||||
fetch(e.target.action, {
|
||||
method: e.target.method,
|
||||
body: data,
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
formatedData.push(data)
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
status.value = alpine.form.successMessage
|
||||
e.target.reset()
|
||||
} else {
|
||||
// Handle errors from API
|
||||
response.json().then(data => {
|
||||
if (Object.hasOwn(data, 'errors')) {
|
||||
console.error(data["errors"].map(error => error["message"]).join(", "))
|
||||
} else {
|
||||
console.error("There was a problem submitting your form")
|
||||
}
|
||||
})
|
||||
}
|
||||
}).catch(error => {
|
||||
// Catch all other errors
|
||||
console.error("There was a problem submitting your form")
|
||||
})
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(formatedData)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="contact-form">
|
||||
<form class="contact-form" @submit="onSend" method="POST" :action="alpine.integrations.formspree.url">
|
||||
<div class="inputs">
|
||||
<Input
|
||||
v-for="(field, index) in form"
|
||||
:key="index"
|
||||
v-model="field.data"
|
||||
:field="field"
|
||||
/>
|
||||
<Input v-for="(field, index) in form" :key="index" v-model="field.data" :field="field" />
|
||||
</div>
|
||||
<div>
|
||||
<Button :on-click="() => onSend()">
|
||||
{{ sendButton }}
|
||||
<Button type="submit">
|
||||
{{ status ? status : sendButton }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<style scoped lang="ts">
|
||||
|
||||
+1
-6
@@ -4,9 +4,4 @@ export interface Field {
|
||||
placeholder?: string;
|
||||
label?: string;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
export interface ContactField {
|
||||
name: string;
|
||||
data: string;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user