parent
e1faba8239
commit
ae18bcbb8d
|
|
@ -69,6 +69,7 @@
|
|||
:loading="loading"
|
||||
:fields="form.properties"
|
||||
:theme="theme"
|
||||
:dark-mode="darkMode"
|
||||
:admin-preview="adminPreview"
|
||||
@submit="submitForm"
|
||||
>
|
||||
|
|
@ -127,7 +128,11 @@ export default {
|
|||
form: { type: Object, required: true },
|
||||
creating: { type: Boolean, default: false }, // If true, fake form submit
|
||||
adminPreview: { type: Boolean, default: false }, // If used in FormEditorPreview
|
||||
submitButtonClass: { type: String, default: '' }
|
||||
submitButtonClass: { type: String, default: '' },
|
||||
darkMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
:data-form="dataForm"
|
||||
:data-form-value="dataFormValue"
|
||||
:theme="theme"
|
||||
:dark-mode="darkMode"
|
||||
:admin-preview="adminPreview"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -51,7 +52,7 @@
|
|||
<!-- Captcha -->
|
||||
<template v-if="form.use_captcha && isLastPage">
|
||||
<div class="mb-3 px-2 mt-2 mx-auto w-max">
|
||||
<vue-hcaptcha ref="hcaptcha" :sitekey="hCaptchaSiteKey" :theme="darkModeEnabled?'dark':'light'" />
|
||||
<vue-hcaptcha ref="hcaptcha" :sitekey="hCaptchaSiteKey" :theme="darkMode?'dark':'light'" />
|
||||
<has-error :form="dataForm" field="h-captcha-response" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -85,7 +86,6 @@ import VueHcaptcha from "@hcaptcha/vue3-hcaptcha"
|
|||
import OpenFormField from './OpenFormField.vue'
|
||||
import {pendingSubmission} from "~/composables/forms/pendingSubmission.js"
|
||||
import FormLogicPropertyResolver from "~/lib/forms/FormLogicPropertyResolver.js"
|
||||
import {darkModeEnabled} from "~/lib/forms/public-page.js"
|
||||
|
||||
export default {
|
||||
name: 'OpenForm',
|
||||
|
|
@ -112,7 +112,11 @@ export default {
|
|||
required: true
|
||||
},
|
||||
defaultDataForm:{},
|
||||
adminPreview: { type: Boolean, default: false } // If used in FormEditorPreview
|
||||
adminPreview: { type: Boolean, default: false }, // If used in FormEditorPreview
|
||||
darkMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
setup (props) {
|
||||
|
|
@ -124,7 +128,6 @@ export default {
|
|||
dataForm,
|
||||
recordsStore,
|
||||
workingFormStore,
|
||||
darkModeEnabled: darkModeEnabled(),
|
||||
pendingSubmission: pendingSubmission(props.form)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@
|
|||
<script>
|
||||
import { computed } from 'vue'
|
||||
import FormLogicPropertyResolver from "~/lib/forms/FormLogicPropertyResolver.js"
|
||||
import { darkModeEnabled } from '~/lib/forms/public-page.js'
|
||||
import { default as _has } from 'lodash/has'
|
||||
|
||||
export default {
|
||||
|
|
@ -83,6 +82,10 @@ export default {
|
|||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
darkMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
field: {
|
||||
type: Object,
|
||||
required: true
|
||||
|
|
@ -177,9 +180,6 @@ export default {
|
|||
},
|
||||
fieldSideBarOpened() {
|
||||
return this.adminPreview && (this.form && this.selectedFieldIndex !== null) ? (this.form.properties[this.selectedFieldIndex] && this.showEditFieldSidebar) : false
|
||||
},
|
||||
isDark () {
|
||||
return this.form.dark_mode === 'dark' || this.form.dark_mode === 'auto' && darkModeEnabled()
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ export default {
|
|||
theme: this.theme,
|
||||
maxCharLimit: (field.max_char_limit) ? parseInt(field.max_char_limit) : 2000,
|
||||
showCharLimit: field.show_char_limit || false,
|
||||
isDark: this.isDark
|
||||
isDark: this.darkMode
|
||||
}
|
||||
|
||||
if (['select', 'multi_select'].includes(field.type)) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
<open-complete-form ref="form-preview" class="w-full mx-auto py-5 px-3" :class="{'max-w-lg': form && (form.width === 'centered')}"
|
||||
:creating="creating"
|
||||
:form="form"
|
||||
:dark-mode="darkMode"
|
||||
:admin-preview="true"
|
||||
@restarted="previewFormSubmitted=false"
|
||||
@submitted="previewFormSubmitted=true"
|
||||
|
|
@ -61,7 +62,7 @@
|
|||
<script>
|
||||
import VSwitch from '../../../../forms/components/VSwitch.vue'
|
||||
import OpenCompleteForm from '../../OpenCompleteForm.vue'
|
||||
import {handleDarkMode} from "~/lib/forms/public-page.js"
|
||||
import {handleDarkMode, useDarkMode} from "~/lib/forms/public-page.js"
|
||||
import { default as _has } from 'lodash/has'
|
||||
|
||||
export default {
|
||||
|
|
@ -69,8 +70,11 @@ export default {
|
|||
props: {},
|
||||
setup () {
|
||||
const workingFormStore = useWorkingFormStore()
|
||||
const parent = ref(null)
|
||||
return {
|
||||
workingFormStore
|
||||
workingFormStore,
|
||||
parent: parent,
|
||||
darkMode: useDarkMode(parent)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
|
|
|
|||
|
|
@ -1,49 +1,63 @@
|
|||
<template>
|
||||
<iframe v-if="!isDark" id="testimonialto-carousel-all-notionforms"
|
||||
<iframe
|
||||
:id="iframeId"
|
||||
title="NoteForms testimonial"
|
||||
loading="lazy"
|
||||
src="https://embed.testimonial.to/carousel/all/notionforms?theme=light&autoplay=on&showmore=on&one-row=on&same-height=off"
|
||||
frameBorder="0" scrolling="no" width="100%"
|
||||
height="500px"
|
||||
:src="'https://embed-v2.testimonial.to/w/notionforms?theme=light&card=base&loadMore=on&initialCount=8&tag=all'"
|
||||
frameBorder="0"
|
||||
scrolling="no"
|
||||
width="100%"
|
||||
/>
|
||||
<iframe v-else id="testimonialto-carousel-all-notionforms" src="https://embed.testimonial.to/carousel/all/notionforms?theme=dark&autoplay=on&showmore=on&one-row=on&same-height=off" frameborder="0" scrolling="no" width="100%" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {darkModeEnabled} from "~/lib/forms/public-page.js"
|
||||
import { useDarkMode } from '~/lib/forms/public-page.js'
|
||||
|
||||
export default {
|
||||
|
||||
props: {
|
||||
featuresOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data: () => ({}),
|
||||
|
||||
setup () {
|
||||
const isDark = darkModeEnabled()
|
||||
return {
|
||||
isDark
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
iframeId: 'testimonialto-carousel-all-notionforms'
|
||||
}),
|
||||
|
||||
computed: {},
|
||||
|
||||
mounted () {
|
||||
window.addEventListener('load', () => {
|
||||
this.loadScript()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadScript () {
|
||||
if (import.meta.server) return
|
||||
if (import.meta.server)
|
||||
return
|
||||
const script = document.createElement('script')
|
||||
script.setAttribute('src', 'https://testimonial.to/js/iframeResizer.min.js')
|
||||
script.setAttribute(
|
||||
'src',
|
||||
'https://testimonial.to/js/iframeResizer.min.js'
|
||||
)
|
||||
script.setAttribute('defer', 'defer')
|
||||
document.head.appendChild(script)
|
||||
script.addEventListener('load', function () {
|
||||
window.iFrameResize({
|
||||
script.addEventListener('load', () => {
|
||||
console.log('resizeing')
|
||||
window.iFrameResize(
|
||||
{
|
||||
log: false,
|
||||
checkOrigin: false
|
||||
}, '#testimonialto-carousel-all-notionforms')
|
||||
},
|
||||
'#' + this.iframeId
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +1,121 @@
|
|||
|
||||
let darkModeNodeParent = import.meta.client ? document.body : null
|
||||
|
||||
/**
|
||||
* Handle form public pages dark mode and transparent mode
|
||||
*/
|
||||
export function handleDarkMode (darkMode, elem = null) {
|
||||
if (import.meta.server) return
|
||||
if (import.meta.server)
|
||||
return
|
||||
|
||||
darkModeNodeParent = elem ?? document.body
|
||||
|
||||
// Dark mode
|
||||
if (['dark', 'light'].includes(darkMode)) {
|
||||
if (['dark', 'light'].includes(darkMode))
|
||||
return handleDarkModeToggle(darkMode === 'dark')
|
||||
}
|
||||
|
||||
// Case auto
|
||||
handleDarkModeToggle(window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
handleDarkModeToggle(
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
)
|
||||
|
||||
// Create listener
|
||||
window.matchMedia('(prefers-color-scheme: dark)')
|
||||
window
|
||||
.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', handleDarkModeToggle)
|
||||
}
|
||||
|
||||
export function darkModeEnabled() {
|
||||
if (import.meta.server) return false
|
||||
return computed(() => document.body.classList.contains('dark'))
|
||||
export function useClassWatcher (elem, className) {
|
||||
const hasClass = ref(false)
|
||||
|
||||
const updateClassPresence = () => {
|
||||
hasClass.value = elem.value?.classList.contains(className) ?? false
|
||||
}
|
||||
|
||||
let observer = null
|
||||
|
||||
const startObserving = () => {
|
||||
if (elem.value) {
|
||||
updateClassPresence()
|
||||
observer = new MutationObserver(updateClassPresence)
|
||||
observer.observe(elem.value, { attributes: true, attributeFilter: ['class'] })
|
||||
}
|
||||
}
|
||||
|
||||
const stopObserving = () => {
|
||||
if (observer) {
|
||||
observer.disconnect()
|
||||
observer = null
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
watch(elem, (newElem, oldElem, onCleanup) => {
|
||||
stopObserving()
|
||||
startObserving()
|
||||
onCleanup(stopObserving)
|
||||
}, { immediate: true })
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
stopObserving()
|
||||
})
|
||||
|
||||
return computed(() => hasClass.value)
|
||||
}
|
||||
|
||||
export function useDarkMode (elem = ref(null)) {
|
||||
// Define a computed property to handle the element reference reactively
|
||||
const effectiveElem = computed(() => {
|
||||
return elem.value || (process.client ? document.body : null)
|
||||
})
|
||||
|
||||
// Pass the computed property to useClassWatcher
|
||||
return useClassWatcher(effectiveElem, 'dark')
|
||||
}
|
||||
|
||||
export function darkModeEnabled (elem = ref(null)) {
|
||||
if (import.meta.server)
|
||||
return ref(false)
|
||||
|
||||
// TODO: replace this with a function that returns a watcher for the given of dark class element
|
||||
// Simplify this
|
||||
const isDark = ref(false)
|
||||
|
||||
// Update isDark based on the current class
|
||||
const updateIsDark = () => {
|
||||
console.log(elem.value, 'test')
|
||||
const finalElement = elem.value ?? document.body
|
||||
isDark.value = finalElement.classList.contains('dark')
|
||||
}
|
||||
|
||||
// MutationObserver callback to react to class changes
|
||||
let observer = new MutationObserver(updateIsDark)
|
||||
|
||||
// Initialize and clean up the observer
|
||||
const initObserver = (element) => {
|
||||
if (observer) {
|
||||
observer.disconnect()
|
||||
}
|
||||
if (element) {
|
||||
observer = new MutationObserver(updateIsDark)
|
||||
observer.observe(element, { attributes: true, attributeFilter: ['class'] })
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!import.meta.server) {
|
||||
initObserver(elem)
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (observer) {
|
||||
observer.disconnect()
|
||||
}
|
||||
})
|
||||
|
||||
// Return a computed ref that depends on isDark
|
||||
return computed(() => isDark.value)
|
||||
}
|
||||
|
||||
function handleDarkModeToggle (enabled) {
|
||||
|
|
@ -32,20 +123,27 @@ function handleDarkModeToggle (enabled) {
|
|||
// if we received an event
|
||||
enabled = enabled.matches
|
||||
}
|
||||
enabled ? darkModeNodeParent.classList.add('dark') : darkModeNodeParent.classList.remove('dark')
|
||||
enabled
|
||||
? darkModeNodeParent.classList.add('dark')
|
||||
: darkModeNodeParent.classList.remove('dark')
|
||||
}
|
||||
|
||||
export function disableDarkMode () {
|
||||
if (import.meta.server) return
|
||||
if (import.meta.server)
|
||||
return
|
||||
const body = document.body
|
||||
body.classList.remove('dark')
|
||||
// Remove event listener
|
||||
window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', handleDarkModeToggle)
|
||||
window
|
||||
.matchMedia('(prefers-color-scheme: dark)')
|
||||
.removeEventListener('change', handleDarkModeToggle)
|
||||
}
|
||||
|
||||
export function handleTransparentMode (transparentModeEnabled) {
|
||||
if (import.meta.server) return
|
||||
if (!useIsIframe() || !transparentModeEnabled) return
|
||||
if (import.meta.server)
|
||||
return
|
||||
if (!useIsIframe() || !transparentModeEnabled)
|
||||
return
|
||||
|
||||
const app = document.getElementById('app')
|
||||
app.classList.remove('bg-white')
|
||||
|
|
@ -54,8 +152,11 @@ export function handleTransparentMode (transparentModeEnabled) {
|
|||
}
|
||||
|
||||
export function focusOnFirstFormElement () {
|
||||
if (import.meta.server) return
|
||||
for (const ele of document.querySelectorAll('input,button,textarea,[role="button"]')) {
|
||||
if (import.meta.server)
|
||||
return
|
||||
for (const ele of document.querySelectorAll(
|
||||
'input,button,textarea,[role="button"]'
|
||||
)) {
|
||||
if (ele.offsetWidth !== 0 || ele.offsetHeight !== 0) {
|
||||
ele.focus()
|
||||
break
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
<loader class="h-6 w-6 text-nt-blue mx-auto"/>
|
||||
</p>
|
||||
</div>
|
||||
<open-complete-form v-show="!recordLoading" ref="openCompleteForm" :form="form" class="mb-10"
|
||||
<open-complete-form v-show="!recordLoading" ref="openCompleteForm" :form="form" class="mb-10" :dark-mode="darkMode"
|
||||
@password-entered="passwordEntered"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -53,12 +53,18 @@ import {computed} from 'vue'
|
|||
import OpenCompleteForm from "~/components/open/forms/OpenCompleteForm.vue"
|
||||
import sha256 from 'js-sha256'
|
||||
import { onBeforeRouteLeave } from 'vue-router'
|
||||
import {disableDarkMode, handleDarkMode, handleTransparentMode, focusOnFirstFormElement} from '~/lib/forms/public-page'
|
||||
import {
|
||||
disableDarkMode,
|
||||
handleDarkMode,
|
||||
handleTransparentMode,
|
||||
focusOnFirstFormElement,
|
||||
useDarkMode
|
||||
} from '~/lib/forms/public-page'
|
||||
|
||||
const crisp = useCrisp()
|
||||
const formsStore = useFormsStore()
|
||||
const recordsStore = useRecordsStore()
|
||||
|
||||
const darkMode = useDarkMode()
|
||||
const isIframe = useIsIframe()
|
||||
const formLoading = computed(() => formsStore.loading)
|
||||
const recordLoading = computed(() => recordsStore.loading)
|
||||
|
|
|
|||
Loading…
Reference in New Issue