Skip to content

Commit fa5ab56

Browse files
committed
feat: ScriptIntercom
1 parent ea8e96b commit fa5ab56

File tree

4 files changed

+113
-7
lines changed

4 files changed

+113
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script lang="ts" setup>
2+
import { useHead } from '#imports'
3+
4+
useHead({
5+
title: 'Intercom',
6+
})
7+
</script>
8+
9+
<template>
10+
<div>
11+
<ScriptIntercom app-id="akg5rmxb" api-base="https://api-iam.intercom.io">
12+
<template #awaitingLoad>
13+
<div style="width: 48px; display: flex; align-items: center; justify-content: center; height: 48px; border-radius: 50%; cursor: pointer; background-color: black; filter: drop-shadow(rgba(0, 0, 0, 0.06) 0px 1px 6px) drop-shadow(rgba(0, 0, 0, 0.16) 0px 2px 32px);">
14+
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill="white" viewBox="0 0 28 32"><path d="M28 32s-4.714-1.855-8.527-3.34H3.437C1.54 28.66 0 27.026 0 25.013V3.644C0 1.633 1.54 0 3.437 0h21.125c1.898 0 3.437 1.632 3.437 3.645v18.404H28V32zm-4.139-11.982a.88.88 0 00-1.292-.105c-.03.026-3.015 2.681-8.57 2.681-5.486 0-8.517-2.636-8.571-2.684a.88.88 0 00-1.29.107 1.01 1.01 0 00-.219.708.992.992 0 00.318.664c.142.128 3.537 3.15 9.762 3.15 6.226 0 9.621-3.022 9.763-3.15a.992.992 0 00.317-.664 1.01 1.01 0 00-.218-.707z" /></svg>
15+
</div>
16+
</template>
17+
<template #loading>
18+
<div style="width: 48px; display: flex; align-items: center; justify-content: center; height: 48px; border-radius: 50%; cursor: pointer; background-color: black; filter: drop-shadow(rgba(0, 0, 0, 0.06) 0px 1px 6px) drop-shadow(rgba(0, 0, 0, 0.16) 0px 2px 32px);">
19+
<ScriptLoadingIndicator color="white" :size="24" />
20+
</div>
21+
</template>
22+
</ScriptIntercom>
23+
</div>
24+
</template>
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<script setup lang="ts">
2+
import { useScriptIntercom } from '../registry/intercom'
3+
import { useElementScriptTrigger } from '../composables/useElementScriptTrigger'
4+
import { ref, onMounted } from '#imports'
5+
import type { ElementScriptTrigger } from '#nuxt-scripts'
6+
7+
const props = withDefaults(defineProps<{
8+
appId: string
9+
apiBase?: string
10+
name?: string
11+
email?: string
12+
userId?: string
13+
// customizing the messenger
14+
alignment?: 'left' | 'right'
15+
horizontalPadding?: number
16+
verticalPadding?: number
17+
/**
18+
* Defines the trigger event to load the script.
19+
*/
20+
trigger?: ElementScriptTrigger
21+
}>(), {
22+
trigger: 'click',
23+
})
24+
25+
const emits = defineEmits<{
26+
// our emit
27+
ready: [e: ReturnType<typeof useScriptIntercom>]
28+
}>()
29+
30+
const rootEl = ref(null)
31+
const trigger = useElementScriptTrigger({ trigger: props.trigger, el: rootEl })
32+
33+
const isReady = ref(false)
34+
const intercom = useScriptIntercom({
35+
app_id: props.appId,
36+
// @ts-expect-error untyped
37+
app_base: props.apiBase,
38+
name: props.name,
39+
email: props.email,
40+
user_id: props.userId,
41+
alignment: props.alignment,
42+
horizontal_padding: props.horizontalPadding,
43+
vertical_padding: props.verticalPadding,
44+
scriptOptions: {
45+
trigger,
46+
},
47+
})
48+
if (props.trigger === 'click')
49+
intercom.Intercom('show')
50+
const { $script } = intercom
51+
52+
defineExpose({
53+
intercom,
54+
})
55+
56+
// add a listener to detect when the dom element #crisp-chatbox is added
57+
onMounted(() => {
58+
const observer = new MutationObserver(() => {
59+
if (document.getElementById('crisp-chatbox')) {
60+
isReady.value = true
61+
emits('ready', intercom)
62+
observer.disconnect()
63+
}
64+
})
65+
observer.observe(document.body, { childList: true, subtree: true })
66+
})
67+
</script>
68+
69+
<template>
70+
<div
71+
ref="rootEl"
72+
style="display: block; position: absolute; bottom: 20px; right: 20px; z-index: 100000; "
73+
>
74+
<slot :ready="isReady" />
75+
<slot v-if="$script.status.value === 'awaitingLoad'" name="awaitingLoad" />
76+
<slot v-else-if="$script.status.value === 'loading' || !isReady" name="loading" />
77+
</div>
78+
</template>

src/runtime/components/ScriptLoadingIndicator.vue

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
<script setup lang="ts">
2-
withDefaults(defineProps<{
2+
import { computed } from '#imports'
3+
4+
const props = withDefaults(defineProps<{
35
color?: string
6+
size?: number
47
}>(), {
58
color: 'currentColor',
9+
size: 30,
610
})
11+
12+
const styles = computed(() => ({
13+
width: `${props.size}px`,
14+
height: `${props.size}px`,
15+
}))
716
</script>
817

918
<template>
10-
<div class="loader" aria-label="Loading..." role="status" />
19+
<div class="loader" :styles="styles" aria-label="Loading..." role="status" />
1120
</template>
1221

1322
<style scoped>
1423
.loader {
15-
position: absolute;
16-
bottom: 12px;
17-
left: 12px;
18-
width: 30px;
19-
height: 30px;
2024
border: 5px solid v-bind(color);
2125
opacity: 0.5;
2226
border-bottom-color: transparent;

0 commit comments

Comments
 (0)