Integration pages from Notion (#753)
* Integration pages from Notion * fix integration page * Refactor environment variables and update routing in integration pages - Removed unused environment variables related to MUX from `.env.docker` and `.env.example` to streamline configuration. - Updated routing links in `OpenFormFooter.vue` to correct navigation paths for "Integrations", "Report Abuse", and "Privacy Policy", enhancing user experience. - Added middleware to `definePageMeta` in `index.vue` and `[slug].vue` for integration pages to enforce self-hosted logic. These changes aim to improve code clarity and ensure proper routing functionality across the application. --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
@@ -50,6 +50,18 @@
|
||||
Technical Docs
|
||||
</a>
|
||||
<template v-if="!useFeatureFlag('self_hosted')">
|
||||
<router-link
|
||||
:to="{ name: 'integrations' }"
|
||||
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
|
||||
>
|
||||
Integrations
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="{ name: 'report-abuse' }"
|
||||
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
|
||||
>
|
||||
Report Abuse
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="{ name: 'privacy-policy' }"
|
||||
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
|
||||
@@ -63,13 +75,6 @@
|
||||
>
|
||||
Terms & Conditions
|
||||
</router-link>
|
||||
|
||||
<router-link
|
||||
:to="{ name: 'report-abuse' }"
|
||||
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
|
||||
>
|
||||
Report Abuse
|
||||
</router-link>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
68
client/components/pages/notion/CustomBlock.vue
Normal file
68
client/components/pages/notion/CustomBlock.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="innerJson"
|
||||
id="custom-block"
|
||||
>
|
||||
<div
|
||||
v-if="innerJson.type=='faq'"
|
||||
class="rounded-lg bg-white z-10 pt-10"
|
||||
>
|
||||
<h2 class="font-medium">
|
||||
Frequently Asked Questions
|
||||
</h2>
|
||||
<dl class="pt-4 space-y-6">
|
||||
<div
|
||||
v-for="question in innerJson.content"
|
||||
:key="question.label"
|
||||
class="space-y-2"
|
||||
>
|
||||
<dt class="font-semibold text-gray-900 dark:text-gray-100">
|
||||
{{ question.label }}
|
||||
</dt>
|
||||
<dd
|
||||
class="leading-6 text-gray-600 dark:text-gray-400"
|
||||
v-html="question.content"
|
||||
/>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="innerJson.type=='cta'"
|
||||
class="rounded-lg relative bg-gradient-to-r from-blue-400 to-blue-600 shadow-ld p-8 z-10"
|
||||
>
|
||||
<div class="absolute inset-px rounded-[calc(var(--radius)-1px)]">
|
||||
<div class="flex justify-center w-full h-full">
|
||||
<SpotlightCard
|
||||
class="w-full p-2 rounded-[--radius] [--radius:theme(borderRadius.lg)] opacity-70"
|
||||
from="#60a5fa"
|
||||
:size="200"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative z-20 flex flex-col items-center gap-4 pb-1">
|
||||
<h2 class="text-xl md:text-2xl text-center font-medium text-white">
|
||||
{{ innerJson.title ? innerJson.title : 'Ready to upgrade your OpnForm forms?' }}
|
||||
</h2>
|
||||
<UButton
|
||||
to="/register"
|
||||
color="white"
|
||||
class="hover:no-underline"
|
||||
icon="i-heroicons-arrow-right"
|
||||
trailing
|
||||
>
|
||||
Try OpnForm for free
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { blockProps } from 'vue-notion'
|
||||
import useNotionBlock from '~/components/pages/notion/useNotionBlock.js'
|
||||
|
||||
const props = defineProps(blockProps)
|
||||
|
||||
const block = useNotionBlock(props)
|
||||
const innerJson = computed(() => block.innerJson.value)
|
||||
</script>
|
||||
107
client/components/pages/notion/useNotionBlock.js
vendored
Normal file
107
client/components/pages/notion/useNotionBlock.js
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
import { computed } from 'vue'
|
||||
|
||||
export default function useNotionBlock (props) {
|
||||
|
||||
const block = computed(() => {
|
||||
const id = props.contentId || Object.keys(props.blockMap)[0]
|
||||
return props.blockMap[id]
|
||||
})
|
||||
|
||||
const value = computed(() => {
|
||||
return block.value?.value
|
||||
})
|
||||
|
||||
const format = computed(() => {
|
||||
return value.value?.format
|
||||
})
|
||||
|
||||
const icon = computed(() => {
|
||||
return format.value?.page_icon || ''
|
||||
})
|
||||
|
||||
const width = computed(() => {
|
||||
return format.value?.block_width
|
||||
})
|
||||
|
||||
const properties = computed(() => {
|
||||
return value.value?.properties
|
||||
})
|
||||
|
||||
const caption = computed(() => {
|
||||
return properties.value?.caption
|
||||
})
|
||||
|
||||
const description = computed(() => {
|
||||
return properties.value?.description
|
||||
})
|
||||
|
||||
const src = computed(() => {
|
||||
return mapImageUrl(properties.value?.source[0][0], block.value)
|
||||
})
|
||||
|
||||
const title = computed(() => {
|
||||
return properties.value?.title
|
||||
})
|
||||
|
||||
const alt = computed(() => {
|
||||
return caption.value?.[0][0]
|
||||
})
|
||||
|
||||
const type = computed(() => {
|
||||
return value.value?.type
|
||||
})
|
||||
|
||||
const visible = computed(() => {
|
||||
return !props.hideList.includes(type.value)
|
||||
})
|
||||
|
||||
const hasPageLinkOptions = computed(() => {
|
||||
return props.pageLinkOptions?.component && props.pageLinkOptions?.href
|
||||
})
|
||||
|
||||
const parent = computed(() => {
|
||||
return props.blockMap[value.value?.parent_id]
|
||||
})
|
||||
|
||||
const innerJson = computed(() => {
|
||||
if (type.value !== 'code') return
|
||||
if (properties.value.language.flat('Infinity').join('') !== 'JSON') {
|
||||
return
|
||||
}
|
||||
try {
|
||||
return JSON.parse(
|
||||
title.value.flat(Infinity).join('').replace(/\n/g, '').replace(/\t/g, '').trim()
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Failed to parse JSON',
|
||||
error,
|
||||
title.value.flat(Infinity).join('').replace(/\n/g, '').replace(/\t/g, '').trim()
|
||||
)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
function mapImageUrl (source) {
|
||||
// Implement your mapImageUrl logic here
|
||||
return source
|
||||
}
|
||||
|
||||
return {
|
||||
icon,
|
||||
width,
|
||||
properties,
|
||||
caption,
|
||||
description,
|
||||
src,
|
||||
title,
|
||||
alt,
|
||||
block,
|
||||
value,
|
||||
format,
|
||||
type,
|
||||
visible,
|
||||
hasPageLinkOptions,
|
||||
parent,
|
||||
innerJson
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user