<template>
<div class="playbook-embed-container" :class="containerClass">
<div class="playbook-embed-wrapper" :style="wrapperStyle">
<iframe
:src="embedUrl"
:style="iframeStyle"
:title="embedTitle"
allow="fullscreen"
@load="handleLoad"
@error="handleError"
/>
</div>
<div v-if="loading" class="embed-loading">
<slot name="loading">
<div class="loading-spinner">Loading...</div>
</slot>
</div>
</div>
</template>
<script>
import { computed, ref, watch } from 'vue';
export default {
name: 'PlarosEmbed',
props: {
tenantSlug: { type: String, required: true },
zonePath: { type: String, required: true },
playbookId: { type: String, default: null },
userId: { type: String, default: null },
primaryColor: { type: String, default: null },
secondaryColor: { type: String, default: null },
themeMode: { type: String, default: null },
size: { type: String, default: 'medium' },
analytics: { type: Boolean, default: true },
debug: { type: Boolean, default: false }
},
emits: ['load', 'error'],
setup(props, { emit }) {
const loading = ref(true);
const embedUrl = computed(() => {
const url = new URL(`https://play.plaros.com/v1/embed/${props.tenantSlug}/playbooks`);
url.searchParams.set('zonePath', props.zonePath);
if (props.playbookId) {
url.searchParams.set('playbookId', props.playbookId);
}
if (props.userId) {
url.searchParams.set('userId', props.userId);
}
if (props.primaryColor) {
url.searchParams.set('primaryColor', props.primaryColor.replace('#', ''));
}
if (props.secondaryColor) {
url.searchParams.set('secondaryColor', props.secondaryColor.replace('#', ''));
}
if (props.themeMode) {
url.searchParams.set('themeMode', props.themeMode);
}
url.searchParams.set('analytics', props.analytics.toString());
if (props.debug) {
url.searchParams.set('debug', 'true');
}
return url.toString();
});
const sizeConfig = {
small: { maxWidth: '400px', paddingBottom: '177.78%' },
medium: { maxWidth: '600px', paddingBottom: '133.33%' },
large: { maxWidth: '800px', paddingBottom: '75%' }
};
const containerClass = computed(() => `embed-size-${props.size}`);
const wrapperStyle = computed(() => ({
position: 'relative',
paddingBottom: sizeConfig[props.size]?.paddingBottom || '133.33%',
height: 0,
overflow: 'hidden'
}));
const iframeStyle = {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
border: 0,
borderRadius: '8px'
};
const embedTitle = computed(() =>
`Interactive Playbook${props.playbookId ? ` - ${props.playbookId}` : ''}`
);
const handleLoad = () => {
loading.value = false;
emit('load');
};
const handleError = (error) => {
loading.value = false;
emit('error', error);
};
// Reset loading state when URL changes
watch(embedUrl, () => {
loading.value = true;
});
return {
loading,
embedUrl,
containerClass,
wrapperStyle,
iframeStyle,
embedTitle,
handleLoad,
handleError
};
}
};
</script>
<style scoped>
.playbook-embed-container {
position: relative;
width: 100%;
margin: 0 auto;
}
.embed-size-small { max-width: 400px; }
.embed-size-medium { max-width: 600px; }
.embed-size-large { max-width: 800px; }
.embed-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1;
background: rgba(255, 255, 255, 0.9);
padding: 20px;
border-radius: 8px;
}
.loading-spinner {
text-align: center;
color: #666;
}
@media (max-width: 600px) {
.playbook-embed-container {
max-width: 100% !important;
padding: 0 16px;
}
}
</style>