mirror of
https://github.com/tiennm99/HugoBlox-kit.git
synced 2026-10-12 18:15:31 +00:00
156 lines
6.2 KiB
HTML
156 lines
6.2 KiB
HTML
{{/*
|
|
Hugo Blox Slides Embed Component - Reusable iframe embed with fullscreen support
|
|
Usage: {{ partial "components/slides-embed.html" (dict "page" . "slides_slug" .Params.slides) }}
|
|
|
|
Params:
|
|
- page: current page context
|
|
- slides_slug: slug of slides to embed (e.g., "example")
|
|
- show_actions: (optional) show open/speaker notes links, default true
|
|
- title: (optional) title for iframe, defaults to page title
|
|
*/}}
|
|
|
|
{{ $page := .page }}
|
|
{{ $slides_slug := .slides_slug }}
|
|
{{ $show_actions := .show_actions | default true }}
|
|
{{ $slides_label := i18n "slides" | default "Slides" }}
|
|
{{ $present_fullscreen_label := i18n "present_fullscreen" | default "Present (fullscreen)" }}
|
|
{{ $enter_fullscreen_label := i18n "enter_fullscreen" | default "Enter fullscreen" }}
|
|
{{ $exit_fullscreen_label := i18n "exit_fullscreen" | default "Exit fullscreen" }}
|
|
{{ $speaker_notes_hint := i18n "speaker_notes_hint" | default "for speaker notes" }}
|
|
{{ $slides_not_found_label := i18n "slides_not_found" | default "Slides not found" }}
|
|
{{ $embed_title := .title | default (printf "%s - %s" $page.Title $slides_label) }}
|
|
|
|
{{/* Enable Alpine.js for fullscreen functionality */}}
|
|
{{ $page.Store.Set "has_alpine" true }}
|
|
|
|
{{/* Get slides page */}}
|
|
{{ $slides_page := site.GetPage (printf "/slides/%s" $slides_slug) }}
|
|
{{ $scr := newScratch }}
|
|
{{ if $slides_page }}
|
|
{{ $scr.Set "slides_url" $slides_page.RelPermalink }}
|
|
{{ $scr.Set "present_url" $slides_page.RelPermalink }}
|
|
{{ $scr.Set "embed_url" $slides_page.RelPermalink }}
|
|
{{ $present_format := $slides_page.OutputFormats.Get "present" }}
|
|
{{ if not $present_format }}
|
|
{{ $present_format = $slides_page.OutputFormats.Get "Present" }}
|
|
{{ end }}
|
|
{{ with $present_format }}
|
|
{{ $scr.Set "present_url" .RelPermalink }}
|
|
{{ $scr.Set "embed_url" (printf "%s?embed=1" .RelPermalink) }}
|
|
{{ end }}
|
|
{{ end }}
|
|
{{ $slides_url := $scr.Get "slides_url" }}
|
|
{{ $present_url := $scr.Get "present_url" | default $slides_url }}
|
|
{{ $embed_url := $scr.Get "embed_url" | default $slides_url }}
|
|
|
|
{{ if $slides_page }}
|
|
<div
|
|
x-data="{
|
|
isFullscreen: false,
|
|
toggleFullscreen() {
|
|
const container = this.$refs.slideContainer;
|
|
if (!this.isFullscreen) {
|
|
if (container.requestFullscreen) {
|
|
container.requestFullscreen();
|
|
} else if (container.webkitRequestFullscreen) {
|
|
container.webkitRequestFullscreen();
|
|
} else if (container.msRequestFullscreen) {
|
|
container.msRequestFullscreen();
|
|
}
|
|
} else {
|
|
if (document.exitFullscreen) {
|
|
document.exitFullscreen();
|
|
} else if (document.webkitExitFullscreen) {
|
|
document.webkitExitFullscreen();
|
|
} else if (document.msExitFullscreen) {
|
|
document.msExitFullscreen();
|
|
}
|
|
}
|
|
}
|
|
}"
|
|
@fullscreenchange.window="isFullscreen = document.fullscreenElement === $refs.slideContainer"
|
|
@webkitfullscreenchange.window="isFullscreen = document.webkitFullscreenElement === $refs.slideContainer"
|
|
class="mb-12"
|
|
>
|
|
{{/* Slides iframe container - wrapper for fullscreen API */}}
|
|
<div
|
|
x-ref="slideContainer"
|
|
class="relative w-full bg-black rounded-lg shadow-2xl overflow-visible"
|
|
style="aspect-ratio: 16 / 9;"
|
|
:class="isFullscreen ? 'h-screen' : ''"
|
|
>
|
|
<iframe
|
|
src="{{ $embed_url }}"
|
|
class="w-full h-full border-0 rounded-lg"
|
|
allowfullscreen
|
|
allow="autoplay"
|
|
title="{{ $embed_title }}"
|
|
loading="lazy"
|
|
></iframe>
|
|
|
|
{{/* Fullscreen toggle button - inside container for fullscreen visibility */}}
|
|
<button
|
|
@click="toggleFullscreen()"
|
|
class="absolute top-4 right-4 p-3 bg-white/95 dark:bg-gray-800/95 hover:bg-white dark:hover:bg-gray-800 text-gray-700 dark:text-gray-200 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 transition-all duration-200 hover:scale-110 focus:outline-none focus:ring-2 focus:ring-primary-500 backdrop-blur-sm"
|
|
:aria-label="isFullscreen ? {{ $exit_fullscreen_label | jsonify }} : {{ $enter_fullscreen_label | jsonify }}"
|
|
type="button"
|
|
style="z-index: 9999;"
|
|
>
|
|
{{/* Expand icon (when not fullscreen) */}}
|
|
<svg
|
|
x-show="!isFullscreen"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-5 w-5"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
>
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
|
|
</svg>
|
|
{{/* Compress icon (when fullscreen) */}}
|
|
<svg
|
|
x-show="isFullscreen"
|
|
x-cloak
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-5 w-5"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
>
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 9V4.5M9 9H4.5M9 9L3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5l5.25 5.25" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
{{ if $show_actions }}
|
|
{{/* Action links below embed */}}
|
|
<div class="mt-4 flex items-center justify-between text-sm text-gray-600 dark:text-gray-400">
|
|
<div class="flex items-center gap-4">
|
|
{{/* Open in new tab */}}
|
|
<a
|
|
href="{{ $present_url }}"
|
|
target="_blank"
|
|
rel="noopener"
|
|
class="inline-flex items-center gap-1 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
|
|
</svg>
|
|
<span>{{ $present_fullscreen_label }}</span>
|
|
</a>
|
|
|
|
{{/* Presentation mode hint */}}
|
|
<span class="text-xs">
|
|
<kbd class="px-2 py-1 text-xs font-semibold text-gray-800 bg-gray-100 border border-gray-200 rounded dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500">S</kbd>
|
|
{{ $speaker_notes_hint }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
</div>
|
|
{{ else }}
|
|
<p class="text-sm text-red-600 dark:text-red-400">{{ $slides_not_found_label }}: {{ $slides_slug }}</p>
|
|
{{ end }}
|